From 938991c408b7d560260f7664d459a3b2193dc644 Mon Sep 17 00:00:00 2001 From: patacongo Date: Thu, 15 Sep 2011 20:05:00 +0000 Subject: [PATCH] Fix a critical bug in FAT sector management git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3955 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 5 ++++- fs/fat/fs_fat32.c | 47 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index c916d8cf98..a5aaa89a25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2085,4 +2085,7 @@ used. There are other issues with the "a+" modes (see the top-level TODO list). * drivers/usbdev/cdc_serial.c and include/nuttx/usb/cdc.h and cdc_serial.h: - Add support for the CDC ACM serial device class. \ No newline at end of file + Add support for the CDC ACM serial device class. + * fs/fat/fs_fat32.c: Fix a critical bug in the write logic: It a tiny write + cross a sector boundary, then two sector writes will occur. The first part + in the first sector may be written to the wrong sector number. diff --git a/fs/fat/fs_fat32.c b/fs/fat/fs_fat32.c index d41df88d5d..c7157b0917 100644 --- a/fs/fat/fs_fat32.c +++ b/fs/fat/fs_fat32.c @@ -630,6 +630,7 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, int32_t cluster; unsigned int byteswritten; unsigned int writesize; + unsigned int bufsize; unsigned int nsectors; uint8_t *userbuffer = (uint8_t*)buffer; int sectorindex; @@ -776,28 +777,56 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer, goto errout_with_semaphore; } } + else + { + /* But in this rare case, we do have to mark the unused cached + * buffer as the current buffer. + */ + + ff->ff_cachesector = ff->ff_currentsector; + } /* Copy the partial sector from the user buffer */ - writesize = fs->fs_hwsectorsize - sectorindex; - if (writesize > buflen) + bufsize = fs->fs_hwsectorsize - sectorindex; + if (bufsize > buflen) { - /* We will not write to the end of the buffer */ + /* We will not write to the end of the buffer. Set + * write size to the size of the user buffer. + */ writesize = buflen; } else { - /* We will write to the end of the buffer (or beyond) */ + /* We will write to the end of the cached sector and + * perhaps beyond. Set writesize to the number of + * bytes still available in the cached sector. + */ + + writesize = bufsize; + } + + /* Copy the data into the cached sector and make sure that the + * cached sector is marked "dirty" + */ + + memcpy(&ff->ff_buffer[sectorindex], userbuffer, writesize); + ff->ff_bflags |= (FFBUFF_DIRTY|FFBUFF_VALID|FFBUFF_MODIFIED); + + /* Do we need to write more in the next sector? We may need + * to this if we wrote to the end of the cached sector. + */ + + if (writesize >= bufsize) + { + /* We will write to the end of the buffer (or beyond). Bump + * up the current sector number. + */ ff->ff_sectorsincluster--; ff->ff_currentsector++; } - - memcpy(&ff->ff_buffer[sectorindex], userbuffer, writesize); - - ff->ff_bflags |= (FFBUFF_DIRTY|FFBUFF_VALID|FFBUFF_MODIFIED); - ff->ff_cachesector = ff->ff_currentsector; } /* Set up for the next write */