[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:
Zhanglong Xia
2024-12-16 08:49:11 -08:00
committed by GitHub
parent 971f05f760
commit 81542cada9
5 changed files with 525 additions and 345 deletions
+2
View File
@@ -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
View File
@@ -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)
{
-51
View File
@@ -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.
*
+370
View File
@@ -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
+131
View File
@@ -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_