Skip to content

KVStore: Add init bit flags for read/write and creation mode #12759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
3 changes: 3 additions & 0 deletions features/storage/TESTS/kvstore/filesystemstore_tests/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ void test_file_system_store_functionality_unit_test()

FileSystemStore *fsst = new FileSystemStore(fs);

err = fsst->init(InitMode::ExclusiveCreation | InitMode::ReadWrite);
TEST_ASSER_EQUAL_ERROR_CODE(MBED_ERROR_INITIALIZATION_FAILED, err);

err = fsst->init();
TEST_ASSERT_EQUAL_ERROR_CODE(0, err);

Expand Down
6 changes: 6 additions & 0 deletions features/storage/TESTS/kvstore/securestore_whitebox/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ static void white_box_test()
SecureStore *sec_kv = new SecureStore(ul_kv, rbp_kv);

for (int i = 0; i < 2; i++) {
timer.reset();
result = tdbs->init(InitMode::ExclusiveCreation | InitMode::ReadWrite);
elapsed = timer.read_ms();
TEST_ASSER_EQUAL_ERROR_CODE(MBED_ERROR_INITIALIZATION_FAILED, result);
printf("Elapsed time for exclusive init failure %d ms\n", elapsed);

timer.reset();
result = sec_kv->init();
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
Expand Down
6 changes: 6 additions & 0 deletions features/storage/TESTS/kvstore/tdbstore_whitebox/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ static void white_box_test()

TDBStore *tdbs = new TDBStore(test_bd);

timer.reset();
result = tdbs->init(InitMode::ExclusiveCreation | InitMode::ReadWrite);
elapsed = timer.read_ms();
TEST_ASSER_EQUAL_ERROR_CODE(MBED_ERROR_INITIALIZATION_FAILED, result);
printf("Elapsed time for exclusive init failure %d ms\n", elapsed);

timer.reset();
result = tdbs->init();
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, result);
Expand Down
45 changes: 44 additions & 1 deletion features/storage/kvstore/filesystemstore/FileSystemStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,19 @@ FileSystemStore::FileSystemStore(FileSystem *fs) : _fs(fs),

}

int FileSystemStore::init()
int FileSystemStore::init(InitMode flags)
{
// Check for implemented flags
if (!KVStore::_is_valid_flags(flags)) {
return MBED_ERROR_INVALID_ARGUMENT;
}
if (!((flags & InitMode::Append) == InitMode::Append ||
(flags & InitMode::ExclusiveCreation) == InitMode::ExclusiveCreation)) {
return MBED_ERROR_UNSUPPORTED;
}

_flags = flags;

int status = MBED_SUCCESS;

_mutex.lock();
Expand All @@ -93,6 +104,10 @@ int FileSystemStore::init()
Dir kv_dir;

if (kv_dir.open(_fs, _cfg_fs_path) != 0) {
if ((flags & InitMode::ExclusiveCreation) == InitMode::ExclusiveCreation) {
status = MBED_ERROR_INITIALIZATION_FAILED;
goto exit_point;
}
tr_info("KV Dir: %s, doesnt exist - creating new.. ", _cfg_fs_path); //TBD verify ERRNO NOEXIST
if (_fs->mkdir(_cfg_fs_path,/* which flags ? */0777) != 0) {
tr_error("KV Dir: %s, mkdir failed.. ", _cfg_fs_path); //TBD verify ERRNO NOEXIST
Expand Down Expand Up @@ -132,6 +147,10 @@ int FileSystemStore::reset()
Dir kv_dir;
struct dirent dir_ent;

if (!KVStore::_has_flags_any(InitMode::Write)) {
return MBED_ERROR_INVALID_OPERATION;
}

_mutex.lock();
if (false == _is_initialized) {
status = MBED_ERROR_NOT_READY;
Expand Down Expand Up @@ -166,6 +185,10 @@ int FileSystemStore::set(const char *key, const void *buffer, size_t size, uint3
goto exit_point;
}

if (!KVStore::_has_flags_any(InitMode::Write)) {
return MBED_ERROR_INVALID_OPERATION;
}

if ((!is_valid_key(key)) || ((buffer == NULL) && (size > 0))) {
status = MBED_ERROR_INVALID_ARGUMENT;
goto exit_point;
Expand Down Expand Up @@ -210,6 +233,10 @@ int FileSystemStore::get(const char *key, void *buffer, size_t buffer_size, size
goto exit_point;
}

if (!KVStore::_has_flags_any(InitMode::Read)) {
return MBED_ERROR_INVALID_OPERATION;
}

key_metadata_t key_metadata;

if ((status = _verify_key_file(key, &key_metadata, &kv_file)) != MBED_SUCCESS) {
Expand Down Expand Up @@ -255,6 +282,10 @@ int FileSystemStore::get_info(const char *key, info_t *info)
int status = MBED_SUCCESS;
File kv_file;

if (!KVStore::_has_flags_any(InitMode::Read)) {
return MBED_ERROR_INVALID_OPERATION;
}

_mutex.lock();

if (false == _is_initialized) {
Expand Down Expand Up @@ -289,6 +320,10 @@ int FileSystemStore::remove(const char *key)
File kv_file;
key_metadata_t key_metadata;

if (!KVStore::_has_flags_any(InitMode::Write)) {
return MBED_ERROR_INVALID_OPERATION;
}

_mutex.lock();

int status = MBED_SUCCESS;
Expand Down Expand Up @@ -331,6 +366,10 @@ int FileSystemStore::set_start(set_handle_t *handle, const char *key, size_t fin
key_metadata_t key_metadata;
int key_len = 0;

if (!KVStore::_has_flags_any(InitMode::Write)) {
return MBED_ERROR_INVALID_OPERATION;
}

if (create_flags & ~supported_flags) {
return MBED_ERROR_INVALID_ARGUMENT;
}
Expand Down Expand Up @@ -478,6 +517,10 @@ int FileSystemStore::iterator_open(iterator_t *it, const char *prefix)
Dir *kv_dir = NULL;
key_iterator_handle_t *key_it = NULL;

if (!KVStore::_has_flags_any(InitMode::Read | InitMode::WriteOnlyAllowKeyRead)) {
return MBED_ERROR_INVALID_OPERATION;
}

if (it == NULL) {
return MBED_ERROR_INVALID_ARGUMENT;
}
Expand Down
32 changes: 22 additions & 10 deletions features/storage/kvstore/filesystemstore/FileSystemStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,18 @@ class FileSystemStore : public KVStore {
virtual ~FileSystemStore() {}

/**
* @brief Initialize FileSystemStore, checking validity of
* KVStore writing folder and if it doesn't exist, creating it.
* @brief Initialize FileSystemStore, checking validity of KVStore writing folder and
* if it doesn't exist, creating it by default. If other init modes are desired,
* set the flags as necessary.
*
* @param[in] flags Flags that determine how the FileSystemStore allows KV
* read/write and store creation.
*
* @returns MBED_SUCCESS Success.
* MBED_ERROR_INITIALIZATION_FAILED No valid FileSystemStore found on the device.
* MBED_ERROR_FAILED_OPERATION Underlying file system failed operation.
*/
virtual int init();
virtual int init(InitMode flags = DEFAULT_INIT_FLAGS);

/**
* @brief Deinitialize FileSystemStore, release and free resources.
Expand All @@ -67,6 +72,7 @@ class FileSystemStore : public KVStore {
* @returns MBED_SUCCESS Success.
* MBED_ERROR_NOT_READY Not initialized.
* MBED_ERROR_FAILED_OPERATION Underlying file system failed operation.
* MBED_ERROR_INVALID_OPERATION InitMode does not include write permission.
*/
virtual int reset();

Expand All @@ -84,6 +90,7 @@ class FileSystemStore : public KVStore {
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
* MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
* MBED_ERROR_INVALID_OPERATION InitMode do not include write permission.
*/
virtual int set(const char *key, const void *buffer, size_t size, uint32_t create_flags);

Expand All @@ -103,6 +110,7 @@ class FileSystemStore : public KVStore {
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
* MBED_ERROR_INVALID_DATA_DETECTED Data is corrupted.
* MBED_ERROR_ITEM_NOT_FOUND No such key.
* MBED_ERROR_INVALID_OPERATION InitMode do not include write permission.
*/
virtual int get(const char *key, void *buffer, size_t buffer_size, size_t *actual_size = NULL, size_t offset = 0);

Expand All @@ -112,13 +120,14 @@ class FileSystemStore : public KVStore {
* @param[in] key Key - must not include '*' '/' '?' ':' ';' '\' '"' '|' ' ' '<' '>' '\'.
* @param[out] info Returned information structure.
*
* @returns MBED_SUCCESS Success.
* MBED_ERROR_NOT_READY Not initialized.
* MBED_ERROR_FAILED_OPERATION Underlying file system failed operation.
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
* MBED_ERROR_INVALID_DATA_DETECTED Data is corrupted.
* MBED_ERROR_ITEM_NOT_FOUND No such key.
* @returns MBED_SUCCESS Success.
* MBED_ERROR_NOT_READY Not initialized.
* MBED_ERROR_FAILED_OPERATION Underlying file system failed operation.
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
* MBED_ERROR_INVALID_DATA_DETECTED Data is corrupted.
* MBED_ERROR_ITEM_NOT_FOUND No such key.
* MBED_ERROR_INVALID_OPERATION InitMode do not include read permission.
*/
virtual int get_info(const char *key, info_t *info);

Expand All @@ -133,6 +142,7 @@ class FileSystemStore : public KVStore {
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
* MBED_ERROR_ITEM_NOT_FOUND No such key.
* MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
* MBED_ERROR_INVALID_OPERATION InitMode do not include write permission.
*/
virtual int remove(const char *key);

Expand All @@ -151,6 +161,7 @@ class FileSystemStore : public KVStore {
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
* MBED_ERROR_INVALID_SIZE Invalid size given in function arguments.
* MBED_ERROR_WRITE_PROTECTED Already stored with "write once" flag.
* MBED_ERROR_INVALID_OPERATION InitMode do not include write permission.
*/
virtual int set_start(set_handle_t *handle, const char *key, size_t final_data_size, uint32_t create_flags);

Expand Down Expand Up @@ -193,6 +204,7 @@ class FileSystemStore : public KVStore {
* @returns MBED_SUCCESS Success.
* MBED_ERROR_NOT_READY Not initialized.
* MBED_ERROR_INVALID_ARGUMENT Invalid argument given in function arguments.
* MBED_ERROR_INVALID_OPERATION InitMode do not include read or write-only read key permissions.
*/
virtual int iterator_open(iterator_t *it, const char *prefix = NULL);

Expand Down
60 changes: 60 additions & 0 deletions features/storage/kvstore/include/InitModeFlags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2020 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef MBED_INIT_MODE_FLAGS_H
#define MBED_INIT_MODE_FLAGS_H

#include <stdint.h>
#include "mbed_enum_flags.h"

namespace mbed {

/**
* @brief A set of creation flags for the KVStore instance.
*
* The Read, Write, and ReadWrite flags may be OR-ed to produce the correct initialization
* sequence. This is similar to how a file is opened.
*
* By default, the init mode opens in ReadWrite and Append mode as the default argument.
*
* At least one of Read, Write, or ReadWrite must be specified. Additionally, at least one
* of the following must be specified with write access: Append, Truncate, CreateNewOnly, or
* ExclusiveCreation.
*
*/
MBED_SCOPED_ENUM_FLAGS(InitMode)
{
Read = (1 << 0), //!< Enable read access from the KVStore
Write = (1 << 1), //!< Enable write access to the KVStore
ReadWrite = (Read | Write), //!< Enable read and write access to the KVSTore. This is the default.
WriteOnlyAllowKeyRead = (1 << 3), //!< Allow reading KVStore keys even in write only mode
Append = (1 << 8), //!< Allow adding to the the KVStore and create from new if necessary. This is the default.
Truncate = (1 << 9), //!< Erase all key/value pairs before using.
CreateNewOnly = (1 << 10), //!< Only open the KVStore if it does not already exist.
ExclusiveCreation = (1 << 11), //!< Only open the KVStore if it already exists.

#if !defined(DOXYGEN_ONLY)
// These are for interal use only
WriteOpenFlags = 0xf00,
NoFlags = 0,
AllFlags = 0xf07

#endif // DOXYGEN_ONLY
};

}

#endif // MBED_INIT_MODE_FLAGS_H
66 changes: 66 additions & 0 deletions features/storage/kvstore/include/KVStore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2020 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// ----------------------------------------------------------- Includes -----------------------------------------------------------

#include "KVStore.h"
namespace mbed {


bool KVStore::is_valid_key(const char *key) const
{
if (!key || !strlen(key) || (strlen(key) > MAX_KEY_SIZE)) {
return false;
}

if (strpbrk(key, " */?:;\"|<>\\")) {
return false;
}
return true;
}

bool KVStore::_is_valid_flags(InitMode flags)
{
// Check that only valid bits are here at all
if ((~(InitMode::AllFlags) & flags) == InitMode::NoFlags) {
return false;
}

// Need at least one of the Read or Write bits set
if ((flags & InitMode::ReadWrite) == InitMode::NoFlags) {
return false;
}

// Check for only one set of the WriteOpenFlags
const uint32_t wo_flags = static_cast<uint32_t>(flags & InitMode::WriteOpenFlags);
// Fails for zero, the conditional afterwards finds this
if (wo_flags & (wo_flags - 1)) {
return false;
}
// Only allow blank Append, etc. if no writing
if (((flags & InitMode::Write) == InitMode::Write) && (wo_flags == 0)) {
return false;
}

return true;
}

bool KVStore::_has_flags_any(InitMode flags) const
{
return !(((_flags & flags)) == InitMode::NoFlags);
}

}
Loading