mirror of
https://github.com/espressif/openthread.git
synced 2026-08-10 04:37:47 +00:00
[posix] move settings file related methods to a separate file (#11023)
This commit refactors the settings module to move the settings file related methods to a seperate file, so that other modules could resue the same code to save thier settings to another settings file.
This commit is contained in:
@@ -146,6 +146,7 @@ add_library(openthread-posix
|
||||
rcp_caps_diag.cpp
|
||||
resolver.cpp
|
||||
settings.cpp
|
||||
settings_file.cpp
|
||||
spinel_manager.cpp
|
||||
spi_interface.cpp
|
||||
system.cpp
|
||||
@@ -207,6 +208,7 @@ target_include_directories(openthread-posix PRIVATE
|
||||
|
||||
add_executable(ot-posix-test-settings
|
||||
settings.cpp
|
||||
settings_file.cpp
|
||||
)
|
||||
target_compile_definitions(ot-posix-test-settings
|
||||
PRIVATE -DSELF_TEST=1 -DOPENTHREAD_CONFIG_LOG_PLATFORM=0
|
||||
|
||||
+22
-294
@@ -54,12 +54,11 @@
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "posix/platform/settings.hpp"
|
||||
#include "posix/platform/settings_file.hpp"
|
||||
|
||||
#include "system.hpp"
|
||||
|
||||
static const size_t kMaxFileNameSize = sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH) + 32;
|
||||
|
||||
static int sSettingsFd = -1;
|
||||
static ot::Posix::SettingsFile sSettingsFile;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
|
||||
static const uint16_t *sSensitiveKeys = nullptr;
|
||||
@@ -81,79 +80,20 @@ exit:
|
||||
}
|
||||
#endif
|
||||
|
||||
static void getSettingsFileName(otInstance *aInstance, char aFileName[kMaxFileNameSize], bool aSwap)
|
||||
static otError settingsFileInit(otInstance *aInstance)
|
||||
{
|
||||
const char *offset = getenv("PORT_OFFSET");
|
||||
uint64_t nodeId;
|
||||
static constexpr size_t kMaxFileBaseNameSize = 32;
|
||||
char fileBaseName[kMaxFileBaseNameSize];
|
||||
const char *offset = getenv("PORT_OFFSET");
|
||||
uint64_t nodeId;
|
||||
|
||||
otPlatRadioGetIeeeEui64(aInstance, reinterpret_cast<uint8_t *>(&nodeId));
|
||||
nodeId = ot::BigEndian::HostSwap64(nodeId);
|
||||
snprintf(aFileName, kMaxFileNameSize, OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH "/%s_%" PRIx64 ".%s",
|
||||
offset == nullptr ? "0" : offset, nodeId, (aSwap ? "swap" : "data"));
|
||||
}
|
||||
|
||||
static int swapOpen(otInstance *aInstance)
|
||||
{
|
||||
char fileName[kMaxFileNameSize];
|
||||
int fd;
|
||||
snprintf(fileBaseName, sizeof(fileBaseName), "%s_%" PRIx64, offset == nullptr ? "0" : offset, nodeId);
|
||||
VerifyOrDie(strlen(fileBaseName) < kMaxFileBaseNameSize, OT_EXIT_FAILURE);
|
||||
|
||||
getSettingsFileName(aInstance, fileName, true);
|
||||
|
||||
fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
|
||||
VerifyOrDie(fd != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads @p aLength bytes from the data file and appends to the swap file.
|
||||
*
|
||||
* @param[in] aFd The file descriptor of the current swap file.
|
||||
* @param[in] aLength Number of bytes to copy.
|
||||
*/
|
||||
static void swapWrite(otInstance *aInstance, int aFd, uint16_t aLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
const size_t kBlockSize = 512;
|
||||
uint8_t buffer[kBlockSize];
|
||||
|
||||
while (aLength > 0)
|
||||
{
|
||||
uint16_t count = aLength >= sizeof(buffer) ? sizeof(buffer) : aLength;
|
||||
ssize_t rval = read(sSettingsFd, buffer, count);
|
||||
|
||||
VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
|
||||
count = static_cast<uint16_t>(rval);
|
||||
rval = write(aFd, buffer, count);
|
||||
assert(rval == count);
|
||||
VerifyOrDie(rval == count, OT_EXIT_FAILURE);
|
||||
aLength -= count;
|
||||
}
|
||||
}
|
||||
|
||||
static void swapPersist(otInstance *aInstance, int aFd)
|
||||
{
|
||||
char swapFile[kMaxFileNameSize];
|
||||
char dataFile[kMaxFileNameSize];
|
||||
|
||||
getSettingsFileName(aInstance, swapFile, true);
|
||||
getSettingsFileName(aInstance, dataFile, false);
|
||||
|
||||
VerifyOrDie(0 == close(sSettingsFd), OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(0 == fsync(aFd), OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(0 == rename(swapFile, dataFile), OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
sSettingsFd = aFd;
|
||||
}
|
||||
|
||||
static void swapDiscard(otInstance *aInstance, int aFd)
|
||||
{
|
||||
char swapFileName[kMaxFileNameSize];
|
||||
|
||||
VerifyOrDie(0 == close(aFd), OT_EXIT_ERROR_ERRNO);
|
||||
getSettingsFileName(aInstance, swapFileName, true);
|
||||
VerifyOrDie(0 == unlink(swapFileName), OT_EXIT_ERROR_ERRNO);
|
||||
return sSettingsFile.Init(fileBaseName);
|
||||
}
|
||||
|
||||
void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, uint16_t aSensitiveKeysLength)
|
||||
@@ -163,8 +103,6 @@ void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, u
|
||||
OT_UNUSED_VARIABLE(aSensitiveKeysLength);
|
||||
#endif
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
|
||||
sSensitiveKeys = aSensitiveKeys;
|
||||
sSensitiveKeysLength = aSensitiveKeysLength;
|
||||
@@ -172,50 +110,14 @@ void otPlatSettingsInit(otInstance *aInstance, const uint16_t *aSensitiveKeys, u
|
||||
|
||||
// Don't touch the settings file the system runs in dry-run mode.
|
||||
VerifyOrExit(!IsSystemDryRun());
|
||||
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, &st) == -1)
|
||||
{
|
||||
VerifyOrDie(mkdir(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, 0755) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char fileName[kMaxFileNameSize];
|
||||
|
||||
getSettingsFileName(aInstance, fileName, false);
|
||||
sSettingsFd = open(fileName, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
|
||||
}
|
||||
|
||||
VerifyOrDie(sSettingsFd != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
for (off_t size = lseek(sSettingsFd, 0, SEEK_END), offset = lseek(sSettingsFd, 0, SEEK_SET); offset < size;)
|
||||
{
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
rval = read(sSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
|
||||
|
||||
rval = read(sSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
}
|
||||
SuccessOrExit(settingsFileInit(aInstance));
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
|
||||
otPosixSecureSettingsInit(aInstance);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
if (error == OT_ERROR_PARSE)
|
||||
{
|
||||
VerifyOrDie(ftruncate(sSettingsFd, 0) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void otPlatSettingsDeinit(otInstance *aInstance)
|
||||
@@ -228,9 +130,7 @@ void otPlatSettingsDeinit(otInstance *aInstance)
|
||||
otPosixSecureSettingsDeinit(aInstance);
|
||||
#endif
|
||||
|
||||
VerifyOrExit(sSettingsFd != -1);
|
||||
VerifyOrDie(close(sSettingsFd) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
sSettingsFd = -1;
|
||||
sSettingsFile.Deinit();
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -251,7 +151,7 @@ otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint
|
||||
else
|
||||
#endif
|
||||
{
|
||||
error = ot::Posix::PlatformSettingsGet(aInstance, aKey, aIndex, aValue, aValueLength);
|
||||
error = sSettingsFile.Get(aKey, aIndex, aValue, aValueLength);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -261,6 +161,8 @@ exit:
|
||||
|
||||
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
|
||||
@@ -271,7 +173,7 @@ otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *a
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ot::Posix::PlatformSettingsSet(aInstance, aKey, aValue, aValueLength);
|
||||
sSettingsFile.Set(aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -291,7 +193,7 @@ otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *a
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ot::Posix::PlatformSettingsAdd(aInstance, aKey, aValue, aValueLength);
|
||||
sSettingsFile.Add(aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -299,6 +201,8 @@ otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *a
|
||||
|
||||
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError error;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
|
||||
@@ -309,7 +213,7 @@ otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
error = ot::Posix::PlatformSettingsDelete(aInstance, aKey, aIndex, nullptr);
|
||||
error = sSettingsFile.Delete(aKey, aIndex);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -322,187 +226,11 @@ void otPlatSettingsWipe(otInstance *aInstance)
|
||||
otPosixSecureSettingsWipe(aInstance);
|
||||
#endif
|
||||
|
||||
VerifyOrDie(0 == ftruncate(sSettingsFd, 0), OT_EXIT_ERROR_ERRNO);
|
||||
sSettingsFile.Wipe();
|
||||
}
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
otError PlatformSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
const off_t size = lseek(sSettingsFd, 0, SEEK_END);
|
||||
off_t offset = lseek(sSettingsFd, 0, SEEK_SET);
|
||||
|
||||
VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_PARSE);
|
||||
|
||||
while (offset < size)
|
||||
{
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
rval = read(sSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
|
||||
|
||||
rval = read(sSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
|
||||
|
||||
if (key == aKey)
|
||||
{
|
||||
if (aIndex == 0)
|
||||
{
|
||||
error = OT_ERROR_NONE;
|
||||
|
||||
if (aValueLength)
|
||||
{
|
||||
if (aValue)
|
||||
{
|
||||
uint16_t readLength = (length <= *aValueLength ? length : *aValueLength);
|
||||
|
||||
VerifyOrExit(read(sSettingsFd, aValue, readLength) == readLength, error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
*aValueLength = length;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
--aIndex;
|
||||
}
|
||||
}
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void PlatformSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
int swapFd = -1;
|
||||
|
||||
switch (PlatformSettingsDelete(aInstance, aKey, -1, &swapFd))
|
||||
{
|
||||
case OT_ERROR_NONE:
|
||||
case OT_ERROR_NOT_FOUND:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
|
||||
write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
|
||||
write(swapFd, aValue, aValueLength) == aValueLength,
|
||||
OT_EXIT_FAILURE);
|
||||
|
||||
swapPersist(aInstance, swapFd);
|
||||
}
|
||||
|
||||
void PlatformSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
off_t size = lseek(sSettingsFd, 0, SEEK_END);
|
||||
int swapFd = swapOpen(aInstance);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
VerifyOrDie(0 == lseek(sSettingsFd, 0, SEEK_SET), OT_EXIT_ERROR_ERRNO);
|
||||
swapWrite(aInstance, swapFd, static_cast<uint16_t>(size));
|
||||
}
|
||||
|
||||
VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
|
||||
write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
|
||||
write(swapFd, aValue, aValueLength) == aValueLength,
|
||||
OT_EXIT_FAILURE);
|
||||
|
||||
swapPersist(aInstance, swapFd);
|
||||
}
|
||||
|
||||
otError PlatformSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex, int *aSwapFd)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
off_t size = lseek(sSettingsFd, 0, SEEK_END);
|
||||
off_t offset = lseek(sSettingsFd, 0, SEEK_SET);
|
||||
int swapFd = swapOpen(aInstance);
|
||||
|
||||
assert(swapFd != -1);
|
||||
assert(offset == 0);
|
||||
VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_FAILED);
|
||||
|
||||
while (offset < size)
|
||||
{
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
rval = read(sSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
|
||||
|
||||
rval = read(sSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
|
||||
if (aKey == key)
|
||||
{
|
||||
if (aIndex == 0)
|
||||
{
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
|
||||
swapWrite(aInstance, swapFd, static_cast<uint16_t>(size - offset));
|
||||
error = OT_ERROR_NONE;
|
||||
break;
|
||||
}
|
||||
else if (aIndex == -1)
|
||||
{
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
|
||||
error = OT_ERROR_NONE;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
--aIndex;
|
||||
}
|
||||
}
|
||||
|
||||
rval = write(swapFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
|
||||
|
||||
rval = write(swapFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
|
||||
|
||||
swapWrite(aInstance, swapFd, length);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (aSwapFd != nullptr)
|
||||
{
|
||||
*aSwapFd = swapFd;
|
||||
}
|
||||
else if (error == OT_ERROR_NONE)
|
||||
{
|
||||
swapPersist(aInstance, swapFd);
|
||||
}
|
||||
else if (error == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
swapDiscard(aInstance, swapFd);
|
||||
}
|
||||
else if (error == OT_ERROR_FAILED)
|
||||
{
|
||||
swapDiscard(aInstance, swapFd);
|
||||
DieNow(error);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_SECURE_SETTINGS_ENABLE
|
||||
void PlatformSettingsGetSensitiveKeys(otInstance *aInstance, const uint16_t **aKeys, uint16_t *aKeysLength)
|
||||
{
|
||||
|
||||
@@ -32,57 +32,6 @@
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
/**
|
||||
* Gets a setting from the persisted file.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aIndex The index of the specific item to get.
|
||||
* @param[out] aValue A pointer to where the value of the setting should be written.
|
||||
* @param[in,out] aValueLength A pointer to the length of the value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given setting was found and fetched successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND The given key or index was not found in the setting store.
|
||||
*/
|
||||
otError PlatformSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength);
|
||||
|
||||
/**
|
||||
* Sets a setting in the persisted file.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aValue A pointer to where the new value of the setting should be read from.
|
||||
* @param[in] aValueLength The length of the data pointed to by aValue.
|
||||
*/
|
||||
void PlatformSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
|
||||
/**
|
||||
* Adds a setting to the persisted file.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aValue A pointer to where the new value of the setting should be read from.
|
||||
* @param[in] aValueLength The length of the data pointed to by aValue.
|
||||
*/
|
||||
void PlatformSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
|
||||
/**
|
||||
* Removes a setting either from swap file or persisted file.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aIndex The index of the value to be removed. If set to -1, all values for this aKey will be removed.
|
||||
* @param[out] aSwapFd A optional pointer to receive file descriptor of the generated swap file descriptor.
|
||||
*
|
||||
* @note
|
||||
* If @p aSwapFd is null, operate deleting on the setting file.
|
||||
* If @p aSwapFd is not null, operate on the swap file, and aSwapFd will point to the swap file descriptor.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given key and index was found and removed successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND The given key or index was not found in the setting store.
|
||||
*/
|
||||
otError PlatformSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex, int *aSwapFd);
|
||||
|
||||
/**
|
||||
* Gets the sensitive keys that should be stored in the secure area.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements the settings file module for getting, setting and deleting the key-value pairs.
|
||||
*/
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
#include "platform-posix.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "posix/platform/settings_file.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
otError SettingsFile::Init(const char *aSettingsFileBaseName)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
const char *directory = OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH;
|
||||
|
||||
OT_ASSERT((aSettingsFileBaseName != nullptr) && (strlen(aSettingsFileBaseName) < kMaxFileBaseNameSize));
|
||||
strncpy(mSettingFileBaseName, aSettingsFileBaseName, sizeof(mSettingFileBaseName) - 1);
|
||||
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(directory, &st) == -1)
|
||||
{
|
||||
VerifyOrDie(mkdir(directory, 0755) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char fileName[kMaxFilePathSize];
|
||||
|
||||
GetSettingsFilePath(fileName, false);
|
||||
mSettingsFd = open(fileName, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
|
||||
}
|
||||
|
||||
VerifyOrDie(mSettingsFd != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
for (off_t size = lseek(mSettingsFd, 0, SEEK_END), offset = lseek(mSettingsFd, 0, SEEK_SET); offset < size;)
|
||||
{
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
rval = read(mSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
|
||||
|
||||
rval = read(mSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error == OT_ERROR_PARSE)
|
||||
{
|
||||
VerifyOrDie(ftruncate(mSettingsFd, 0) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void SettingsFile::Deinit(void)
|
||||
{
|
||||
VerifyOrExit(mSettingsFd != -1);
|
||||
VerifyOrDie(close(mSettingsFd) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
mSettingsFd = -1;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError SettingsFile::Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
off_t size;
|
||||
off_t offset;
|
||||
|
||||
OT_ASSERT(mSettingsFd >= 0);
|
||||
|
||||
size = lseek(mSettingsFd, 0, SEEK_END);
|
||||
offset = lseek(mSettingsFd, 0, SEEK_SET);
|
||||
VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_PARSE);
|
||||
|
||||
while (offset < size)
|
||||
{
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
rval = read(mSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
|
||||
|
||||
rval = read(mSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
|
||||
|
||||
if (key == aKey)
|
||||
{
|
||||
if (aIndex == 0)
|
||||
{
|
||||
error = OT_ERROR_NONE;
|
||||
|
||||
if (aValueLength)
|
||||
{
|
||||
if (aValue)
|
||||
{
|
||||
uint16_t readLength = (length <= *aValueLength ? length : *aValueLength);
|
||||
|
||||
VerifyOrExit(read(mSettingsFd, aValue, readLength) == readLength, error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
*aValueLength = length;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
--aIndex;
|
||||
}
|
||||
}
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void SettingsFile::Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
int swapFd = -1;
|
||||
|
||||
OT_ASSERT(mSettingsFd >= 0);
|
||||
|
||||
switch (Delete(aKey, -1, &swapFd))
|
||||
{
|
||||
case OT_ERROR_NONE:
|
||||
case OT_ERROR_NOT_FOUND:
|
||||
break;
|
||||
|
||||
default:
|
||||
OT_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
|
||||
write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
|
||||
write(swapFd, aValue, aValueLength) == aValueLength,
|
||||
OT_EXIT_FAILURE);
|
||||
|
||||
SwapPersist(swapFd);
|
||||
}
|
||||
|
||||
void SettingsFile::Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
off_t size;
|
||||
int swapFd;
|
||||
|
||||
OT_ASSERT(mSettingsFd >= 0);
|
||||
|
||||
size = lseek(mSettingsFd, 0, SEEK_END);
|
||||
swapFd = SwapOpen();
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
VerifyOrDie(0 == lseek(mSettingsFd, 0, SEEK_SET), OT_EXIT_ERROR_ERRNO);
|
||||
SwapWrite(swapFd, static_cast<uint16_t>(size));
|
||||
}
|
||||
|
||||
VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
|
||||
write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
|
||||
write(swapFd, aValue, aValueLength) == aValueLength,
|
||||
OT_EXIT_FAILURE);
|
||||
|
||||
SwapPersist(swapFd);
|
||||
}
|
||||
|
||||
otError SettingsFile::Delete(uint16_t aKey, int aIndex) { return Delete(aKey, aIndex, nullptr); }
|
||||
|
||||
otError SettingsFile::Delete(uint16_t aKey, int aIndex, int *aSwapFd)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
off_t size;
|
||||
off_t offset;
|
||||
int swapFd;
|
||||
|
||||
OT_ASSERT(mSettingsFd >= 0);
|
||||
|
||||
size = lseek(mSettingsFd, 0, SEEK_END);
|
||||
offset = lseek(mSettingsFd, 0, SEEK_SET);
|
||||
swapFd = SwapOpen();
|
||||
|
||||
OT_ASSERT(swapFd != -1);
|
||||
OT_ASSERT(offset == 0);
|
||||
VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_FAILED);
|
||||
|
||||
while (offset < size)
|
||||
{
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
rval = read(mSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
|
||||
|
||||
rval = read(mSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
|
||||
if (aKey == key)
|
||||
{
|
||||
if (aIndex == 0)
|
||||
{
|
||||
VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
|
||||
SwapWrite(swapFd, static_cast<uint16_t>(size - offset));
|
||||
error = OT_ERROR_NONE;
|
||||
break;
|
||||
}
|
||||
else if (aIndex == -1)
|
||||
{
|
||||
VerifyOrExit(offset == lseek(mSettingsFd, length, SEEK_CUR), error = OT_ERROR_FAILED);
|
||||
error = OT_ERROR_NONE;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
--aIndex;
|
||||
}
|
||||
}
|
||||
|
||||
rval = write(swapFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_FAILED);
|
||||
|
||||
rval = write(swapFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_FAILED);
|
||||
|
||||
SwapWrite(swapFd, length);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (aSwapFd != nullptr)
|
||||
{
|
||||
*aSwapFd = swapFd;
|
||||
}
|
||||
else if (error == OT_ERROR_NONE)
|
||||
{
|
||||
SwapPersist(swapFd);
|
||||
}
|
||||
else if (error == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
SwapDiscard(swapFd);
|
||||
}
|
||||
else if (error == OT_ERROR_FAILED)
|
||||
{
|
||||
SwapDiscard(swapFd);
|
||||
DieNow(error);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void SettingsFile::Wipe(void) { VerifyOrDie(0 == ftruncate(mSettingsFd, 0), OT_EXIT_ERROR_ERRNO); }
|
||||
|
||||
void SettingsFile::GetSettingsFilePath(char aFileName[kMaxFilePathSize], bool aSwap)
|
||||
{
|
||||
snprintf(aFileName, kMaxFilePathSize, OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH "/%s.%s", mSettingFileBaseName,
|
||||
(aSwap ? "Swap" : "data"));
|
||||
}
|
||||
|
||||
int SettingsFile::SwapOpen(void)
|
||||
{
|
||||
char fileName[kMaxFilePathSize];
|
||||
int fd;
|
||||
|
||||
GetSettingsFilePath(fileName, true);
|
||||
|
||||
fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
|
||||
VerifyOrDie(fd != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void SettingsFile::SwapWrite(int aFd, uint16_t aLength)
|
||||
{
|
||||
const size_t kBlockSize = 512;
|
||||
uint8_t buffer[kBlockSize];
|
||||
|
||||
while (aLength > 0)
|
||||
{
|
||||
uint16_t count = aLength >= sizeof(buffer) ? sizeof(buffer) : aLength;
|
||||
ssize_t rval = read(mSettingsFd, buffer, count);
|
||||
|
||||
VerifyOrDie(rval > 0, OT_EXIT_FAILURE);
|
||||
count = static_cast<uint16_t>(rval);
|
||||
rval = write(aFd, buffer, count);
|
||||
OT_ASSERT(rval == count);
|
||||
VerifyOrDie(rval == count, OT_EXIT_FAILURE);
|
||||
aLength -= count;
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsFile::SwapPersist(int aFd)
|
||||
{
|
||||
char swapFile[kMaxFilePathSize];
|
||||
char dataFile[kMaxFilePathSize];
|
||||
|
||||
GetSettingsFilePath(swapFile, true);
|
||||
GetSettingsFilePath(dataFile, false);
|
||||
|
||||
VerifyOrDie(0 == close(mSettingsFd), OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(0 == fsync(aFd), OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(0 == rename(swapFile, dataFile), OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
mSettingsFd = aFd;
|
||||
}
|
||||
|
||||
void SettingsFile::SwapDiscard(int aFd)
|
||||
{
|
||||
char swapFileName[kMaxFilePathSize];
|
||||
|
||||
VerifyOrDie(0 == close(aFd), OT_EXIT_ERROR_ERRNO);
|
||||
GetSettingsFilePath(swapFileName, true);
|
||||
VerifyOrDie(0 == unlink(swapFileName), OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2024, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef OT_POSIX_PLATFORM_SETTINGS_FILE_HPP_
|
||||
#define OT_POSIX_PLATFORM_SETTINGS_FILE_HPP_
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
#include "platform-posix.h"
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
class SettingsFile
|
||||
{
|
||||
public:
|
||||
SettingsFile(void)
|
||||
: mSettingsFd(-1)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the initialization for the settings file.
|
||||
*
|
||||
* @param[in] aSettingsFileBaseName A pointer to the base name of the settings file.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given settings file was initialized successfully.
|
||||
* @retval OT_ERROR_PARSE The key-value format could not be parsed (invalid format).
|
||||
*/
|
||||
otError Init(const char *aSettingsFileBaseName);
|
||||
|
||||
/**
|
||||
* Performs the de-initialization for the settings file.
|
||||
*/
|
||||
void Deinit(void);
|
||||
|
||||
/**
|
||||
* Gets a setting from the settings file.
|
||||
*
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aIndex The index of the specific item to get.
|
||||
* @param[out] aValue A pointer to where the value of the setting should be written.
|
||||
* @param[in,out] aValueLength A pointer to the length of the value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given setting was found and fetched successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND The given key or index was not found in the setting store.
|
||||
*/
|
||||
otError Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength);
|
||||
|
||||
/**
|
||||
* Sets a setting in the settings file.
|
||||
*
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aValue A pointer to where the new value of the setting should be read from.
|
||||
* @param[in] aValueLength The length of the data pointed to by aValue.
|
||||
*/
|
||||
void Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
|
||||
/**
|
||||
* Adds a setting to the settings file.
|
||||
*
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aValue A pointer to where the new value of the setting should be read from.
|
||||
* @param[in] aValueLength The length of the data pointed to by aValue.
|
||||
*/
|
||||
void Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
||||
|
||||
/**
|
||||
* Removes a setting from the settings file.
|
||||
*
|
||||
* @param[in] aKey The key associated with the requested setting.
|
||||
* @param[in] aIndex The index of the value to be removed. If set to -1, all values for this aKey will be
|
||||
* removed.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given key and index was found and removed successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND The given key or index was not found in the setting store.
|
||||
*/
|
||||
otError Delete(uint16_t aKey, int aIndex);
|
||||
|
||||
/**
|
||||
* Deletes all settings from the setting file.
|
||||
*/
|
||||
void Wipe(void);
|
||||
|
||||
private:
|
||||
static const size_t kMaxFileDirectorySize = sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH);
|
||||
static const size_t kSlashLength = 1;
|
||||
static const size_t kMaxFileBaseNameSize = 64;
|
||||
static const size_t kMaxFileExtensionLength = 5; ///< The length of `.Swap` or `.data`.
|
||||
static const size_t kMaxFilePathSize =
|
||||
kMaxFileDirectorySize + kSlashLength + kMaxFileBaseNameSize + kMaxFileExtensionLength;
|
||||
|
||||
otError Delete(uint16_t aKey, int aIndex, int *aSwapFd);
|
||||
void GetSettingsFilePath(char aFileName[kMaxFilePathSize], bool aSwap);
|
||||
int SwapOpen(void);
|
||||
void SwapWrite(int aFd, uint16_t aLength);
|
||||
void SwapPersist(int aFd);
|
||||
void SwapDiscard(int aFd);
|
||||
|
||||
char mSettingFileBaseName[kMaxFileBaseNameSize];
|
||||
int mSettingsFd;
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // OT_POSIX_PLATFORM_SETTINGS_FILE_HPP_
|
||||
Reference in New Issue
Block a user