Fix a FAT file corruption problem. From Andrew Tridgell

This commit is contained in:
Gregory Nutt 2014-03-04 11:34:54 -06:00
parent b94573e9b2
commit 4f6d6a6aa2
2 changed files with 61 additions and 56 deletions

View File

@ -6807,3 +6807,8 @@
kconfig-frontends tools (2014-3-4)
* configs/stm3220g-eval/telnetd: Configuration converted to use the
kconfig-frontends tools (2014-3-4)
* fs/fat/fs_fat32.c: Fix an error in the FAT logic that can cause file
corruption. The error conditions are rare and only seen with very
large files. From Andrew Tridgell. This replaces a previous, partial
fix for the same problem (2014-3-3).

View File

@ -518,6 +518,28 @@ static ssize_t fat_read(FAR struct file *filep, char *buffer, size_t buflen)
{
bytesread = 0;
/* 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, ff->ff_currentcluster);
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;
}
#ifdef CONFIG_FAT_DMAMEMORY /* Warning avoidance */
fat_read_restart:
#endif
@ -618,28 +640,6 @@ fat_read_restart:
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 (buflen > 0 && ff->ff_sectorsincluster < 1)
{
/* Find the next cluster in the FAT. */
cluster = fat_getcluster(fs, ff->ff_currentcluster);
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);
@ -754,14 +754,46 @@ static ssize_t fat_write(FAR struct file *filep, const char *buffer,
while (buflen > 0)
{
/* Check if the user has provided a buffer large enough to
* hold one or more complete sectors.
/* Check if the current write 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);
}
#ifdef CONFIG_FAT_DMAMEMORY /* Warning avoidance */
fat_write_restart:
#endif
/* Check if the user has provided a buffer large enough to
* hold one or more complete sectors.
*/
nsectors = buflen / fs->fs_hwsectorsize;
if (nsectors > 0 && sectorindex == 0 && !force_indirect)
{
@ -894,38 +926,6 @@ fat_write_restart:
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 (buflen > 0 && 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 */