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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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
Generated on Tue Jul 12 2022 13:54:26 by
