Squashed commit of the following:

fs/nxffs:  Add partial implementation of the truncate method:  It extend files, but cannot yet shrink them.
    fs/smartfs:  Add partial implementation of the truncate method:  It extend files, but cannot yet shrink them.
    fs/fat:  Add partial implementation of the truncate method:  It extend files, but no yet shrink them.
    fs/nfs:  Add support for the truncate method to the NFS file system.
This commit is contained in:
Gregory Nutt 2018-01-04 10:54:54 -06:00
parent e4652bd3dc
commit 39fe6a0dff
14 changed files with 831 additions and 45 deletions

View File

@ -87,6 +87,7 @@ static int fat_sync(FAR struct file *filep);
static int fat_dup(FAR const struct file *oldp, FAR struct file *newp);
static int fat_fstat(FAR const struct file *filep,
FAR struct stat *buf);
static int fat_truncate(FAR struct file *filep, off_t length);
static int fat_opendir(FAR struct inode *mountpt,
FAR const char *relpath, FAR struct fs_dirent_s *dir);
@ -139,7 +140,7 @@ const struct mountpt_operations fat_operations =
fat_sync, /* sync */
fat_dup, /* dup */
fat_fstat, /* fstat */
NULL, /* truncate */
fat_truncate, /* truncate */
fat_opendir, /* opendir */
NULL, /* closedir */
@ -794,7 +795,7 @@ static ssize_t fat_write(FAR struct file *filep, FAR const char *buffer,
ff->ff_sectorsincluster = fs->fs_fatsecperclus;
}
/* The current sector can then be determined from the currentcluster
/* The current sector can then be determined from the current cluster
* and the file offset.
*/
@ -1622,7 +1623,7 @@ errout_with_semaphore:
*
* Description:
* Obtain information about an open file associated with the file
* descriptor 'fd', and will write it to the area pointed to by 'buf'.
* structure 'filep', and will write it to the area pointed to by 'buf'.
*
****************************************************************************/
@ -1687,6 +1688,240 @@ errout_with_semaphore:
return ret;
}
/****************************************************************************
* Name: fat_truncate
*
* Description:
* Set the length of the open, regular file associated with the file
* structure 'filep' to 'length'.
*
****************************************************************************/
static int fat_truncate(FAR struct file *filep, off_t length)
{
FAR struct inode *inode;
FAR struct fat_mountpt_s *fs;
FAR struct fat_file_s *ff;
int32_t cluster;
off_t remaining;
off_t oldsize;
off_t pos;
unsigned int zerosize;
int sectndx;
int ret;
DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
/* Recover our private data from the struct file instance */
ff = filep->f_priv;
/* Check for the forced mount condition */
if ((ff->ff_bflags & UMOUNT_FORCED) != 0)
{
return -EPIPE;
}
inode = filep->f_inode;
fs = inode->i_private;
DEBUGASSERT(fs != NULL);
/* Make sure that the mount is still healthy */
fat_semtake(fs);
ret = fat_checkmount(fs);
if (ret != OK)
{
goto errout_with_semaphore;
}
/* Check if the file was opened for write access */
if ((ff->ff_oflags & O_WROK) == 0)
{
ret = -EACCES;
goto errout_with_semaphore;
}
/* Are we shrinking the file? Or extending it? */
oldsize = ff->ff_size;
if (oldsize == length)
{
ret = OK;
goto errout_with_semaphore;
}
else if (oldsize > length)
{
/* We are shrinking the file */
/* REVISIT: Logic to shrink the file has not yet been implemented */
ret = -ENOSYS;
goto errout_with_semaphore;
}
/* Otherwise we are extending the file. This is essentially the same as a
* write except that (1) we write zeros and (2) we don't update the file
* position.
*/
pos = ff->ff_size;
/* Get the first sector to write to. */
if (!ff->ff_currentsector)
{
/* Has the starting cluster been defined? */
if (ff->ff_startcluster == 0)
{
/* No.. we have to create a new cluster chain */
ff->ff_startcluster = fat_createchain(fs);
ff->ff_currentcluster = ff->ff_startcluster;
ff->ff_sectorsincluster = fs->fs_fatsecperclus;
}
/* The current sector can then be determined from the current cluster
* and the file offset.
*/
ret = fat_currentsector(fs, ff, pos);
if (ret < 0)
{
goto errout_with_semaphore;
}
}
/* Loop until either (1) the file has been fully extended with zeroed data
* or (2) an error occurs. We assume we start with the current sector in
* cache (ff_currentsector)
*/
sectndx = pos & SEC_NDXMASK(fs);
remaining = length - pos;
while (remaining > 0)
{
/* 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 zero the first sector from the new cluster */
ff->ff_currentcluster = cluster;
ff->ff_sectorsincluster = fs->fs_fatsecperclus;
ff->ff_currentsector = fat_cluster2sector(fs, cluster);
}
/* Decide whether we are performing a read-modify-write
* operation, in which case we have to read the existing sector
* into the buffer first.
*
* There are two cases where we can avoid this read:
*
* - If we are performing a whole-sector clear that was rejected
* by fat_hwwrite(), i.e. sectndx == 0 and remaining >= sector size.
*
* - If the clear is aligned to the beginning of the sector and
* extends beyond the end of the file, i.e. sectndx == 0 and
* file pos + remaining >= file size.
*/
if (sectndx == 0 && (remaining >= fs->fs_hwsectorsize ||
(pos + remaining) >= ff->ff_size))
{
/* Flush unwritten data in the sector cache. */
ret = fat_ffcacheflush(fs, ff);
if (ret < 0)
{
goto errout_with_semaphore;
}
/* Now mark the clean cache buffer as the current sector. */
ff->ff_cachesector = ff->ff_currentsector;
}
else
{
/* Read the current sector into memory (perhaps first flushing the
* old, dirty sector to disk).
*/
ret = fat_ffcacheread(fs, ff, ff->ff_currentsector);
if (ret < 0)
{
goto errout_with_semaphore;
}
}
/* Copy the requested part of the sector from the user buffer */
zerosize = fs->fs_hwsectorsize - sectndx;
if (zerosize > remaining)
{
/* We will not zero to the end of the sector. */
zerosize = remaining;
}
else
{
/* We will zero to the end of the buffer (or beyond). Bump up
* the current sector number (actually the next sector number).
*/
ff->ff_sectorsincluster--;
ff->ff_currentsector++;
}
/* Zero the data into the cached sector and make sure that the cached
* sector is marked "dirty" so that it will be written back.
*/
memset(&ff->ff_buffer[sectndx], 0, zerosize);
ff->ff_bflags |= (FFBUFF_DIRTY | FFBUFF_VALID | FFBUFF_MODIFIED);
/* Set up for the next sector */
pos += zerosize;
remaining -= zerosize;
sectndx = pos & SEC_NDXMASK(fs);
}
/* The truncation has completed without error. Update the file size */
ff->ff_size = length;
ret = OK;
errout_with_semaphore:
fat_semgive(fs);
return ret;
}
/****************************************************************************
* Name: fat_readdir
*

View File

@ -135,11 +135,15 @@ struct nfsstats nfsstats;
* Private Function Prototypes
****************************************************************************/
static int nfs_filecreate(FAR struct nfsmount *nmp, struct nfsnode *np,
FAR const char *relpath, mode_t mode);
static int nfs_filetruncate(FAR struct nfsmount *nmp, struct nfsnode *np);
static int nfs_fileopen(FAR struct nfsmount *nmp, struct nfsnode *np,
FAR const char *relpath, int oflags, mode_t mode);
static int nfs_filecreate(FAR struct nfsmount *nmp,
FAR struct nfsnode *np, FAR const char *relpath,
mode_t mode);
static int nfs_filetruncate(FAR struct nfsmount *nmp,
FAR struct nfsnode *np, uint32_t length);
static int nfs_fileopen(FAR struct nfsmount *nmp,
FAR struct nfsnode *np, FAR const char *relpath,
int oflags, mode_t mode);
static int nfs_open(FAR struct file *filep, const char *relpath,
int oflags, mode_t mode);
static int nfs_close(FAR struct file *filep);
@ -148,6 +152,7 @@ static ssize_t nfs_write(FAR struct file *filep, const char *buffer,
size_t buflen);
static int nfs_dup(FAR const struct file *oldp, FAR struct file *newp);
static int nfs_fstat(FAR const struct file *filep, FAR struct stat *buf);
static int nfs_truncate(FAR struct file *filep, off_t length);
static int nfs_opendir(struct inode *mountpt, const char *relpath,
struct fs_dirent_s *dir);
static int nfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir);
@ -191,7 +196,7 @@ const struct mountpt_operations nfs_operations =
NULL, /* sync */
nfs_dup, /* dup */
nfs_fstat, /* fstat */
NULL, /* truncate */
nfs_truncate, /* truncate */
nfs_opendir, /* opendir */
NULL, /* closedir */
@ -225,7 +230,7 @@ const struct mountpt_operations nfs_operations =
*
****************************************************************************/
static int nfs_filecreate(FAR struct nfsmount *nmp, struct nfsnode *np,
static int nfs_filecreate(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
FAR const char *relpath, mode_t mode)
{
struct file_handle fhandle;
@ -408,7 +413,8 @@ static int nfs_filecreate(FAR struct nfsmount *nmp, struct nfsnode *np,
*
****************************************************************************/
static int nfs_filetruncate(FAR struct nfsmount *nmp, struct nfsnode *np)
static int nfs_filetruncate(FAR struct nfsmount *nmp,
FAR struct nfsnode *np, uint32_t length)
{
FAR uint32_t *ptr;
int reqlen;
@ -436,7 +442,7 @@ static int nfs_filetruncate(FAR struct nfsmount *nmp, struct nfsnode *np)
*ptr++ = nfs_false; /* Don't change uid */
*ptr++ = nfs_false; /* Don't change gid */
*ptr++ = nfs_true; /* Use the following size */
*ptr++ = 0; /* Truncate to zero length */
*ptr++ = length; /* Truncate to the specified length */
*ptr++ = 0;
*ptr++ = HTONL(NFSV3SATTRTIME_TOSERVER); /* Use the server's time */
*ptr++ = HTONL(NFSV3SATTRTIME_TOSERVER); /* Use the server's time */
@ -473,7 +479,7 @@ static int nfs_filetruncate(FAR struct nfsmount *nmp, struct nfsnode *np)
*
****************************************************************************/
static int nfs_fileopen(FAR struct nfsmount *nmp, struct nfsnode *np,
static int nfs_fileopen(FAR struct nfsmount *nmp, FAR struct nfsnode *np,
FAR const char *relpath, int oflags, mode_t mode)
{
struct file_handle fhandle;
@ -550,7 +556,7 @@ static int nfs_fileopen(FAR struct nfsmount *nmp, struct nfsnode *np,
* the SETATTR call by setting the length to zero.
*/
return nfs_filetruncate(nmp, np);
return nfs_filetruncate(nmp, np, 0);
}
return OK;
@ -1202,7 +1208,7 @@ static int nfs_dup(FAR const struct file *oldp, FAR struct file *newp)
*
* Description:
* Obtain information about an open file associated with the file
* descriptor 'fd', and will write it to the area pointed to by 'buf'.
* structure 'filep', and will write it to the area pointed to by 'buf'.
*
****************************************************************************/
@ -1271,6 +1277,50 @@ errout_with_semaphore:
return -error;
}
/****************************************************************************
* Name: nfs_truncate
*
* Description:
* Set the length of the open, regular file associated with the file
* structure 'filep' to 'length'.
*
****************************************************************************/
static int nfs_truncate(FAR struct file *filep, off_t length)
{
struct nfsmount *nmp;
struct nfsnode *np;
int error;
finfo("Truncate to %ld bytes\n", (long)length);
DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
/* Recover our private data from the struct file instance */
nmp = (FAR struct nfsmount *)filep->f_inode->i_private;
np = (FAR struct nfsnode *)filep->f_priv;
DEBUGASSERT(nmp != NULL);
/* Make sure that the mount is still healthy */
nfs_semtake(nmp);
error = nfs_checkmount(nmp);
if (error != OK)
{
ferr("ERROR: nfs_checkmount failed: %d\n", error);
goto errout_with_semaphore;
}
/* Then perform the SETATTR RPC to set the new file size */
error = nfs_filetruncate(nmp, np, length);
errout_with_semaphore:
nfs_semgive(nmp);
return -error;
}
/****************************************************************************
* Name: nfs_opendir
*

View File

@ -34,11 +34,14 @@
############################################################################
ifeq ($(CONFIG_FS_NXFFS),y)
ASRCS +=
CSRCS += nxffs_block.c nxffs_blockstats.c nxffs_cache.c nxffs_dirent.c \
nxffs_dump.c nxffs_initialize.c nxffs_inode.c nxffs_ioctl.c \
nxffs_open.c nxffs_pack.c nxffs_read.c nxffs_reformat.c \
nxffs_stat.c nxffs_unlink.c nxffs_util.c nxffs_write.c
CSRCS += nxffs_block.c nxffs_blockstats.c nxffs_cache.c nxffs_dirent.c
CSRCS += nxffs_dump.c nxffs_initialize.c nxffs_inode.c nxffs_ioctl.c
CSRCS += nxffs_open.c nxffs_pack.c nxffs_read.c nxffs_reformat.c
CSRCS += nxffs_stat.c nxffs_truncate.c nxffs_unlink.c nxffs_util.c
CSRCS += nxffs_write.c
# Include NXFFS build support

View File

@ -1,7 +1,8 @@
/****************************************************************************
* fs/nxffs/nxffs.h
*
* Copyright (C) 2011, 2013, 2015, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2013, 2015, 2017-2018 Gregory Nutt. All rights
* reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References: Linux/Documentation/filesystems/romfs.txt
@ -870,6 +871,26 @@ int nxffs_wrinode(FAR struct nxffs_volume_s *volume,
int nxffs_updateinode(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_entry_s *entry);
/****************************************************************************
* Name: nxffs_wrextend
*
* Description:
* Zero-extend a file.
*
* Input parameters
* volume - Describes the NXFFS volume
* entry - Describes the new inode entry
* length - The new, extended length of the file
*
* Assumptions:
* The caller holds the NXFFS semaphore.
* The caller has verified that the file is writable.
*
****************************************************************************/
int nxffs_wrextend(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile, off_t length);
/****************************************************************************
* Name: nxffs_wrreserve
*
@ -1091,12 +1112,16 @@ ssize_t nxffs_read(FAR struct file *filep, FAR char *buffer, size_t buflen);
ssize_t nxffs_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
int nxffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
int nxffs_dup(FAR const struct file *oldp, FAR struct file *newp);
int nxffs_fstat(FAR const struct file *filep, FAR struct stat *buf);
int nxffs_truncate(FAR struct file *filep, off_t length);
int nxffs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
FAR struct fs_dirent_s *dir);
int nxffs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir);
int nxffs_rewinddir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir);
int nxffs_bind(FAR struct inode *blkdriver, FAR const void *data,
FAR void **handle);
int nxffs_unbind(FAR void *handle, FAR struct inode **blkdriver,

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/nxffs/nxffs_dirent.c
*
* Copyright (C) 2011, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References: Linux/Documentation/filesystems/romfs.txt
@ -47,6 +47,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/fs/dirent.h>

View File

@ -75,7 +75,7 @@ const struct mountpt_operations nxffs_operations =
NULL, /* sync -- No buffered data */
nxffs_dup, /* dup */
nxffs_fstat, /* fstat */
NULL, /* truncate */
nxffs_truncate, /* truncate */
nxffs_opendir, /* opendir */
NULL, /* closedir */

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/nxffs/nxffs_ioctl.c
*
* Copyright (C) 2011, 2013, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2013, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References: Linux/Documentation/filesystems/romfs.txt
@ -46,6 +46,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/mtd/mtd.h>

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/nxffs/nxffs_read.c
*
* Copyright (C) 2011, 2013, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2013, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References: Linux/Documentation/filesystems/romfs.txt
@ -48,6 +48,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mtd/mtd.h>

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/nxffs/nxffs_stat.c
*
* Copyright (C) 2011, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References: Linux/Documentation/filesystems/romfs.txt
@ -50,6 +50,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mtd/mtd.h>

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/nxffs/nxffs_unlink.c
*
* Copyright (C) 2011, 2013, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2013, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References: Linux/Documentation/filesystems/romfs.txt
@ -46,6 +46,7 @@
#include <assert.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mtd/mtd.h>

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/nxffs/nxffs_write.c
*
* Copyright (C) 2011, 2013, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2011, 2013, 2017-2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* References: Linux/Documentation/filesystems/romfs.txt
@ -48,6 +48,7 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/semaphore.h>
#include <nuttx/fs/fs.h>
#include <nuttx/mtd/mtd.h>
@ -327,7 +328,7 @@ static inline int nxffs_reverify(FAR struct nxffs_volume_s *volume,
* volume - Describes the NXFFS volume
* wrfile - Describes the open file to be written.
* buffer - Address of buffer of data to be written.
* buflen - The number of bytes remaimining to be written
* buflen - The number of bytes remaining to be written
*
* Returned Value:
* The number of bytes written is returned on success. Otherwise, a
@ -414,6 +415,96 @@ static inline ssize_t nxffs_wrappend(FAR struct nxffs_volume_s *volume,
return nbytestowrite;
}
/****************************************************************************
* Name: nxffs_zappend
*
* Description:
* Zero-extend FLASH data to the data block.
*
* Input Parameters:
* volume - Describes the NXFFS volume
* wrfile - Describes the open file to be written.
* nzeros - The number of bytes of zeroed data to be written
*
* Returned Value:
* The number of bytes written is returned on success. Otherwise, a
* negated errno value is returned indicating the nature of the failure.
*
****************************************************************************/
static inline ssize_t nxffs_zappend(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile,
off_t nzeros)
{
ssize_t maxsize;
size_t nbytestoclear;
ssize_t remaining;
off_t offset;
int ret;
/* Get the offset to the start of unwritten data */
offset = volume->iooffset + wrfile->datlen + SIZEOF_NXFFS_DATA_HDR;
/* Determine that maximum amount of data that can be written to this
* block.
*/
maxsize = volume->geo.blocksize - offset;
DEBUGASSERT(maxsize > 0);
/* Write as many bytes as we can into the data buffer */
nbytestoclear = MIN(maxsize, nzeros);
remaining = maxsize - nbytestoclear;
if (nbytestoclear > 0)
{
/* Copy the data into the volume write cache */
memset(&volume->cache[offset], 0, nbytestoclear);
/* Increment the number of bytes written to the data block */
wrfile->datlen += nbytestoclear;
/* Re-calculate the CRC */
offset = volume->iooffset + SIZEOF_NXFFS_DATA_HDR;
wrfile->crc = crc32(&volume->cache[offset], wrfile->datlen);
/* And write the partial write block to FLASH -- unless the data
* block is full. In that case, the block will be written below.
*/
if (remaining > 0)
{
ret = nxffs_wrcache(volume);
if (ret < 0)
{
ferr("ERROR: nxffs_wrcache failed: %d\n", -ret);
return ret;
}
}
}
/* Check if the data block is now full */
if (remaining <= 0)
{
/* The data block is full, write the block to FLASH */
ret = nxffs_wrblkhdr(volume, wrfile);
if (ret < 0)
{
ferr("ERROR: nxffs_wrblkdhr failed: %d\n", -ret);
return ret;
}
}
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -534,6 +625,91 @@ errout:
return ret;
}
/****************************************************************************
* Name: nxffs_wrextend
*
* Description:
* Zero-extend a file.
*
* Input parameters
* volume - Describes the NXFFS volume
* entry - Describes the new inode entry
* length - The new, extended length of the file
*
* Assumptions:
* The caller holds the NXFFS semaphore.
* The caller has verified that the file is writable.
*
****************************************************************************/
int nxffs_wrextend(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile, off_t length)
{
ssize_t remaining;
ssize_t nwritten;
off_t oldsize;
int ret;
finfo("Extend file to %ld bytes to offset %d\n", (long)length);
DEBUGASSERT(volume != NULL && wrfile != NULL);
oldsize = wrfile->ofile.entry.datlen;
DEBUGASSERT(length > oldsize);
/* Loop until we successfully appended all of the data to the file (or an
* error occurs)
*/
remaining = length - oldsize;
while (remaining > 0)
{
/* Have we already allocated the data block? */
if (wrfile->doffset == 0)
{
/* No, allocate the data block now, re-packing if necessary. */
wrfile->datlen = 0;
ret = nxffs_wralloc(volume, wrfile, remaining);
if (ret < 0)
{
ferr("ERROR: Failed to allocate a data block: %d\n", -ret);
return ret;
}
}
/* Seek to the FLASH block containing the data block */
nxffs_ioseek(volume, wrfile->doffset);
/* Verify that the FLASH data that was previously written is still intact */
ret = nxffs_reverify(volume, wrfile);
if (ret < 0)
{
ferr("ERROR: Failed to verify FLASH data block: %d\n", -ret);
return ret;
}
/* Append the data to the end of the data block and write the updated
* block to flash.
*/
nwritten = nxffs_zappend(volume, wrfile, remaining);
if (nwritten < 0)
{
ferr("ERROR: Failed to zero extend FLASH data block: %d\n", -ret);
return (int)nwritten;
}
/* Decrement the number of bytes remaining to be written */
remaining -= nwritten;
}
return OK;
}
/****************************************************************************
* Name: nxffs_wrreserve
*

View File

@ -209,12 +209,18 @@
#define SMARTFS_ERASEDSTATE_16BIT (uint16_t) ((CONFIG_SMARTFS_ERASEDSTATE << 8) | \
CONFIG_SMARTFS_ERASEDSTATE)
/* Size of temporary buffer used when a file is zero extended by ftruncate()
* logic.
*/
#define SMARTFS_TRUNCBUFFER_SIZE 512
#ifndef offsetof
#define offsetof(type, member) ( (size_t) &( ( (type *) 0)->member))
# define offsetof(type, member) ((size_t) & (((type *)0)->member))
#endif
#define SMARTFS_NEXTSECTOR(h) ( *((uint16_t *) h->nextsector))
#define SMARTFS_USED(h) ( *((uint16_t *) h->used))
#define SMARTFS_NEXTSECTOR(h) (*((uint16_t *)h->nextsector))
#define SMARTFS_USED(h) (*((uint16_t *)h->used))
#ifdef CONFIG_MTD_SMART_ENABLE_CRC
#define CONFIG_SMARTFS_USE_SECTOR_BUFFER

View File

@ -83,6 +83,7 @@ static int smartfs_dup(FAR const struct file *oldp,
FAR struct file *newp);
static int smartfs_fstat(FAR const struct file *filep,
FAR struct stat *buf);
static int smartfs_truncate(FAR struct file *filep, off_t length);
static int smartfs_opendir(FAR struct inode *mountpt,
FAR const char *relpath,
@ -149,7 +150,7 @@ const struct mountpt_operations smartfs_operations =
smartfs_sync, /* sync */
smartfs_dup, /* dup */
smartfs_fstat, /* fstat */
NULL, /* truncate */
smartfs_truncate, /* truncate */
smartfs_opendir, /* opendir */
NULL, /* closedir */
@ -618,22 +619,23 @@ static int smartfs_sync_internal(struct smartfs_mountpt_s *fs,
{
/* Update the header with the number of bytes written */
header = (struct smartfs_chain_header_s *) sf->buffer;
if (*((uint16_t *) header->used) == SMARTFS_ERASEDSTATE_16BIT)
header = (struct smartfs_chain_header_s *)sf->buffer;
if (*((uint16_t *)header->used) == SMARTFS_ERASEDSTATE_16BIT)
{
*((uint16_t *) header->used) = sf->byteswritten;
*((uint16_t *)header->used) = sf->byteswritten;
}
else
{
*((uint16_t *) header->used) += sf->byteswritten;
*((uint16_t *)header->used) += sf->byteswritten;
}
/* Write the entire sector to FLASH */
readwrite.logsector = sf->currsector;
readwrite.offset = 0;
readwrite.count = fs->fs_llformat.availbytes;
readwrite.buffer = sf->buffer;
readwrite.offset = 0;
readwrite.count = fs->fs_llformat.availbytes;
readwrite.buffer = sf->buffer;
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
if (ret < 0)
{
@ -657,9 +659,10 @@ static int smartfs_sync_internal(struct smartfs_mountpt_s *fs,
/* Read the existing sector used bytes value */
readwrite.logsector = sf->currsector;
readwrite.offset = 0;
readwrite.buffer = (uint8_t *) fs->fs_rwbuffer;
readwrite.count = sizeof(struct smartfs_chain_header_s);
readwrite.offset = 0;
readwrite.buffer = (uint8_t *) fs->fs_rwbuffer;
readwrite.count = sizeof(struct smartfs_chain_header_s);
ret = FS_IOCTL(fs, BIOC_READSECT, (unsigned long) &readwrite);
if (ret < 0)
{
@ -681,8 +684,9 @@ static int smartfs_sync_internal(struct smartfs_mountpt_s *fs,
}
readwrite.offset = offsetof(struct smartfs_chain_header_s, used);
readwrite.count = sizeof(uint16_t);
readwrite.count = sizeof(uint16_t);
readwrite.buffer = (uint8_t *) &fs->fs_rwbuffer[readwrite.offset];
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
if (ret < 0)
{
@ -774,7 +778,9 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
/* Limit the write based on available data to write */
if (readwrite.count > buflen)
readwrite.count = buflen;
{
readwrite.count = buflen;
}
/* Limit the write based on current file length */
@ -1308,6 +1314,286 @@ static int smartfs_fstat(FAR const struct file *filep, FAR struct stat *buf)
return OK;
}
/****************************************************************************
* Name: smartfs_truncate
*
* Description:
* Set the length of the open, regular file associated with the file
* structure 'filep' to 'length'.
*
****************************************************************************/
static int smartfs_truncate(FAR struct file *filep, off_t length)
{
struct smart_read_write_s readwrite;
FAR struct inode *inode;
FAR struct smartfs_mountpt_s *fs;
FAR struct smartfs_ofile_s *sf;
FAR struct smartfs_chain_header_s *header;
#ifndef CONFIG_SMARTFS_USE_SECTOR_BUFFER
FAR uint8_t *buffer;
#endif
off_t remaining;
off_t savepos;
off_t oldsize;
int ret;
DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
/* Recover our private data from the struct file instance */
sf = filep->f_priv;
inode = filep->f_inode;
fs = inode->i_private;
DEBUGASSERT(fs != NULL);
/* Take the semaphore */
smartfs_semtake(fs);
/* Test the permissions. Only allow truncation if the file was opened with
* write flags.
*/
if ((sf->oflags & O_WROK) == 0)
{
ret = -EACCES;
goto errout_with_semaphore;
}
/* Are we shrinking the file? Or extending it? */
oldsize = sf->entry.datlen;
if (oldsize == length)
{
ret = OK;
goto errout_with_semaphore;
}
else if (oldsize > length)
{
/* We are shrinking the file */
/* REVISIT: Logic to shrink the file has not yet been implemented */
ret = -ENOSYS;
goto errout_with_semaphore;
}
/* Otherwise we are extending the file. This is essentially the same as a
* write except that (1) we write zeros and (2) we don't update the file
* position.
*/
#ifndef CONFIG_SMARTFS_USE_SECTOR_BUFFER
/* In order to perform the writes we will have to have a sector buffer. If
* SmartFS is not configured with a sector buffer then we will, then we
* will, unfortunately, need to allocate one.
*/
buffer = (FAR uint8_t *)kmm_malloc(SMARTFS_TRUNCBUFFER_SIZE);
if (buffer == NULL)
{
ret = -ENOMEM;
goto errout_with_semaphore;
}
#endif
/* Seek to the end of the file (remembering the current file position) */
savepos = sf->filepos;
(void)smartfs_seek_internal(fs, sf, 0, SEEK_END);
/* Loop until either (1) the file has been fully extended with zeroed data
* or (2) an error occurs. We assume we start with the current sector in
* cache (ff_currentsector)
*/
remaining = length - oldsize;
while (remaining > 0)
{
/* We will fill up the current sector. Write data to the current
* sector first.
*/
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
readwrite.count = fs->fs_llformat.availbytes - sf->curroffset;
if (readwrite.count > remaining)
{
readwrite.count = remaining;
}
memset(&sf->buffer[sf->curroffset], 0, readwrite.count);
sf->bflags |= SMARTFS_BFLAG_DIRTY;
#else /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
readwrite.offset = sf->curroffset;
readwrite.logsector = sf->currsector;
readwrite.buffer = buffer;
/* Select max size that available in the current sector */
readwrite.count = fs->fs_llformat.availbytes - sf->curroffset;
if (readwrite.count > remaining)
{
/* Limit the write to the size for our smaller working buffer*/
readwrite.count = SMARTFS_TRUNCBUFFER_SIZE;
}
if (readwrite.count > remaining)
{
/* Futher limit the write to the remaining bytes to write */
readwrite.count = remaining;
}
/* Perform the write */
if (readwrite.count > 0)
{
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
if (ret < 0)
{
ferr("ERROR: Error %d writing sector %d data\n",
ret, sf->currsector);
goto errout_with_buffer;
}
}
#endif /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
/* Update our control variables */
sf->entry.datlen += readwrite.count;
sf->byteswritten += readwrite.count;
sf->curroffset += readwrite.count;
remaining -= readwrite.count;
/* Test if we wrote a full sector of data */
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
if (sf->curroffset == fs->fs_llformat.availbytes && remaining)
{
/* First get a new chained sector */
ret = FS_IOCTL(fs, BIOC_ALLOCSECT, 0xFFFF);
if (ret < 0)
{
ferr("ERROR: Error %d allocating new sector\n", ret);
goto errout_with_buffer;
}
/* Copy the new sector to the old one and chain it */
header = (struct smartfs_chain_header_s *) sf->buffer;
*((uint16_t *) header->nextsector) = (uint16_t) ret;
/* Now sync the file to write this sector out */
ret = smartfs_sync_internal(fs, sf);
if (ret != OK)
{
goto errout_with_buffer;
}
/* Record the new sector in our tracking variables and reset the
* offset to "zero".
*/
if (sf->currsector == SMARTFS_NEXTSECTOR(header))
{
/* Error allocating logical sector! */
ferr("ERROR: Duplicate logical sector %d\n", sf->currsector);
}
sf->bflags = SMARTFS_BFLAG_DIRTY;
sf->currsector = SMARTFS_NEXTSECTOR(header);
sf->curroffset = sizeof(struct smartfs_chain_header_s);
memset(sf->buffer, CONFIG_SMARTFS_ERASEDSTATE, fs->fs_llformat.availbytes);
header->type = SMARTFS_DIRENT_TYPE_FILE;
}
#else /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
if (sf->curroffset == fs->fs_llformat.availbytes)
{
/* Sync the file to write this sector out */
ret = smartfs_sync_internal(fs, sf);
if (ret != OK)
{
goto errout_with_buffer;
}
/* Allocate a new sector if needed */
if (remaining > 0)
{
/* Allocate a new sector */
ret = FS_IOCTL(fs, BIOC_ALLOCSECT, 0xFFFF);
if (ret < 0)
{
ferr("ERROR: Error %d allocating new sector\n", ret);
goto errout_with_buffer;
}
/* Copy the new sector to the old one and chain it */
header = (struct smartfs_chain_header_s *)fs->fs_rwbuffer;
*((uint16_t *) header->nextsector) = (uint16_t) ret;
readwrite.offset = offsetof(struct smartfs_chain_header_s,
nextsector);
readwrite.buffer = (uint8_t *) header->nextsector;
readwrite.count = sizeof(uint16_t);
ret = FS_IOCTL(fs, BIOC_WRITESECT, (unsigned long) &readwrite);
if (ret < 0)
{
ferr("ERROR: Error %d writing next sector\n", ret);
goto errout_with_buffer;
}
/* Record the new sector in our tracking variables and
* reset the offset to "zero".
*/
if (sf->currsector == SMARTFS_NEXTSECTOR(header))
{
/* Error allocating logical sector! */
ferr("ERROR: Duplicate logical sector %d\n", sf->currsector);
}
sf->currsector = SMARTFS_NEXTSECTOR(header);
sf->curroffset = sizeof(struct smartfs_chain_header_s);
}
}
#endif /* CONFIG_SMARTFS_USE_SECTOR_BUFFER */
}
/* The file was successfully extended with zeros */
ret = OK;
errout_with_buffer:
/* Restore the original file position */
(void)smartfs_seek_internal(fs, sf, savepos, SEEK_SET);
/* Release the allocated buffer */
#ifdef CONFIG_SMARTFS_USE_SECTOR_BUFFER
kmm_free(buffer);
#endif
errout_with_semaphore:
/* Relinquish exclusive access */
smartfs_semgive(fs);
return ret;
}
/****************************************************************************
* Name: smartfs_opendir
*

View File

@ -89,7 +89,7 @@ int file_truncate(FAR struct file *filep, off_t length)
}
/* A NULL write() method is an indicator of a read-only file system (but
* possible not the only indicator)
* possible not the only indicator -- sufficient, but not necessary")
*/
if (inode->u.i_mops->write == NULL)