From 2831d048c995917abbf96226f3a23efff3d01d0c Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 7 Sep 2008 20:18:36 +0000 Subject: update git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@893 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/fs/fat/fs_fat32.c | 287 +++++++++++++++++++------------------------- nuttx/fs/fat/fs_fat32.h | 7 +- nuttx/fs/fat/fs_fat32util.c | 43 ++++--- 3 files changed, 155 insertions(+), 182 deletions(-) (limited to 'nuttx/fs') diff --git a/nuttx/fs/fat/fs_fat32.c b/nuttx/fs/fat/fs_fat32.c index f7942e548..6c4f66743 100644 --- a/nuttx/fs/fat/fs_fat32.c +++ b/nuttx/fs/fat/fs_fat32.c @@ -289,7 +289,7 @@ static int fat_open(FAR struct file *filep, const char *relpath, ret = -ENOMEM; goto errout_with_semaphore; } - + /* Create a file buffer to support partial sector accesses */ ff->ff_buffer = (ubyte*)malloc(fs->fs_hwsectorsize); @@ -316,6 +316,8 @@ static int fat_open(FAR struct file *filep, const char *relpath, ((uint32)DIR_GETFSTCLUSTHI(dirinfo.fd_entry) << 16) | DIR_GETFSTCLUSTLO(dirinfo.fd_entry); + ff->ff_currentcluster = ff->ff_startcluster; + ff->ff_sectorsincluster = fs->fs_fatsecperclus; ff->ff_size = DIR_GETFILESIZE(dirinfo.fd_entry); /* Attach the private date to the struct file instance */ @@ -417,13 +419,13 @@ static ssize_t fat_read(FAR struct file *filep, char *buffer, size_t buflen) struct inode *inode; struct fat_mountpt_s *fs; struct fat_file_s *ff; - uint32 cluster; unsigned int bytesread; unsigned int readsize; unsigned int nsectors; - size_t readsector; size_t bytesleft; + sint32 cluster; ubyte *userbuffer = (ubyte*)buffer; + int sectorindex; int ret; /* Sanity checks */ @@ -468,81 +470,38 @@ static ssize_t fat_read(FAR struct file *filep, char *buffer, size_t buflen) buflen = bytesleft; } - /* Loop until either (1) all data has been transferred, or (2) an - * error occurs. - */ + /* Get the first sector to read from. */ - readsize = 0; - readsector = ff->ff_currentsector; - while (buflen > 0) + if (!ff->ff_currentsector) { - /* Get offset into the sector where we begin the read */ - - int sectorindex = filep->f_pos & SEC_NDXMASK(fs); - bytesread = 0; - - /* Check if the current read stream happens to lie on a - * sector boundary. + /* The current sector can be determined from the current cluster + * and the file offset. */ - if (sectorindex == 0) - { - /* Try to read another contiguous sector from the cluster */ - - ff->ff_sectorsincluster--; - - /* Are there unread sectors remaining in the cluster? */ - - if (ff->ff_sectorsincluster > 0) - { - /* Yes.. There are more sectors in this cluster to be read - * just increment the current sector number and read. - */ - - readsector = ff->ff_currentsector + 1; - } - else - { - /* No.. Handle the case of the first sector of the file */ - - if (filep->f_pos == 0) - { - /* Get the first cluster of the file */ - - cluster = ff->ff_startcluster; - } - - /* But in the general case, we have to find the next cluster - * in the FAT. - */ - - else - { - cluster = fat_getcluster(fs, ff->ff_currentcluster); - } - - /* Verify the cluster number */ + ff->ff_currentsector = fat_cluster2sector(fs, ff->ff_currentcluster) + + (SEC_NSECTORS(fs, filep->f_pos) & CLUS_NDXMASK(fs)); + fdbg("Start with sector: %d\n", ff->ff_currentsector); + } - if (cluster < 2 || cluster >= fs->fs_nclusters) - { - ret = -EINVAL; /* Not the right error */ - goto errout_with_semaphore; - } + /* Loop until either (1) all data has been transferred, or (2) an + * error occurs. We assume we start with the current sector + * (ff_currentsector) which may be uninitialized. + */ - /* Setup to read the first sector from the new cluster */ + readsize = 0; + sectorindex = filep->f_pos & SEC_NDXMASK(fs); - ff->ff_currentcluster = cluster; - ff->ff_sectorsincluster = fs->fs_fatsecperclus; - readsector = fat_cluster2sector(fs, cluster); - } - } + while (buflen > 0) + { + bytesread = 0; /* Check if the user has provided a buffer large enough to - * hold one or more complete sectors. + * hold one or more complete sectors -AND- the read is + * aligned to a sector boundary. */ nsectors = buflen / fs->fs_hwsectorsize; - if (nsectors > 0) + if (nsectors > 0 && sectorindex == 0) { /* Read maximum contiguous sectors directly to the user's * buffer without using our tiny read buffer. @@ -563,16 +522,16 @@ static ssize_t fat_read(FAR struct file *filep, char *buffer, size_t buflen) (void)fat_ffcacheinvalidate(fs, ff); - /* Read all of the sectors directory into user memory */ + /* Read all of the sectors directly into user memory */ - ret = fat_hwread(fs, userbuffer, readsector, nsectors); + ret = fat_hwread(fs, userbuffer, ff->ff_currentsector, nsectors); if (ret < 0) { goto errout_with_semaphore; } - ff->ff_sectorsincluster -= nsectors - 1; - ff->ff_currentsector = readsector + nsectors - 1; + ff->ff_sectorsincluster -= nsectors; + ff->ff_currentsector += nsectors; bytesread = nsectors * fs->fs_hwsectorsize; } else @@ -582,7 +541,7 @@ static ssize_t fat_read(FAR struct file *filep, char *buffer, size_t buflen) * it is already there then all is well. */ - ret = fat_ffcacheread(fs, ff, readsector); + ret = fat_ffcacheread(fs, ff, ff->ff_currentsector); if (ret < 0) { goto errout_with_semaphore; @@ -595,9 +554,13 @@ static ssize_t fat_read(FAR struct file *filep, char *buffer, size_t buflen) { bytesread = buflen; } + else + { + ff->ff_sectorsincluster--; + ff->ff_currentsector++; + } memcpy(userbuffer, &ff->ff_buffer[sectorindex], bytesread); - ff->ff_currentsector = readsector; } /* Set up for the next sector read */ @@ -606,6 +569,29 @@ static ssize_t fat_read(FAR struct file *filep, char *buffer, size_t buflen) filep->f_pos += bytesread; readsize += bytesread; buflen -= bytesread; + sectorindex = filep->f_pos & SEC_NDXMASK(fs); + + /* Check if the current read stream has incremented to the next + * cluster boundary + */ + + if (ff->ff_sectorsincluster < 1) + { + /* Find the next cluster in the FAT. */ + + cluster = fat_getcluster(fs, cluster); + if (cluster < 2 || cluster >= fs->fs_nclusters) + { + ret = -EINVAL; /* Not the right error */ + goto errout_with_semaphore; + } + + /* Setup to read the first sector from the new cluster */ + + ff->ff_currentcluster = cluster; + ff->ff_currentsector = fat_cluster2sector(fs, cluster); + ff->ff_sectorsincluster = fs->fs_fatsecperclus; + } } fat_semgive(fs); @@ -627,11 +613,11 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, struct fat_mountpt_s *fs; struct fat_file_s *ff; sint32 cluster; - size_t writesector; unsigned int byteswritten; unsigned int writesize; unsigned int nsectors; ubyte *userbuffer = (ubyte*)buffer; + int sectorindex; int ret; /* Sanity checks */ @@ -671,96 +657,39 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, goto errout_with_semaphore; } - /* Loop until either (1) all data has been transferred, or (2) an - * error occurs. - */ + /* Get the first sector to write to. */ - byteswritten = 0; - writesector = ff->ff_currentsector; - while (buflen > 0) + if (!ff->ff_currentsector) { - /* Get offset into the sector where we begin the read */ - - int sectorindex = filep->f_pos & SEC_NDXMASK(fs); - - /* Check if the current read stream happens to lie on a - * sector boundary. - */ + /* Has the starting cluster been defined? */ - if (sectorindex == 0) + if (ff->ff_startcluster == 0) { - /* Decrement the number of sectors left in this cluster */ - - ff->ff_sectorsincluster--; - - /* Are there unwritten sectors remaining in this cluster */ - - if (ff->ff_sectorsincluster > 0) - { - /* Yes.. There are more sectors in this cluster to be written. - * just increment the current sector number and write. - */ - - writesector = ff->ff_currentsector + 1; - } - else - { - /* No.. Handle the case of the first sector of the file */ - - if (filep->f_pos == 0) - { - /* Check the first cluster of the file. Zero means that - * the file is empty -- perhaps the file was truncated or - * created when it was opened - */ - - if (ff->ff_startcluster == 0) - { - /* In this case, we have to create a new cluster chain */ - - ff->ff_startcluster = fat_createchain(fs); - } - - /* Start writing at the first cluster of the file */ + /* No.. we have to create a new cluster chain */ - cluster = ff->ff_startcluster; - } - - /* But in the general case, we have to extend the current - * cluster by one (unless lseek was used to move the file - * position back from the end of the file) - */ - - else - { - /* Extend the chain by adding a new cluster after - * the last one - */ - - cluster = fat_extendchain(fs, ff->ff_currentcluster); - } + ff->ff_startcluster = fat_createchain(fs); + ff->ff_currentcluster = ff->ff_startcluster; + ff->ff_sectorsincluster = fs->fs_fatsecperclus; + } - /* Verify the cluster number */ + /* The current sector can then be determined from the currentcluster + * and the file offset. + */ - if (cluster < 0) - { - ret = cluster; - goto errout_with_semaphore; - } - else if (cluster < 2 || cluster >= fs->fs_nclusters) - { - ret = -ENOSPC; - goto errout_with_semaphore; - } + ff->ff_currentsector = fat_cluster2sector(fs, ff->ff_currentcluster) + + (SEC_NSECTORS(fs, filep->f_pos) & CLUS_NDXMASK(fs)); + } - /* Setup to write the first sector from the new cluster */ + /* Loop until either (1) all data has been transferred, or (2) an + * error occurs. We assume we start with the current sector in + * cache (ff_currentsector) + */ - ff->ff_currentcluster = cluster; - ff->ff_sectorsincluster = fs->fs_fatsecperclus; - writesector = fat_cluster2sector(fs, cluster); - } - } + byteswritten = 0; + sectorindex = filep->f_pos & SEC_NDXMASK(fs); + while (buflen > 0) + { /* Check if there is unwritten data in the file buffer */ ret = fat_ffcacheflush(fs, ff); @@ -795,16 +724,16 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, (void)fat_ffcacheinvalidate(fs, ff); - /* Write all of the sectors directory from user memory */ + /* Write all of the sectors directly from user memory */ - ret = fat_hwwrite(fs, userbuffer, writesector, nsectors); + ret = fat_hwwrite(fs, userbuffer, ff->ff_currentsector, nsectors); if (ret < 0) { goto errout_with_semaphore; } - ff->ff_sectorsincluster -= nsectors - 1; - ff->ff_currentsector = writesector + nsectors - 1; + ff->ff_sectorsincluster -= nsectors; + ff->ff_currentsector += nsectors; writesize = nsectors * fs->fs_hwsectorsize; ff->ff_bflags |= FFBUFF_MODIFIED; } @@ -823,8 +752,7 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, if (filep->f_pos < ff->ff_size || sectorindex != 0) { - ff->ff_currentsector = writesector; - ret = fat_ffcacheread(fs, ff, writesector); + ret = fat_ffcacheread(fs, ff, ff->ff_currentsector); if (ret < 0) { goto errout_with_semaphore; @@ -838,9 +766,13 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, { writesize = buflen; } + else + { + ff->ff_sectorsincluster--; + ff->ff_currentsector++; + } memcpy(&ff->ff_buffer[sectorindex], userbuffer, writesize); - ff->ff_currentsector = writesector; ff->ff_bflags |= (FFBUFF_DIRTY|FFBUFF_VALID|FFBUFF_MODIFIED); } @@ -850,7 +782,40 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, filep->f_pos += writesize; byteswritten += writesize; buflen -= writesize; - } + sectorindex = filep->f_pos & SEC_NDXMASK(fs); + + /* Check if the current read stream has incremented to the next + * cluster boundary + */ + + if (ff->ff_sectorsincluster < 1) + { + /* Extend the current cluster by one (unless lseek was used to + * move the file position back from the end of the file) + */ + + cluster = fat_extendchain(fs, ff->ff_currentcluster); + + /* Verify the cluster number */ + + if (cluster < 0) + { + ret = cluster; + goto errout_with_semaphore; + } + else if (cluster < 2 || cluster >= fs->fs_nclusters) + { + ret = -ENOSPC; + goto errout_with_semaphore; + } + + /* Setup to write the first sector from the new cluster */ + + ff->ff_currentcluster = cluster; + ff->ff_sectorsincluster = fs->fs_fatsecperclus; + ff->ff_currentsector = fat_cluster2sector(fs, cluster); + } + } /* The transfer has completed without error. Update the file size */ diff --git a/nuttx/fs/fat/fs_fat32.h b/nuttx/fs/fat/fs_fat32.h index 9cad293bb..576e7ea84 100644 --- a/nuttx/fs/fat/fs_fat32.h +++ b/nuttx/fs/fat/fs_fat32.h @@ -162,6 +162,8 @@ #define SEC_NDXMASK(f) ((f)->fs_hwsectorsize - 1) #define SEC_NSECTORS(f,n) ((n) / (f)->fs_hwsectorsize) +#define CLUS_NDXMASK(f) ((f)->fs_fatsecperclus -1) + /**************************************************************************** * File system types */ @@ -515,7 +517,8 @@ struct fat_file_s size_t ff_dirsector; /* Sector containing the directory entry */ off_t ff_size; /* Size of the file in bytes */ size_t ff_startcluster; /* Start cluster of file on media */ - size_t ff_currentsector; /* Current sector in the file buffer */ + size_t ff_currentsector; /* Current sector being operated on */ + size_t ff_cachesector; /* Current sector in the file buffer */ ubyte *ff_buffer; /* File buffer (for partial sector accesses) */ }; @@ -578,7 +581,7 @@ EXTERN int fat_hwwrite(struct fat_mountpt_s *fs, ubyte *buffer, /* Cluster / cluster chain access helpers */ -EXTERN ssize_t fat_cluster2sector(struct fat_mountpt_s *fs, uint32 cluster ); +EXTERN ssize_t fat_cluster2sector(struct fat_mountpt_s *fs, uint32 cluster); EXTERN ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno); EXTERN int fat_putcluster(struct fat_mountpt_s *fs, uint32 clusterno, size_t startsector); diff --git a/nuttx/fs/fat/fs_fat32util.c b/nuttx/fs/fat/fs_fat32util.c index 637e4d1a3..c70c4cb1e 100644 --- a/nuttx/fs/fat/fs_fat32util.c +++ b/nuttx/fs/fat/fs_fat32util.c @@ -858,7 +858,7 @@ ssize_t fat_cluster2sector(struct fat_mountpt_s *fs, uint32 cluster ) /**************************************************************************** * Name: fat_getcluster * - * Desciption: Get the cluster start sector into the FAT. + * Desciption: Get the next cluster start from the FAT. * * Return: <0: error, 0:cluster unassigned, >=0: start sector of cluster * @@ -880,7 +880,7 @@ ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno) { size_t fatsector; unsigned int fatoffset; - unsigned int startsector; + unsigned int cluster; unsigned int fatindex; /* FAT12 is more complex because it has 12-bits (1.5 bytes) @@ -895,13 +895,14 @@ ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno) if (fat_fscacheread(fs, fatsector) < 0) { /* Read error */ + break; } /* Get the first, LS byte of the cluster from the FAT */ - fatindex = fatoffset & SEC_NDXMASK(fs); - startsector = fs->fs_buffer[fatindex]; + fatindex = fatoffset & SEC_NDXMASK(fs); + cluster = fs->fs_buffer[fatindex]; /* With FAT12, the second byte of the cluster number may lie in * a different sector than the first byte. @@ -916,6 +917,7 @@ ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno) if (fat_fscacheread(fs, fatsector) < 0) { /* Read error */ + break; } } @@ -925,21 +927,23 @@ ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno) * on the fact that the byte stream is little-endian. */ - startsector |= (unsigned int)fs->fs_buffer[fatindex] << 8; + cluster |= (unsigned int)fs->fs_buffer[fatindex] << 8; /* Now, pick out the correct 12 bit cluster start sector value */ if ((clusterno & 1) != 0) { /* Odd.. take the MS 12-bits */ - startsector >>= 4; + + cluster >>= 4; } else { /* Even.. take the LS 12-bits */ - startsector &= 0x0fff; + + cluster &= 0x0fff; } - return startsector; + return cluster; } case FSTYPE_FAT16 : @@ -967,7 +971,7 @@ ssize_t fat_getcluster(struct fat_mountpt_s *fs, uint32 clusterno) /* Read error */ break; } - return FAT_GETFAT16(fs->fs_buffer, fatindex) & 0x0fffffff; + return FAT_GETFAT32(fs->fs_buffer, fatindex) & 0x0fffffff; } default: break; @@ -2198,20 +2202,21 @@ int fat_ffcacheflush(struct fat_mountpt_s *fs, struct fat_file_s *ff) * contents of ff_buffer. */ - if (ff->ff_bflags && (FFBUFF_DIRTY|FFBUFF_VALID) == (FFBUFF_DIRTY|FFBUFF_VALID)) - { + if (ff->ff_cachesector && + ff->ff_bflags && (FFBUFF_DIRTY|FFBUFF_VALID) == (FFBUFF_DIRTY|FFBUFF_VALID)) + { /* Write the dirty sector */ - ret = fat_hwwrite(fs, ff->ff_buffer, ff->ff_currentsector, 1); + ret = fat_hwwrite(fs, ff->ff_buffer, ff->ff_cachesector, 1); if (ret < 0) - { + { return ret; - } + } - /* No longer dirty */ + /* No longer dirty, but still valid */ ff->ff_bflags &= ~FFBUFF_DIRTY; - } + } return OK; } @@ -2228,12 +2233,12 @@ int fat_ffcacheread(struct fat_mountpt_s *fs, struct fat_file_s *ff, size_t sect { int ret; - /* ff->ff_currentsector holds the current sector that is buffered in + /* ff->ff_cachesector holds the current sector that is buffered in * ff->ff_buffer. If the requested sector is the same as this sector, then * we do nothing. Otherwise, we will have to read the new sector. */ - if (ff->ff_currentsector != sector || (ff->ff_bflags & FFBUFF_VALID) == 0) + if (ff->ff_cachesector != sector || (ff->ff_bflags & FFBUFF_VALID) == 0) { /* We will need to read the new sector. First, flush the cached * sector if it is dirty. @@ -2255,7 +2260,7 @@ int fat_ffcacheread(struct fat_mountpt_s *fs, struct fat_file_s *ff, size_t sect /* Update the cached sector number */ - ff->ff_currentsector = sector; + ff->ff_cachesector = sector; ff->ff_bflags |= FFBUFF_VALID; } return OK; -- cgit v1.2.3