zephyr/subsys/bluetooth/host/storage.c
Johan Hedberg 2975ca0754 Bluetooth: Kconfig: Rename CONFIG_BLUETOOTH_* to CONFIG_BT_*
The API name space for Bluetooth is bt_* and BT_* so it makes sense to
align the Kconfig name space with this. The additional benefit is that
this also makes the names shorter. It is also in line with what Linux
uses for Bluetooth Kconfig entries.

Some Bluetooth-related Networking Kconfig defines are renamed as well
in order to be consistent, such as NET_L2_BLUETOOTH.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
2017-08-09 11:14:19 +03:00

230 lines
4.3 KiB
C

/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <string.h>
#include <misc/printk.h>
#include <zephyr.h>
#include <init.h>
#include <fs.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/storage.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
#include "common/log.h"
#define STORAGE_ROOT "/bt"
/* Required file name length for full storage support. If the maximum
* file name length supported by the chosen file system is less than
* this value, then only local keys are supported (/bt/abcd).
*/
#define STORAGE_FILE_NAME_LEN 13
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
/* /bt/aabbccddeeff0/abcd */
#define STORAGE_PATH_MAX 23
#else
/* /bt/abcd */
#define STORAGE_PATH_MAX 9
#endif
enum storage_access {
STORAGE_READ,
STORAGE_WRITE
};
static int storage_open(const bt_addr_le_t *addr, u16_t key,
enum storage_access access, fs_file_t *file)
{
char path[STORAGE_PATH_MAX];
if (addr) {
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
int len;
len = snprintk(path, sizeof(path),
STORAGE_ROOT "/%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%u",
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type);
/* Create the subdirectory if necessary */
if (access == STORAGE_WRITE) {
struct fs_dirent entry;
int err;
err = fs_stat(path, &entry);
if (err) {
err = fs_mkdir(path);
if (err) {
return err;
}
}
}
snprintk(path + len, sizeof(path) - len, "/%04x", key);
#else
return -ENAMETOOLONG;
#endif
} else {
snprintk(path, sizeof(path), STORAGE_ROOT "/%04x", key);
}
return fs_open(file, path);
}
static ssize_t storage_read(const bt_addr_le_t *addr, u16_t key, void *data,
size_t length)
{
fs_file_t file;
ssize_t ret;
ret = storage_open(addr, key, STORAGE_READ, &file);
if (ret) {
return ret;
}
ret = fs_read(&file, data, length);
fs_close(&file);
return ret;
}
static ssize_t storage_write(const bt_addr_le_t *addr, u16_t key,
const void *data, size_t length)
{
fs_file_t file;
ssize_t ret;
ret = storage_open(addr, key, STORAGE_WRITE, &file);
if (ret) {
return ret;
}
ret = fs_write(&file, data, length);
fs_close(&file);
return ret;
}
static int unlink_recursive(char path[STORAGE_PATH_MAX])
{
size_t path_len;
fs_dir_t dir;
int err;
err = fs_opendir(&dir, path);
if (err) {
return err;
}
/* We calculate this up-front so we can keep reusing the same
* buffer for the path when recursing.
*/
path_len = strlen(path);
while (1) {
struct fs_dirent entry;
err = fs_readdir(&dir, &entry);
if (err) {
break;
}
if (entry.name[0] == '\0') {
break;
}
snprintk(path + path_len, STORAGE_PATH_MAX - path_len, "/%s",
entry.name);
if (entry.type == FS_DIR_ENTRY_DIR) {
err = unlink_recursive(path);
} else {
err = fs_unlink(path);
}
if (err) {
break;
}
}
fs_closedir(&dir);
/* Return to the original value */
path[path_len] = '\0';
fs_unlink(path);
return err;
}
static int storage_clear(const bt_addr_le_t *addr)
{
char path[STORAGE_PATH_MAX];
int err;
if (addr) {
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
snprintk(path, STORAGE_PATH_MAX,
STORAGE_ROOT "/%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X%u",
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type);
return unlink_recursive(path);
#else
return -ENAMETOOLONG;
#endif
}
/* unlink_recursive() uses the given path as a buffer for
* constructing sub-paths, so we can't give it a string literal
* such as STORAGE_ROOT directly.
*/
strcpy(path, STORAGE_ROOT);
err = unlink_recursive(path);
if (err) {
return err;
}
return fs_mkdir(STORAGE_ROOT);
}
static int storage_init(struct device *unused)
{
static const struct bt_storage storage = {
.read = storage_read,
.write = storage_write,
.clear = storage_clear
};
struct fs_dirent entry;
int err;
err = fs_stat(STORAGE_ROOT, &entry);
if (err) {
BT_WARN("%s doesn't seem to exist (err %d). Creating it.",
STORAGE_ROOT, err);
err = fs_mkdir(STORAGE_ROOT);
if (err) {
BT_ERR("Unable to create %s (err %d)",
STORAGE_ROOT, err);
return err;
}
}
bt_storage_register(&storage);
return 0;
}
SYS_INIT(storage_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);