diff --git a/fs/vfs/Make.defs b/fs/vfs/Make.defs index c768b1819ab..900dc20534b 100644 --- a/fs/vfs/Make.defs +++ b/fs/vfs/Make.defs @@ -87,7 +87,7 @@ endif CSRCS += fs_pread.c fs_pwrite.c ifneq ($(CONFIG_PSEUDOFS_SOFTLINKS),0) -CSRCS += fs_link.c +CSRCS += fs_link.c fs_readlink.c endif # Stream support diff --git a/fs/vfs/fs_readlink.c b/fs/vfs/fs_readlink.c new file mode 100644 index 00000000000..b5a38f1cc63 --- /dev/null +++ b/fs/vfs/fs_readlink.c @@ -0,0 +1,130 @@ +/**************************************************************************** + * fs/vfs/fs_readlink.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 will 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 + +#include "inode/inode.h" + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mkdir + * + * Description: + * The readlink() function will place the contents of the symbolic link + * referred to by 'path' in the buffer 'buf' which has size 'bufsize'. If + * the number of bytes in the symbolic link is less than bufsize, the + * contents of the remainder of 'buf' are unspecified. If the buf argument + * is not large enough to contain the link content, the first bufsize bytes + * will be placed in buf. If the value of bufsize is greater than + * {SSIZE_MAX}, the result is implementation-defined. * + * + * Input Parameters: + * path - The full path to the symbolic link + * buf - The user-provided buffer in which to return the path to the + * link target. + * bufixe - The size of 'buf' + * + * Returned Value: + * Upon successful completion, readlink() will return the count of bytes + * placed in the buffer. Otherwise, it will return a value of -1, leave the + * buffer unchanged, and set errno to indicate the error. + * + ****************************************************************************/ + +ssize_t readlink(FAR const char *path, FAR char *buf, size_t bufsize) +{ + FAR struct inode *node; + const char *relpath = NULL; + int errcode; + + DEBUGASSERT(path != NULL && buf != NULL && bufsize > 0); + + /* Find the inode that includes this path (without derefencing the final) + * symbolic link node. + */ + + node = inode_find(path, &relpath); + if (node == NULL) + { + errcode = ENOENT; + goto errout; + } + + /* An inode was found that includes this path and possibly refers to a + * symbolic link. + * + * Check if the inode is a valid symbolic link. + */ + + if (!INODE_IS_SOFTLINK(node)) + { + errcode = EINVAL; + goto errout_with_inode; + } + + /* Copy the link target pathto the user-provided buffer. */ + + *buf = '\0'; + (void)strncpy(node->u.i_link, buf, bufsize); + + /* Release our reference on the inode and return the length */ + + inode_release(node); + return strlen(buf); + +errout_with_inode: + inode_release(node); +errout: + set_errno(errcode); + return ERROR; +} + +#endif /* CONFIG_PSEUDOFS_SOFTLINKS */ diff --git a/include/sys/syscall.h b/include/sys/syscall.h index ac1dde570bf..b195fafc38d 100644 --- a/include/sys/syscall.h +++ b/include/sys/syscall.h @@ -325,7 +325,8 @@ # if defined(CONFIG_PSEUDOFS_SOFTLINKS) # define SYS_link (__SYS_filedesc+14) -# define __SYS_pipes (__SYS_filedesc+15) +# define SYS_readlink (__SYS_filedesc+15) +# define __SYS_pipes (__SYS_filedesc+16) # else # define __SYS_pipes (__SYS_filedesc+14) # endif diff --git a/include/unistd.h b/include/unistd.h index e5e69f261b3..4453c2d4f46 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -190,7 +190,11 @@ 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); + +#ifdef CONFIG_PSEUDOFS_SOFTLINKS int link(FAR const char *path1, FAR const char *path2); +ssize_t readlink(FAR const char *path, FAR char *buf, size_t bufsize); +#endif /* Execution of programs from files */ diff --git a/syscall/syscall.csv b/syscall/syscall.csv index d8ff96cf034..acba1d86dbe 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -99,6 +99,7 @@ "putenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","int","FAR const char*" "read","unistd.h","CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0","ssize_t","int","FAR void*","size_t" "readdir","dirent.h","CONFIG_NFILE_DESCRIPTORS > 0","FAR struct dirent*","FAR DIR*" +"readlink","unistd.h","defined(CONFIG_PSEUDOFS_SOFTLINKS)","ssize_t","FAR const char *","FAR char *","size_t" "recv","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","ssize_t","int","FAR void*","size_t","int" "recvfrom","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","ssize_t","int","FAR void*","size_t","int","FAR struct sockaddr*","FAR socklen_t*" "rename","stdio.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*","FAR const char*" diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index b302a928296..784613adc4a 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -234,6 +234,7 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert) # if defined(CONFIG_PSEUDOFS_SOFTLINKS) SYSCALL_LOOKUP(link, 2, STUB_link) + SYSCALL_LOOKUP(readlink, 3, STUB_readlink) # endif # if defined(CONFIG_PIPES) && CONFIG_DEV_PIPE_SIZE > 0 diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c index 950553c7425..971879d308c 100644 --- a/syscall/syscall_stublookup.c +++ b/syscall/syscall_stublookup.c @@ -239,6 +239,8 @@ uintptr_t STUB_statfs(int nbr, uintptr_t parm1, uintptr_t parm2); uintptr_t STUB_telldir(int nbr, uintptr_t parm1); uintptr_t STUB_link(int nbr, uintptr_t parm1, uintptr_t parm2); +uintptr_t STUB_readlink(int nbr, uintptr_t parm1, uintptr_t parm2, + uintptr_t parm3); uintptr_t STUB_pipe2(int nbr, uintptr_t parm1, uintptr_t parm2); uintptr_t STUB_mkfifo2(int nbr, uintptr_t parm1, uintptr_t parm2,