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