-
Notifications
You must be signed in to change notification settings - Fork 884
Open
Description
As the attributes are not used by default in littlefs but it is intended to be used depending on the implementation.
In my project I use the attributes to store the modification date of an entry.
Here is my modification I have made on lfs to implement it:
static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir,
const lfs_entry_t *entry,
const void *attribute, const void *name) {
return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
{entry->off, sizeof(entry->d), &entry->d, sizeof(entry->d)},
{entry->off+sizeof(entry->d), entry->d.alen, attribute, entry->d.alen},
{entry->off+sizeof(entry->d)+entry->d.alen, entry->d.nlen, name, entry->d.nlen}
}, name ? 3 : attribute ? 2 : 1);
}
static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
lfs_entry_t *entry, const void *attribute, const void *name) {
// check if we fit, if top bit is set we do not and move on
while (true) {
if (dir->d.size + lfs_entry_size(entry) <= lfs->cfg->block_size) {
entry->off = dir->d.size - 4;
return lfs_dir_commit(lfs, dir, (struct lfs_region[]){
{entry->off, 0, &entry->d, sizeof(entry->d)},
{entry->off, 0, attribute, entry->d.alen},
{entry->off, 0, name, entry->d.nlen}
}, 3);
}
// we need to allocate a new dir block
if (!(0x80000000 & dir->d.size)) {
lfs_dir_t newdir;
int err = lfs_dir_alloc(lfs, &newdir);
if (err) {
return err;
}
newdir.d.tail[0] = dir->d.tail[0];
newdir.d.tail[1] = dir->d.tail[1];
entry->off = newdir.d.size - 4;
err = lfs_dir_commit(lfs, &newdir, (struct lfs_region[]){
{entry->off, 0, &entry->d, sizeof(entry->d)},
{entry->off, 0, attribute, entry->d.alen},
{entry->off, 0, name, entry->d.nlen}
}, 3);
if (err) {
return err;
}
dir->d.size |= 0x80000000;
dir->d.tail[0] = newdir.pair[0];
dir->d.tail[1] = newdir.pair[1];
return lfs_dir_commit(lfs, dir, NULL, 0);
}
int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
if (err) {
return err;
}
}
}
In lfs_mkdir:
...
uint8_t attribute[ATTRIBUTE_LENGTH];
entry.d.type = LFS_TYPE_DIR;
entry.d.elen = sizeof(entry.d) - 4;
entry.d.alen = lfs_dir_compute_attribute(attribute);
entry.d.nlen = strlen(path);
entry.d.u.dir[0] = dir.pair[0];
entry.d.u.dir[1] = dir.pair[1];
cwd.d.tail[0] = dir.pair[0];
cwd.d.tail[1] = dir.pair[1];
err = lfs_dir_append(lfs, &cwd, &entry, attribute, path);
...
In lfs_dir_read
...
if(entry.d.alen > 0){
lfs_dir_extract_attribute(lfs, dir, &entry, info);
}
...
In lfs_file_open
...
if (err == LFS_ERR_NOENT) {
if (!(flags & LFS_O_CREAT)) {
return LFS_ERR_NOENT;
}
uint8_t attribute[ATTRIBUTE_LENGTH];
// create entry to remember name
entry.d.type = LFS_TYPE_REG;
entry.d.elen = sizeof(entry.d) - 4;
entry.d.alen = lfs_dir_compute_attribute(attribute);
entry.d.nlen = strlen(path);
entry.d.u.file.head = 0xffffffff;
entry.d.u.file.size = 0;
err = lfs_dir_append(lfs, &cwd, &entry, attribute, path);
if (err) {
return err;
}
} else if (entry.d.type == LFS_TYPE_DIR) {
return LFS_ERR_ISDIR;
} else if (flags & LFS_O_EXCL) {
return LFS_ERR_EXIST;
}
...
In lfs_file_sync
...
uint8_t attribute[ATTRIBUTE_LENGTH];
entry.d.u.file.head = file->head;
entry.d.u.file.size = file->size;
entry.d.alen = lfs_dir_compute_attribute(attribute);
err = lfs_dir_update(lfs, &cwd, &entry, attribute, NULL);
...
And then the 2 function to generate and extract the attributes
static uint8_t lfs_dir_compute_attribute(uint8_t *buf) {
uint32_t datetime = now(NULL);
buf[0] = LFS_ATTRIBUTE_TIME;
buf[1] = datetime & 0xFF;
buf[2] = (datetime >> 8) & 0xFF;
buf[3] = (datetime >> 16) & 0xFF;
buf[4] = (datetime >> 24) & 0xFF;
return ATTRIBUTE_LENGTH;
}
static int lfs_dir_extract_attribute(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry, struct lfs_info *info) {
uint8_t *attribute = malloc(entry->d.alen);
ASSERT(attribute);
if (attribute) {
int err = lfs_bd_read(lfs, dir->pair[0],
entry->off + 4 + entry->d.elen,
attribute, entry->d.alen);
if (err) {
free(attribute);
return err;
}
if (entry->d.alen >= ATTRIBUTE_LENGTH) {
if (attribute[0] == LFS_ATTRIBUTE_TIME) {
info->time =
attribute[1] + attribute[2] * 256 + attribute[3] * 256 * 256 + attribute[4] * 256 * 256 * 256;
}
}
free(attribute);
}
return 0;
}
What do you think to include this in littlefs by default, to manage the attributes and let the developer to implement its custom attributes ?
Metadata
Metadata
Assignees
Labels
No labels