878 lines
16 KiB
C
878 lines
16 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation.
|
|
* Copyright (c) 2020 Peter Bigot Consulting, LLC
|
|
* Copyright (c) 2020-2024 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <zephyr/types.h>
|
|
#include <errno.h>
|
|
#include <zephyr/init.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/fs/fs.h>
|
|
#include <zephyr/fs/fs_sys.h>
|
|
#include <zephyr/sys/check.h>
|
|
|
|
|
|
#define LOG_LEVEL CONFIG_FS_LOG_LEVEL
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(fs);
|
|
|
|
/* list of mounted file systems */
|
|
static sys_dlist_t fs_mnt_list = SYS_DLIST_STATIC_INIT(&fs_mnt_list);
|
|
|
|
/* lock to protect mount list operations */
|
|
static K_MUTEX_DEFINE(mutex);
|
|
|
|
/* Maps an identifier used in mount points to the file system
|
|
* implementation.
|
|
*/
|
|
struct registry_entry {
|
|
int type;
|
|
const struct fs_file_system_t *fstp;
|
|
};
|
|
static struct registry_entry registry[CONFIG_FILE_SYSTEM_MAX_TYPES];
|
|
|
|
static inline void registry_clear_entry(struct registry_entry *ep)
|
|
{
|
|
ep->fstp = NULL;
|
|
}
|
|
|
|
static int registry_add(int type,
|
|
const struct fs_file_system_t *fstp)
|
|
{
|
|
int rv = -ENOSPC;
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(registry); ++i) {
|
|
struct registry_entry *ep = ®istry[i];
|
|
|
|
if (ep->fstp == NULL) {
|
|
ep->type = type;
|
|
ep->fstp = fstp;
|
|
rv = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
static struct registry_entry *registry_find(int type)
|
|
{
|
|
for (size_t i = 0; i < ARRAY_SIZE(registry); ++i) {
|
|
struct registry_entry *ep = ®istry[i];
|
|
|
|
if ((ep->fstp != NULL) && (ep->type == type)) {
|
|
return ep;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static const struct fs_file_system_t *fs_type_get(int type)
|
|
{
|
|
struct registry_entry *ep = registry_find(type);
|
|
|
|
return (ep != NULL) ? ep->fstp : NULL;
|
|
}
|
|
|
|
static int fs_get_mnt_point(struct fs_mount_t **mnt_pntp,
|
|
const char *name, size_t *match_len)
|
|
{
|
|
struct fs_mount_t *mnt_p = NULL, *itr;
|
|
size_t longest_match = 0;
|
|
size_t len, name_len = strlen(name);
|
|
sys_dnode_t *node;
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
|
|
itr = CONTAINER_OF(node, struct fs_mount_t, node);
|
|
len = itr->mountp_len;
|
|
|
|
/*
|
|
* Move to next node if mount point length is
|
|
* shorter than longest_match match or if path
|
|
* name is shorter than the mount point name.
|
|
*/
|
|
if ((len < longest_match) || (len > name_len)) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Move to next node if name does not have a directory
|
|
* separator where mount point name ends.
|
|
*/
|
|
if ((len > 1) && (name[len] != '/') && (name[len] != '\0')) {
|
|
continue;
|
|
}
|
|
|
|
/* Check for mount point match */
|
|
if (strncmp(name, itr->mnt_point, len) == 0) {
|
|
mnt_p = itr;
|
|
longest_match = len;
|
|
}
|
|
}
|
|
k_mutex_unlock(&mutex);
|
|
|
|
if (mnt_p == NULL) {
|
|
return -ENOENT;
|
|
}
|
|
|
|
*mnt_pntp = mnt_p;
|
|
if (match_len) {
|
|
*match_len = mnt_p->mountp_len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* File operations */
|
|
int fs_open(struct fs_file_t *zfp, const char *file_name, fs_mode_t flags)
|
|
{
|
|
struct fs_mount_t *mp;
|
|
int rc = -EINVAL;
|
|
|
|
if ((file_name == NULL) ||
|
|
(strlen(file_name) <= 1) || (file_name[0] != '/')) {
|
|
LOG_ERR("invalid file name!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (zfp->mp != NULL) {
|
|
return -EBUSY;
|
|
}
|
|
|
|
rc = fs_get_mnt_point(&mp, file_name, NULL);
|
|
if (rc < 0) {
|
|
LOG_ERR("mount point not found!!");
|
|
return rc;
|
|
}
|
|
|
|
if (((mp->flags & FS_MOUNT_FLAG_READ_ONLY) != 0) &&
|
|
(flags & FS_O_CREATE || flags & FS_O_WRITE)) {
|
|
return -EROFS;
|
|
}
|
|
|
|
CHECKIF(mp->fs->open == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
zfp->mp = mp;
|
|
rc = mp->fs->open(zfp, file_name, flags);
|
|
if (rc < 0) {
|
|
LOG_ERR("file open error (%d)", rc);
|
|
zfp->mp = NULL;
|
|
return rc;
|
|
}
|
|
|
|
/* Copy flags to zfp for use with other fs_ API calls */
|
|
zfp->flags = flags;
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_close(struct fs_file_t *zfp)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (zfp->mp == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
CHECKIF(zfp->mp->fs->close == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zfp->mp->fs->close(zfp);
|
|
if (rc < 0) {
|
|
LOG_ERR("file close error (%d)", rc);
|
|
return rc;
|
|
}
|
|
|
|
zfp->mp = NULL;
|
|
|
|
return rc;
|
|
}
|
|
|
|
ssize_t fs_read(struct fs_file_t *zfp, void *ptr, size_t size)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (zfp->mp == NULL) {
|
|
return -EBADF;
|
|
}
|
|
|
|
CHECKIF(zfp->mp->fs->read == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zfp->mp->fs->read(zfp, ptr, size);
|
|
if (rc < 0) {
|
|
LOG_ERR("file read error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
ssize_t fs_write(struct fs_file_t *zfp, const void *ptr, size_t size)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (zfp->mp == NULL) {
|
|
return -EBADF;
|
|
}
|
|
|
|
CHECKIF(zfp->mp->fs->write == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zfp->mp->fs->write(zfp, ptr, size);
|
|
if (rc < 0) {
|
|
LOG_ERR("file write error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_seek(struct fs_file_t *zfp, off_t offset, int whence)
|
|
{
|
|
int rc = -ENOTSUP;
|
|
|
|
if (zfp->mp == NULL) {
|
|
return -EBADF;
|
|
}
|
|
|
|
CHECKIF(zfp->mp->fs->lseek == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zfp->mp->fs->lseek(zfp, offset, whence);
|
|
if (rc < 0) {
|
|
LOG_ERR("file seek error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
off_t fs_tell(struct fs_file_t *zfp)
|
|
{
|
|
int rc = -ENOTSUP;
|
|
|
|
if (zfp->mp == NULL) {
|
|
return -EBADF;
|
|
}
|
|
|
|
CHECKIF(zfp->mp->fs->tell == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zfp->mp->fs->tell(zfp);
|
|
if (rc < 0) {
|
|
LOG_ERR("file tell error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_truncate(struct fs_file_t *zfp, off_t length)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (zfp->mp == NULL) {
|
|
return -EBADF;
|
|
}
|
|
|
|
CHECKIF(zfp->mp->fs->truncate == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zfp->mp->fs->truncate(zfp, length);
|
|
if (rc < 0) {
|
|
LOG_ERR("file truncate error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_sync(struct fs_file_t *zfp)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (zfp->mp == NULL) {
|
|
return -EBADF;
|
|
}
|
|
|
|
CHECKIF(zfp->mp->fs->sync == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zfp->mp->fs->sync(zfp);
|
|
if (rc < 0) {
|
|
LOG_ERR("file sync error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* Directory operations */
|
|
int fs_opendir(struct fs_dir_t *zdp, const char *abs_path)
|
|
{
|
|
struct fs_mount_t *mp;
|
|
int rc = -EINVAL;
|
|
|
|
if ((abs_path == NULL) ||
|
|
(strlen(abs_path) < 1) || (abs_path[0] != '/')) {
|
|
LOG_ERR("invalid directory name!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (zdp->mp != NULL || zdp->dirp != NULL) {
|
|
return -EBUSY;
|
|
}
|
|
|
|
|
|
if (strcmp(abs_path, "/") == 0) {
|
|
/* Open VFS root dir, marked by zdp->mp == NULL */
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
zdp->mp = NULL;
|
|
zdp->dirp = sys_dlist_peek_head(&fs_mnt_list);
|
|
|
|
k_mutex_unlock(&mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
rc = fs_get_mnt_point(&mp, abs_path, NULL);
|
|
if (rc < 0) {
|
|
LOG_ERR("mount point not found!!");
|
|
return rc;
|
|
}
|
|
|
|
CHECKIF(mp->fs->opendir == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
zdp->mp = mp;
|
|
rc = zdp->mp->fs->opendir(zdp, abs_path);
|
|
if (rc < 0) {
|
|
zdp->mp = NULL;
|
|
zdp->dirp = NULL;
|
|
LOG_ERR("directory open error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry)
|
|
{
|
|
if (zdp->mp) {
|
|
/* Delegate to mounted filesystem */
|
|
int rc = -EINVAL;
|
|
|
|
CHECKIF(zdp->mp->fs->readdir == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
/* Loop until error or not special directory */
|
|
while (true) {
|
|
rc = zdp->mp->fs->readdir(zdp, entry);
|
|
if (rc < 0) {
|
|
break;
|
|
}
|
|
if (entry->name[0] == 0) {
|
|
break;
|
|
}
|
|
if (entry->type != FS_DIR_ENTRY_DIR) {
|
|
break;
|
|
}
|
|
if ((strcmp(entry->name, ".") != 0)
|
|
&& (strcmp(entry->name, "..") != 0)) {
|
|
break;
|
|
}
|
|
}
|
|
if (rc < 0) {
|
|
LOG_ERR("directory read error (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* VFS root dir */
|
|
if (zdp->dirp == NULL) {
|
|
/* No more entries */
|
|
entry->name[0] = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* Find the current and next entries in the mount point dlist */
|
|
sys_dnode_t *node, *next = NULL;
|
|
bool found = false;
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
|
|
if (node == zdp->dirp) {
|
|
found = true;
|
|
|
|
/* Pull info from current entry */
|
|
struct fs_mount_t *mnt;
|
|
|
|
mnt = CONTAINER_OF(node, struct fs_mount_t, node);
|
|
|
|
entry->type = FS_DIR_ENTRY_DIR;
|
|
strncpy(entry->name, mnt->mnt_point + 1,
|
|
sizeof(entry->name) - 1);
|
|
entry->name[sizeof(entry->name) - 1] = 0;
|
|
entry->size = 0;
|
|
|
|
/* Save pointer to the next one, for later */
|
|
next = sys_dlist_peek_next(&fs_mnt_list, node);
|
|
break;
|
|
}
|
|
}
|
|
|
|
k_mutex_unlock(&mutex);
|
|
|
|
if (!found) {
|
|
/* Current entry must have been removed before this
|
|
* call to readdir -- return an error
|
|
*/
|
|
return -ENOENT;
|
|
}
|
|
|
|
zdp->dirp = next;
|
|
return 0;
|
|
}
|
|
|
|
int fs_closedir(struct fs_dir_t *zdp)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (zdp->mp == NULL) {
|
|
/* VFS root dir */
|
|
zdp->dirp = NULL;
|
|
return 0;
|
|
}
|
|
|
|
CHECKIF(zdp->mp->fs->closedir == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = zdp->mp->fs->closedir(zdp);
|
|
if (rc < 0) {
|
|
LOG_ERR("directory close error (%d)", rc);
|
|
return rc;
|
|
}
|
|
|
|
zdp->mp = NULL;
|
|
zdp->dirp = NULL;
|
|
return rc;
|
|
}
|
|
|
|
/* Filesystem operations */
|
|
int fs_mkdir(const char *abs_path)
|
|
{
|
|
struct fs_mount_t *mp;
|
|
int rc = -EINVAL;
|
|
|
|
if ((abs_path == NULL) ||
|
|
(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
|
|
LOG_ERR("invalid directory name!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = fs_get_mnt_point(&mp, abs_path, NULL);
|
|
if (rc < 0) {
|
|
LOG_ERR("mount point not found!!");
|
|
return rc;
|
|
}
|
|
|
|
if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
|
|
return -EROFS;
|
|
}
|
|
|
|
CHECKIF(mp->fs->mkdir == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = mp->fs->mkdir(mp, abs_path);
|
|
if (rc < 0) {
|
|
LOG_ERR("failed to create directory (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_unlink(const char *abs_path)
|
|
{
|
|
struct fs_mount_t *mp;
|
|
int rc = -EINVAL;
|
|
|
|
if ((abs_path == NULL) ||
|
|
(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
|
|
LOG_ERR("invalid file name!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = fs_get_mnt_point(&mp, abs_path, NULL);
|
|
if (rc < 0) {
|
|
LOG_ERR("mount point not found!!");
|
|
return rc;
|
|
}
|
|
|
|
if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
|
|
return -EROFS;
|
|
}
|
|
|
|
CHECKIF(mp->fs->unlink == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = mp->fs->unlink(mp, abs_path);
|
|
if (rc < 0) {
|
|
LOG_ERR("failed to unlink path (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_rename(const char *from, const char *to)
|
|
{
|
|
struct fs_mount_t *mp;
|
|
size_t match_len;
|
|
int rc = -EINVAL;
|
|
|
|
if ((from == NULL) || (strlen(from) <= 1) || (from[0] != '/') ||
|
|
(to == NULL) || (strlen(to) <= 1) || (to[0] != '/')) {
|
|
LOG_ERR("invalid file name!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = fs_get_mnt_point(&mp, from, &match_len);
|
|
if (rc < 0) {
|
|
LOG_ERR("mount point not found!!");
|
|
return rc;
|
|
}
|
|
|
|
if (mp->flags & FS_MOUNT_FLAG_READ_ONLY) {
|
|
return -EROFS;
|
|
}
|
|
|
|
/* Make sure both files are mounted on the same path */
|
|
if (strncmp(from, to, match_len) != 0) {
|
|
LOG_ERR("mount point not same!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
CHECKIF(mp->fs->rename == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = mp->fs->rename(mp, from, to);
|
|
if (rc < 0) {
|
|
LOG_ERR("failed to rename file or dir (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_stat(const char *abs_path, struct fs_dirent *entry)
|
|
{
|
|
struct fs_mount_t *mp;
|
|
int rc = -EINVAL;
|
|
|
|
if ((abs_path == NULL) ||
|
|
(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
|
|
LOG_ERR("invalid file or dir name!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = fs_get_mnt_point(&mp, abs_path, NULL);
|
|
if (rc < 0) {
|
|
LOG_ERR("mount point not found!!");
|
|
return rc;
|
|
}
|
|
|
|
CHECKIF(mp->fs->stat == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = mp->fs->stat(mp, abs_path, entry);
|
|
if (rc == -ENOENT) {
|
|
/* File doesn't exist, which is a valid stat response */
|
|
} else if (rc < 0) {
|
|
LOG_ERR("failed get file or dir stat (%d)", rc);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int fs_statvfs(const char *abs_path, struct fs_statvfs *stat)
|
|
{
|
|
struct fs_mount_t *mp;
|
|
int rc;
|
|
|
|
if ((abs_path == NULL) ||
|
|
(strlen(abs_path) <= 1) || (abs_path[0] != '/')) {
|
|
LOG_ERR("invalid file or dir name!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = fs_get_mnt_point(&mp, abs_path, NULL);
|
|
if (rc < 0) {
|
|
LOG_ERR("mount point not found!!");
|
|
return rc;
|
|
}
|
|
|
|
CHECKIF(mp->fs->statvfs == NULL) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
rc = mp->fs->statvfs(mp, abs_path, stat);
|
|
if (rc < 0) {
|
|
LOG_ERR("failed get file or dir stat (%d)", rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int fs_mount(struct fs_mount_t *mp)
|
|
{
|
|
struct fs_mount_t *itr;
|
|
const struct fs_file_system_t *fs;
|
|
sys_dnode_t *node;
|
|
int rc = -EINVAL;
|
|
size_t len = 0;
|
|
|
|
/* Do all the mp checks prior to locking the mutex on the file
|
|
* subsystem.
|
|
*/
|
|
if ((mp == NULL) || (mp->mnt_point == NULL)) {
|
|
LOG_ERR("mount point not initialized!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sys_dnode_is_linked(&mp->node)) {
|
|
LOG_ERR("file system already mounted!!");
|
|
return -EBUSY;
|
|
}
|
|
|
|
len = strlen(mp->mnt_point);
|
|
|
|
if ((len <= 1) || (mp->mnt_point[0] != '/')) {
|
|
LOG_ERR("invalid mount point!!");
|
|
return -EINVAL;
|
|
}
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
/* Check if mount point already exists */
|
|
SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
|
|
itr = CONTAINER_OF(node, struct fs_mount_t, node);
|
|
/* continue if length does not match */
|
|
if (len != itr->mountp_len) {
|
|
continue;
|
|
}
|
|
|
|
CHECKIF(mp->fs_data == itr->fs_data) {
|
|
LOG_ERR("file system already mounted!!");
|
|
rc = -EBUSY;
|
|
goto mount_err;
|
|
}
|
|
|
|
if (strncmp(mp->mnt_point, itr->mnt_point, len) == 0) {
|
|
LOG_ERR("mount point already exists!!");
|
|
rc = -EBUSY;
|
|
goto mount_err;
|
|
}
|
|
}
|
|
|
|
/* Get file system information */
|
|
fs = fs_type_get(mp->type);
|
|
if (fs == NULL) {
|
|
LOG_ERR("requested file system type not registered!!");
|
|
rc = -ENOENT;
|
|
goto mount_err;
|
|
}
|
|
|
|
CHECKIF(fs->mount == NULL) {
|
|
LOG_ERR("fs type %d does not support mounting", mp->type);
|
|
rc = -ENOTSUP;
|
|
goto mount_err;
|
|
}
|
|
|
|
if (fs->unmount == NULL) {
|
|
LOG_WRN("mount path %s is not unmountable",
|
|
mp->mnt_point);
|
|
}
|
|
|
|
rc = fs->mount(mp);
|
|
if (rc < 0) {
|
|
LOG_ERR("fs mount error (%d)", rc);
|
|
goto mount_err;
|
|
}
|
|
|
|
/* Update mount point data and append it to the list */
|
|
mp->mountp_len = len;
|
|
mp->fs = fs;
|
|
|
|
sys_dlist_append(&fs_mnt_list, &mp->node);
|
|
LOG_DBG("fs mounted at %s", mp->mnt_point);
|
|
|
|
mount_err:
|
|
k_mutex_unlock(&mutex);
|
|
return rc;
|
|
}
|
|
|
|
#if defined(CONFIG_FILE_SYSTEM_MKFS)
|
|
|
|
int fs_mkfs(int fs_type, uintptr_t dev_id, void *cfg, int flags)
|
|
{
|
|
int rc = -EINVAL;
|
|
const struct fs_file_system_t *fs;
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
/* Get file system information */
|
|
fs = fs_type_get(fs_type);
|
|
if (fs == NULL) {
|
|
LOG_ERR("fs type %d not registered!!",
|
|
fs_type);
|
|
rc = -ENOENT;
|
|
goto mount_err;
|
|
}
|
|
|
|
CHECKIF(fs->mkfs == NULL) {
|
|
LOG_ERR("fs type %d does not support mkfs", fs_type);
|
|
rc = -ENOTSUP;
|
|
goto mount_err;
|
|
}
|
|
|
|
rc = fs->mkfs(dev_id, cfg, flags);
|
|
if (rc < 0) {
|
|
LOG_ERR("mkfs error (%d)", rc);
|
|
goto mount_err;
|
|
}
|
|
|
|
mount_err:
|
|
k_mutex_unlock(&mutex);
|
|
return rc;
|
|
}
|
|
|
|
#endif /* CONFIG_FILE_SYSTEM_MKFS */
|
|
|
|
int fs_unmount(struct fs_mount_t *mp)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (mp == NULL) {
|
|
return rc;
|
|
}
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
if (!sys_dnode_is_linked(&mp->node)) {
|
|
LOG_ERR("fs not mounted (mp == %p)", mp);
|
|
goto unmount_err;
|
|
}
|
|
|
|
CHECKIF(mp->fs->unmount == NULL) {
|
|
LOG_ERR("fs unmount not supported!!");
|
|
rc = -ENOTSUP;
|
|
goto unmount_err;
|
|
}
|
|
|
|
rc = mp->fs->unmount(mp);
|
|
if (rc < 0) {
|
|
LOG_ERR("fs unmount error (%d)", rc);
|
|
goto unmount_err;
|
|
}
|
|
|
|
/* clear file system interface */
|
|
mp->fs = NULL;
|
|
|
|
/* remove mount node from the list */
|
|
sys_dlist_remove(&mp->node);
|
|
LOG_DBG("fs unmounted from %s", mp->mnt_point);
|
|
|
|
unmount_err:
|
|
k_mutex_unlock(&mutex);
|
|
return rc;
|
|
}
|
|
|
|
int fs_readmount(int *index, const char **name)
|
|
{
|
|
sys_dnode_t *node;
|
|
int rc = -ENOENT;
|
|
int cnt = 0;
|
|
struct fs_mount_t *itr = NULL;
|
|
|
|
*name = NULL;
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) {
|
|
if (*index == cnt) {
|
|
itr = CONTAINER_OF(node, struct fs_mount_t, node);
|
|
break;
|
|
}
|
|
|
|
++cnt;
|
|
}
|
|
|
|
k_mutex_unlock(&mutex);
|
|
|
|
if (itr != NULL) {
|
|
rc = 0;
|
|
*name = itr->mnt_point;
|
|
++(*index);
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
/* Register File system */
|
|
int fs_register(int type, const struct fs_file_system_t *fs)
|
|
{
|
|
int rc = 0;
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
if (fs_type_get(type) != NULL) {
|
|
rc = -EALREADY;
|
|
} else {
|
|
rc = registry_add(type, fs);
|
|
}
|
|
|
|
k_mutex_unlock(&mutex);
|
|
|
|
LOG_DBG("fs register %d: %d", type, rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* Unregister File system */
|
|
int fs_unregister(int type, const struct fs_file_system_t *fs)
|
|
{
|
|
int rc = 0;
|
|
struct registry_entry *ep;
|
|
|
|
k_mutex_lock(&mutex, K_FOREVER);
|
|
|
|
ep = registry_find(type);
|
|
if ((ep == NULL) || (ep->fstp != fs)) {
|
|
rc = -EINVAL;
|
|
} else {
|
|
registry_clear_entry(ep);
|
|
}
|
|
|
|
k_mutex_unlock(&mutex);
|
|
|
|
LOG_DBG("fs unregister %d: %d", type, rc);
|
|
return rc;
|
|
}
|