From ae66c2b9ee621946d2c7175d94f9adfbd361a699 Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Sun, 3 Dec 2006 18:12:19 +0000 Subject: [PATCH] Add support (runtime detection) for 2048 bytes/sector filesystem. Large sectors are enabled for iPod Video (including 5.5G) only. Might still cause FS corruption (however, unlikely), so beware! Based on FS#6169 by Robert Carboneau. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11651 a1c6a512-1295-4272-9138-f99709370657 --- firmware/common/disk.c | 14 +++++ firmware/common/file.c | 29 +++++---- firmware/drivers/fat.c | 138 ++++++++++++++++++++++++++++------------- firmware/export/fat.h | 13 +++- 4 files changed, 135 insertions(+), 59 deletions(-) diff --git a/firmware/common/disk.c b/firmware/common/disk.c index 950658286c..f5f9f194b2 100644 --- a/firmware/common/disk.c +++ b/firmware/common/disk.c @@ -157,7 +157,21 @@ int disk_mount(int drive) mounted++; vol_drive[volume] = drive; /* remember the drive for this volume */ volume = get_free_volume(); /* prepare next entry */ + continue; } + +# if MAX_SECTOR_SIZE != PHYSICAL_SECTOR_SIZE + /* Try again with sector size 2048 */ + if (!fat_mount(IF_MV2(volume,) IF_MV2(drive,) pinfo[i].start + * (MAX_SECTOR_SIZE/PHYSICAL_SECTOR_SIZE))) + { + pinfo[i].start *= MAX_SECTOR_SIZE/PHYSICAL_SECTOR_SIZE; + pinfo[i].size *= MAX_SECTOR_SIZE/PHYSICAL_SECTOR_SIZE; + mounted++; + vol_drive[volume] = drive; /* remember the drive for this volume */ + volume = get_free_volume(); /* prepare next entry */ + } +# endif } #endif diff --git a/firmware/common/file.c b/firmware/common/file.c index e24b44ce1f..d1ba10569a 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c @@ -36,7 +36,7 @@ */ struct filedesc { - unsigned char cache[SECTOR_SIZE]; + unsigned char cache[MAX_SECTOR_SIZE]; int cacheoffset; /* invariant: 0 <= cacheoffset <= SECTOR_SIZE */ long fileoffset; long size; @@ -415,9 +415,10 @@ int ftruncate(int fd, off_t size) { int rc, sector; struct filedesc* file = &openfiles[fd]; + int secsize = fat_get_secsize(&(file->fatfile)); - sector = size / SECTOR_SIZE; - if (size % SECTOR_SIZE) + sector = size / secsize; + if (size % secsize) sector++; rc = fat_seek(&(file->fatfile), sector); @@ -444,7 +445,7 @@ static int flush_cache(int fd) { int rc; struct filedesc* file = &openfiles[fd]; - long sector = file->fileoffset / SECTOR_SIZE; + long sector = file->fileoffset / fat_get_secsize(&(file->fatfile)); DEBUGF("Flushing dirty sector cache\n"); @@ -473,6 +474,7 @@ static int readwrite(int fd, void* buf, long count, bool write) long sectors; long nread=0; struct filedesc* file = &openfiles[fd]; + int secsize = fat_get_secsize(&(file->fatfile)); int rc; if ( !file->busy ) { @@ -490,7 +492,7 @@ static int readwrite(int fd, void* buf, long count, bool write) /* any head bytes? */ if ( file->cacheoffset != -1 ) { int offs = file->cacheoffset; - int headbytes = MIN(count, SECTOR_SIZE - offs); + int headbytes = MIN(count, secsize - offs); if (write) { memcpy( file->cache + offs, buf, headbytes ); @@ -500,7 +502,7 @@ static int readwrite(int fd, void* buf, long count, bool write) memcpy( buf, file->cache + offs, headbytes ); } - if (offs + headbytes == SECTOR_SIZE) { + if (offs + headbytes == secsize) { if (file->dirty) { int rc = flush_cache(fd); if ( rc < 0 ) { @@ -523,7 +525,7 @@ static int readwrite(int fd, void* buf, long count, bool write) * more data to follow in this call). Do NOT flush here. */ /* read/write whole sectors right into/from the supplied buffer */ - sectors = count / SECTOR_SIZE; + sectors = count / secsize; if ( sectors ) { int rc = fat_readwrite(&(file->fatfile), sectors, (unsigned char*)buf+nread, write ); @@ -541,8 +543,8 @@ static int readwrite(int fd, void* buf, long count, bool write) } else { if ( rc > 0 ) { - nread += rc * SECTOR_SIZE; - count -= sectors * SECTOR_SIZE; + nread += rc * secsize; + count -= sectors * secsize; /* if eof, skip tail bytes */ if ( rc < sectors ) @@ -575,7 +577,7 @@ static int readwrite(int fd, void* buf, long count, bool write) /* seek back one sector to put file position right */ rc = fat_seek(&(file->fatfile), (file->fileoffset + nread) / - SECTOR_SIZE); + secsize); if ( rc < 0 ) { DEBUGF("fat_seek() failed\n"); errno = EIO; @@ -641,6 +643,7 @@ off_t lseek(int fd, off_t offset, int whence) int sectoroffset; int rc; struct filedesc* file = &openfiles[fd]; + int secsize = fat_get_secsize(&(file->fatfile)); LDEBUGF("lseek(%d,%ld,%d)\n",fd,offset,whence); @@ -672,9 +675,9 @@ off_t lseek(int fd, off_t offset, int whence) } /* new sector? */ - newsector = pos / SECTOR_SIZE; - oldsector = file->fileoffset / SECTOR_SIZE; - sectoroffset = pos % SECTOR_SIZE; + newsector = pos / secsize; + oldsector = file->fileoffset / secsize; + sectoroffset = pos % secsize; if ( (newsector != oldsector) || ((file->cacheoffset==-1) && sectoroffset) ) { diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index e1c0a00ab8..7d5a879249 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c @@ -109,9 +109,9 @@ #define FATLONG_TYPE 12 #define FATLONG_CHKSUM 13 -#define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4) -#define CLUSTERS_PER_FAT16_SECTOR (SECTOR_SIZE / 2) -#define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / DIR_ENTRY_SIZE) +#define CLUSTERS_PER_FAT_SECTOR ((unsigned int)(fat_bpb->bpb_bytspersec / 4)) +#define CLUSTERS_PER_FAT16_SECTOR ((unsigned int)(fat_bpb->bpb_bytspersec / 2)) +#define DIR_ENTRIES_PER_SECTOR ((unsigned int)(fat_bpb->bpb_bytspersec / DIR_ENTRY_SIZE)) #define DIR_ENTRY_SIZE 32 #define NAME_BYTES_PER_ENTRY 13 #define FAT_BAD_MARK 0x0ffffff7 @@ -165,8 +165,12 @@ struct bpb int drive; /* on which physical device is this located */ bool mounted; /* flag if this volume is mounted */ #endif + + int secmult; /* bpb_bytspersec / PHYSICAL_SECTOR_SIZE */ }; +int fat_sector_size; + static struct bpb fat_bpbs[NUM_VOLUMES]; /* mounted partition info */ static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb)); @@ -191,7 +195,7 @@ struct fat_cache_entry #endif }; -static char fat_cache_sectors[FAT_CACHE_SIZE][SECTOR_SIZE]; +static char fat_cache_sectors[FAT_CACHE_SIZE][MAX_SECTOR_SIZE]; static struct fat_cache_entry fat_cache[FAT_CACHE_SIZE]; static struct mutex cache_mutex; @@ -233,9 +237,11 @@ void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free) #endif struct bpb* fat_bpb = &fat_bpbs[volume]; if (size) - *size = fat_bpb->dataclusters * fat_bpb->bpb_secperclus / 2; + *size = (fat_bpb->dataclusters * fat_bpb->bpb_secperclus + * fat_bpb->bpb_bytspersec) / 1024; if (free) - *free = fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus / 2; + *free = (fat_bpb->fsinfo.freecount * fat_bpb->bpb_secperclus + * fat_bpb->bpb_bytspersec) / 1024; } void fat_init(void) @@ -269,7 +275,7 @@ int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector) const int volume = 0; #endif struct bpb* fat_bpb = &fat_bpbs[volume]; - unsigned char buf[SECTOR_SIZE]; + unsigned char buf[MAX_SECTOR_SIZE]; int rc; long datasec; #ifdef HAVE_FAT16SUPPORT @@ -302,6 +308,8 @@ int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector) fat_bpb->last_word = BYTES2INT16(buf,BPB_LAST_WORD); /* calculate a few commonly used values */ + fat_bpb->secmult = fat_bpb->bpb_bytspersec / PHYSICAL_SECTOR_SIZE; + if (fat_bpb->bpb_fatsz16 != 0) fat_bpb->fatsize = fat_bpb->bpb_fatsz16; else @@ -391,7 +399,7 @@ int fat_mount(IF_MV2(int volume,) IF_MV2(int drive,) long startsector) { /* Read the fsinfo sector */ rc = ata_read_sectors(IF_MV2(drive,) - startsector + fat_bpb->bpb_fsinfo, 1, buf); + startsector + (fat_bpb->bpb_fsinfo * fat_bpb->secmult), 1, buf); if (rc < 0) { DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", rc); @@ -506,12 +514,15 @@ static int bpb_is_sane(IF_MV_NONVOID(struct bpb* fat_bpb)) #ifndef HAVE_MULTIVOLUME struct bpb* fat_bpb = &fat_bpbs[0]; #endif - if(fat_bpb->bpb_bytspersec != 512) + if(fat_bpb->bpb_bytspersec > MAX_SECTOR_SIZE + || fat_bpb->bpb_bytspersec < PHYSICAL_SECTOR_SIZE + || fat_bpb->bpb_bytspersec % PHYSICAL_SECTOR_SIZE) { - DEBUGF( "bpb_is_sane() - Error: sector size is not 512 (%d)\n", + DEBUGF( "bpb_is_sane() - Error: sector size is not sane (%d)\n", fat_bpb->bpb_bytspersec); return -1; } + if((long)fat_bpb->bpb_secperclus * (long)fat_bpb->bpb_bytspersec > 128L*1024L) { DEBUGF( "bpb_is_sane() - Error: cluster size is larger than 128K " @@ -555,17 +566,20 @@ static void flush_fat_sector(struct fat_cache_entry *fce, { int rc; long secnum; + int secmult; /* With multivolume, use only the FAT info from the cached sector! */ #ifdef HAVE_MULTIVOLUME - secnum = fce->secnum + fce->fat_vol->startsector; + secmult = fce->fat_vol->secmult; + secnum = (fce->secnum * secmult) + fce->fat_vol->startsector; #else - secnum = fce->secnum + fat_bpbs[0].startsector; + secmult = fat_bpbs[0].secmult; + secnum = (fce->secnum * secmult) + fat_bpbs[0].startsector; #endif /* Write to the first FAT */ rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,) - secnum, 1, + secnum, secmult, sectorbuf); if(rc < 0) { @@ -581,12 +595,12 @@ static void flush_fat_sector(struct fat_cache_entry *fce, { /* Write to the second FAT */ #ifdef HAVE_MULTIVOLUME - secnum += fce->fat_vol->fatsize; + secnum += fce->fat_vol->fatsize * secmult; #else - secnum += fat_bpbs[0].fatsize; + secnum += fat_bpbs[0].fatsize * secmult; #endif rc = ata_write_sectors(IF_MV2(fce->fat_vol->drive,) - secnum, 1, sectorbuf); + secnum, secmult, sectorbuf); if(rc < 0) { panicf("flush_fat_sector() - Could not write sector %ld" @@ -632,8 +646,8 @@ static void *cache_fat_sector(IF_MV2(struct bpb* fat_bpb,) if(!fce->inuse) { rc = ata_read_sectors(IF_MV2(fat_bpb->drive,) - secnum + fat_bpb->startsector,1, - sectorbuf); + (secnum * fat_bpb->secmult) + fat_bpb->startsector, + fat_bpb->secmult, sectorbuf); if(rc < 0) { DEBUGF( "cache_fat_sector() - Could not read sector %ld" @@ -809,10 +823,10 @@ static int update_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry, un static long read_fat_entry(IF_MV2(struct bpb* fat_bpb,) unsigned long entry) { -#ifdef HAVE_FAT16SUPPORT #ifndef HAVE_MULTIVOLUME struct bpb* fat_bpb = &fat_bpbs[0]; #endif +#ifdef HAVE_FAT16SUPPORT if (fat_bpb->is_fat16) { int sector = entry / CLUSTERS_PER_FAT16_SECTOR; @@ -876,7 +890,7 @@ static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb)) #ifndef HAVE_MULTIVOLUME struct bpb* fat_bpb = &fat_bpbs[0]; #endif - unsigned char fsinfo[SECTOR_SIZE]; + unsigned char fsinfo[MAX_SECTOR_SIZE]; unsigned long* intptr; int rc; @@ -887,7 +901,8 @@ static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb)) /* update fsinfo */ rc = ata_read_sectors(IF_MV2(fat_bpb->drive,) - fat_bpb->startsector + fat_bpb->bpb_fsinfo, 1,fsinfo); + fat_bpb->startsector + + (fat_bpb->bpb_fsinfo * fat_bpb->secmult), 1, fsinfo); if (rc < 0) { DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", rc); @@ -900,7 +915,8 @@ static int update_fsinfo(IF_MV_NONVOID(struct bpb* fat_bpb)) *intptr = htole32(fat_bpb->fsinfo.nextfree); rc = ata_write_sectors(IF_MV2(fat_bpb->drive,) - fat_bpb->startsector + fat_bpb->bpb_fsinfo,1,fsinfo); + fat_bpb->startsector + + (fat_bpb->bpb_fsinfo * fat_bpb->secmult), 1, fsinfo); if (rc < 0) { DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", rc); @@ -1036,7 +1052,12 @@ static int write_long_name(struct fat_file* file, const unsigned char* shortname, bool is_directory) { - unsigned char buf[SECTOR_SIZE]; +#ifdef HAVE_MULTIVOLUME + struct bpb *fat_bpb = &fat_bpbs[file->volume]; +#else + struct bpb *fat_bpb = &fat_bpbs[0]; +#endif + unsigned char buf[MAX_SECTOR_SIZE]; unsigned char* entry; unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR; unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR; @@ -1194,7 +1215,7 @@ static int add_dir_entry(struct fat_dir* dir, #else struct bpb* fat_bpb = &fat_bpbs[0]; #endif - unsigned char buf[SECTOR_SIZE]; + unsigned char buf[MAX_SECTOR_SIZE]; unsigned char shortname[12]; int rc; unsigned int sector; @@ -1429,7 +1450,12 @@ static void randomize_dos_name(unsigned char *name) static int update_short_entry( struct fat_file* file, long size, int attr ) { - unsigned char buf[SECTOR_SIZE]; +#ifdef HAVE_MULTIVOLUME + struct bpb *fat_bpb = &fat_bpbs[file->volume]; +#else + struct bpb *fat_bpb = &fat_bpbs[0]; +#endif + unsigned char buf[MAX_SECTOR_SIZE]; int sector = file->direntry / DIR_ENTRIES_PER_SECTOR; unsigned char* entry = buf + DIR_ENTRY_SIZE * (file->direntry % DIR_ENTRIES_PER_SECTOR); @@ -1594,7 +1620,7 @@ int fat_create_dir(const char* name, #else struct bpb* fat_bpb = &fat_bpbs[0]; #endif - unsigned char buf[SECTOR_SIZE]; + unsigned char buf[MAX_SECTOR_SIZE]; int i; long sector; int rc; @@ -1716,10 +1742,10 @@ int fat_closewrite(struct fat_file *file, long size, int attr) LDEBUGF("cluster %ld: %lx\n", count, next); count++; } - len = count * fat_bpb->bpb_secperclus * SECTOR_SIZE; + len = count * fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec; LDEBUGF("File is %ld clusters (chainlen=%ld, size=%ld)\n", count, len, size ); - if ( len > size + fat_bpb->bpb_secperclus * SECTOR_SIZE) + if ( len > size + fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec) panicf("Cluster chain is too long\n"); if ( len < size ) panicf("Cluster chain is too short\n"); @@ -1731,7 +1757,12 @@ int fat_closewrite(struct fat_file *file, long size, int attr) static int free_direntries(struct fat_file* file) { - unsigned char buf[SECTOR_SIZE]; +#ifdef HAVE_MULTIVOLUME + struct bpb *fat_bpb = &fat_bpbs[file->volume]; +#else + struct bpb *fat_bpb = &fat_bpbs[0]; +#endif + unsigned char buf[MAX_SECTOR_SIZE]; struct fat_file dir; int numentries = file->direntries; unsigned int entry = file->direntry - numentries + 1; @@ -1933,6 +1964,9 @@ static int transfer(IF_MV2(struct bpb* fat_bpb,) struct bpb* fat_bpb = &fat_bpbs[0]; #endif int rc; + + start *= fat_bpb->secmult; + count *= fat_bpb->secmult; LDEBUGF("transfer(s=%lx, c=%lx, %s)\n", start+ fat_bpb->startsector, count, write?"write":"read"); @@ -1945,9 +1979,9 @@ static int transfer(IF_MV2(struct bpb* fat_bpb,) #endif firstallowed = fat_bpb->firstdatasector; - if (start < firstallowed) + if (start < (firstallowed * fat_bpb->secmult)) panicf("Write %ld before data\n", firstallowed - start); - if (start + count > fat_bpb->totalsectors) + if (start + count > (fat_bpb->totalsectors * fat_bpb->secmult)) panicf("Write %ld after data\n", start + count - fat_bpb->totalsectors); rc = ata_write_sectors(IF_MV2(fat_bpb->drive,) @@ -2041,13 +2075,14 @@ long fat_readwrite( struct fat_file *file, long sectorcount, first = sector; if ( ((sector != first) && (sector != last+1)) || /* not sequential */ - (last-first+1 == 256) ) { /* max 256 sectors per ata request */ + (last-first+1 == (256 / fat_bpb->secmult)) ) { + /* max 256 sectors per ata request */ long count = last - first + 1; rc = transfer(IF_MV2(fat_bpb,) first, count, buf, write ); if (rc < 0) return rc * 10 - 1; - buf = (char *)buf + count * SECTOR_SIZE; + buf = (char *)buf + count * fat_bpb->bpb_bytspersec; first = sector; } @@ -2077,6 +2112,16 @@ long fat_readwrite( struct fat_file *file, long sectorcount, return i; } +int fat_get_secsize(const struct fat_file *file) +{ +#ifdef HAVE_MULTIVOLUME + fat_bpbs[file->volume].bpb_bytspersec; +#else + (void)file; + return fat_bpbs[0].bpb_bytspersec; +#endif +} + int fat_seek(struct fat_file *file, unsigned long seeksector ) { #ifdef HAVE_MULTIVOLUME @@ -2196,6 +2241,11 @@ static int fat_copy_long_name_segment(unsigned char *utf16src, int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) { +#ifdef HAVE_MULTIVOLUME + struct bpb* fat_bpb = &fat_bpbs[dir->file.volume]; +#else + struct bpb* fat_bpb = &fat_bpbs[0]; +#endif bool done = false; int i; int rc; @@ -2229,7 +2279,7 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) } for (i = dir->entry % DIR_ENTRIES_PER_SECTOR; - i < DIR_ENTRIES_PER_SECTOR; i++) + i < (int)DIR_ENTRIES_PER_SECTOR; i++) { unsigned int entrypos = i * DIR_ENTRY_SIZE; @@ -2283,20 +2333,20 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) 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 )) + if ( sectoridx >= fat_bpb->bpb_bytspersec ) { + if ( sectoridx >= fat_bpb->bpb_bytspersec*2 ) { + if ( ( index >= fat_bpb->bpb_bytspersec ) && + ( index < fat_bpb->bpb_bytspersec*2 )) ptr = dir->sectorcache[1]; else ptr = dir->sectorcache[2]; } else { - if ( index < SECTOR_SIZE ) + if ( index < fat_bpb->bpb_bytspersec ) ptr = dir->sectorcache[1]; } - index &= SECTOR_SIZE-1; + index &= fat_bpb->bpb_bytspersec-1; } /* Try to append each segment of the long name. Check if we'd @@ -2356,10 +2406,10 @@ 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 ); + memcpy( dir->sectorcache[2], dir->sectorcache[0], fat_bpb->bpb_bytspersec ); else - memcpy( dir->sectorcache[1], dir->sectorcache[0], SECTOR_SIZE ); - sectoridx += SECTOR_SIZE; + memcpy( dir->sectorcache[1], dir->sectorcache[0], fat_bpb->bpb_bytspersec ); + sectoridx += fat_bpb->bpb_bytspersec; } return 0; @@ -2371,7 +2421,7 @@ unsigned int fat_get_cluster_size(IF_MV_NONVOID(int volume)) const int volume = 0; #endif struct bpb* fat_bpb = &fat_bpbs[volume]; - return fat_bpb->bpb_secperclus * SECTOR_SIZE; + return fat_bpb->bpb_secperclus * fat_bpb->bpb_bytspersec; } #ifdef HAVE_MULTIVOLUME diff --git a/firmware/export/fat.h b/firmware/export/fat.h index 4cdc479844..4110f765a3 100644 --- a/firmware/export/fat.h +++ b/firmware/export/fat.h @@ -22,8 +22,16 @@ #include #include "ata.h" /* for volume definitions */ +#include "config.h" -#define SECTOR_SIZE 512 +#define PHYSICAL_SECTOR_SIZE 512 + +/* Some never players (such as iPod 5.5G) might have 2048 bytes per sector. */ +#ifdef IPOD_VIDEO +#define MAX_SECTOR_SIZE 2048 +#else +#define MAX_SECTOR_SIZE 512 +#endif /* Number of bytes reserved for a file name (including the trailing \0). Since names are stored in the entry as UTF-8, we won't be able to @@ -78,7 +86,7 @@ struct fat_dir unsigned int entrycount; long sector; struct fat_file file; - unsigned char sectorcache[3][SECTOR_SIZE]; + unsigned char sectorcache[3][MAX_SECTOR_SIZE]; }; @@ -101,6 +109,7 @@ extern int fat_create_file(const char* name, extern long fat_readwrite(struct fat_file *ent, long sectorcount, void* buf, bool write ); extern int fat_closewrite(struct fat_file *ent, long size, int attr); +extern int fat_get_secsize(const struct fat_file *file); extern int fat_seek(struct fat_file *ent, unsigned long sector ); extern int fat_remove(struct fat_file *ent); extern int fat_truncate(const struct fat_file *ent);