8000 Manage generic attributes · Issue #23 · littlefs-project/littlefs · GitHub
[go: up one dir, main page]

Skip to content
Manage generic attributes #23
@guillaumerems

Description

@guillaumerems

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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0