1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Linus Nielsen Feltzing 2007-01-29 22:26:16 +00:00
parent 1bb3d2601f
commit 0f03e3af31
2 changed files with 65 additions and 49 deletions

View file

@ -16,6 +16,7 @@
* KIND, either express or implied. * KIND, either express or implied.
* *
****************************************************************************/ ****************************************************************************/
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -2158,6 +2159,7 @@ int fat_opendir(IF_MV2(int volume,)
dir->entry = 0; dir->entry = 0;
dir->sector = 0; dir->sector = 0;
dir->bufindex = 0;
if (startcluster == 0) if (startcluster == 0)
startcluster = fat_bpb->bpb_rootclus; startcluster = fat_bpb->bpb_rootclus;
@ -2213,15 +2215,19 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
int longarray[20]; int longarray[20];
int longs=0; int longs=0;
int sectoridx=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; dir->entrycount = 0;
while(!done) 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) { if (rc == 0) {
/* eof */ /* eof */
entry->name[0] = 0; entry->name[0] = 0;
@ -2235,8 +2241,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
dir->sector = dir->file.lastsector; dir->sector = dir->file.lastsector;
} }
for (i = dir->entry % DIR_ENTRIES_PER_SECTOR; for (i = dir->entry % (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS);
i < DIR_ENTRIES_PER_SECTOR; i++) i < (DIR_ENTRIES_PER_SECTOR*FAT_DIR_BUFSECTORS); i++)
{ {
unsigned int entrypos = i * DIR_ENTRY_SIZE; 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? */ /* replace shortname with longname? */
if ( longs ) { if ( longs ) {
int j; 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 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; int longname_utf8len = 0;
strcpy(shortname, entry->name); /* Temporarily store it */ /* Store it temporarily */
strcpy(shortname, entry->name);
entry->name[0] = 0; entry->name[0] = 0;
/* iterate backwards through the dir entries */ /* iterate backwards through the dir entries */
for (j=longs-1; j>=0; j--) { for (j=longs-1; j>=0; j--) {
unsigned char* ptr = cached_buf;
int index = longarray[j]; int index = longarray[j];
/* current or cached sector? */ unsigned char* ptr;
if ( sectoridx >= SECTOR_SIZE ) {
if ( sectoridx >= SECTOR_SIZE*2 ) { /* If we have spanned over 3 sectors, the current
if ( ( index >= SECTOR_SIZE ) && buffer holds the last part and the other one
( index < SECTOR_SIZE*2 )) the first part. */
ptr = dir->sectorcache[1]; if(sectoridx >= FAT_DIR_BUFSIZE) {
if(index / FAT_DIR_BUFSIZE > 0)
ptr = dir->sectorcache[dir->bufindex];
else else
ptr = dir->sectorcache[2]; ptr = dir->sectorcache[1 - dir->bufindex];
} } else {
else { ptr = dir->sectorcache[dir->bufindex];
if ( index < SECTOR_SIZE )
ptr = dir->sectorcache[1];
} }
index &= SECTOR_SIZE-1; /* 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 /* Try to append each segment of the long name.
exceed the buffer. Also check for FAT padding characters 0xFFFF. */ Check if we'd exceed the buffer. Also check for
FAT padding characters 0xFFFF. */
if (fat_copy_long_name_segment(ptr + index + 1, 5, if (fat_copy_long_name_segment(ptr + index + 1, 5,
longname_utf8segm) == 0) break; longname_utf8segm) == 0)
// logf("SG: %s, EN: %s", longname_utf8segm, entry->name); break;
longname_utf8len += strlen(longname_utf8segm); longname_utf8len += strlen(longname_utf8segm);
if (longname_utf8len < FAT_FILENAME_BYTES) if (longname_utf8len < FAT_FILENAME_BYTES)
strcat(entry->name, longname_utf8segm); strcat(entry->name, longname_utf8segm);
@ -2318,8 +2328,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
break; break;
if (fat_copy_long_name_segment(ptr + index + 14, 6, if (fat_copy_long_name_segment(ptr + index + 14, 6,
longname_utf8segm) == 0) break; longname_utf8segm) == 0)
// logf("SG: %s, EN: %s", longname_utf8segm, entry->name); break;
longname_utf8len += strlen(longname_utf8segm); longname_utf8len += strlen(longname_utf8segm);
if (longname_utf8len < FAT_FILENAME_BYTES) if (longname_utf8len < FAT_FILENAME_BYTES)
strcat(entry->name, longname_utf8segm); strcat(entry->name, longname_utf8segm);
@ -2327,8 +2337,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
break; break;
if (fat_copy_long_name_segment(ptr + index + 28, 2, if (fat_copy_long_name_segment(ptr + index + 28, 2,
longname_utf8segm) == 0) break; longname_utf8segm) == 0)
// logf("SG: %s, EN: %s", longname_utf8segm, entry->name); break;
longname_utf8len += strlen(longname_utf8segm); longname_utf8len += strlen(longname_utf8segm);
if (longname_utf8len < FAT_FILENAME_BYTES) if (longname_utf8len < FAT_FILENAME_BYTES)
strcat(entry->name, longname_utf8segm); 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? */ /* Does the utf8-encoded name fit into the entry? */
if (longname_utf8len >= FAT_FILENAME_BYTES) { if (longname_utf8len >= FAT_FILENAME_BYTES) {
/* Take the short DOS name. Need to utf8-encode it since /* Take the short DOS name. Need to utf8-encode it
it may contain chars from the upper half of the OEM since it may contain chars from the upper half
code page which wouldn't be a valid utf8. Beware: this of the OEM code page which wouldn't be a valid
file will be shown with strange glyphs in file browser utf8. Beware: this file will be shown with
since unicode 0x80 to 0x9F are control characters. */ strange glyphs in file browser since unicode
0x80 to 0x9F are control characters. */
logf("SN-DOS: %s", shortname); logf("SN-DOS: %s", shortname);
unsigned char *utf8; unsigned char *utf8;
utf8 = iso_decode(shortname, entry->name, -1, strlen(shortname)); utf8 = iso_decode(shortname, entry->name, -1,
strlen(shortname));
*utf8 = 0; *utf8 = 0;
logf("SN: %s", entry->name); logf("SN: %s", entry->name);
} else {
// logf("LN: %s", entry->name);
// logf("LNLen: %d (%c)", longname_utf8len, entry->name[0]);
} }
} }
done = true; done = true;
@ -2361,13 +2370,14 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
} }
} }
/* save this sector, for longname use */ /* Did the name span across a buffer boundary?
if ( sectoridx ) Then we need to fill the second buffer as well and continue. */
memcpy( dir->sectorcache[2], dir->sectorcache[0], SECTOR_SIZE ); if(!done) {
else sectoridx += FAT_DIR_BUFSIZE;
memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE );
sectoridx += SECTOR_SIZE;
dir->bufindex = 1 - dir->bufindex;
cached_buf = dir->sectorcache[dir->bufindex];
}
} }
return 0; return 0;
} }

View file

@ -73,13 +73,19 @@ struct fat_file
#endif #endif
}; };
#define FAT_DIR_BUFSECTORS 2 /* Needs to be an even number, at least 2 */
#define FAT_DIR_BUFSIZE (SECTOR_SIZE*FAT_DIR_BUFSECTORS)
struct fat_dir struct fat_dir
{ {
unsigned int entry; unsigned int entry;
unsigned int entrycount; unsigned int entrycount;
long sector; long sector;
struct fat_file file; struct fat_file file;
unsigned char sectorcache[3][SECTOR_SIZE]; /* The buffer needs to be at least 3 sectors, so we make it 2*2 and
alternate between them */
unsigned char sectorcache[2][FAT_DIR_BUFSIZE];
unsigned int bufindex; /* Which buffer to be loaded next */
}; };