summaryrefslogtreecommitdiff
path: root/firmware/drivers/fat.c
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2002-04-23 09:13:23 +0000
committerBjörn Stenberg <bjorn@haxx.se>2002-04-23 09:13:23 +0000
commitc6773e1436ba3adda0a6456dbe54ba1320a095be (patch)
tree172c21804499aa84fcab2f755596a3272cfbd59a /firmware/drivers/fat.c
parent34f948291202bdb42391bbc1200326e1aca00e5c (diff)
downloadrockbox-c6773e1436ba3adda0a6456dbe54ba1320a095be.tar.gz
rockbox-c6773e1436ba3adda0a6456dbe54ba1320a095be.zip
Moved driver to 'drivers' subdir
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@189 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers/fat.c')
-rw-r--r--firmware/drivers/fat.c1315
1 files changed, 1315 insertions, 0 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
new file mode 100644
index 0000000000..328428a941
--- /dev/null
+++ b/firmware/drivers/fat.c
@@ -0,0 +1,1315 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <stdio.h>
21#include <string.h>
22#include <math.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <time.h>
26#include <sys/timeb.h>
27
28#define BLOCK_SIZE 512
29
30#include "fat.h"
31#include "ata.h"
32
33#define NUM_ROOT_DIR_ENTRIES 512
34#define NUM_FATS 2
35#define NUM_RESERVED_SECTORS 1
36#define NUM_BLOCKS 10000
37
38struct dsksz2secperclus
39{
40 unsigned int disk_size;
41 unsigned int sec_per_cluster;
42};
43
44/*
45** This is the table for FAT16 drives. NOTE that this table includes
46** entries for disk sizes larger than 512 MB even though typically
47** only the entries for disks < 512 MB in size are used.
48** The way this table is accessed is to look for the first entry
49** in the table for which the disk size is less than or equal
50** to the DiskSize field in that table entry. For this table to
51** work properly BPB_RsvdSecCnt must be 1, BPB_NumFATs
52** must be 2, and BPB_RootEntCnt must be 512. Any of these values
53** being different may require the first table entries DiskSize value
54** to be changed otherwise the cluster count may be to low for FAT16.
55*/
56struct dsksz2secperclus dsk_table_fat16 [] =
57{
58 { 8400, 0}, /* disks up to 4.1 MB, the 0 value for SecPerClusVal
59 trips an error */
60 { 32680, 2}, /* disks up to 16 MB, 1k cluster */
61 { 262144, 4}, /* disks up to 128 MB, 2k cluster */
62 { 524288, 8}, /* disks up to 256 MB, 4k cluster */
63 { 1048576, 16}, /* disks up to 512 MB, 8k cluster */
64/* The entries after this point are not used unless FAT16 is forced */
65 { 2097152, 32}, /* disks up to 1 GB, 16k cluster */
66 { 4194304, 64}, /* disks up to 2 GB, 32k cluster */
67 { 0xFFFFFFFF, 0} /* any disk greater than 2GB,
68 0 value for SecPerClusVal trips an error */
69};
70
71int fat_num_rootdir_sectors(struct bpb *bpb);
72int fat_first_sector_of_cluster(struct bpb *bpb, unsigned int cluster);
73int fat_get_fatsize(struct bpb* bpb);
74int fat_get_totsec(struct bpb* bpb);
75int fat_get_rootdir_sector(struct bpb *bpb);
76int fat_first_data_sector(struct bpb* bpb);
77int fat_get_bpb(struct bpb *bpb);
78int fat_bpb_is_sane(struct bpb *bpb);
79int fat_create_fat(struct bpb* bpb);
80int fat_dbg_read_block(char *name, unsigned char *buf);
81int fat_flush_fat(struct bpb *bpb);
82unsigned char *fat_cache_fat_sector(struct bpb *bpb, int secnum);
83int fat_update_entry(struct bpb *bpb, int entry, unsigned int val);
84unsigned int fat_getcurrdostime(unsigned short *dosdate,
85 unsigned short *dostime,
86 unsigned char *dostenth);
87int fat_create_root_dir(struct bpb *bpb);
88int fat_create_dos_name(unsigned char *name, unsigned char *newname);
89int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name);
90
91unsigned char *fat_cache[256];
92int fat_cache_dirty[256];
93char current_directory[256] = "\\";
94struct bpb *global_bpb;
95struct disk_info di;
96
97extern int yyparse(void);
98
99
100#ifdef TEST_FAT
101void prompt(void)
102{
103 printf("C:%s>", current_directory);
104}
105
106int main(int argc, char *argv[])
107{
108 struct bpb bpb;
109
110 memset(fat_cache, 0, sizeof(fat_cache));
111 memset(fat_cache_dirty, 0, sizeof(fat_cache_dirty));
112
113 disk_init(NUM_BLOCKS);
114
115 di.num_sectors = NUM_BLOCKS;
116 di.sec_per_track = 40;
117 di.num_heads = 250;
118 di.hidden_sectors = 0;
119
120 if(read_disk("diskdump.dmp") < 0)
121 {
122 printf("*** Warning! The disk is uninitialized\n");
123 }
124 else
125 {
126 fat_get_bpb(&bpb);
127 }
128
129 global_bpb = &bpb;
130 prompt();
131 yyparse();
132
133 dump_disk("diskdump.dmp");
134 return 0;
135}
136#endif
137
138int fat_sec2cluster(struct bpb *bpb, unsigned int sec)
139{
140 int first_sec = fat_first_data_sector(bpb);
141
142 if(sec < first_sec)
143 {
144 fprintf(stderr, "fat_sec2cluster() - Bad sector number (%d)\n", sec);
145 return -1;
146 }
147
148 return ((sec - first_sec) / bpb->bpb_secperclus) + 2;
149}
150
151int fat_last_cluster_in_chain(struct bpb *bpb, unsigned int cluster)
152{
153 int iseof = 0;
154
155 switch(bpb->fat_type)
156 {
157 case FATTYPE_FAT12:
158 if(cluster >= 0x0ff8)
159 iseof = 1;
160 break;
161 case FATTYPE_FAT16:
162 if(cluster >= 0xfff8)
163 iseof = 1;
164 break;
165 case FATTYPE_FAT32:
166 if(cluster >= 0x0ffffff8)
167 iseof = 1;
168 break;
169 }
170 return iseof;
171}
172
173int fat_cluster2sec(struct bpb *bpb, unsigned int cluster)
174{
175 int max_cluster = (fat_get_totsec(bpb) - fat_first_data_sector(bpb)) /
176 bpb->bpb_secperclus + 1;
177
178 if(cluster > max_cluster)
179 {
180 fprintf(stderr, "fat_cluster2sec() - Bad cluster number (%d)\n",
181 cluster);
182 return -1;
183 }
184
185 return fat_first_sector_of_cluster(bpb, cluster);
186}
187
188int fat_first_sector_of_cluster(struct bpb *bpb, unsigned int cluster)
189{
190 return (cluster - 2) * bpb->bpb_secperclus + fat_first_data_sector(bpb);
191}
192
193int fat_num_rootdir_sectors(struct bpb *bpb)
194{
195 return ((bpb->bpb_rootentcnt * 32) + (bpb->bpb_bytspersec - 1)) /
196 bpb->bpb_bytspersec;
197}
198
199int fat_get_fatsize(struct bpb* bpb)
200{
201 if(bpb->bpb_fatsz16 != 0)
202 return bpb->bpb_fatsz16;
203 else
204 return bpb->bpb_fatsz32;
205}
206
207int fat_get_totsec(struct bpb* bpb)
208{
209 if(bpb->bpb_totsec16 != 0)
210 return bpb->bpb_totsec16;
211 else
212 return bpb->bpb_totsec32;
213}
214
215int fat_get_rootdir_sector(struct bpb *bpb)
216{
217 return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fat_get_fatsize(bpb);
218}
219
220int fat_first_data_sector(struct bpb* bpb)
221{
222 int fatsz;
223 int rootdirsectors;
224
225 fatsz = fat_get_fatsize(bpb);
226
227 rootdirsectors = fat_num_rootdir_sectors(bpb);
228
229 return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz + rootdirsectors;
230}
231
232int fat_format(struct disk_info *di, char *vol_name)
233{
234 unsigned char buf[BLOCK_SIZE];
235 struct bpb bpb;
236 unsigned int root_dir_sectors;
237 unsigned int tmp1, tmp2;
238 int sec_per_clus = 0;
239 int fat_size;
240 int i = 0;
241 int err;
242
243 while(di->num_sectors > dsk_table_fat16[i].disk_size)
244 {
245 i++;
246 }
247
248 sec_per_clus = dsk_table_fat16[i].sec_per_cluster;
249
250 if(sec_per_clus == 0)
251 {
252 fprintf(stderr, "fat_format() - Bad disk size (%u)\n",
253 di->num_sectors);
254 return -1;
255 }
256
257 /* First calculate how many sectors we need for
258 the root directory */
259 root_dir_sectors = ((NUM_ROOT_DIR_ENTRIES * 32) +
260 (BLOCK_SIZE - 1)) / BLOCK_SIZE;
261
262 /* Now calculate the FAT size */
263 tmp1 = di->num_sectors - (NUM_RESERVED_SECTORS + root_dir_sectors);
264 tmp2 = (256 * sec_per_clus) + NUM_FATS;
265
266 fat_size = (tmp1 + (tmp2 - 1)) / tmp2;
267
268 /* Now create the BPB. We must be careful, so we really make
269 it little endian. */
270 memset(buf, 0xff, BLOCK_SIZE);
271
272 strncpy(&buf[BS_OEMNAME], "MSWIN4.1", 8);
273 buf[BPB_BYTSPERSEC] = BLOCK_SIZE & 0xff;
274 buf[BPB_BYTSPERSEC+1] = BLOCK_SIZE >> 8;
275 buf[BPB_SECPERCLUS] = sec_per_clus;
276 buf[BPB_RSVDSECCNT] = 1;
277 buf[BPB_RSVDSECCNT+1] = 0;
278 buf[BPB_NUMFATS] = 2;
279 buf[BPB_ROOTENTCNT] = NUM_ROOT_DIR_ENTRIES & 0xff;
280 buf[BPB_ROOTENTCNT+1] = NUM_ROOT_DIR_ENTRIES >> 8;
281 buf[BPB_TOTSEC16] = di->num_sectors & 0xff;
282 buf[BPB_TOTSEC16+1] = di->num_sectors >> 8;
283 buf[BPB_MEDIA] = 0xf0;
284 buf[BPB_FATSZ16] = fat_size & 0xff;
285 buf[BPB_FATSZ16+1] = fat_size >> 8;
286 buf[BPB_SECPERTRK] = di->sec_per_track & 0xff;
287 buf[BPB_SECPERTRK+1] = di->sec_per_track >> 8;
288 buf[BPB_NUMHEADS] = di->num_heads & 0xff;
289 buf[BPB_NUMHEADS+1] = di->num_heads >> 8;
290 buf[BPB_HIDDSEC] = di->hidden_sectors & 0xff;
291 buf[BPB_HIDDSEC+1] = (di->hidden_sectors >> 8) & 0xff;
292 buf[BPB_HIDDSEC+2] = (di->hidden_sectors >> 16) & 0xff;
293 buf[BPB_HIDDSEC+3] = (di->hidden_sectors >> 24) & 0xff;
294 buf[BPB_TOTSEC32] = 0;
295 buf[BPB_TOTSEC32+1] = 0;
296 buf[BPB_TOTSEC32+2] = 0;
297 buf[BPB_TOTSEC32+3] = 0;
298
299 buf[BS_DRVNUM] = 0;
300 buf[BS_RESERVED1] = 0;
301 buf[BS_BOOTSIG] = 0x29;
302 buf[BS_VOLID] = 0x78;
303 buf[BS_VOLID+1] = 0x56;
304 buf[BS_VOLID+2] = 0x34;
305 buf[BS_VOLID+3] = 0x12;
306 memset(&buf[BS_VOLLAB], ' ', 11);
307 strncpy(&buf[BS_VOLLAB], vol_name, MIN(11, strlen(vol_name));
308 strncpy(&buf[BS_FILSYSTYPE], "FAT16 ", 8);
309
310 /* The final signature */
311 buf[BPB_LAST_WORD] = 0x55;
312 buf[BPB_LAST_WORD+1] = 0xaa;
313
314 /* Now write the sector to disk */
315 err = ata_write_sectors(0,1,buf);
316 if(err)
317 {
318 fprintf(stderr, "fat_format() - Couldn't write BSB (error code %i)\n",
319 err);
320 return -1;
321 }
322
323 if(fat_get_bpb(&bpb) < 0)
324 {
325 fprintf(stderr, "fat_format() - Couldn't read BPB\n");
326 return -1;
327 }
328
329 if(fat_create_fat(&bpb) < 0)
330 {
331 fprintf(stderr, "fat_format() - Couldn't create FAT\n");
332 return -1;
333 }
334
335 if(fat_create_root_dir(&bpb) < 0)
336 {
337 fprintf(stderr, "fat_format() - Couldn't write root dir sector\n");
338 return -1;
339 }
340
341 return 0;
342}
343
344int fat_get_bpb(struct bpb *bpb)
345{
346 unsigned char buf[BLOCK_SIZE];
347 int err;
348 int fatsz;
349 int rootdirsectors;
350 int totsec;
351 int datasec;
352 int countofclusters;
353
354 /* Read the sector */
355 err = ata_read_sectors(0,1,buf);
356 if(err)
357 {
358 fprintf(stderr, "fat_get_bpb() - Couldn't read BPB (error code %i)\n",
359 err);
360 return -1;
361 }
362
363 memset(bpb, 0, sizeof(struct bpb));
364
365 strncpy(bpb->bs_oemname, &buf[BS_OEMNAME], 8);
366 bpb->bs_oemname[8] = 0;
367
368 bpb->bpb_bytspersec = buf[BPB_BYTSPERSEC] | (buf[BPB_BYTSPERSEC+1] << 8);
369 bpb->bpb_secperclus = buf[BPB_SECPERCLUS];
370 bpb->bpb_rsvdseccnt = buf[BPB_RSVDSECCNT] | (buf[BPB_RSVDSECCNT+1] << 8);
371 bpb->bpb_numfats = buf[BPB_NUMFATS];
372 bpb->bpb_rootentcnt = buf[BPB_ROOTENTCNT] | (buf[BPB_ROOTENTCNT+1] << 8);
373 bpb->bpb_totsec16 = buf[BPB_TOTSEC16] | (buf[BPB_TOTSEC16+1] << 8);
374 bpb->bpb_media = buf[BPB_MEDIA];
375 bpb->bpb_fatsz16 = buf[BPB_FATSZ16] | (buf[BPB_FATSZ16+1] << 8);
376 bpb->bpb_secpertrk = buf[BPB_SECPERTRK] | (buf[BPB_SECPERTRK+1] << 8);
377 bpb->bpb_numheads = buf[BPB_NUMHEADS] | (buf[BPB_NUMHEADS+1] << 8);
378 bpb->bpb_hiddsec = buf[BPB_HIDDSEC] | (buf[BPB_HIDDSEC+1] << 8) |
379 (buf[BPB_HIDDSEC+2] << 16) | (buf[BPB_HIDDSEC+3] << 24);
380 bpb->bpb_totsec32 = buf[BPB_TOTSEC32] | (buf[BPB_TOTSEC32+1] << 8) |
381 (buf[BPB_TOTSEC32+2] << 16) | (buf[BPB_TOTSEC32+3] << 24);
382
383 bpb->bs_drvnum = buf[BS_DRVNUM];
384 bpb->bs_bootsig = buf[BS_BOOTSIG];
385 if(bpb->bs_bootsig == 0x29)
386 {
387 bpb->bs_volid = buf[BS_VOLID] | (buf[BS_VOLID+1] << 8) |
388 (buf[BS_VOLID+2] << 16) | (buf[BS_VOLID+3] << 24);
389 strncpy(bpb->bs_vollab, &buf[BS_VOLLAB], 11);
390 strncpy(bpb->bs_filsystype, &buf[BS_FILSYSTYPE], 8);
391 }
392
393 bpb->bpb_fatsz32 = (buf[BPB_FATSZ32] + (buf[BPB_FATSZ32+1] << 8)) |
394 (buf[BPB_FATSZ32+2] << 16) | (buf[BPB_FATSZ32+3] << 24);
395
396 bpb->last_word = buf[BPB_LAST_WORD] | (buf[BPB_LAST_WORD+1] << 8);
397
398 /* Determine FAT type */
399 fatsz = fat_get_fatsize(bpb);
400
401 if(bpb->bpb_totsec16 != 0)
402 totsec = bpb->bpb_totsec16;
403 else
404 totsec = bpb->bpb_totsec32;
405
406 rootdirsectors = fat_num_rootdir_sectors(bpb);
407 datasec = totsec - (bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz +
408 rootdirsectors);
409 countofclusters = datasec / bpb->bpb_secperclus;
410
411 if(countofclusters < 4085)
412 {
413 bpb->fat_type = FATTYPE_FAT12;
414 }
415 else
416 {
417 if(countofclusters < 65525)
418 {
419 bpb->fat_type = FATTYPE_FAT16;
420 }
421 else
422 {
423 bpb->fat_type = FATTYPE_FAT32;
424 }
425 }
426
427 if(fat_bpb_is_sane(bpb) < 0)
428 {
429 fprintf(stderr, "fat_get_bpb() - BPB is not sane\n");
430 return -1;
431 }
432
433 return 0;
434}
435
436int fat_bpb_is_sane(struct bpb *bpb)
437{
438 if(bpb->fat_type == FATTYPE_FAT32)
439 {
440 fprintf(stderr, "fat_bpb_is_sane() - Error: FAT32 not supported\n");
441 return -1;
442 }
443
444 if(bpb->bpb_bytspersec != 512)
445 {
446 fprintf(stderr,
447 "fat_bpb_is_sane() - Warning: sector size is not 512 (%i)\n",
448 bpb->bpb_bytspersec);
449 }
450 if(bpb->bpb_secperclus * bpb->bpb_bytspersec > 32768)
451 {
452 fprintf(stderr,
453 "fat_bpb_is_sane() - Warning: cluster size is larger than 32K "
454 "(%i * %i = %i)\n",
455 bpb->bpb_bytspersec, bpb->bpb_secperclus,
456 bpb->bpb_bytspersec * bpb->bpb_secperclus);
457 }
458 if(bpb->bpb_rsvdseccnt != 1)
459 {
460 fprintf(stderr,
461 "fat_bpb_is_sane() - Warning: Reserved sectors is not 1 (%i)\n",
462 bpb->bpb_rsvdseccnt);
463 }
464 if(bpb->bpb_numfats != 2)
465 {
466 fprintf(stderr,
467 "fat_bpb_is_sane() - Warning: NumFATS is not 2 (%i)\n",
468 bpb->bpb_numfats);
469 }
470 if(bpb->bpb_rootentcnt != 512)
471 {
472 fprintf(stderr,
473 "fat_bpb_is_sane() - Warning: RootEntCnt is not 512 (%i)\n",
474 bpb->bpb_rootentcnt);
475 }
476 if(bpb->bpb_totsec16 < 200)
477 {
478 if(bpb->bpb_totsec16 == 0)
479 {
480 fprintf(stderr, "fat_bpb_is_sane() - Error: TotSec16 is 0\n");
481 return -1;
482 }
483 else
484 {
485 fprintf(stderr,
486 "fat_bpb_is_sane() - Warning: TotSec16 "
487 "is quite small (%i)\n",
488 bpb->bpb_totsec16);
489 }
490 }
491 if(bpb->bpb_media != 0xf0 && bpb->bpb_media < 0xf8)
492 {
493 fprintf(stderr,
494 "fat_bpb_is_sane() - Warning: Non-standard "
495 "media type (0x%02x)\n",
496 bpb->bpb_media);
497 }
498 if(bpb->last_word != 0xaa55)
499 {
500 fprintf(stderr, "fat_bpb_is_sane() - Error: Last word is not "
501 "0xaa55 (0x%04x)\n", bpb->last_word);
502 return -1;
503 }
504 return 0;
505}
506
507int fat_create_fat(struct bpb* bpb)
508{
509 unsigned char *sec;
510 int i;
511 int secnum = 0;
512 int fatsz;
513
514 if(fat_bpb_is_sane(bpb) < 0)
515 {
516 fprintf(stderr, "fat_create_fat() - BPB is not sane\n");
517 return -1;
518 }
519
520 if(bpb->bpb_fatsz16 != 0)
521 fatsz = bpb->bpb_fatsz16;
522 else
523 fatsz = bpb->bpb_fatsz32;
524
525 sec = fat_cache_fat_sector(bpb, secnum);
526 if(!sec)
527 {
528 fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector"
529 " (%d)\n", secnum);
530 return -1;
531 }
532
533 fat_cache_dirty[secnum] = 1;
534
535 /* First entry should have the media type in the
536 low byte and the rest of the bits set to 1.
537 The second should be the EOC mark. */
538 memset(sec, 0, BLOCK_SIZE);
539 sec[0] = bpb->bpb_media;
540 if(bpb->fat_type == FATTYPE_FAT12)
541 {
542 sec[1] = 0xff;
543 sec[2] = 0xff;
544 }
545 if(bpb->fat_type == FATTYPE_FAT16)
546 {
547 sec[0] = bpb->bpb_media;
548 sec[1] = 0xff;
549 sec[2] = 0xff;
550 sec[3] = 0xff;
551 }
552 secnum++;
553
554 for(i = 0; i < fatsz - 1;i++)
555 {
556 sec = fat_cache_fat_sector(bpb, secnum);
557 if(!sec)
558 {
559 fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector"
560 " (%d)\n", i);
561 return -1;
562 }
563 fat_cache_dirty[secnum] = 1;
564 secnum++;
565 memset(sec, 0, BLOCK_SIZE);
566 }
567
568 if(fat_flush_fat(bpb) < 0)
569 {
570 fprintf(stderr, "fat_create_fat() - Couldn't flush fat\n");
571 return -1;
572 }
573 return 0;
574}
575
576int fat_dbg_read_block(char *name, unsigned char *buf)
577{
578 FILE *f;
579
580 f = fopen(name, "rb");
581 if(f)
582 {
583 if(fread(buf, 1, 512, f) != 512)
584 {
585 fprintf(stderr, "Could not read file \"%s\"\n", name);
586 fclose(f);
587 return -1;
588 }
589 /* Now write the sector to disk */
590 ata_write_sectors(0,1,buf);
591 fclose(f);
592 }
593 else
594 {
595 fprintf(stderr, "Could not open file \"%s\"\n", name);
596 return -1;
597 }
598 return 0;
599}
600
601unsigned char *fat_cache_fat_sector(struct bpb *bpb, int secnum)
602{
603 unsigned char *sec;
604
605 sec = fat_cache[secnum];
606 /* Load the sector if it is not cached */
607 if(!sec)
608 {
609 sec = malloc(bpb->bpb_bytspersec);
610 if(!sec)
611 {
612 fprintf(stderr, "fat_cache_fat_sector() - Out of memory\n");
613 return NULL;
614 }
615 if(ata_read_sectors(secnum + bpb->bpb_rsvdseccnt,1,sec))
616 {
617 fprintf(stderr, "fat_cache_fat_sector() - Could"
618 " not read sector %d\n",
619 secnum);
620 free(sec);
621 return NULL;
622 }
623 fat_cache[secnum] = sec;
624 }
625 return sec;
626}
627
628int fat_update_entry(struct bpb *bpb, int entry, unsigned int val)
629{
630 unsigned char *sec;
631 unsigned char *sec2;
632 int fatsz;
633 int fatoffset;
634 int thisfatsecnum;
635 int thisfatentoffset;
636 unsigned int tmp;
637
638 fatsz = fat_get_fatsize(bpb);
639
640 if(bpb->fat_type == FATTYPE_FAT12)
641 {
642 fatoffset = entry + (entry / 2);
643 }
644 else
645 {
646 if(bpb->fat_type == FATTYPE_FAT16)
647 fatoffset = entry * 2;
648 else
649 fatoffset = entry * 4;
650 }
651 thisfatsecnum = fatoffset / bpb->bpb_bytspersec;
652 thisfatentoffset = fatoffset % bpb->bpb_bytspersec;
653
654 sec = fat_cache_fat_sector(bpb, thisfatsecnum);
655 /* Load the sector if it is not cached */
656 if(!sec)
657 {
658 fprintf(stderr, "fat_update_entry() - Could not cache sector %d\n",
659 thisfatsecnum);
660 return -1;
661 }
662
663 fat_cache_dirty[thisfatsecnum] = 1;
664
665 switch(bpb->fat_type)
666 {
667 case FATTYPE_FAT12:
668 if(thisfatentoffset == bpb->bpb_bytspersec - 1)
669 {
670 /* This entry spans a sector boundary. Take care */
671 sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1);
672 /* Load the sector if it is not cached */
673 if(!sec2)
674 {
675 fprintf(stderr, "fat_update_entry() - Could not "
676 "cache sector %d\n",
677 thisfatsecnum + 1);
678 return -1;
679 }
680 fat_cache_dirty[thisfatsecnum + 1] = 1;
681 }
682 else
683 {
684 if(entry & 1) /* Odd entry number? */
685 {
686 tmp = sec[thisfatentoffset] & 0xf0;
687 sec[thisfatentoffset] = tmp | (val & 0x0f);
688 sec[thisfatentoffset+1] = (val >> 4) & 0xff;
689 }
690 else
691 {
692 sec[thisfatentoffset] = val & 0xff;
693 tmp = sec[thisfatentoffset+1] & 0x0f;
694 sec[thisfatentoffset+1] = tmp | ((val >> 4) & 0xf0);
695 }
696 }
697 break;
698 case FATTYPE_FAT16:
699 *(unsigned short *)(&sec[thisfatentoffset]) = val;
700 break;
701 case FATTYPE_FAT32:
702 tmp = *(unsigned short *)(&sec[thisfatentoffset]) & 0xf000000;
703 val = tmp | (val & 0x0fffffff);
704 *(unsigned short *)(&sec[thisfatentoffset]) = val;
705 break;
706 }
707 return 0;
708}
709
710int fat_read_entry(struct bpb *bpb, int entry)
711{
712 unsigned char *sec;
713 unsigned char *sec2;
714 int fatsz;
715 int fatoffset;
716 int thisfatsecnum;
717 int thisfatentoffset;
718 int val = -1;
719
720 fatsz = fat_get_fatsize(bpb);
721
722 if(bpb->fat_type == FATTYPE_FAT12)
723 {
724 fatoffset = entry + (entry / 2);
725 }
726 else
727 {
728 if(bpb->fat_type == FATTYPE_FAT16)
729 fatoffset = entry * 2;
730 else
731 fatoffset = entry * 4;
732 }
733 thisfatsecnum = fatoffset / bpb->bpb_bytspersec;
734 thisfatentoffset = fatoffset % bpb->bpb_bytspersec;
735
736 sec = fat_cache_fat_sector(bpb, thisfatsecnum);
737 /* Load the sector if it is not cached */
738 if(!sec)
739 {
740 fprintf(stderr, "fat_update_entry() - Could not cache sector %d\n",
741 thisfatsecnum);
742 return -1;
743 }
744
745 switch(bpb->fat_type)
746 {
747 case FATTYPE_FAT12:
748 if(thisfatentoffset == bpb->bpb_bytspersec - 1)
749 {
750 /* This entry spans a sector boundary. Take care */
751 sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1);
752 /* Load the sector if it is not cached */
753 if(!sec2)
754 {
755 fprintf(stderr, "fat_update_entry() - Could not "
756 "cache sector %d\n",
757 thisfatsecnum + 1);
758 return -1;
759 }
760 }
761 else
762 {
763 if(entry & 1) /* Odd entry number? */
764 {
765 val = (sec[thisfatentoffset] & 0x0f) |
766 (sec[thisfatentoffset+1] << 4);
767 }
768 else
769 {
770 val = (sec[thisfatentoffset] & 0xff) |
771 ((sec[thisfatentoffset+1] & 0x0f) << 8);
772 }
773 }
774 break;
775 case FATTYPE_FAT16:
776 val = *(unsigned short *)(&sec[thisfatentoffset]);
777 break;
778 case FATTYPE_FAT32:
779 val = *(unsigned int *)(&sec[thisfatentoffset]);
780 break;
781 }
782 return val;
783}
784
785int fat_flush_fat(struct bpb *bpb)
786{
787 int i;
788 int err;
789 unsigned char *sec;
790 int fatsz;
791 unsigned short d, t;
792 char m;
793
794 fatsz = fat_get_fatsize(bpb);
795
796 for(i = 0;i < 256;i++)
797 {
798 if(fat_cache[i] && fat_cache_dirty[i])
799 {
800 printf("Flushing FAT sector %d\n", i);
801 sec = fat_cache[i];
802 err = ata_write_sectors(i + bpb->bpb_rsvdseccnt,1,sec);
803 if(err)
804 {
805 fprintf(stderr, "fat_flush_fat() - Couldn't write"
806 " sector (%d)\n", i + bpb->bpb_rsvdseccnt);
807 return -1;
808 }
809 err = ata_write_sectors(i + bpb->bpb_rsvdseccnt + fatsz,1,sec);
810 if(err)
811 {
812 fprintf(stderr, "fat_flush_fat() - Couldn't write"
813 " sector (%d)\n", i + bpb->bpb_rsvdseccnt + fatsz);
814 return -1;
815 }
816 fat_cache_dirty[i] = 0;
817 }
818 }
819
820 fat_getcurrdostime(&d, &t, &m);
821 return 0;
822}
823
824unsigned int fat_getcurrdostime(unsigned short *dosdate,
825 unsigned short *dostime,
826 unsigned char *dostenth)
827{
828 struct timeb tb;
829 struct tm *tm;
830
831 ftime(&tb);
832 tm = localtime(&tb.time);
833
834 *dosdate = ((tm->tm_year - 80) << 9) |
835 ((tm->tm_mon + 1) << 5) |
836 (tm->tm_mday);
837
838 *dostime = (tm->tm_hour << 11) |
839 (tm->tm_min << 5) |
840 (tm->tm_sec >> 1);
841
842 *dostenth = (tm->tm_sec & 1) * 100 + tb.millitm / 10;
843 return 0;
844}
845
846int fat_create_root_dir(struct bpb *bpb)
847{
848 unsigned char buf[BLOCK_SIZE];
849 int fatsz;
850 int sec;
851 int res;
852 int i;
853 unsigned short dosdate;
854 unsigned short dostime;
855 unsigned char dostenth;
856 int num_root_sectors;
857
858 fatsz = fat_get_fatsize(bpb);
859
860 sec = bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz;
861
862 memset(buf, 0, sizeof(buf));
863
864 strncpy(&buf[FATDIR_NAME], bpb->bs_vollab, 11);
865 buf[FATDIR_ATTR] = FAT_ATTR_VOLUME_ID;
866 buf[FATDIR_NTRES] = 0;
867
868 fat_getcurrdostime(&dosdate, &dostime, &dostenth);
869 buf[FATDIR_WRTDATE] = dosdate & 0xff;
870 buf[FATDIR_WRTDATE+1] = dosdate >> 8;
871 buf[FATDIR_WRTTIME] = dostime & 0xff;
872 buf[FATDIR_WRTTIME+1] = dostime >> 8;
873
874 printf("Writing rootdir to sector %d...\n", sec);
875
876 res = ata_write_sectors(sec,1,buf);
877 if(res)
878 {
879 fprintf(stderr, "fat_create_root_dir() - Couldn't write sector (%d)\n",
880 sec);
881 return -1;
882 }
883
884 printf("Clearing the rest of the root dir.\n");
885 sec++;
886 num_root_sectors = bpb->bpb_rootentcnt * 32 / bpb->bpb_bytspersec;
887 memset(buf, 0, BLOCK_SIZE);
888
889 for(i = 1;i < num_root_sectors;i++)
890 {
891 if(ata_write_sectors(sec++,1,buf))
892 {
893 fprintf(stderr, "fat_create_root_dir() - "
894 " Couldn't write sector (%d)\n", sec);
895 return -1;
896 }
897 }
898
899 return 0;
900}
901
902int fat_get_next_cluster(struct bpb *bpb, unsigned int cluster)
903{
904 int next_cluster = fat_read_entry(bpb, cluster);
905
906 if(fat_last_cluster_in_chain(bpb, next_cluster))
907 return 0;
908 else
909 return next_cluster;
910}
911
912int fat_add_dir_entry(struct bpb *bpb, unsigned int currdir,
913 struct fat_direntry *de)
914{
915 unsigned char buf[BLOCK_SIZE];
916 unsigned char *eptr;
917 int i;
918 int err;
919 unsigned int sec;
920 unsigned int sec_cnt;
921 int need_to_update_last_empty_marker = 0;
922 int is_rootdir = (currdir == 0);
923 int done = 0;
924 unsigned char firstbyte;
925
926 if(is_rootdir)
927 {
928 sec = fat_get_rootdir_sector(bpb);
929 }
930 else
931 {
932 sec = fat_first_sector_of_cluster(bpb, currdir);
933 }
934
935 sec_cnt = 0;
936
937 while(!done)
938 {
939 /* The root dir has a fixed size */
940 if(is_rootdir)
941 {
942 if(sec_cnt >= bpb->bpb_rootentcnt * 32 / bpb->bpb_bytspersec)
943 {
944 /* We have reached the last sector of the root dir */
945 if(need_to_update_last_empty_marker)
946 {
947 /* Since the directory is full, there is no room for
948 a marker, so we just exit */
949 return 0;
950 }
951 else
952 {
953 fprintf(stderr, "fat_add_dir_entry() -"
954 " Root dir is full\n");
955 return -1;
956 }
957 }
958 }
959 else
960 {
961 if(sec_cnt >= bpb->bpb_secperclus)
962 {
963 /* We have reached the end of this cluster */
964 printf("Moving to the next cluster...");
965 currdir = fat_get_next_cluster(bpb, currdir);
966 printf("new cluster is %d\n", currdir);
967
968 if(!currdir)
969 {
970 /* This was the last in the chain,
971 we have to allocate a new cluster */
972 /* TODO */
973 }
974 }
975 }
976
977 printf("Reading sector %d...\n", sec);
978 /* Read the next sector in the current dir */
979 err = ata_read_sectors(sec,1,buf);
980 if(err)
981 {
982 fprintf(stderr, "fat_add_dir_entry() - Couldn't read dir sector"
983 " (error code %i)\n", err);
984 return -1;
985 }
986
987 if(need_to_update_last_empty_marker)
988 {
989 /* All we need to do is to set the first entry to 0 */
990 printf("Clearing the first entry in sector %d\n", sec);
991 buf[0] = 0;
992 done = 1;
993 }
994 else
995 {
996 /* Look for a free slot */
997 for(i = 0;i < BLOCK_SIZE;i+=32)
998 {
999 firstbyte = buf[i];
1000 if(firstbyte == 0xe5 || firstbyte == 0)
1001 {
1002 printf("Found free slot at entry %d in sector %d\n",
1003 i/32, sec);
1004 eptr = &buf[i];
1005 memset(eptr, 0, 32);
1006 strncpy(&eptr[FATDIR_NAME], de->name, 11);
1007 eptr[FATDIR_ATTR] = de->attr;
1008 eptr[FATDIR_NTRES] = 0;
1009
1010 eptr[FATDIR_CRTTIMETENTH] = de->crttimetenth;
1011 eptr[FATDIR_CRTDATE] = de->crtdate & 0xff;
1012 eptr[FATDIR_CRTDATE+1] = de->crtdate >> 8;
1013 eptr[FATDIR_CRTTIME] = de->crttime & 0xff;
1014 eptr[FATDIR_CRTTIME+1] = de->crttime >> 8;
1015
1016 eptr[FATDIR_WRTDATE] = de->wrtdate & 0xff;
1017 eptr[FATDIR_WRTDATE+1] = de->wrtdate >> 8;
1018 eptr[FATDIR_WRTTIME] = de->wrttime & 0xff;
1019 eptr[FATDIR_WRTTIME+1] = de->wrttime >> 8;
1020
1021 eptr[FATDIR_FILESIZE] = de->filesize & 0xff;
1022 eptr[FATDIR_FILESIZE+1] = (de->filesize >> 8) & 0xff;
1023 eptr[FATDIR_FILESIZE+2] = (de->filesize >> 16) & 0xff;
1024 eptr[FATDIR_FILESIZE+3] = (de->filesize >> 24) & 0xff;
1025
1026 /* Advance the last_empty_entry marker */
1027 if(firstbyte == 0)
1028 {
1029 i += 32;
1030 if(i < BLOCK_SIZE)
1031 {
1032 buf[i] = 0;
1033 /* We are done */
1034 done = 1;
1035 }
1036 else
1037 {
1038 /* We must fill in the first entry
1039 in the next sector */
1040 need_to_update_last_empty_marker = 1;
1041 }
1042 }
1043
1044 err = ata_write_sectors(sec,1,buf);
1045 if(err)
1046 {
1047 fprintf(stderr, "fat_add_dir_entry() - "
1048 " Couldn't write dir"
1049 " sector (error code %i)\n", err);
1050 return -1;
1051 }
1052 break;
1053 }
1054 }
1055 }
1056 sec++;
1057 sec_cnt++;
1058 }
1059
1060 return 0;
1061}
1062
1063unsigned char fat_char2dos(unsigned char c)
1064{
1065 switch(c)
1066 {
1067 case 0xe5: /* Special kanji character */
1068 c = 0x05;
1069 break;
1070 case 0x22:
1071 case 0x2a:
1072 case 0x2b:
1073 case 0x2c:
1074 case 0x2e:
1075 case 0x3a:
1076 case 0x3b:
1077 case 0x3c:
1078 case 0x3d:
1079 case 0x3e:
1080 case 0x3f:
1081 case 0x5b:
1082 case 0x5c:
1083 case 0x5d:
1084 case 0x7c:
1085 /* Illegal name */
1086 c = 0;
1087 break;
1088
1089 default:
1090 if(c < 0x20)
1091 {
1092 /* Illegal name */
1093 c = 0;
1094 }
1095 break;
1096 }
1097 return c;
1098}
1099
1100int fat_create_dos_name(unsigned char *name, unsigned char *newname)
1101{
1102 unsigned char n[12];
1103 unsigned char c;
1104 int i;
1105 char *ext;
1106
1107 if(strlen(name) > 12)
1108 {
1109 return -1;
1110 }
1111
1112 strcpy(n, name);
1113
1114 ext = strchr(n, '.');
1115 if(ext)
1116 {
1117 *ext++ = 0;
1118 }
1119
1120 /* The file name is either empty, or there was only an extension.
1121 In either case it is illegal. */
1122 if(n[0] == 0)
1123 {
1124 return -1;
1125 }
1126
1127 /* Name part */
1128 for(i = 0;n[i] && (i < 8);i++)
1129 {
1130 c = fat_char2dos(n[i]);
1131 if(c)
1132 {
1133 newname[i] = toupper(c);
1134 }
1135 }
1136 while(i < 8)
1137 {
1138 newname[i++] = ' ';
1139 }
1140
1141 /* Extension part */
1142 for(i = 0;ext && ext[i] && (i < 3);i++)
1143 {
1144 c = fat_char2dos(ext[i]);
1145 if(c)
1146 {
1147 newname[8+i] = toupper(c);
1148 }
1149 }
1150 while(i < 3)
1151 {
1152 newname[8+i++] = ' ';
1153 }
1154 return 0;
1155}
1156
1157int fat_create_dir(struct bpb *bpb, unsigned int currdir, char *name)
1158{
1159 struct fat_direntry de;
1160 int err;
1161
1162 printf("fat_create_file()\n");
1163 memset(&de, 0, sizeof(struct fat_direntry));
1164 if(fat_create_dos_name(name, de.name) < 0)
1165 {
1166 fprintf(stderr, "fat_create_file() - Illegal file name (%s)\n", name);
1167 return -1;
1168 }
1169
1170 fat_getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth);
1171 de.wrtdate = de.crtdate;
1172 de.wrttime = de.crttime;
1173 de.filesize = 0;
1174 de.attr = FAT_ATTR_DIRECTORY;
1175
1176 err = fat_add_dir_entry(bpb, currdir, &de);
1177 return 0;
1178}
1179
1180int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name)
1181{
1182 struct fat_direntry de;
1183 int err;
1184
1185 printf("fat_create_file()\n");
1186 memset(&de, 0, sizeof(struct fat_direntry));
1187 if(fat_create_dos_name(name, de.name) < 0)
1188 {
1189 fprintf(stderr, "fat_create_file() - Illegal file name (%s)\n", name);
1190 return -1;
1191 }
1192 fat_getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth);
1193 de.wrtdate = de.crtdate;
1194 de.wrttime = de.crttime;
1195 de.filesize = 0;
1196
1197 err = fat_add_dir_entry(bpb, currdir, &de);
1198 return err;
1199}
1200
1201void fat_fill_direntry(struct fat_direntry *de, char *buf)
1202{
1203 memset(de, 0, sizeof(struct fat_direntry));
1204
1205 strncpy(de->name, &buf[FATDIR_NAME], 11);
1206 de->attr = buf[FATDIR_ATTR];
1207 de->crttimetenth = buf[FATDIR_CRTTIMETENTH];
1208 de->crtdate = buf[FATDIR_CRTDATE] | (buf[FATDIR_CRTDATE+1] << 8);
1209 de->crttime = buf[FATDIR_CRTTIME] | (buf[FATDIR_CRTTIME+1] << 8);
1210 de->wrtdate = buf[FATDIR_WRTDATE] | (buf[FATDIR_WRTDATE+1] << 8);
1211 de->wrttime = buf[FATDIR_WRTTIME] | (buf[FATDIR_WRTTIME+1] << 8);
1212
1213 de->filesize = buf[FATDIR_FILESIZE] |
1214 (buf[FATDIR_FILESIZE+1] << 8) |
1215 (buf[FATDIR_FILESIZE+2] << 16) |
1216 (buf[FATDIR_FILESIZE+3] << 24);
1217}
1218
1219int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir)
1220{
1221 int is_rootdir = (currdir == 0);
1222 unsigned int sec;
1223 int err;
1224
1225 if(is_rootdir)
1226 {
1227 sec = fat_get_rootdir_sector(bpb);
1228 }
1229 else
1230 {
1231 sec = fat_first_sector_of_cluster(bpb, currdir);
1232 }
1233
1234 /* Read the first sector in the current dir */
1235 err = ata_read_sectors(sec,1,ent->cached_buf);
1236 if(err)
1237 {
1238 fprintf(stderr, "fat_getfirst() - Couldn't read dir sector"
1239 " (error code %i)\n", err);
1240 return -1;
1241 }
1242
1243 ent->entry = 0;
1244 ent->cached_sec = sec;
1245 ent->num_sec = 0;
1246 return 0;
1247}
1248
1249int fat_getnext(struct bpb *bpb, struct fat_dirent *ent,
1250 struct fat_direntry *entry)
1251{
1252 int done = 0;
1253 int i;
1254 int err;
1255 unsigned char firstbyte;
1256
1257 while(!done)
1258 {
1259 /* Look for a free slot */
1260 for(i = ent->entry;i < BLOCK_SIZE/32;i++)
1261 {
1262 firstbyte = ent->cached_buf[i*32];
1263 if(firstbyte == 0xe5)
1264 {
1265 continue;
1266 }
1267
1268 if(firstbyte == 0)
1269 {
1270 return -1;
1271 }
1272
1273 fat_fill_direntry(entry, &ent->cached_buf[i*32]);
1274 done = 1;
1275 break;
1276 }
1277
1278 /* Next sector? */
1279 if(i >= BLOCK_SIZE/32)
1280 {
1281 ent->num_sec++;
1282 ent->cached_sec++;
1283
1284 /* Do we need to advance one cluster? */
1285 if(ent->num_sec >= bpb->bpb_secperclus)
1286 {
1287 ent->num_sec = 0;
1288 ent->cached_sec = fat_get_next_cluster(
1289 bpb, fat_sec2cluster(bpb, ent->cached_sec));
1290 if(!ent->cached_sec)
1291 {
1292 printf("End of cluster chain.\n");
1293 return -1;
1294 }
1295 }
1296
1297 /* Read the next sector */
1298 err = ata_read_sectors(ent->cached_sec,1,ent->cached_buf);
1299 if(err)
1300 {
1301 fprintf(stderr, "fat_getnext() - Couldn't read dir sector"
1302 " (error code %i)\n", err);
1303 return -1;
1304 }
1305
1306 i = 0;
1307 }
1308 else
1309 {
1310 i++;
1311 }
1312 ent->entry = i;
1313 }
1314 return 0;
1315}