diff --git a/fs/inode/inode.h b/fs/inode/inode.h index 419b6a42a03..eb9ef58f62f 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -248,9 +248,10 @@ int inode_find(FAR struct inode_search_s *desc); * , into which information is placed concerning the file. * * Input Parameters: - * inode - The indoe of interest - * buf - The caller provide location in which to return information about - * the inode. + * inode - The inode of interest + * buf - The caller provide location in which to return information + * about the inode. + * resolve - Whether to resolve the symbolic link * * Returned Value: * Zero (OK) returned on success. Otherwise, a negated errno value is @@ -259,7 +260,7 @@ int inode_find(FAR struct inode_search_s *desc); ****************************************************************************/ struct stat; /* Forward reference */ -int inode_stat(FAR struct inode *inode, FAR struct stat *buf); +int inode_stat(FAR struct inode *inode, FAR struct stat *buf, int resolve); /**************************************************************************** * Name: inode_free diff --git a/fs/mount/fs_automount.c b/fs/mount/fs_automount.c index 0685daa683b..16c99e3007c 100644 --- a/fs/mount/fs_automount.c +++ b/fs/mount/fs_automount.c @@ -104,7 +104,7 @@ static int automount_interrupt(FAR const struct automount_lower_s *lower, * * Returned Value: * OK_EXIST if the inode exists - * OK_NOENT if the indoe does not exist + * OK_NOENT if the inode does not exist * Negated errno if some failure occurs * ****************************************************************************/ diff --git a/fs/vfs/fs_fstat.c b/fs/vfs/fs_fstat.c index f58fdc23a51..2612ba86343 100644 --- a/fs/vfs/fs_fstat.c +++ b/fs/vfs/fs_fstat.c @@ -199,7 +199,7 @@ int file_fstat(FAR struct file *filep, FAR struct stat *buf) { /* The inode is part of the root pseudo file system. */ - ret = inode_stat(inode, buf); + ret = inode_stat(inode, buf, 1); } } diff --git a/fs/vfs/fs_stat.c b/fs/vfs/fs_stat.c index e0f53ba6a91..7889efaf7bd 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -58,7 +58,7 @@ ****************************************************************************/ static inline int statroot(FAR struct stat *buf); -int stat_recursive(FAR const char *path, FAR struct stat *buf); +int stat_recursive(FAR const char *path, FAR struct stat *buf, int resolve); /**************************************************************************** * Private Functions @@ -93,7 +93,7 @@ static inline int statroot(FAR struct stat *buf) * ****************************************************************************/ -int stat_recursive(FAR const char *path, FAR struct stat *buf) +int stat_recursive(FAR const char *path, FAR struct stat *buf, int resolve) { struct inode_search_s desc; FAR struct inode *inode; @@ -143,7 +143,7 @@ int stat_recursive(FAR const char *path, FAR struct stat *buf) * recurse if soft links are supported in the pseudo file system. */ - ret = inode_stat(inode, buf); + ret = inode_stat(inode, buf, resolve); } inode_release(inode); @@ -171,7 +171,7 @@ errout_with_search: * ****************************************************************************/ -int nx_stat(FAR const char *path, FAR struct stat *buf) +int nx_stat(FAR const char *path, FAR struct stat *buf, int resolve) { /* Sanity checks */ @@ -199,7 +199,7 @@ int nx_stat(FAR const char *path, FAR struct stat *buf) #ifdef CONFIG_PSEUDOFS_SOFTLINKS buf->st_count = 0; #endif - return stat_recursive(path, buf); + return stat_recursive(path, buf, resolve); } /**************************************************************************** @@ -222,7 +222,21 @@ int stat(FAR const char *path, FAR struct stat *buf) { int ret; - ret = nx_stat(path, buf); + ret = nx_stat(path, buf, 1); + if (ret < 0) + { + set_errno(-ret); + ret = ERROR; + } + + return ret; +} + +int lstat(FAR const char *path, FAR struct stat *buf) +{ + int ret; + + ret = nx_stat(path, buf, 0); if (ret < 0) { set_errno(-ret); @@ -243,9 +257,10 @@ int stat(FAR const char *path, FAR struct stat *buf) * , into which information is placed concerning the file. * * Input Parameters: - * inode - The indoe of interest - * buf - The caller provide location in which to return information about - * the inode. + * inode - The inode of interest + * buf - The caller provide location in which to return information + * about the inode. + * resolve - Whether to resolve the symbolic link * * Returned Value: * Zero (OK) returned on success. Otherwise, a negated errno value is @@ -253,7 +268,7 @@ int stat(FAR const char *path, FAR struct stat *buf) * ****************************************************************************/ -int inode_stat(FAR struct inode *inode, FAR struct stat *buf) +int inode_stat(FAR struct inode *inode, FAR struct stat *buf, int resolve) { DEBUGASSERT(inode != NULL && buf != NULL); @@ -321,42 +336,47 @@ int inode_stat(FAR struct inode *inode, FAR struct stat *buf) if (INODE_IS_SOFTLINK(inode)) { - int ret; - - /* Increment the link counter. This is necessary to avoid - * infinite recursion if loops are encountered in the traversal. - * If we encounter more SYMLOOP_MAX symbolic links at any time - * during the traversal, error out. - * - * NOTE: That inode_search() will automatically skip over - * consecutive, intermediate symbolic links. Those numbers will - * not be included in the total. - */ - - if (++buf->st_count > SYMLOOP_MAX) + if (resolve) { - return -ELOOP; + int ret; + + /* Increment the link counter. This is necessary to avoid + * infinite recursion if loops are encountered in the + * traversal. If we encounter more SYMLOOP_MAX symbolic links + * at any time during the traversal, error out. + * + * NOTE: That inode_search() will automatically skip over + * consecutive, intermediate symbolic links. Those numbers + * will not be included in the total. + */ + + if (++buf->st_count > SYMLOOP_MAX) + { + return -ELOOP; + } + + DEBUGASSERT(buf->st_count > 0); /* Check for unsigned integer overflow */ + + /* stat() the target of the soft link. */ + + ret = stat_recursive(inode->u.i_link, buf, 1); + + /* If stat() fails, then there is a problem with the target of + * the symbolic link, but not with the symbolic link itself. + * We should still report success, just with less information. + */ + + if (ret < 0) + { + RESET_BUF(buf); + } } - - DEBUGASSERT(buf->st_count > 0); /* Check for unsigned integer overflow */ - - /* stat() the target of the soft link. */ - - ret = stat_recursive((FAR const char *)inode->u.i_link, buf); - - /* If stat() fails, then there is a problem with the target of the - * symbolic link, but not with the symbolic link itself. We should - * still report success, just with less information. - */ - - if (ret < 0) + else { - RESET_BUF(buf); + /* Make sure the caller knows that this is a symbolic link. */ + + buf->st_mode |= S_IFLNK; } - - /* Make sure the caller knows that this really a symbolic link. */ - - buf->st_mode |= S_IFLNK; } else #endif diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 80c6e7a0efc..9447afbc370 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -78,7 +78,7 @@ # define _NX_WRITE(f,b,s) nx_write(f,b,s) # define _NX_SEEK(f,o,w) nx_seek(f,o,w) # define _NX_IOCTL(f,r,a) nx_ioctl(f,r,a) -# define _NX_STAT(p,s) nx_stat(p,s) +# define _NX_STAT(p,s) nx_stat(p,s,1) # define _NX_GETERRNO(r) (-(r)) # define _NX_SETERRNO(r) set_errno(-(r)) # define _NX_GETERRVAL(r) (r) @@ -1450,7 +1450,7 @@ int file_fstat(FAR struct file *filep, FAR struct stat *buf); * ****************************************************************************/ -int nx_stat(FAR const char *path, FAR struct stat *buf); +int nx_stat(FAR const char *path, FAR struct stat *buf, int resolve); #undef EXTERN #if defined(__cplusplus) diff --git a/include/sys/stat.h b/include/sys/stat.h index 33b743bbfc5..6483c46dcd0 100644 --- a/include/sys/stat.h +++ b/include/sys/stat.h @@ -156,6 +156,7 @@ extern "C" int mkdir(FAR const char *pathname, mode_t mode); int mkfifo(FAR const char *pathname, mode_t mode); int stat(FAR const char *path, FAR struct stat *buf); +int lstat(FAR const char *path, FAR struct stat *buf); int fstat(int fd, FAR struct stat *buf); int chmod(FAR const char *path, mode_t mode); int fchmod(int fd, mode_t mode); diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index c5b63bc8e0d..67b8472af55 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -235,6 +235,7 @@ SYSCALL_LOOKUP(readdir, 1) SYSCALL_LOOKUP(rewinddir, 1) SYSCALL_LOOKUP(seekdir, 2) SYSCALL_LOOKUP(stat, 2) +SYSCALL_LOOKUP(lstat, 2) SYSCALL_LOOKUP(fstat, 2) SYSCALL_LOOKUP(statfs, 2) SYSCALL_LOOKUP(fstatfs, 2) diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 3f487cb6427..b79f7797ef8 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -45,6 +45,7 @@ "link","unistd.h","defined(CONFIG_PSEUDOFS_SOFTLINKS)","int","FAR const char *","FAR const char *" "listen","sys/socket.h","defined(CONFIG_NET)","int","int","int" "lseek","unistd.h","","off_t","int","off_t","int" +"lstat","sys/stat.h","","int","FAR const char *","FAR struct stat *" "mkdir","sys/stat.h","!defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char *","mode_t" "mmap","sys/mman.h","","FAR void *","FAR void *","size_t","int","int","int","off_t" "modhandle","nuttx/module.h","defined(CONFIG_MODULE)","FAR void *","FAR const char *"