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 "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
Generated on Tue Aug 9 2022 00:37:09 by
