1
0
Fork 0
forked from len0rd/rockbox

Added longname handling to fat_remove().

Added proper 0xffff padding of last longname entry.
add_dir_entry() now makes sure shortname is unique.
Changed update_file_size() to use dir-as-file handling.
Simplified create_dos_name() since we never use shortnames.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2853 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Björn Stenberg 2002-11-18 11:58:43 +00:00
parent 7aabb1ab66
commit eee2c01697
2 changed files with 246 additions and 147 deletions

View file

@ -100,7 +100,6 @@
#define FATDIR_FILESIZE 28 #define FATDIR_FILESIZE 28
#define FATLONG_ORDER 0 #define FATLONG_ORDER 0
#define FATLONG_ATTR 11
#define FATLONG_TYPE 12 #define FATLONG_TYPE 12
#define FATLONG_CHKSUM 13 #define FATLONG_CHKSUM 13
@ -648,9 +647,9 @@ static int write_long_name(struct fat_file* file,
unsigned char* entry; unsigned char* entry;
unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR; unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR; unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
unsigned int i, j=0, nameidx; unsigned int i, j=0;
unsigned char chksum = 0; unsigned char chksum = 0;
unsigned int namelen = strlen(name); int nameidx=0, namelen = strlen(name);
int rc; int rc;
LDEBUGF("write_long_name(file:%x, first:%d, num:%d, name:%s)\n", LDEBUGF("write_long_name(file:%x, first:%d, num:%d, name:%s)\n",
@ -669,9 +668,10 @@ static int write_long_name(struct fat_file* file,
chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++]; chksum = ((chksum & 1) ? 0x80 : 0) + (chksum >> 1) + shortname[j++];
/* calc position of last name segment */ /* calc position of last name segment */
for (nameidx=0; if ( namelen > NAME_BYTES_PER_ENTRY )
nameidx < (namelen - NAME_BYTES_PER_ENTRY); for (nameidx=0;
nameidx += NAME_BYTES_PER_ENTRY); nameidx < (namelen - NAME_BYTES_PER_ENTRY);
nameidx += NAME_BYTES_PER_ENTRY);
for (i=0; i < numentries; i++) { for (i=0; i < numentries; i++) {
/* new sector? */ /* new sector? */
@ -685,10 +685,15 @@ static int write_long_name(struct fat_file* file,
if (rc<1) if (rc<1)
return -4; return -4;
/* grab next sector */ /* read next sector */
rc = fat_readwrite(file, 1, buf, false); rc = fat_readwrite(file, 1, buf, false);
if (rc<1) if (rc<0) {
LDEBUGF("Failed writing new sector: %d\n",rc);
return -5; return -5;
}
if (rc==0)
/* end of dir */
memset(buf, 0, sizeof buf);
sector++; sector++;
idx = 0; idx = 0;
@ -707,13 +712,34 @@ static int write_long_name(struct fat_file* file,
if ( i+1 < numentries ) { if ( i+1 < numentries ) {
/* longname entry */ /* longname entry */
int k, l = nameidx; int k, l = nameidx;
entry[FATLONG_ORDER] = numentries-i-1; entry[FATLONG_ORDER] = numentries-i-1;
if (i==0) if (i==0) {
/* mark this as last long entry */
entry[FATLONG_ORDER] |= 0x40; entry[FATLONG_ORDER] |= 0x40;
for (k=0; k<5 && name[l]; k++) entry[k*2 + 1] = name[l++];
for (k=0; k<6 && name[l]; k++) entry[k*2 + 14] = name[l++]; /* pad name with 0xffff */
for (k=0; k<2 && name[l]; k++) entry[k*2 + 28] = name[l++]; for (k=1; k<12; k++) entry[k] = 0xff;
entry[FATLONG_ATTR] = FAT_ATTR_LONG_NAME; for (k=14; k<26; k++) entry[k] = 0xff;
for (k=28; k<32; k++) entry[k] = 0xff;
};
/* set name */
for (k=0; k<5 && l <= namelen; k++) {
entry[k*2 + 1] = name[l++];
entry[k*2 + 2] = 0;
}
for (k=0; k<6 && l <= namelen; k++) {
entry[k*2 + 14] = name[l++];
entry[k*2 + 15] = 0;
}
for (k=0; k<2 && l <= namelen; k++) {
entry[k*2 + 28] = name[l++];
entry[k*2 + 29] = 0;
}
entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
entry[FATDIR_FSTCLUSLO] = 0;
entry[FATLONG_TYPE] = 0;
entry[FATLONG_CHKSUM] = chksum; entry[FATLONG_CHKSUM] = chksum;
LDEBUGF("Longname entry %d: %.13s\n", idx, name+nameidx); LDEBUGF("Longname entry %d: %.13s\n", idx, name+nameidx);
} }
@ -726,7 +752,6 @@ static int write_long_name(struct fat_file* file,
} }
idx++; idx++;
nameidx -= NAME_BYTES_PER_ENTRY; nameidx -= NAME_BYTES_PER_ENTRY;
//dbg_dump_buffer(buf, SECTOR_SIZE, 0);
} }
/* update last sector */ /* update last sector */
@ -751,8 +776,10 @@ static int add_dir_entry(struct fat_dir* dir,
unsigned int sector; unsigned int sector;
bool done = false; bool done = false;
bool eof = false; bool eof = false;
bool last = false;
int entries_needed, entries_found = 0; int entries_needed, entries_found = 0;
int namelen = strlen(name); int namelen = strlen(name);
int firstentry;
LDEBUGF( "add_dir_entry(%s,%x)\n", LDEBUGF( "add_dir_entry(%s,%x)\n",
name, file->firstcluster); name, file->firstcluster);
@ -767,6 +794,9 @@ static int add_dir_entry(struct fat_dir* dir,
if (namelen % NAME_BYTES_PER_ENTRY) if (namelen % NAME_BYTES_PER_ENTRY)
entries_needed++; entries_needed++;
restart:
firstentry = 0;
err=fat_seek(&dir->file, 0); err=fat_seek(&dir->file, 0);
if (err<0) if (err<0)
return -1; return -1;
@ -803,7 +833,7 @@ static int add_dir_entry(struct fat_dir* dir,
} }
/* look for free slots */ /* look for free slots */
for (i=0; i < DIR_ENTRIES_PER_SECTOR; i++) for (i=0; i < DIR_ENTRIES_PER_SECTOR && !done; i++)
{ {
unsigned char firstbyte = buf[i * DIR_ENTRY_SIZE]; unsigned char firstbyte = buf[i * DIR_ENTRY_SIZE];
switch (firstbyte) { switch (firstbyte) {
@ -811,6 +841,8 @@ static int add_dir_entry(struct fat_dir* dir,
entries_found = entries_needed; entries_found = entries_needed;
LDEBUGF("Found last entry %d\n", LDEBUGF("Found last entry %d\n",
sector * DIR_ENTRIES_PER_SECTOR + i); sector * DIR_ENTRIES_PER_SECTOR + i);
last = true;
done = true;
break; break;
case 0xe5: /* free entry */ case 0xe5: /* free entry */
@ -822,55 +854,90 @@ static int add_dir_entry(struct fat_dir* dir,
default: default:
entries_found = 0; entries_found = 0;
break;
}
if (entries_found == entries_needed) /* check that our intended shortname doesn't already exist */
{ if (!strncmp(shortname, buf + i * DIR_ENTRY_SIZE, 12)) {
int firstentry = sector * DIR_ENTRIES_PER_SECTOR + i; /* filename exists already. make a new one */
snprintf(shortname+8, 4, "%03X", (unsigned)rand() & 0xfff);
LDEBUGF("Duplicate shortname, changing to %s\n",
shortname);
/* if we're not extending the dir, we must go back to first /* name has changed, we need to restart search */
free entry */ goto restart;
if (firstbyte)
firstentry -= (entries_needed - 1);
LDEBUGF("Adding longname to entry %d in sector %d\n",
i, sector);
err = write_long_name(&dir->file, firstentry,
entries_needed, name, shortname);
if (err < 0)
return -5;
/* remember where the shortname dir entry is located */
file->dirsector = dir->file.lastsector;
file->direntry =
(i + entries_needed - 1) % DIR_ENTRIES_PER_SECTOR;
/* advance the last_empty_entry marker? */
if (firstbyte == 0)
{
i++;
if (i < DIR_ENTRIES_PER_SECTOR)
{
/* next entry is now last */
buf[i*DIR_ENTRY_SIZE] = 0;
}
else
{
/* add a new sector/cluster for last entry */
memset(buf, 0, sizeof buf);
do {
err = fat_readwrite(&dir->file, 1, buf, true);
if (err<1)
return -6;
} while (dir->file.sectornum <
(int)fat_bpb.bpb_secperclus);
}
} }
done = true;
break; break;
} }
if (!firstentry && (entries_found == entries_needed)) {
firstentry = sector * DIR_ENTRIES_PER_SECTOR + i;
/* if we're not extending the dir,
we must go back to first free entry */
if (!last)
firstentry -= (entries_needed - 1);
}
}
}
sector = firstentry / DIR_ENTRIES_PER_SECTOR;
LDEBUGF("Adding longname to entry %d in sector %d\n",
firstentry, sector);
err = write_long_name(&dir->file, firstentry,
entries_needed, name, shortname);
if (err < 0)
return -5;
/* remember where the shortname dir entry is located */
file->direntry = firstentry + entries_needed - 1;
file->direntries = entries_needed;
file->dircluster = dir->file.firstcluster;
LDEBUGF("Added new dir entry %d, using %d slots.\n",
file->direntry, file->direntries);
/* advance the end-of-dir marker? */
if (last)
{
unsigned int lastentry = firstentry + entries_needed;
LDEBUGF("Updating end-of-dir entry %d\n",lastentry);
if (lastentry % DIR_ENTRIES_PER_SECTOR)
{
int idx = (lastentry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE;
err=fat_seek(&dir->file, lastentry / DIR_ENTRIES_PER_SECTOR);
if (err<0)
return -6;
err = fat_readwrite(&dir->file, 1, buf, false);
if (err<1)
return -7;
/* clear last entry */
buf[idx] = 0;
err=fat_seek(&dir->file, lastentry / DIR_ENTRIES_PER_SECTOR);
if (err<0)
return -8;
/* we must clear entire last cluster */
do {
err = fat_readwrite(&dir->file, 1, buf, true);
if (err<1)
return -9;
memset(buf, 0, sizeof buf);
} while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus);
}
else
{
/* add a new sector/cluster for last entry */
memset(buf, 0, sizeof buf);
do {
err = fat_readwrite(&dir->file, 1, buf, true);
if (err<1)
return -10;
} while (dir->file.sectornum < (int)fat_bpb.bpb_secperclus);
} }
} }
@ -916,106 +983,70 @@ unsigned char char2dos(unsigned char c)
static int create_dos_name(unsigned char *name, unsigned char *newname) static int create_dos_name(unsigned char *name, unsigned char *newname)
{ {
unsigned char n[12]; int i,j;
unsigned char c;
int i;
char *ext;
strncpy(n, name, sizeof n);
ext = strchr(n, '.');
if(ext)
{
*ext++ = 0;
}
/* The file name is either empty, or there was only an extension.
In either case it is illegal. */
if(n[0] == 0)
{
return -2;
}
/* Name part */ /* Name part */
for(i = 0;n[i] && (i < 8);i++) for (i=0, j=0; name[i] && (j < 8); i++)
{ {
c = char2dos(n[i]); unsigned char c = char2dos(name[i]);
if(c) if (c)
{ newname[j++] = toupper(c);
newname[i] = toupper(c);
}
}
while(i < 8)
{
newname[i++] = ' ';
} }
while (j < 8)
newname[j++] = ' ';
/* Extension part */ /* Extension part */
for (i = 0;ext && ext[i] && (i < 3);i++) snprintf(newname+8, 4, "%03X", (unsigned)rand() & 0xfff);
{
c = char2dos(ext[i]);
if (c)
{
newname[8+i] = toupper(c);
}
}
while(i < 3)
{
newname[8+i++] = ' ';
}
newname[11] = 0;
return 0; return 0;
} }
static int update_file_size( struct fat_file* file, int size ) static int update_file_size( struct fat_file* file, int size )
{ {
unsigned char buf[SECTOR_SIZE]; unsigned char buf[SECTOR_SIZE];
int sector = file->dirsector + fat_bpb.startsector; int sector = file->direntry / DIR_ENTRIES_PER_SECTOR;
unsigned char* entry = buf + file->direntry * DIR_ENTRY_SIZE; unsigned char* entry =
buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR);
unsigned int* sizeptr; unsigned int* sizeptr;
unsigned short* clusptr; unsigned short* clusptr;
struct fat_file dir;
int err; int err;
LDEBUGF("update_file_size(cluster:%x entry:%d sector:%x size:%d)\n", LDEBUGF("update_file_size(cluster:%x entry:%d size:%d)\n",
file->firstcluster, file->direntry, file->dirsector, size); file->firstcluster, file->direntry, size);
if ( file->direntry >= DIR_ENTRIES_PER_SECTOR ) /* create a temporary file handle for the dir holding this file */
panicf("update_file_size(): Illegal entry %d!\n",file->direntry); err = fat_open(file->dircluster, &dir, NULL);
if (err<0)
if ( file->direntry < 0 )
panicf("update_file_size(): Illegal entry %d!\n",file->direntry);
err = ata_read_sectors(sector, 1, buf);
if (err)
{
DEBUGF( "update_file_size() - Couldn't read dir sector %d"
" (error code %d)\n", sector, err);
return -1; return -1;
}
if ( size == -1 ) { err = fat_seek( &dir, sector );
/* mark entry deleted */ if (err<0)
entry[0] = 0xe5;
}
else {
clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
*clusptr = SWAB16(file->firstcluster >> 16);
clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
*clusptr = SWAB16(file->firstcluster & 0xffff);
sizeptr = (int*)(entry + FATDIR_FILESIZE);
*sizeptr = SWAB32(size);
}
err = ata_write_sectors(sector, 1, buf);
if (err)
{
DEBUGF( "update_file_size() - Couldn't write dir sector %d"
" (error code %d)\n", sector, err);
return -2; return -2;
}
err = fat_readwrite(&dir, 1, buf, false);
if (err<1)
return -3;
if (!entry[0] || entry[0] == 0xe5)
panicf("Updating size on empty dir entry %d\n", file->direntry);
clusptr = (short*)(entry + FATDIR_FSTCLUSHI);
*clusptr = SWAB16(file->firstcluster >> 16);
clusptr = (short*)(entry + FATDIR_FSTCLUSLO);
*clusptr = SWAB16(file->firstcluster & 0xffff);
sizeptr = (int*)(entry + FATDIR_FILESIZE);
*sizeptr = SWAB32(size);
err = fat_seek( &dir, sector );
if (err<0)
return -4;
err = fat_readwrite(&dir, 1, buf, true);
if (err<1)
return -5;
return 0; return 0;
} }
@ -1057,8 +1088,9 @@ int fat_open(unsigned int startcluster,
/* remember where the file's dir entry is located */ /* remember where the file's dir entry is located */
if ( dir ) { if ( dir ) {
file->dirsector = dir->sector;
file->direntry = dir->entry - 1; file->direntry = dir->entry - 1;
file->direntries = dir->entrycount;
file->dircluster = dir->file.firstcluster;
} }
LDEBUGF("fat_open(%x), entry %d\n",startcluster,file->direntry); LDEBUGF("fat_open(%x), entry %d\n",startcluster,file->direntry);
return 0; return 0;
@ -1113,7 +1145,7 @@ int fat_closewrite(struct fat_file *file, int size)
} }
} }
if (file->dirsector) if (file->dircluster)
if (update_file_size(file, size) < 0) if (update_file_size(file, size) < 0)
return -1; return -1;
@ -1152,9 +1184,69 @@ int fat_remove(struct fat_file* file)
update_fat_entry(last,0); update_fat_entry(last,0);
last = next; last = next;
} }
update_file_size(file, -1);
file->dirsector = 0; /* free all dir entries */
if ( file->dircluster ) {
unsigned char buf[SECTOR_SIZE];
struct fat_file dir;
unsigned int entry = file->direntry - file->direntries + 1;
unsigned int sector = entry / DIR_ENTRIES_PER_SECTOR;
unsigned int i;
int err;
/* create a temporary file handle for the dir holding this file */
err = fat_open(file->dircluster, &dir, NULL);
if (err<0)
return -1;
err = fat_seek( &dir, sector );
if (err<0)
return -2;
err = fat_readwrite(&dir, 1, buf, false);
if (err<1)
return -3;
for (i=0; i < file->direntries; i++) {
LDEBUGF("Clearing dir entry %d (%d/%d)\n",
entry, i+1, file->direntries);
buf[(entry % DIR_ENTRIES_PER_SECTOR) * DIR_ENTRY_SIZE] = 0xe5;
entry++;
if ( (entry % DIR_ENTRIES_PER_SECTOR) == 0 ) {
/* flush this sector */
err = fat_seek(&dir, sector);
if (err<0)
return -4;
err = fat_readwrite(&dir, 1, buf, true);
if (err<1)
return -5;
if ( i+1 < file->direntries ) {
/* read next sector */
err = fat_readwrite(&dir, 1, buf, false);
if (err<1)
return -6;
}
sector++;
}
}
if ( entry % DIR_ENTRIES_PER_SECTOR ) {
/* flush this sector */
err = fat_seek(&dir, sector);
if (err<0)
return -7;
err = fat_readwrite(&dir, 1, buf, true);
if (err<1)
return -8;
}
}
file->firstcluster = 0; file->firstcluster = 0;
file->dircluster = 0;
return 0; return 0;
} }
@ -1384,9 +1476,11 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
int sectoridx=0; int sectoridx=0;
static unsigned char cached_buf[SECTOR_SIZE]; static unsigned char cached_buf[SECTOR_SIZE];
dir->entrycount = 0;
while(!done) while(!done)
{ {
if ( dir->entry >= DIR_ENTRIES_PER_SECTOR || !dir->sector ) if ( !(dir->entry % DIR_ENTRIES_PER_SECTOR) || !dir->sector )
{ {
err = fat_readwrite(&dir->file, 1, cached_buf, false); err = fat_readwrite(&dir->file, 1, cached_buf, false);
if (err==0) { if (err==0) {
@ -1400,7 +1494,6 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
return -1; return -1;
} }
dir->sector = dir->file.lastsector; dir->sector = dir->file.lastsector;
dir->entry = 0;
} }
for (i = dir->entry % DIR_ENTRIES_PER_SECTOR; for (i = dir->entry % DIR_ENTRIES_PER_SECTOR;
@ -1414,15 +1507,19 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
if (firstbyte == 0xe5) { if (firstbyte == 0xe5) {
/* free entry */ /* free entry */
sectoridx = 0; sectoridx = 0;
dir->entrycount = 0;
continue; continue;
} }
if (firstbyte == 0) { if (firstbyte == 0) {
/* last entry */ /* last entry */
entry->name[0] = 0; entry->name[0] = 0;
dir->entrycount = 0;
return 0; return 0;
} }
dir->entrycount++;
/* longname entry? */ /* longname entry? */
if ( ( cached_buf[entrypos + FATDIR_ATTR] & if ( ( cached_buf[entrypos + FATDIR_ATTR] &
FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) { FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) {

View file

@ -52,14 +52,16 @@ struct fat_file
int lastcluster; /* cluster of last access */ int lastcluster; /* cluster of last access */
int lastsector; /* sector of last access */ int lastsector; /* sector of last access */
int sectornum; /* sector number in this cluster */ int sectornum; /* sector number in this cluster */
int dirsector; /* sector where the dir entry is located */ unsigned int direntry; /* short dir entry index from start of dir */
int direntry; /* dir entry index in sector */ unsigned int direntries; /* number of dir entries used by this file */
unsigned int dircluster; /* first cluster of dir */
bool eof; bool eof;
}; };
struct fat_dir struct fat_dir
{ {
unsigned int entry; unsigned int entry;
unsigned int entrycount;
int sector; int sector;
struct fat_file file; struct fat_file file;
}; };