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