diff --git a/lfs.c b/lfs.c index 3b507ca..5b4f0fd 100644 --- a/lfs.c +++ b/lfs.c @@ -401,7 +401,7 @@ static inline lfs_size_t lfs_tag_size(uint32_t tag) { } static inline lfs_size_t lfs_tag_dsize(uint32_t tag) { - return sizeof(tag) + lfs_tag_size(tag) + lfs_tag_isdelete(tag); + return sizeof(tag) + lfs_tag_size(tag + lfs_tag_isdelete(tag)); } // operations on set of globals @@ -472,7 +472,7 @@ struct lfs_diskoff { }; static int32_t lfs_commit_get(lfs_t *lfs, - lfs_block_t block, lfs_off_t off, uint32_t tag, bool stopatcommit, + lfs_block_t block, lfs_off_t off, uint32_t tag, bool compacting, uint32_t getmask, uint32_t gettag, int32_t getdiff, void *buffer) { gettag += getdiff; @@ -480,7 +480,7 @@ static int32_t lfs_commit_get(lfs_t *lfs, while (off >= sizeof(uint32_t) + lfs_tag_dsize(tag)) { off -= lfs_tag_dsize(tag); - if (lfs_tag_subtype(tag) == LFS_TYPE_CRC && stopatcommit) { + if (lfs_tag_subtype(tag) == LFS_TYPE_CRC && compacting) { break; } else if (lfs_tag_subtype(tag) == LFS_TYPE_DELETE) { // something was deleted, need to move around it @@ -489,8 +489,11 @@ static int32_t lfs_commit_get(lfs_t *lfs, } } - if (!lfs_tag_isdelete(tag) && - (tag & getmask) == ((gettag - getdiff) & getmask)) { + if ((tag & getmask) == ((gettag - getdiff) & getmask)) { + if (lfs_tag_isdelete(tag) && !compacting) { + return LFS_ERR_NOENT; + } + if (buffer) { lfs_size_t diff = lfs_min( lfs_tag_size(gettag), lfs_tag_size(tag)); @@ -2912,19 +2915,18 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, res = lfs_dir_get(lfs, &cwd, 0x7ffff000, LFS_MKTAG(0x100 | type, id, lfs_min(size, lfs->attr_max)), buffer); - if (res < 0 && res != LFS_ERR_NOENT) { + if (res < 0) { + if (res == LFS_ERR_NOENT) { + return LFS_ERR_NOATTR; + } return res; } - return (res == LFS_ERR_NOENT) ? 0 : lfs_tag_size(res); + return lfs_tag_size(res); } -int lfs_setattr(lfs_t *lfs, const char *path, +static int lfs_commitattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size) { - if (size > lfs->attr_max) { - return LFS_ERR_NOSPC; - } - lfs_mdir_t cwd; int32_t res = lfs_dir_lookup(lfs, &cwd, &path); if (res < 0) { @@ -2946,6 +2948,19 @@ int lfs_setattr(lfs_t *lfs, const char *path, NULL)); } +int lfs_setattr(lfs_t *lfs, const char *path, + uint8_t type, const void *buffer, lfs_size_t size) { + if (size > lfs->attr_max) { + return LFS_ERR_NOSPC; + } + + return lfs_commitattr(lfs, path, type, buffer, size); +} + +int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { + return lfs_commitattr(lfs, path, type, NULL, 0xfff); +} + /// Filesystem operations /// static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { diff --git a/lfs.h b/lfs.h index 987b234..120a9a3 100644 --- a/lfs.h +++ b/lfs.h @@ -82,6 +82,7 @@ enum lfs_error { LFS_ERR_INVAL = -22, // Invalid parameter LFS_ERR_NOSPC = -28, // No space left on device LFS_ERR_NOMEM = -12, // No more memory available + LFS_ERR_NOATTR = -61, // No data/attr available LFS_ERR_NAMETOOLONG = -36, // File name too long }; @@ -456,7 +457,8 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); // Custom attributes are uniquely identified by an 8-bit type and limited // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than // the buffer, it will be padded with zeros. If the stored attribute is larger, -// then it will be silently truncated. +// then it will be silently truncated. If no attribute is found, the error +// LFS_ERR_NOATTR is returned and the buffer is filled with zeros. // // Returns the size of the attribute, or a negative error code on failure. // Note, the returned size is the size of the attribute on disk, irrespective @@ -469,13 +471,19 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, // // Custom attributes are uniquely identified by an 8-bit type and limited // to LFS_ATTR_MAX bytes. If an attribute is not found, it will be -// implicitly created, and setting the size of an attribute to zero deletes -// the attribute. +// implicitly created. // // Returns a negative error code on failure. int lfs_setattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size); +// Removes a custom attribute +// +// If an attribute is not found, nothing happens. +// +// Returns a negative error code on failure. +int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); + /// File operations /// diff --git a/tests/corrupt.py b/tests/corrupt.py index 9b5d4bd..4a49d42 100755 --- a/tests/corrupt.py +++ b/tests/corrupt.py @@ -19,10 +19,11 @@ def corrupt(block): break tag ^= ntag - file.seek(tag & 0xfff, os.SEEK_CUR) + size = (tag & 0xfff) if (tag & 0xfff) != 0xfff else 0 + file.seek(size, os.SEEK_CUR) # lob off last 3 bytes - file.seek(-((tag & 0xfff) + 3), os.SEEK_CUR) + file.seek(-(size + 3), os.SEEK_CUR) file.truncate() def main(args): diff --git a/tests/debug.py b/tests/debug.py index 0beb4c4..3c975c8 100755 --- a/tests/debug.py +++ b/tests/debug.py @@ -81,20 +81,21 @@ def main(*blocks): size = (tag & 0x00000fff) >> 0 iscrc = (type & 0x1f0) == 0x0f0 - data = file.read(size) + data = file.read(size if size != 0xfff else 0) if iscrc: crc = binascii.crc32(data[:4], crc) else: crc = binascii.crc32(data, crc) - print '%04x: %08x %-14s %3s %3d %-23s %-8s' % ( + print '%04x: %08x %-14s %3s %3s %-23s %-8s' % ( off, tag, typeof(type) + (' bad!' if iscrc and ~crc else ''), - id if id != 0x3ff else '.', size, + id if id != 0x3ff else '.', + size if size != 0xfff else 'x', ' '.join('%02x' % ord(c) for c in data[:8]), ''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8])) - off += tag & 0xfff + off += size if size != 0xfff else 0 if iscrc: crc = 0 tag ^= (type & 1) << 31 diff --git a/tests/test_attrs.sh b/tests/test_attrs.sh index bbe78cc..e9b2227 100755 --- a/tests/test_attrs.sh +++ b/tests/test_attrs.sh @@ -37,6 +37,14 @@ tests/test.py << TEST memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+10, "ccccc", 5) => 0; + lfs_removeattr(&lfs, "hello", 'B') => 0; + lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR; + lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; + memcmp(buffer, "aaaa", 4) => 0; + memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; + memcmp(buffer+10, "ccccc", 5) => 0; + lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; @@ -98,6 +106,14 @@ tests/test.py << TEST memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; memcmp(buffer+10, "ccccc", 5) => 0; + lfs_removeattr(&lfs, "/", 'B') => 0; + lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; + lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR; + lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; + memcmp(buffer, "aaaa", 4) => 0; + memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; + memcmp(buffer+10, "ccccc", 5) => 0; + lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; @@ -241,7 +257,7 @@ tests/test.py << TEST lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9; lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5; - lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 0; + lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; memcmp(buffer, "fffffffff", 9) => 0; memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0; memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0;