mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Added file-level and fs-level custom attribute APIs
In the form of lfs_file_setattr, lfs_file_getattr, lfs_fs_setattr,
lfs_fs_getattr.
This enables atomic updates of custom attributes as described in
6c754c8, and provides a custom attribute API that allows custom attributes
to be stored on the filesystem itself.
			
			
This commit is contained in:
		
							
								
								
									
										309
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										309
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -932,11 +932,11 @@ shift: | |||||||
|     // shift over any files/directories that are affected |     // shift over any files/directories that are affected | ||||||
|     for (lfs_file_t *f = lfs->files; f; f = f->next) { |     for (lfs_file_t *f = lfs->files; f; f = f->next) { | ||||||
|         if (lfs_paircmp(f->pair, dir->pair) == 0) { |         if (lfs_paircmp(f->pair, dir->pair) == 0) { | ||||||
|             if (f->poff == entry->off && entry->size == 0) { |             if (f->pairoff == entry->off && entry->size == 0) { | ||||||
|                 f->pair[0] = 0xffffffff; |                 f->pair[0] = 0xffffffff; | ||||||
|                 f->pair[1] = 0xffffffff; |                 f->pair[1] = 0xffffffff; | ||||||
|             } else if (f->poff > entry->off) { |             } else if (f->pairoff > entry->off) { | ||||||
|                 f->poff += diff; |                 f->pairoff += diff; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -1135,8 +1135,8 @@ static int lfs_dir_getattrs(lfs_t *lfs, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (int j = 0; j < count; j++) { |         for (int j = 0; j < count; j++) { | ||||||
|             if (attr.d.type == attrs[j].type) { |             if (attrs[j].type == attr.d.type) { | ||||||
|                 if (attr.d.len > attrs[j].size) { |                 if (attrs[j].size < attr.d.len) { | ||||||
|                     return LFS_ERR_RANGE; |                     return LFS_ERR_RANGE; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
| @@ -1190,8 +1190,8 @@ static lfs_ssize_t lfs_dir_checkattrs(lfs_t *lfs, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (nsize > lfs->attrs_size || ( |     if (nsize > lfs->attrs_size || ( | ||||||
|             (0x7fffffff & dir->d.size) + lfs_entry_size(entry) - |             lfs_entry_size(entry) - lfs_entry_alen(entry) + nsize | ||||||
|             lfs_entry_alen(entry) + nsize > lfs->cfg->block_size)) { |                 > lfs->cfg->block_size)) { | ||||||
|         return LFS_ERR_NOSPC; |         return LFS_ERR_NOSPC; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1688,7 +1688,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | |||||||
|     // setup file struct |     // setup file struct | ||||||
|     file->pair[0] = cwd.pair[0]; |     file->pair[0] = cwd.pair[0]; | ||||||
|     file->pair[1] = cwd.pair[1]; |     file->pair[1] = cwd.pair[1]; | ||||||
|     file->poff = entry.off; |     file->pairoff = entry.off; | ||||||
|     file->flags = flags; |     file->flags = flags; | ||||||
|     file->pos = 0; |     file->pos = 0; | ||||||
|  |  | ||||||
| @@ -1738,87 +1738,87 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | |||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     int err = lfs_file_sync(lfs, file); |         int err = lfs_file_sync(lfs, file); | ||||||
|  |  | ||||||
|     // remove from list of files |         // remove from list of files | ||||||
|     for (lfs_file_t **p = &lfs->files; *p; p = &(*p)->next) { |         for (lfs_file_t **p = &lfs->files; *p; p = &(*p)->next) { | ||||||
|         if (*p == file) { |             if (*p == file) { | ||||||
|             *p = file->next; |                 *p = file->next; | ||||||
|             break; |                 break; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // clean up memory |         // clean up memory | ||||||
|     if (!lfs->cfg->file_buffer) { |         if (!lfs->cfg->file_buffer) { | ||||||
|         lfs_free(file->cache.buffer); |             lfs_free(file->cache.buffer); | ||||||
|     } |         } | ||||||
|  |  | ||||||
|     return err; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { |  | ||||||
| relocate:; |  | ||||||
|     // just relocate what exists into new block |  | ||||||
|     lfs_block_t nblock; |  | ||||||
|     int err = lfs_alloc(lfs, &nblock); |  | ||||||
|     if (err) { |  | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     err = lfs_bd_erase(lfs, nblock); |     static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     if (err) { |     relocate:; | ||||||
|         if (err == LFS_ERR_CORRUPT) { |         // just relocate what exists into new block | ||||||
|             goto relocate; |         lfs_block_t nblock; | ||||||
|         } |         int err = lfs_alloc(lfs, &nblock); | ||||||
|         return err; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // either read from dirty cache or disk |  | ||||||
|     for (lfs_off_t i = 0; i < file->off; i++) { |  | ||||||
|         uint8_t data; |  | ||||||
|         err = lfs_cache_read(lfs, &lfs->rcache, &file->cache, |  | ||||||
|                 file->block, i, &data, 1); |  | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, |         err = lfs_bd_erase(lfs, nblock); | ||||||
|                 nblock, i, &data, 1); |  | ||||||
|         if (err) { |         if (err) { | ||||||
|             if (err == LFS_ERR_CORRUPT) { |             if (err == LFS_ERR_CORRUPT) { | ||||||
|                 goto relocate; |                 goto relocate; | ||||||
|             } |             } | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // either read from dirty cache or disk | ||||||
|  |         for (lfs_off_t i = 0; i < file->off; i++) { | ||||||
|  |             uint8_t data; | ||||||
|  |             err = lfs_cache_read(lfs, &lfs->rcache, &file->cache, | ||||||
|  |                     file->block, i, &data, 1); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, | ||||||
|  |                     nblock, i, &data, 1); | ||||||
|  |             if (err) { | ||||||
|  |                 if (err == LFS_ERR_CORRUPT) { | ||||||
|  |                     goto relocate; | ||||||
|  |                 } | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // copy over new state of file | ||||||
|  |         memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); | ||||||
|  |         file->cache.block = lfs->pcache.block; | ||||||
|  |         file->cache.off = lfs->pcache.off; | ||||||
|  |         lfs->pcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|  |         file->block = nblock; | ||||||
|  |         return 0; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // copy over new state of file |     static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); |         if (file->flags & LFS_F_READING) { | ||||||
|     file->cache.block = lfs->pcache.block; |             file->flags &= ~LFS_F_READING; | ||||||
|     file->cache.off = lfs->pcache.off; |         } | ||||||
|     lfs->pcache.block = 0xffffffff; |  | ||||||
|  |  | ||||||
|     file->block = nblock; |         if (file->flags & LFS_F_WRITING) { | ||||||
|     return 0; |             lfs_off_t pos = file->pos; | ||||||
| } |  | ||||||
|  |  | ||||||
| static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { |             if (!(file->flags & LFS_F_INLINE)) { | ||||||
|     if (file->flags & LFS_F_READING) { |                 // copy over anything after current branch | ||||||
|         file->flags &= ~LFS_F_READING; |                 lfs_file_t orig = { | ||||||
|     } |                     .head = file->head, | ||||||
|  |                     .size = file->size, | ||||||
|     if (file->flags & LFS_F_WRITING) { |                     .flags = LFS_O_RDONLY, | ||||||
|         lfs_off_t pos = file->pos; |                     .pos = file->pos, | ||||||
|  |                     .cache = lfs->rcache, | ||||||
|         if (!(file->flags & LFS_F_INLINE)) { |                 }; | ||||||
|             // copy over anything after current branch |  | ||||||
|             lfs_file_t orig = { |  | ||||||
|                 .head = file->head, |  | ||||||
|                 .size = file->size, |  | ||||||
|                 .flags = LFS_O_RDONLY, |  | ||||||
|                 .pos = file->pos, |  | ||||||
|                 .cache = lfs->rcache, |  | ||||||
|             }; |  | ||||||
|             lfs->rcache.block = 0xffffffff; |             lfs->rcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|             while (file->pos < file->size) { |             while (file->pos < file->size) { | ||||||
| @@ -1892,42 +1892,54 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | |||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         lfs_entry_t entry = {.off = file->poff}; |         lfs_entry_t entry = {.off = file->pairoff}; | ||||||
|         err = lfs_dir_get(lfs, &cwd, entry.off, &entry.d, sizeof(entry.d)); |         err = lfs_dir_get(lfs, &cwd, entry.off, &entry.d, sizeof(entry.d)); | ||||||
|         lfs_entry_fromle32(&entry.d); |         lfs_entry_fromle32(&entry.d); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |         entry.size = lfs_entry_size(&entry); | ||||||
|  |  | ||||||
|         LFS_ASSERT((0xf & entry.d.type) == LFS_TYPE_REG); |         LFS_ASSERT((0xf & entry.d.type) == LFS_TYPE_REG); | ||||||
|         lfs_size_t oldlen = lfs_entry_elen(&entry); |         lfs_size_t oldelen = lfs_entry_elen(&entry); | ||||||
|         entry.size = lfs_entry_size(&entry); |         lfs_size_t oldalen = lfs_entry_alen(&entry); | ||||||
|  |         const void *buffer; | ||||||
|  |         lfs_size_t size; | ||||||
|  |  | ||||||
|         // either update the references or inline the whole file |         // either update the references or inline the whole file | ||||||
|         if (!(file->flags & LFS_F_INLINE)) { |         if (!(file->flags & LFS_F_INLINE)) { | ||||||
|             entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG; |             entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG; | ||||||
|             entry.d.elen = sizeof(entry.d)-4; |  | ||||||
|             entry.d.u.file.head = file->head; |             entry.d.u.file.head = file->head; | ||||||
|             entry.d.u.file.size = file->size; |             entry.d.u.file.size = file->size; | ||||||
|  |  | ||||||
|             err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ |             buffer = (const uint8_t *)&entry.d + 4; | ||||||
|                     {LFS_FROM_MEM, 0, 4+oldlen, |             size = sizeof(entry.d) - 4; | ||||||
|                         &entry.d, sizeof(entry.d)}}, 1); |  | ||||||
|             if (err) { |  | ||||||
|                 return err; |  | ||||||
|             } |  | ||||||
|         } else { |         } else { | ||||||
|             entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG; |             entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG; | ||||||
|             entry.d.elen = file->size & 0xff; |  | ||||||
|             entry.d.alen = (entry.d.alen & 0x3f) | ((file->size >> 2) & 0xc0); |  | ||||||
|  |  | ||||||
|             err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ |             buffer = file->cache.buffer; | ||||||
|                     {LFS_FROM_MEM, 0, 0, &entry.d, 4}, |             size = file->size; | ||||||
|                     {LFS_FROM_MEM, 0, 4+oldlen, |         } | ||||||
|                         file->cache.buffer, file->size}}, 2); |  | ||||||
|             if (err) { |         // get new alen from disk | ||||||
|                 return err; |         lfs_ssize_t newalen = lfs_dir_checkattrs(lfs, &cwd, &entry, | ||||||
|             } |                 file->attrs, file->attrcount); | ||||||
|  |         if (newalen < 0) { | ||||||
|  |             return newalen; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         entry.d.elen = size & 0xff; | ||||||
|  |         entry.d.alen = (newalen & 0x3f) | ((size >> 2) & 0xc0); | ||||||
|  |  | ||||||
|  |         // write out update | ||||||
|  |         err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ | ||||||
|  |                 {LFS_FROM_MEM, 0, 4, &entry.d, 4}, | ||||||
|  |                 {LFS_FROM_MEM, 4, oldelen, buffer, size}, | ||||||
|  |                 {LFS_FROM_ATTRS, 4+oldelen, oldalen, | ||||||
|  |                     &(struct lfs_region_attrs){file->attrs, file->attrcount}, | ||||||
|  |                     newalen}}, 3); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         file->flags &= ~LFS_F_DIRTY; |         file->flags &= ~LFS_F_DIRTY; | ||||||
| @@ -2221,6 +2233,81 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int lfs_file_getattrs(lfs_t *lfs, lfs_file_t *file, | ||||||
|  |         const struct lfs_attr *attrs, int count) { | ||||||
|  |     // set to null in case we can't find the attrs (missing file?) | ||||||
|  |     for (int j = 0; j < count; j++) { | ||||||
|  |         memset(attrs[j].buffer, 0, attrs[j].size); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // load from disk if we haven't already been deleted | ||||||
|  |     if (!lfs_pairisnull(file->pair)) { | ||||||
|  |         lfs_dir_t cwd; | ||||||
|  |         int err = lfs_dir_fetch(lfs, &cwd, file->pair); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         lfs_entry_t entry = {.off = file->pairoff}; | ||||||
|  |         err = lfs_dir_get(lfs, &cwd, entry.off, &entry.d, sizeof(entry.d)); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |         entry.size = lfs_entry_size(&entry); | ||||||
|  |  | ||||||
|  |         err = lfs_dir_getattrs(lfs, &cwd, &entry, attrs, count); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // override an attrs we have stored locally | ||||||
|  |     for (int i = 0; i < file->attrcount; i++) { | ||||||
|  |         for (int j = 0; j < count; j++) { | ||||||
|  |             if (attrs[j].type == file->attrs[i].type) { | ||||||
|  |                 if (attrs[j].size < file->attrs[i].size) { | ||||||
|  |                     return LFS_ERR_RANGE; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 memcpy(attrs[j].buffer, | ||||||
|  |                         file->attrs[i].buffer, file->attrs[i].size); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_file_setattrs(lfs_t *lfs, lfs_file_t *file, | ||||||
|  |         const struct lfs_attr *attrs, int count) { | ||||||
|  |     // just tack to the file, will be written at sync time | ||||||
|  |     file->attrs = attrs; | ||||||
|  |     file->attrcount = count; | ||||||
|  |  | ||||||
|  |     // at least make sure attributes fit | ||||||
|  |     if (!lfs_pairisnull(file->pair)) { | ||||||
|  |         lfs_dir_t cwd; | ||||||
|  |         int err = lfs_dir_fetch(lfs, &cwd, file->pair); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         lfs_entry_t entry = {.off = file->pairoff}; | ||||||
|  |         err = lfs_dir_get(lfs, &cwd, entry.off, &entry.d, sizeof(entry.d)); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |         entry.size = lfs_entry_size(&entry); | ||||||
|  |  | ||||||
|  |         lfs_ssize_t res = lfs_dir_checkattrs(lfs, &cwd, &entry, attrs, count); | ||||||
|  |         if (res < 0) { | ||||||
|  |             return res; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// General fs operations /// | /// General fs operations /// | ||||||
| int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { | int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { | ||||||
| @@ -2427,8 +2514,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Attribute operations /// |  | ||||||
| int lfs_getattrs(lfs_t *lfs, const char *path, | int lfs_getattrs(lfs_t *lfs, const char *path, | ||||||
|         const struct lfs_attr *attrs, int count) { |         const struct lfs_attr *attrs, int count) { | ||||||
|     lfs_dir_t cwd; |     lfs_dir_t cwd; | ||||||
| @@ -2646,10 +2731,6 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|     // load superblock |     // load superblock | ||||||
|     lfs_dir_t dir; |     lfs_dir_t dir; | ||||||
|     lfs_entry_t entry; |  | ||||||
|     lfs_superblock_t superblock; |  | ||||||
|     char magic[8]; |  | ||||||
|  |  | ||||||
|     err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); |     err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||||
|     if (err) { |     if (err) { | ||||||
|         if (err == LFS_ERR_CORRUPT) { |         if (err == LFS_ERR_CORRUPT) { | ||||||
| @@ -2658,11 +2739,13 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     err = lfs_dir_get(lfs, &dir, sizeof(dir.d), &entry.d, sizeof(entry.d)); |     lfs_entry_t entry = {.off = sizeof(dir.d)}; | ||||||
|  |     err = lfs_dir_get(lfs, &dir, entry.off, &entry.d, sizeof(entry.d)); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     lfs_superblock_t superblock; | ||||||
|     memset(&superblock.d, 0, sizeof(superblock.d)); |     memset(&superblock.d, 0, sizeof(superblock.d)); | ||||||
|     err = lfs_dir_get(lfs, &dir, |     err = lfs_dir_get(lfs, &dir, | ||||||
|             sizeof(dir.d)+4, &superblock.d, |             sizeof(dir.d)+4, &superblock.d, | ||||||
| @@ -2672,6 +2755,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     char magic[8]; | ||||||
|     err = lfs_dir_get(lfs, &dir, |     err = lfs_dir_get(lfs, &dir, | ||||||
|             sizeof(dir.d)+lfs_entry_size(&entry)-entry.d.nlen, magic, |             sizeof(dir.d)+lfs_entry_size(&entry)-entry.d.nlen, magic, | ||||||
|             lfs_min(sizeof(magic), entry.d.nlen)); |             lfs_min(sizeof(magic), entry.d.nlen)); | ||||||
| @@ -2733,7 +2817,7 @@ int lfs_unmount(lfs_t *lfs) { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Littlefs specific operations /// | /// Internal filesystem filesystem operations /// | ||||||
| int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { | int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { | ||||||
|     if (lfs_pairisnull(lfs->root)) { |     if (lfs_pairisnull(lfs->root)) { | ||||||
|         return 0; |         return 0; | ||||||
| @@ -3064,3 +3148,38 @@ int lfs_deorphan(lfs_t *lfs) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /// External filesystem filesystem operations /// | ||||||
|  | int lfs_fs_getattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count) { | ||||||
|  |     lfs_dir_t dir; | ||||||
|  |     int err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_entry_t entry = {.off = sizeof(dir.d)}; | ||||||
|  |     err = lfs_dir_get(lfs, &dir, entry.off, &entry.d, sizeof(entry.d)); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |     entry.size = lfs_entry_size(&entry); | ||||||
|  |  | ||||||
|  |     return lfs_dir_getattrs(lfs, &dir, &entry, attrs, count); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_fs_setattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count) { | ||||||
|  |     lfs_dir_t dir; | ||||||
|  |     int err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_entry_t entry = {.off = sizeof(dir.d)}; | ||||||
|  |     err = lfs_dir_get(lfs, &dir, entry.off, &entry.d, sizeof(entry.d)); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |     entry.size = lfs_entry_size(&entry); | ||||||
|  |  | ||||||
|  |     return lfs_dir_setattrs(lfs, &dir, &entry, attrs, count); | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -283,7 +283,7 @@ typedef struct lfs_cache { | |||||||
| typedef struct lfs_file { | typedef struct lfs_file { | ||||||
|     struct lfs_file *next; |     struct lfs_file *next; | ||||||
|     lfs_block_t pair[2]; |     lfs_block_t pair[2]; | ||||||
|     lfs_off_t poff; |     lfs_off_t pairoff; | ||||||
|  |  | ||||||
|     lfs_block_t head; |     lfs_block_t head; | ||||||
|     lfs_size_t size; |     lfs_size_t size; | ||||||
| @@ -294,6 +294,9 @@ typedef struct lfs_file { | |||||||
|     lfs_block_t block; |     lfs_block_t block; | ||||||
|     lfs_off_t off; |     lfs_off_t off; | ||||||
|     lfs_cache_t cache; |     lfs_cache_t cache; | ||||||
|  |  | ||||||
|  |     const struct lfs_attr *attrs; | ||||||
|  |     int attrcount; | ||||||
| } lfs_file_t; | } lfs_file_t; | ||||||
|  |  | ||||||
| typedef struct lfs_dir { | typedef struct lfs_dir { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user