diff --git a/fs/nxffs/nxffs.h b/fs/nxffs/nxffs.h index 735e4fc0aa8..262c8577e8d 100644 --- a/fs/nxffs/nxffs.h +++ b/fs/nxffs/nxffs.h @@ -177,7 +177,6 @@ #define NXFFS_MINDATA 16 - /* Internal definitions *****************************************************/ /* If we encounter this number of erased bytes, we assume that all of the * flash beyond this point is erased. @@ -640,6 +639,33 @@ extern int nxffs_findinode(FAR struct nxffs_volume_s *volume, FAR const char *name, FAR struct nxffs_entry_s *entry); +/**************************************************************************** + * Name: nxffs_inodeend + * + * Description: + * Return an *approximiate* FLASH offset to end of the inode data. The + * returned value is guaranteed to be be less then or equal to the offset + * of the thing-of-interest in FLASH. Parsing for interesting things + * can begin at that point. + * + * Assumption: The inode header has been verified by the caller and is + * known to contain valid data. + * + * Input Parameters: + * volume - Describes the NXFFS volume + * entry - Describes the inode. + * + * Returned Value: + * A FLASH offset to the (approximate) end of the inode data. No errors + * are detected. + * + * Defined in nxffs_inode.c + * + ****************************************************************************/ + +extern off_t nxffs_inodeend(FAR struct nxffs_volume_s *volume, + FAR struct nxffs_entry_s *entry); + /**************************************************************************** * Name: nxffs_verifyblock * diff --git a/fs/nxffs/nxffs_dirent.c b/fs/nxffs/nxffs_dirent.c index bd53ffe0cea..40ae8662f43 100644 --- a/fs/nxffs/nxffs_dirent.c +++ b/fs/nxffs/nxffs_dirent.c @@ -166,14 +166,9 @@ int nxffs_readdir(FAR struct inode *mountpt, FAR struct fs_dirent_s *dir) dir->fd_dir.d_type = DTYPE_FILE; strncpy(dir->fd_dir.d_name, entry.name, NAME_MAX+1); - /* Discard this entry and set the next offset using the rw data - * length as the offset increment. This is, of course, not accurate - * because it does not account for the data headers that enclose the - * data. But it is guaranteed to be less than or equal to the - * correct offset and, hence, better then searching byte-for-byte. - */ + /* Discard this entry and set the next offset. */ - dir->u.nxffs.nx_offset = entry.doffset + entry.datlen; + dir->u.nxffs.nx_offset = nxffs_inodeend(volume, &entry); nxffs_freeentry(&entry); ret = OK; } diff --git a/fs/nxffs/nxffs_initialize.c b/fs/nxffs/nxffs_initialize.c index c040fa64999..7fd1d51fc5a 100644 --- a/fs/nxffs/nxffs_initialize.c +++ b/fs/nxffs/nxffs_initialize.c @@ -361,14 +361,9 @@ int nxffs_limits(FAR struct nxffs_volume_s *volume) volume->inoffset = entry.hoffset; fvdbg("First inode at offset %d\n", volume->inoffset); - /* Discard this entry and set the next offset using the rw data - * length as the offset increment. This is, of course, not accurate - * because it does not account for the data headers that enclose the - * data. But it is guaranteed to be less than or equal to the - * correct offset and, hence, better then searching byte-for-byte. - */ + /* Discard this entry and set the next offset. */ - offset = entry.doffset + entry.datlen; + offset = nxffs_inodeend(volume, &entry); nxffs_freeentry(&entry); } @@ -378,9 +373,9 @@ int nxffs_limits(FAR struct nxffs_volume_s *volume) { while ((ret = nxffs_nextentry(volume, offset, &entry)) == OK) { - /* Discard the entry and guess the next offset (see comments above). */ + /* Discard the entry and guess the next offset. */ - offset = entry.doffset + entry.datlen; + offset = nxffs_inodeend(volume, &entry); nxffs_freeentry(&entry); } fvdbg("Last inode before offset %d\n", offset); diff --git a/fs/nxffs/nxffs_inode.c b/fs/nxffs/nxffs_inode.c index 361b5df7ee6..121c1f6db43 100644 --- a/fs/nxffs/nxffs_inode.c +++ b/fs/nxffs/nxffs_inode.c @@ -181,11 +181,11 @@ static int nxffs_rdentry(FAR struct nxffs_volume_s *volume, off_t offset, if (state != INODE_STATE_FILE) { /* It is a deleted file. But still, the data offset and the - * start size is good so we can use this information to advance + * start size are good so we can use this information to advance * further in FLASH memory and reduce the search time. */ - offset = entry->doffset + entry->datlen + SIZEOF_NXFFS_DATA_HDR; + offset = nxffs_inodeend(volume, entry); nxffs_freeentry(entry); ret = -ENOENT; goto errout; @@ -432,7 +432,7 @@ int nxffs_findinode(FAR struct nxffs_volume_s *volume, FAR const char *name, * byte-for-byte. */ - offset = entry->doffset + entry->datlen; + offset = nxffs_inodeend(volume, entry); nxffs_freeentry(entry); } @@ -440,3 +440,61 @@ int nxffs_findinode(FAR struct nxffs_volume_s *volume, FAR const char *name, return -ENOENT; } + +/**************************************************************************** + * Name: nxffs_inodeend + * + * Description: + * Return an *approximiate* FLASH offset to end of the inode data. The + * returned value is guaranteed to be be less then or equal to the offset + * of the thing-of-interest in FLASH. Parsing for interesting things + * can begin at that point. + * + * Assumption: The inode header has been verified by the caller and is + * known to contain valid data. + * + * Input Parameters: + * volume - Describes the NXFFS volume + * entry - Describes the inode. + * + * Returned Value: + * A FLASH offset to the (approximate) end of the inode data. No errors + * are detected. + * + ****************************************************************************/ + +off_t nxffs_inodeend(FAR struct nxffs_volume_s *volume, + FAR struct nxffs_entry_s *entry) +{ + /* A zero length file will have no data blocks */ + + if (entry->doffset) + { + /* This is the maximum size of one data block */ + + uint16_t maxsize = volume->geo.blocksize - SIZEOF_NXFFS_DATA_HDR; + + /* This is the minimum number of blocks require to span all of the + * inode data. One additional block could possibly be required -- we + * could make this accurate by looking at the size of the first, perhaps + * partial, data block. + */ + + off_t minblocks = (entry->datlen + maxsize - 1) / maxsize; + + /* And this is our best, simple guess at the end of the inode data */ + + return entry->doffset + entry->datlen + minblocks * SIZEOF_NXFFS_DATA_HDR; + } + + /* Otherwise, return an offset that accounts only for the inode header and + * the inode name. + */ + + /* All valid inodes will have a name associated with them */ + + DEBUGASSERT(entry->noffset); + return entry->noffset + strlen(entry->name); +} + + diff --git a/fs/nxffs/nxffs_pack.c b/fs/nxffs/nxffs_pack.c index d4a7d5f39e1..212d2b42937 100644 --- a/fs/nxffs/nxffs_pack.c +++ b/fs/nxffs/nxffs_pack.c @@ -399,7 +399,8 @@ static inline int nxffs_startpos(FAR struct nxffs_volume_s *volume, * Input Parameters: * volume - The volume to be packed * pack - The volume packing state structure. - * offset - FLASH offset to the data block header + * offset - FLASH offset to the data block header (will be zero for zero- + * files. * * Returned Values: * Zero on success; Otherwise, a negated errno value is returned to @@ -410,22 +411,27 @@ static inline int nxffs_startpos(FAR struct nxffs_volume_s *volume, static int nxffs_srcsetup(FAR struct nxffs_volume_s *volume, FAR struct nxffs_pack_s *pack, off_t offset) { - int ret; - - /* No, start with the first data block */ + /* Start with the first data block */ pack->src.blkoffset = offset; pack->src.blkpos = 0; - /* Seek to the data block header, read and verify the block header */ + /* Zero-length files have no valid data block offset */ - ret = nxffs_rdblkhdr(volume, offset, &pack->src.blklen); - if (ret < 0) + if (offset > 0) { - fdbg("Failed to verify the data block header: %d\n", -ret); + /* Seek to the data block header, read and verify the block header */ + + int ret = nxffs_rdblkhdr(volume, offset, &pack->src.blklen); + if (ret < 0) + { + fdbg("Failed to verify the data block header: %d\n", -ret); + } + return ret; } - return ret; + DEBUGASSERT(pack->src.entry.datlen == 0); + return OK; } /**************************************************************************** @@ -449,6 +455,7 @@ static int nxffs_destsetup(FAR struct nxffs_volume_s *volume, { size_t mindata; int namlen; + int ret; /* The destination can be in one of three of states: * @@ -516,66 +523,77 @@ static int nxffs_destsetup(FAR struct nxffs_volume_s *volume, /* State 3: Inode header not-written, inode name written. Still need the position * of the first data block. + * + * Deal with the special case where the source inode is a zero length file + * with no data blocks to be transferred. */ - if (pack->dest.entry.doffset == 0) + if (pack->src.entry.doffset > 0) { - /* Will the data block header plus a minimal amount of data fit in this - * block? (or the whole file if the file is very small). - */ - - mindata = MIN(NXFFS_MINDATA, pack->dest.entry.datlen); - if (pack->iooffset + SIZEOF_NXFFS_DATA_HDR + mindata > volume->geo.blocksize) + if (pack->dest.entry.doffset == 0) { - /* No.. return an indication that we are at the end of the block - * and try again later. + /* Will the data block header plus a minimal amount of data fit in this + * block? (or the whole file if the file is very small). */ - return -ENOSPC; + mindata = MIN(NXFFS_MINDATA, pack->dest.entry.datlen); + if (pack->iooffset + SIZEOF_NXFFS_DATA_HDR + mindata > volume->geo.blocksize) + { + /* No.. return an indication that we are at the end of the block + * and try again later. + */ + + ret = -ENOSPC; + goto errout; + } + + /* Yes.. reserve space for the data block header */ + + pack->dest.entry.doffset = nxffs_packtell(volume, pack); + pack->iooffset += SIZEOF_NXFFS_DATA_HDR; + + /* Initialize the output data stream to start with the first data block */ + + pack->dest.blkoffset = pack->dest.entry.doffset; + pack->dest.blklen = 0; + pack->dest.blkpos = 0; } - /* Yes.. reserve space for the data block header */ - - pack->dest.entry.doffset = nxffs_packtell(volume, pack); - pack->iooffset += SIZEOF_NXFFS_DATA_HDR; - - /* Initialize the output data stream to start with the first data block */ - - pack->dest.blkoffset = pack->dest.entry.doffset; - pack->dest.blklen = 0; - pack->dest.blkpos = 0; - } - - /* State 4: Starting a new block. Verify that there is space in the current - * block for another (minimal sized) block - */ - - if (pack->dest.blkoffset == 0) - { - /* Will the data block header plus a minimal amount of data fit in this - * block? (or the whole file if the file is very small). + /* State 4: Starting a new block. Verify that there is space in the current + * block for another (minimal sized) block */ - mindata = MIN(NXFFS_MINDATA, pack->dest.entry.datlen); - if (pack->iooffset + SIZEOF_NXFFS_DATA_HDR + mindata > volume->geo.blocksize) + if (pack->dest.blkoffset == 0) { - /* No.. return an indication that we are at the end of the block - * and try again later. + /* Will the data block header plus a minimal amount of data fit in this + * block? (or the whole file if the file is very small). */ - return -ENOSPC; + mindata = MIN(NXFFS_MINDATA, pack->dest.entry.datlen); + if (pack->iooffset + SIZEOF_NXFFS_DATA_HDR + mindata > volume->geo.blocksize) + { + /* No.. return an indication that we are at the end of the block + * and try again later. + */ + + ret = -ENOSPC; + goto errout; + } + + /* Yes.. reserve space for the data block header */ + + pack->dest.blkoffset = nxffs_packtell(volume, pack); + pack->iooffset += SIZEOF_NXFFS_DATA_HDR; + pack->dest.blklen = 0; + pack->dest.blkpos = 0; } - - /* Yes.. reserve space for the data block header */ - - pack->dest.blkoffset = nxffs_packtell(volume, pack); - pack->iooffset += SIZEOF_NXFFS_DATA_HDR; - pack->dest.blklen = 0; - pack->dest.blkpos = 0; } + ret = OK; + +errout: volume->froffset = nxffs_packtell(volume, pack); - return OK; + return ret; } /**************************************************************************** @@ -806,19 +824,22 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, /* Transfer the smaller of the two amounts data */ uint16_t xfrlen = MIN(srclen, destlen); - nxffs_ioseek(volume, pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR + pack->src.blkpos); - memcpy(&pack->iobuffer[pack->iooffset], &volume->cache[volume->iooffset], xfrlen); + if (xfrlen > 0) + { + nxffs_ioseek(volume, pack->src.blkoffset + SIZEOF_NXFFS_DATA_HDR + pack->src.blkpos); + memcpy(&pack->iobuffer[pack->iooffset], &volume->cache[volume->iooffset], xfrlen); - /* Increment counts and offset for this data transfer */ + /* Increment counts and offset for this data transfer */ - pack->src.fpos += xfrlen; /* Source data offsets */ - pack->src.blkpos += xfrlen; - pack->dest.fpos += xfrlen; /* Destination data offsets */ - pack->dest.blkpos += xfrlen; - pack->dest.blklen += xfrlen; /* Destination data block size */ - pack->iooffset += xfrlen; /* Destination I/O block offset */ - volume->iooffset += xfrlen; /* Source I/O block offset */ - volume->froffset += xfrlen; /* Free FLASH offset */ + pack->src.fpos += xfrlen; /* Source data offsets */ + pack->src.blkpos += xfrlen; + pack->dest.fpos += xfrlen; /* Destination data offsets */ + pack->dest.blkpos += xfrlen; + pack->dest.blklen += xfrlen; /* Destination data block size */ + pack->iooffset += xfrlen; /* Destination I/O block offset */ + volume->iooffset += xfrlen; /* Source I/O block offset */ + volume->froffset += xfrlen; /* Free FLASH offset */ + } /* Now, either the (1) src block has been fully transferred, (2) all * of the source data has been transferred, or (3) the the destination @@ -839,7 +860,9 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, /* Find the next valid source inode */ offset = pack->src.blkoffset + pack->src.blklen; - ret = nxffs_nextentry(volume, offset, &pack->src.entry); + memset(&pack->src, 0, sizeof(struct nxffs_packstream_s)); + + ret = nxffs_nextentry(volume, offset, &pack->src.entry); if (ret < 0) { /* No more valid inode entries. Just return an end-of-flash error @@ -859,16 +882,11 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, /* Setup the dest stream */ - pack->dest.entry.hoffset = 0; - pack->dest.entry.noffset = 0; - pack->dest.entry.doffset = 0; - pack->dest.entry.name = pack->src.entry.name; - pack->dest.entry.utc = pack->src.entry.utc; - pack->dest.entry.datlen = pack->src.entry.datlen; - pack->dest.blkoffset = 0; - pack->dest.blklen = 0; - pack->dest.blkpos = 0; - pack->src.entry.name = NULL; + memset(&pack->dest, 0, sizeof(struct nxffs_packstream_s)); + pack->dest.entry.name = pack->src.entry.name; + pack->dest.entry.utc = pack->src.entry.utc; + pack->dest.entry.datlen = pack->src.entry.datlen; + pack->src.entry.name = NULL; /* Is there sufficient space at the end of the I/O block to hold * the inode header? @@ -883,14 +901,7 @@ static inline int nxffs_packblock(FAR struct nxffs_volume_s *volume, return OK; } - /* Set the current inode header off to the current position and reserve - * the memory. - */ - - pack->dest.entry.hoffset = nxffs_packtell(volume, pack); - pack->iooffset += SIZEOF_NXFFS_INODE_HDR; - - /* Then configure the destination stream */ + /* Configure the destination stream */ ret = nxffs_destsetup(volume, pack); if (ret < 0) diff --git a/fs/nxffs/nxffs_read.c b/fs/nxffs/nxffs_read.c index f52e2185983..cf9bf78e0a5 100644 --- a/fs/nxffs/nxffs_read.c +++ b/fs/nxffs/nxffs_read.c @@ -101,6 +101,12 @@ static ssize_t nxffs_rdseek(FAR struct nxffs_volume_s *volume, */ offset = entry->doffset; + if (offset == 0) + { + /* Zero length files will have no data blocks */ + + return -ENOSPC; + } /* Loop until we read the data block containing the desired position */