takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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     FILE *f = fopen(emu->path, "r");
00051     if (!f) {
00052         return -errno;
00053     }
00054 
00055     size_t res = fread(&emu->stats, sizeof(emu->stats), 1, f);
00056     if (res < 1) {
00057         return -errno;
00058     }
00059 
00060     err = fclose(f);
00061     if (err) {
00062         return -errno;
00063     }
00064 
00065     return 0;
00066 }
00067 
00068 void lfs_emubd_destroy(const struct lfs_config *cfg) {
00069     lfs_emubd_sync(cfg);
00070 
00071     lfs_emubd_t *emu = cfg->context;
00072     free(emu->path);
00073 }
00074 
00075 int lfs_emubd_read(const struct lfs_config *cfg, lfs_block_t block,
00076         lfs_off_t off, void *buffer, lfs_size_t size) {
00077     lfs_emubd_t *emu = cfg->context;
00078     uint8_t *data = buffer;
00079 
00080     // Check if read is valid
00081     assert(off  % cfg->read_size == 0);
00082     assert(size % cfg->read_size == 0);
00083     assert(block < cfg->block_count);
00084 
00085     // Zero out buffer for debugging
00086     memset(data, 0, size);
00087 
00088     // Read data
00089     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
00090 
00091     FILE *f = fopen(emu->path, "rb");
00092     if (!f && errno != ENOENT) {
00093         return -errno;
00094     }
00095 
00096     if (f) {
00097         int err = fseek(f, off, SEEK_SET);
00098         if (err) {
00099             return -errno;
00100         }
00101 
00102         size_t res = fread(data, 1, size, f);
00103         if (res < size && !feof(f)) {
00104             return -errno;
00105         }
00106 
00107         err = fclose(f);
00108         if (err) {
00109             return -errno;
00110         }
00111     }
00112 
00113     emu->stats.read_count += 1;
00114     return 0;
00115 }
00116 
00117 int lfs_emubd_prog(const struct lfs_config *cfg, lfs_block_t block,
00118         lfs_off_t off, const void *buffer, lfs_size_t size) {
00119     lfs_emubd_t *emu = cfg->context;
00120     const uint8_t *data = buffer;
00121 
00122     // Check if write is valid
00123     assert(off  % cfg->prog_size == 0);
00124     assert(size % cfg->prog_size == 0);
00125     assert(block < cfg->block_count);
00126 
00127     // Program data
00128     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
00129 
00130     FILE *f = fopen(emu->path, "r+b");
00131     if (!f) {
00132         return (errno == EACCES) ? 0 : -errno;
00133     }
00134 
00135     // Check that file was erased
00136     assert(f);
00137 
00138     int err = fseek(f, off, SEEK_SET);
00139     if (err) {
00140         return -errno;
00141     }
00142 
00143     size_t res = fwrite(data, 1, size, f);
00144     if (res < size) {
00145         return -errno;
00146     }
00147 
00148     err = fseek(f, off, SEEK_SET);
00149     if (err) {
00150         return -errno;
00151     }
00152 
00153     uint8_t dat;
00154     res = fread(&dat, 1, 1, f);
00155     if (res < 1) {
00156         return -errno;
00157     }
00158 
00159     err = fclose(f);
00160     if (err) {
00161         return -errno;
00162     }
00163 
00164     emu->stats.prog_count += 1;
00165     return 0;
00166 }
00167 
00168 int lfs_emubd_erase(const struct lfs_config *cfg, lfs_block_t block) {
00169     lfs_emubd_t *emu = cfg->context;
00170 
00171     // Check if erase is valid
00172     assert(block < cfg->block_count);
00173 
00174     // Erase the block
00175     snprintf(emu->child, LFS_NAME_MAX, "%" PRIx32, block);
00176     struct stat st;
00177     int err = stat(emu->path, &st);
00178     if (err && errno != ENOENT) {
00179         return -errno;
00180     }
00181 
00182     if (!err && S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode)) {
00183         err = unlink(emu->path);
00184         if (err) {
00185             return -errno;
00186         }
00187     }
00188 
00189     if (err || (S_ISREG(st.st_mode) && (S_IWUSR & st.st_mode))) {
00190         FILE *f = fopen(emu->path, "w");
00191         if (!f) {
00192             return -errno;
00193         }
00194 
00195         err = fclose(f);
00196         if (err) {
00197             return -errno;
00198         }
00199     }
00200 
00201     emu->stats.erase_count += 1;
00202     return 0;
00203 }
00204 
00205 int lfs_emubd_sync(const struct lfs_config *cfg) {
00206     lfs_emubd_t *emu = cfg->context;
00207 
00208     // Just write out info/stats for later lookup
00209     snprintf(emu->child, LFS_NAME_MAX, "config");
00210     FILE *f = fopen(emu->path, "w");
00211     if (!f) {
00212         return -errno;
00213     }
00214 
00215     size_t res = fwrite(&emu->cfg, sizeof(emu->cfg), 1, f);
00216     if (res < 1) {
00217         return -errno;
00218     }
00219 
00220     int err = fclose(f);
00221     if (err) {
00222         return -errno;
00223     }
00224 
00225     snprintf(emu->child, LFS_NAME_MAX, "stats");
00226     f = fopen(emu->path, "w");
00227     if (!f) {
00228         return -errno;
00229     }
00230 
00231     res = fwrite(&emu->stats, sizeof(emu->stats), 1, f);
00232     if (res < 1) {
00233         return -errno;
00234     }
00235 
00236     err = fclose(f);
00237     if (err) {
00238         return -errno;
00239     }
00240 
00241     return 0;
00242 }