mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			v2.4.2
			...
			open-file-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | c7820e653e | ||
|  | deeaa17317 | ||
|  | 026833214a | ||
|  | b19a51c044 | ||
|  | d97d66adf5 | 
							
								
								
									
										260
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										260
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -24,6 +24,14 @@ static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) { | ||||
|     pcache->block = LFS_BLOCK_NULL; | ||||
| } | ||||
|  | ||||
| static inline void lfs_cache_copy(lfs_t *lfs, | ||||
|         lfs_cache_t *dcache, const lfs_cache_t *scache) { | ||||
|     memcpy(dcache->buffer, scache->buffer, lfs->cfg->cache_size); | ||||
|     dcache->block = scache->block; | ||||
|     dcache->off   = scache->off; | ||||
|     dcache->size  = scache->size; | ||||
| } | ||||
|  | ||||
| static int lfs_bd_read(lfs_t *lfs, | ||||
|         const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, | ||||
|         lfs_block_t block, lfs_off_t off, | ||||
| @@ -630,8 +638,6 @@ static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             memset((uint8_t*)gbuffer + diff, 0, gsize - diff); | ||||
|  | ||||
|             return tag + gdiff; | ||||
|         } | ||||
|     } | ||||
| @@ -815,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) { | ||||
| @@ -1080,7 +1090,7 @@ static int lfs_dir_fetch(lfs_t *lfs, | ||||
|  | ||||
| static int lfs_dir_getgstate(lfs_t *lfs, const lfs_mdir_t *dir, | ||||
|         lfs_gstate_t *gstate) { | ||||
|     lfs_gstate_t temp; | ||||
|     lfs_gstate_t temp = {0}; | ||||
|     lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x7ff, 0, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_MOVESTATE, 0, sizeof(temp)), &temp); | ||||
|     if (res < 0 && res != LFS_ERR_NOENT) { | ||||
| @@ -1106,10 +1116,11 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|     } | ||||
|  | ||||
|     lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0), | ||||
|             LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name); | ||||
|             LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max), info->name); | ||||
|     if (tag < 0) { | ||||
|         return (int)tag; | ||||
|     } | ||||
|     info->name[lfs_tag_size(tag)] = '\0'; | ||||
|  | ||||
|     info->type = lfs_tag_type3(tag); | ||||
|  | ||||
| @@ -1173,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 | ||||
| @@ -1821,7 +1837,7 @@ relocate: | ||||
| #ifndef LFS_READONLY | ||||
| static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|         const struct lfs_mattr *attrs, int attrcount) { | ||||
|     // check for any inline files that aren't RAM backed and | ||||
|     // check for any open inline files that aren't RAM backed and | ||||
|     // forcefully evict them, needed for filesystem consistency | ||||
|     for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { | ||||
|         if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && | ||||
| @@ -2013,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; | ||||
| @@ -2450,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 | ||||
| @@ -2468,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; | ||||
| @@ -2476,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); | ||||
| @@ -2501,63 +2521,57 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|         err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( | ||||
|                 {LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL}, | ||||
|                 {LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path}, | ||||
|                 {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL})); | ||||
|                 {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL}, | ||||
|                 {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 | ||||
|         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 (unsigned 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; | ||||
|             } | ||||
|  | ||||
|             file->flags |= LFS_F_DIRTY; | ||||
|             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 | ||||
| @@ -2602,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; | ||||
| @@ -2616,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 | ||||
| @@ -2801,17 +2814,21 @@ 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)) { | ||||
| @@ -2841,10 +2858,41 @@ 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; | ||||
|         } | ||||
|  | ||||
|         // update readable handles referencing this file device-side | ||||
|         for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { | ||||
|             if (f != file && | ||||
|                     f->type == LFS_TYPE_REG && | ||||
|                     lfs_pair_cmp(f->m.pair, file->m.pair) == 0 && | ||||
|                     f->id == file->id && | ||||
|                     // only readable handles because wronly files | ||||
|                     // may reference attributes in ROM | ||||
|                     (f->flags & LFS_O_RDONLY)) { | ||||
|                 // sync disk structure | ||||
|                 f->ctz = file->ctz; | ||||
|                 // copying the cache is required for inline files | ||||
|                 lfs_cache_copy(lfs, &f->cache, &file->cache); | ||||
|  | ||||
|                 // sync attrs | ||||
|                 for (lfs_size_t i = 0; i < f->cfg->attr_count; i++) { | ||||
|                     for (lfs_size_t j = 0; j < file->cfg->attr_count; j++) { | ||||
|                         if (f->cfg->attrs[i].type == file->cfg->attrs[i].type) { | ||||
|                             memcpy(f->cfg->attrs[i].buffer, | ||||
|                                     file->cfg->attrs[i].buffer, | ||||
|                                     lfs_min( | ||||
|                                         f->cfg->attrs[i].size, | ||||
|                                         file->cfg->attrs[i].size)); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 f->flags &= ~(LFS_F_DIRTY | LFS_F_WRITING | LFS_F_READING); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         file->flags &= ~LFS_F_DIRTY; | ||||
|     } | ||||
|  | ||||
| @@ -2854,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; | ||||
| @@ -2928,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; | ||||
| @@ -2970,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; | ||||
|         } | ||||
|     } | ||||
| @@ -2986,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; | ||||
|                     } | ||||
|  | ||||
| @@ -3000,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 { | ||||
| @@ -3020,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; | ||||
|             } | ||||
|  | ||||
| @@ -3028,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; | ||||
|             } | ||||
|         } | ||||
| @@ -3041,7 +3089,7 @@ relocate: | ||||
|         lfs_alloc_ack(lfs); | ||||
|     } | ||||
|  | ||||
|     file->flags &= ~LFS_F_ERRED; | ||||
|     file->flags &= ~LFS_F_ZOMBIE; | ||||
|     return size; | ||||
| } | ||||
| #endif | ||||
| @@ -3078,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; | ||||
| @@ -3424,8 +3472,34 @@ static int lfs_commitattr(lfs_t *lfs, const char *path, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( | ||||
|     int err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( | ||||
|             {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer})); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     if (lfs_tag_type3(tag) == LFS_TYPE_REG && size != 0x3ff) { | ||||
|         // sync attrs with any files open for reading, this follows | ||||
|         // the behavior of lfs_file_sync with attributes | ||||
|         for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { | ||||
|             if (f->type == LFS_TYPE_REG && | ||||
|                     lfs_pair_cmp(f->m.pair, cwd.pair) == 0 && | ||||
|                     f->id == id && | ||||
|                     // only readable handles because wronly files | ||||
|                     // may reference attributes in ROM | ||||
|                     (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) { | ||||
|                         memcpy(f->cfg->attrs[i].buffer, buffer, | ||||
|                                 lfs_min(f->cfg->attrs[i].size, size)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @@ -3829,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]); | ||||
| @@ -5084,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); | ||||
|  | ||||
| @@ -5100,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); | ||||
|  | ||||
| @@ -5118,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); | ||||
|  | ||||
| @@ -5136,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); | ||||
|  | ||||
| @@ -5154,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); | ||||
|  | ||||
| @@ -5171,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); | ||||
|  | ||||
| @@ -5187,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); | ||||
|  | ||||
| @@ -5216,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); | ||||
|  | ||||
|   | ||||
							
								
								
									
										50
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -123,26 +123,30 @@ enum lfs_type { | ||||
| // File open flags | ||||
| enum lfs_open_flags { | ||||
|     // open flags | ||||
|     LFS_O_RDONLY = 1,         // Open a file as read only | ||||
|     LFS_O_RDONLY    = 1,        // Open a file as read only | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_O_WRONLY = 2,         // Open a file as write only | ||||
|     LFS_O_RDWR   = 3,         // Open a file as read and write | ||||
|     LFS_O_CREAT  = 0x0100,    // Create a file if it does not exist | ||||
|     LFS_O_EXCL   = 0x0200,    // Fail if a file already exists | ||||
|     LFS_O_TRUNC  = 0x0400,    // Truncate the existing file to zero size | ||||
|     LFS_O_APPEND = 0x0800,    // Move to end of file on every write | ||||
|     LFS_O_WRONLY    = 2,        // Open a file as write only | ||||
|     LFS_O_RDWR      = 3,        // Open a file as read and write | ||||
| #endif | ||||
|  | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_O_CREAT     = 0x0100,   // Create a file if it does not exist | ||||
|     LFS_O_EXCL      = 0x0200,   // Fail if a file already exists | ||||
|     LFS_O_TRUNC     = 0x0400,   // Truncate the existing file to zero size | ||||
|     LFS_O_APPEND    = 0x0800,   // Move to end of file on every write | ||||
|     LFS_O_SNAPSHOT  = 0x1000,   // Open a temporary snapshot, ignore changes | ||||
| #endif | ||||
|  | ||||
|     // internally used flags | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_F_DIRTY   = 0x010000, // File does not match storage | ||||
|     LFS_F_WRITING = 0x020000, // File has been written since last flush | ||||
|     LFS_F_DIRTY     = 0x010000, // File does not match storage | ||||
| #endif | ||||
|     LFS_F_READING = 0x040000, // File has been read since last flush | ||||
|     LFS_F_READING   = 0x020000, // File has been read since last flush | ||||
| #ifndef LFS_READONLY | ||||
|     LFS_F_ERRED   = 0x080000, // An error occurred during write | ||||
|     LFS_F_WRITING   = 0x040000, // File has been written since last flush | ||||
|     LFS_F_ZOMBIE    = 0x080000, // An error occurred during write | ||||
| #endif | ||||
|     LFS_F_INLINE  = 0x100000, // Currently inlined in directory entry | ||||
|     LFS_F_INLINE    = 0x100000, // Currently inlined in directory entry | ||||
| }; | ||||
|  | ||||
| // File seek flags | ||||
| @@ -294,16 +298,15 @@ struct lfs_file_config { | ||||
|     void *buffer; | ||||
|  | ||||
|     // Optional list of custom attributes related to the file. If the file | ||||
|     // is opened with read access, these attributes will be read from disk | ||||
|     // during the open call. If the file is opened with write access, the | ||||
|     // attributes will be written to disk every file sync or close. This | ||||
|     // write occurs atomically with update to the file's contents. | ||||
|     // is opened for reading, these attributes will be read from disk during | ||||
|     // open. If the file is open for writing, these attribute will be atomically | ||||
|     // written to disk when the file is written to disk. Note that these | ||||
|     // attributes are not written unless the file is modified. | ||||
|     // | ||||
|     // Custom attributes are uniquely identified by an 8-bit type and limited | ||||
|     // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller | ||||
|     // than the buffer, it will be padded with zeros. If the stored attribute | ||||
|     // is larger, then it will be silently truncated. If the attribute is not | ||||
|     // found, it will be created implicitly. | ||||
|     // to LFS_ATTR_MAX bytes. If the stored attribute is larger than the | ||||
|     // provided buffer, it will be silently truncated. If no attribute is | ||||
|     // found, and the file is open for writing, it will be created implicitly. | ||||
|     struct lfs_attr *attrs; | ||||
|  | ||||
|     // Number of custom attributes in the list | ||||
| @@ -471,10 +474,9 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); | ||||
| // Get a custom attribute | ||||
| // | ||||
| // Custom attributes are uniquely identified by an 8-bit type and limited | ||||
| // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than | ||||
| // the buffer, it will be padded with zeros. If the stored attribute is larger, | ||||
| // then it will be silently truncated. If no attribute is found, the error | ||||
| // LFS_ERR_NOATTR is returned and the buffer is filled with zeros. | ||||
| // to LFS_ATTR_MAX bytes. If the stored attribute is larger than the | ||||
| // provided buffer, it will be silently truncated. If no attribute is found, | ||||
| // the error LFS_ERR_NOATTR is returned and the buffer is filled with zeros. | ||||
| // | ||||
| // Returns the size of the attribute, or a negative error code on failure. | ||||
| // Note, the returned size is the size of the attribute on disk, irrespective | ||||
|   | ||||
| @@ -16,41 +16,39 @@ code = ''' | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",   4) == 0); | ||||
|     assert(memcmp(buffer+4,  "bbbbbb", 6) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",  5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",         4) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",        5) == 0); | ||||
|  | ||||
|     lfs_removeattr(&lfs, "hello", 'B') => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => LFS_ERR_NOATTR; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",         4) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",        5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",   4) == 0); | ||||
|     assert(memcmp(buffer+4,  "dddddd", 6) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",  5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 3; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",  4) == 0); | ||||
|     assert(memcmp(buffer+4,  "eee",   3) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc", 5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||
|     lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; | ||||
| @@ -65,13 +63,13 @@ code = ''' | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  9) => 9; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",      4) == 0); | ||||
|     assert(memcmp(buffer+4,  "fffffffff", 9) == 0); | ||||
|     assert(memcmp(buffer+13, "ccccc",     5) == 0); | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     assert(memcmp(buffer, "hello", strlen("hello")) == 0); | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
| @@ -94,41 +92,39 @@ code = ''' | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",   4) == 0); | ||||
|     assert(memcmp(buffer+4,  "bbbbbb", 6) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",  5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'B', "", 0) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",  4) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc", 5) == 0); | ||||
|  | ||||
|     lfs_removeattr(&lfs, "/", 'B') => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => LFS_ERR_NOATTR; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",  4) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc", 5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",   4) == 0); | ||||
|     assert(memcmp(buffer+4,  "dddddd", 6) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",  5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 3; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",  4) == 0); | ||||
|     assert(memcmp(buffer+4,  "eee",   3) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc", 5) == 0); | ||||
|  | ||||
|     lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||
|     lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; | ||||
| @@ -142,13 +138,13 @@ code = ''' | ||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  9) => 9; | ||||
|     lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",      4) == 0); | ||||
|     assert(memcmp(buffer+4,  "fffffffff", 9) == 0); | ||||
|     assert(memcmp(buffer+13, "ccccc",     5) == 0); | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     assert(memcmp(buffer, "hello", strlen("hello")) == 0); | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
| @@ -176,52 +172,55 @@ code = ''' | ||||
|     memcpy(buffer,    "aaaa",   4); | ||||
|     memcpy(buffer+4,  "bbbbbb", 6); | ||||
|     memcpy(buffer+10, "ccccc",  5); | ||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",   4) == 0); | ||||
|     assert(memcmp(buffer+4,  "bbbbbb", 6) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",  5) == 0); | ||||
|  | ||||
|     attrs1[1].size = 0; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     attrs1[1].size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",  4) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc", 5) == 0); | ||||
|  | ||||
|     attrs1[1].size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer+4,  "dddddd", 6); | ||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     attrs1[1].size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",   4) == 0); | ||||
|     assert(memcmp(buffer+4,  "dddddd", 6) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc",  5) == 0); | ||||
|  | ||||
|     attrs1[1].size = 3; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer+4,  "eee", 3); | ||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     attrs1[1].size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",  4) == 0); | ||||
|     assert(memcmp(buffer+4,  "eee",   3) == 0); | ||||
|     assert(memcmp(buffer+10, "ccccc", 5) == 0); | ||||
|  | ||||
|     attrs1[0].size = LFS_ATTR_MAX+1; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) | ||||
|         => LFS_ERR_NOSPC; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello2", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT, &cfg1) => LFS_ERR_NOSPC; | ||||
|  | ||||
|     struct lfs_attr attrs2[] = { | ||||
|         {'A', buffer,    4}, | ||||
| @@ -231,6 +230,7 @@ code = ''' | ||||
|     struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; | ||||
|     memcpy(buffer+4,  "fffffffff", 9); | ||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     attrs1[0].size = 4; | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||
| @@ -249,13 +249,13 @@ code = ''' | ||||
|  | ||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0; | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
|     assert(memcmp(buffer,    "aaaa",      4) == 0); | ||||
|     assert(memcmp(buffer+4,  "fffffffff", 9) == 0); | ||||
|     assert(memcmp(buffer+13, "ccccc",     5) == 0); | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; | ||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); | ||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; | ||||
|     assert(memcmp(buffer, "hillo", strlen("hello")) == 0); | ||||
|     lfs_file_close(&lfs, &file); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
| @@ -287,17 +287,16 @@ code = ''' | ||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 9; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 5; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; | ||||
|     memcmp(buffer,    "fffffffff",          9) => 0; | ||||
|     memcmp(buffer+9,  "ccccc\0\0\0\0",      9) => 0; | ||||
|     memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; | ||||
|     assert(memcmp(buffer,    "fffffffff", 9) == 0); | ||||
|     assert(memcmp(buffer+9,  "ccccc",     5) == 0); | ||||
|  | ||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; | ||||
|     lfs_file_sync(&lfs, &file) => 0; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 4; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 0; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; | ||||
|     memcmp(buffer,    "gggg\0\0\0\0\0",     9) => 0; | ||||
|     memcmp(buffer+9,  "\0\0\0\0\0\0\0\0\0", 9) => 0; | ||||
|     memcmp(buffer+18, "hhhh\0\0\0\0\0",     9) => 0; | ||||
|     assert(memcmp(buffer,    "gggg", 4) == 0); | ||||
|     assert(memcmp(buffer+18, "hhhh", 4) == 0); | ||||
|  | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
|  | ||||
| [[case]] # interspersed file test | ||||
| define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26]  | ||||
| define.FILES = [4, 10, 26] | ||||
| code = ''' | ||||
|     lfs_file_t files[FILES]; | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
| @@ -55,7 +55,7 @@ code = ''' | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs_file_close(&lfs, &files[j]); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| @@ -108,7 +108,7 @@ code = ''' | ||||
|         assert(buffer[0] == '~'); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file); | ||||
|      | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| @@ -168,13 +168,13 @@ code = ''' | ||||
|     } | ||||
|     lfs_file_close(&lfs, &files[0]); | ||||
|     lfs_file_close(&lfs, &files[1]); | ||||
|      | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant interspersed file test | ||||
| define.SIZE = [10, 100] | ||||
| define.FILES = [4, 10, 26]  | ||||
| define.FILES = [4, 10, 26] | ||||
| reentrant = true | ||||
| code = ''' | ||||
|     lfs_file_t files[FILES]; | ||||
| @@ -239,6 +239,698 @@ code = ''' | ||||
|     for (int j = 0; j < FILES; j++) { | ||||
|         lfs_file_close(&lfs, &files[j]); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # open same file reading from separate file handles | ||||
| define.READERS = 3 | ||||
| define.SIZE = [10, 100, 1000, 10000] | ||||
| define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR'] | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "shared", LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // open all files | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_t readers[READERS]; | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         lfs_file_open(&lfs, &readers[i], "shared", RDMODE) => 0; | ||||
|     } | ||||
|  | ||||
|     // perform operations while all readers are open | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         for (int j = 0; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &readers[i], buffer, 1) => 1; | ||||
|             assert(buffer[0] == alphas[j % 26]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         lfs_file_close(&lfs, &readers[i]) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # open same file reading and writing from separate file handles | ||||
| define.READERS = 3 | ||||
| define.SIZE = [10, 100, 1000, 10000] | ||||
| define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR'] | ||||
| define.WRMODE = ['LFS_O_WRONLY', 'LFS_O_RDWR'] | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     const char nums[] = "0123456789"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, "shared", LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // open all files | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_t writer; | ||||
|     lfs_file_t readers[READERS]; | ||||
|     lfs_file_open(&lfs, &writer, "shared", WRMODE) => 0; | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         lfs_file_open(&lfs, &readers[i], "shared", RDMODE) => 0; | ||||
|     } | ||||
|  | ||||
|     // perform operations while all readers are open | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         for (int j = 0; j < SIZE/2; j++) { | ||||
|             lfs_file_read(&lfs, &readers[i], buffer, 1) => 1; | ||||
|             assert(buffer[0] == alphas[j % 26]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // sync, now write should reflect in all open files | ||||
|     lfs_file_sync(&lfs, &writer) => 0; | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         for (int j = SIZE/2; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &readers[i], buffer, 1) => 1; | ||||
|             assert(buffer[0] == nums[j % 10]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // double check our writer reflects its own changes | ||||
|     if (WRMODE == LFS_O_RDWR) { | ||||
|         lfs_file_rewind(&lfs, &writer) => 0; | ||||
|         for (int j = 0; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &writer, buffer, 1) => 1; | ||||
|             assert(buffer[0] == nums[j % 10]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         lfs_file_close(&lfs, &readers[i]) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # check that attributes are updated in open files | ||||
| define.READERS = 3 | ||||
| define.SIZE = 10 | ||||
| define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR'] | ||||
| define.WRMODE = ['LFS_O_WRONLY', 'LFS_O_RDWR'] | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     const char nums[] = "0123456789"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     const struct lfs_file_config filecfg = { | ||||
|         .attr_count = 3, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', "a",   1}, | ||||
|             {'B', "bb",  2}, | ||||
|             {'C', "ccc", 3}, | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_opencfg(&lfs, &file, "shared", | ||||
|             LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // open all files | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_t writer; | ||||
|     const struct lfs_file_config writercfg = { | ||||
|         .attr_count = 3, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[1]){0}, 1}, | ||||
|             {'B', &(uint8_t[2]){0}, 2}, | ||||
|             {'C', &(uint8_t[3]){0}, 3}}}; | ||||
|     lfs_file_t readers[READERS]; | ||||
|     const struct lfs_file_config readercfgs[READERS] = { | ||||
|         {   .attr_count = 3, | ||||
|             .attrs = (struct lfs_attr[]){ | ||||
|                 {'A', &(uint8_t[1]){0}, 1}, | ||||
|                 {'B', &(uint8_t[2]){0}, 2}, | ||||
|                 {'C', &(uint8_t[3]){0}, 3}}}, | ||||
|         {   .attr_count = 3, | ||||
|             .attrs = (struct lfs_attr[]){ | ||||
|                 {'A', &(uint8_t[1]){0}, 1}, | ||||
|                 {'B', &(uint8_t[2]){0}, 2}, | ||||
|                 {'C', &(uint8_t[3]){0}, 3}}}, | ||||
|         {   .attr_count = 3, | ||||
|             .attrs = (struct lfs_attr[]){ | ||||
|                 {'A', &(uint8_t[1]){0}, 1}, | ||||
|                 {'B', &(uint8_t[2]){0}, 2}, | ||||
|                 {'C', &(uint8_t[3]){0}, 3}}}}; | ||||
|     lfs_file_opencfg(&lfs, &writer, "shared", | ||||
|             WRMODE, &writercfg) => 0; | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         lfs_file_opencfg(&lfs, &readers[i], "shared", | ||||
|                 RDMODE, &readercfgs[i]) => 0; | ||||
|     } | ||||
|  | ||||
|     // perform operations while all readers are open | ||||
|     writercfg.attrs[0].size = 1; | ||||
|     memcpy(writercfg.attrs[0].buffer, "0", 1); | ||||
|     writercfg.attrs[1].size = 2; | ||||
|     memcpy(writercfg.attrs[1].buffer, "11", 2); | ||||
|     writercfg.attrs[2].size = 3; | ||||
|     memcpy(writercfg.attrs[2].buffer, "222", 3); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         assert(readercfgs[i].attrs[0].size == 1); | ||||
|         assert(memcmp(readercfgs[i].attrs[0].buffer, "a", 1) == 0); | ||||
|         assert(readercfgs[i].attrs[1].size == 2); | ||||
|         assert(memcmp(readercfgs[i].attrs[1].buffer, "bb", 2) == 0); | ||||
|         assert(readercfgs[i].attrs[2].size == 3); | ||||
|         assert(memcmp(readercfgs[i].attrs[2].buffer, "ccc", 3) == 0); | ||||
|         for (int j = 0; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &readers[i], buffer, 1) => 1; | ||||
|             assert(buffer[0] == alphas[j % 26]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // sync, now write should reflect in all open files | ||||
|     lfs_file_sync(&lfs, &writer) => 0; | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         assert(readercfgs[i].attrs[0].size == 1); | ||||
|         assert(memcmp(readercfgs[i].attrs[0].buffer, "0", 1) == 0); | ||||
|         assert(readercfgs[i].attrs[1].size == 2); | ||||
|         assert(memcmp(readercfgs[i].attrs[1].buffer, "11", 2) == 0); | ||||
|         assert(readercfgs[i].attrs[2].size == 3); | ||||
|         assert(memcmp(readercfgs[i].attrs[2].buffer, "222", 3) == 0); | ||||
|         lfs_file_rewind(&lfs, &readers[i]) => 0; | ||||
|         for (int j = 0; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &readers[i], buffer, 1) => 1; | ||||
|             assert(buffer[0] == nums[j % 10]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // double check our writer reflects its own changes | ||||
|     if (WRMODE == LFS_O_RDWR) { | ||||
|         assert(writercfg.attrs[0].size == 1); | ||||
|         assert(memcmp(writercfg.attrs[0].buffer, "0", 1) == 0); | ||||
|         assert(writercfg.attrs[1].size == 2); | ||||
|         assert(memcmp(writercfg.attrs[1].buffer, "11", 2) == 0); | ||||
|         assert(writercfg.attrs[2].size == 3); | ||||
|         assert(memcmp(writercfg.attrs[2].buffer, "222", 3) == 0); | ||||
|         lfs_file_rewind(&lfs, &writer) => 0; | ||||
|         for (int j = 0; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &writer, buffer, 1) => 1; | ||||
|             assert(buffer[0] == nums[j % 10]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // now try explicit lfs_setattr calls, this should still update open files | ||||
|     lfs_setattr(&lfs, "shared", 'A', "A",   1) => 0; | ||||
|     lfs_setattr(&lfs, "shared", 'B', "BB",  2) => 0; | ||||
|     lfs_setattr(&lfs, "shared", 'C', "CCC", 3) => 0; | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         assert(readercfgs[i].attrs[0].size == 1); | ||||
|         assert(memcmp(readercfgs[i].attrs[0].buffer, "A", 1) == 0); | ||||
|         assert(readercfgs[i].attrs[1].size == 2); | ||||
|         assert(memcmp(readercfgs[i].attrs[1].buffer, "BB", 2) == 0); | ||||
|         assert(readercfgs[i].attrs[2].size == 3); | ||||
|         assert(memcmp(readercfgs[i].attrs[2].buffer, "CCC", 3) == 0); | ||||
|         lfs_file_rewind(&lfs, &readers[i]) => 0; | ||||
|         for (int j = 0; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &readers[i], buffer, 1) => 1; | ||||
|             assert(buffer[0] == nums[j % 10]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (WRMODE == LFS_O_RDWR) { | ||||
|         assert(writercfg.attrs[0].size == 1); | ||||
|         assert(memcmp(writercfg.attrs[0].buffer, "A", 1) == 0); | ||||
|         assert(writercfg.attrs[1].size == 2); | ||||
|         assert(memcmp(writercfg.attrs[1].buffer, "BB", 2) == 0); | ||||
|         assert(writercfg.attrs[2].size == 3); | ||||
|         assert(memcmp(writercfg.attrs[2].buffer, "CCC", 3) == 0); | ||||
|         lfs_file_rewind(&lfs, &writer) => 0; | ||||
|         for (int j = 0; j < SIZE; j++) { | ||||
|             lfs_file_read(&lfs, &writer, buffer, 1) => 1; | ||||
|             assert(buffer[0] == nums[j % 10]); | ||||
|         } | ||||
|     } else if (WRMODE == LFS_O_WRONLY) { | ||||
|         // this should NOT update wronly attributes, these may be | ||||
|         // stored in read-only memory | ||||
|         assert(writercfg.attrs[0].size == 1); | ||||
|         assert(memcmp(writercfg.attrs[0].buffer, "0", 1) == 0); | ||||
|         assert(writercfg.attrs[1].size == 2); | ||||
|         assert(memcmp(writercfg.attrs[1].buffer, "11", 2) == 0); | ||||
|         assert(writercfg.attrs[2].size == 3); | ||||
|         assert(memcmp(writercfg.attrs[2].buffer, "222", 3) == 0); | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < READERS; i++) { | ||||
|         lfs_file_close(&lfs, &readers[i]) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # simple snapshot for reading | ||||
| define.SIZE = [10, 100, 1000, 10000] | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     const char nums[] = "0123456789"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     const struct lfs_file_config filecfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', "abcd", 4}, | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_opencfg(&lfs, &file, "open_me", | ||||
|             LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // open reader/writer/snapshot | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_t reader; | ||||
|     const struct lfs_file_config readercfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_t writer; | ||||
|     const struct lfs_file_config writercfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_t snapshot; | ||||
|     const struct lfs_file_config snapshotcfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     lfs_file_opencfg(&lfs, &writer, "open_me", | ||||
|             LFS_O_WRONLY, &writercfg) => 0; | ||||
|     lfs_file_opencfg(&lfs, &snapshot, "open_me", | ||||
|             LFS_O_RDONLY | LFS_O_SNAPSHOT, &snapshotcfg) => 0; | ||||
|  | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE/2; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE/2; j++) { | ||||
|         lfs_file_read(&lfs, &snapshot, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     // write file | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1; | ||||
|     } | ||||
|     memcpy(writercfg.attrs[0].buffer, "0123", 4); | ||||
|     lfs_file_sync(&lfs, &writer) => 0; | ||||
|  | ||||
|     // reader should change | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0); | ||||
|     for (int j = SIZE/2; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|  | ||||
|     // snapshot should remain unchanged | ||||
|     assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = SIZE/2; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &snapshot, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_file_close(&lfs, &writer) => 0; | ||||
|     lfs_file_close(&lfs, &snapshot) => 0; | ||||
|  | ||||
|     // disk should change | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # simple snapshot for writing | ||||
| define.SIZE = [10, 100, 1000, 10000] | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     const char nums[] = "0123456789"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     const struct lfs_file_config filecfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', "abcd", 4}, | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_opencfg(&lfs, &file, "open_me", | ||||
|             LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // open reader/snapshot | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_t reader; | ||||
|     const struct lfs_file_config readercfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_t snapshot; | ||||
|     const struct lfs_file_config snapshotcfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     lfs_file_opencfg(&lfs, &snapshot, "open_me", | ||||
|             LFS_O_RDWR | LFS_O_SNAPSHOT, &snapshotcfg) => 0; | ||||
|  | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE/2; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &snapshot, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     // modify snapshot | ||||
|     lfs_file_rewind(&lfs, &snapshot) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &snapshot, &nums[j % 10], 1) => 1; | ||||
|     } | ||||
|     memcpy(snapshotcfg.attrs[0].buffer, "0123", 4); | ||||
|  | ||||
|     lfs_file_rewind(&lfs, &snapshot) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &snapshot, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|  | ||||
|     lfs_file_sync(&lfs, &snapshot) => 0; | ||||
|  | ||||
|     // reader should not change | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = SIZE/2; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     // snapshot should changed | ||||
|     assert(memcmp(snapshotcfg.attrs[0].buffer, "0123", 4) == 0); | ||||
|     lfs_file_rewind(&lfs, &snapshot) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &snapshot, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|  | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_file_close(&lfs, &snapshot) => 0; | ||||
|  | ||||
|     // disk should not change | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # temporary files | ||||
| define.SIZE = [10, 100, 1000, 10000] | ||||
| define.TMP_PATH = 'range(4)' | ||||
| code = ''' | ||||
|     const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; | ||||
|     const char nums[] = "0123456789"; | ||||
|     const char caps[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     const struct lfs_file_config filecfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', "abcd", 4}, | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_opencfg(&lfs, &file, "open_me", | ||||
|             LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_file_opencfg(&lfs, &file, "dont_open_me", | ||||
|             LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     // open reader/writer/temp | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_t reader; | ||||
|     const struct lfs_file_config readercfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_t writer; | ||||
|     const struct lfs_file_config writercfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_t tmp; | ||||
|     const struct lfs_file_config tmpcfg = { | ||||
|         .attr_count = 1, | ||||
|         .attrs = (struct lfs_attr[]){ | ||||
|             {'A', &(uint8_t[4]){0}, 4} | ||||
|         }, | ||||
|     }; | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     lfs_file_opencfg(&lfs, &writer, "open_me", | ||||
|             LFS_O_WRONLY, &writercfg) => 0; | ||||
|     const char *tmp_paths[] = {NULL, "/", "/tmp", "/open_me.tmp"}; | ||||
|     lfs_file_opencfg(&lfs, &tmp, tmp_paths[TMP_PATH], | ||||
|             LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT, &tmpcfg) => 0; | ||||
|  | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE/3; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     assert(memcmp(tmpcfg.attrs[0].buffer, "\0\0\0\0", 4) == 0); | ||||
|     assert(lfs_file_size(&lfs, &tmp) == 0); | ||||
|  | ||||
|     // write to tmp | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &tmp, &nums[j % 10], 1) => 1; | ||||
|     } | ||||
|     memcpy(tmpcfg.attrs[0].buffer, "0123", 4); | ||||
|  | ||||
|     lfs_file_rewind(&lfs, &tmp) => 0; | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &tmp, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|  | ||||
|     lfs_file_sync(&lfs, &tmp) => 0; | ||||
|  | ||||
|     // reader should not change | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = SIZE/3; j < 2*SIZE/3; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|  | ||||
|     // tmp should change | ||||
|     assert(memcmp(tmpcfg.attrs[0].buffer, "0123", 4) == 0); | ||||
|     lfs_file_rewind(&lfs, &tmp) => 0; | ||||
|     for (int j = 0; j < SIZE/2; j++) { | ||||
|         lfs_file_read(&lfs, &tmp, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|  | ||||
|     // write to file | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_write(&lfs, &writer, &caps[j % 26], 1) => 1; | ||||
|     } | ||||
|     memcpy(writercfg.attrs[0].buffer, "ABCD", 4); | ||||
|     lfs_file_sync(&lfs, &writer) => 0; | ||||
|  | ||||
|     // reader should change | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0); | ||||
|     for (int j = 2*SIZE/3; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == caps[j % 26]); | ||||
|     } | ||||
|  | ||||
|     // tmp should not change | ||||
|     assert(memcmp(tmpcfg.attrs[0].buffer, "0123", 4) == 0); | ||||
|     for (int j = SIZE/2; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &tmp, buffer, 1) => 1; | ||||
|         assert(buffer[0] == nums[j % 10]); | ||||
|     } | ||||
|  | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_file_close(&lfs, &writer) => 0; | ||||
|     lfs_file_close(&lfs, &tmp) => 0; | ||||
|  | ||||
|     // tmp should not appear on disk | ||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(strcmp(info.name, "dont_open_me") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(strcmp(info.name, "open_me") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == caps[j % 26]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_file_opencfg(&lfs, &reader, "dont_open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(strcmp(info.name, "dont_open_me") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(strcmp(info.name, "open_me") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|     lfs_file_opencfg(&lfs, &reader, "open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == caps[j % 26]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_file_opencfg(&lfs, &reader, "dont_open_me", | ||||
|             LFS_O_RDONLY, &readercfg) => 0; | ||||
|     assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0); | ||||
|     for (int j = 0; j < SIZE; j++) { | ||||
|         lfs_file_read(&lfs, &reader, buffer, 1) => 1; | ||||
|         assert(buffer[0] == alphas[j % 26]); | ||||
|     } | ||||
|     lfs_file_close(&lfs, &reader) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # test snapshot open errors | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file, NULL, | ||||
|             LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_ISDIR; | ||||
|     lfs_file_open(&lfs, &file, "/", | ||||
|             LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_ISDIR; | ||||
|     lfs_file_open(&lfs, &file, "/tmp", | ||||
|             LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_NOENT; | ||||
|     lfs_file_open(&lfs, &file, "/tmp/", | ||||
|             LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT) => LFS_ERR_NOENT; | ||||
|     lfs_file_open(&lfs, &file, "/tmp/tmp", | ||||
|             LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT) => LFS_ERR_NOENT; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|   | ||||
| @@ -95,9 +95,9 @@ code = ''' | ||||
|  | ||||
|     lfs_mkdir(&lfs, "coffee/../milk") => 0; | ||||
|     lfs_stat(&lfs, "coffee/../milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_stat(&lfs, "milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| @@ -129,9 +129,9 @@ code = ''' | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, ".milk") => 0; | ||||
|     lfs_stat(&lfs, ".milk", &info) => 0; | ||||
|     strcmp(info.name, ".milk") => 0; | ||||
|     assert(strcmp(info.name, ".milk") == 0); | ||||
|     lfs_stat(&lfs, "tea/.././.milk", &info) => 0; | ||||
|     strcmp(info.name, ".milk") => 0; | ||||
|     assert(strcmp(info.name, ".milk") == 0); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| @@ -149,13 +149,13 @@ code = ''' | ||||
|     lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; | ||||
|  | ||||
|     lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     assert(strcmp(info.name, "hottea") == 0); | ||||
|  | ||||
|     lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0; | ||||
|     lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_stat(&lfs, "milk", &info) => 0; | ||||
|     strcmp(info.name, "milk") => 0; | ||||
|     assert(strcmp(info.name, "milk") == 0); | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user