takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LittleFileSystem.cpp Source File

LittleFileSystem.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "filesystem/mbed_filesystem.h"
00017 #include "LittleFileSystem.h"
00018 #include "errno.h"
00019 #include "lfs.h"
00020 #include "lfs_util.h"
00021 #include "MbedCRC.h"
00022 
00023 extern "C" void lfs_crc(uint32_t *crc, const void *buffer, size_t size)
00024 {
00025     uint32_t initial_xor = *crc;    
00026     MbedCRC<POLY_32BIT_REV_ANSI, 32> ct(initial_xor, 0x0, true, false);
00027     ct.compute((void *)buffer, size, (uint32_t *) crc);
00028 }
00029 
00030 ////// Conversion functions //////
00031 static int lfs_toerror(int err)
00032 {
00033     switch (err) {
00034         case LFS_ERR_OK:        return 0;
00035         case LFS_ERR_IO:        return -EIO;
00036         case LFS_ERR_NOENT:     return -ENOENT;
00037         case LFS_ERR_EXIST:     return -EEXIST;
00038         case LFS_ERR_NOTDIR:    return -ENOTDIR;
00039         case LFS_ERR_ISDIR:     return -EISDIR;
00040         case LFS_ERR_INVAL:     return -EINVAL;
00041         case LFS_ERR_NOSPC:     return -ENOSPC;
00042         case LFS_ERR_NOMEM:     return -ENOMEM;
00043         case LFS_ERR_CORRUPT:   return -EILSEQ;
00044         default:                return err;
00045     }
00046 }
00047 
00048 static int lfs_fromflags(int flags)
00049 {
00050     return (
00051         (((flags & 3) == O_RDONLY) ? LFS_O_RDONLY : 0) |
00052         (((flags & 3) == O_WRONLY) ? LFS_O_WRONLY : 0) |
00053         (((flags & 3) == O_RDWR)   ? LFS_O_RDWR   : 0) |
00054         ((flags & O_CREAT)  ? LFS_O_CREAT  : 0) |
00055         ((flags & O_EXCL)   ? LFS_O_EXCL   : 0) |
00056         ((flags & O_TRUNC)  ? LFS_O_TRUNC  : 0) |
00057         ((flags & O_APPEND) ? LFS_O_APPEND : 0));
00058 }
00059 
00060 static int lfs_fromwhence(int whence)
00061 {
00062     switch (whence) {
00063         case SEEK_SET: return LFS_SEEK_SET;
00064         case SEEK_CUR: return LFS_SEEK_CUR;
00065         case SEEK_END: return LFS_SEEK_END;
00066         default: return whence;
00067     }
00068 }
00069 
00070 static int lfs_tomode(int type)
00071 {
00072     int mode = S_IRWXU | S_IRWXG | S_IRWXO;
00073     switch (type) {
00074         case LFS_TYPE_DIR: return mode | S_IFDIR;
00075         case LFS_TYPE_REG: return mode | S_IFREG;
00076         default: return 0;
00077     }
00078 }
00079 
00080 static int lfs_totype(int type)
00081 {
00082     switch (type) {
00083         case LFS_TYPE_DIR: return DT_DIR;
00084         case LFS_TYPE_REG: return DT_REG;
00085         default: return DT_UNKNOWN;
00086     }
00087 }
00088 
00089 
00090 ////// Block device operations //////
00091 static int lfs_bd_read(const struct lfs_config *c, lfs_block_t block,
00092         lfs_off_t off, void *buffer, lfs_size_t size) {
00093     BlockDevice *bd = (BlockDevice *)c->context;
00094     return bd->read(buffer, (bd_addr_t)block*c->block_size + off, size);
00095 }
00096 
00097 static int lfs_bd_prog(const struct lfs_config *c, lfs_block_t block,
00098         lfs_off_t off, const void *buffer, lfs_size_t size) {
00099     BlockDevice *bd = (BlockDevice *)c->context;
00100     return bd->program(buffer, (bd_addr_t)block*c->block_size + off, size);
00101 }
00102 
00103 static int lfs_bd_erase(const struct lfs_config *c, lfs_block_t block)
00104 {
00105     BlockDevice *bd = (BlockDevice *)c->context;
00106     return bd->erase((bd_addr_t)block*c->block_size, c->block_size);
00107 }
00108 
00109 static int lfs_bd_sync(const struct lfs_config *c)
00110 {
00111     BlockDevice *bd = (BlockDevice *)c->context;
00112     return bd->sync();
00113 }
00114 
00115 
00116 ////// Generic filesystem operations //////
00117 
00118 // Filesystem implementation (See LittleFileSystem.h)
00119 LittleFileSystem::LittleFileSystem(const char *name, BlockDevice *bd,
00120         lfs_size_t read_size, lfs_size_t prog_size,
00121         lfs_size_t block_size, lfs_size_t lookahead)
00122         : FileSystem(name)
00123         , _read_size(read_size)
00124         , _prog_size(prog_size)
00125         , _block_size(block_size)
00126         , _lookahead(lookahead) {
00127     if (bd) {
00128         mount(bd);
00129     }
00130 }
00131 
00132 LittleFileSystem::~LittleFileSystem() {
00133     // nop if unmounted
00134     unmount();
00135 }
00136 
00137 int LittleFileSystem::mount(BlockDevice *bd)
00138 {
00139     _mutex.lock();
00140     LFS_INFO("mount(%p)", bd);
00141     _bd = bd;
00142     int err = _bd->init();
00143     if (err) {
00144         _bd = NULL;
00145         LFS_INFO("mount -> %d", err);
00146         _mutex.unlock();
00147         return err;
00148     }
00149 
00150     memset(&_config, 0, sizeof(_config));
00151     _config.context = bd;
00152     _config.read  = lfs_bd_read;
00153     _config.prog  = lfs_bd_prog;
00154     _config.erase = lfs_bd_erase;
00155     _config.sync  = lfs_bd_sync;
00156     _config.read_size   = bd->get_read_size();
00157     if (_config.read_size < _read_size) {
00158         _config.read_size = _read_size;
00159     }
00160     _config.prog_size   = bd->get_program_size();
00161     if (_config.prog_size < _prog_size) {
00162         _config.prog_size = _prog_size;
00163     }
00164     _config.block_size  = bd->get_erase_size();
00165     if (_config.block_size < _block_size) {
00166         _config.block_size = _block_size;
00167     }
00168     _config.block_count = bd->size() / _config.block_size;
00169     _config.lookahead = 32 * ((_config.block_count+31)/32);
00170     if (_config.lookahead > _lookahead) {
00171         _config.lookahead = _lookahead;
00172     }
00173 
00174     err = lfs_mount(&_lfs, &_config);
00175     if (err) {
00176         _bd = NULL;
00177         LFS_INFO("mount -> %d", lfs_toerror(err));
00178         _mutex.unlock();
00179         return lfs_toerror(err);
00180     }
00181 
00182     _mutex.unlock();
00183     LFS_INFO("mount -> %d", 0);
00184     return 0;
00185 }
00186 
00187 int LittleFileSystem::unmount()
00188 {
00189     _mutex.lock();
00190     LFS_INFO("unmount(%s)", "");
00191     int res = 0;
00192     if (_bd) {
00193         int err = lfs_unmount(&_lfs);
00194         if (err && !res) {
00195             res = lfs_toerror(err);
00196         }
00197 
00198         err = _bd->deinit();
00199         if (err && !res) {
00200             res = err;
00201         }
00202 
00203         _bd = NULL;
00204     }
00205     
00206     LFS_INFO("unmount -> %d", res);
00207     _mutex.unlock();
00208     return res;
00209 }
00210 
00211 int LittleFileSystem::format(BlockDevice *bd,
00212         lfs_size_t read_size, lfs_size_t prog_size,
00213         lfs_size_t block_size, lfs_size_t lookahead) {
00214     LFS_INFO("format(%p, %ld, %ld, %ld, %ld)",
00215             bd, read_size, prog_size, block_size, lookahead);
00216     int err = bd->init();
00217     if (err) {
00218         LFS_INFO("format -> %d", err);
00219         return err;
00220     }
00221 
00222     lfs_t _lfs;
00223     struct lfs_config _config;
00224     
00225     memset(&_config, 0, sizeof(_config));
00226     _config.context = bd;
00227     _config.read  = lfs_bd_read;
00228     _config.prog  = lfs_bd_prog;
00229     _config.erase = lfs_bd_erase;
00230     _config.sync  = lfs_bd_sync;
00231     _config.read_size   = bd->get_read_size();
00232     if (_config.read_size < read_size) {
00233         _config.read_size = read_size;
00234     }
00235     _config.prog_size   = bd->get_program_size();
00236     if (_config.prog_size < prog_size) {
00237         _config.prog_size = prog_size;
00238     }
00239     _config.block_size  = bd->get_erase_size();
00240     if (_config.block_size < block_size) {
00241         _config.block_size = block_size;
00242     }
00243     _config.block_count = bd->size() / _config.block_size;
00244     _config.lookahead = 32 * ((_config.block_count+31)/32);
00245     if (_config.lookahead > lookahead) {
00246         _config.lookahead = lookahead;
00247     }
00248 
00249     err = lfs_format(&_lfs, &_config);
00250     if (err) {
00251         LFS_INFO("format -> %d", lfs_toerror(err));
00252         return lfs_toerror(err);
00253     }
00254 
00255     err = bd->deinit();
00256     if (err) {
00257         LFS_INFO("format -> %d", err);
00258         return err;
00259     }
00260 
00261     LFS_INFO("format -> %d", 0);
00262     return 0;
00263 }
00264 
00265 int LittleFileSystem::reformat(BlockDevice *bd)
00266 {
00267     _mutex.lock();
00268     LFS_INFO("reformat(%p)", bd);
00269     if (_bd) {
00270         if (!bd) {
00271             bd = _bd;
00272         }
00273 
00274         int err = unmount();
00275         if (err) {
00276             LFS_INFO("reformat -> %d", err);
00277             _mutex.unlock();
00278             return err;
00279         }
00280     }
00281 
00282     if (!bd) {
00283         LFS_INFO("reformat -> %d", -ENODEV);
00284         _mutex.unlock();
00285         return -ENODEV;
00286     }
00287 
00288     int err = LittleFileSystem::format(bd,
00289             _read_size, _prog_size, _block_size, _lookahead);
00290     if (err) {
00291         LFS_INFO("reformat -> %d", err);
00292         _mutex.unlock();
00293         return err;
00294     }
00295 
00296     err = mount(bd);
00297     if (err) {
00298         LFS_INFO("reformat -> %d", err);
00299         _mutex.unlock();
00300         return err;
00301     }
00302 
00303     LFS_INFO("reformat -> %d", 0);
00304     _mutex.unlock();
00305     return 0;
00306 }
00307 
00308 int LittleFileSystem::remove(const char *filename)
00309 {
00310     _mutex.lock();
00311     LFS_INFO("remove(\"%s\")", filename);
00312     int err = lfs_remove(&_lfs, filename);
00313     LFS_INFO("remove -> %d", lfs_toerror(err));
00314     _mutex.unlock();
00315     return lfs_toerror(err);
00316 }
00317 
00318 int LittleFileSystem::rename(const char *oldname, const char *newname)
00319 {
00320     _mutex.lock();
00321     LFS_INFO("rename(\"%s\", \"%s\")", oldname, newname);
00322     int err = lfs_rename(&_lfs, oldname, newname);
00323     LFS_INFO("rename -> %d", lfs_toerror(err));
00324     _mutex.unlock();
00325     return lfs_toerror(err);
00326 }
00327 
00328 int LittleFileSystem::mkdir(const char *name, mode_t mode)
00329 {
00330     _mutex.lock();
00331     LFS_INFO("mkdir(\"%s\", 0x%lx)", name, mode);
00332     int err = lfs_mkdir(&_lfs, name);
00333     LFS_INFO("mkdir -> %d", lfs_toerror(err));
00334     _mutex.unlock();
00335     return lfs_toerror(err);
00336 }
00337 
00338 int LittleFileSystem::stat(const char *name, struct stat *st)
00339 {
00340     struct lfs_info info;
00341     _mutex.lock();
00342     LFS_INFO("stat(\"%s\", %p)", name, st);
00343     int err = lfs_stat(&_lfs, name, &info);
00344     LFS_INFO("stat -> %d", lfs_toerror(err));
00345     _mutex.unlock();
00346     st->st_size = info.size;
00347     st->st_mode = lfs_tomode(info.type);
00348     return lfs_toerror(err);
00349 }
00350 
00351 static int lfs_statvfs_count(void *p, lfs_block_t b)
00352 {
00353     *(lfs_size_t *)p += 1;
00354     return 0;
00355 }
00356 
00357 int LittleFileSystem::statvfs(const char *name, struct statvfs *st)
00358 {
00359     memset(st, 0, sizeof(struct statvfs));
00360 
00361     lfs_size_t in_use = 0;
00362     _mutex.lock();
00363     LFS_INFO("statvfs(\"%s\", %p)", name, st);
00364     int err = lfs_traverse(&_lfs, lfs_statvfs_count, &in_use);
00365     LFS_INFO("statvfs -> %d", lfs_toerror(err));
00366     _mutex.unlock();
00367     if (err) {
00368         return err;
00369     }
00370 
00371     st->f_bsize  = _config.block_size;
00372     st->f_frsize = _config.block_size;
00373     st->f_blocks = _config.block_count;
00374     st->f_bfree  = _config.block_count - in_use;
00375     st->f_bavail = _config.block_count - in_use;
00376     st->f_namemax = LFS_NAME_MAX;
00377     return 0;
00378 }
00379 
00380 ////// File operations //////
00381 int LittleFileSystem::file_open(fs_file_t *file, const char *path, int flags)
00382 {
00383     lfs_file_t *f = new lfs_file_t;
00384     _mutex.lock();
00385     LFS_INFO("file_open(%p, \"%s\", 0x%x)", *file, path, flags);
00386     int err = lfs_file_open(&_lfs, f, path, lfs_fromflags(flags));
00387     LFS_INFO("file_open -> %d", lfs_toerror(err));
00388     _mutex.unlock();
00389     if (!err) {
00390         *file = f;
00391     } else {
00392         delete f;
00393     }
00394     return lfs_toerror(err);
00395 }
00396 
00397 int LittleFileSystem::file_close(fs_file_t file)
00398 {
00399     lfs_file_t *f = (lfs_file_t *)file;
00400     _mutex.lock();
00401     LFS_INFO("file_close(%p)", file);
00402     int err = lfs_file_close(&_lfs, f);
00403     LFS_INFO("file_close -> %d", lfs_toerror(err));
00404     _mutex.unlock();
00405     delete f;
00406     return lfs_toerror(err);
00407 }
00408 
00409 ssize_t LittleFileSystem::file_read(fs_file_t file, void *buffer, size_t len)
00410 {
00411     lfs_file_t *f = (lfs_file_t *)file;
00412     _mutex.lock();
00413     LFS_INFO("file_read(%p, %p, %d)", file, buffer, len);
00414     lfs_ssize_t res = lfs_file_read(&_lfs, f, buffer, len);
00415     LFS_INFO("file_read -> %d", lfs_toerror(res));
00416     _mutex.unlock();
00417     return lfs_toerror(res);
00418 }
00419 
00420 ssize_t LittleFileSystem::file_write(fs_file_t file, const void *buffer, size_t len)
00421 {
00422     lfs_file_t *f = (lfs_file_t *)file;
00423     _mutex.lock();
00424     LFS_INFO("file_write(%p, %p, %d)", file, buffer, len);
00425     lfs_ssize_t res = lfs_file_write(&_lfs, f, buffer, len);
00426     LFS_INFO("file_write -> %d", lfs_toerror(res));
00427     _mutex.unlock();
00428     return lfs_toerror(res);
00429 }
00430 
00431 int LittleFileSystem::file_sync(fs_file_t file)
00432 {
00433     lfs_file_t *f = (lfs_file_t *)file;
00434     _mutex.lock();
00435     LFS_INFO("file_sync(%p)", file);
00436     int err = lfs_file_sync(&_lfs, f);
00437     LFS_INFO("file_sync -> %d", lfs_toerror(err));
00438     _mutex.unlock();
00439     return lfs_toerror(err);
00440 }
00441 
00442 off_t LittleFileSystem::file_seek(fs_file_t file, off_t offset, int whence)
00443 {
00444     lfs_file_t *f = (lfs_file_t *)file;
00445     _mutex.lock();
00446     LFS_INFO("file_seek(%p, %ld, %d)", file, offset, whence);
00447     off_t res = lfs_file_seek(&_lfs, f, offset, lfs_fromwhence(whence));
00448     LFS_INFO("file_seek -> %d", lfs_toerror(res));
00449     _mutex.unlock();
00450     return lfs_toerror(res);
00451 }
00452 
00453 off_t LittleFileSystem::file_tell(fs_file_t file)
00454 {
00455     lfs_file_t *f = (lfs_file_t *)file;
00456     _mutex.lock();
00457     LFS_INFO("file_tell(%p)", file);
00458     off_t res = lfs_file_tell(&_lfs, f);
00459     LFS_INFO("file_tell -> %d", lfs_toerror(res));
00460     _mutex.unlock();
00461     return lfs_toerror(res);
00462 }
00463 
00464 off_t LittleFileSystem::file_size(fs_file_t file)
00465 {
00466     lfs_file_t *f = (lfs_file_t *)file;
00467     _mutex.lock();
00468     LFS_INFO("file_size(%p)", file);
00469     off_t res = lfs_file_size(&_lfs, f);
00470     LFS_INFO("file_size -> %d", lfs_toerror(res));
00471     _mutex.unlock();
00472     return lfs_toerror(res);
00473 }
00474 
00475 
00476 ////// Dir operations //////
00477 int LittleFileSystem::dir_open(fs_dir_t *dir, const char *path)
00478 {
00479     lfs_dir_t *d = new lfs_dir_t;
00480     _mutex.lock();
00481     LFS_INFO("dir_open(%p, \"%s\")", *dir, path);
00482     int err = lfs_dir_open(&_lfs, d, path);
00483     LFS_INFO("dir_open -> %d", lfs_toerror(err));
00484     _mutex.unlock();
00485     if (!err) {
00486         *dir = d;
00487     } else {
00488         delete d;
00489     }
00490     return lfs_toerror(err);
00491 }
00492 
00493 int LittleFileSystem::dir_close(fs_dir_t dir)
00494 {
00495     lfs_dir_t *d = (lfs_dir_t *)dir;
00496     _mutex.lock();
00497     LFS_INFO("dir_close(%p)", dir);
00498     int err = lfs_dir_close(&_lfs, d);
00499     LFS_INFO("dir_close -> %d", lfs_toerror(err));
00500     _mutex.unlock();
00501     delete d;
00502     return lfs_toerror(err);
00503 }
00504 
00505 ssize_t LittleFileSystem::dir_read(fs_dir_t dir, struct dirent *ent)
00506 {
00507     lfs_dir_t *d = (lfs_dir_t *)dir;
00508     struct lfs_info info;
00509     _mutex.lock();
00510     LFS_INFO("dir_read(%p, %p)", dir, ent);
00511     int res = lfs_dir_read(&_lfs, d, &info);
00512     LFS_INFO("dir_read -> %d", lfs_toerror(res));
00513     _mutex.unlock();
00514     if (res == 1) {
00515         ent->d_type = lfs_totype(info.type);
00516         strcpy(ent->d_name, info.name);
00517     }
00518     return lfs_toerror(res);
00519 }
00520 
00521 void LittleFileSystem::dir_seek(fs_dir_t dir, off_t offset)
00522 {
00523     lfs_dir_t *d = (lfs_dir_t *)dir;
00524     _mutex.lock();
00525     LFS_INFO("dir_seek(%p, %ld)", dir, offset);
00526     lfs_dir_seek(&_lfs, d, offset);
00527     LFS_INFO("dir_seek -> %s", "void");
00528     _mutex.unlock();
00529 }
00530 
00531 off_t LittleFileSystem::dir_tell(fs_dir_t dir)
00532 {
00533     lfs_dir_t *d = (lfs_dir_t *)dir;
00534     _mutex.lock();
00535     LFS_INFO("dir_tell(%p)", dir);
00536     lfs_soff_t res = lfs_dir_tell(&_lfs, d);
00537     LFS_INFO("dir_tell -> %d", lfs_toerror(res));
00538     _mutex.unlock();
00539     return lfs_toerror(res);
00540 }
00541 
00542 void LittleFileSystem::dir_rewind(fs_dir_t dir)
00543 {
00544     lfs_dir_t *d = (lfs_dir_t *)dir;
00545     _mutex.lock();
00546     LFS_INFO("dir_rewind(%p)", dir);
00547     lfs_dir_rewind(&_lfs, d);
00548     LFS_INFO("dir_rewind -> %s", "void");
00549     _mutex.unlock();
00550 }
00551