WIP custom attributes

This commit is contained in:
Christopher Haster
2018-04-05 19:03:58 -05:00
parent a82ea60658
commit 2aee22aa49
2 changed files with 224 additions and 32 deletions

224
lfs.c
View File

@@ -913,7 +913,7 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
lfs_entry_t *entry, const char **path) {
const char *pathname = *path;
size_t pathlen;
lfs_size_t pathlen;
while (true) {
nextname:
@@ -940,7 +940,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
// skip if matched by '..' in name
const char *suffix = pathname + pathlen;
size_t sufflen;
lfs_size_t sufflen;
int depth = 1;
while (true) {
suffix += strspn(suffix, "/");
@@ -1019,6 +1019,142 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
}
}
/// Internal attribute operations ///
static int lfs_dir_getinfo(lfs_t *lfs,
lfs_dir_t *dir, const lfs_entry_t *entry, struct lfs_info *info) {
memset(info, 0, sizeof(*info));
info->type = 0xf & entry->d.type;
if (entry->d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)) {
info->size = entry->d.u.file.size;
} else if (entry->d.type == (LFS_STRUCT_INLINE | LFS_TYPE_REG)) {
info->size = lfs_entry_elen(entry);
}
if (lfs_paircmp(entry->d.u.dir, lfs->root) == 0) {
strcpy(info->name, "/");
} else {
int err = lfs_dir_get(lfs, dir,
entry->off + entry->size - entry->d.nlen,
info->name, entry->d.nlen);
if (err) {
return err;
}
}
return 0;
}
static int lfs_dir_getattr(lfs_t *lfs,
lfs_dir_t *dir, const lfs_entry_t *entry,
uint8_t type, void *buffer, lfs_size_t size) {
// search for attribute in attribute region
lfs_off_t off = sizeof(dir->d) + lfs_entry_elen(entry);
lfs_off_t i = 0;
while (i < lfs_entry_alen(entry)) {
lfs_attr_t attr;
int err = lfs_dir_get(lfs, dir,
entry->off+off+i, &attr.d, sizeof(attr.d));
if (err) {
return err;
}
if (attr.d.type != type) {
i += attr.d.len;
continue;
}
if (attr.d.len > size) {
return LFS_ERR_RANGE;
}
err = lfs_dir_get(lfs, dir,
entry->off+off+i+sizeof(attr.d), buffer, attr.d.len);
if (err) {
return err;
}
return attr.d.len;
}
return LFS_ERR_NODATA;
}
static int lfs_dir_setattr(lfs_t *lfs,
lfs_dir_t *dir, lfs_entry_t *entry,
uint8_t type, const void *buffer, lfs_size_t size) {
// search for attribute in attribute region
lfs_off_t off = sizeof(dir->d) + lfs_entry_elen(entry);
lfs_off_t i = 0;
lfs_size_t oldlen = 0;
while (i < lfs_entry_alen(entry)) {
lfs_attr_t attr;
int err = lfs_dir_get(lfs, dir,
entry->off+off+i, &attr.d, sizeof(attr.d));
if (err) {
return err;
}
if (attr.d.type != type) {
i += attr.d.len;
continue;
}
oldlen = attr.d.len;
break;
}
// make sure the attribute fits
if (lfs_entry_elen(entry) - oldlen + size > lfs->attrs_size ||
(0x7fffffff & dir->d.size) - oldlen + size > lfs->cfg->block_size) {
return LFS_ERR_NOSPC;
}
lfs_attr_t attr;
attr.d.type = type;
attr.d.len = size;
int err = lfs_dir_set(lfs, dir, entry, (struct lfs_region[]){
{LFS_FROM_MEM, off+i, &attr.d, sizeof(attr.d)},
{LFS_FROM_MEM, off+i, buffer, size},
{LFS_FROM_DROP, off+i, NULL, -oldlen}}, 3);
if (err) {
return err;
}
return 0;
}
static int lfs_dir_removeattr(lfs_t *lfs,
lfs_dir_t *dir, lfs_entry_t *entry, uint8_t type) {
// search for attribute in attribute region
lfs_off_t off = sizeof(dir->d) + lfs_entry_elen(entry);
lfs_off_t i = 0;
while (i < lfs_entry_alen(entry)) {
lfs_attr_t attr;
int err = lfs_dir_get(lfs, dir,
entry->off+off+i, &attr.d, sizeof(attr.d));
if (err) {
return err;
}
if (attr.d.type != type) {
i += attr.d.len;
continue;
}
err = lfs_dir_set(lfs, dir, entry, (struct lfs_region[]){
{LFS_FROM_DROP, off+i,
NULL, -(sizeof(attr.d)+attr.d.len)}}, 1);
if (err) {
return err;
}
return 0;
}
return LFS_ERR_NODATA;
}
/// Top level directory operations ///
int lfs_mkdir(lfs_t *lfs, const char *path) {
@@ -1179,16 +1315,7 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
break;
}
info->type = 0xf & entry.d.type;
if (entry.d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)) {
info->size = entry.d.u.file.size;
} else if (entry.d.type == (LFS_STRUCT_INLINE | LFS_TYPE_REG)) {
info->size = lfs_entry_elen(&entry);
}
int err = lfs_dir_get(lfs, dir,
entry.off + entry.size - entry.d.nlen,
info->name, entry.d.nlen);
int err = lfs_dir_getinfo(lfs, dir, &entry, info);
if (err) {
return err;
}
@@ -2048,26 +2175,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
return err;
}
memset(info, 0, sizeof(*info));
info->type = 0xf & entry.d.type;
if (entry.d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)) {
info->size = entry.d.u.file.size;
} else if (entry.d.type == (LFS_STRUCT_INLINE | LFS_TYPE_REG)) {
info->size = lfs_entry_elen(&entry);
}
if (lfs_paircmp(entry.d.u.dir, lfs->root) == 0) {
strcpy(info->name, "/");
} else {
err = lfs_dir_get(lfs, &cwd,
entry.off + entry.size - entry.d.nlen,
info->name, entry.d.nlen);
if (err) {
return err;
}
}
return 0;
return lfs_dir_getinfo(lfs, &cwd, &entry, info);
}
int lfs_remove(lfs_t *lfs, const char *path) {
@@ -2263,6 +2371,58 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
}
/// Attribute operations ///
int lfs_getattr(lfs_t *lfs, const char *path,
uint8_t type, void *buffer, lfs_size_t size) {
lfs_dir_t cwd;
int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
if (err) {
return err;
}
lfs_entry_t entry;
err = lfs_dir_find(lfs, &cwd, &entry, &path);
if (err) {
return err;
}
return lfs_dir_getattr(lfs, &cwd, &entry, type, buffer, size);
}
int lfs_setattr(lfs_t *lfs, const char *path,
uint8_t type, const void *buffer, lfs_size_t size) {
lfs_dir_t cwd;
int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
if (err) {
return err;
}
lfs_entry_t entry;
err = lfs_dir_find(lfs, &cwd, &entry, &path);
if (err) {
return err;
}
return lfs_dir_setattr(lfs, &cwd, &entry, type, buffer, size);
}
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) {
lfs_dir_t cwd;
int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
if (err) {
return err;
}
lfs_entry_t entry;
err = lfs_dir_find(lfs, &cwd, &entry, &path);
if (err) {
return err;
}
return lfs_dir_removeattr(lfs, &cwd, &entry, type);
}
/// Filesystem operations ///
static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->cfg = cfg;

32
lfs.h
View File

@@ -89,6 +89,8 @@ enum lfs_error {
LFS_ERR_NOSPC = -28, // No space left on device
LFS_ERR_NOMEM = -12, // No more memory available
LFS_ERR_NAMETOOLONG = -36, // File name too long
LFS_ERR_NODATA = -61, // No data/attr available
LFS_ERR_RANGE = -34, // Result not representable
};
// File types
@@ -253,6 +255,13 @@ typedef struct lfs_entry {
} d;
} lfs_entry_t;
typedef struct lfs_attr {
struct lfs_disk_attr {
uint8_t type;
uint8_t len;
} d;
} lfs_attr_t;
typedef struct lfs_cache {
lfs_block_t block;
lfs_off_t off;
@@ -379,6 +388,29 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath);
// Returns a negative error code on failure.
int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
// Get a custom attribute
//
// Attributes are identified by an 8-bit type and are limited to at
// most LFS_ATTRS_SIZE bytes.
// Returns the size of the attribute, or a negative error code on failure.
int lfs_getattr(lfs_t *lfs, const char *path,
uint8_t type, void *buffer, lfs_size_t size);
// Set a custom attribute
//
// Attributes are identified by an 8-bit type and are limited to at
// most LFS_ATTRS_SIZE bytes.
// 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);
// Remove a custom attribute
//
// Attributes are identified by an 8-bit type and are limited to at
// most LFS_ATTRS_SIZE bytes.
// Returns a negative error code on failure.
int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type);
/// File operations ///