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 | // Block device emulated on existing filesystem | ||||||
| int lfs_emubd_create(lfs_emubd_t *emu, const char *path) { | int lfs_emubd_create(const struct lfs_config *cfg, const char *path) { | ||||||
|     memset(&emu->info, 0, sizeof(emu->info)); |     lfs_emubd_t *emu = cfg->context; | ||||||
|     memset(&emu->stats, 0, sizeof(emu->stats)); |     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 |     // Allocate buffer for creating children files | ||||||
|     size_t pathlen = strlen(path); |     size_t pathlen = strlen(path); | ||||||
| @@ -41,12 +44,6 @@ int lfs_emubd_create(lfs_emubd_t *emu, const char *path) { | |||||||
|         return -errno; |         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 |     // Load stats to continue incrementing | ||||||
|     snprintf(emu->child, LFS_NAME_MAX, "stats"); |     snprintf(emu->child, LFS_NAME_MAX, "stats"); | ||||||
|     FILE *f = fopen(emu->path, "r"); |     FILE *f = fopen(emu->path, "r"); | ||||||
| @@ -67,92 +64,42 @@ int lfs_emubd_create(lfs_emubd_t *emu, const char *path) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| void lfs_emubd_destroy(lfs_emubd_t *emu) { | void lfs_emubd_destroy(const struct lfs_config *cfg) { | ||||||
|     lfs_emubd_sync(emu); |     lfs_emubd_sync(cfg); | ||||||
|  |  | ||||||
|  |     lfs_emubd_t *emu = cfg->context; | ||||||
|     free(emu->path); |     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_off_t off, lfs_size_t size, void *buffer) { | ||||||
|  |     lfs_emubd_t *emu = cfg->context; | ||||||
|     uint8_t *data = buffer; |     uint8_t *data = buffer; | ||||||
|  |  | ||||||
|     // Check if read is valid |     // Check if read is valid | ||||||
|     assert(off % emu->info.read_size == 0); |     assert(off  % cfg->read_size == 0); | ||||||
|     assert(size % emu->info.read_size == 0); |     assert(size % cfg->read_size == 0); | ||||||
|     assert((uint64_t)block*emu->info.erase_size + off + size |     assert(block < cfg->block_count); | ||||||
|             < emu->info.total_size); |  | ||||||
|  |  | ||||||
|     // Zero out buffer for debugging |     // Zero out buffer for debugging | ||||||
|     memset(data, 0, size); |     memset(data, 0, size); | ||||||
|  |  | ||||||
|     // Iterate over blocks until enough data is read |     // Read data | ||||||
|     while (size > 0) { |     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||||
|         snprintf(emu->child, LFS_NAME_MAX, "%x", block); |  | ||||||
|         size_t count = lfs_min(emu->info.erase_size - off, size); |  | ||||||
|  |  | ||||||
|         FILE *f = fopen(emu->path, "rb"); |     FILE *f = fopen(emu->path, "rb"); | ||||||
|         if (!f && errno != ENOENT) { |     if (!f && errno != ENOENT) { | ||||||
|             return -errno; |         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; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     emu->stats.read_count += 1; |     if (f) { | ||||||
|     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; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         int err = fseek(f, off, SEEK_SET); |         int err = fseek(f, off, SEEK_SET); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return -errno; |             return -errno; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         size_t res = fwrite(data, 1, count, f); |         size_t res = fread(data, 1, size, f); | ||||||
|         if (res < count) { |         if (res < size && !feof(f)) { | ||||||
|             return -errno; |             return -errno; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -160,60 +107,88 @@ int lfs_emubd_prog(lfs_emubd_t *emu, lfs_block_t block, | |||||||
|         if (err) { |         if (err) { | ||||||
|             return -errno; |             return -errno; | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|         size -= count; |     emu->stats.read_count += 1; | ||||||
|         data += count; |     return 0; | ||||||
|         block += 1; | } | ||||||
|         off = 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; |     emu->stats.prog_count += 1; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_emubd_erase(lfs_emubd_t *emu, lfs_block_t block, | int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) { | ||||||
|         lfs_off_t off, lfs_size_t size) { |     lfs_emubd_t *emu = cfg->context; | ||||||
|  |  | ||||||
|     // Check if erase is valid |     // Check if erase is valid | ||||||
|     assert(off % emu->info.erase_size == 0); |     assert(block < cfg->block_count); | ||||||
|     assert(size % emu->info.erase_size == 0); |  | ||||||
|     assert((uint64_t)block*emu->info.erase_size + off + size |  | ||||||
|             < emu->info.total_size); |  | ||||||
|  |  | ||||||
|     // Iterate and erase blocks |     // Erase the block | ||||||
|     while (size > 0) { |     snprintf(emu->child, LFS_NAME_MAX, "%x", block); | ||||||
|         snprintf(emu->child, LFS_NAME_MAX, "%x", block); |     struct stat st; | ||||||
|         struct stat st; |     int err = stat(emu->path, &st); | ||||||
|         int err = stat(emu->path, &st); |     if (err && errno != ENOENT) { | ||||||
|         if (err && errno != ENOENT) { |         return -errno; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!err && S_ISREG(st.st_mode)) { | ||||||
|  |         int err = unlink(emu->path); | ||||||
|  |         if (err) { | ||||||
|             return -errno; |             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; |     emu->stats.erase_count += 1; | ||||||
|     return 0; |     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 |     // 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"); |     FILE *f = fopen(emu->path, "w"); | ||||||
|     if (!f) { |     if (!f) { | ||||||
|         return -errno; |         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) { |     if (res < 1) { | ||||||
|         return -errno; |         return -errno; | ||||||
|     } |     } | ||||||
| @@ -242,46 +217,3 @@ int lfs_emubd_sync(lfs_emubd_t *emu) { | |||||||
|     return 0; |     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 | #ifndef LFS_EMUBD_H | ||||||
| #define LFS_EMUBD_H | #define LFS_EMUBD_H | ||||||
|  |  | ||||||
| #include "lfs_config.h" | #include "lfs.h" | ||||||
| #include "lfs_util.h" | #include "lfs_util.h" | ||||||
| #include "lfs_bd.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // Config options | // Config options | ||||||
| @@ -30,60 +29,50 @@ | |||||||
| #endif | #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 | // The emu bd state | ||||||
| typedef struct lfs_emubd { | typedef struct lfs_emubd { | ||||||
|     char *path; |     char *path; | ||||||
|     char *child; |     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; | } lfs_emubd_t; | ||||||
|  |  | ||||||
|  |  | ||||||
| // Create a block device using path for the directory to store blocks | // 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 | // 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 | // 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); |         lfs_off_t off, lfs_size_t size, void *buffer); | ||||||
|  |  | ||||||
| // Program a block | // Program a block | ||||||
| // | // | ||||||
| // The block must have previously been erased. | // 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); |         lfs_off_t off, lfs_size_t size, const void *buffer); | ||||||
|  |  | ||||||
| // Erase a block | // Erase a block | ||||||
| // | // | ||||||
| // A block must be erased before being programmed. The | // A block must be erased before being programmed. The | ||||||
| // state of an erased block is undefined. | // state of an erased block is undefined. | ||||||
| int lfs_emubd_erase(lfs_emubd_t *bd, lfs_block_t block, | int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block); | ||||||
|         lfs_off_t off, lfs_size_t size); |  | ||||||
|  |  | ||||||
| // Sync the block device | // Sync the block device | ||||||
| int lfs_emubd_sync(lfs_emubd_t *bd); | int lfs_emubd_sync(const struct lfs_config *cfg); | ||||||
|  |  | ||||||
| // 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; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										141
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -12,27 +12,22 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| /// Block device operations /// | /// 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, | static int lfs_bd_read(lfs_t *lfs, lfs_block_t block, | ||||||
|         lfs_off_t off, lfs_size_t size, void *buffer) { |         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, | static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block, | ||||||
|         lfs_off_t off, lfs_size_t size, const void *buffer) { |         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, | static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { | ||||||
|         lfs_off_t off, lfs_size_t size) { |     return lfs->cfg->erase(lfs->cfg, block); | ||||||
|     return lfs->bd_ops->erase(lfs->bd, block, off, size); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_bd_sync(lfs_t *lfs) { | 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, | 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 |             // found free block, now find stride of free blocks | ||||||
|             // since this is relatively cheap (stress on relatively) |             // since this is relatively cheap (stress on relatively) | ||||||
|             lfs->free.begin += off; |             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 |             // find maximum stride in tree | ||||||
|             return lfs_traverse(lfs, lfs_alloc_stride, lfs); |             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 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) { | static lfs_off_t lfs_indexfrom(lfs_t *lfs, lfs_off_t off) { | ||||||
|     lfs_off_t i = 0; |     lfs_off_t i = 0; | ||||||
|     while (off > lfs->block_size) { |     while (off > lfs->cfg->block_size) { | ||||||
|         i = lfs_indexnext(lfs, i); |         i = lfs_indexnext(lfs, i); | ||||||
|         off -= lfs->block_size; |         off -= lfs->cfg->block_size; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return i; |     return i; | ||||||
| @@ -370,7 +365,7 @@ static int lfs_dir_fetch(lfs_t *lfs, | |||||||
|         uint32_t crc = 0xffffffff; |         uint32_t crc = 0xffffffff; | ||||||
|         crc = lfs_crc(crc, sizeof(test), &test); |         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; |             uint32_t word; | ||||||
|             int err = lfs_bd_read(lfs, tpair[i], j, 4, &word); |             int err = lfs_bd_read(lfs, tpair[i], j, 4, &word); | ||||||
|             if (err) { |             if (err) { | ||||||
| @@ -406,7 +401,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | |||||||
|     dir->d.rev += 1; |     dir->d.rev += 1; | ||||||
|     lfs_pairswap(dir->pair); |     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) { |     if (err) { | ||||||
|         return 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; |         uint8_t data; | ||||||
|         int err = lfs_bd_read(lfs, dir->pair[0], off, 1, &data); |         int err = lfs_bd_read(lfs, dir->pair[0], off, 1, &data); | ||||||
|         if (err) { |         if (err) { | ||||||
| @@ -467,7 +462,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | |||||||
|         off += 1; |         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) { |     if (err) { | ||||||
|         return 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; |     dir->d.size -= entry->d.len; | ||||||
|     lfs_pairswap(dir->pair); |     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) { |     if (err) { | ||||||
|         return 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; |         uint8_t data; | ||||||
|         int err = lfs_bd_read(lfs, dir->pair[0], woff, 1, &data); |         int err = lfs_bd_read(lfs, dir->pair[0], woff, 1, &data); | ||||||
|         if (err) { |         if (err) { | ||||||
| @@ -527,7 +522,7 @@ static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | |||||||
|         woff += 1; |         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) { |     if (err) { | ||||||
|         return 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) { |         lfs_entry_t *entry, const void *data) { | ||||||
|     // check if we fit, if top bit is set we do not and move on |     // check if we fit, if top bit is set we do not and move on | ||||||
|     while (true) { |     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[0] = dir->pair[0]; | ||||||
|             entry->pair[1] = dir->pair[1]; |             entry->pair[1] = dir->pair[1]; | ||||||
|             entry->off = dir->d.size; |             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 do this lazily in write? | ||||||
|     // TODO cow the head i/d block |     // TODO cow the head i/d block | ||||||
|     if (file->size < lfs->block_size) { |     if (file->size < lfs->cfg->block_size) { | ||||||
|         file->wblock = file->head; |         file->wblock = file->head; | ||||||
|     } else { |     } else { | ||||||
|         int err = lfs_index_find(lfs, file->head, file->windex, |         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; |     lfs_size_t nsize = size; | ||||||
|  |  | ||||||
|     while (nsize > 0) { |     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) { |         if (file->size == 0) { | ||||||
|             int err = lfs_alloc_erased(lfs, &file->wblock); |             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); |         int err = lfs_bd_prog(lfs, file->wblock, woff, diff, data); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return 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; |     lfs_size_t nsize = size; | ||||||
|  |  | ||||||
|     while (nsize > 0 && file->roff < file->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 |         // TODO cache index blocks | ||||||
|         if (file->size < lfs->block_size) { |         if (file->size < lfs->cfg->block_size) { | ||||||
|             file->rblock = file->head; |             file->rblock = file->head; | ||||||
|         } else if (roff == 0) { |         } else if (roff == 0) { | ||||||
|             int err = lfs_index_find(lfs, file->head, file->windex, |             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_size_t diff = lfs_min( | ||||||
|                 lfs_min(nsize, file->size-file->roff), |                 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); |         int err = lfs_bd_read(lfs, file->rblock, roff, diff, data); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -991,85 +986,17 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, | |||||||
|  |  | ||||||
|  |  | ||||||
| /// Generic filesystem operations /// | /// 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 lfs_format(lfs_t *lfs, const struct lfs_config *config) { | ||||||
|     int err = lfs_configure(lfs, config); |     lfs->cfg = config; | ||||||
|     if (err) { |     lfs->words = lfs->cfg->block_size / sizeof(uint32_t); | ||||||
|         return err; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Create free list |     // Create free list | ||||||
|     lfs->free.begin = 0; |     lfs->free.begin = 0; | ||||||
|     lfs->free.end = lfs->block_count-1; |     lfs->free.end = lfs->cfg->block_count-1; | ||||||
|  |  | ||||||
|     // Create superblock dir |     // Create superblock dir | ||||||
|     lfs_dir_t superdir; |     lfs_dir_t superdir; | ||||||
|     err = lfs_dir_alloc(lfs, &superdir); |     int err = lfs_dir_alloc(lfs, &superdir); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -1096,8 +1023,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config) { | |||||||
|         .d.len = sizeof(superblock.d), |         .d.len = sizeof(superblock.d), | ||||||
|         .d.version = 0x00000001, |         .d.version = 0x00000001, | ||||||
|         .d.magic = {"littlefs"}, |         .d.magic = {"littlefs"}, | ||||||
|         .d.block_size  = lfs->block_size, |         .d.block_size  = lfs->cfg->block_size, | ||||||
|         .d.block_count = lfs->block_count, |         .d.block_count = lfs->cfg->block_count, | ||||||
|         .d.root = {lfs->root[0], lfs->root[1]}, |         .d.root = {lfs->root[0], lfs->root[1]}, | ||||||
|     }; |     }; | ||||||
|     superdir.d.tail[0] = root.pair[0]; |     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 lfs_mount(lfs_t *lfs, const struct lfs_config *config) { | ||||||
|     int err = lfs_configure(lfs, config); |     lfs->cfg = config; | ||||||
|     if (err) { |     lfs->words = lfs->cfg->block_size / sizeof(uint32_t); | ||||||
|         return err; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_dir_t dir; |     lfs_dir_t dir; | ||||||
|     lfs_superblock_t superblock; |     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) { |     if (!err) { | ||||||
|         err = lfs_bd_read(lfs, dir.pair[0], |         err = lfs_bd_read(lfs, dir.pair[0], | ||||||
|                 sizeof(dir.d), sizeof(superblock.d), &superblock.d); |                 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; |             dir.off += file.entry.d.len; | ||||||
|             if ((0xf & file.entry.d.type) == LFS_TYPE_REG) { |             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); |                     int err = cb(data, file.entry.d.u.file.head); | ||||||
|                     if (err) { |                     if (err) { | ||||||
|                         return err; |                         return err; | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -8,10 +8,9 @@ | |||||||
| #define LFS_H | #define LFS_H | ||||||
|  |  | ||||||
| #include "lfs_config.h" | #include "lfs_config.h" | ||||||
| #include "lfs_bd.h" |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // Data structures | // The littefs constants | ||||||
| enum lfs_error { | enum lfs_error { | ||||||
|     LFS_ERROR_OK       = 0, |     LFS_ERROR_OK       = 0, | ||||||
|     LFS_ERROR_CORRUPT  = -3, |     LFS_ERROR_CORRUPT  = -3, | ||||||
| @@ -41,23 +40,56 @@ enum lfs_open_flags { | |||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Configuration provided during initialization of the littlefs | ||||||
| struct lfs_config { | struct lfs_config { | ||||||
|     lfs_bd_t *bd; |     // Opaque user provided context | ||||||
|     const struct lfs_bd_ops *bd_ops; |     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; |     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; |     lfs_size_t prog_size; | ||||||
|  |  | ||||||
|  |     // Size of an erasable block. | ||||||
|     lfs_size_t block_size; |     lfs_size_t block_size; | ||||||
|  |  | ||||||
|  |     // Number of erasable blocks on the device. | ||||||
|     lfs_size_t block_count; |     lfs_size_t block_count; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | // File info structure | ||||||
| struct lfs_info { | struct lfs_info { | ||||||
|  |     // Type of the file, either REG or DIR | ||||||
|     uint8_t type; |     uint8_t type; | ||||||
|  |  | ||||||
|  |     // Size of the file, only valid for REG files | ||||||
|     lfs_size_t size; |     lfs_size_t size; | ||||||
|  |  | ||||||
|  |     // Name of the file stored as a null-terminated string | ||||||
|     char name[LFS_NAME_MAX+1]; |     char name[LFS_NAME_MAX+1]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Internal data structures | ||||||
| typedef struct lfs_entry { | typedef struct lfs_entry { | ||||||
|     lfs_block_t pair[2]; |     lfs_block_t pair[2]; | ||||||
|     lfs_off_t off; |     lfs_off_t off; | ||||||
| @@ -115,17 +147,12 @@ typedef struct lfs_superblock { | |||||||
|     } d; |     } d; | ||||||
| } lfs_superblock_t; | } lfs_superblock_t; | ||||||
|  |  | ||||||
|  |  | ||||||
| // Little filesystem type | // Little filesystem type | ||||||
| typedef struct lfs { | typedef struct lfs { | ||||||
|     lfs_size_t read_size;   // size of read |     const struct lfs_config *cfg; | ||||||
|     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 |  | ||||||
|     lfs_size_t words;       // number of 32-bit words that can fit in a block |     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]; |     lfs_block_t root[2]; | ||||||
|     struct { |     struct { | ||||||
|         lfs_block_t begin; |         lfs_block_t begin; | ||||||
| @@ -135,6 +162,7 @@ typedef struct lfs { | |||||||
|     uint32_t lookahead[LFS_CFG_LOOKAHEAD/32]; |     uint32_t lookahead[LFS_CFG_LOOKAHEAD/32]; | ||||||
| } lfs_t; | } lfs_t; | ||||||
|  |  | ||||||
|  |  | ||||||
| // Functions | // Functions | ||||||
| int lfs_format(lfs_t *lfs, const struct lfs_config *config); | int lfs_format(lfs_t *lfs, const struct lfs_config *config); | ||||||
| int lfs_mount(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_deorphan(lfs_t *lfs); | ||||||
| int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); | int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif | #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 | import re | ||||||
|  |  | ||||||
| def main(): | def main(): | ||||||
|     with open('blocks/info') as file: |     with open('blocks/config') as file: | ||||||
|         s = struct.unpack('<LLL4xQ', file.read()) |         s = struct.unpack('<LLLL', file.read()) | ||||||
|         print 'read_size: %d' % s[0] |         print 'read_size: %d' % s[0] | ||||||
|         print 'prog_size: %d' % s[1] |         print 'prog_size: %d' % s[1] | ||||||
|         print 'erase_size: %d' % s[2] |         print 'block_size: %d' % s[2] | ||||||
|         print 'total_size: %d' % s[3] |         print 'block_size: %d' % s[3] | ||||||
|  |  | ||||||
|     print 'real_size: %d' % sum( |     print 'real_size: %d' % sum( | ||||||
|         os.path.getsize(os.path.join('blocks', f)) |         os.path.getsize(os.path.join('blocks', f)) | ||||||
|   | |||||||
| @@ -43,8 +43,6 @@ lfs_t lfs; | |||||||
| lfs_emubd_t bd; | lfs_emubd_t bd; | ||||||
| lfs_file_t file[4]; | lfs_file_t file[4]; | ||||||
| lfs_dir_t dir[4]; | lfs_dir_t dir[4]; | ||||||
| struct lfs_bd_info bd_info; |  | ||||||
| struct lfs_bd_stats bd_stats; |  | ||||||
| struct lfs_info info; | struct lfs_info info; | ||||||
|  |  | ||||||
| uint8_t buffer[1024]; | uint8_t buffer[1024]; | ||||||
| @@ -56,17 +54,41 @@ lfs_size_t rsize; | |||||||
|  |  | ||||||
| uintmax_t res; | uintmax_t res; | ||||||
|  |  | ||||||
| const struct lfs_config config = {{ | #ifndef LFS_READ_SIZE | ||||||
|     .bd = &bd, | #define LFS_READ_SIZE 1 | ||||||
|     .bd_ops = &lfs_emubd_ops, | #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 | // Entry point | ||||||
| int main() {{ | int main() {{ | ||||||
|     lfs_emubd_create(&bd, "blocks"); |     lfs_emubd_create(&cfg, "blocks"); | ||||||
|  |  | ||||||
| {tests} | {tests} | ||||||
|  |  | ||||||
|     lfs_emubd_destroy(&bd); |     lfs_emubd_destroy(&cfg); | ||||||
| }} | }} | ||||||
|   | |||||||
| @@ -4,14 +4,14 @@ set -eu | |||||||
| echo "=== Allocator tests ===" | echo "=== Allocator tests ===" | ||||||
| rm -rf blocks | rm -rf blocks | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| SIZE=15000 | SIZE=15000 | ||||||
|  |  | ||||||
| lfs_mkdir() { | lfs_mkdir() { | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "$1") => 0; |     lfs_mkdir(&lfs, "$1") => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| @@ -19,7 +19,7 @@ TEST | |||||||
|  |  | ||||||
| lfs_remove() { | lfs_remove() { | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_remove(&lfs, "$1/eggs") => 0; |     lfs_remove(&lfs, "$1/eggs") => 0; | ||||||
|     lfs_remove(&lfs, "$1/bacon") => 0; |     lfs_remove(&lfs, "$1/bacon") => 0; | ||||||
|     lfs_remove(&lfs, "$1/pancakes") => 0; |     lfs_remove(&lfs, "$1/pancakes") => 0; | ||||||
| @@ -31,7 +31,7 @@ TEST | |||||||
| lfs_alloc_singleproc() { | lfs_alloc_singleproc() { | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     const char *names[] = {"bacon", "eggs", "pancakes"}; |     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++) { |     for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) { | ||||||
|         sprintf((char*)buffer, "$1/%s", names[n]); |         sprintf((char*)buffer, "$1/%s", names[n]); | ||||||
|         lfs_file_open(&lfs, &file[n], (char*)buffer, |         lfs_file_open(&lfs, &file[n], (char*)buffer, | ||||||
| @@ -54,7 +54,7 @@ lfs_alloc_multiproc() { | |||||||
| for name in bacon eggs pancakes | for name in bacon eggs pancakes | ||||||
| do | do | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_file_open(&lfs, &file[0], "$1/$name", |     lfs_file_open(&lfs, &file[0], "$1/$name", | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; |             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||||
|     size = strlen("$name"); |     size = strlen("$name"); | ||||||
| @@ -72,7 +72,7 @@ lfs_verify() { | |||||||
| for name in bacon eggs pancakes | for name in bacon eggs pancakes | ||||||
| do | do | ||||||
| tests/test.py << TEST | 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; |     lfs_file_open(&lfs, &file[0], "$1/$name", LFS_O_RDONLY) => 0; | ||||||
|     size = strlen("$name"); |     size = strlen("$name"); | ||||||
|     for (int i = 0; i < $SIZE; i++) { |     for (int i = 0; i < $SIZE; i++) { | ||||||
|   | |||||||
| @@ -6,12 +6,12 @@ LARGESIZE=128 | |||||||
| echo "=== Directory tests ===" | echo "=== Directory tests ===" | ||||||
| rm -rf blocks | rm -rf blocks | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Root directory ---" | echo "--- Root directory ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; |     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||||
|     lfs_dir_close(&lfs, &dir[0]) => 0; |     lfs_dir_close(&lfs, &dir[0]) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| @@ -19,14 +19,14 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Directory creation ---" | echo "--- Directory creation ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "potato") => 0; |     lfs_mkdir(&lfs, "potato") => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- File creation ---" | echo "--- File creation ---" | ||||||
| tests/test.py << TEST | 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_open(&lfs, &file[0], "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0; | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| @@ -34,7 +34,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Directory iteration ---" | echo "--- Directory iteration ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; |     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     strcmp(info.name, ".") => 0; |     strcmp(info.name, ".") => 0; | ||||||
| @@ -55,7 +55,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Directory failures ---" | echo "--- Directory failures ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "potato") => LFS_ERROR_EXISTS; |     lfs_mkdir(&lfs, "potato") => LFS_ERROR_EXISTS; | ||||||
|     lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERROR_NO_ENTRY; |     lfs_dir_open(&lfs, &dir[0], "tomato") => LFS_ERROR_NO_ENTRY; | ||||||
|     lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERROR_NOT_DIR; |     lfs_dir_open(&lfs, &dir[0], "burito") => LFS_ERROR_NOT_DIR; | ||||||
| @@ -66,14 +66,14 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Nested directories ---" | echo "--- Nested directories ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "potato/baked") => 0; |     lfs_mkdir(&lfs, "potato/baked") => 0; | ||||||
|     lfs_mkdir(&lfs, "potato/sweet") => 0; |     lfs_mkdir(&lfs, "potato/sweet") => 0; | ||||||
|     lfs_mkdir(&lfs, "potato/fried") => 0; |     lfs_mkdir(&lfs, "potato/fried") => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << 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_open(&lfs, &dir[0], "potato") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     strcmp(info.name, ".") => 0; |     strcmp(info.name, ".") => 0; | ||||||
| @@ -97,7 +97,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Multi-block directory ---" | echo "--- Multi-block directory ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "cactus") => 0; |     lfs_mkdir(&lfs, "cactus") => 0; | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |     for (int i = 0; i < $LARGESIZE; i++) { | ||||||
|         sprintf((char*)buffer, "cactus/test%d", i); |         sprintf((char*)buffer, "cactus/test%d", i); | ||||||
| @@ -106,7 +106,7 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << 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_open(&lfs, &dir[0], "cactus") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     strcmp(info.name, ".") => 0; |     strcmp(info.name, ".") => 0; | ||||||
| @@ -125,7 +125,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Directory remove ---" | echo "--- Directory remove ---" | ||||||
| tests/test.py << TEST | 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") => LFS_ERROR_INVALID; | ||||||
|     lfs_remove(&lfs, "potato/sweet") => 0; |     lfs_remove(&lfs, "potato/sweet") => 0; | ||||||
|     lfs_remove(&lfs, "potato/baked") => 0; |     lfs_remove(&lfs, "potato/baked") => 0; | ||||||
| @@ -161,7 +161,7 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; |     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     strcmp(info.name, ".") => 0; |     strcmp(info.name, ".") => 0; | ||||||
| @@ -182,7 +182,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Directory rename ---" | echo "--- Directory rename ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "coldpotato") => 0; |     lfs_mkdir(&lfs, "coldpotato") => 0; | ||||||
|     lfs_mkdir(&lfs, "coldpotato/baked") => 0; |     lfs_mkdir(&lfs, "coldpotato/baked") => 0; | ||||||
|     lfs_mkdir(&lfs, "coldpotato/sweet") => 0; |     lfs_mkdir(&lfs, "coldpotato/sweet") => 0; | ||||||
| @@ -190,12 +190,12 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; |     lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << 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_open(&lfs, &dir[0], "hotpotato") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     strcmp(info.name, ".") => 0; |     strcmp(info.name, ".") => 0; | ||||||
| @@ -217,7 +217,7 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "warmpotato") => 0; |     lfs_mkdir(&lfs, "warmpotato") => 0; | ||||||
|     lfs_mkdir(&lfs, "warmpotato/mushy") => 0; |     lfs_mkdir(&lfs, "warmpotato/mushy") => 0; | ||||||
|     lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERROR_INVALID; |     lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERROR_INVALID; | ||||||
| @@ -228,7 +228,7 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << 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_open(&lfs, &dir[0], "warmpotato") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     strcmp(info.name, ".") => 0; |     strcmp(info.name, ".") => 0; | ||||||
| @@ -250,7 +250,7 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "coldpotato") => 0; |     lfs_mkdir(&lfs, "coldpotato") => 0; | ||||||
|     lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; |     lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; | ||||||
|     lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0; |     lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0; | ||||||
| @@ -260,7 +260,7 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << 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_open(&lfs, &dir[0], "coldpotato") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     strcmp(info.name, ".") => 0; |     strcmp(info.name, ".") => 0; | ||||||
|   | |||||||
| @@ -8,12 +8,12 @@ LARGESIZE=262144 | |||||||
| echo "=== File tests ===" | echo "=== File tests ===" | ||||||
| rm -rf blocks | rm -rf blocks | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Simple file test ---" | echo "--- Simple file test ---" | ||||||
| tests/test.py << 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; |     lfs_file_open(&lfs, &file[0], "hello", LFS_O_RDWR | LFS_O_CREAT | LFS_O_APPEND) => 0; | ||||||
|     size = strlen("Hello World!\n"); |     size = strlen("Hello World!\n"); | ||||||
|     memcpy(wbuffer, "Hello World!\n", size); |     memcpy(wbuffer, "Hello World!\n", size); | ||||||
| @@ -29,7 +29,7 @@ tests/test.py << TEST | |||||||
|     lfs_size_t size = $1; |     lfs_size_t size = $1; | ||||||
|     lfs_size_t chunk = 31; |     lfs_size_t chunk = 31; | ||||||
|     srand(0); |     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; |     lfs_file_open(&lfs, &file[0], "$2", LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||||
|     for (lfs_size_t i = 0; i < size; i += chunk) { |     for (lfs_size_t i = 0; i < size; i += chunk) { | ||||||
|         chunk = (chunk < size - i) ? chunk : size - i; |         chunk = (chunk < size - i) ? chunk : size - i; | ||||||
| @@ -48,7 +48,7 @@ tests/test.py << TEST | |||||||
|     lfs_size_t size = $1; |     lfs_size_t size = $1; | ||||||
|     lfs_size_t chunk = 29; |     lfs_size_t chunk = 29; | ||||||
|     srand(0); |     srand(0); | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_file_open(&lfs, &file[0], "$2", LFS_O_RDONLY) => 0; |     lfs_file_open(&lfs, &file[0], "$2", LFS_O_RDONLY) => 0; | ||||||
|     for (lfs_size_t i = 0; i < size; i += chunk) { |     for (lfs_size_t i = 0; i < size; i += chunk) { | ||||||
|         chunk = (chunk < size - i) ? chunk : size - i; |         chunk = (chunk < size - i) ? chunk : size - i; | ||||||
| @@ -81,7 +81,7 @@ r_test $LARGESIZE largeavacado | |||||||
|  |  | ||||||
| echo "--- Dir check ---" | echo "--- Dir check ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_dir_open(&lfs, &dir[0], "/") => 0; |     lfs_dir_open(&lfs, &dir[0], "/") => 0; | ||||||
|     lfs_dir_read(&lfs, &dir[0], &info) => 1; |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|     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 ---" | echo "--- Basic formatting ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Invalid superblocks ---" | echo "--- Invalid superblocks ---" | ||||||
| ln -f -s /dev/null blocks/0 | ln -f -s /dev/null blocks/0 | ||||||
| ln -f -s /dev/null blocks/1 | ln -f -s /dev/null blocks/1 | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => LFS_ERROR_CORRUPT; |     lfs_format(&lfs, &cfg) => LFS_ERROR_CORRUPT; | ||||||
| TEST | TEST | ||||||
| rm blocks/0 blocks/1 | rm blocks/0 blocks/1 | ||||||
|  |  | ||||||
| echo "--- Basic mounting ---" | echo "--- Basic mounting ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Invalid mount ---" | echo "--- Invalid mount ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
| rm blocks/0 blocks/1 | rm blocks/0 blocks/1 | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => LFS_ERROR_CORRUPT; |     lfs_mount(&lfs, &cfg) => LFS_ERROR_CORRUPT; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Valid corrupt mount ---" | echo "--- Valid corrupt mount ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
| rm blocks/0 | rm blocks/0 | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,12 +4,12 @@ set -eu | |||||||
| echo "=== Orphan tests ===" | echo "=== Orphan tests ===" | ||||||
| rm -rf blocks | rm -rf blocks | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Orphan test ---" | echo "--- Orphan test ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "parent") => 0; |     lfs_mkdir(&lfs, "parent") => 0; | ||||||
|     lfs_mkdir(&lfs, "parent/orphan") => 0; |     lfs_mkdir(&lfs, "parent/orphan") => 0; | ||||||
|     lfs_mkdir(&lfs, "parent/child") => 0; |     lfs_mkdir(&lfs, "parent/child") => 0; | ||||||
| @@ -19,7 +19,7 @@ TEST | |||||||
| # linked-list entry and should orphan the child | # linked-list entry and should orphan the child | ||||||
| rm -v blocks/8 | rm -v blocks/8 | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERROR_NO_ENTRY; |     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERROR_NO_ENTRY; | ||||||
|     unsigned before = 0; |     unsigned before = 0; | ||||||
|     lfs_traverse(&lfs, test_count, &before) => 0; |     lfs_traverse(&lfs, test_count, &before) => 0; | ||||||
|   | |||||||
| @@ -4,11 +4,11 @@ set -eu | |||||||
| echo "=== Path tests ===" | echo "=== Path tests ===" | ||||||
| rm -rf blocks | rm -rf blocks | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_format(&lfs, &config) => 0; |     lfs_format(&lfs, &cfg) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_mkdir(&lfs, "tea") => 0; |     lfs_mkdir(&lfs, "tea") => 0; | ||||||
|     lfs_mkdir(&lfs, "coffee") => 0; |     lfs_mkdir(&lfs, "coffee") => 0; | ||||||
|     lfs_mkdir(&lfs, "soda") => 0; |     lfs_mkdir(&lfs, "soda") => 0; | ||||||
| @@ -26,7 +26,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Root path tests ---" | echo "--- Root path tests ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_stat(&lfs, "tea/hottea", &info) => 0; |     lfs_stat(&lfs, "tea/hottea", &info) => 0; | ||||||
|     strcmp(info.name, "hottea") => 0; |     strcmp(info.name, "hottea") => 0; | ||||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; |     lfs_stat(&lfs, "/tea/hottea", &info) => 0; | ||||||
| @@ -36,7 +36,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Redundant slash path tests ---" | echo "--- Redundant slash path tests ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; |     lfs_stat(&lfs, "/tea/hottea", &info) => 0; | ||||||
|     strcmp(info.name, "hottea") => 0; |     strcmp(info.name, "hottea") => 0; | ||||||
|     lfs_stat(&lfs, "//tea//hottea", &info) => 0; |     lfs_stat(&lfs, "//tea//hottea", &info) => 0; | ||||||
| @@ -48,7 +48,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Dot path tests ---" | echo "--- Dot path tests ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_stat(&lfs, "./tea/hottea", &info) => 0; |     lfs_stat(&lfs, "./tea/hottea", &info) => 0; | ||||||
|     strcmp(info.name, "hottea") => 0; |     strcmp(info.name, "hottea") => 0; | ||||||
|     lfs_stat(&lfs, "/./tea/hottea", &info) => 0; |     lfs_stat(&lfs, "/./tea/hottea", &info) => 0; | ||||||
| @@ -62,7 +62,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Dot dot path tests ---" | echo "--- Dot dot path tests ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; |     lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; | ||||||
|     strcmp(info.name, "hottea") => 0; |     strcmp(info.name, "hottea") => 0; | ||||||
|     lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; |     lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; | ||||||
| @@ -76,7 +76,7 @@ TEST | |||||||
|  |  | ||||||
| echo "--- Root dot dot path tests ---" | echo "--- Root dot dot path tests ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; |     lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; | ||||||
|     strcmp(info.name, "hottea") => 0; |     strcmp(info.name, "hottea") => 0; | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user