From 0f03e3af3104a78d60f13e7eeb5b9ace12cc0bb3 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Mon, 29 Jan 2007 22:26:16 +0000 Subject: Changed fat_getnext(): 1) Fixed a bug where really long filenames could be messed up if they spanned 3 sectors 2) Now uses 2 buffers instead of 3, without copying the buffers with memcpy() 3) Can now use aligned sector reads, first step towards iPod 5.5G 80GB git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12151 a1c6a512-1295-4272-9138-f99709370657 --- firmware/drivers/fat.c | 108 +++++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 49 deletions(-) (limited to 'firmware/drivers/fat.c') diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index f9d116eba8..e6383787ca 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c @@ -16,6 +16,7 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "config.h" #include #include #include @@ -2158,6 +2159,7 @@ int fat_opendir(IF_MV2(int volume,) dir->entry = 0; dir->sector = 0; + dir->bufindex = 0; if (startcluster == 0) startcluster = fat_bpb->bpb_rootclus; @@ -2213,15 +2215,19 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) int longarray[20]; int longs=0; int sectoridx=0; - unsigned char* cached_buf = dir->sectorcache[0]; + /* Set the cache pointer to the sector buffer we are currently using */ + unsigned char* cached_buf = dir->sectorcache[dir->bufindex]; dir->entrycount = 0; while(!done) { - if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector ) + if ( !(dir->entry % (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS)) || + !dir->sector ) { - rc = fat_readwrite(&dir->file, 1, cached_buf, false); + /* Always read 2 sectors at a time */ + rc = fat_readwrite(&dir->file, FAT_DIR_BUFSECTORS, cached_buf, + false); if (rc == 0) { /* eof */ entry->name[0] = 0; @@ -2235,8 +2241,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) dir->sector = dir->file.lastsector; } - for (i = dir->entry % DIR_ENTRIES_PER_SECTOR; - i < DIR_ENTRIES_PER_SECTOR; i++) + for (i = dir->entry % (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS); + i < (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS); i++) { unsigned int entrypos = i * DIR_ENTRY_SIZE; @@ -2277,40 +2283,44 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) /* replace shortname with longname? */ if ( longs ) { int j; - /* This should be enough to hold any name segment utf8-encoded */ + /* This should be enough to hold any name segment + utf8-encoded */ unsigned char shortname[13]; /* 8+3+dot+\0 */ - unsigned char longname_utf8segm[6*4 + 1]; /* Add 1 for trailing \0 */ + /* Add 1 for trailing \0 */ + unsigned char longname_utf8segm[6*4 + 1]; int longname_utf8len = 0; - - strcpy(shortname, entry->name); /* Temporarily store it */ + + /* Store it temporarily */ + strcpy(shortname, entry->name); entry->name[0] = 0; /* iterate backwards through the dir entries */ for (j=longs-1; j>=0; j--) { - unsigned char* ptr = cached_buf; int index = longarray[j]; - /* current or cached sector? */ - if ( sectoridx >= SECTOR_SIZE ) { - if ( sectoridx >= SECTOR_SIZE*2 ) { - if ( ( index >= SECTOR_SIZE ) && - ( index < SECTOR_SIZE*2 )) - ptr = dir->sectorcache[1]; - else - ptr = dir->sectorcache[2]; - } - else { - if ( index < SECTOR_SIZE ) - ptr = dir->sectorcache[1]; - } - - index &= SECTOR_SIZE-1; + unsigned char* ptr; + + /* If we have spanned over 3 sectors, the current + buffer holds the last part and the other one + the first part. */ + if(sectoridx >= FAT_DIR_BUFSIZE) { + if(index / FAT_DIR_BUFSIZE > 0) + ptr = dir->sectorcache[dir->bufindex]; + else + ptr = dir->sectorcache[1 - dir->bufindex]; + } else { + ptr = dir->sectorcache[dir->bufindex]; } - /* Try to append each segment of the long name. Check if we'd - exceed the buffer. Also check for FAT padding characters 0xFFFF. */ + /* Let the index point into the selected + buffer */ + index &= FAT_DIR_BUFSIZE-1; + + /* Try to append each segment of the long name. + Check if we'd exceed the buffer. Also check for + FAT padding characters 0xFFFF. */ if (fat_copy_long_name_segment(ptr + index + 1, 5, - longname_utf8segm) == 0) break; - // logf("SG: %s, EN: %s", longname_utf8segm, entry->name); + longname_utf8segm) == 0) + break; longname_utf8len += strlen(longname_utf8segm); if (longname_utf8len < FAT_FILENAME_BYTES) strcat(entry->name, longname_utf8segm); @@ -2318,8 +2328,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) break; if (fat_copy_long_name_segment(ptr + index + 14, 6, - longname_utf8segm) == 0) break; - // logf("SG: %s, EN: %s", longname_utf8segm, entry->name); + longname_utf8segm) == 0) + break; longname_utf8len += strlen(longname_utf8segm); if (longname_utf8len < FAT_FILENAME_BYTES) strcat(entry->name, longname_utf8segm); @@ -2327,8 +2337,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) break; if (fat_copy_long_name_segment(ptr + index + 28, 2, - longname_utf8segm) == 0) break; - // logf("SG: %s, EN: %s", longname_utf8segm, entry->name); + longname_utf8segm) == 0) + break; longname_utf8len += strlen(longname_utf8segm); if (longname_utf8len < FAT_FILENAME_BYTES) strcat(entry->name, longname_utf8segm); @@ -2338,19 +2348,18 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) /* Does the utf8-encoded name fit into the entry? */ if (longname_utf8len >= FAT_FILENAME_BYTES) { - /* Take the short DOS name. Need to utf8-encode it since - it may contain chars from the upper half of the OEM - code page which wouldn't be a valid utf8. Beware: this - file will be shown with strange glyphs in file browser - since unicode 0x80 to 0x9F are control characters. */ + /* Take the short DOS name. Need to utf8-encode it + since it may contain chars from the upper half + of the OEM code page which wouldn't be a valid + utf8. Beware: this file will be shown with + strange glyphs in file browser since unicode + 0x80 to 0x9F are control characters. */ logf("SN-DOS: %s", shortname); unsigned char *utf8; - utf8 = iso_decode(shortname, entry->name, -1, strlen(shortname)); - *utf8 = 0; + utf8 = iso_decode(shortname, entry->name, -1, + strlen(shortname)); + *utf8 = 0; logf("SN: %s", entry->name); - } else { - // logf("LN: %s", entry->name); - // logf("LNLen: %d (%c)", longname_utf8len, entry->name[0]); } } done = true; @@ -2361,13 +2370,14 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) } } - /* save this sector, for longname use */ - if ( sectoridx ) - memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE ); - else - memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE ); - sectoridx += SECTOR_SIZE; + /* Did the name span across a buffer boundary? + Then we need to fill the second buffer as well and continue. */ + if(!done) { + sectoridx += FAT_DIR_BUFSIZE; + dir->bufindex = 1 - dir->bufindex; + cached_buf = dir->sectorcache[dir->bufindex]; + } } return 0; } -- cgit v1.2.3