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
FileSystemStore.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * 00004 * SPDX-License-Identifier: Apache-2.0 00005 * 00006 * Licensed under the Apache License, Version 2.0 (the "License"); 00007 * you may not use this file except in compliance with the License. 00008 * You may obtain a copy of the License at 00009 * 00010 * http://www.apache.org/licenses/LICENSE-2.0 00011 * 00012 * Unless required by applicable law or agreed to in writing, software 00013 * distributed under the License is distributed on an "AS IS" BASIS, 00014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 * See the License for the specific language governing permissions and 00016 * limitations under the License. 00017 */ 00018 00019 #include "FileSystemStore.h" 00020 #include "features/storage/kvstore/conf/kv_config.h" 00021 #include "features/storage/filesystem/Dir.h" 00022 #include "features/storage/filesystem/File.h" 00023 #include "features/storage/blockdevice/BlockDevice.h" 00024 #include "mbed_error.h" 00025 #include <string.h> 00026 #include <stdio.h> 00027 #include <stdlib.h> 00028 00029 #include "mbed_trace.h" 00030 #define TRACE_GROUP "FSST" 00031 00032 #define FSST_REVISION 1 00033 #define FSST_MAGIC 0x46535354 // "FSST" hex 'magic' signature 00034 00035 #define FSST_DEFAULT_FOLDER_PATH "kvstore" //default FileSystemStore folder path on fs 00036 00037 // Only write once flag is supported, other two are kept in storage but ignored 00038 static const uint32_t supported_flags = mbed::KVStore::WRITE_ONCE_FLAG | mbed::KVStore::REQUIRE_CONFIDENTIALITY_FLAG | 00039 mbed::KVStore::REQUIRE_REPLAY_PROTECTION_FLAG; 00040 00041 using namespace mbed; 00042 00043 namespace { 00044 00045 // incremental set handle 00046 typedef struct { 00047 char *key; 00048 uint32_t create_flags; 00049 size_t data_size; 00050 File *file_handle; 00051 } inc_set_handle_t; 00052 00053 // iterator handle 00054 typedef struct { 00055 void *dir_handle; 00056 char *prefix; 00057 } key_iterator_handle_t; 00058 00059 } // anonymous namespace 00060 00061 // Local Functions 00062 static char *string_ndup(const char *src, size_t size); 00063 00064 00065 // Class Functions 00066 FileSystemStore::FileSystemStore(FileSystem *fs) : _fs(fs), 00067 _is_initialized(false), _cfg_fs_path(NULL), _cfg_fs_path_size(0), 00068 _full_path_key(NULL), _cur_inc_data_size(0), _cur_inc_set_handle(NULL) 00069 { 00070 00071 } 00072 00073 int FileSystemStore::init() 00074 { 00075 int status = MBED_SUCCESS; 00076 00077 _mutex.lock(); 00078 const char *temp_path = get_filesystemstore_folder_path(); 00079 if (temp_path == NULL) { 00080 _cfg_fs_path_size = strlen(FSST_DEFAULT_FOLDER_PATH); 00081 _cfg_fs_path = string_ndup(FSST_DEFAULT_FOLDER_PATH, _cfg_fs_path_size); 00082 } else { 00083 _cfg_fs_path_size = strlen(temp_path); 00084 _cfg_fs_path = string_ndup(temp_path, _cfg_fs_path_size); 00085 } 00086 00087 _full_path_key = new char[_cfg_fs_path_size + KVStore::MAX_KEY_SIZE + 1]; 00088 memset(_full_path_key, 0, (_cfg_fs_path_size + KVStore::MAX_KEY_SIZE + 1)); 00089 strncpy(_full_path_key, _cfg_fs_path, _cfg_fs_path_size); 00090 _full_path_key[_cfg_fs_path_size] = '/'; 00091 _cur_inc_data_size = 0; 00092 _cur_inc_set_handle = NULL; 00093 Dir kv_dir; 00094 00095 if (kv_dir.open(_fs, _cfg_fs_path) != 0) { 00096 tr_info("KV Dir: %s, doesnt exist - creating new.. ", _cfg_fs_path); //TBD verify ERRNO NOEXIST 00097 if (_fs->mkdir(_cfg_fs_path,/* which flags ? */0777) != 0) { 00098 tr_error("KV Dir: %s, mkdir failed.. ", _cfg_fs_path); //TBD verify ERRNO NOEXIST 00099 status = MBED_ERROR_FAILED_OPERATION; 00100 goto exit_point; 00101 } 00102 } else { 00103 tr_info("KV Dir: %s, exists(verified) - now closing it", _cfg_fs_path); 00104 if (kv_dir.close() != 0) { 00105 tr_error("KV Dir: %s, dir_close failed", _cfg_fs_path); //TBD verify ERRNO NOEXIST 00106 } 00107 } 00108 00109 _is_initialized = true; 00110 exit_point: 00111 00112 _mutex.unlock(); 00113 00114 return status; 00115 00116 } 00117 00118 int FileSystemStore::deinit() 00119 { 00120 _mutex.lock(); 00121 _is_initialized = false; 00122 delete[] _cfg_fs_path; 00123 delete[] _full_path_key; 00124 _mutex.unlock(); 00125 return MBED_SUCCESS; 00126 00127 } 00128 00129 int FileSystemStore::reset() 00130 { 00131 int status = MBED_SUCCESS; 00132 Dir kv_dir; 00133 struct dirent dir_ent; 00134 00135 _mutex.lock(); 00136 if (false == _is_initialized) { 00137 status = MBED_ERROR_NOT_READY; 00138 goto exit_point; 00139 } 00140 00141 kv_dir.open(_fs, _cfg_fs_path); 00142 00143 while (kv_dir.read(&dir_ent) != 0) { 00144 if (dir_ent.d_type != DT_REG) { 00145 continue; 00146 } 00147 // Build File's full path name and delete it (even if write-onced) 00148 _build_full_path_key(dir_ent.d_name); 00149 _fs->remove(_full_path_key); 00150 } 00151 00152 kv_dir.close(); 00153 00154 exit_point: 00155 _mutex.unlock(); 00156 return status; 00157 } 00158 00159 int FileSystemStore::set(const char *key, const void *buffer, size_t size, uint32_t create_flags) 00160 { 00161 int status = MBED_SUCCESS; 00162 set_handle_t handle; 00163 00164 if (false == _is_initialized) { 00165 status = MBED_ERROR_NOT_READY; 00166 goto exit_point; 00167 } 00168 00169 if ((!is_valid_key(key)) || ((buffer == NULL) && (size > 0))) { 00170 status = MBED_ERROR_INVALID_ARGUMENT; 00171 goto exit_point; 00172 } 00173 00174 status = set_start(&handle, key, size, create_flags); 00175 if (status != MBED_SUCCESS) { 00176 tr_error("FSST Set set_start Failed: %d", status); 00177 goto exit_point; 00178 } 00179 00180 status = set_add_data(handle, buffer, size); 00181 if (status != MBED_SUCCESS) { 00182 tr_error("FSST Set set_add_data Failed: %d", status); 00183 set_finalize(handle); 00184 goto exit_point; 00185 } 00186 00187 status = set_finalize(handle); 00188 if (status != MBED_SUCCESS) { 00189 tr_error("FSST Set set_finalize Failed: %d", status); 00190 goto exit_point; 00191 } 00192 00193 exit_point: 00194 00195 return status; 00196 } 00197 00198 int FileSystemStore::get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size, size_t offset) 00199 { 00200 int status = MBED_SUCCESS; 00201 00202 File kv_file; 00203 size_t kv_file_size = 0; 00204 size_t value_actual_size = 0; 00205 00206 _mutex.lock(); 00207 00208 if (false == _is_initialized) { 00209 status = MBED_ERROR_NOT_READY; 00210 goto exit_point; 00211 } 00212 00213 key_metadata_t key_metadata; 00214 00215 if ((status = _verify_key_file(key, &key_metadata, &kv_file)) != MBED_SUCCESS) { 00216 tr_debug("File Verification failed, status: %d", status); 00217 goto exit_point; 00218 } 00219 00220 kv_file_size = kv_file.size() - key_metadata.metadata_size; 00221 // Actual size is the minimum of buffer_size and remainder of data in file (file's data size - offset) 00222 value_actual_size = buffer_size; 00223 if (offset > kv_file_size) { 00224 status = MBED_ERROR_INVALID_SIZE; 00225 goto exit_point; 00226 } else if ((kv_file_size - offset) < buffer_size) { 00227 value_actual_size = kv_file_size - offset; 00228 } 00229 00230 if ((buffer == NULL) && (value_actual_size > 0)) { 00231 status = MBED_ERROR_INVALID_DATA_DETECTED; 00232 goto exit_point; 00233 } 00234 00235 if (actual_size != NULL) { 00236 *actual_size = value_actual_size; 00237 } 00238 00239 kv_file.seek(key_metadata.metadata_size + offset, SEEK_SET); 00240 // Read remainder of data 00241 kv_file.read(buffer, value_actual_size); 00242 00243 exit_point: 00244 if ((status == MBED_SUCCESS) || 00245 (status == MBED_ERROR_INVALID_DATA_DETECTED)) { 00246 kv_file.close(); 00247 } 00248 _mutex.unlock(); 00249 00250 return status; 00251 } 00252 00253 int FileSystemStore::get_info(const char *key, info_t *info) 00254 { 00255 int status = MBED_SUCCESS; 00256 File kv_file; 00257 00258 _mutex.lock(); 00259 00260 if (false == _is_initialized) { 00261 status = MBED_ERROR_NOT_READY; 00262 goto exit_point; 00263 } 00264 00265 key_metadata_t key_metadata; 00266 00267 if ((status = _verify_key_file(key, &key_metadata, &kv_file)) != MBED_SUCCESS) { 00268 tr_debug("File Verification failed, status: %d", status); 00269 goto exit_point; 00270 } 00271 00272 if (info != NULL) { 00273 info->size = kv_file.size() - key_metadata.metadata_size; 00274 info->flags = key_metadata.user_flags; 00275 } 00276 00277 exit_point: 00278 if ((status == MBED_SUCCESS) || 00279 (status == MBED_ERROR_INVALID_DATA_DETECTED)) { 00280 kv_file.close(); 00281 } 00282 _mutex.unlock(); 00283 00284 return status; 00285 } 00286 00287 int FileSystemStore::remove(const char *key) 00288 { 00289 File kv_file; 00290 key_metadata_t key_metadata; 00291 00292 _mutex.lock(); 00293 00294 int status = MBED_SUCCESS; 00295 00296 if (false == _is_initialized) { 00297 status = MBED_ERROR_NOT_READY; 00298 goto exit_point; 00299 } 00300 00301 /* If File Exists and is Valid, then check its Write Once Flag to verify its disabled before removing */ 00302 /* If File exists and is not valid, or is Valid and not Write-Onced then remove it */ 00303 if ((status = _verify_key_file(key, &key_metadata, &kv_file)) == MBED_SUCCESS) { 00304 if (key_metadata.user_flags & KVStore::WRITE_ONCE_FLAG) { 00305 kv_file.close(); 00306 tr_error("File: %s, Exists but write protected", _full_path_key); 00307 status = MBED_ERROR_WRITE_PROTECTED; 00308 goto exit_point; 00309 } 00310 } else if ((status == MBED_ERROR_ITEM_NOT_FOUND) || 00311 (status == MBED_ERROR_INVALID_ARGUMENT)) { 00312 goto exit_point; 00313 } 00314 kv_file.close(); 00315 00316 if (0 != _fs->remove(_full_path_key)) { 00317 status = MBED_ERROR_FAILED_OPERATION; 00318 } 00319 00320 exit_point: 00321 _mutex.unlock(); 00322 return status; 00323 } 00324 00325 // Incremental set API 00326 int FileSystemStore::set_start(set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags) 00327 { 00328 int status = MBED_SUCCESS; 00329 inc_set_handle_t *set_handle = NULL; 00330 File *kv_file; 00331 key_metadata_t key_metadata; 00332 int key_len = 0; 00333 00334 if (create_flags & ~supported_flags) { 00335 return MBED_ERROR_INVALID_ARGUMENT; 00336 } 00337 00338 // Only a single key file can be incrementaly editted at a time 00339 _mutex.lock(); 00340 00341 kv_file = new File; 00342 00343 if (handle == NULL) { 00344 status = MBED_ERROR_INVALID_ARGUMENT; 00345 goto exit_point; 00346 } 00347 00348 /* If File Exists and is Valid, then check its Write Once Flag to verify its disabled before setting */ 00349 /* If File exists and is not valid, or is Valid and not Write-Onced then erase it */ 00350 status = _verify_key_file(key, &key_metadata, kv_file); 00351 00352 if (status == MBED_ERROR_INVALID_ARGUMENT) { 00353 tr_error("File Verification failed, status: %d", status); 00354 goto exit_point; 00355 } 00356 00357 if (status == MBED_SUCCESS) { 00358 if (key_metadata.user_flags & KVStore::WRITE_ONCE_FLAG) { 00359 kv_file->close(); 00360 status = MBED_ERROR_WRITE_PROTECTED; 00361 goto exit_point; 00362 } 00363 } 00364 00365 /* For Success (not write_once) and for corrupted data close file before recreating it as a new file */ 00366 if (status != MBED_ERROR_ITEM_NOT_FOUND) { 00367 kv_file->close(); 00368 } 00369 00370 if ((status = kv_file->open(_fs, _full_path_key, O_WRONLY | O_CREAT | O_TRUNC)) != MBED_SUCCESS) { 00371 tr_info("set_start failed to open: %s, for writing, err: %d", _full_path_key, status); 00372 status = MBED_ERROR_FAILED_OPERATION ; 00373 goto exit_point; 00374 } 00375 _cur_inc_data_size = 0; 00376 00377 set_handle = new inc_set_handle_t; 00378 set_handle->create_flags = create_flags; 00379 set_handle->data_size = final_data_size; 00380 set_handle->file_handle = kv_file; 00381 key_len = strlen(key); 00382 set_handle->key = string_ndup(key, key_len); 00383 *handle = (set_handle_t)set_handle; 00384 _cur_inc_set_handle = *handle; 00385 00386 key_metadata.magic = FSST_MAGIC; 00387 key_metadata.metadata_size = sizeof(key_metadata_t); 00388 key_metadata.revision = FSST_REVISION; 00389 key_metadata.user_flags = create_flags; 00390 kv_file->write(&key_metadata, sizeof(key_metadata_t)); 00391 00392 exit_point: 00393 if (status != MBED_SUCCESS) { 00394 delete kv_file; 00395 _mutex.unlock(); 00396 } 00397 return status; 00398 } 00399 00400 int FileSystemStore::set_add_data(set_handle_t handle, const void *value_data, size_t data_size) 00401 { 00402 int status = MBED_SUCCESS; 00403 size_t added_data = 0; 00404 inc_set_handle_t *set_handle = (inc_set_handle_t *)handle; 00405 File *kv_file; 00406 00407 if (((value_data == NULL) && (data_size > 0)) || (handle == NULL) || (handle != _cur_inc_set_handle)) { 00408 status = MBED_ERROR_INVALID_ARGUMENT; 00409 goto exit_point; 00410 } 00411 00412 // Single key incrementally edited, can be edited from multiple threads - lock to protect 00413 _inc_data_add_mutex.lock(); 00414 if ((_cur_inc_data_size + data_size) > set_handle->data_size) { 00415 tr_warning("Added Data(%d) will exceed set_start final size(%d) - not adding data to file: %s", 00416 _cur_inc_data_size + data_size, set_handle->data_size, _full_path_key); 00417 status = MBED_ERROR_INVALID_SIZE; 00418 goto exit_point; 00419 } 00420 00421 kv_file = set_handle->file_handle; 00422 00423 added_data = kv_file->write(value_data, data_size); 00424 if (added_data != data_size) { 00425 status = MBED_ERROR_FAILED_OPERATION ; 00426 } 00427 _cur_inc_data_size += added_data; 00428 00429 exit_point: 00430 if (status != MBED_ERROR_INVALID_ARGUMENT) { 00431 _inc_data_add_mutex.unlock(); 00432 } 00433 00434 return status; 00435 } 00436 00437 int FileSystemStore::set_finalize(set_handle_t handle) 00438 { 00439 int status = MBED_SUCCESS; 00440 inc_set_handle_t *set_handle = NULL; 00441 00442 if ((handle == NULL) || (handle != _cur_inc_set_handle)) { 00443 status = MBED_ERROR_INVALID_ARGUMENT; 00444 goto exit_point; 00445 } 00446 00447 set_handle = (inc_set_handle_t *)handle; 00448 00449 if (set_handle->key == NULL) { 00450 status = MBED_ERROR_INVALID_DATA_DETECTED; 00451 } else { 00452 if (_cur_inc_data_size != set_handle->data_size) { 00453 tr_error("Accumulated Data (%d) size doesn't match set_start final size (%d) - file: %s", _cur_inc_data_size, 00454 set_handle->data_size, _full_path_key); 00455 status = MBED_ERROR_INVALID_SIZE; 00456 _fs->remove(_full_path_key); 00457 } 00458 delete[] set_handle->key; 00459 } 00460 00461 set_handle->file_handle->close(); 00462 delete set_handle->file_handle; 00463 delete set_handle; 00464 _cur_inc_data_size = 0; 00465 _cur_inc_set_handle = NULL; 00466 00467 exit_point: 00468 if (status != MBED_ERROR_INVALID_ARGUMENT) { 00469 _mutex.unlock(); 00470 } 00471 00472 return status; 00473 } 00474 00475 int FileSystemStore::iterator_open(iterator_t *it, const char *prefix) 00476 { 00477 int status = MBED_SUCCESS; 00478 Dir *kv_dir = NULL; 00479 key_iterator_handle_t *key_it = NULL; 00480 00481 if (it == NULL) { 00482 return MBED_ERROR_INVALID_ARGUMENT; 00483 } 00484 00485 _mutex.lock(); 00486 if (false == _is_initialized) { 00487 status = MBED_ERROR_NOT_READY; 00488 goto exit_point; 00489 } 00490 key_it = new key_iterator_handle_t; 00491 key_it->dir_handle = NULL; 00492 key_it->prefix = NULL; 00493 if (prefix != NULL) { 00494 key_it->prefix = string_ndup(prefix, KVStore::MAX_KEY_SIZE); 00495 } 00496 00497 kv_dir = new Dir; 00498 if (kv_dir->open(_fs, _cfg_fs_path) != 0) { 00499 tr_error("KV Dir: %s, doesnt exist", _cfg_fs_path); //TBD verify ERRNO NOEXIST 00500 delete kv_dir; 00501 if (key_it->prefix != NULL) { 00502 delete[] key_it->prefix; 00503 } 00504 delete key_it; 00505 status = MBED_ERROR_ITEM_NOT_FOUND; 00506 goto exit_point; 00507 } 00508 00509 key_it->dir_handle = kv_dir; 00510 00511 *it = (iterator_t)key_it; 00512 00513 exit_point: 00514 _mutex.unlock(); 00515 00516 return status; 00517 } 00518 00519 int FileSystemStore::iterator_next(iterator_t it, char *key, size_t key_size) 00520 { 00521 Dir *kv_dir; 00522 struct dirent kv_dir_ent; 00523 int status = MBED_ERROR_ITEM_NOT_FOUND; 00524 key_iterator_handle_t *key_it; 00525 size_t key_name_size = KVStore::MAX_KEY_SIZE; 00526 if (key_size < key_name_size) { 00527 key_name_size = key_size; 00528 } 00529 00530 _mutex.lock(); 00531 if (false == _is_initialized) { 00532 status = MBED_ERROR_NOT_READY; 00533 goto exit_point; 00534 } 00535 00536 key_it = (key_iterator_handle_t *)it; 00537 00538 if ((key_it->prefix != NULL) && (key_name_size < strlen(key_it->prefix))) { 00539 status = MBED_ERROR_INVALID_SIZE; 00540 goto exit_point; 00541 } 00542 00543 kv_dir = (Dir *)key_it->dir_handle; 00544 00545 while (kv_dir->read(&kv_dir_ent) != 0) { 00546 if (kv_dir_ent.d_type != DT_REG) { 00547 continue; 00548 } 00549 00550 if ((key_it->prefix == NULL) || 00551 (strncmp(kv_dir_ent.d_name, key_it->prefix, strlen(key_it->prefix)) == 0)) { 00552 if (key_name_size < strlen(kv_dir_ent.d_name)) { 00553 status = MBED_ERROR_INVALID_SIZE; 00554 break; 00555 } 00556 strncpy(key, kv_dir_ent.d_name, key_name_size); 00557 key[key_name_size - 1] = '\0'; 00558 status = MBED_SUCCESS; 00559 break; 00560 } 00561 } 00562 00563 exit_point: 00564 _mutex.unlock(); 00565 return status; 00566 } 00567 00568 int FileSystemStore::iterator_close(iterator_t it) 00569 { 00570 int status = MBED_SUCCESS; 00571 key_iterator_handle_t *key_it = (key_iterator_handle_t *)it; 00572 00573 _mutex.lock(); 00574 if (key_it == NULL) { 00575 status = MBED_ERROR_INVALID_ARGUMENT; 00576 goto exit_point; 00577 } 00578 00579 if (key_it->prefix != NULL) { 00580 delete[] key_it->prefix; 00581 } 00582 00583 if (key_it->dir_handle != NULL) { 00584 ((Dir *)(key_it->dir_handle))->close(); 00585 delete ((Dir *)(key_it->dir_handle)); 00586 } 00587 delete key_it; 00588 00589 exit_point: 00590 _mutex.unlock(); 00591 return status; 00592 } 00593 00594 int FileSystemStore::_verify_key_file(const char *key, key_metadata_t *key_metadata, File *kv_file) 00595 { 00596 int status = MBED_SUCCESS; 00597 00598 if (!is_valid_key(key)) { 00599 status = MBED_ERROR_INVALID_ARGUMENT; 00600 goto exit_point; 00601 } 00602 00603 _build_full_path_key(key); 00604 00605 if (0 != kv_file->open(_fs, _full_path_key, O_RDONLY)) { 00606 status = MBED_ERROR_ITEM_NOT_FOUND; 00607 goto exit_point; 00608 } 00609 00610 //Read Metadata 00611 kv_file->read(key_metadata, sizeof(key_metadata_t)); 00612 00613 if ((key_metadata->magic != FSST_MAGIC) || 00614 (key_metadata->revision > FSST_REVISION)) { 00615 status = MBED_ERROR_INVALID_DATA_DETECTED; 00616 goto exit_point; 00617 } 00618 00619 exit_point: 00620 return status; 00621 } 00622 00623 int FileSystemStore::_build_full_path_key(const char *key_src) 00624 { 00625 strncpy(&_full_path_key[_cfg_fs_path_size + 1/* for path's \ */], key_src, KVStore::MAX_KEY_SIZE); 00626 _full_path_key[(_cfg_fs_path_size + KVStore::MAX_KEY_SIZE)] = '\0'; 00627 return 0; 00628 } 00629 00630 // Local Functions 00631 static char *string_ndup(const char *src, size_t size) 00632 { 00633 char *string_copy = new char[size + 1]; 00634 strncpy(string_copy, src, size); 00635 string_copy[size] = '\0'; 00636 return string_copy; 00637 } 00638 00639 00640
Generated on Tue Jul 12 2022 13:54:21 by
