9
0
Fork 0

Add file creation logic

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@3542 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2011-04-30 17:29:40 +00:00
parent ffc37c1121
commit b5ec116550
14 changed files with 1249 additions and 167 deletions

View File

@ -79,12 +79,17 @@
# define CONFIG_EXAMPLES_NXFFS_MAXNAME 128
#endif
#if CONFIG_EXAMPLES_NXFFS_MAXNAME > 255
# undef CONFIG_EXAMPLES_NXFFS_MAXNAME
# define CONFIG_EXAMPLES_NXFFS_MAXNAME 255
#endif
#ifndef CONFIG_EXAMPLES_NXFFS_MAXFILE
# define CONFIG_EXAMPLES_NXFFS_MAXFILE 8192
#endif
#ifndef CONFIG_EXAMPLES_NXFFS_GULP
# define CONFIG_EXAMPLES_NXFFS_GULP 347
#ifndef CONFIG_EXAMPLES_NXFFS_MAXIO
# define CONFIG_EXAMPLES_NXFFS_MAXIO 347
#endif
#ifndef CONFIG_EXAMPLES_NXFFS_MAXOPEN
@ -248,12 +253,13 @@ static inline int nxffs_wrfile(void)
for (offset = 0; offset < file->len; )
{
size_t maxio = (rand() % CONFIG_EXAMPLES_NXFFS_MAXIO) + 1;
size_t nbytestowrite = file->len - offset;
ssize_t nbyteswritten;
if (nbytestowrite > CONFIG_EXAMPLES_NXFFS_GULP)
if (nbytestowrite > maxio)
{
nbytestowrite = CONFIG_EXAMPLES_NXFFS_GULP;
nbytestowrite = maxio;
}
nbyteswritten = write(fd, &g_fileimage[offset], nbytestowrite);
@ -270,7 +276,7 @@ static inline int nxffs_wrfile(void)
}
else if (nbyteswritten != nbytestowrite)
{
fprintf(stderr, "Partial write: %d\n");
fprintf(stderr, "Partial write:\n");
fprintf(stderr, " File name: %s\n", file->name);
fprintf(stderr, " File size: %d\n", file->len);
fprintf(stderr, " Write offset: %d\n", offset);

View File

@ -37,8 +37,8 @@ ifeq ($(CONFIG_FS_NXFFS),y)
ASRCS +=
CSRCS += nxffs_block.c nxffs_blockstats.c nxffs_cache.c nxffs_dirent.c \
nxffs_initialize.c nxffs_inode.c nxffs_ioctl.c nxffs_open.c \
nxffs_read.c nxffs_reformat.c nxffs_stat.c nxffs_unlink.c \
nxffs_util.c nxffs_write.c
nxffs_pack.c nxffs_read.c nxffs_reformat.c nxffs_stat.c \
nxffs_unlink.c nxffs_util.c nxffs_write.c
# Argument for dependency checking

View File

@ -6,7 +6,7 @@ actual relationship is determined by the FLASH geometry reported by the MTD
driver.
ERASE LOGICAL Inodes begin with a inode header. inode may
BLOCK BLOCK CONTENTS be marked as "deleted," pending clean-up.
BLOCK BLOCK CONTENTS be marked as "deleted," pending re-packing.
n 4*n --+--------------+
|BBBBBBBBBBBBBB| Logic block header
|IIIIIIIIIIIIII| Inodes begin with a inode header
@ -42,7 +42,7 @@ General operation
supporting wear leveling by using all FLASH blocks equally.
When the FLASH becomes full (no more space at the end of the FLASH), a
clean-up operation must be performed: All inodes marked deleted are
re-packing operation must be performed: All inodes marked deleted are
finally removed and the remaining inodes are packed at the beginning of
the FLASH. Allocations then continue at the freed FLASH memory at the
end of the FLASH.
@ -89,7 +89,7 @@ that you should be aware before opting to use NXFFS:
5. Files may be opened for reading or for writing, but not both: The O_RDWR
open flag is not supported.
6. The clean-up process occurs only during a write when the free FLASH
6. The re-packing process occurs only during a write when the free FLASH
memory at the end of the FLASH is exhausted. Thus, occasionally, file
writing may take a long time.

View File

@ -61,7 +61,7 @@
* the FLASH geometry reported by the MTD driver.
*
* ERASE LOGICAL Inodes begin with a inode header. inode may
* BLOCK BLOCK CONTENTS be marked as "deleted," pending clean-up.
* BLOCK BLOCK CONTENTS be marked as "deleted," pending re-packing.
* n 4*n --+--------------+
* |BBBBBBBBBBBBBB| Logic block header
* |IIIIIIIIIIIIII| Inodes begin with a inode header
@ -95,7 +95,7 @@
* supporting wear leveling by using all FLASH blocks equally.
*
* When the FLASH becomes full (no more space at the end of the FLASH), a
* clean-up operation must be performed: All inodes marked deleted are
* re-packing operation must be performed: All inodes marked deleted are
* finally removed and the remaining inodes are packed at the beginning of
* the FLASH. Allocations then continue at the freed FLASH memory at the
* end of the FLASH.
@ -130,7 +130,7 @@
* string providing some illusion of directories.
* 5. Files may be opened for reading or for writing, but not both: The O_RDWR
* open flag is not supported.
* 6. The clean-up process occurs only during a write when the free FLASH
* 6. The re-packing process occurs only during a write when the free FLASH
* memory at the end of the FLASH is exhausted. Thus, occasionally, file
* writing may take a long time.
* 7. Another limitation is that there can be only a single NXFFS volume
@ -175,7 +175,7 @@
* flash beyond this point is erased.
*/
#define NXFFS_NERASED 128
#define NXFFS_NERASED 128
/****************************************************************************
* Public Types
@ -185,8 +185,8 @@
struct nxffs_block_s
{
uint8_t magic[4]; /* 0-3: Magic number for valid block */
uint8_t state; /* 4: Block state: See BLOCK_STATE_* */
uint8_t magic[4]; /* 0-3: Magic number for valid block */
uint8_t state; /* 4: Block state: See BLOCK_STATE_* */
};
#define SIZEOF_NXFFS_BLOCK_HDR 5
@ -194,25 +194,25 @@ struct nxffs_block_s
struct nxffs_inode_s
{
uint8_t magic[4]; /* 0-3: Magic number for valid inode */
uint8_t state; /* 4: Inode state: See INODE_STATE_* */
uint8_t noffset; /* 5: Offset to the file name from the header */
uint8_t doffset; /* 5: Offset to data from file header */
uint8_t utc[4]; /* 7-9: Creation time */
uint8_t crc[4]; /* 10-13: CRC32 */
uint8_t datlen[4]; /* 14-17: Length of data in bytes */
/* 18-: Variable length file name follows */
uint8_t magic[4]; /* 0-3: Magic number for valid inode */
uint8_t state; /* 4: Inode state: See INODE_STATE_* */
uint8_t namlen; /* 5: Length of the inode name */
uint8_t noffs[4]; /* 6-9: FLASH offset to the file name */
uint8_t doffs[4]; /* 10-13: FLASH offset to the first data block */
uint8_t utc[4]; /* 14-17: Creation time */
uint8_t crc[4]; /* 18-21: CRC32 */
uint8_t datlen[4]; /* 22-25: Length of data in bytes */
};
#define SIZEOF_NXFFS_INODE_HDR 18
#define SIZEOF_NXFFS_INODE_HDR 26
/* This structure defines each packed NXFFS data header on the FLASH media */
struct nxffs_data_s
{
uint8_t magic[4]; /* 0-3: Magic number for valid data */
uint8_t crc[4]; /* 4-7: CRC32 */
uint8_t datlen[4]; /* 8-11: Length of data in bytes */
/* 12-: Variable length data follows */
uint8_t magic[4]; /* 0-3: Magic number for valid data */
uint8_t crc[4]; /* 4-7: CRC32 */
uint8_t datlen[4]; /* 8-11: Length of data in bytes */
/* 12-: Variable length data follows */
};
#define SIZEOF_NXFFS_DATA_HDR 12
@ -222,29 +222,12 @@ struct nxffs_data_s
struct nxffs_entry_s
{
off_t hoffset; /* Offset to the inode on the media */
off_t doffset; /* Offset to the data on the media */
FAR char *name; /* inode name */
uint32_t utc; /* Time stamp */
uint32_t datlen; /* Length of inode data */
};
/* This structure represents the overall state of on NXFFS instance. */
struct nxffs_volume_s
{
FAR struct mtd_dev_s *mtd; /* Supports FLASH access */
sem_t exclsem; /* Used to assure thread-safe access */
struct mtd_geometry_s geo; /* Device geometry */
uint8_t wrbusy: 1; /* 1: Volume open for writing */
uint8_t blkper; /* R/W blocks per erase block */
uint8_t ncached; /* Number of blocks in cache */
uint16_t iooffset; /* Next offset in read/write access (in ioblock) */
off_t inoffset; /* Offset to the first valid inode header */
off_t froffset; /* Offset to the first free byte */
off_t ioblock; /* Current block number being accessed */
off_t cblock; /* Starting block number in cache */
FAR uint8_t *cache; /* Allocated erase block */
off_t hoffset; /* FLASH offset to the inode header */
off_t noffset; /* FLASH offset to the inode name */
off_t doffset; /* FLASH offset to the first data header */
FAR char *name; /* inode name */
uint32_t utc; /* Time stamp */
uint32_t datlen; /* Length of inode data */
};
/* This structure describes the state of one open file. This structure
@ -253,10 +236,10 @@ struct nxffs_volume_s
struct nxffs_ofile_s
{
struct nxffs_ofile_s *flink; /* Supports a singly linked list */
int16_t crefs; /* Reference count */
mode_t mode; /* Open mode */
struct nxffs_entry_s entry; /* Describes the NXFFS inode entry */
struct nxffs_ofile_s *flink; /* Supports a singly linked list */
int16_t crefs; /* Reference count */
mode_t mode; /* Open mode */
struct nxffs_entry_s entry; /* Describes the NXFFS inode entry */
};
/* A file opened for writing require some additional information */
@ -265,7 +248,7 @@ struct nxffs_wrfile_s
{
/* The following fields provide the common open file information. */
struct nxffs_ofile_s ofile;
struct nxffs_ofile_s ofile;
/* The following fields are required to support the current write
* operation. Note that the size of the current block can be determined
@ -279,24 +262,46 @@ struct nxffs_wrfile_s
* 5. If the end of the FLASH block is encountered, the data block CRC is
* calculated and the block header is also written to flash.
* 6. When the file is closed, the final, partial data block is written to
* FLASH in the same way. The final file size is determined, the header
* FLASH in the same way. Any previously identified file with the same
* name is deleted. The final file size is determined, the header
* CRC is calculated, and the inode header is written to FLASH, completing
* the write operation.
*/
uint16_t wrlen; /* Number of bytes written in data block */
off_t dathdr; /* FLASH offset to the current data header */
bool truncate; /* Delete a file of the same name */
uint16_t wrlen; /* Number of bytes written in data block */
off_t dathdr; /* FLASH offset to the current data header */
};
/* This structure represents the overall state of on NXFFS instance. */
struct nxffs_volume_s
{
FAR struct mtd_dev_s *mtd; /* Supports FLASH access */
sem_t exclsem; /* Used to assure thread-safe access */
struct mtd_geometry_s geo; /* Device geometry */
uint8_t wrbusy: 1; /* 1: Volume open for writing */
uint8_t blkper; /* R/W blocks per erase block */
uint8_t ncached; /* Number of blocks in cache */
uint16_t iooffset; /* Next offset in read/write access (in ioblock) */
off_t inoffset; /* Offset to the first valid inode header */
off_t froffset; /* Offset to the first free byte */
off_t nblocks; /* Number of R/W blocks on volume */
off_t ioblock; /* Current block number being accessed */
off_t cblock; /* Starting block number in cache */
FAR struct nxffs_ofile_s *ofiles; /* A singly-linked list of open files */
FAR uint8_t *cache; /* Allocated erase block */
};
/* This structure describes the state of the blocks on the NXFFS volume */
struct nxffs_blkstats_s
{
off_t nblocks; /* Total number of FLASH blocks */
off_t ngood; /* Number of good FLASH blocks found */
off_t nbad; /* Number of well-formatted FLASH blocks marked as bad */
off_t nunformat; /* Number of unformatted FLASH blocks */
off_t ncorrupt; /* Number of blocks with correupted format info */
off_t nblocks; /* Total number of FLASH blocks */
off_t ngood; /* Number of good FLASH blocks found */
off_t nbad; /* Number of well-formatted FLASH blocks marked as bad */
off_t nunformat; /* Number of unformatted FLASH blocks */
off_t ncorrupt; /* Number of blocks with correupted format info */
};
/****************************************************************************
@ -327,10 +332,6 @@ extern const uint8_t g_datamagic[NXFFS_MAGICSIZE];
extern struct nxffs_volume_s g_volume;
#endif
/* A singly-linked list of open files */
extern struct nxffs_ofile_s *g_ofiles;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@ -345,10 +346,11 @@ extern struct nxffs_ofile_s *g_ofiles;
*
* The first, lower limit must be recalculated: (1) initially, (2)
* whenever the first inode is deleted, or (3) whenever inode is moved
* as part of the clean-up operation.
* as part of the file system packing operation.
*
* The second, upper limit must be (1) incremented whenever new file
* data is written, or (2) recalculated as part of the clean-up operation.
* data is written, or (2) recalculated as part of the file system packing
* operation.
*
* Input Parameters:
* volume - Identifies the NXFFS volume
@ -379,7 +381,24 @@ extern int nxffs_limits(FAR struct nxffs_volume_s *volume);
*
****************************************************************************/
extern uint16_t nxffs_rdle16(const uint8_t *val);
extern uint16_t nxffs_rdle16(FAR const uint8_t *val);
/****************************************************************************
* Name: nxffs_wrle16
*
* Description:
* Put a (possibly unaligned) 16-bit little endian value.
*
* Input Parameters:
* dest - A pointer to the first byte to save the little endian value.
* val - The 16-bit value to be saved.
*
* Returned Values:
* None
*
****************************************************************************/
extern void nxffs_wrle16(uint8_t *dest, uint16_t val);
/****************************************************************************
* Name: nxffs_rdle32
@ -397,7 +416,43 @@ extern uint16_t nxffs_rdle16(const uint8_t *val);
*
****************************************************************************/
extern uint32_t nxffs_rdle32(const uint8_t *val);
extern uint32_t nxffs_rdle32(FAR const uint8_t *val);
/****************************************************************************
* Name: nxffs_wrle32
*
* Description:
* Put a (possibly unaligned) 32-bit little endian value.
*
* Input Parameters:
* dest - A pointer to the first byte to save the little endian value.
* val - The 32-bit value to be saved.
*
* Returned Value:
* None
*
****************************************************************************/
extern void nxffs_wrle32(uint8_t *dest, uint32_t val);
/****************************************************************************
* Name: nxffs_erased
*
* Description:
* Check if the block of memory if in the erased state.
*
* Input Parameters:
* buffer - Address of the start of the memory to check.
* buflen - The number of bytes to check.
*
* Returned Values:
* true: memory is erased; false: memory is not erased
*
* Defined in nxffs_util.c
*
****************************************************************************/
extern bool nxffs_erased(FAR const uint8_t *buffer, size_t buflen);
/****************************************************************************
* Name: nxffs_rdcache
@ -701,6 +756,7 @@ extern int nxffs_reformat(FAR struct nxffs_volume_s *volume);
* name is one of the opened files.
*
* Input Parameters:
* volume - Describes the NXFFS volume.
* name - The name of the inode to check.
*
* Returned Value:
@ -712,8 +768,115 @@ extern int nxffs_reformat(FAR struct nxffs_volume_s *volume);
*
****************************************************************************/
extern FAR struct nxffs_ofile_s *nxffs_findofile(FAR const char *name);
extern FAR struct nxffs_ofile_s *nxffs_findofile(FAR struct nxffs_volume_s *volume,
FAR const char *name);
/****************************************************************************
* Name: nxffs_wrreserve
*
* Description:
* Find a valid location for a file system object of 'size'. A valid
* location will have these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire object
* 3. The memory at this location will be fully erased.
*
* This function will only perform the checks of 1) and 2). The
* end-of-filesystem offset, froffset, is update past this memory which,
* in effect, reserves the memory.
*
* Input Parameters:
* volume - Describes the NXFFS volume
* size - The size of the object to be reserved.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* volume->ioblock - Read/write block number of the block containing the
* candidate oject position
* volume->iooffset - The offset in the block to the candidate object
* position.
* volume->froffset - Updated offset to the first free FLASH block after
* the reserved memory.
*
*
* Defined in nxffs_write.c
*
****************************************************************************/
extern int nxffs_wrreserve(FAR struct nxffs_volume_s *volume, size_t size);
/****************************************************************************
* Name: nxffs_wrverify
*
* Description:
* Find a valid location for the object. A valid location will have
* these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire header
* (excluding the file name which may lie in the next block).
* 3. The memory at this location will be fully erased.
*
* This function will only perform the check 3). On entry it assumes the
* following settings (left by nxffs_wrreserve()):
*
* volume->ioblock - Read/write block number of the block containing the
* candidate oject position
* volume->iooffset - The offset in the block to the candidate object
* position.
*
* Input Parameters:
* volume - Describes the NXFFS volume
* size - The size of the object to be verifed.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* volume->ioblock - Read/write block number of the block containing the
* verified object position
* volume->iooffset - The offset in the block to the verified object
* position.
* volume->froffset - Updated offset to the first free FLASH block.
*
****************************************************************************/
extern int nxffs_wrverify(FAR struct nxffs_volume_s *volume, size_t size);
/****************************************************************************
* Name: nxffs_wrblkhdr
*
* Description:
* Write the block header information. This is done (1) whenever the end-
* block is encountered and (2) also when the file is closed in order to
* flush the final block of data to FLASH.
*
* Input Parameters:
* volume - Describes the state of the NXFFS volume
* wrfile - Describes the state of the open file
*
* Returned Value:
* Zero is returned on success; Otherwise, a negated errno value is
* returned to indicate the nature of the failure.
*
* Defined in nxffs_write.c
*
****************************************************************************/
extern int nxffs_wrblkhdr(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile);
/****************************************************************************
* Name: nxffs_rminode
*
@ -733,6 +896,24 @@ extern FAR struct nxffs_ofile_s *nxffs_findofile(FAR const char *name);
extern int nxffs_rminode(FAR struct nxffs_volume_s *volume, FAR const char *name);
/****************************************************************************
* Name: nxffs_pack
*
* Description:
* Pack and re-write the filesystem in order to free up memory at the end
* of FLASH.
*
* Input Parameters:
* volume - The volume to be packed.
*
* Returned Values:
* Zero on success; Otherwise, a negated errno value is returned to
* indicate the nature of the failure.
*
****************************************************************************/
extern int nxffs_pack(FAR struct nxffs_volume_s *volume);
/****************************************************************************
* Standard mountpoint operation methods
*

View File

@ -105,7 +105,7 @@ int nxffs_verifyblock(FAR struct nxffs_volume_s *volume, off_t block)
/* Check if the block has a magic number (meaning that it is not
* erased) and that it is valid (meaning that it is not marked
* for cleanup)
* for deletion)
*/
blkhdr = (FAR struct nxffs_block_s *)volume->cache;
@ -147,7 +147,7 @@ int nxffs_validblock(struct nxffs_volume_s *volume, off_t *block)
/* Loop for each possible block or until a valid block is found */
for (i = *block; i < volume->geo.neraseblocks * volume->blkper; i++)
for (i = *block; i < volume->nblocks; i++)
{
/* Loop until we find a valid block */
@ -161,6 +161,10 @@ int nxffs_validblock(struct nxffs_volume_s *volume, off_t *block)
}
}
/* ENOSPC is special return value that means that there is no further,
* valid blocks left in the volume.
*/
fdbg("No valid block found\n");
return -ENOENT;
return -ENOSPC;
}

View File

@ -206,9 +206,12 @@ int nxffs_initialize(FAR struct mtd_dev_s *mtd)
goto errout_with_volume;
}
/* Get the number of R/W blocks per erase block */
/* Get the number of R/W blocks per erase block and the total number o
* R/W blocks
*/
volume->blkper = volume->geo.erasesize / volume->geo.blocksize;
volume->blkper = volume->geo.erasesize / volume->geo.blocksize;
volume->nblocks = volume->geo.neraseblocks * volume->blkper;
DEBUGASSERT((off_t)volume->blkper * volume->geo.blocksize == volume->geo.erasesize);
/* Check if there is a valid NXFFS file system on the flash */
@ -274,10 +277,11 @@ errout_with_volume:
*
* The first, lower limit must be recalculated: (1) initially, (2)
* whenever the first inode is deleted, or (3) whenever inode is moved
* as part of the clean-up operation.
* as part of the file system packing operation.
*
* The second, upper limit must be (1) incremented whenever new file
* data is written, or (2) recalculated as part of the clean-up operation.
* data is written, or (2) recalculated as part of the file system packing
* operation.
*
* Input Parameters:
* volume - Identifies the NXFFS volume
@ -477,5 +481,9 @@ int nxffs_bind(FAR struct inode *blkdriver, FAR const void *data,
int nxffs_unbind(FAR void *handle, FAR struct inode **blkdriver)
{
return g_ofiles ? -EBUSY : OK;
#ifndef CONFIG_NXFSS_PREALLOCATED
# error "No design to support dynamic allocation of volumes"
#else
return g_volume.ofiles ? -EBUSY : OK;
#endif
}

View File

@ -93,7 +93,7 @@ static int nxffs_rdentry(FAR struct nxffs_volume_s *volume, off_t offset,
struct nxffs_inode_s inode;
uint32_t ecrc;
uint32_t crc;
int namelen;
int namlen;
int ret;
DEBUGASSERT(volume && entry);
@ -119,7 +119,8 @@ static int nxffs_rdentry(FAR struct nxffs_volume_s *volume, off_t offset,
/* Copy the packed header into the user-friendly buffer */
entry->hoffset = offset;
entry->doffset = offset + inode.doffset;
entry->noffset = nxffs_rdle32(inode.noffs);
entry->doffset = nxffs_rdle32(inode.doffs);
entry->utc = nxffs_rdle32(inode.utc);
entry->datlen = nxffs_rdle32(inode.datlen);
@ -132,34 +133,27 @@ static int nxffs_rdentry(FAR struct nxffs_volume_s *volume, off_t offset,
/* Allocate memory to hold the variable-length file name */
namelen = (int)inode.doffset - (int)inode.noffset;
if (namelen < 0)
{
fdbg("Bad offsets, name: %d data: %d\n", inode.noffset, inode.doffset);
return -EIO;
}
entry->name = (FAR char *)kmalloc(namelen+1);
entry->name = (FAR char *)kmalloc(inode.namlen + 1);
if (!entry->name)
{
fdbg("Failed to allocate name, namelen: %d\n", namelen);
fdbg("Failed to allocate name, namlen: %d\n", inode.namlen);
return -ENOMEM;
}
/* Read the file name from the expected offset in FLASH */
nxffs_ioseek(volume, offset + inode.noffset);
ret = nxffs_rddata(volume, (FAR uint8_t*)entry->name, namelen);
nxffs_ioseek(volume, entry->noffset);
ret = nxffs_rddata(volume, (FAR uint8_t*)entry->name, namlen);
if (ret < 0)
{
fdbg("Failed to read inode, offset %d: %d\n", offset, -ret);
return -EIO;
}
entry->name[namelen] = '\0';
entry->name[namlen] = '\0';
/* Finish the CRC calculation and verify the entry */
crc = crc32part(entry->name, namelen, crc);
crc = crc32part((FAR const uint8_t *)entry->name, namlen, crc);
if (crc != ecrc)
{
fdbg("CRC entry: %08x CRC calculated: %08x\n", ecrc, crc);
@ -332,7 +326,7 @@ int nxffs_findinode(FAR struct nxffs_volume_s *volume, FAR const char *name,
int ret;
/* Start with the first valid inode that was discovered when the volume
* was created (or modified after the last cleanup).
* was created (or modified after the last file system re-packing).
*/
offset = volume->inoffset;

View File

@ -43,6 +43,8 @@
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <crc32.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
@ -65,10 +67,6 @@
* Public Variables
****************************************************************************/
/* A singly-linked list of open files */
struct nxffs_ofile_s *g_ofiles;
/****************************************************************************
* Private Variables
****************************************************************************/
@ -78,22 +76,241 @@ struct nxffs_ofile_s *g_ofiles;
****************************************************************************/
/****************************************************************************
* Name: nxffs_create
* Name: nxffs_hdrpos
*
* Description:
* Create a file: Verify the sufficient space exists at the end of the
* FLASH. If so, then write then update entry in preparation for writing.
* Find a valid location for the inode header. A valid location will have
* these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire header
* (excluding the file name which may lie in the next block).
* 3. The memory at this location will be fully erased.
*
* This function will only perform the checks of 1) and 2).
*
* Input Parameters:
* volume - Describes the NXFFS volume
* wrfile - Contains the current guess for the header position. On
* successful return, this field will hold the selected header
* position.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* wrfile->ofile.entry.hoffset - Flash offset to candidate header position
* volume->ioblock - Read/write block number of the block containing the
* header position
* volume->iooffset - The offset in the block to the candidate header
* position.
* volume->froffset - Updated offset to the first free FLASH block.
*
****************************************************************************/
static inline int nxffs_create(FAR struct nxffs_volume_s *volume,
FAR const char *name, mode_t mode,
FAR struct nxffs_ofile_s **ppofile)
static inline int nxffs_hdrpos(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile)
{
#warning "Check if too close to end of block for whole header"
int ret;
/* Reserve memory for the object */
ret = nxffs_wrreserve(volume, SIZEOF_NXFFS_INODE_HDR);
if (ret == OK)
{
/* Save the offset to the FLASH region reserved for the inode header */
wrfile->ofile.entry.hoffset =
volume->ioblock * volume->geo.blocksize + volume->iooffset;
}
return OK;
}
/****************************************************************************
* Name: nxffs_nampos
*
* Description:
* Find a valid location for the inode name. A valid location will have
* these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire name
* 3. The memory at this location will be fully erased.
*
* This function will only perform the checks of 1) and 2).
*
* Input Parameters:
* volume - Describes the NXFFS volume
* wrfile - Contains the current guess for the name position. On
* successful return, this field will hold the selected name
* position.
* namlen - The length of the name.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* wrfile->ofile.entry.noffset - Flash offset to candidate name position
* volume->ioblock - Read/write block number of the block containing the
* name position
* volume->iooffset - The offset in the block to the candidate name
* position.
* volume->froffset - Updated offset to the first free FLASH block.
*
****************************************************************************/
static inline int nxffs_nampos(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile,
int namlen)
{
int ret;
/* Reserve memory for the object */
ret = nxffs_wrreserve(volume, namlen);
if (ret == OK)
{
/* Save the offset to the FLASH region reserved for the inode name */
wrfile->ofile.entry.noffset =
volume->ioblock * volume->geo.blocksize + volume->iooffset;
}
return OK;
}
/****************************************************************************
* Name: nxffs_hdrerased
*
* Description:
* Find a valid location for the inode header. A valid location will have
* these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire header
* (excluding the file name which may lie in the next block).
* 3. The memory at this location will be fully erased.
*
* This function will only perform the check 3).
*
* On entry it assumes:
*
* volume->ioblock - Read/write block number of the block containing the
* header position
* volume->iooffset - The offset in the block to the candidate header
* position.
*
* Input Parameters:
* volume - Describes the NXFFS volume
* wrfile - Contains the current guess for the header position. On
* successful return, this field will hold the selected header
* position.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* wrfile->ofile.entry.hoffset - Flash offset to candidate header position
* volume->ioblock - Read/write block number of the block containing the
* header position
* volume->iooffset - The offset in the block to the candidate header
* position.
* volume->froffset - Updated offset to the first free FLASH block.
*
****************************************************************************/
static inline int nxffs_hdrerased(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile)
{
int ret;
/* Find a valid location to save the inode header */
ret = nxffs_wrverify(volume, SIZEOF_NXFFS_INODE_HDR);
if (ret == OK)
{
/* This is where we will put the header */
wrfile->ofile.entry.hoffset =
volume->ioblock * volume->geo.blocksize + volume->iooffset;
}
return ret;
}
/****************************************************************************
* Name: nxffs_namerased
*
* Description:
* Find a valid location for the inode name. A valid location will have
* these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire name
* (excluding the file name which may lie in the next block).
* 3. The memory at this location will be fully erased.
*
* This function will only perform the check 3).
*
* On entry it assumes:
*
* volume->ioblock - Read/write block number of the block containing the
* name position
* volume->iooffset - The offset in the block to the candidate name
* position.
*
* Input Parameters:
* volume - Describes the NXFFS volume
* wrfile - Contains the current guess for the name position. On
* successful return, this field will hold the selected name
* position.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* wrfile->ofile.entry.noffset - Flash offset to candidate name position
* volume->ioblock - Read/write block number of the block containing the
* name position
* volume->iooffset - The offset in the block to the candidate name
* position.
* volume->froffset - Updated offset to the first free FLASH block.
*
****************************************************************************/
static inline int nxffs_namerased(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile,
int namlen)
{
int ret;
/* Find a valid location to save the inode name */
ret = nxffs_wrverify(volume, namlen);
if (ret == OK)
{
/* This is where we will put the name */
wrfile->ofile.entry.hoffset =
volume->ioblock * volume->geo.blocksize + volume->iooffset;
}
return ret;
}
/****************************************************************************
* Name: nxffs_wropen
*
@ -109,6 +326,9 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
{
FAR struct nxffs_wrfile_s *wrfile;
FAR struct nxffs_entry_s entry;
bool packed;
bool truncate = false;
int namlen;
int ret;
/* Limitation: Only a single writer is permitted. Writing may involve
@ -119,7 +339,8 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
if (volume->wrbusy)
{
fdbg("There is already a file writer\n");
return -ENOSYS;
ret = -ENOSYS;
goto errout;
}
/* Check if the file exists */
@ -134,7 +355,8 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
{
fdbg("File exists, can't create O_EXCL\n");
return -EEXIST;
ret = -EEXIST;
goto errout;
}
/* Were we asked to truncate the file? NOTE: Don't truncate the
@ -144,15 +366,12 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
else if ((mode & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC))
{
/* Just remove the file and fall through to re-create it */
#warning "Should defer file removal until new file successfully written"
/* Just schedule the removal the file and fall through to re-create it.
* Note that the old file of the same name will not actually be removed
* until the new file is successfully written.
*/
ret = nxffs_rminode(volume, name);
if (ret < 0)
{
fdbg("nxffs_rminode failed: %d\n", -ret);
return ret;
}
truncate = true;
}
/* The file exists and we were not asked to truncate (and recreate) it.
@ -162,7 +381,8 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
else
{
fdbg("File %s exists and we were not asked to truncate it\n");
return -ENOSYS;
ret = -ENOSYS;
goto errout;
}
}
@ -173,7 +393,18 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
if ((mode & O_CREAT) == 0)
{
fdbg("Not asked to create the file\n");
return -ENOENT;
ret = -ENOENT;
goto errout;
}
/* Make sure that the length of the file name will fit in a uint8_t */
namlen = strlen(name);
if (namlen > UINT8_MAX)
{
fdbg("Name is too long: %d\n", namlen);
ret = -EINVAL;
goto errout;
}
/* Yes.. Create a new structure that will describe the state of this open
@ -184,21 +415,134 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
wrfile = (FAR struct nxffs_wrfile_s *)kzalloc(sizeof(struct nxffs_wrfile_s));
if (!wrfile)
{
return -ENOMEM;
ret = -ENOMEM;
goto errout;
}
/* Initialize the open file state structure */
wrfile->ofile.crefs = 1;
wrfile->ofile.crefs = 1;
wrfile->ofile.mode = O_WROK;
wrfile->ofile.entry.utc = time(NULL);
wrfile->truncate = truncate;
/* Allocate FLASH memory for the file and set up for the write */
/* Allocate FLASH memory for the file and set up for the write.
*
* Loop until the inode header is configured or until a failure occurs.
* Note that nothing is written to FLASH. The inode header is not
* written until the file is closed.
*/
#warning "Missing Logic"
packed = false;
for (;;)
{
/* File a valid location to position the inode header. Start with the
* first byte in the free FLASH region.
*/
ret = nxffs_hdrpos(volume, wrfile);
if (ret == OK)
{
/* Find a region of memory in the block that is fully erased */
ret = nxffs_hdrerased(volume, wrfile);
if (ret == OK)
{
/* Valid memory for the inode header was found. Break out of
* the loop.
*/
break;
}
}
/* If no valid memory is found searching to the end of the volume,
* then -ENOSPC will be returned. Other errors are not handled.
*/
if (ret != -ENOSPC || packed)
{
fdbg("Failed to find inode header memory: %d\n", -ret);
goto errout_with_ofile;
}
/* -ENOSPC is a special case.. It means that the volume is full.
* Try to pack the volume in order to free up some space.
*/
ret = nxffs_pack(volume);
if (ret < 0)
{
fdbg("Failed to pack the volume: %d\n", -ret);
goto errout_with_ofile;
}
/* After packing the volume, froffset will be updated to point to the
* new free flash region. Try again.
*/
packed = true;
}
/* Loop until the inode name is configured or until a failure occurs.
* Note that nothing is written to FLASH. The inode name is not
* written until the file is closed.
*/
for (;;)
{
/* File a valid location to position the inode name. Start with the
* first byte in the free FLASH region.
*/
ret = nxffs_nampos(volume, wrfile, namlen);
if (ret == OK)
{
/* Find a region of memory in the block that is fully erased */
ret = nxffs_namerased(volume, wrfile, namlen);
if (ret == OK)
{
/* Valid memory for the inode header was found. Break out of
* the loop.
*/
break;
}
}
/* If no valid memory is found searching to the end of the volume,
* then -ENOSPC will be returned. Other errors are not handled.
*/
if (ret != -ENOSPC || packed)
{
fdbg("Failed to find inode name memory: %d\n", -ret);
goto errout_with_ofile;
}
/* -ENOSPC is a special case.. It means that the volume is full.
* Try to pack the volume in order to free up some space.
*/
ret = nxffs_pack(volume);
if (ret < 0)
{
fdbg("Failed to pack the volume: %d\n", -ret);
goto errout_with_ofile;
}
/* After packing the volume, froffset will be updated to point to the
* new free flash region. Try again.
*/
packed = true;
}
/* Add the open file structure to the head of the list of open files */
wrfile->ofile.flink = g_ofiles;
g_ofiles = &wrfile->ofile;
wrfile->ofile.flink = volume->ofiles;
volume->ofiles = &wrfile->ofile;
/* Indicate that the volume is open for writing and return the open file
* instance.
@ -207,6 +551,11 @@ static inline int nxffs_wropen(FAR struct nxffs_volume_s *volume,
volume->wrbusy = 1;
*ppofile = &wrfile->ofile;
return OK;
errout_with_ofile:
kfree(wrfile);
errout:
return ret;
}
/****************************************************************************
@ -226,7 +575,7 @@ static inline int nxffs_rdopen(FAR struct nxffs_volume_s *volume,
/* Check if the file has already been opened (for reading) */
ofile = nxffs_findofile(name);
ofile = nxffs_findofile(volume, name);
if (ofile)
{
/* The file is already open.
@ -263,7 +612,8 @@ static inline int nxffs_rdopen(FAR struct nxffs_volume_s *volume,
/* Initialize the open file state structure */
ofile->crefs = 1;
ofile->crefs = 1;
ofile->mode = O_RDOK;
/* Find the file on this volume associated with this file name */
@ -277,8 +627,8 @@ static inline int nxffs_rdopen(FAR struct nxffs_volume_s *volume,
/* Add the open file structure to the head of the list of open files */
ofile->flink = g_ofiles;
g_ofiles = ofile;
ofile->flink = volume->ofiles;
volume->ofiles = ofile;
}
/* Return the open file state structure */
@ -295,14 +645,15 @@ static inline int nxffs_rdopen(FAR struct nxffs_volume_s *volume,
*
****************************************************************************/
static inline void nxffs_freeofile(FAR struct nxffs_ofile_s *ofile)
static inline void nxffs_freeofile(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_ofile_s *ofile)
{
FAR struct nxffs_ofile_s *prev;
FAR struct nxffs_ofile_s *curr;
/* Find the open file structure to be removed */
for (prev = NULL, curr = g_ofiles;
for (prev = NULL, curr = volume->ofiles;
curr && curr != ofile;
prev = curr, curr = curr->flink);
@ -318,7 +669,7 @@ static inline void nxffs_freeofile(FAR struct nxffs_ofile_s *ofile)
}
else
{
g_ofiles = ofile->flink;
volume->ofiles = ofile->flink;
}
/* Then free the open file */
@ -332,6 +683,146 @@ static inline void nxffs_freeofile(FAR struct nxffs_ofile_s *ofile)
}
}
/****************************************************************************
* Name: nxffs_wrclose
*
* Description:
* Perform special operations when a file is closed:
* 1. Write the file block header
* 2. Remove any file with the same name that was discovered when the
* file was open for writing, and finally,
* 3. Write the new file inode.
*
* Input parameters
* volume - Describes the NXFFS volume
* wrfile - Describes the state of the open file
*
****************************************************************************/
static int nxffs_wrclose(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile)
{
FAR struct nxffs_inode_s *inode;
off_t namblock;
uint16_t namoffset;
uint32_t crc;
int namlen;
int ret;
/* Write the final file block header */
ret = nxffs_wrblkhdr(volume, wrfile);
if (ret < 0)
{
fdbg("Failed to write the final block of the file: %d\n", -ret);
goto errout;
}
if (wrfile->truncate)
{
fvdbg("Removing old file: %s\n", wrfile->ofile.entry.name);
ret = nxffs_rminode(volume, wrfile->ofile.entry.name);
if (ret < 0)
{
fdbg("nxffs_rminode failed: %d\n", -ret);
goto errout;
}
}
/* Write the inode header to FLASH. First get the block where we will
* write the file name.
*/
nxffs_ioseek(volume, wrfile->ofile.entry.noffset);
namblock = volume->ioblock;
namoffset = volume->iooffset;
/* Now seek to the inode header position and assure that it is in the
* volume cache.
*/
nxffs_ioseek(volume, wrfile->ofile.entry.hoffset);
ret = nxffs_rdcache(volume, volume->ioblock, 1);
if (ret < 0)
{
fdbg("Failed to read inode header block %d: %d\n", volume->ioblock, -ret);
goto errout;
}
/* Get the length of the inode name */
namlen = strlen(wrfile->ofile.entry.name);
DEBUGASSERT(namlen < UINT8_MAX); /* This was verified earlier */
/* Initialize the inode header */
inode = (FAR struct nxffs_inode_s *)&volume->cache[volume->iooffset];
memcmp(inode->magic, g_inodemagic, NXFFS_MAGICSIZE);
inode->state = CONFIG_NXFFS_ERASEDSTATE;
inode->namlen = namlen;
nxffs_wrle32(inode->noffs, wrfile->ofile.entry.noffset);
nxffs_wrle32(inode->doffs, wrfile->ofile.entry.doffset);
nxffs_wrle32(inode->utc, wrfile->ofile.entry.utc);
nxffs_wrle32(inode->crc, 0);
nxffs_wrle32(inode->noffs, wrfile->ofile.entry.datlen);
/* Calculate the CRC */
crc = crc32((FAR const uint8_t *)inode, SIZEOF_NXFFS_INODE_HDR);
crc = crc32part((FAR const uint8_t *)wrfile->ofile.entry.name, namlen, crc);
/* Finish the inode header */
inode->state = INODE_STATE_FILE;
nxffs_wrle32(inode->crc, crc);
/* Are the inode header and the inode name in the same block? Normally,
* they will be in the same block. However, they could potentially be
* far apart due to intervening bad blocks.
*/
if (volume->ioblock != namblock)
{
/* Write the block with the inode header */
ret = nxffs_wrcache(volume, volume->ioblock, 1);
if (ret < 0)
{
fdbg("Failed to write inode header block %d: %d\n", volume->ioblock, -ret);
goto errout;
}
/* Make sure the that block containing the inode name is in the cache */
volume->ioblock = namblock;
volume->iooffset = namoffset;
ret = nxffs_rdcache(volume, volume->ioblock, 1);
if (ret < 0)
{
fdbg("Failed to read inode name block %d: %d\n", volume->ioblock, -ret);
goto errout;
}
}
/* Finally, copy the inode name to the cache and write the inode name block */
memcpy(&volume->cache[namoffset], wrfile->ofile.entry.name, namlen);
ret = nxffs_wrcache(volume, volume->ioblock, 1);
if (ret < 0)
{
fdbg("Failed to write inode header block %d: %d\n", volume->ioblock, -ret);
}
/* The volume is now available for other writers */
errout:
volume->wrbusy = 0;
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -353,7 +844,8 @@ static inline void nxffs_freeofile(FAR struct nxffs_ofile_s *ofile)
*
****************************************************************************/
FAR struct nxffs_ofile_s *nxffs_findofile(FAR const char *name)
FAR struct nxffs_ofile_s *nxffs_findofile(FAR struct nxffs_volume_s *volume,
FAR const char *name)
{
FAR struct nxffs_ofile_s *ofile;
@ -361,7 +853,7 @@ FAR struct nxffs_ofile_s *nxffs_findofile(FAR const char *name)
* list of open files.
*/
for (ofile = g_ofiles; ofile; ofile = ofile->flink)
for (ofile = volume->ofiles; ofile; ofile = ofile->flink)
{
/* Check for a name match */
@ -501,13 +993,21 @@ int nxffs_close(FAR struct file *filep)
/* Decrement the reference count on the open file */
ret = OK;
if (ofile->crefs == 1)
{
/* Decrementing the reference count would take it zero. Time to
* delete the open file state.
/* Decrementing the reference count would take it zero. Handle
* finalization of the write operation.
*/
nxffs_freeofile(ofile);
if (ofile->mode == O_WROK)
{
ret = nxffs_wrclose(volume, (FAR struct nxffs_wrfile_s *)ofile);
}
/* Delete the open file state structure */
nxffs_freeofile(volume, ofile);
}
else
{
@ -517,7 +1017,6 @@ int nxffs_close(FAR struct file *filep)
}
filep->f_priv = NULL;
ret = OK;
sem_post(&volume->exclsem);
errout:

View File

@ -0,0 +1,88 @@
/****************************************************************************
* fs/nxffs/nxffs_pack.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* References: Linux/Documentation/filesystems/romfs.txt
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include "nxffs.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Variables
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: nxffs_pack
*
* Description:
* Pack and re-write the filesystem in order to free up memory at the end
* of FLASH.
*
* Input Parameters:
* volume - The volume to be packed.
*
* Returned Values:
* Zero on success; Otherwise, a negated errno value is returned to
* indicate the nature of the failure.
*
****************************************************************************/
int nxffs_pack(FAR struct nxffs_volume_s *volume)
{
# warning "Missing logic"
return -ENOSYS;
}

View File

@ -148,12 +148,10 @@ static int nxffs_format(FAR struct nxffs_volume_s *volume)
static int nxffs_badblocks(FAR struct nxffs_volume_s *volume)
{
FAR uint8_t *blkptr; /* Pointer to next block data */
FAR uint8_t *datptr; /* Pointer to next data byte */
off_t eblock; /* Erase block number */
off_t lblock; /* Logical block number */
ssize_t nxfrd; /* Number of blocks transferred */
uint16_t blkndx; /* Logical block data index */
bool bad; /* TRUE: block is bad */
bool good; /* TRUE: block is good */
bool modified; /* TRUE: The erase block has been modified */
int i;
@ -182,32 +180,19 @@ static int nxffs_badblocks(FAR struct nxffs_volume_s *volume)
/* Check block header */
bad = false;
good = true;
if (memcmp(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE) != 0 ||
blkhdr->state != BLOCK_STATE_GOOD)
{
bad = true;;
good = false;
}
/* Check that block data is erased */
else
{
/* Check every byte in the block payload */
for (blkndx = SIZEOF_NXFFS_BLOCK_HDR, datptr = &blkptr[blkndx];
blkndx < volume->geo.blocksize;
blkndx++)
{
/* If the data byte is not in the erased state, then the block is bad */
uint8_t byte = *datptr++;
if (byte != CONFIG_NXFFS_ERASEDSTATE)
{
bad = true;
break;
}
}
good = nxffs_erased(&blkptr[SIZEOF_NXFFS_BLOCK_HDR],
volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR);
}
/* If the block is bad, attempt to re-write the block header indicating
@ -215,7 +200,7 @@ static int nxffs_badblocks(FAR struct nxffs_volume_s *volume)
* possible, depending upon failure modes.
*/
if (bad)
if (!good)
{
memcpy(blkhdr->magic, g_blockmagic, NXFFS_MAGICSIZE);
blkhdr->state = BLOCK_STATE_BAD;

View File

@ -107,7 +107,7 @@ int nxffs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
memset(buf, 0, sizeof(struct statfs));
buf->f_type = NXFFS_MAGIC;
buf->f_bsize = volume->geo.blocksize;
buf->f_blocks = volume->geo.neraseblocks * volume->blkper;
buf->f_blocks = volume->nblocks;
buf->f_namelen = volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR - SIZEOF_NXFFS_INODE_HDR;
ret = OK;

View File

@ -97,7 +97,7 @@ int nxffs_rminode(FAR struct nxffs_volume_s *volume, FAR const char *name)
/* Check if the file is open */
ofile = nxffs_findofile(name);
ofile = nxffs_findofile(volume, name);
if (ofile)
{
/* We can't remove the inode if it is open */

View File

@ -74,16 +74,37 @@
* Input Parameters:
* val - A pointer to the first byte of the little endian value.
*
* Returned Values:
* Returned Value:
* A uint16_t representing the whole 16-bit integer value
*
****************************************************************************/
uint16_t nxffs_rdle16(const uint8_t *val)
uint16_t nxffs_rdle16(FAR const uint8_t *val)
{
return (uint16_t)val[1] << 8 | (uint16_t)val[0];
}
/****************************************************************************
* Name: nxffs_wrle16
*
* Description:
* Put a (possibly unaligned) 16-bit little endian value.
*
* Input Parameters:
* dest - A pointer to the first byte to save the little endian value.
* val - The 16-bit value to be saved.
*
* Returned Value:
* None
*
****************************************************************************/
void nxffs_wrle16(uint8_t *dest, uint16_t val)
{
dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
dest[1] = val >> 8;
}
/****************************************************************************
* Name: nxffs_rdle32
*
@ -93,15 +114,65 @@ uint16_t nxffs_rdle16(const uint8_t *val)
* Input Parameters:
* val - A pointer to the first byte of the little endian value.
*
* Returned Values:
* Returned Value:
* A uint32_t representing the whole 32-bit integer value
*
****************************************************************************/
uint32_t nxffs_rdle32(const uint8_t *val)
uint32_t nxffs_rdle32(FAR const uint8_t *val)
{
/* Little endian means LS halfword first in byte stream */
return (uint32_t)nxffs_rdle16(&val[2]) << 16 | (uint32_t)nxffs_rdle16(val);
}
/****************************************************************************
* Name: nxffs_wrle32
*
* Description:
* Put a (possibly unaligned) 32-bit little endian value.
*
* Input Parameters:
* dest - A pointer to the first byte to save the little endian value.
* val - The 32-bit value to be saved.
*
* Returned Value:
* None
*
****************************************************************************/
void nxffs_wrle32(uint8_t *dest, uint32_t val)
{
/* Little endian means LS halfword first in byte stream */
nxffs_wrle16(dest, (uint16_t)(val & 0xffff));
nxffs_wrle16(dest+2, (uint16_t)(val >> 16));
}
/****************************************************************************
* Name: nxffs_erased
*
* Description:
* Check if the block of memory if in the erased state.
*
* Input Parameters:
* buffer - Address of the start of the memory to check.
* buflen - The number of bytes to check.
*
* Returned Values:
* true: memory is erased; false: memory is not erased
*
****************************************************************************/
bool nxffs_erased(FAR const uint8_t *buffer, size_t buflen)
{
for (; buflen; buflen--)
{
if (*buffer != CONFIG_NXFFS_ERASEDSTATE)
{
return false;
}
buffer++;
}
return true;
}

View File

@ -145,3 +145,249 @@ errout_with_semaphore:
errout:
return ret;
}
/****************************************************************************
* Name: nxffs_wrreserve
*
* Description:
* Find a valid location for a file system object of 'size'. A valid
* location will have these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire object
* 3. The memory at this location will be fully erased.
*
* This function will only perform the checks of 1) and 2). The
* end-of-filesystem offset, froffset, is update past this memory which,
* in effect, reserves the memory.
*
* Input Parameters:
* volume - Describes the NXFFS volume
* size - The size of the object to be reserved.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* volume->ioblock - Read/write block number of the block containing the
* candidate oject position
* volume->iooffset - The offset in the block to the candidate object
* position.
* volume->froffset - Updated offset to the first free FLASH block after
* the reserved memory.
*
****************************************************************************/
int nxffs_wrreserve(FAR struct nxffs_volume_s *volume, size_t size)
{
off_t offset;
int ret;
/* Seek to the beginning of the free FLASH region */
offset = volume->froffset;
nxffs_ioseek(volume, offset);
/* Check for a seek past the end of the volume */
if (volume->ioblock >= volume->nblocks)
{
/* Return -ENOSPC to indicate that the volume is full */
return -ENOSPC;
}
/* Make sure that there is space there to hold the entire object */
DEBUGASSERT(volume->iooffset >= SIZEOF_NXFFS_BLOCK_HDR);
if (volume->iooffset + size > volume->geo.blocksize)
{
/* We will need to skip to the next block. But first, check if we are
* already at the final block.
*/
if (volume->ioblock + 1 >= volume->geo.neraseblocks)
{
/* Return -ENOSPC to indicate that the volume is full */
fdbg("No space in last block\n");
return -ENOSPC;
}
/* This is not the last block in the volume, so just seek to the
* beginning of the next, valid block.
*/
volume->ioblock++;
ret = nxffs_validblock(volume, &volume->ioblock);
if (ret < 0)
{
fdbg("No more valid blocks\n");
return ret;
}
volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR;
offset = volume->ioblock * volume->geo.blocksize + SIZEOF_NXFFS_BLOCK_HDR;
}
/* Update the pointer to the first next free FLASH memory -- reserving this
* block of memory.
*/
volume->froffset = offset + size;
return OK;
}
/****************************************************************************
* Name: nxffs_wrverify
*
* Description:
* Find a valid location for the object. A valid location will have
* these properties:
*
* 1. It will lie in the free flash region.
* 2. It will have enough contiguous memory to hold the entire header
* (excluding the file name which may lie in the next block).
* 3. The memory at this location will be fully erased.
*
* This function will only perform the check 3). On entry it assumes the
* following settings (left by nxffs_wrreserve()):
*
* volume->ioblock - Read/write block number of the block containing the
* candidate oject position
* volume->iooffset - The offset in the block to the candidate object
* position.
*
* Input Parameters:
* volume - Describes the NXFFS volume
* size - The size of the object to be verifed.
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned indicating the nature of the failure. Of special interest
* the return error of -ENOSPC which means that the FLASH volume is
* full and should be repacked.
*
* On successful return the following are also valid:
*
* volume->ioblock - Read/write block number of the block containing the
* verified object position
* volume->iooffset - The offset in the block to the verified object
* position.
* volume->froffset - Updated offset to the first free FLASH block.
*
****************************************************************************/
int nxffs_wrverify(FAR struct nxffs_volume_s *volume, size_t size)
{
uint16_t iooffset;
int nerased;
int ret;
int i;
/* Search to the very last block in the volume if we have to */
while (volume->ioblock < volume->nblocks)
{
/* Make sure that the block is in memory */
ret = nxffs_rdcache(volume, volume->ioblock, 1);
if (ret < 0)
{
fdbg("nxffsx_rdcache failed: %d\n", -ret);
return ret;
}
/* Search to the very end of this block if we have to */
iooffset = volume->iooffset;
nerased = 0;
for (i = volume->iooffset; i <= volume->geo.blocksize - size; i++)
{
/* Is this byte erased? */
if (volume->cache[i] == CONFIG_NXFFS_ERASEDSTATE)
{
/* Yes.. increment the count of contiguous, erased bytes */
nerased++;
/* Is the whole header memory erased? */
if (nerased >= size)
{
/* Yes.. this this is where we will put the object */
off_t offset = volume->ioblock * volume->geo.blocksize + iooffset;
/* Update the free flash offset and return success */
volume->froffset = offset + size;
return OK;
}
}
/* This byte is not erased! (It should be unless the block is bad) */
else
{
nerased = 0;
iooffset = volume->iooffset + 1;
}
}
/* If we get here, then we have looked at every byte in the the block
* and did not find any sequence of erased bytes long enough to hold
* the object. Skip to the next, valid block.
*/
volume->ioblock++;
ret = nxffs_validblock(volume, &volume->ioblock);
if (ret < 0)
{
fdbg("No more valid blocks\n");
return ret;
}
volume->iooffset = size;
volume->froffset = volume->ioblock * volume->geo.blocksize + size;
}
/* Return -ENOSPC if there is no erased memory left in the volume for
* the object.
*/
fdbg("Not enough memory left to hold the file header\n");
return -ENOSPC;
}
/****************************************************************************
* Name: nxffs_wrblkhdr
*
* Description:
* Write the block header information. This is done (1) whenever the end-
* block is encountered and (2) also when the file is closed in order to
* flush the final block of data to FLASH.
*
* Input Parameters:
* volume - Describes the state of the NXFFS volume
* wrfile - Describes the state of the open file
*
* Returned Value:
* Zero is returned on success; Otherwise, a negated errno value is
* returned to indicate the nature of the failure.
*
****************************************************************************/
int nxffs_wrblkhdr(FAR struct nxffs_volume_s *volume,
FAR struct nxffs_wrfile_s *wrfile)
{
#warning "Missing logic"
return -ENOSYS;
}