From 78e3621d37847476e4c9f69d996f18fd7ae38dd1 Mon Sep 17 00:00:00 2001 From: Martin Lenders Date: Tue, 3 Jun 2014 16:16:59 +0200 Subject: [PATCH 1/5] fs: Start filesystem module --- sys/fs/Makefile | 3 + sys/fs/fs.c | 71 +++++++++ sys/include/fs.h | 377 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 451 insertions(+) create mode 100644 sys/fs/Makefile create mode 100644 sys/fs/fs.c create mode 100644 sys/include/fs.h diff --git a/sys/fs/Makefile b/sys/fs/Makefile new file mode 100644 index 000000000000..252c37b58634 --- /dev/null +++ b/sys/fs/Makefile @@ -0,0 +1,3 @@ +MODULE = fs + +include $(RIOTBASE)/Makefile.base diff --git a/sys/fs/fs.c b/sys/fs/fs.c new file mode 100644 index 000000000000..9e8d4b600ad9 --- /dev/null +++ b/sys/fs/fs.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ +#include +#include + +#include "fs.h" +#include "scfs.h" + +static fs_table_t fs_table[FS_TABLE_SIZE]; + +const fs_op_table_t fs_op_table[1]; + +static fs_table_t *fs_search_entry(const char *path) +{ + fs_table_t *tmp = NULL; + + for (int i = 0; i < FS_TABLE_SIZE; i++) { + if (!strncmp(fs_table[i].mount_point, padg, + strlen(fs_table[i].mount_point))) { + tmp = &(fs_table[i]); + } + } + + return tmp; +} + +int fs_mount(const char *mount_point, int device, fs_type_t type) +{ + if (strlen(mount_point) + 1 > FS_MOUNT_POINT_LEN) { + errno = ENAMETOOLONG; + return -ENAMETOOLONG; + } + + for (int i = 0; fs_table[i].type != FS_NONE && i < FS_TABLE_SIZE; i++); + + if (i == FS_TABLE_SIZE) { + errno = ENOMEM; + return -ENOMEM; + } + + memcpy(fs_table[i].mount_point, mount_point, FS_MOUNT_POINT_LEN); + fs_table[i].device = device; + fs_table[i].type = type; + + int 1; +} + +int fs_unmount(const char *mount_point, int device) +{ + if (!mount_point && !device) { + errno = ENOENT; + return -ENOENT; + } + + for (int i = 0; i < FS_TABLE_SIZE; i++) { + if ((device && fs_table[i].device == device) || + (mount_point && !strncmp(fs_table[i].mount_point, mount_point, + strlen(fs_table[i].mount_point)))) { + fs_table[i].type = FS_NONE; + return 0; + } + } + + errno = EINVAL; + return -EINVAL; +} diff --git a/sys/include/fs.h b/sys/include/fs.h new file mode 100644 index 000000000000..76195da4d146 --- /dev/null +++ b/sys/include/fs.h @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup fs Filesystems + * @brief Filesystem implementations, inspired by FUSE + * @ingroup sys + * @{ + * + * @file fs.h + * @brief Common functionalities for filesytems + * + * @author Freie Universität Berlin + * @author Martine Lenders + */ +#ifndef __FS_H_ +#define __FS_H_ +#include + +/** + * @brief Allowed length of a mount point + */ +#define FS_MOUNT_POINT_LEN (16) + +/** + * @brief Size of the filesystem table. + */ +#define FS_TABLE_SIZE (1) + +/** + * @brief Number of byte fs_file_info_t can be extended by an implementation + */ +#define FS_FILE_INFO_EXT_SIZE (2) + +typedef int fid_t; + +typedef enum { + FS_NONE = 0; +} fs_type_t; + +/** + * @brief Filesystem table. + */ +typedef struct { + char mount_point[FS_MOUNT_POINT_LEN]; /**< mount point of the filesystem */ + int device; /**< device the filesystem is on */ + fs_type_t type; /**< type of the filesystem */ +} fs_table_t; + +/** + * @brief an extendable file information type + */ +typedef struct { + int flags; /**< Flags provided to fs_op_table_t::open() + fs_op_table_t::release() */ + uint8_t ext[FS_FILE_INFO_EXT_SIZE]; /**< Filesystem specific extensions */ +} fs_file_info_t; + +/** + * @brief Operation type for fs_op_table_t::flock() + */ +typedef enum { + FS_LOCK_SH = 0; /**< Place a shared lock. More then one thread may hold a + shared lock for a given file at a given time */ + FS_LOCK_EX; /**< Place an exclusive lock. Only one thread may hold an + exclusive lock for a given file at given time */ + FS_LOCK_UN; /**< Remove an existing lock held by this process */ +} fs_lock_op_t + +/** + * @brief Table of operations for a filesystem + */ +typedef struct { + /** + * @brief Determines accessibility of a file. + * + * @param[in] path Path to a file + * @param[in] amode Accessibility flags to check + * (bitwise-inclusive OR of R_OK, W_OK, or X_OK or existence + * check with F_OK) + * + * @return 0 if successful + * @return -EACCESS, if the requested acces would be denied to the file, or + * search permission is denied for one of the directories + * in the path prefix of *path* + * @return -ELOOP, if too many symbolic links were encountered in resolving + * *path* + * @return -ENAMETOOLONG, if *path* is too long + * @return -ENOENT, if a component of *path* does not exist or is a + * dangling symbolic link + * @return -ENOTDIR, if a component of used as a directory in *path* is not, + * in fact, a directory + * @return -EROFS, if write perission was requested for a file on a + * read-only filesystem + * @return -EINVAL, if *amode* was incorrectly specified + * @return -EIO, if an I/O error occured + * @return -ETXTBSY, if write access was requested to an executable which + * is being executed + */ + int (*access)(const char *path, int amode); + + /** + * @brief Changes mode of a file. + * + * On error there are no changes made to the file. + OA* + * @param[in] path Path to a file + * @param[in] mode Mode to set + * + * @return 0 if successful + * @return -EACCES, if search permission is denied on a component of the + * path prefix of *path* + * @return -EFAULT, if *path* points outside your accessible address space + * @return -EIO, if an I/O error occured. + * @return -ELOOP, if too many symbolic links were encountered in resolving + * *path* + * @return -ENAMETOOLONG, if *path* is too long + * @return -ENOENT, if file referred to by *path* does not exist + * @return -ENOTDIR, if a component used as a directory in *path* is not, + * in fact, a directory + */ + int (*chmod)(const char *path, mode_t mode); + + /** + * @brief Creates file with mode. + * + * @param[in] path Path to the file + * @param[in] mode Mode to set + * @param[out] info Information about the file. Can be set by create. + * + * @return 0, on success + * @return -EACCES, if the parent directory does not allow write permission + * or one of the directories in the path prefix of *path* + * did not allow search permission + * @return -EDQUOT, if the user's quota of disk blocks or inodes on the + * filesystem has been exhausted + * @return -EEXIST, if *path* already exists. This includes the case where + * *path* is a symbolic link, dangling or not + * @return -ELOOP, if too many symbolic links were encountered in resolving + * *path* + * @return -ENAMETOOLONG, if *path* was too long + * @return -ENOENT, if a directory componenent in *path* does not exist or + * is a dangling symbolic link + * @return -ENOSPC, if the device containing *path* has no room for a new + * node + * @return -ENOTDIR, if a component used as a directory in *path* is not, + * in fact, a directory + * @return -EPERM, if *mode* requested creation of something other than + * a regular file, or FIFO (named pipe); also returned + * if the filesystem does not support type of node + * requested + * @return -EROFS, if filesystem is read-only. + */ + int (*create)(const char *path, mode_t mode, fs_file_info_t *info); + + /** + * @brief Called on filesystem exit. + */ + void (*destroy)(void); + + /** + * @brief Executes file at given path. + * + * @param[in] path Path to executable file + * @param[in] envp NULL terminated array of environment variables in + * the format "key=value" + * @param[in] argv NULL terminated array of arguments for the executable + * @param[out] out Return value of executable + * + * @return 0, on success + * @return TODO, error codes + */ + int (*execve)(const char *path, char *envp[], char *argv[], int *out); + + /** + * @brief Allocate requested space. + * + * If this function returns success then subsequent writes to the specified + * range shall not fail due to the lack of free space on the file system + * storage media. + * + * @param[in] path Path to file. + * @param[in] offset Starting point for allocated region + * @param[in] length Size of allocated region + * @param[in,out] info File information handed by filesystem API + * + * @return 0, on success + * @return -EBADF, if *path* is not a valid file or not open for writing + * @return -EFBIG, if *offset* + *length* exeeds the maximum file size + * @return -EINTR, if a signal was cought during execution + * @return -EINVAL, if *offset* or *length* were less than or equal to 0. + * @return -EIO, if an I/O error occured while reading from or writing to + * a filestem + * @return -ENOSPC, if the is not enough space left on the device + * containing the file referred to by *path* + * @return -EOPNOSUPP, if the filesystem containing the file referred to + * by *path* does not support this operation + * @return -EPERM, if the file referred to by *path* is marked immutable + * @return -ESPIPE, if *path* refers to a pipe or FIFO + */ + int (*fallocate)(const char *path, off_t offset, off_t length, + fs_file_info_t *info); + + /** + * @brief apply or remove an advisory lock on an open file + * + * @param[in] path Path to file + * @param[in] op Locking operation to perform + * (see fs_lock_op_t) + * @param[in,out] info File information handed by filesystem API + * + * @return 0, on success + * @return TODO, error codes + */ + int (*flock)(const char *path, fs_lock_op_t op, fs_file_info_t *info); + + /** + * @brief Get attributes from an open file. + * + * This function is called instead of fs_op_table_t::getattr() if file + * information is available. + * + * @return 0, on success. + * @return TODO: error codes + */ + int (*fstat)(const char *path, struct stat *stat, fs_file_info_t *info); + + /** + * Synchronize file contents + * + * @param[in] path Path to file + * @param[in,out] info File information handed by filesystem API + * + * @return 0 on success, + * @return TODO error codes + */ + int (*fsync)(const char *, fs_file_info_t *info); + + /** + * Synchronize directory contents + * + * @param[in] path Path to directory + * @param[in,out] info File information handed by filesystem API + * + * @return 0 on success, + * @return TODO error codes + */ + int (*fsyncdir)(const char *, fs_file_info_t *); + + /** + * Initializes the filesystem + */ + void (*init)(void); + + /** + * Create a hard link to a file + * + * @param[in] src_path Path name of source file + * @param[in] tgt_path Path name of the link to create + * + * @return 0 on success, + * @return TODO error codes + */ + int (*link)(const char *src_path, const char *tgt_path); + + /** + * Crete a new directory + * + * @param[in] path Path to the new directory + * @param[in] mode Mode to set the new directory to + * + * @return 0 on success, + * @return TODO error codes + */ + int (*mkdir)(const char *path, mode_t mode); + + /** + * @brief Creates file node (reqular file, character device, block device, + * fifo, ...) + * + * If file system implements fs_op_table_t::create() this will be used + * instead for reqular files + * + * @param[in] path Path to the new file node + * @param[in] mode Mode to set the new file node to + * @param[in] rdev Device number (if the call creates a device) + * + * @return 0 on success, + * @return TODO error codes + */ + int (*mknod)(const char *path, mode_t mode, dev_t rdev); + + /** + * @brief Opens a file. + * + * Flags can be passed via *info*::flags + * + * @param[in] path Path to the file. + * @param[in,out] info File information handed by filesystem API + * + * @return positive file id on success, + * @return TODO error codes + */ + fid_t (*open)(const char *path, fs_file_info_t *info); + + /** + * @brief Opens a directory. + * + * @param[in] path Path to the directory. + * @param[in,out] info File information handed by the filesystem API. + * + * @return positive file id on success, + * @return TODO error codes + */ + fid_t (*opendir)(const char *path, fs_file_info_t *info); + + /** + * @brief Read from a file + * + * @param[in] path Path to file. + * @param[out] buf Buffer to be filled. + * @param[in] size Size of *buf*. + * @param[in] offset Offset in *buf*. + * @param[in,out] info File information handed by the filesystem API. + */ + int (*read)(const char *path, char *buf, size_t size, off_t offset, + fs_file_info_t *info); + + int (*readdir)(const char *path, void *); // TODO + + /** + * TODO + int (*readlink)(const char *, char *, size_t); + int (*release)(const char *); + int (*releasedir)(const char *); + int (*rename)(const char *, const char *); + int (*rmdir)(const char *); + int (*stat)(const char*, struct stat *); + int (*statfs)(const char *, struct statvfs *); + int (*symlink)(const char *, const char *); + int (*truncate)(const char *, off_t); + int (*unlink)(const char *); + int (*utimens)(const char *, const struct timespec tv[2]); + int (*write)(const char *, const char *, size_t, off_t); + int (*write_buf)(const char *, off_t off); + */ +} fs_op_table_t; + +/** + * @brief The operation table for various file systems + * @internal + * + * For internal use only + */ +extern const fs_op_table_t fs_op_table[1]; + +/** + * @brief Searches a filesystem table entry based on the name + * of the path + * + * @internal + * + * For internal use only. + * + * @param[in] pathname The path to search. + * + * @return Filesystem table entry for the filesystem the file referenced by + * pathname is in. NULL if no entry is found. + */ +fs_table_t *fs_search_entry(const char *pathname); + +#endif /* __FS_H_ */ From 214984e280afbd1bd5aa901392a38add8a7d91a9 Mon Sep 17 00:00:00 2001 From: Martin Lenders Date: Tue, 15 Jul 2014 15:15:33 +0200 Subject: [PATCH 2/5] [SQUASH ME] Use strncpy instead of memcpy to copy strings --- sys/fs/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/fs/fs.c b/sys/fs/fs.c index 9e8d4b600ad9..80695249c667 100644 --- a/sys/fs/fs.c +++ b/sys/fs/fs.c @@ -43,7 +43,7 @@ int fs_mount(const char *mount_point, int device, fs_type_t type) return -ENOMEM; } - memcpy(fs_table[i].mount_point, mount_point, FS_MOUNT_POINT_LEN); + strncpy(fs_table[i].mount_point, mount_point, FS_MOUNT_POINT_LEN); fs_table[i].device = device; fs_table[i].type = type; From 565c303851e0dc79fdcd689225dd74524467310a Mon Sep 17 00:00:00 2001 From: Martin Lenders Date: Tue, 15 Jul 2014 15:16:38 +0200 Subject: [PATCH 3/5] [SQUASH ME] Store strlen of fs_table_t::mount_point in fs_table_t --- sys/fs/fs.c | 6 ++++++ sys/include/fs.h | 1 + 2 files changed, 7 insertions(+) diff --git a/sys/fs/fs.c b/sys/fs/fs.c index 80695249c667..2475bdc49bec 100644 --- a/sys/fs/fs.c +++ b/sys/fs/fs.c @@ -44,6 +44,12 @@ int fs_mount(const char *mount_point, int device, fs_type_t type) } strncpy(fs_table[i].mount_point, mount_point, FS_MOUNT_POINT_LEN); + fs_table[i].mp_len = strlen(mount_point); + + if (fs_table[i].mp_len < 0 || fs_table[i].mp_len > FS_MOUNT_POINT_LEN) { + fs_table[i].mp_len = FS_MOUNT_POINT_LEN; + } + fs_table[i].device = device; fs_table[i].type = type; diff --git a/sys/include/fs.h b/sys/include/fs.h index 76195da4d146..2c78237499e6 100644 --- a/sys/include/fs.h +++ b/sys/include/fs.h @@ -48,6 +48,7 @@ typedef enum { */ typedef struct { char mount_point[FS_MOUNT_POINT_LEN]; /**< mount point of the filesystem */ + size_t mp_len; /**< length of mount point name */ int device; /**< device the filesystem is on */ fs_type_t type; /**< type of the filesystem */ } fs_table_t; From f3a748d7573ff8f14afc4b589085f73af68f10ab Mon Sep 17 00:00:00 2001 From: Martin Lenders Date: Tue, 15 Jul 2014 15:18:24 +0200 Subject: [PATCH 4/5] [SQUASH ME] Search for longest path in fs_search_entry --- sys/fs/fs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/fs/fs.c b/sys/fs/fs.c index 2475bdc49bec..a0661f099a9f 100644 --- a/sys/fs/fs.c +++ b/sys/fs/fs.c @@ -18,11 +18,13 @@ const fs_op_table_t fs_op_table[1]; static fs_table_t *fs_search_entry(const char *path) { fs_table_t *tmp = NULL; + size_t tmp_len = 0; for (int i = 0; i < FS_TABLE_SIZE; i++) { - if (!strncmp(fs_table[i].mount_point, padg, - strlen(fs_table[i].mount_point))) { + if (fs_table[i].mp_len >= tmp_len && + strncmp(fs_table[i].mount_point, path, fs_table[i].mp_len) == 0) { tmp = &(fs_table[i]); + tmp_len = fs_table[i].mp_len; } } From 6f9b03e569ba9859a90bdb00178a12243e17e40b Mon Sep 17 00:00:00 2001 From: Martin Lenders Date: Tue, 27 May 2014 18:03:48 +0200 Subject: [PATCH 5/5] fs : scfs: Start SCFS module --- Makefile.dep | 8 +++++ sys/Makefile | 6 ++++ sys/fs/scfs/Makefile | 3 ++ sys/fs/scfs/scfs.c | 34 +++++++++++++++++++++ sys/include/scfs.h | 72 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+) create mode 100644 sys/fs/scfs/Makefile create mode 100644 sys/fs/scfs/scfs.c create mode 100644 sys/include/scfs.h diff --git a/Makefile.dep b/Makefile.dep index 7455a419b709..689e2cb9733b 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -71,6 +71,14 @@ endif ifneq (,$(filter net_if,$(USEMODULE))) USEMODULE += transceiver +endif + +ifneq (,$(filter scfs,$(USEMODULE))) + USEMODULE += fs + USEMODULE += shell_commands +endif + +ifneq (,$(filter shell_commands,$(USEMODULE))) USEMODULE += net_help endif diff --git a/sys/Makefile b/sys/Makefile index d7c973ac1b7f..028c82c34062 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -4,6 +4,9 @@ endif ifneq (,$(filter config,$(USEMODULE))) DIRS += config endif +ifneq (,$(filter fs,$(USEMODULE))) + DIRS += fs +endif ifneq (,$(filter lib,$(USEMODULE))) DIRS += lib endif @@ -22,6 +25,9 @@ endif ifneq (,$(filter pthread,$(USEMODULE))) DIRS += posix/pthread endif +ifneq (,$(filter scfs,$(USEMODULE))) + DIRS += fs/scfs +endif ifneq (,$(filter shell,$(USEMODULE))) DIRS += shell endif diff --git a/sys/fs/scfs/Makefile b/sys/fs/scfs/Makefile new file mode 100644 index 000000000000..88f49842fc98 --- /dev/null +++ b/sys/fs/scfs/Makefile @@ -0,0 +1,3 @@ +MODULE =scfs + +include $(RIOTBASE)/Makefile.base diff --git a/sys/fs/scfs/scfs.c b/sys/fs/scfs/scfs.c new file mode 100644 index 000000000000..72c19cc760fc --- /dev/null +++ b/sys/fs/scfs/scfs.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +#include + +#include "fs.h" +#include "scfs.h" +#include "shell_commands.h" + +static int busy = 0; + +int scfs_mount(const char *mount_point) +{ + if (busy) { + errno = EBUSY; + return -EBUSY; + } + + return fs_mount(mount_point, 0, FS_SCFS); +} + +int scfs_unmount(const char *mount_point) +{ + if (!busy) { + return 0; + } + + return fs_unmount(mount_point, 0); +} diff --git a/sys/include/scfs.h b/sys/include/scfs.h new file mode 100644 index 000000000000..e1d34906d058 --- /dev/null +++ b/sys/include/scfs.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @addtogroup fs + * @{ + * + * @file scfs.h + * @brief A simple file system that emulates commands from the shell + * command module as binary files + * + * @author Freie Universität Berlin + * @author Martine Lenders + */ + +#ifndef __SCFS_H_ +#define __SCFS_H_ + +#include + +/** + * @brief Initializes SCFS. + * + * @param[in] mount_point Path where to mount SCFS + * + * @return 0, on success + * @return other on error, errno is set accordingly + */ +int scfs_mount(const char *mount_point); + +/** + * @brief Removes SCFS. + * + * @param[in] mount_point Path where SCFS is mounted + * + * @return 0, on success + * @return other on error, errno is set accordingly + */ +int scfs_unmount(const char *mount_point); + +/** + * @brief Get file status. + * + * @param[in] path Path to the file. + * @param[out] stat The status of the file. + * + * @return 0, on success. + * @return -1, on failure. *errno* is set appropriatly. + */ +int scfs_stat(const char *path, struct stat *stat); + +/** + * @brief Executes a file. + * + * @param[in] path Path to the file. + * @param[in] argv NULL-terminated array of command line arguments. By + * convention, the first argument must the calling name of + * the executed file. + * @param[in] env NULL-terminated array of strings, conventionally in the + * form of "key=value", that represent the environment + * variables passed to the command. + * + * @return The return value of the executed program + */ +int scfs_exec(const char *path, const char *argv[], const char *env[]); + +#endif /* __SCFS_H_ */