1
0
Fork 0
forked from len0rd/rockbox

Fat writing update. File creation now works, though still only short filenames.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2790 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Björn Stenberg 2002-10-31 16:09:28 +00:00
parent 3bf2f78581
commit a5e77d8f94
5 changed files with 212 additions and 111 deletions

View file

@ -455,11 +455,13 @@ static int update_fat_entry(unsigned int entry, unsigned int val)
LDEBUGF("update_fat_entry(%x,%x)\n",entry,val); LDEBUGF("update_fat_entry(%x,%x)\n",entry,val);
#ifdef TEST_FAT
if (entry==val) if (entry==val)
panicf("Creating FAT loop: %x,%x\n",entry,val); panicf("Creating FAT loop: %x,%x\n",entry,val);
if ( entry < 2 ) if ( entry < 2 )
panicf("Updating reserved FAT entry %d.\n",entry); panicf("Updating reserved FAT entry %d.\n",entry);
#endif
sec = cache_fat_sector(sector); sec = cache_fat_sector(sector);
if (!sec) if (!sec)
@ -636,6 +638,12 @@ static int add_dir_entry(struct fat_dir* dir,
if (sec_cnt >= fat_bpb.bpb_secperclus) if (sec_cnt >= fat_bpb.bpb_secperclus)
{ {
int oldcluster; int oldcluster;
/* we're not adding a whole new sector
just for the end-of-dir marker */
if ( need_to_update_last_empty_marker )
break;
if (!currdir) if (!currdir)
currdir = sec2cluster(fat_bpb.rootdirsector); currdir = sec2cluster(fat_bpb.rootdirsector);
oldcluster = currdir; oldcluster = currdir;
@ -647,17 +655,35 @@ static int add_dir_entry(struct fat_dir* dir,
{ {
/* end of dir, add new cluster */ /* end of dir, add new cluster */
LDEBUGF("Adding cluster to dir\n"); LDEBUGF("Adding cluster to dir\n");
currdir = find_free_cluster(fat_bpb.fsinfo.nextfree); currdir = find_free_cluster(oldcluster+1);
if (!currdir) { if (!currdir) {
DEBUGF("add_dir_entry(): Disk full!\n"); DEBUGF("add_dir_entry(): Disk full!\n");
return -1; return -1;
} }
update_fat_entry(oldcluster, currdir); update_fat_entry(oldcluster, currdir);
update_fat_entry(currdir, FAT_EOF_MARK);
new = true; new = true;
memset(buf, 0, sizeof buf); memset(buf, 0, sizeof buf);
/* clear remaining sectors in this cluster */
if (fat_bpb.bpb_secperclus > 1) {
int i;
sec = cluster2sec(currdir);
for (i=1; i<fat_bpb.bpb_secperclus; i++ ) {
err = ata_write_sectors(sec + fat_bpb.startsector + i,
1, buf);
if (err) {
DEBUGF( "add_dir_entry() - "
" Couldn't write dir"
" sector (error code %d)\n", err);
return -3;
}
}
}
} }
LDEBUGF("new cluster is %x\n", currdir); LDEBUGF("new cluster is %x\n", currdir);
sec = cluster2sec(currdir); sec = cluster2sec(currdir);
sec_cnt = 0;
} }
if (!new) { if (!new) {
@ -714,6 +740,7 @@ static int add_dir_entry(struct fat_dir* dir,
/* We must fill in the first entry /* We must fill in the first entry
in the next sector */ in the next sector */
need_to_update_last_empty_marker = true; need_to_update_last_empty_marker = true;
LDEBUGF("need_to_update_last_empty\n");
} }
} }
else else
@ -907,13 +934,13 @@ int fat_open(unsigned int startcluster,
{ {
file->firstcluster = startcluster; file->firstcluster = startcluster;
file->lastcluster = startcluster; file->lastcluster = startcluster;
file->lastsector = cluster2sec(startcluster); file->lastsector = 0;
file->sectornum = 0; file->sectornum = 0;
/* remember where the file's dir entry is located */ /* remember where the file's dir entry is located */
file->dirsector = dir->cached_sec; file->dirsector = dir->cached_sec;
file->direntry = (dir->entry % DIR_ENTRIES_PER_SECTOR) - 1; file->direntry = (dir->entry % DIR_ENTRIES_PER_SECTOR) - 1;
LDEBUGF("fat_open: entry %d\n",file->direntry); LDEBUGF("fat_open(%x), entry %d\n",startcluster,file->direntry);
return 0; return 0;
} }
@ -952,7 +979,7 @@ int fat_closewrite(struct fat_file *file, int size)
int next, last = file->lastcluster; int next, last = file->lastcluster;
int endcluster = last; int endcluster = last;
LDEBUGF("fat_closewrite()\n"); LDEBUGF("fat_closewrite(%d)\n",size);
last = get_next_cluster(last); last = get_next_cluster(last);
while ( last && last != FAT_EOF_MARK ) { while ( last && last != FAT_EOF_MARK ) {
@ -961,10 +988,32 @@ int fat_closewrite(struct fat_file *file, int size)
last = next; last = next;
} }
if ( !size ) {
/* empty file */
update_fat_entry(file->firstcluster, 0);
file->firstcluster = 0;
}
else
update_fat_entry(endcluster, FAT_EOF_MARK); update_fat_entry(endcluster, FAT_EOF_MARK);
update_dir_entry(file, size); update_dir_entry(file, size);
flush_fat(); flush_fat();
#ifdef TEST_FAT
{
/* debug */
int count = 0;
int len;
for ( next = file->firstcluster; next;
next = get_next_cluster(next) )
LDEBUGF("cluster %d: %x\n", count++, next);
len = count * fat_bpb.bpb_secperclus * SECTOR_SIZE;
LDEBUGF("File is %d clusters (chainlen=%d, size=%d)\n",
count, len, size );
if ( len > size + fat_bpb.bpb_secperclus * SECTOR_SIZE)
panicf("Cluster chain is too long\n");
}
#endif
return 0; return 0;
} }
@ -999,12 +1048,10 @@ int fat_read( struct fat_file *file, int sectorcount, void* buf )
if ( sector == -1 ) if ( sector == -1 )
return 0; return 0;
first = last = sector;
/* find sequential sectors and read/write them all at once */ /* find sequential sectors and read/write them all at once */
for (i=0; i<sectorcount && sector>=0; i++ ) { for (i=0; i<sectorcount && sector>=0; i++ ) {
numsec++; numsec++;
if ( numsec >= fat_bpb.bpb_secperclus ) { if ( numsec > fat_bpb.bpb_secperclus ) {
cluster = get_next_cluster(cluster); cluster = get_next_cluster(cluster);
if (!cluster) { if (!cluster) {
/* reading past end-of-file */ /* reading past end-of-file */
@ -1016,16 +1063,26 @@ int fat_read( struct fat_file *file, int sectorcount, void* buf )
LDEBUGF("cluster2sec(%x) == %x\n",cluster,sector); LDEBUGF("cluster2sec(%x) == %x\n",cluster,sector);
if (sector<0) if (sector<0)
return -1; return -1;
numsec=0; numsec=1;
} }
} }
else else {
if (sector)
sector++; sector++;
else {
sector = cluster2sec(file->firstcluster);
numsec=1;
}
}
if ( (sector != last+1) || /* not sequential any more? */ if (!first)
first = sector;
if ( ((sector != first) && (sector != last+1)) ||
/* not sequential any more? */
(i == sectorcount-1) || /* last sector requested? */ (i == sectorcount-1) || /* last sector requested? */
(last-first+1 == 256) ) { /* max 256 sectors per ata request */ (sector-first+1 == 256) ) { /* max 256 sectors per ata request */
int count = last - first + 1; int count = sector - first + 1;
int start = first + fat_bpb.startsector; int start = first + fat_bpb.startsector;
LDEBUGF("s=%x, l=%x, f=%x, i=%d\n",sector,last,first,i); LDEBUGF("s=%x, l=%x, f=%x, i=%d\n",sector,last,first,i);
err = ata_read_sectors(start, count, buf); err = ata_read_sectors(start, count, buf);
@ -1035,7 +1092,7 @@ int fat_read( struct fat_file *file, int sectorcount, void* buf )
return -2; return -2;
} }
((char*)buf) += count * SECTOR_SIZE; ((char*)buf) += count * SECTOR_SIZE;
first = sector; first = 0;
} }
last = sector; last = sector;
} }
@ -1047,7 +1104,41 @@ int fat_read( struct fat_file *file, int sectorcount, void* buf )
return sectorcount; return sectorcount;
} }
int fat_write( struct fat_file *file, int sectorcount, void* buf ) int next_write_cluster(struct fat_file* file, int oldcluster, int* newsector)
{
int cluster;
int sector;
LDEBUGF("next_write_cluster(%x,%x)\n",file->firstcluster, oldcluster);
cluster = get_next_cluster(oldcluster);
if (!cluster) {
if (oldcluster)
cluster = find_free_cluster(oldcluster+1);
else
cluster = find_free_cluster(fat_bpb.fsinfo.nextfree);
if (cluster) {
if (oldcluster)
update_fat_entry(oldcluster, cluster);
else
file->firstcluster = cluster;
}
else {
DEBUGF("next_write_sector(): Disk full!\n");
return 0;
}
}
sector = cluster2sec(cluster);
if (sector<0)
return 0;
*newsector = sector;
return cluster;
}
int fat_readwrite( struct fat_file *file, int sectorcount,
void* buf, bool write )
{ {
int cluster = file->lastcluster; int cluster = file->lastcluster;
int sector = file->lastsector; int sector = file->lastsector;
@ -1062,53 +1153,50 @@ int fat_write( struct fat_file *file, int sectorcount, void* buf )
return 0; return 0;
/* find sequential sectors and write them all at once */ /* find sequential sectors and write them all at once */
for (i=0; i<sectorcount && sector>=0; i++ ) { for (i=0; i<sectorcount; i++ ) {
numsec++; numsec++;
if ( numsec > fat_bpb.bpb_secperclus || !cluster ) {
/* find a new cluster */ if (write)
if ( numsec >= fat_bpb.bpb_secperclus || !cluster) { cluster = next_write_cluster(file, cluster, &sector);
int oldcluster = cluster; else {
cluster = get_next_cluster(cluster); cluster = get_next_cluster(cluster);
if (!cluster) { sector = cluster2sec(cluster);
if (!oldcluster) }
cluster = find_free_cluster(fat_bpb.fsinfo.nextfree); if (!cluster)
else sector = -1;
cluster = find_free_cluster(oldcluster+1); numsec=1;
if (cluster) {
if ( !oldcluster )
file->firstcluster = cluster;
else
update_fat_entry(oldcluster, cluster);
} }
else { else {
sector = -1; if (sector)
DEBUGF("fat_write(): Disk full!\n");
}
}
if (cluster) {
sector = cluster2sec(cluster);
LDEBUGF("cluster2sec(%x) == %x\n",cluster,sector);
if (sector<0)
return -1;
numsec=0;
if (!oldcluster)
first = last = sector;
}
}
else
sector++; sector++;
else {
sector = cluster2sec(file->firstcluster);
numsec=1;
}
}
/* we start simple: one sector at a time */ if (!first)
err = ata_write_sectors(sector, 1, buf); first = sector;
if ( ((sector != first) && (sector != last+1)) || /* not sequential */
(i == sectorcount-1) || /* last sector requested */
(sector-first+1 == 256) ) { /* max 256 sectors per ata request */
int count = sector - first + 1;
int start = first + fat_bpb.startsector;
LDEBUGF("s=%x, l=%x, f=%x, i=%d\n",sector,last,first,i);
if (write)
err = ata_write_sectors(start, count, buf);
else
err = ata_read_sectors(start, count, buf);
if (err) { if (err) {
DEBUGF( "fat_write() - Couldn't write sector %d" DEBUGF( "fat_readwrite() - Couldn't read sector %d"
" (error code %d)\n", sector,err); " (error code %d)\n", sector,err);
return -2; return -2;
} }
((char*)buf) += SECTOR_SIZE; ((char*)buf) += count * SECTOR_SIZE;
first = 0;
}
last = sector;
} }
file->lastcluster = cluster; file->lastcluster = cluster;
@ -1118,15 +1206,6 @@ int fat_write( struct fat_file *file, int sectorcount, void* buf )
return sectorcount; return sectorcount;
} }
int fat_readwrite( struct fat_file *file, int sectorcount,
void* buf, bool write )
{
if (write)
return fat_write(file, sectorcount, buf);
else
return fat_read(file, sectorcount, buf);
}
int fat_seek(struct fat_file *file, int seeksector ) int fat_seek(struct fat_file *file, int seeksector )
{ {
int cluster = file->firstcluster; int cluster = file->firstcluster;

View file

@ -46,15 +46,6 @@ struct fat_direntry
#define FAT_ATTR_DIRECTORY 0x10 #define FAT_ATTR_DIRECTORY 0x10
#define FAT_ATTR_ARCHIVE 0x20 #define FAT_ATTR_ARCHIVE 0x20
struct fat_dir
{
int entry;
int cached_sec;
int num_sec;
unsigned char cached_buf[SECTOR_SIZE];
int startcluster;
};
struct fat_file struct fat_file
{ {
int firstcluster; /* first cluster in file */ int firstcluster; /* first cluster in file */
@ -65,6 +56,16 @@ struct fat_file
int direntry; /* dir entry index in sector */ int direntry; /* dir entry index in sector */
}; };
struct fat_dir
{
int entry;
int cached_sec;
int num_sec;
unsigned char cached_buf[SECTOR_SIZE];
int startcluster;
};
extern int fat_mount(int startsector); extern int fat_mount(int startsector);
extern int fat_create_dir(unsigned int currdir, char *name); extern int fat_create_dir(unsigned int currdir, char *name);

View file

@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "debug.h" #include "debug.h"
#include "panic.h"
#define BLOCK_SIZE 512 #define BLOCK_SIZE 512
@ -9,7 +10,10 @@ static FILE* file;
int ata_read_sectors(unsigned long start, unsigned char count, void* buf) int ata_read_sectors(unsigned long start, unsigned char count, void* buf)
{ {
DEBUGF("[Reading block 0x%lx]\n",start); int i;
for (i=0; i<count; i++ )
DEBUGF("[Reading block 0x%lx]\n",start+i);
if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) {
perror("fseek"); perror("fseek");
return -1; return -1;
@ -17,6 +21,7 @@ int ata_read_sectors(unsigned long start, unsigned char count, void* buf)
if(!fread(buf,BLOCK_SIZE,count,file)) { if(!fread(buf,BLOCK_SIZE,count,file)) {
printf("Failed reading %d blocks starting at block 0x%lx\n",count,start); printf("Failed reading %d blocks starting at block 0x%lx\n",count,start);
perror("fread"); perror("fread");
panicf("Disk error\n");
return -2; return -2;
} }
return 0; return 0;
@ -24,20 +29,22 @@ int ata_read_sectors(unsigned long start, unsigned char count, void* buf)
int ata_write_sectors(unsigned long start, unsigned char count, void* buf) int ata_write_sectors(unsigned long start, unsigned char count, void* buf)
{ {
DEBUGF("[Writing block 0x%lx]\n",start); int i;
for (i=0; i<count; i++ )
DEBUGF("[Writing block 0x%lx]\n",start+i);
if (start == 0) { if (start == 0)
DEBUGF("Holy crap! You're writing on sector 0!\n"); panicf("Writing on sector 0!\n");
exit(0);
}
if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) {
perror("fseek"); perror("fseek");
return -1; return -1;
panicf("Disk error\n");
} }
if(!fwrite(buf,BLOCK_SIZE,count,file)) { if(!fwrite(buf,BLOCK_SIZE,count,file)) {
perror("fwrite"); perror("fwrite");
return -2; return -2;
panicf("Disk error\n");
} }
return 0; return 0;
} }

View file

@ -12,7 +12,7 @@ extern int ata_init(char*);
extern void ata_read_sectors(int, int, char*); extern void ata_read_sectors(int, int, char*);
void dbg_dump_sector(int sec); void dbg_dump_sector(int sec);
void dbg_dump_buffer(unsigned char *buf, int len); void dbg_dump_buffer(unsigned char *buf, int len, int offset);
void dbg_console(void); void dbg_console(void);
void panicf( char *fmt, ...) void panicf( char *fmt, ...)
@ -31,10 +31,10 @@ void dbg_dump_sector(int sec)
ata_read_sectors(sec,1,buf); ata_read_sectors(sec,1,buf);
DEBUGF("---< Sector %d >-----------------------------------------\n", sec); DEBUGF("---< Sector %d >-----------------------------------------\n", sec);
dbg_dump_buffer(buf, 512); dbg_dump_buffer(buf, 512, 0);
} }
void dbg_dump_buffer(unsigned char *buf, int len) void dbg_dump_buffer(unsigned char *buf, int len, int offset)
{ {
int i, j; int i, j;
unsigned char c; unsigned char c;
@ -42,7 +42,7 @@ void dbg_dump_buffer(unsigned char *buf, int len)
for(i = 0;i < len/16;i++) for(i = 0;i < len/16;i++)
{ {
DEBUGF("%03x: ", i*16); DEBUGF("%03x: ", i*16 + offset);
for(j = 0;j < 16;j++) for(j = 0;j < 16;j++)
{ {
c = buf[i*16+j]; c = buf[i*16+j];
@ -102,7 +102,7 @@ int dbg_mkfile(char* name, int num)
int len = num > sizeof text ? sizeof text : num; int len = num > sizeof text ? sizeof text : num;
for (i=0; i<len/CHUNKSIZE; i++ ) for (i=0; i<len/CHUNKSIZE; i++ )
sprintf(text+i*CHUNKSIZE,"%07x,",x++); sprintf(text+i*CHUNKSIZE,"%c%06x,",name[1],x++);
if (write(fd, text, len) < 0) { if (write(fd, text, len) < 0) {
DEBUGF("Failed writing data\n"); DEBUGF("Failed writing data\n");
@ -139,12 +139,15 @@ int dbg_chkfile(char* name)
if (!rc) if (!rc)
break; break;
for (i=0; i<rc/CHUNKSIZE; i++ ) { for (i=0; i<rc/CHUNKSIZE; i++ ) {
sprintf(tmp,"%07x,",x++); sprintf(tmp,"%c%06x,",name[1],x++);
if (strncmp(text+i*CHUNKSIZE,tmp,CHUNKSIZE)) { if (strncmp(text+i*CHUNKSIZE,tmp,CHUNKSIZE)) {
DEBUGF("Mismatch in byte %d (%.4s != %.4s)\n", DEBUGF("Mismatch in byte %x (sector %d). Expected %.8s found %.8s\n",
block*sizeof(text)+i*CHUNKSIZE, tmp, block*sizeof(text)+i*CHUNKSIZE,
(block*sizeof(text)+i*CHUNKSIZE) / SECTOR_SIZE,
tmp,
text+i*CHUNKSIZE); text+i*CHUNKSIZE);
dbg_dump_buffer(text+i*CHUNKSIZE - 0x20, 0x40); dbg_dump_buffer(text+i*CHUNKSIZE - 0x20, 0x40,
block*sizeof(text)+i*CHUNKSIZE - 0x20);
return -1; return -1;
} }
} }

View file

@ -2,32 +2,34 @@
IMAGE=disk.img IMAGE=disk.img
MOUNT=/mnt/dummy MOUNT=/mnt/dummy
RESULT=result.txt
fail() { fail() {
echo "!! Test failed. Look in result.txt for test log." echo "!! Test failed. Look in $RESULT for test logs."
exit exit
} }
check() { check() {
/sbin/dosfsck -r $IMAGE | tee -a result.txt /sbin/dosfsck -r $IMAGE | tee -a $RESULT
[ $RETVAL -ne 0 ] && fail [ $RETVAL -ne 0 ] && fail
} }
try() { try() {
./fat $1 $2 $3 2> result.txt ./fat $1 $2 $3 2>> $RESULT
RETVAL=$? RETVAL=$?
[ $RETVAL -ne 0 ] && fail [ $RETVAL -ne 0 ] && fail
} }
buildimage() { buildimage() {
umount $MOUNT /sbin/mkdosfs -F 32 -s $1 $IMAGE > /dev/null
/sbin/mkdosfs -F 32 -s $1 disk.img >/dev/null
mount -o loop $IMAGE $MOUNT mount -o loop $IMAGE $MOUNT
echo "Filling it with /etc files" echo "Filling it with /etc files"
find /etc -type f -maxdepth 1 -exec cp {} $MOUNT \; find /etc -type f -maxdepth 1 -exec cp {} $MOUNT \;
umount $MOUNT
} }
runtests() { runtests() {
rm $RESULT
echo ---Test: create a 10K file echo ---Test: create a 10K file
try mkfile /apa.txt 10 try mkfile /apa.txt 10
@ -53,29 +55,38 @@ runtests() {
try mkfile /cpa.txt 0 try mkfile /cpa.txt 0
check check
try chkfile /cpa.txt try chkfile /cpa.txt
try chkfile /apa.txt
try chkfile /bpa.txt
echo ---Test: create 20 1k files echo ---Test: create 10 1k files
for i in `seq 1 10`; for i in `seq 1 10`;
do do
echo -n $i echo ---Test: $i/10 ---
try mkfile /rockbox.$i try mkfile /rockbox.$i
check check
try chkfile /bpa.txt
done done
} }
echo "Building test image A (2 sectors/cluster)" echo "Building test image (1 sector/cluster)"
buildimage 2
runtests
echo "Building test image B (8 sectors/cluster)"
buildimage 8
runtests
echo "Building test image B (1 sector/cluster)"
buildimage 1 buildimage 1
runtests runtests
umount $MOUNT echo "Building test image (4 sector/cluster)"
buildimage 4
runtests
echo "-- Test complete --" echo "Building test image (8 sectors/cluster)"
buildimage 8
runtests
echo "Building test image (32 sectors/cluster)"
buildimage 32
runtests
echo "Building test image (128 sectors/cluster)"
buildimage 128
runtests
echo "== Test completed sucessfully =="