mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Simplified config
Before, the lfs had multiple paths to determine config options: - lfs_config struct passed during initialization - lfs_bd_info struct passed during block device initialization - compile time options This allowed different developers to provide their own needs to the filesystem, such as the block device capabilities and the higher level user's own tweaks. However, this comes with additional complexity and action required when the configurations are incompatible. For now, this has been reduced to all information (including block device function pointers) being passed through the lfs_config struct. We just defer more complicated handling of configuration options to the top level user. This simplifies configuration handling and gives the top level user the responsibility to handle configuration, which they probably would have wanted to do anyways.
This commit is contained in:
		| @@ -19,9 +19,12 @@ | ||||
|  | ||||
|  | ||||
| // Block device emulated on existing filesystem | ||||
| int lfs_emubd_create(lfs_emubd_t *emu, const char *path) { | ||||
|     memset(&emu->info, 0, sizeof(emu->info)); | ||||
|     memset(&emu->stats, 0, sizeof(emu->stats)); | ||||
| int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { | ||||
|     lfs_emubd_t *emu = cfg->context; | ||||
|     emu->cfg.read_size   = cfg->read_size; | ||||
|     emu->cfg.prog_size   = cfg->prog_size; | ||||
|     emu->cfg.block_size  = cfg->block_size; | ||||
|     emu->cfg.block_count = cfg->block_count; | ||||
|  | ||||
|     // Allocate buffer for creating children files | ||||
|     size_t pathlen = strlen(path); | ||||
| @@ -41,12 +44,6 @@ int lfs_emubd_create(lfs_emubd_t *emu, const char *path) { | ||||
|         return -errno; | ||||
|     } | ||||
|  | ||||
|     // Setup info based on configuration | ||||
|     emu->info.read_size  = LFS_EMUBD_READ_SIZE; | ||||
|     emu->info.prog_size  = LFS_EMUBD_PROG_SIZE; | ||||
|     emu->info.erase_size = LFS_EMUBD_ERASE_SIZE; | ||||
|     emu->info.total_size = LFS_EMUBD_TOTAL_SIZE; | ||||
|  | ||||
|     // Load stats to continue incrementing | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "stats"); | ||||
|     FILE *f = fopen(emu->path, "r"); | ||||
| @@ -67,92 +64,42 @@ int lfs_emubd_create(lfs_emubd_t *emu, const char *path) { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void lfs_emubd_destroy(lfs_emubd_t *emu) { | ||||
|     lfs_emubd_sync(emu); | ||||
| void lfs_emubd_destroy(const struct lfs_config *cfg) { | ||||
|     lfs_emubd_sync(cfg); | ||||
|  | ||||
|     lfs_emubd_t *emu = cfg->context; | ||||
|     free(emu->path); | ||||
| } | ||||
|  | ||||
| int lfs_emubd_read(lfs_emubd_t *emu, lfs_block_t block, | ||||
| int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, void *buffer) { | ||||
|     lfs_emubd_t *emu = cfg->context; | ||||
|     uint8_t *data = buffer; | ||||
|  | ||||
|     // Check if read is valid | ||||
|     assert(off % emu->info.read_size == 0); | ||||
|     assert(size % emu->info.read_size == 0); | ||||
|     assert((uint64_t)block*emu->info.erase_size + off + size | ||||
|             < emu->info.total_size); | ||||
|     assert(off  % cfg->read_size == 0); | ||||
|     assert(size % cfg->read_size == 0); | ||||
|     assert(block < cfg->block_count); | ||||
|  | ||||
|     // Zero out buffer for debugging | ||||
|     memset(data, 0, size); | ||||
|  | ||||
|     // Iterate over blocks until enough data is read | ||||
|     while (size > 0) { | ||||
|         snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|         size_t count = lfs_min(emu->info.erase_size - off, size); | ||||
|     // Read data | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|  | ||||
|         FILE *f = fopen(emu->path, "rb"); | ||||
|         if (!f && errno != ENOENT) { | ||||
|             return -errno; | ||||
|         } | ||||
|  | ||||
|         if (f) { | ||||
|             int err = fseek(f, off, SEEK_SET); | ||||
|             if (err) { | ||||
|                 return -errno; | ||||
|             } | ||||
|  | ||||
|             size_t res = fread(data, 1, count, f); | ||||
|             if (res < count && !feof(f)) { | ||||
|                 return -errno; | ||||
|             } | ||||
|  | ||||
|             err = fclose(f); | ||||
|             if (err) { | ||||
|                 return -errno; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         size -= count; | ||||
|         data += count; | ||||
|         block += 1; | ||||
|         off = 0; | ||||
|     FILE *f = fopen(emu->path, "rb"); | ||||
|     if (!f && errno != ENOENT) { | ||||
|         return -errno; | ||||
|     } | ||||
|  | ||||
|     emu->stats.read_count += 1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_emubd_prog(lfs_emubd_t *emu, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, const void *buffer) { | ||||
|     const uint8_t *data = buffer; | ||||
|  | ||||
|     // Check if write is valid | ||||
|     assert(off % emu->info.prog_size == 0); | ||||
|     assert(size % emu->info.prog_size == 0); | ||||
|     assert((uint64_t)block*emu->info.erase_size + off + size | ||||
|             < emu->info.total_size); | ||||
|  | ||||
|     // Iterate over blocks until enough data is read | ||||
|     while (size > 0) { | ||||
|         snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|         size_t count = lfs_min(emu->info.erase_size - off, size); | ||||
|  | ||||
|         FILE *f = fopen(emu->path, "r+b"); | ||||
|         if (!f && errno == ENOENT) { | ||||
|             f = fopen(emu->path, "w+b"); | ||||
|             if (!f) { | ||||
|                 return -errno; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     if (f) { | ||||
|         int err = fseek(f, off, SEEK_SET); | ||||
|         if (err) { | ||||
|             return -errno; | ||||
|         } | ||||
|  | ||||
|         size_t res = fwrite(data, 1, count, f); | ||||
|         if (res < count) { | ||||
|         size_t res = fread(data, 1, size, f); | ||||
|         if (res < size && !feof(f)) { | ||||
|             return -errno; | ||||
|         } | ||||
|  | ||||
| @@ -160,60 +107,88 @@ int lfs_emubd_prog(lfs_emubd_t *emu, lfs_block_t block, | ||||
|         if (err) { | ||||
|             return -errno; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         size -= count; | ||||
|         data += count; | ||||
|         block += 1; | ||||
|         off = 0; | ||||
|     emu->stats.read_count += 1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, const void *buffer) { | ||||
|     lfs_emubd_t *emu = cfg->context; | ||||
|     const uint8_t *data = buffer; | ||||
|  | ||||
|     // Check if write is valid | ||||
|     assert(off  % cfg->prog_size == 0); | ||||
|     assert(size % cfg->prog_size == 0); | ||||
|     assert(block < cfg->block_count); | ||||
|  | ||||
|     // Program data | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|  | ||||
|     FILE *f = fopen(emu->path, "r+b"); | ||||
|     if (!f && errno == ENOENT) { | ||||
|         f = fopen(emu->path, "w+b"); | ||||
|         if (!f) { | ||||
|             return -errno; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     int err = fseek(f, off, SEEK_SET); | ||||
|     if (err) { | ||||
|         return -errno; | ||||
|     } | ||||
|  | ||||
|     size_t res = fwrite(data, 1, size, f); | ||||
|     if (res < size) { | ||||
|         return -errno; | ||||
|     } | ||||
|  | ||||
|     err = fclose(f); | ||||
|     if (err) { | ||||
|         return -errno; | ||||
|     } | ||||
|  | ||||
|     emu->stats.prog_count += 1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_emubd_erase(lfs_emubd_t *emu, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size) { | ||||
| int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||
|     lfs_emubd_t *emu = cfg->context; | ||||
|  | ||||
|     // Check if erase is valid | ||||
|     assert(off % emu->info.erase_size == 0); | ||||
|     assert(size % emu->info.erase_size == 0); | ||||
|     assert((uint64_t)block*emu->info.erase_size + off + size | ||||
|             < emu->info.total_size); | ||||
|     assert(block < cfg->block_count); | ||||
|  | ||||
|     // Iterate and erase blocks | ||||
|     while (size > 0) { | ||||
|         snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|         struct stat st; | ||||
|         int err = stat(emu->path, &st); | ||||
|         if (err && errno != ENOENT) { | ||||
|     // Erase the block | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||
|     struct stat st; | ||||
|     int err = stat(emu->path, &st); | ||||
|     if (err && errno != ENOENT) { | ||||
|         return -errno; | ||||
|     } | ||||
|  | ||||
|     if (!err && S_ISREG(st.st_mode)) { | ||||
|         int err = unlink(emu->path); | ||||
|         if (err) { | ||||
|             return -errno; | ||||
|         } | ||||
|  | ||||
|         if (!err && S_ISREG(st.st_mode)) { | ||||
|             int err = unlink(emu->path); | ||||
|             if (err) { | ||||
|                 return -errno; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         size -= emu->info.erase_size; | ||||
|         block += 1; | ||||
|         off = 0; | ||||
|     } | ||||
|  | ||||
|     emu->stats.erase_count += 1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_emubd_sync(lfs_emubd_t *emu) { | ||||
| int lfs_emubd_sync(const struct lfs_config *cfg) { | ||||
|     lfs_emubd_t *emu = cfg->context; | ||||
|  | ||||
|     // Just write out info/stats for later lookup | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "info"); | ||||
|     snprintf(emu->child, LFS_NAME_MAX, "config"); | ||||
|     FILE *f = fopen(emu->path, "w"); | ||||
|     if (!f) { | ||||
|         return -errno; | ||||
|     } | ||||
|  | ||||
|     size_t res = fwrite(&emu->info, sizeof(emu->info), 1, f); | ||||
|     size_t res = fwrite(&emu->cfg, sizeof(emu->cfg), 1, f); | ||||
|     if (res < 1) { | ||||
|         return -errno; | ||||
|     } | ||||
| @@ -242,46 +217,3 @@ int lfs_emubd_sync(lfs_emubd_t *emu) { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_emubd_info(lfs_emubd_t *emu, struct lfs_bd_info *info) { | ||||
|     *info = emu->info; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_emubd_stats(lfs_emubd_t *emu, struct lfs_bd_stats *stats) { | ||||
|     *stats = emu->stats; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| // Wrappers for void*s | ||||
| static int lfs_emubd_bd_read(void *bd, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, void *buffer) { | ||||
|     return lfs_emubd_read((lfs_emubd_t*)bd, block, off, size, buffer); | ||||
| } | ||||
|  | ||||
| static int lfs_emubd_bd_prog(void *bd, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, const void *buffer) { | ||||
|     return lfs_emubd_prog((lfs_emubd_t*)bd, block, off, size, buffer); | ||||
| } | ||||
|  | ||||
| static int lfs_emubd_bd_erase(void *bd, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size) { | ||||
|     return lfs_emubd_erase((lfs_emubd_t*)bd, block, off, size); | ||||
| } | ||||
|  | ||||
| static int lfs_emubd_bd_sync(void *bd) { | ||||
|     return lfs_emubd_sync((lfs_emubd_t*)bd); | ||||
| } | ||||
|  | ||||
| static int lfs_emubd_bd_info(void *bd, struct lfs_bd_info *info) { | ||||
|     return lfs_emubd_info((lfs_emubd_t*)bd, info); | ||||
| } | ||||
|  | ||||
| const struct lfs_bd_ops lfs_emubd_ops = { | ||||
|     .read = lfs_emubd_bd_read, | ||||
|     .prog = lfs_emubd_bd_prog, | ||||
|     .erase = lfs_emubd_bd_erase, | ||||
|     .sync = lfs_emubd_bd_sync, | ||||
|     .info = lfs_emubd_bd_info, | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -7,9 +7,8 @@ | ||||
| #ifndef LFS_EMUBD_H | ||||
| #define LFS_EMUBD_H | ||||
|  | ||||
| #include "lfs_config.h" | ||||
| #include "lfs.h" | ||||
| #include "lfs_util.h" | ||||
| #include "lfs_bd.h" | ||||
|  | ||||
|  | ||||
| // Config options | ||||
| @@ -30,60 +29,50 @@ | ||||
| #endif | ||||
|  | ||||
|  | ||||
| // Stats for debugging and optimization | ||||
| struct lfs_bd_stats { | ||||
|     uint64_t read_count; | ||||
|     uint64_t prog_count; | ||||
|     uint64_t erase_count; | ||||
| }; | ||||
|  | ||||
| // The emu bd state | ||||
| typedef struct lfs_emubd { | ||||
|     char *path; | ||||
|     char *child; | ||||
|     struct lfs_bd_info info; | ||||
|     struct lfs_bd_stats stats; | ||||
|  | ||||
|     struct { | ||||
|         uint64_t read_count; | ||||
|         uint64_t prog_count; | ||||
|         uint64_t erase_count; | ||||
|     } stats; | ||||
|  | ||||
|     struct { | ||||
|         uint32_t read_size; | ||||
|         uint32_t prog_size; | ||||
|         uint32_t block_size; | ||||
|         uint32_t block_count; | ||||
|     } cfg; | ||||
| } lfs_emubd_t; | ||||
|  | ||||
|  | ||||
| // Create a block device using path for the directory to store blocks | ||||
| int lfs_emubd_create(lfs_emubd_t *emu, const char *path); | ||||
| int lfs_emubd_create(const struct lfs_config *cfg, const char *path); | ||||
|  | ||||
| // Clean up memory associated with emu block device | ||||
| void lfs_emubd_destroy(lfs_emubd_t *emu); | ||||
| void lfs_emubd_destroy(const struct lfs_config *cfg); | ||||
|  | ||||
| // Read a block | ||||
| int lfs_emubd_read(lfs_emubd_t *bd, lfs_block_t block, | ||||
| int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, void *buffer); | ||||
|  | ||||
| // Program a block | ||||
| // | ||||
| // The block must have previously been erased. | ||||
| int lfs_emubd_prog(lfs_emubd_t *bd, lfs_block_t block, | ||||
| int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, const void *buffer); | ||||
|  | ||||
| // Erase a block | ||||
| // | ||||
| // A block must be erased before being programmed. The | ||||
| // state of an erased block is undefined. | ||||
| int lfs_emubd_erase(lfs_emubd_t *bd, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size); | ||||
| int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block); | ||||
|  | ||||
| // Sync the block device | ||||
| int lfs_emubd_sync(lfs_emubd_t *bd); | ||||
|  | ||||
| // Get a description of the block device | ||||
| // | ||||
| // Any unknown information may be left unmodified | ||||
| int lfs_emubd_info(lfs_emubd_t *bd, struct lfs_bd_info *info); | ||||
|  | ||||
| // Get stats of operations on the block device | ||||
| // | ||||
| // Used for debugging and optimizations | ||||
| int lfs_emubd_stats(lfs_emubd_t *bd, struct lfs_bd_stats *stats); | ||||
|  | ||||
| // Block device operations | ||||
| extern const struct lfs_bd_ops lfs_emubd_ops; | ||||
| int lfs_emubd_sync(const struct lfs_config *cfg); | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										141
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -12,27 +12,22 @@ | ||||
|  | ||||
|  | ||||
| /// Block device operations /// | ||||
| static int lfs_bd_info(lfs_t *lfs, struct lfs_bd_info *info) { | ||||
|     return lfs->bd_ops->info(lfs->bd, info); | ||||
| } | ||||
|  | ||||
| static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, void *buffer) { | ||||
|     return lfs->bd_ops->read(lfs->bd, block, off, size, buffer); | ||||
|     return lfs->cfg->read(lfs->cfg, block, off, size, buffer); | ||||
| } | ||||
|  | ||||
| static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size, const void *buffer) { | ||||
|     return lfs->bd_ops->prog(lfs->bd, block, off, size, buffer); | ||||
|     return lfs->cfg->prog(lfs->cfg, block, off, size, buffer); | ||||
| } | ||||
|  | ||||
| static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block, | ||||
|         lfs_off_t off, lfs_size_t size) { | ||||
|     return lfs->bd_ops->erase(lfs->bd, block, off, size); | ||||
| static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { | ||||
|     return lfs->cfg->erase(lfs->cfg, block); | ||||
| } | ||||
|  | ||||
| static int lfs_bd_sync(lfs_t *lfs) { | ||||
|     return lfs->bd_ops->sync(lfs->bd); | ||||
|     return lfs->cfg->sync(lfs->cfg); | ||||
| } | ||||
|  | ||||
| static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block, | ||||
| @@ -101,7 +96,7 @@ static int lfs_alloc_scan(lfs_t *lfs) { | ||||
|             // found free block, now find stride of free blocks | ||||
|             // since this is relatively cheap (stress on relatively) | ||||
|             lfs->free.begin += off; | ||||
|             lfs->free.end = lfs->block_count; // before superblock | ||||
|             lfs->free.end = lfs->cfg->block_count; // before superblock | ||||
|  | ||||
|             // find maximum stride in tree | ||||
|             return lfs_traverse(lfs, lfs_alloc_stride, lfs); | ||||
| @@ -157,7 +152,7 @@ static int lfs_alloc_erased(lfs_t *lfs, lfs_block_t *block) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     return lfs_bd_erase(lfs, *block, 0, lfs->block_size); | ||||
|     return lfs_bd_erase(lfs, *block); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -175,9 +170,9 @@ static lfs_off_t lfs_indexnext(lfs_t *lfs, lfs_off_t ioff) { | ||||
|  | ||||
| static lfs_off_t lfs_indexfrom(lfs_t *lfs, lfs_off_t off) { | ||||
|     lfs_off_t i = 0; | ||||
|     while (off > lfs->block_size) { | ||||
|     while (off > lfs->cfg->block_size) { | ||||
|         i = lfs_indexnext(lfs, i); | ||||
|         off -= lfs->block_size; | ||||
|         off -= lfs->cfg->block_size; | ||||
|     } | ||||
|  | ||||
|     return i; | ||||
| @@ -370,7 +365,7 @@ static int lfs_dir_fetch(lfs_t *lfs, | ||||
|         uint32_t crc = 0xffffffff; | ||||
|         crc = lfs_crc(crc, sizeof(test), &test); | ||||
|  | ||||
|         for (lfs_off_t j = sizeof(test); j < lfs->block_size; j += 4) { | ||||
|         for (lfs_off_t j = sizeof(test); j < lfs->cfg->block_size; j += 4) { | ||||
|             uint32_t word; | ||||
|             int err = lfs_bd_read(lfs, tpair[i], j, 4, &word); | ||||
|             if (err) { | ||||
| @@ -406,7 +401,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | ||||
|     dir->d.rev += 1; | ||||
|     lfs_pairswap(dir->pair); | ||||
|  | ||||
|     int err = lfs_bd_erase(lfs, dir->pair[0], 0, lfs->block_size); | ||||
|     int err = lfs_bd_erase(lfs, dir->pair[0]); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -456,7 +451,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     while (off < lfs->block_size-4) { | ||||
|     while (off < lfs->cfg->block_size-4) { | ||||
|         uint8_t data; | ||||
|         int err = lfs_bd_read(lfs, dir->pair[0], off, 1, &data); | ||||
|         if (err) { | ||||
| @@ -467,7 +462,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         off += 1; | ||||
|     } | ||||
|  | ||||
|     err = lfs_bd_prog(lfs, dir->pair[0], lfs->block_size-4, 4, &crc); | ||||
|     err = lfs_bd_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, 4, &crc); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -480,7 +475,7 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|     dir->d.size -= entry->d.len; | ||||
|     lfs_pairswap(dir->pair); | ||||
|  | ||||
|     int err = lfs_bd_erase(lfs, dir->pair[0], 0, lfs->block_size); | ||||
|     int err = lfs_bd_erase(lfs, dir->pair[0]); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -516,7 +511,7 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     while (woff < lfs->block_size-4) { | ||||
|     while (woff < lfs->cfg->block_size-4) { | ||||
|         uint8_t data; | ||||
|         int err = lfs_bd_read(lfs, dir->pair[0], woff, 1, &data); | ||||
|         if (err) { | ||||
| @@ -527,7 +522,7 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|         woff += 1; | ||||
|     } | ||||
|  | ||||
|     err = lfs_bd_prog(lfs, dir->pair[0], lfs->block_size-4, 4, &crc); | ||||
|     err = lfs_bd_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, 4, &crc); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -539,7 +534,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         lfs_entry_t *entry, const void *data) { | ||||
|     // check if we fit, if top bit is set we do not and move on | ||||
|     while (true) { | ||||
|         if (dir->d.size + entry->d.len <= lfs->block_size - 4) { | ||||
|         if (dir->d.size + entry->d.len <= lfs->cfg->block_size - 4) { | ||||
|             entry->pair[0] = dir->pair[0]; | ||||
|             entry->pair[1] = dir->pair[1]; | ||||
|             entry->off = dir->d.size; | ||||
| @@ -882,7 +877,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|  | ||||
|     // TODO do this lazily in write? | ||||
|     // TODO cow the head i/d block | ||||
|     if (file->size < lfs->block_size) { | ||||
|     if (file->size < lfs->cfg->block_size) { | ||||
|         file->wblock = file->head; | ||||
|     } else { | ||||
|         int err = lfs_index_find(lfs, file->head, file->windex, | ||||
| @@ -915,7 +910,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | ||||
|     lfs_size_t nsize = size; | ||||
|  | ||||
|     while (nsize > 0) { | ||||
|         lfs_off_t woff = file->size % lfs->block_size; | ||||
|         lfs_off_t woff = file->size % lfs->cfg->block_size; | ||||
|  | ||||
|         if (file->size == 0) { | ||||
|             int err = lfs_alloc_erased(lfs, &file->wblock); | ||||
| @@ -938,7 +933,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         lfs_size_t diff = lfs_min(nsize, lfs->block_size - woff); | ||||
|         lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - woff); | ||||
|         int err = lfs_bd_prog(lfs, file->wblock, woff, diff, data); | ||||
|         if (err) { | ||||
|             return err; | ||||
| @@ -958,10 +953,10 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | ||||
|     lfs_size_t nsize = size; | ||||
|  | ||||
|     while (nsize > 0 && file->roff < file->size) { | ||||
|         lfs_off_t roff = file->roff % lfs->block_size; | ||||
|         lfs_off_t roff = file->roff % lfs->cfg->block_size; | ||||
|  | ||||
|         // TODO cache index blocks | ||||
|         if (file->size < lfs->block_size) { | ||||
|         if (file->size < lfs->cfg->block_size) { | ||||
|             file->rblock = file->head; | ||||
|         } else if (roff == 0) { | ||||
|             int err = lfs_index_find(lfs, file->head, file->windex, | ||||
| @@ -975,7 +970,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | ||||
|  | ||||
|         lfs_size_t diff = lfs_min( | ||||
|                 lfs_min(nsize, file->size-file->roff), | ||||
|                 lfs->block_size - roff); | ||||
|                 lfs->cfg->block_size - roff); | ||||
|         int err = lfs_bd_read(lfs, file->rblock, roff, diff, data); | ||||
|         if (err) { | ||||
|             return err; | ||||
| @@ -991,85 +986,17 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | ||||
|  | ||||
|  | ||||
| /// Generic filesystem operations /// | ||||
| static int lfs_configure(lfs_t *lfs, const struct lfs_config *config) { | ||||
|     lfs->bd = config->bd; | ||||
|     lfs->bd_ops = config->bd_ops; | ||||
|  | ||||
|     struct lfs_bd_info info; | ||||
|     int err = lfs_bd_info(lfs, &info); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     if (config->read_size) { | ||||
|         if (config->read_size < info.read_size || | ||||
|             config->read_size % info.read_size != 0) { | ||||
|             LFS_ERROR("Invalid read size %u, device has %u\n", | ||||
|                 config->read_size, info.read_size); | ||||
|             return LFS_ERROR_INVALID; | ||||
|         } | ||||
|  | ||||
|         lfs->read_size = config->read_size; | ||||
|     } else { | ||||
|         lfs->read_size = info.read_size; | ||||
|     } | ||||
|  | ||||
|     if (config->prog_size) { | ||||
|         if (config->prog_size < info.prog_size || | ||||
|             config->prog_size % info.prog_size != 0) { | ||||
|             LFS_ERROR("Invalid prog size %u, device has %u\n", | ||||
|                 config->prog_size, info.prog_size); | ||||
|             return LFS_ERROR_INVALID; | ||||
|         } | ||||
|  | ||||
|         lfs->prog_size = config->prog_size; | ||||
|     } else { | ||||
|         lfs->prog_size = info.prog_size; | ||||
|     } | ||||
|  | ||||
|     if (config->block_size) { | ||||
|         if (config->block_size < info.erase_size || | ||||
|             config->block_size % info.erase_size != 0) { | ||||
|             LFS_ERROR("Invalid block size %u, device has %u\n", | ||||
|                 config->prog_size, info.prog_size); | ||||
|             return LFS_ERROR_INVALID; | ||||
|         } | ||||
|  | ||||
|         lfs->block_size = config->block_size; | ||||
|     } else { | ||||
|         lfs->block_size = lfs_min(512, info.erase_size); | ||||
|     } | ||||
|  | ||||
|     if (config->block_count) { | ||||
|         if (config->block_count > info.total_size/info.erase_size) { | ||||
|             LFS_ERROR("Invalid block size %u, device has %u\n", | ||||
|                 config->block_size, | ||||
|                 (uint32_t)(info.total_size/info.erase_size)); | ||||
|             return LFS_ERROR_INVALID; | ||||
|         } | ||||
|  | ||||
|         lfs->block_count = config->block_count; | ||||
|     } else { | ||||
|         lfs->block_count = info.total_size / info.erase_size; | ||||
|     } | ||||
|  | ||||
|     lfs->words = lfs->block_size / sizeof(uint32_t); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_format(lfs_t *lfs, const struct lfs_config *config) { | ||||
|     int err = lfs_configure(lfs, config); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|     lfs->cfg = config; | ||||
|     lfs->words = lfs->cfg->block_size / sizeof(uint32_t); | ||||
|  | ||||
|     // Create free list | ||||
|     lfs->free.begin = 0; | ||||
|     lfs->free.end = lfs->block_count-1; | ||||
|     lfs->free.end = lfs->cfg->block_count-1; | ||||
|  | ||||
|     // Create superblock dir | ||||
|     lfs_dir_t superdir; | ||||
|     err = lfs_dir_alloc(lfs, &superdir); | ||||
|     int err = lfs_dir_alloc(lfs, &superdir); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -1096,8 +1023,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config) { | ||||
|         .d.len = sizeof(superblock.d), | ||||
|         .d.version = 0x00000001, | ||||
|         .d.magic = {"littlefs"}, | ||||
|         .d.block_size  = lfs->block_size, | ||||
|         .d.block_count = lfs->block_count, | ||||
|         .d.block_size  = lfs->cfg->block_size, | ||||
|         .d.block_count = lfs->cfg->block_count, | ||||
|         .d.root = {lfs->root[0], lfs->root[1]}, | ||||
|     }; | ||||
|     superdir.d.tail[0] = root.pair[0]; | ||||
| @@ -1121,14 +1048,12 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config) { | ||||
| } | ||||
|  | ||||
| int lfs_mount(lfs_t *lfs, const struct lfs_config *config) { | ||||
|     int err = lfs_configure(lfs, config); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|     lfs->cfg = config; | ||||
|     lfs->words = lfs->cfg->block_size / sizeof(uint32_t); | ||||
|  | ||||
|     lfs_dir_t dir; | ||||
|     lfs_superblock_t superblock; | ||||
|     err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||
|     int err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||
|     if (!err) { | ||||
|         err = lfs_bd_read(lfs, dir.pair[0], | ||||
|                 sizeof(dir.d), sizeof(superblock.d), &superblock.d); | ||||
| @@ -1186,7 +1111,7 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { | ||||
|  | ||||
|             dir.off += file.entry.d.len; | ||||
|             if ((0xf & file.entry.d.type) == LFS_TYPE_REG) { | ||||
|                 if (file.entry.d.u.file.size < lfs->block_size) { | ||||
|                 if (file.entry.d.u.file.size < lfs->cfg->block_size) { | ||||
|                     int err = cb(data, file.entry.d.u.file.head); | ||||
|                     if (err) { | ||||
|                         return err; | ||||
|   | ||||
							
								
								
									
										51
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -8,10 +8,9 @@ | ||||
| #define LFS_H | ||||
|  | ||||
| #include "lfs_config.h" | ||||
| #include "lfs_bd.h" | ||||
|  | ||||
|  | ||||
| // Data structures | ||||
| // The littefs constants | ||||
| enum lfs_error { | ||||
|     LFS_ERROR_OK       = 0, | ||||
|     LFS_ERROR_CORRUPT  = -3, | ||||
| @@ -41,23 +40,56 @@ enum lfs_open_flags { | ||||
| }; | ||||
|  | ||||
|  | ||||
| // Configuration provided during initialization of the littlefs | ||||
| struct lfs_config { | ||||
|     lfs_bd_t *bd; | ||||
|     const struct lfs_bd_ops *bd_ops; | ||||
|     // Opaque user provided context | ||||
|     void *context; | ||||
|  | ||||
|     // Read a region in a block | ||||
|     int (*read)(const struct lfs_config *c, lfs_block_t block, | ||||
|             lfs_off_t off, lfs_size_t size, void *buffer); | ||||
|  | ||||
|     // Program a region in a block. The block must have previously | ||||
|     // been erased. | ||||
|     int (*prog)(const struct lfs_config *c, lfs_block_t block, | ||||
|             lfs_off_t off, lfs_size_t size, const void *buffer); | ||||
|  | ||||
|     // Erase a block. A block must be erased before being programmed. | ||||
|     // The state of an erased block is undefined. | ||||
|     int (*erase)(const struct lfs_config *c, lfs_block_t block); | ||||
|  | ||||
|     // Sync the state of the underlying block device | ||||
|     int (*sync)(const struct lfs_config *c); | ||||
|  | ||||
|     // Minimum size of a read. This may be larger than the physical | ||||
|     // read size to cache reads from the block device. | ||||
|     lfs_size_t read_size; | ||||
|  | ||||
|     // Minimum size of a program. This may be larger than the physical | ||||
|     // program size to cache programs to the block device. | ||||
|     lfs_size_t prog_size; | ||||
|  | ||||
|     // Size of an erasable block. | ||||
|     lfs_size_t block_size; | ||||
|  | ||||
|     // Number of erasable blocks on the device. | ||||
|     lfs_size_t block_count; | ||||
| }; | ||||
|  | ||||
| // File info structure | ||||
| struct lfs_info { | ||||
|     // Type of the file, either REG or DIR | ||||
|     uint8_t type; | ||||
|  | ||||
|     // Size of the file, only valid for REG files | ||||
|     lfs_size_t size; | ||||
|  | ||||
|     // Name of the file stored as a null-terminated string | ||||
|     char name[LFS_NAME_MAX+1]; | ||||
| }; | ||||
|  | ||||
|  | ||||
| // Internal data structures | ||||
| typedef struct lfs_entry { | ||||
|     lfs_block_t pair[2]; | ||||
|     lfs_off_t off; | ||||
| @@ -115,17 +147,12 @@ typedef struct lfs_superblock { | ||||
|     } d; | ||||
| } lfs_superblock_t; | ||||
|  | ||||
|  | ||||
| // Little filesystem type | ||||
| typedef struct lfs { | ||||
|     lfs_size_t read_size;   // size of read | ||||
|     lfs_size_t prog_size;   // size of program | ||||
|     lfs_size_t block_size;  // size of erase (block size) | ||||
|     lfs_size_t block_count; // number of erasable blocks | ||||
|     const struct lfs_config *cfg; | ||||
|     lfs_size_t words;       // number of 32-bit words that can fit in a block | ||||
|  | ||||
|     lfs_bd_t *bd; | ||||
|     const struct lfs_bd_ops *bd_ops; | ||||
|  | ||||
|     lfs_block_t root[2]; | ||||
|     struct { | ||||
|         lfs_block_t begin; | ||||
| @@ -135,6 +162,7 @@ typedef struct lfs { | ||||
|     uint32_t lookahead[LFS_CFG_LOOKAHEAD/32]; | ||||
| } lfs_t; | ||||
|  | ||||
|  | ||||
| // Functions | ||||
| int lfs_format(lfs_t *lfs, const struct lfs_config *config); | ||||
| int lfs_mount(lfs_t *lfs, const struct lfs_config *config); | ||||
| @@ -160,4 +188,5 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | ||||
| int lfs_deorphan(lfs_t *lfs); | ||||
| int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										59
									
								
								lfs_bd.h
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								lfs_bd.h
									
									
									
									
									
								
							| @@ -1,59 +0,0 @@ | ||||
| /* | ||||
|  * Block device interface | ||||
|  * | ||||
|  * Copyright (c) 2017 Christopher Haster | ||||
|  * Distributed under the MIT license | ||||
|  */ | ||||
| #ifndef LFS_BD_H | ||||
| #define LFS_BD_H | ||||
|  | ||||
| #include "lfs_config.h" | ||||
|  | ||||
|  | ||||
| // Opaque type for block devices | ||||
| typedef void lfs_bd_t; | ||||
|  | ||||
| // Description of block devices | ||||
| struct lfs_bd_info { | ||||
|     lfs_size_t read_size;   // Size of readable block | ||||
|     lfs_size_t prog_size;   // Size of programmable block | ||||
|     lfs_size_t erase_size;  // Size of erase block | ||||
|  | ||||
|     uint64_t total_size; // Total size of the device | ||||
| }; | ||||
|  | ||||
| // Block device operations | ||||
| // | ||||
| // The little file system takes in a pointer to an opaque type | ||||
| // and this struct, all operations are passed the opaque pointer | ||||
| // which can be used to reference any state associated with the | ||||
| // block device | ||||
| struct lfs_bd_ops { | ||||
|     // Read a block | ||||
|     int (*read)(lfs_bd_t *bd, lfs_block_t block, | ||||
|             lfs_off_t off, lfs_size_t size, void *buffer); | ||||
|  | ||||
|     // Program a block | ||||
|     // | ||||
|     // The block must have previously been erased. | ||||
|     int (*prog)(lfs_bd_t *bd, lfs_block_t block, | ||||
|             lfs_off_t off, lfs_size_t size, const void *buffer); | ||||
|  | ||||
|     // Erase a block | ||||
|     // | ||||
|     // A block must be erased before being programmed. The | ||||
|     // state of an erased block is undefined. | ||||
|     int (*erase)(lfs_bd_t *bd, lfs_block_t block, | ||||
|             lfs_off_t off, lfs_size_t size); | ||||
|  | ||||
|     // Sync the block device | ||||
|     int (*sync)(lfs_bd_t *bd); | ||||
|  | ||||
|     // Get a description of the block device | ||||
|     // | ||||
|     // Any unknown information may be left as zero | ||||
|     int (*info)(lfs_bd_t *bd, struct lfs_bd_info *info); | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif | ||||
| @@ -7,12 +7,12 @@ import os | ||||
| import re | ||||
|  | ||||
| def main(): | ||||
|     with open('blocks/info') as file: | ||||
|         s = struct.unpack('<LLL4xQ', file.read()) | ||||
|     with open('blocks/config') as file: | ||||
|         s = struct.unpack('<LLLL', file.read()) | ||||
|         print 'read_size: %d' % s[0] | ||||
|         print 'prog_size: %d' % s[1] | ||||
|         print 'erase_size: %d' % s[2] | ||||
|         print 'total_size: %d' % s[3] | ||||
|         print 'block_size: %d' % s[2] | ||||
|         print 'block_size: %d' % s[3] | ||||
|  | ||||
|     print 'real_size: %d' % sum( | ||||
|         os.path.getsize(os.path.join('blocks', f)) | ||||
|   | ||||
| @@ -43,8 +43,6 @@ lfs_t lfs; | ||||
| lfs_emubd_t bd; | ||||
| lfs_file_t file[4]; | ||||
| lfs_dir_t dir[4]; | ||||
| struct lfs_bd_info bd_info; | ||||
| struct lfs_bd_stats bd_stats; | ||||
| struct lfs_info info; | ||||
|  | ||||
| uint8_t buffer[1024]; | ||||
| @@ -56,17 +54,41 @@ lfs_size_t rsize; | ||||
|  | ||||
| uintmax_t res; | ||||
|  | ||||
| const struct lfs_config config = {{ | ||||
|     .bd = &bd, | ||||
|     .bd_ops = &lfs_emubd_ops, | ||||
| #ifndef LFS_READ_SIZE | ||||
| #define LFS_READ_SIZE 1 | ||||
| #endif | ||||
|  | ||||
| #ifndef LFS_PROG_SIZE | ||||
| #define LFS_PROG_SIZE 1 | ||||
| #endif | ||||
|  | ||||
| #ifndef LFS_BLOCK_SIZE | ||||
| #define LFS_BLOCK_SIZE 512 | ||||
| #endif | ||||
|  | ||||
| #ifndef LFS_BLOCK_COUNT | ||||
| #define LFS_BLOCK_COUNT 1024 | ||||
| #endif | ||||
|  | ||||
| const struct lfs_config cfg = {{ | ||||
|     .context = &bd, | ||||
|     .read  = &lfs_emubd_read, | ||||
|     .prog  = &lfs_emubd_prog, | ||||
|     .erase = &lfs_emubd_erase, | ||||
|     .sync  = &lfs_emubd_sync, | ||||
|  | ||||
|     .read_size   = LFS_READ_SIZE, | ||||
|     .prog_size   = LFS_PROG_SIZE, | ||||
|     .block_size  = LFS_BLOCK_SIZE, | ||||
|     .block_count = LFS_BLOCK_COUNT, | ||||
| }}; | ||||
|  | ||||
|  | ||||
| // Entry point | ||||
| int main() {{ | ||||
|     lfs_emubd_create(&bd, "blocks"); | ||||
|     lfs_emubd_create(&cfg, "blocks"); | ||||
|  | ||||
| {tests} | ||||
|  | ||||
|     lfs_emubd_destroy(&bd); | ||||
|     lfs_emubd_destroy(&cfg); | ||||
| }} | ||||
|   | ||||
| @@ -4,14 +4,14 @@ set -eu | ||||
| echo "=== Allocator tests ===" | ||||
| rm -rf blocks | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| SIZE=15000 | ||||
|  | ||||
| lfs_mkdir() { | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "$1") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| @@ -19,7 +19,7 @@ TEST | ||||
|  | ||||
| lfs_remove() { | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_remove(&lfs, "$1/eggs") => 0; | ||||
|     lfs_remove(&lfs, "$1/bacon") => 0; | ||||
|     lfs_remove(&lfs, "$1/pancakes") => 0; | ||||
| @@ -31,7 +31,7 @@ TEST | ||||
| lfs_alloc_singleproc() { | ||||
| tests/test.py << TEST | ||||
|     const char *names[] = {"bacon", "eggs", "pancakes"}; | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||
|         sprintf((char*)buffer, "$1/%s", names[n]); | ||||
|         lfs_file_open(&lfs, &file[n], (char*)buffer, | ||||
| @@ -54,7 +54,7 @@ lfs_alloc_multiproc() { | ||||
| for name in bacon eggs pancakes | ||||
| do | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file[0], "$1/$name", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     size = strlen("$name"); | ||||
| @@ -72,7 +72,7 @@ lfs_verify() { | ||||
| for name in bacon eggs pancakes | ||||
| do | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file[0], "$1/$name", LFS_O_RDONLY) => 0; | ||||
|     size = strlen("$name"); | ||||
|     for (int i = 0; i < $SIZE; i++) { | ||||
|   | ||||
| @@ -6,12 +6,12 @@ LARGESIZE=128 | ||||
| echo "=== Directory tests ===" | ||||
| rm -rf blocks | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Root directory ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||
|     lfs_dir_close(&lfs, &dir[0]) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| @@ -19,14 +19,14 @@ TEST | ||||
|  | ||||
| echo "--- Directory creation ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "potato") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- File creation ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file[0], "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| @@ -34,7 +34,7 @@ TEST | ||||
|  | ||||
| echo "--- Directory iteration ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
| @@ -55,7 +55,7 @@ TEST | ||||
|  | ||||
| echo "--- Directory failures ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "potato") => LFS_ERROR_EXISTS; | ||||
|     lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERROR_NO_ENTRY; | ||||
|     lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERROR_NOT_DIR; | ||||
| @@ -66,14 +66,14 @@ TEST | ||||
|  | ||||
| echo "--- Nested directories ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "potato/baked") => 0; | ||||
|     lfs_mkdir(&lfs, "potato/sweet") => 0; | ||||
|     lfs_mkdir(&lfs, "potato/fried") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "potato") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
| @@ -97,7 +97,7 @@ TEST | ||||
|  | ||||
| echo "--- Multi-block directory ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "cactus") => 0; | ||||
|     for (int i = 0; i < $LARGESIZE; i++) { | ||||
|         sprintf((char*)buffer, "cactus/test%d", i); | ||||
| @@ -106,7 +106,7 @@ tests/test.py << TEST | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "cactus") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
| @@ -125,7 +125,7 @@ TEST | ||||
|  | ||||
| echo "--- Directory remove ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_remove(&lfs, "potato") => LFS_ERROR_INVALID; | ||||
|     lfs_remove(&lfs, "potato/sweet") => 0; | ||||
|     lfs_remove(&lfs, "potato/baked") => 0; | ||||
| @@ -161,7 +161,7 @@ tests/test.py << TEST | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
| @@ -182,7 +182,7 @@ TEST | ||||
|  | ||||
| echo "--- Directory rename ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "coldpotato") => 0; | ||||
|     lfs_mkdir(&lfs, "coldpotato/baked") => 0; | ||||
|     lfs_mkdir(&lfs, "coldpotato/sweet") => 0; | ||||
| @@ -190,12 +190,12 @@ tests/test.py << TEST | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "hotpotato") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
| @@ -217,7 +217,7 @@ tests/test.py << TEST | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "warmpotato") => 0; | ||||
|     lfs_mkdir(&lfs, "warmpotato/mushy") => 0; | ||||
|     lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERROR_INVALID; | ||||
| @@ -228,7 +228,7 @@ tests/test.py << TEST | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "warmpotato") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
| @@ -250,7 +250,7 @@ tests/test.py << TEST | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "coldpotato") => 0; | ||||
|     lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; | ||||
|     lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0; | ||||
| @@ -260,7 +260,7 @@ tests/test.py << TEST | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     strcmp(info.name, ".") => 0; | ||||
|   | ||||
| @@ -8,12 +8,12 @@ LARGESIZE=262144 | ||||
| echo "=== File tests ===" | ||||
| rm -rf blocks | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Simple file test ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file[0], "hello", LFS_O_RDWR | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||
|     size = strlen("Hello World!\n"); | ||||
|     memcpy(wbuffer, "Hello World!\n", size); | ||||
| @@ -29,7 +29,7 @@ tests/test.py << TEST | ||||
|     lfs_size_t size = $1; | ||||
|     lfs_size_t chunk = 31; | ||||
|     srand(0); | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file[0], "$2", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     for (lfs_size_t i = 0; i < size; i += chunk) { | ||||
|         chunk = (chunk < size - i) ? chunk : size - i; | ||||
| @@ -48,7 +48,7 @@ tests/test.py << TEST | ||||
|     lfs_size_t size = $1; | ||||
|     lfs_size_t chunk = 29; | ||||
|     srand(0); | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file[0], "$2", LFS_O_RDONLY) => 0; | ||||
|     for (lfs_size_t i = 0; i < size; i += chunk) { | ||||
|         chunk = (chunk < size - i) ? chunk : size - i; | ||||
| @@ -81,7 +81,7 @@ r_test $LARGESIZE largeavacado | ||||
|  | ||||
| echo "--- Dir check ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||
|   | ||||
| @@ -6,42 +6,42 @@ rm -rf blocks | ||||
|  | ||||
| echo "--- Basic formatting ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Invalid superblocks ---" | ||||
| ln -f -s /dev/null blocks/0 | ||||
| ln -f -s /dev/null blocks/1 | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => LFS_ERROR_CORRUPT; | ||||
|     lfs_format(&lfs, &cfg) => LFS_ERROR_CORRUPT; | ||||
| TEST | ||||
| rm blocks/0 blocks/1 | ||||
|  | ||||
| echo "--- Basic mounting ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Invalid mount ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
| rm blocks/0 blocks/1 | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => LFS_ERROR_CORRUPT; | ||||
|     lfs_mount(&lfs, &cfg) => LFS_ERROR_CORRUPT; | ||||
| TEST | ||||
|  | ||||
| echo "--- Valid corrupt mount ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
| rm blocks/0 | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
|  | ||||
|   | ||||
| @@ -4,12 +4,12 @@ set -eu | ||||
| echo "=== Orphan tests ===" | ||||
| rm -rf blocks | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| echo "--- Orphan test ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "parent") => 0; | ||||
|     lfs_mkdir(&lfs, "parent/orphan") => 0; | ||||
|     lfs_mkdir(&lfs, "parent/child") => 0; | ||||
| @@ -19,7 +19,7 @@ TEST | ||||
| # linked-list entry and should orphan the child | ||||
| rm -v blocks/8 | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERROR_NO_ENTRY; | ||||
|     unsigned before = 0; | ||||
|     lfs_traverse(&lfs, test_count, &before) => 0; | ||||
|   | ||||
| @@ -4,11 +4,11 @@ set -eu | ||||
| echo "=== Path tests ===" | ||||
| rm -rf blocks | ||||
| tests/test.py << TEST | ||||
|     lfs_format(&lfs, &config) => 0; | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
| TEST | ||||
|  | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "tea") => 0; | ||||
|     lfs_mkdir(&lfs, "coffee") => 0; | ||||
|     lfs_mkdir(&lfs, "soda") => 0; | ||||
| @@ -26,7 +26,7 @@ TEST | ||||
|  | ||||
| echo "--- Root path tests ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; | ||||
| @@ -36,7 +36,7 @@ TEST | ||||
|  | ||||
| echo "--- Redundant slash path tests ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs_stat(&lfs, "//tea//hottea", &info) => 0; | ||||
| @@ -48,7 +48,7 @@ TEST | ||||
|  | ||||
| echo "--- Dot path tests ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "./tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs_stat(&lfs, "/./tea/hottea", &info) => 0; | ||||
| @@ -62,7 +62,7 @@ TEST | ||||
|  | ||||
| echo "--- Dot dot path tests ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; | ||||
| @@ -76,7 +76,7 @@ TEST | ||||
|  | ||||
| echo "--- Root dot dot path tests ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &config) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; | ||||
|     strcmp(info.name, "hottea") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user