summaryrefslogtreecommitdiff
path: root/firmware/drivers/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/fat.c')
-rw-r--r--firmware/drivers/fat.c209
1 files changed, 115 insertions, 94 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index 5cc47be2cf..5ca422063b 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -106,9 +106,9 @@
106#define FAT_EOF_MARK 0x0ffffff8 106#define FAT_EOF_MARK 0x0ffffff8
107 107
108struct fsinfo { 108struct fsinfo {
109 int freecount; /* last known free cluster count */ 109 unsigned int freecount; /* last known free cluster count */
110 int nextfree; /* first cluster to start looking for free clusters, 110 unsigned int nextfree; /* first cluster to start looking for free
111 or 0xffffffff for no hint */ 111 clusters, or 0xffffffff for no hint */
112}; 112};
113/* fsinfo offsets */ 113/* fsinfo offsets */
114#define FSINFO_FREECOUNT 488 114#define FSINFO_FREECOUNT 488
@@ -118,7 +118,7 @@ struct bpb
118{ 118{
119 char bs_oemname[9]; /* OEM string, ending with \0 */ 119 char bs_oemname[9]; /* OEM string, ending with \0 */
120 int bpb_bytspersec; /* Bytes per sectory, typically 512 */ 120 int bpb_bytspersec; /* Bytes per sectory, typically 512 */
121 int bpb_secperclus; /* Sectors per cluster */ 121 unsigned int bpb_secperclus; /* Sectors per cluster */
122 int bpb_rsvdseccnt; /* Number of reserved sectors */ 122 int bpb_rsvdseccnt; /* Number of reserved sectors */
123 int bpb_numfats; /* Number of FAT structures, typically 2 */ 123 int bpb_numfats; /* Number of FAT structures, typically 2 */
124 int bpb_rootentcnt; /* Number of dir entries in the root */ 124 int bpb_rootentcnt; /* Number of dir entries in the root */
@@ -148,12 +148,12 @@ struct bpb
148 int bpb_bkbootsec; 148 int bpb_bkbootsec;
149 149
150 /* variables for internal use */ 150 /* variables for internal use */
151 int fatsize; 151 unsigned int fatsize;
152 int totalsectors; 152 unsigned int totalsectors;
153 int rootdirsector; 153 unsigned int rootdirsector;
154 int firstdatasector; 154 unsigned int firstdatasector;
155 int startsector; 155 unsigned int startsector;
156 int dataclusters; 156 unsigned int dataclusters;
157 struct fsinfo fsinfo; 157 struct fsinfo fsinfo;
158}; 158};
159 159
@@ -187,7 +187,7 @@ static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE];
187static unsigned char lastsector[SECTOR_SIZE]; 187static unsigned char lastsector[SECTOR_SIZE];
188static unsigned char lastsector2[SECTOR_SIZE]; 188static unsigned char lastsector2[SECTOR_SIZE];
189 189
190static int sec2cluster(int sec) 190static int sec2cluster(unsigned int sec)
191{ 191{
192 if ( sec < fat_bpb.firstdatasector ) 192 if ( sec < fat_bpb.firstdatasector )
193 { 193 {
@@ -236,7 +236,7 @@ int fat_mount(int startsector)
236 unsigned char buf[SECTOR_SIZE]; 236 unsigned char buf[SECTOR_SIZE];
237 int err; 237 int err;
238 int datasec; 238 int datasec;
239 int i; 239 unsigned int i;
240 240
241 for(i = 0;i < FAT_CACHE_SIZE;i++) 241 for(i = 0;i < FAT_CACHE_SIZE;i++)
242 { 242 {
@@ -336,7 +336,30 @@ int fat_mount(int startsector)
336 } 336 }
337 fat_bpb.fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT); 337 fat_bpb.fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT);
338 fat_bpb.fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE); 338 fat_bpb.fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
339 LDEBUGF("Freecount: %x\n",fat_bpb.fsinfo.freecount); 339
340 /* calculate freecount if unset */
341 if ( fat_bpb.fsinfo.freecount == 0xffffffff )
342 {
343 int free = 0;
344 for (i = 0; i<fat_bpb.fatsize; i++) {
345 unsigned int j;
346 unsigned int* fat = cache_fat_sector(i);
347 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
348 unsigned int c = i * CLUSTERS_PER_FAT_SECTOR + j;
349 if ( c > fat_bpb.dataclusters+1 ) /* nr 0 is unused */
350 break;
351
352 if (!(SWAB32(fat[j]) & 0x0fffffff)) {
353 free++;
354 if ( fat_bpb.fsinfo.nextfree == 0xffffffff )
355 fat_bpb.fsinfo.nextfree = c;
356 }
357 }
358 }
359 fat_bpb.fsinfo.freecount = free;
360 }
361
362 LDEBUGF("Freecount: %d\n",fat_bpb.fsinfo.freecount);
340 LDEBUGF("Nextfree: %x\n",fat_bpb.fsinfo.nextfree); 363 LDEBUGF("Nextfree: %x\n",fat_bpb.fsinfo.nextfree);
341 LDEBUGF("Cluster count: %x\n",fat_bpb.dataclusters); 364 LDEBUGF("Cluster count: %x\n",fat_bpb.dataclusters);
342 LDEBUGF("Sectors per cluster: %d\n",fat_bpb.bpb_secperclus); 365 LDEBUGF("Sectors per cluster: %d\n",fat_bpb.bpb_secperclus);
@@ -450,22 +473,22 @@ static unsigned int find_free_cluster(unsigned int startcluster)
450{ 473{
451 unsigned int sector = startcluster / CLUSTERS_PER_FAT_SECTOR; 474 unsigned int sector = startcluster / CLUSTERS_PER_FAT_SECTOR;
452 unsigned int offset = startcluster % CLUSTERS_PER_FAT_SECTOR; 475 unsigned int offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
453 int i; 476 unsigned int i;
454 477
455 /* don't waste time scanning if the disk is already full */ 478 /* don't waste time scanning if the disk is already full */
456 if (!fat_bpb.fsinfo.freecount) 479 if (!fat_bpb.fsinfo.freecount)
457 return 0; 480 return 0;
458 481
459 for (i = 0; i<fat_bpb.fatsize; i++) { 482 for (i = 0; i<fat_bpb.fatsize; i++) {
460 int j; 483 unsigned int j;
461 int nr = (i + sector) % fat_bpb.fatsize; 484 unsigned int nr = (i + sector) % fat_bpb.fatsize;
462 unsigned int* fat = cache_fat_sector(nr); 485 unsigned int* fat = cache_fat_sector(nr);
463 if ( !fat ) 486 if ( !fat )
464 break; 487 break;
465 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) { 488 for (j = 0; j < CLUSTERS_PER_FAT_SECTOR; j++) {
466 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR; 489 int k = (j + offset) % CLUSTERS_PER_FAT_SECTOR;
467 if (!(SWAB32(fat[k]) & 0x0fffffff)) { 490 if (!(SWAB32(fat[k]) & 0x0fffffff)) {
468 int c = nr * CLUSTERS_PER_FAT_SECTOR + k; 491 unsigned int c = nr * CLUSTERS_PER_FAT_SECTOR + k;
469 if ( c > fat_bpb.dataclusters+1 ) /* nr 0 is unused */ 492 if ( c > fat_bpb.dataclusters+1 ) /* nr 0 is unused */
470 continue; 493 continue;
471 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c); 494 LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
@@ -646,42 +669,41 @@ static int add_dir_entry(struct fat_dir* dir,
646{ 669{
647 unsigned char buf[SECTOR_SIZE]; 670 unsigned char buf[SECTOR_SIZE];
648 int err; 671 int err;
649 int sector=0; 672 unsigned int sector;
650 bool update_last = false; 673 bool update_last = false;
651 bool done = false; 674 bool done = false;
652 bool eof = false; 675 bool eof = false;
653 676
654 LDEBUGF( "add_dir_entry(%x,%s,%x)\n", 677 LDEBUGF( "add_dir_entry(%s,%x)\n",
655 dir->startcluster, de->name, file->firstcluster); 678 de->name, file->firstcluster);
656 679
657 err=fat_seek(&dir->file, 0); 680 err=fat_seek(&dir->file, 0);
658 if (err<0) 681 if (err<0)
659 return -1; 682 return -1;
660 683
661 while(!done) 684 for (sector=0; !done; sector++)
662 { 685 {
663 err = 0; 686 err = 0;
664 if (!eof) { 687 if (!eof) {
665 err = fat_readwrite(&dir->file, 1, buf, false); 688 err = fat_readwrite(&dir->file, 1, buf, false);
666 sector++;
667 } 689 }
668 if (err==0) { 690 if (err==0) {
669 /* eof: add new sector */ 691 /* eof: add new sector */
670 eof = true; 692 eof = true;
671 693
672 /* don't add a new sector only for the last-entry marker */
673 if (update_last)
674 break;
675
676 memset(buf, 0, sizeof buf); 694 memset(buf, 0, sizeof buf);
677 LDEBUGF("Adding new sector to dir\n"); 695 LDEBUGF("Adding new sector to dir\n");
678 err=fat_seek(&dir->file, sector-1); 696 err=fat_seek(&dir->file, sector);
679 if (err<0) 697 if (err<0)
680 return -2; 698 return -5;
681 err = fat_readwrite(&dir->file, 1, buf, true); 699
682 if (err<1) 700 /* add sectors (we must clear the whole cluster) */
683 return -3; 701 do {
684 } 702 err = fat_readwrite(&dir->file, 1, buf, true);
703 if (err<1)
704 return -3;
705 } while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus);
706 }
685 if (err<0) { 707 if (err<0) {
686 DEBUGF( "add_dir_entry() - Couldn't read dir" 708 DEBUGF( "add_dir_entry() - Couldn't read dir"
687 " (error code %d)\n", err); 709 " (error code %d)\n", err);
@@ -690,24 +712,23 @@ static int add_dir_entry(struct fat_dir* dir,
690 712
691 if (update_last) 713 if (update_last)
692 { 714 {
693 /* All we need to do is to set the first entry to 0 */ 715 /* buffer is already cleared,
694 LDEBUGF("Clearing the first entry in sector %d\n", sector); 716 we just need to flag for sector update */
695 buf[0] = 0;
696 done = true; 717 done = true;
697 } 718 }
698 else 719 else
699 { 720 {
700 int i; 721 unsigned int i;
701 /* Look for a free slot */ 722 /* Look for a free slot */
702 for (i = 0; i < SECTOR_SIZE; i += DIR_ENTRY_SIZE) 723 for (i = 0; i < DIR_ENTRIES_PER_SECTOR; i++)
703 { 724 {
704 unsigned char firstbyte = buf[i]; 725 unsigned char firstbyte = buf[i*DIR_ENTRY_SIZE];
705 if (firstbyte == 0xe5 || firstbyte == 0) 726 if (firstbyte == 0xe5 || firstbyte == 0)
706 { 727 {
707 unsigned char* eptr; 728 unsigned char* eptr;
708 LDEBUGF("Found free entry %d in sector %d\n", 729 LDEBUGF("Found free entry %d in sector %d (%x)\n",
709 i/DIR_ENTRY_SIZE, sector); 730 i, sector, dir->file.lastsector);
710 eptr = &buf[i]; 731 eptr = &buf[i*DIR_ENTRY_SIZE];
711 memset(eptr, 0, DIR_ENTRY_SIZE); 732 memset(eptr, 0, DIR_ENTRY_SIZE);
712 strncpy(&eptr[FATDIR_NAME], de->name, 11); 733 strncpy(&eptr[FATDIR_NAME], de->name, 11);
713 eptr[FATDIR_ATTR] = de->attr; 734 eptr[FATDIR_ATTR] = de->attr;
@@ -715,16 +736,16 @@ static int add_dir_entry(struct fat_dir* dir,
715 736
716 /* remember where the dir entry is located */ 737 /* remember where the dir entry is located */
717 file->dirsector = dir->file.lastsector; 738 file->dirsector = dir->file.lastsector;
718 file->direntry = i/DIR_ENTRY_SIZE; 739 file->direntry = i;
719 740
720 /* Advance the last_empty_entry marker */ 741 /* advance the last_empty_entry marker? */
721 if (firstbyte == 0) 742 if (firstbyte == 0)
722 { 743 {
723 i += DIR_ENTRY_SIZE; 744 i++;
724 if (i < SECTOR_SIZE) 745 if (i < DIR_ENTRIES_PER_SECTOR)
725 { 746 {
726 buf[i] = 0; 747 /* next entry is now last */
727 /* We are done */ 748 buf[i*DIR_ENTRY_SIZE] = 0;
728 done = true; 749 done = true;
729 } 750 }
730 else 751 else
@@ -737,17 +758,19 @@ static int add_dir_entry(struct fat_dir* dir,
737 } 758 }
738 else 759 else
739 done = true; 760 done = true;
740
741 err=fat_seek(&dir->file, sector-1);
742 if (err<0)
743 return -5;
744 err = fat_readwrite(&dir->file, 1, buf, true);
745 if (err<1)
746 return -6;
747 break; 761 break;
748 } 762 }
749 } 763 }
750 } 764 }
765 if (done || update_last) {
766 /* update sector */
767 err=fat_seek(&dir->file, sector);
768 if (err<0)
769 return -5;
770 err = fat_readwrite(&dir->file, 1, buf, true);
771 if (err<1)
772 return -6;
773 }
751 } 774 }
752 775
753 return 0; 776 return 0;
@@ -852,7 +875,7 @@ static int update_file_size( struct fat_file* file, int size )
852 int err; 875 int err;
853 876
854 LDEBUGF("update_file_size(cluster:%x entry:%d sector:%x size:%d)\n", 877 LDEBUGF("update_file_size(cluster:%x entry:%d sector:%x size:%d)\n",
855 file->firstcluster,file->direntry,sector,size); 878 file->firstcluster, file->direntry, file->dirsector, size);
856 879
857 if ( file->direntry >= DIR_ENTRIES_PER_SECTOR ) 880 if ( file->direntry >= DIR_ENTRIES_PER_SECTOR )
858 panicf("update_file_size(): Illegal entry %d!\n",file->direntry); 881 panicf("update_file_size(): Illegal entry %d!\n",file->direntry);
@@ -931,7 +954,7 @@ int fat_open(unsigned int startcluster,
931 954
932 /* remember where the file's dir entry is located */ 955 /* remember where the file's dir entry is located */
933 if ( dir ) { 956 if ( dir ) {
934 file->dirsector = dir->cached_sec; 957 file->dirsector = dir->sector;
935 file->direntry = dir->entry - 1; 958 file->direntry = dir->entry - 1;
936 } 959 }
937 LDEBUGF("fat_open(%x), entry %d\n",startcluster,file->direntry); 960 LDEBUGF("fat_open(%x), entry %d\n",startcluster,file->direntry);
@@ -1089,7 +1112,7 @@ static int next_write_cluster(struct fat_file* file,
1089 return cluster; 1112 return cluster;
1090} 1113}
1091 1114
1092static bool transfer( int start, int count, char* buf, bool write ) 1115static bool transfer( unsigned int start, int count, char* buf, bool write )
1093{ 1116{
1094 int err; 1117 int err;
1095 1118
@@ -1132,7 +1155,7 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
1132 /* find sequential sectors and write them all at once */ 1155 /* find sequential sectors and write them all at once */
1133 for (i=0; (i < sectorcount) && (sector > -1); i++ ) { 1156 for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
1134 numsec++; 1157 numsec++;
1135 if ( numsec > fat_bpb.bpb_secperclus || !cluster ) { 1158 if ( numsec > (int)fat_bpb.bpb_secperclus || !cluster ) {
1136 int oldcluster = cluster; 1159 int oldcluster = cluster;
1137 if (write) 1160 if (write)
1138 cluster = next_write_cluster(file, cluster, &sector); 1161 cluster = next_write_cluster(file, cluster, &sector);
@@ -1217,7 +1240,8 @@ int fat_seek(struct fat_file *file, unsigned int seeksector )
1217 for (i=0; i<clusternum; i++) { 1240 for (i=0; i<clusternum; i++) {
1218 cluster = get_next_cluster(cluster); 1241 cluster = get_next_cluster(cluster);
1219 if (!cluster) { 1242 if (!cluster) {
1220 DEBUGF("Seeking beyond the end of the file!\n"); 1243 DEBUGF("Seeking beyond the end of the file! "
1244 "(sector %d, cluster %d)\n", seeksector, i);
1221 return -1; 1245 return -1;
1222 } 1246 }
1223 } 1247 }
@@ -1252,14 +1276,8 @@ int fat_opendir(struct fat_dir *dir, unsigned int startcluster)
1252 return -1; 1276 return -1;
1253 } 1277 }
1254 1278
1255 err = fat_readwrite(&dir->file, 1, dir->cached_buf, false);
1256 if (err<1)
1257 return -2;
1258
1259 dir->entry = 0; 1279 dir->entry = 0;
1260 dir->cached_sec = dir->file.lastsector; 1280 dir->sector = 0;
1261 dir->num_sec = 0;
1262 dir->startcluster = startcluster;
1263 1281
1264 return 0; 1282 return 0;
1265} 1283}
@@ -1273,12 +1291,34 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
1273 int longarray[20]; 1291 int longarray[20];
1274 int longs=0; 1292 int longs=0;
1275 int sectoridx=0; 1293 int sectoridx=0;
1294 static unsigned char cached_buf[SECTOR_SIZE];
1276 1295
1277 while(!done) 1296 while(!done)
1278 { 1297 {
1279 for (i = dir->entry; i < SECTOR_SIZE/DIR_ENTRY_SIZE; i++) 1298 if ( dir->entry >= DIR_ENTRIES_PER_SECTOR || !dir->sector )
1299 {
1300 err = fat_readwrite(&dir->file, 1, cached_buf, false);
1301 if (err==0) {
1302 /* eof */
1303 entry->name[0] = 0;
1304 break;
1305 }
1306 if (err<0) {
1307 DEBUGF( "fat_getnext() - Couldn't read dir"
1308 " (error code %d)\n", err);
1309 return -1;
1310 }
1311 dir->sector = dir->file.lastsector;
1312 dir->entry = 0;
1313 }
1314
1315 for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
1316 i < DIR_ENTRIES_PER_SECTOR; i++)
1280 { 1317 {
1281 firstbyte = dir->cached_buf[i*DIR_ENTRY_SIZE]; 1318 unsigned int entrypos = i * DIR_ENTRY_SIZE;
1319
1320 firstbyte = cached_buf[entrypos];
1321 dir->entry++;
1282 1322
1283 if (firstbyte == 0xe5) { 1323 if (firstbyte == 0xe5) {
1284 /* free entry */ 1324 /* free entry */
@@ -1293,13 +1333,13 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
1293 } 1333 }
1294 1334
1295 /* longname entry? */ 1335 /* longname entry? */
1296 if ( ( dir->cached_buf[i*DIR_ENTRY_SIZE + FATDIR_ATTR] & 1336 if ( ( cached_buf[entrypos + FATDIR_ATTR] &
1297 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) { 1337 FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {
1298 longarray[longs++] = i*DIR_ENTRY_SIZE + sectoridx; 1338 longarray[longs++] = entrypos + sectoridx;
1299 } 1339 }
1300 else { 1340 else {
1301 if ( parse_direntry(entry, 1341 if ( parse_direntry(entry,
1302 &dir->cached_buf[i*DIR_ENTRY_SIZE]) ) { 1342 &cached_buf[entrypos]) ) {
1303 1343
1304 /* don't return volume id entry */ 1344 /* don't return volume id entry */
1305 if ( entry->attr == FAT_ATTR_VOLUME_ID ) 1345 if ( entry->attr == FAT_ATTR_VOLUME_ID )
@@ -1310,7 +1350,7 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
1310 int j,k,l=0; 1350 int j,k,l=0;
1311 /* iterate backwards through the dir entries */ 1351 /* iterate backwards through the dir entries */
1312 for (j=longs-1; j>=0; j--) { 1352 for (j=longs-1; j>=0; j--) {
1313 unsigned char* ptr = dir->cached_buf; 1353 unsigned char* ptr = cached_buf;
1314 int index = longarray[j]; 1354 int index = longarray[j];
1315 /* current or cached sector? */ 1355 /* current or cached sector? */
1316 if ( sectoridx >= SECTOR_SIZE ) { 1356 if ( sectoridx >= SECTOR_SIZE ) {
@@ -1342,6 +1382,7 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
1342 } 1382 }
1343 done = true; 1383 done = true;
1344 sectoridx = 0; 1384 sectoridx = 0;
1385 i++;
1345 break; 1386 break;
1346 } 1387 }
1347 } 1388 }
@@ -1349,31 +1390,11 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
1349 1390
1350 /* save this sector, for longname use */ 1391 /* save this sector, for longname use */
1351 if ( sectoridx ) 1392 if ( sectoridx )
1352 memcpy( lastsector2, dir->cached_buf, SECTOR_SIZE ); 1393 memcpy( lastsector2, cached_buf, SECTOR_SIZE );
1353 else 1394 else
1354 memcpy( lastsector, dir->cached_buf, SECTOR_SIZE ); 1395 memcpy( lastsector, cached_buf, SECTOR_SIZE );
1355 sectoridx += SECTOR_SIZE; 1396 sectoridx += SECTOR_SIZE;
1356 1397
1357 if ( i < SECTOR_SIZE/DIR_ENTRY_SIZE ) {
1358 i++;
1359 }
1360 else {
1361 err = fat_readwrite(&dir->file, 1, dir->cached_buf, false);
1362 if (err==0) {
1363 /* eof */
1364 entry->name[0] = 0;
1365 return 0;
1366 }
1367 if (err<0) {
1368 DEBUGF( "fat_getnext() - Couldn't read dir"
1369 " (error code %d)\n", err);
1370 return -1;
1371 }
1372 i = 0;
1373 dir->cached_sec = dir->file.lastsector;
1374 }
1375
1376 dir->entry = i;
1377 } 1398 }
1378 return 0; 1399 return 0;
1379} 1400}