Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lfs_emubd.c Source File

lfs_emubd.c

00001 /*
00002  * Block device emulated on standard files
00003  *
00004  * Copyright (c) 2017, Arm Limited. All rights reserved.
00005  * SPDX-License-Identifier: BSD-3-Clause
00006  */
00007 #include "emubd/lfs_emubd.h"
00008 
00009 #include <errno.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <stdio.h>
00013 #include <limits.h>
00014 #include <dirent.h>
00015 #include <sys/stat.h>
00016 #include <unistd.h>
00017 #include <assert.h>
00018 #include <stdbool.h>
00019 #include <inttypes.h>
00020 
00021 
00022 // Block device emulated on existing filesystem
00023 int lfs_emubd_create(const struct lfs_config *cfg, const char *path) {
00024     lfs_emubd_t *emu = cfg->context;
00025     emu->cfg.read_size   = cfg->read_size;
00026     emu->cfg.prog_size   = cfg->prog_size;
00027     emu->cfg.block_size  = cfg->block_size;
00028     emu->cfg.block_count = cfg->block_count;
00029 
00030     // Allocate buffer for creating children files
00031     size_t pathlen = strlen(path);
00032     emu->path = malloc(pathlen + 1 + LFS_NAME_MAX + 1);
00033     if (!emu->path) {
00034         return -ENOMEM;
00035     }
00036 
00037     strcpy(emu->path, path);
00038     emu->path[pathlen] = '/';
00039     emu->child = &emu->path[pathlen+1];
00040     memset(emu->child, '\0', LFS_NAME_MAX+1);
00041 
00042     // Create directory if it doesn't exist
00043     int err = mkdir(path, 0777);
00044     if (err && errno != EEXIST) {
00045         return -errno;
00046     }
00047 
00048     // Load stats to continue incrementing
00049     snprintf(emu->child, LFS_NAME_MAX, "stats");
00050 
00051     FILE *f = fopen(emu->path, "r");
00052     if (!f && errno != ENOENT) {
00053         return -errno;
00054     }
00055 
00056     if (errno == ENOENT) {
00057         memset(&emu->stats, 0x0, sizeof(emu->stats));
00058     } else {
00059         size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f);
00060         if (res < 1) {
00061             return -errno;
00062         }
00063 
00064         err = fclose(f);
00065         if (err) {
00066             return -errno;
00067         }
00068     }
00069 
00070     return 0;
00071 }
00072 
00073 void lfs_emubd_destroy(const struct lfs_config *cfg) {
00074     lfs_emubd_sync(cfg);
00075 
00076     lfs_emubd_t *emu = cfg->context;
00077     free(emu->path);
00078 }
00079 
00080 int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
00081         lfs_off_t off, void *buffer, lfs_size_t size) {
00082     lfs_emubd_t *emu = cfg->context;
00083     uint8_t *data = buffer;
00084 
00085     // Check if read is valid
00086     assert(off  % cfg->read_size == 0);
00087     assert(size % cfg->read_size == 0);
00088     assert(block < cfg->block_count);
00089 
00090     // Zero out buffer for debugging
00091     memset(data, 0, size);
00092 
00093     // Read data
00094     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
00095 
00096     FILE *f = fopen(emu->path, "rb");
00097     if (!f && errno != ENOENT) {
00098         return -errno;
00099     }
00100 
00101     if (f) {
00102         int err = fseek(f, off, SEEK_SET);
00103         if (err) {
00104             return -errno;
00105         }
00106 
00107         size_t res = fread(data, 1, size, f);
00108         if (res < size && !feof(f)) {
00109             return -errno;
00110         }
00111 
00112         err = fclose(f);
00113         if (err) {
00114             return -errno;
00115         }
00116     }
00117 
00118     emu->stats.read_count += 1;
00119     return 0;
00120 }
00121 
00122 int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
00123         lfs_off_t off, const void *buffer, lfs_size_t size) {
00124     lfs_emubd_t *emu = cfg->context;
00125     const uint8_t *data = buffer;
00126 
00127     // Check if write is valid
00128     assert(off  % cfg->prog_size == 0);
00129     assert(size % cfg->prog_size == 0);
00130     assert(block < cfg->block_count);
00131 
00132     // Program data
00133     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
00134 
00135     FILE *f = fopen(emu->path, "r+b");
00136     if (!f) {
00137         return (errno == EACCES) ? 0 : -errno;
00138     }
00139 
00140     // Check that file was erased
00141     assert(f);
00142 
00143     int err = fseek(f, off, SEEK_SET);
00144     if (err) {
00145         return -errno;
00146     }
00147 
00148     size_t res = fwrite(data, 1, size, f);
00149     if (res < size) {
00150         return -errno;
00151     }
00152 
00153     err = fseek(f, off, SEEK_SET);
00154     if (err) {
00155         return -errno;
00156     }
00157 
00158     uint8_t dat;
00159     res = fread(&dat, 1, 1, f);
00160     if (res < 1) {
00161         return -errno;
00162     }
00163 
00164     err = fclose(f);
00165     if (err) {
00166         return -errno;
00167     }
00168 
00169     emu->stats.prog_count += 1;
00170     return 0;
00171 }
00172 
00173 int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
00174     lfs_emubd_t *emu = cfg->context;
00175 
00176     // Check if erase is valid
00177     assert(block < cfg->block_count);
00178 
00179     // Erase the block
00180     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
00181     struct stat st;
00182     int err = stat(emu->path, &st);
00183     if (err && errno != ENOENT) {
00184         return -errno;
00185     }
00186 
00187     if (!err && S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode)) {
00188         err = unlink(emu->path);
00189         if (err) {
00190             return -errno;
00191         }
00192     }
00193 
00194     if (err || (S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode))) {
00195         FILE *f = fopen(emu->path, "w");
00196         if (!f) {
00197             return -errno;
00198         }
00199 
00200         err = fclose(f);
00201         if (err) {
00202             return -errno;
00203         }
00204     }
00205 
00206     emu->stats.erase_count += 1;
00207     return 0;
00208 }
00209 
00210 int lfs_emubd_sync(const struct lfs_config *cfg) {
00211     lfs_emubd_t *emu = cfg->context;
00212 
00213     // Just write out info/stats for later lookup
00214     snprintf(emu->child, LFS_NAME_MAX, "config");
00215     FILE *f = fopen(emu->path, "w");
00216     if (!f) {
00217         return -errno;
00218     }
00219 
00220     size_t res = fwrite(&emu->cfg, sizeof(emu->cfg), 1, f);
00221     if (res < 1) {
00222         return -errno;
00223     }
00224 
00225     int err = fclose(f);
00226     if (err) {
00227         return -errno;
00228     }
00229 
00230     snprintf(emu->child, LFS_NAME_MAX, "stats");
00231     f = fopen(emu->path, "w");
00232     if (!f) {
00233         return -errno;
00234     }
00235 
00236     res = fwrite(&emu->stats, sizeof(emu->stats), 1, f);
00237     if (res < 1) {
00238         return -errno;
00239     }
00240 
00241     err = fclose(f);
00242     if (err) {
00243         return -errno;
00244     }
00245 
00246     return 0;
00247 }