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