Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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