summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2002-10-31 19:05:25 +0000
committerBjörn Stenberg <bjorn@haxx.se>2002-10-31 19:05:25 +0000
commit08356fb50a70bc44e598ff49ab61bd149060a668 (patch)
tree00a9d8d7f42a5102643b228f58ff2c85932478fb
parent0d79fa127dfc1f5650d3701a174983de8f9e5e4d (diff)
downloadrockbox-08356fb50a70bc44e598ff49ab61bd149060a668.zip
rockbox-08356fb50a70bc44e598ff49ab61bd149060a668.tar.gz
rockbox-08356fb50a70bc44e598ff49ab61bd149060a668.tar.bz2
rockbox-08356fb50a70bc44e598ff49ab61bd149060a668.tar.xz
More graceful handling when running out of space.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@2793 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/common/file.c22
-rw-r--r--firmware/drivers/fat.c204
2 files changed, 114 insertions, 112 deletions
diff --git a/firmware/common/file.c b/firmware/common/file.c
index 0cde938..3e730c2 100644
--- a/firmware/common/file.c
+++ b/firmware/common/file.c
@@ -197,13 +197,9 @@ static int readwrite(int fd, void* buf, int count, bool write)
LDEBUGF( "readwrite(%d,%x,%d,%s)\n",
fd,buf,count,write?"write":"read");
- /* attempt to access past EOF? */
- if (count > openfiles[fd].size - openfiles[fd].fileoffset) {
- if ( write )
- openfiles[fd].size = openfiles[fd].fileoffset + count;
- else
- count = openfiles[fd].size - openfiles[fd].fileoffset;
- }
+ /* attempt to read past EOF? */
+ if (!write && count > openfiles[fd].size - openfiles[fd].fileoffset)
+ count = openfiles[fd].size - openfiles[fd].fileoffset;
/* any head bytes? */
if ( openfiles[fd].cacheoffset != -1 ) {
@@ -253,8 +249,12 @@ static int readwrite(int fd, void* buf, int count, bool write)
}
else {
if ( rc > 0 ) {
- nread += sectors * SECTOR_SIZE;
+ nread += rc * SECTOR_SIZE;
count -= sectors * SECTOR_SIZE;
+
+ /* if eof, skip tail bytes */
+ if ( rc < sectors )
+ count = 0;
}
else {
/* eof */
@@ -285,6 +285,12 @@ static int readwrite(int fd, void* buf, int count, bool write)
}
openfiles[fd].fileoffset += nread;
+ LDEBUGF("fileoffset: %d\n", openfiles[fd].fileoffset);
+
+ /* adjust file size to length written */
+ if ( write && openfiles[fd].fileoffset > openfiles[fd].size )
+ openfiles[fd].size = openfiles[fd].fileoffset;
+
return nread;
}
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index 4c3e410..884311c 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -153,6 +153,7 @@ struct bpb
int rootdirsector;
int firstdatasector;
int startsector;
+ int dataclusters;
struct fsinfo fsinfo;
};
@@ -227,7 +228,6 @@ int fat_mount(int startsector)
unsigned char buf[SECTOR_SIZE];
int err;
int datasec;
- int countofclusters;
int i;
for(i = 0;i < FAT_CACHE_SIZE;i++)
@@ -280,7 +280,7 @@ int fat_mount(int startsector)
/* Determine FAT type */
datasec = fat_bpb.totalsectors - fat_bpb.firstdatasector;
- countofclusters = datasec / fat_bpb.bpb_secperclus;
+ fat_bpb.dataclusters = datasec / fat_bpb.bpb_secperclus;
#ifdef TEST_FAT
/*
@@ -289,7 +289,7 @@ int fat_mount(int startsector)
*/
if ( fat_bpb.bpb_fatsz16 )
#else
- if ( countofclusters < 65525 )
+ if ( fat_bpb.dataclusters < 65525 )
#endif
{
DEBUGF("This is not FAT32. Go away!\n");
@@ -330,6 +330,8 @@ int fat_mount(int startsector)
fat_bpb.fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE);
LDEBUGF("Freecount: %x\n",fat_bpb.fsinfo.freecount);
LDEBUGF("Nextfree: %x\n",fat_bpb.fsinfo.nextfree);
+ LDEBUGF("Cluster count: %x\n",fat_bpb.dataclusters);
+ LDEBUGF("FAT sectors: %x\n",fat_bpb.fatsize);
return 0;
}
@@ -342,12 +344,13 @@ static int bpb_is_sane(void)
fat_bpb.bpb_bytspersec);
return -1;
}
- if(fat_bpb.bpb_secperclus * fat_bpb.bpb_bytspersec > 32768)
+ if(fat_bpb.bpb_secperclus * fat_bpb.bpb_bytspersec > 128*1024)
{
- DEBUGF( "bpb_is_sane() - Warning: cluster size is larger than 32K "
+ DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K "
"(%d * %d = %d)\n",
fat_bpb.bpb_bytspersec, fat_bpb.bpb_secperclus,
fat_bpb.bpb_bytspersec * fat_bpb.bpb_secperclus);
+ return -2;
}
if (fat_bpb.bpb_rsvdseccnt != 32)
{
@@ -369,7 +372,7 @@ static int bpb_is_sane(void)
{
DEBUGF( "bpb_is_sane() - Error: Last word is not "
"0xaa55 (0x%04x)\n", fat_bpb.last_word);
- return -4;
+ return -3;
}
if (fat_bpb.fsinfo.freecount >
@@ -378,7 +381,7 @@ static int bpb_is_sane(void)
{
DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size "
"(0x%04x)\n", fat_bpb.fsinfo.freecount);
- return -5;
+ return -4;
}
return 0;
@@ -429,19 +432,27 @@ static int find_free_cluster(int startcluster)
int offset = startcluster % CLUSTERS_PER_FAT_SECTOR;
int i;
+ /* don't waste time scanning if the disk is already full */
+ if (!fat_bpb.fsinfo.freecount)
+ return 0;
+
for (i = 0; i<fat_bpb.fatsize; i++) {
int j;
int nr = (i + sector) % fat_bpb.fatsize;
unsigned int* fat = cache_fat_sector(nr);
if ( !fat )
break;
- for (j = offset; j < CLUSTERS_PER_FAT_SECTOR; j++)
+ for (j = offset; j < CLUSTERS_PER_FAT_SECTOR; j++) {
if (!(SWAB32(fat[j]) & 0x0fffffff)) {
int c = nr * CLUSTERS_PER_FAT_SECTOR + j;
+ if ( c > fat_bpb.dataclusters+1 ) /* nr 0 is unused */
+ break;
LDEBUGF("find_free_cluster(%x) == %x\n",startcluster,c);
fat_bpb.fsinfo.nextfree = c;
return c;
}
+ }
+ offset = 0;
}
LDEBUGF("find_free_cluster(%x) == 0\n",startcluster);
return 0; /* 0 is an illegal cluster number */
@@ -687,7 +698,6 @@ static int add_dir_entry(struct fat_dir* dir,
}
if (!new) {
- LDEBUGF("Reading sector %x...\n", sec);
/* Read the next sector in the current dir */
err = ata_read_sectors(sec + fat_bpb.startsector,1,buf);
if (err)
@@ -979,8 +989,9 @@ int fat_closewrite(struct fat_file *file, int size)
int next, last = file->lastcluster;
int endcluster = last;
- LDEBUGF("fat_closewrite(%d)\n",size);
+ LDEBUGF("fat_closewrite(size=%d, last=%x)\n",size, last);
+ /* truncate trailing clusters */
last = get_next_cluster(last);
while ( last && last != FAT_EOF_MARK ) {
next = get_next_cluster(last);
@@ -988,13 +999,20 @@ int fat_closewrite(struct fat_file *file, int size)
last = next;
}
- if ( !size ) {
+ /* if no cluster was written, size is 0 */
+ if (!endcluster)
+ size = 0;
+
+ if (!size) {
/* empty file */
- update_fat_entry(file->firstcluster, 0);
- file->firstcluster = 0;
+ if ( file->firstcluster ) {
+ update_fat_entry(file->firstcluster, 0);
+ file->firstcluster = 0;
+ }
}
else
update_fat_entry(endcluster, FAT_EOF_MARK);
+
update_dir_entry(file, size);
flush_fat();
@@ -1011,6 +1029,8 @@ int fat_closewrite(struct fat_file *file, int size)
count, len, size );
if ( len > size + fat_bpb.bpb_secperclus * SECTOR_SIZE)
panicf("Cluster chain is too long\n");
+ if ( len < size )
+ panicf("Cluster chain is too short\n");
}
#endif
@@ -1034,84 +1054,19 @@ int fat_remove(struct fat_file* file)
return 0;
}
-int fat_read( struct fat_file *file, int sectorcount, void* buf )
-{
- int cluster = file->lastcluster;
- int sector = file->lastsector;
- int numsec = file->sectornum;
- int first=0, last=0;
- int err, i;
-
- LDEBUGF( "fat_read(file:%x,count:%d,buf:%x)\n",
- cluster,sectorcount,buf);
- LDEBUGF( "fat_read: c=%x s=%x n=%d\n", cluster,sector,numsec);
- if ( sector == -1 )
- return 0;
-
- /* find sequential sectors and read/write them all at once */
- for (i=0; i<sectorcount && sector>=0; i++ ) {
- numsec++;
- if ( numsec > fat_bpb.bpb_secperclus ) {
- cluster = get_next_cluster(cluster);
- if (!cluster) {
- /* reading past end-of-file */
- sector = -1;
- }
-
- if (cluster) {
- sector = cluster2sec(cluster);
- LDEBUGF("cluster2sec(%x) == %x\n",cluster,sector);
- if (sector<0)
- return -1;
- numsec=1;
- }
- }
- else {
- if (sector)
- sector++;
- else {
- sector = cluster2sec(file->firstcluster);
- numsec=1;
- }
- }
-
- if (!first)
- first = sector;
- if ( ((sector != first) && (sector != last+1)) ||
- /* not sequential any more? */
- (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);
- err = ata_read_sectors(start, count, buf);
- if (err) {
- DEBUGF( "fat_read() - Couldn't read sector %d"
- " (error code %d)\n", sector,err);
- return -2;
- }
- ((char*)buf) += count * SECTOR_SIZE;
- first = 0;
- }
- last = sector;
- }
-
- file->lastcluster = cluster;
- file->lastsector = sector;
- file->sectornum = numsec;
-
- return sectorcount;
-}
-
-int next_write_cluster(struct fat_file* file, int oldcluster, int* newsector)
+static int next_write_cluster(struct fat_file* file,
+ int oldcluster,
+ int* newsector)
{
- int cluster;
+ int cluster = 0;
int sector;
LDEBUGF("next_write_cluster(%x,%x)\n",file->firstcluster, oldcluster);
- cluster = get_next_cluster(oldcluster);
+ if (oldcluster)
+ cluster = get_next_cluster(oldcluster);
+
if (!cluster) {
if (oldcluster)
cluster = find_free_cluster(oldcluster+1);
@@ -1123,9 +1078,15 @@ int next_write_cluster(struct fat_file* file, int oldcluster, int* newsector)
update_fat_entry(oldcluster, cluster);
else
file->firstcluster = cluster;
+ update_fat_entry(cluster, FAT_EOF_MARK);
}
else {
- DEBUGF("next_write_sector(): Disk full!\n");
+#ifdef TEST_FAT
+ if (fat_bpb.fsinfo.freecount>0)
+ panicf("There is free space, but find_free_cluster() "
+ "didn't find it!\n");
+#endif
+ DEBUGF("next_write_cluster(): Disk full!\n");
return 0;
}
}
@@ -1137,6 +1098,25 @@ int next_write_cluster(struct fat_file* file, int oldcluster, int* newsector)
return cluster;
}
+static bool transfer( int start, int count, char* buf, bool write )
+{
+ int err;
+
+ LDEBUGF("transfer(s=%x, c=%x)\n",start, count);
+ if (write)
+ err = ata_write_sectors(start, count, buf);
+ else
+ err = ata_read_sectors(start, count, buf);
+ if (err) {
+ DEBUGF( "transfer() - Couldn't %s sector %x"
+ " (error code %d)\n",
+ write ? "write":"read", start, err);
+ return false;
+ }
+ return true;
+}
+
+
int fat_readwrite( struct fat_file *file, int sectorcount,
void* buf, bool write )
{
@@ -1144,7 +1124,7 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
int sector = file->lastsector;
int numsec = file->sectornum;
int first=0, last=0;
- int err, i;
+ int i;
LDEBUGF( "fat_write(file:%x,count:%d,buf:%x)\n",
cluster,sectorcount,buf);
@@ -1153,23 +1133,31 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
return 0;
/* find sequential sectors and write them all at once */
- for (i=0; i<sectorcount; i++ ) {
+ for (i=0; (i < sectorcount) && (sector > -1); i++ ) {
numsec++;
if ( numsec > fat_bpb.bpb_secperclus || !cluster ) {
+ int oldcluster = cluster;
if (write)
cluster = next_write_cluster(file, cluster, &sector);
else {
cluster = get_next_cluster(cluster);
sector = cluster2sec(cluster);
}
- if (!cluster)
+ if (!cluster) {
sector = -1;
+ if ( write ) {
+ /* set file->lastcluster to last available cluster,
+ so we can terminate the file in closewrite() */
+ cluster = oldcluster;
+ }
+ }
numsec=1;
}
else {
if (sector)
sector++;
else {
+ /* look up first sector of file */
sector = cluster2sec(file->firstcluster);
numsec=1;
}
@@ -1179,23 +1167,27 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
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) {
- DEBUGF( "fat_readwrite() - Couldn't read sector %d"
- " (error code %d)\n", sector,err);
+ (last-first+1 == 256) ) { /* max 256 sectors per ata request */
+ int count = last - first + 1;
+ if (!transfer( first + fat_bpb.startsector, count, buf, write ))
return -2;
- }
+
((char*)buf) += count * SECTOR_SIZE;
- first = 0;
+ first = sector;
+ }
+ else {
+ /* last sector requested */
+ if (i >= sectorcount-1) {
+ int count = sector - first + 1;
+ if (!transfer( first + fat_bpb.startsector,
+ count, buf, write ))
+ return -2;
+
+ ((char*)buf) += count * SECTOR_SIZE;
+ first = sector;
+ }
}
+
last = sector;
}
@@ -1203,7 +1195,11 @@ int fat_readwrite( struct fat_file *file, int sectorcount,
file->lastsector = sector;
file->sectornum = numsec;
- return sectorcount;
+ /* if eof, don't report last block as read/written */
+ if (sector == -1)
+ i--;
+
+ return i;
}
int fat_seek(struct fat_file *file, int seeksector )