diff --git a/fs/Kconfig b/fs/Kconfig index 603d9a5115..6b67520fd2 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -40,6 +40,19 @@ config DISABLE_PSEUDOFS_OPERATIONS However, in practical embedded system, they are seldom needed and you can save a little FLASH space by disabling the capability. +config PSEUDOFS_SOFTLINKS + bool "Pseudo-filesystem soft links" + default y if DEFAULT_SMALL + default n if !DEFAULT_SMALL + depends on !DISABLE_PSEUDOFS_OPERATIONS + ---help--- + Enable support for soft links in the pseudeo file system. Soft + links are not supported within mounted volumes by any NuttX file + system. However, if this option is selected, then soft links + may be add in the pseudo file system. This might be useful, for + to link a directory in the pseudo-file system, such as /bin, to + to a directory in a mounted volume, say /mnt/sdcard/bin. + config FS_READABLE bool default n diff --git a/fs/inode/fs_inode.c b/fs/inode/fs_inode.c index 3658ad5e44..e77c157415 100644 --- a/fs/inode/fs_inode.c +++ b/fs/inode/fs_inode.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/inode/fs_inode.c * - * Copyright (C) 2007-2009, 2011-2012, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2012, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -345,6 +346,7 @@ FAR struct inode *inode_search(FAR const char **path, { *relpath = name; } + break; } else @@ -401,8 +403,29 @@ void inode_free(FAR struct inode *node) if (node != NULL) { +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* Symbol links should never have peers or children */ + + DEBUGASSERT(!INODE_IS_SOFTLINK(node)) || + (node->i_peer == NULL && node->i_child == NULL) +#endif + + /* Free all peers and children of this i_node */ + inode_free(node->i_peer); inode_free(node->i_child); + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + /* If the inode is a symbolic link, the free the path to the linked + * entity. + */ + + if (INODE_IS_SOFTLINK(node) && inode->u.i_link != NULL) + { + kmm_free(node->u.i_link); + } +#endif + kmm_free(node); } } diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index 645e23f97e..9b5e6911af 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # fs/vfs/Make.defs # -# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved. +# Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -43,7 +43,11 @@ ifneq ($(CONFIG_NSOCKET_DESCRIPTORS),0) CSRCS += fs_close.c fs_read.c fs_write.c fs_ioctl.c -# Support for network access using streams +ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0) +CSRCS += fs_softlink.c +endif + +# Stream support ifneq ($(CONFIG_NFILE_STREAMS),0) CSRCS += fs_fdopen.c @@ -86,6 +90,10 @@ endif CSRCS += fs_pread.c fs_pwrite.c +ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0) +CSRCS += fs_softlink.c +endif + # Stream support ifneq ($(CONFIG_NFILE_STREAMS),0) diff --git a/fs/vfs/fs_rmdir.c b/fs/vfs/fs_rmdir.c index ecef33558e..d3e15bce13 100644 --- a/fs/vfs/fs_rmdir.c +++ b/fs/vfs/fs_rmdir.c @@ -84,8 +84,9 @@ int rmdir(FAR const char *pathname) const char *relpath = NULL; int errcode; - /* Get an inode for this file. inode_find() automatically increments the - * reference count on the inode if one is found. + /* Get an inode for the directory (or for the mountpoint containing the + * directory). inode_find() automatically increments the reference count + * on the inode if one is found. */ inode = inode_find(pathname, &relpath); diff --git a/fs/vfs/fs_softlink.c b/fs/vfs/fs_softlink.c new file mode 100644 index 0000000000..483bcb4ffa --- /dev/null +++ b/fs/vfs/fs_softlink.c @@ -0,0 +1,169 @@ +/**************************************************************************** + * fs/vfs/fs_softlink.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "inode/inode.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: link + * + * Description: + * The link() function will create a new link (directory entry) for the + * existing file, path1. This implementation is simplied for use with + * NuttX in these ways: + * + * - Links may be created only within the NuttX top-level, pseudo file + * system. No file system currently supported by NuttX provides + * symbolic links. + * - For the same reason, only soft links are implemented. + * - File privileges are ignored. + * - c_time is not updated. + * + * Input Parameters: + * path1 - Points to a pathname naming an existing file. + * path2 - Points to a pathname naming the new directory entry to be created. + * + * Returned Value: + * On success, zero (OK) is returned. Otherwise, -1 (ERROR) is returned + * the the errno variable is set appropriately. + * + ****************************************************************************/ + +int link(FAR const char *path1, FAR const char *path2) +{ + FAR struct inode *inode; + int errcode; + int ret; + + DEBUGASSERT(path1 != NULL && path2 != NULL && *path2 != '\0'); + + /* Check that no inode exists at the 'path2' and that the path up to 'path2' + * does not lie on a mounted volume. + */ + + inode = inode_find(pathname, NULL); + if (inode != NULL) + { +#ifndef CONFIG_DISABLE_MOUNTPOINT + /* Check if the inode is a mountpoint. */ + + if (INODE_IS_MOUNTPT(inode)) + { + /* Symbol links within the mounted volume are not supported */ + + errcode = ENOSYS; + } + else +#endif + { + /* A node already exists in the pseudofs at 'path2' */ + + errorcode = EEXIST; + } + + goto errout_with_inode; + } + + /* No inode exists that contains this path. Create a new inode in the + * pseudo-filesystem at this location. + */ + + else + { + /* Copy path2 */ + + FAR char newpath2 = strdup(path2); + if (newpath2 == NULL) + { + errcode = ENOMEM; + goto errout; + } + + /* Create an inode in the pseudo-filesystem at this path. + * NOTE that the new inode will be created with a reference + * count of zero. + */ + + inode_semtake(); + ret = inode_reserve(pathname, &inode); + inode_semgive(); + + if (ret < 0) + { + kmm_free(newpath2) + errcode = -ret; + goto errout; + } + + /* Initialize the inode */ + + INODE_SET_SOFTLINK(inode); + inode->u.i_link = newpath2; + inode->i_crefs = 1; + } + + /* Symbolic link successfully created */ + + return OK; + +errout_with_inode: + inode_release(inode); +errout: + set_errno(errcode); + return ERROR; +} + +#endif /* CONFIG_PSEUDOFS_SOFTLINKS */ diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 238a6b8ef9..8ec3bc83da 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/fs/fs.h * - * Copyright (C) 2007-2009, 2011-2013, 2015-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2013, 2015-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -66,12 +66,17 @@ #define __FS_FLAG_EOF (1 << 0) /* EOF detected by a read operation */ #define __FS_FLAG_ERROR (1 << 1) /* Error detected by any operation */ -/* Inode i_flag values */ +/* Inode i_flag values: + * + * Bit 0-3: Inode type (Bit 4 indicates internal OS types) + * Bit 4: Set if inode has been unlinked and is pending removal. + */ #define FSNODEFLAG_TYPE_MASK 0x00000007 /* Isolates type field */ #define FSNODEFLAG_TYPE_DRIVER 0x00000000 /* Character driver */ #define FSNODEFLAG_TYPE_BLOCK 0x00000001 /* Block driver */ #define FSNODEFLAG_TYPE_MOUNTPT 0x00000002 /* Mount point */ +#define FSNODEFLAG_TYPE_SOFTLINK 0x00000003 /* Soft link */ #define FSNODEFLAG_TYPE_SPECIAL 0x00000004 /* Special OS type */ #define FSNODEFLAG_TYPE_NAMEDSEM 0x00000004 /* Named semaphore */ #define FSNODEFLAG_TYPE_MQUEUE 0x00000005 /* Message Queue */ @@ -86,6 +91,7 @@ #define INODE_IS_DRIVER(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_DRIVER) #define INODE_IS_BLOCK(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_BLOCK) #define INODE_IS_MOUNTPT(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_MOUNTPT) +#define INODE_IS_SOFTLINK(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK) #define INODE_IS_NAMEDSEM(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_NAMEDSEM) #define INODE_IS_MQUEUE(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_MQUEUE) #define INODE_IS_SHM(i) INODE_IS_TYPE(i,FSNODEFLAG_TYPE_SHM) @@ -101,6 +107,7 @@ #define INODE_SET_DRIVER(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_DRIVER) #define INODE_SET_BLOCK(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_BLOCK) #define INODE_SET_MOUNTPT(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MOUNTPT) +#define (i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SOFTLINK) #define INODE_SET_NAMEDSEM(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_NAMEDSEM) #define INODE_SET_MQUEUE(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_MQUEUE) #define INODE_SET_SHM(i) INODE_SET_TYPE(i,FSNODEFLAG_TYPE_SHM) @@ -309,16 +316,19 @@ struct mountpt_operations union inode_ops_u { - FAR const struct file_operations *i_ops; /* Driver operations for inode */ + FAR const struct file_operations *i_ops; /* Driver operations for inode */ #ifndef CONFIG_DISABLE_MOUNTPOINT - FAR const struct block_operations *i_bops; /* Block driver operations */ - FAR const struct mountpt_operations *i_mops; /* Operations on a mountpoint */ + FAR const struct block_operations *i_bops; /* Block driver operations */ + FAR const struct mountpt_operations *i_mops; /* Operations on a mountpoint */ #endif #ifdef CONFIG_FS_NAMED_SEMAPHORES - FAR struct nsem_inode_s *i_nsem; /* Named semaphore */ + FAR struct nsem_inode_s *i_nsem; /* Named semaphore */ #endif #ifndef CONFIG_DISABLE_MQUEUE - FAR struct mqueue_inode_s *i_mqueue; /* POSIX message queue */ + FAR struct mqueue_inode_s *i_mqueue; /* POSIX message queue */ +#endif +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + FAR char *i_link; /* Full path to link */ #endif }; @@ -337,6 +347,7 @@ struct inode FAR void *i_private; /* Per inode driver private data */ char i_name[1]; /* Name of inode (variable) */ }; + #define FSNODE_SIZE(n) (sizeof(struct inode) + (n)) /* This is the underlying representation of an open file. A file diff --git a/include/unistd.h b/include/unistd.h index 7361b412ea..e5e69f261b 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/unistd.h * - * Copyright (C) 2007-2009, 2013-2014, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013-2014, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -190,6 +190,7 @@ FAR char *getcwd(FAR char *buf, size_t size); int access(FAR const char *path, int amode); int rmdir(FAR const char *pathname); int unlink(FAR const char *pathname); +int link(FAR const char *path1, FAR const char *path2); /* Execution of programs from files */