mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Introduced the LFS_O_SNAPSHOT flag
LFS_O_SNAPSHOT brings back some of littlefs's idiosyncratic behavior removed in the changes to open file syncing in a form that may be more useful for users. LFS_O_SNAPSHOT allows you to open a "snapshot" of a file. This is a cheap, local copy of a file who's changes are not reflected on disk. Internally, snapshot files use the same mechanism as pending writes. A separate, copy-on-write CTZ skip-list is created, with read-only references to the existing data blocks until a write occurs. The difference is that snapshot files are not enrolled in the mlist, meaning they won't get updates from open file syncs, and during close their contents are simply discarded. As an extra benefit, LFS_O_CREAT | LFS_O_SNAPSHOT is equivalent to Linux's O_TMPFILE, making it easy to create temporary, unnamed files. This may be useful for embedded development, where unnamed flash-backed buffers may provide a slower, but larger, alternative to RAM-backed buffers.
This commit is contained in:
		
							
								
								
									
										184
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										184
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -821,8 +821,12 @@ static int lfs_dir_traverse(lfs_t *lfs, | ||||
|                 return err; | ||||
|             } | ||||
|         } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) { | ||||
|             const struct lfs_attr *a = buffer; | ||||
|             for (unsigned i = 0; i < lfs_tag_size(tag); i++) { | ||||
|                 const struct lfs_attr *a = buffer; | ||||
|                 if (a[i].size > lfs->attr_max) { | ||||
|                     return LFS_ERR_NOSPC; | ||||
|                 } | ||||
|  | ||||
|                 int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type, | ||||
|                         lfs_tag_id(tag) + diff, a[i].size), a[i].buffer); | ||||
|                 if (err) { | ||||
| @@ -1180,6 +1184,11 @@ static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|     dir->tail[0] = lfs->root[0]; | ||||
|     dir->tail[1] = lfs->root[1]; | ||||
|  | ||||
|     // NULL path == root | ||||
|     if (!name) { | ||||
|         return tag; | ||||
|     } | ||||
|  | ||||
|     while (true) { | ||||
| nextname: | ||||
|         // skip slashes | ||||
| @@ -2020,6 +2029,7 @@ compact: | ||||
| #ifndef LFS_READONLY | ||||
| static int lfs_rawmkdir(lfs_t *lfs, const char *path) { | ||||
|     // deorphan if we haven't yet, needed at most once after poweron | ||||
|     LFS_ASSERT(path); | ||||
|     int err = lfs_fs_forceconsistency(lfs); | ||||
|     if (err) { | ||||
|         return err; | ||||
| @@ -2457,14 +2467,14 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|         const struct lfs_file_config *cfg) { | ||||
| #ifndef LFS_READONLY | ||||
|     // deorphan if we haven't yet, needed at most once after poweron | ||||
|     if ((flags & LFS_O_WRONLY) == LFS_O_WRONLY) { | ||||
|     if (flags & LFS_O_WRONLY) { | ||||
|         int err = lfs_fs_forceconsistency(lfs); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     } | ||||
| #else | ||||
|     LFS_ASSERT((flags & LFS_O_RDONLY) == LFS_O_RDONLY); | ||||
|     LFS_ASSERT(flags & LFS_O_RDONLY); | ||||
| #endif | ||||
|  | ||||
|     // setup simple file details | ||||
| @@ -2475,7 +2485,7 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|     file->off = 0; | ||||
|     file->cache.buffer = NULL; | ||||
|  | ||||
|     // allocate entry for file if it doesn't exist | ||||
|     // find path | ||||
|     lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id); | ||||
|     if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) { | ||||
|         err = tag; | ||||
| @@ -2483,19 +2493,22 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|     } | ||||
|  | ||||
|     // get id, add to list of mdirs to catch update changes | ||||
|     file->type = LFS_TYPE_REG; | ||||
|     lfs_mlist_append(lfs, (struct lfs_mlist *)file); | ||||
|     if (!(flags & LFS_O_SNAPSHOT)) { | ||||
|         file->type = LFS_TYPE_REG; | ||||
|         lfs_mlist_append(lfs, (struct lfs_mlist *)file); | ||||
|     } | ||||
|  | ||||
| #ifdef LFS_READONLY | ||||
|     if (tag == LFS_ERR_NOENT) { | ||||
|         err = LFS_ERR_NOENT; | ||||
| #ifndef LFS_READONLY | ||||
|     if ((flags & LFS_O_CREAT) && (flags & LFS_O_SNAPSHOT) && | ||||
|             (tag == LFS_ERR_NOENT || lfs_tag_type3(tag) != LFS_TYPE_REG)) { | ||||
|         // special case for "temporary" files | ||||
|         tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0); | ||||
|     } else if ((flags & LFS_O_EXCL) && tag != LFS_ERR_NOENT) { | ||||
|         err = LFS_ERR_EXIST; | ||||
|         goto cleanup; | ||||
| #else | ||||
|     if (tag == LFS_ERR_NOENT) { | ||||
|         if (!(flags & LFS_O_CREAT)) { | ||||
|             err = LFS_ERR_NOENT; | ||||
|             goto cleanup; | ||||
|         } | ||||
|     } else if ((flags & LFS_O_CREAT) && tag == LFS_ERR_NOENT) { | ||||
|         // allocate entry for file if it doesn't exist | ||||
|         LFS_ASSERT(path); | ||||
|  | ||||
|         // check that name fits | ||||
|         lfs_size_t nlen = strlen(path); | ||||
| @@ -2512,60 +2525,53 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|                 {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, | ||||
|                     file->cfg->attr_count), file->cfg->attrs})); | ||||
|         if (err) { | ||||
|             err = LFS_ERR_NAMETOOLONG; | ||||
|             goto cleanup; | ||||
|         } | ||||
|  | ||||
|         tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0); | ||||
|     } else if (flags & LFS_O_EXCL) { | ||||
|         err = LFS_ERR_EXIST; | ||||
|     } else /**/ | ||||
| #endif     /**/ | ||||
|     /*********/ | ||||
|     /**/ if (tag == LFS_ERR_NOENT) { | ||||
|         err = LFS_ERR_NOENT; | ||||
|         goto cleanup; | ||||
| #endif | ||||
|     } else if (lfs_tag_type3(tag) != LFS_TYPE_REG) { | ||||
|         err = LFS_ERR_ISDIR; | ||||
|         goto cleanup; | ||||
| #ifndef LFS_READONLY | ||||
|     } else if (flags & LFS_O_TRUNC) { | ||||
|         // truncate if requested | ||||
|         // always mark dirty in case we have custom attributes | ||||
|         tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0); | ||||
|         file->flags |= LFS_F_DIRTY; | ||||
| #endif | ||||
|     } else { | ||||
|         // try to load what's on disk, if it's inlined we'll fix it later | ||||
|         tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0), | ||||
|                 LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz); | ||||
|         if (tag < 0) { | ||||
|             err = tag; | ||||
|             goto cleanup; | ||||
|         } | ||||
|         lfs_ctz_fromle32(&file->ctz); | ||||
|     } | ||||
|  | ||||
|     // fetch attrs | ||||
|     for (lfs_size_t i = 0; i < file->cfg->attr_count; i++) { | ||||
|         // if opened for read / read-write operations | ||||
|         if ((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY) { | ||||
|             lfs_stag_t res = lfs_dir_get(lfs, &file->m, | ||||
|                     LFS_MKTAG(0x7ff, 0x3ff, 0), | ||||
|                     LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type, | ||||
|                         file->id, file->cfg->attrs[i].size), | ||||
|                         file->cfg->attrs[i].buffer); | ||||
|             if (res < 0 && res != LFS_ERR_NOENT) { | ||||
|                 err = res; | ||||
|                 goto cleanup; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
|         // if opened for write / read-write operations | ||||
|         if ((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY) { | ||||
|             if (file->cfg->attrs[i].size > lfs->attr_max) { | ||||
|                 err = LFS_ERR_NOSPC; | ||||
|         if (flags & LFS_O_TRUNC) { | ||||
|             // truncate if requested | ||||
|             // always mark dirty in case we have custom attributes | ||||
|             tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0); | ||||
|             file->flags |= LFS_F_DIRTY; | ||||
|         } else /**/ | ||||
| #endif  /*********/ | ||||
|         /**/ { | ||||
|             // try to load what's on disk, if it's inlined we'll fix it later | ||||
|             tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0), | ||||
|                     LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz); | ||||
|             if (tag < 0) { | ||||
|                 err = tag; | ||||
|                 goto cleanup; | ||||
|             } | ||||
|             lfs_ctz_fromle32(&file->ctz); | ||||
|         } | ||||
|  | ||||
|         // fetch attrs if opened for read / read-write operations | ||||
|         if (flags & LFS_O_RDONLY) { | ||||
|             for (lfs_size_t i = 0; i < file->cfg->attr_count; i++) { | ||||
|                 lfs_stag_t res = lfs_dir_get(lfs, &file->m, | ||||
|                         LFS_MKTAG(0x7ff, 0x3ff, 0), | ||||
|                         LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type, | ||||
|                             file->id, file->cfg->attrs[i].size), | ||||
|                             file->cfg->attrs[i].buffer); | ||||
|                 if (res < 0 && res != LFS_ERR_NOENT) { | ||||
|                     err = res; | ||||
|                     goto cleanup; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     // allocate buffer if needed | ||||
| @@ -2610,7 +2616,7 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, | ||||
| cleanup: | ||||
|     // clean up lingering resources | ||||
| #ifndef LFS_READONLY | ||||
|     file->flags |= LFS_F_ERRED; | ||||
|     file->flags |= LFS_F_ZOMBIE; | ||||
| #endif | ||||
|     lfs_file_rawclose(lfs, file); | ||||
|     return err; | ||||
| @@ -2624,10 +2630,9 @@ static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file, | ||||
| } | ||||
|  | ||||
| static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) { | ||||
| #ifndef LFS_READONLY | ||||
|     int err = lfs_file_rawsync(lfs, file); | ||||
| #else | ||||
|     int err = 0; | ||||
| #ifndef LFS_READONLY | ||||
|     err = lfs_file_rawsync(lfs, file); | ||||
| #endif | ||||
|  | ||||
|     // remove from list of mdirs | ||||
| @@ -2809,17 +2814,22 @@ relocate: | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { | ||||
|     if (file->flags & LFS_F_ERRED) { | ||||
|     if (file->flags & LFS_F_ZOMBIE) { | ||||
|         // it's not safe to do anything if our file errored | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     int err = lfs_file_flush(lfs, file); | ||||
|     if (err) { | ||||
|         file->flags |= LFS_F_ERRED; | ||||
|         file->flags |= LFS_F_ZOMBIE; | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     if (file->flags & LFS_O_SNAPSHOT) { | ||||
|         // we do flush snapshot files, but we don't commit, so stop here | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if ((file->flags & LFS_F_DIRTY) && | ||||
|             !lfs_pair_isnull(file->m.pair)) { | ||||
|         // update dir entry | ||||
| @@ -2848,7 +2858,7 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { | ||||
|                 {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, | ||||
|                     file->cfg->attr_count), file->cfg->attrs})); | ||||
|         if (err) { | ||||
|             file->flags |= LFS_F_ERRED; | ||||
|             file->flags |= LFS_F_ZOMBIE; | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
| @@ -2860,7 +2870,7 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { | ||||
|                     f->id == file->id && | ||||
|                     // only readable handles because wronly files | ||||
|                     // may reference attributes in ROM | ||||
|                     (f->flags & LFS_O_RDONLY) == LFS_O_RDONLY) { | ||||
|                     (f->flags & LFS_O_RDONLY)) { | ||||
|                 // sync disk structure | ||||
|                 f->ctz = file->ctz; | ||||
|                 // copying the cache is required for inline files | ||||
| @@ -2892,7 +2902,7 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { | ||||
|  | ||||
| static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, | ||||
|         void *buffer, lfs_size_t size) { | ||||
|     LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY); | ||||
|     LFS_ASSERT(file->flags & LFS_O_RDONLY); | ||||
|  | ||||
|     uint8_t *data = buffer; | ||||
|     lfs_size_t nsize = size; | ||||
| @@ -2966,7 +2976,7 @@ static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, | ||||
| #ifndef LFS_READONLY | ||||
| static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, | ||||
|         const void *buffer, lfs_size_t size) { | ||||
|     LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); | ||||
|     LFS_ASSERT(file->flags & LFS_O_WRONLY); | ||||
|  | ||||
|     const uint8_t *data = buffer; | ||||
|     lfs_size_t nsize = size; | ||||
| @@ -3008,7 +3018,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, | ||||
|         // inline file doesn't fit anymore | ||||
|         int err = lfs_file_outline(lfs, file); | ||||
|         if (err) { | ||||
|             file->flags |= LFS_F_ERRED; | ||||
|             file->flags |= LFS_F_ZOMBIE; | ||||
|             return err; | ||||
|         } | ||||
|     } | ||||
| @@ -3024,7 +3034,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, | ||||
|                             file->ctz.head, file->ctz.size, | ||||
|                             file->pos-1, &file->block, &file->off); | ||||
|                     if (err) { | ||||
|                         file->flags |= LFS_F_ERRED; | ||||
|                         file->flags |= LFS_F_ZOMBIE; | ||||
|                         return err; | ||||
|                     } | ||||
|  | ||||
| @@ -3038,7 +3048,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, | ||||
|                         file->block, file->pos, | ||||
|                         &file->block, &file->off); | ||||
|                 if (err) { | ||||
|                     file->flags |= LFS_F_ERRED; | ||||
|                     file->flags |= LFS_F_ZOMBIE; | ||||
|                     return err; | ||||
|                 } | ||||
|             } else { | ||||
| @@ -3058,7 +3068,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, | ||||
|                 if (err == LFS_ERR_CORRUPT) { | ||||
|                     goto relocate; | ||||
|                 } | ||||
|                 file->flags |= LFS_F_ERRED; | ||||
|                 file->flags |= LFS_F_ZOMBIE; | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
| @@ -3066,7 +3076,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, | ||||
| relocate: | ||||
|             err = lfs_file_relocate(lfs, file); | ||||
|             if (err) { | ||||
|                 file->flags |= LFS_F_ERRED; | ||||
|                 file->flags |= LFS_F_ZOMBIE; | ||||
|                 return err; | ||||
|             } | ||||
|         } | ||||
| @@ -3079,7 +3089,7 @@ relocate: | ||||
|         lfs_alloc_ack(lfs); | ||||
|     } | ||||
|  | ||||
|     file->flags &= ~LFS_F_ERRED; | ||||
|     file->flags &= ~LFS_F_ZOMBIE; | ||||
|     return size; | ||||
| } | ||||
| #endif | ||||
| @@ -3116,7 +3126,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
| static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { | ||||
|     LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); | ||||
|     LFS_ASSERT(file->flags & LFS_O_WRONLY); | ||||
|  | ||||
|     if (size > LFS_FILE_MAX) { | ||||
|         return LFS_ERR_INVAL; | ||||
| @@ -3477,7 +3487,7 @@ static int lfs_commitattr(lfs_t *lfs, const char *path, | ||||
|                     f->id == id && | ||||
|                     // only readable handles because wronly files | ||||
|                     // may reference attributes in ROM | ||||
|                     (f->flags & LFS_O_RDONLY) == LFS_O_RDONLY) { | ||||
|                     (f->flags & LFS_O_RDONLY)) { | ||||
|                 // sync attrs | ||||
|                 for (lfs_size_t i = 0; i < f->cfg->attr_count; i++) { | ||||
|                     if (f->cfg->attrs[i].type == type) { | ||||
| @@ -3893,7 +3903,7 @@ int lfs_fs_rawtraverse(lfs_t *lfs, | ||||
|                 if (err) { | ||||
|                     return err; | ||||
|                 } | ||||
|             } else if (includeorphans &&  | ||||
|             } else if (includeorphans && | ||||
|                     lfs_tag_type3(tag) == LFS_TYPE_DIRSTRUCT) { | ||||
|                 for (int i = 0; i < 2; i++) { | ||||
|                     err = cb(data, (&ctz.head)[i]); | ||||
| @@ -5148,7 +5158,8 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | ||||
|         return err; | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     err = lfs_file_rawclose(lfs, file); | ||||
|  | ||||
| @@ -5164,7 +5175,8 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | ||||
|         return err; | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     err = lfs_file_rawsync(lfs, file); | ||||
|  | ||||
| @@ -5182,7 +5194,8 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", | ||||
|             (void*)lfs, (void*)file, buffer, size); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size); | ||||
|  | ||||
| @@ -5200,7 +5213,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", | ||||
|             (void*)lfs, (void*)file, buffer, size); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size); | ||||
|  | ||||
| @@ -5218,7 +5232,8 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", | ||||
|             (void*)lfs, (void*)file, off, whence); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence); | ||||
|  | ||||
| @@ -5235,7 +5250,8 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", | ||||
|             (void*)lfs, (void*)file, size); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     err = lfs_file_rawtruncate(lfs, file, size); | ||||
|  | ||||
| @@ -5251,7 +5267,8 @@ lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { | ||||
|         return err; | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     lfs_soff_t res = lfs_file_rawtell(lfs, file); | ||||
|  | ||||
| @@ -5280,7 +5297,8 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { | ||||
|         return err; | ||||
|     } | ||||
|     LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); | ||||
|     LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|     LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) || | ||||
|             lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); | ||||
|  | ||||
|     lfs_soff_t res = lfs_file_rawsize(lfs, file); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user