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