5 * Copyright (C) 2008-2009 Pawel Dziepak
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "manes/manec.h"
27 using namespace manes
;
28 using namespace resources
;
30 fat::fat() : mounted(false) {}
32 bool fat::mount(p
<block
> _dep
) {
36 mbr
= new unsigned char[512];
37 dep
->read_block(0, 1, (void*)mbr
);
39 /* Check if filesystem is FAT12 */
40 if (strncmp((char*)&(mbr
[mbr_fsid
]),"FAT12",5)) {
41 debug("fat: fs is not fat12");
44 if (mbr
[mbr_dev_desc
] != 0xF0) {
45 debug("fat: fs is not fat12");
50 main_fat
= new unsigned char[(unsigned short)mbr
[mbr_sectors_per_fat
] << 9];
51 dep
->read_block(mbr
[mbr_reserved_sectors
], ((unsigned short)mbr
[mbr_sectors_per_fat
]), (void*)main_fat
);
54 root_dir
= new dir_entry
[(unsigned short)mbr
[mbr_root_entries
] * 32];
55 dep
->read_block(mbr
[mbr_fat_count
] * mbr
[mbr_sectors_per_fat
] + mbr
[mbr_reserved_sectors
], ((unsigned short)mbr
[mbr_root_entries
])* 32 / 512, (void*)root_dir
);
61 typedef unsigned int cpu_word
;
62 void fat::load_file(const string
&filename
, buffer
&addr
) {
63 assert("fat: filesystem is not mounted", !mounted
);
65 int index
= find_file(filename
);
67 unsigned int cluster
= root_dir
[index
].cluster
;
70 while (cluster
< 0xFF0 && cluster
> 1) {
71 index
= ((unsigned char)mbr
[mbr_fat_count
])*((unsigned short)mbr
[mbr_sectors_per_fat
])+((unsigned short)mbr
[mbr_reserved_sectors
])+((unsigned short)mbr
[mbr_root_entries
])*32/512;
75 dep
->read_block(index
, 1, (void*)((cpu_word
)addr
.get_address() + count
));
77 cluster
= get_cluster_val(cluster
);
83 file::file_meta
fat::load_meta(const string
&filename
) {
84 assert("fat: filesystem is not mounted", !mounted
);
86 int index
= find_file(filename
);
89 meta
.creation_d
= date(root_dir
[index
].date
& 0x1f, root_dir
[index
].date
& 0x1e0 >> 5, (root_dir
[index
].date
& 0xf800 >> 9) + 1980);
90 meta
.creation_t
= time(root_dir
[index
].time
& 0x1f, root_dir
[index
].time
& 0x7e0 >> 5, root_dir
[index
].time
& 0xf800 >> 0xb);
92 if ((root_dir
[index
].attr
& fat_hidden
) == fat_hidden
)
93 meta
.attributes
= file::attr_hidden
;
95 meta
.attributes
= (file::attrib
)0;
97 meta
.directory
= (root_dir
[index
].attr
& fat_directory
) == fat_directory
;
99 if ((root_dir
[index
].attr
& fat_read_only
) == fat_read_only
)
100 meta
.access
= prvl(0, 555);
102 meta
.access
= prvl(0, 777);
104 meta
.size
= root_dir
[index
].size
;
109 short fat::get_cluster_val(int n
) {
111 int index
= cluster
+ (cluster
>> 1);
112 cluster
= *((unsigned short*)((int)main_fat
+index
));
122 void fat::set_cluster_val(int n
, int val
) {
124 int index
= cluster
+ (cluster
>> 1);
128 *((unsigned short*)((int)main_fat
+index
)) &= 0xF000;
130 *((unsigned short*)((int)main_fat
+index
)) |= val
;
132 *((unsigned short*)((int)main_fat
+index
)) &= 0x000F;
134 *((unsigned short*)((int)main_fat
+index
)) |= val
;
138 void fat::filename_to_fatname(const char *filename
, char *fatname
) {
140 for (int i
= 0, j
= 0; i
< 11; j
++, i
++) {
143 for (; filename
[j
] != '.' && filename
[j
]; j
++);
148 if (filename
[j
] >= 'a' && filename
[j
] <= 'z') fatname
[i
] = filename
[j
] - 'a' + 'A';
149 else if (filename
[j
] == '.') {
155 else if (!filename
[j
])
158 else fatname
[i
] = filename
[j
];
162 void fat::fatname_to_filename(const char *fatname
, char *filename
) {
164 for (i
= 0, j
= 0; i
< 11; i
++,j
++) {
165 if (i
== 8 && fatname
[9] != ' ') {
170 if (fatname
[i
] >= 'A' && fatname
[i
] <= 'Z')
171 filename
[j
] = fatname
[i
] - 'A' + 'a';
172 else if (fatname
[i
] != ' ')
173 filename
[j
] = fatname
[i
];
175 if (fatname
[i
] == ' ') {
176 for (; fatname
[i
]==' ' && i
< 11; i
++);
178 /*filename[j] = '.';*/
186 bool valid_fatname(const char *fatname
) {
187 for (int i
= 0; i
< 11; i
++)
188 if (fatname
[i
] < ' ' || fatname
[i
] > '~')
193 void fat::save_file(const string
&filename
, buffer
&addr
) {
194 assert("fat: filesystem is not mounted", !mounted
);
197 filename_to_fatname(filename
, fatname
);
200 for (int i
= 0; i
< 50; i
++)
201 if (root_dir
[i
].name
[0] == '\0' && root_dir
[i
].name
[1] == '\0')
203 assert("fat: no free entry in root dir", pos
== 0);
205 strcpy((char*)root_dir
[pos
].name
, fatname
);
206 root_dir
[pos
].size
= addr
.get_size();
208 int first_cluster
= 0, n_cluster
, cluster
, saved
= 0;
210 for (first_cluster
= 3; get_cluster_val(first_cluster
) != 0; first_cluster
++);
212 n_cluster
= first_cluster
;
216 int index
= ((unsigned char)mbr
[mbr_fat_count
])*((unsigned short)mbr
[mbr_sectors_per_fat
])+((unsigned short)mbr
[mbr_reserved_sectors
])+((unsigned short)mbr
[mbr_root_entries
])*32/512;
217 index
+= cluster
- 2;
219 dep
->write_block(index
, 1, (void*)((int)addr
.get_address() + saved
));
221 for (n_cluster
= cluster
+ 1; get_cluster_val(n_cluster
) != 0; n_cluster
++);
222 set_cluster_val(cluster
, n_cluster
);
225 } while (saved
< addr
.get_size());
227 set_cluster_val(cluster
, 0xFFF);
229 root_dir
[pos
].cluster
= first_cluster
;
232 dep
->write_block(mbr
[mbr_reserved_sectors
], ((unsigned short)mbr
[mbr_sectors_per_fat
]), (void*)main_fat
);
235 dep
->write_block(mbr
[mbr_fat_count
] * mbr
[mbr_sectors_per_fat
] + mbr
[mbr_reserved_sectors
], ((unsigned short)mbr
[mbr_root_entries
])* 32 / 512, (void*)root_dir
);
239 list
<p
<file
> > fat::list_directory(const string
&dirname
) {
242 for (int i
= 0; i
< 50; i
++) {
243 if (valid_fatname((char*)root_dir
[i
].name
)) {
245 p
<file
> fp
= new file();
246 fatname_to_filename((char*)root_dir
[i
].name
, filename
);
247 fp
->set(filename
, (fs
*)this);
255 int fat::find_file(const char *filename
) {
258 filename_to_fatname(filename
, fatname
);
260 for (int i
= 0; i
< 50; i
++)
261 if (!strncmp(fatname
, (const char*)root_dir
[i
].name
,11))
264 debug((string
)"fat: file not found: " + filename
);
268 void fat::register_type() {
269 manec::get()->register_type
<fat
>("fat", "manec");