From 73dc8f84cc8bd5c2c18f387c676eb09669024a7e Mon Sep 17 00:00:00 2001 From: dongjiuzhu1 Date: Sun, 22 Oct 2023 16:53:58 +0800 Subject: [PATCH] fs/dup3: impletement dup3/nx_dup3_from_tcb function refs: https://man7.org/linux/man-pages/man2/dup.2.html Signed-off-by: dongjiuzhu1 --- fs/inode/fs_files.c | 183 ++++++++++++++++++++++++-------------- fs/vfs/fs_dup.c | 13 +-- fs/vfs/fs_dup2.c | 45 ++++++++-- fs/vfs/fs_fcntl.c | 4 +- include/nuttx/fs/fs.h | 20 ++++- include/unistd.h | 1 + net/local/local_recvmsg.c | 4 +- 7 files changed, 184 insertions(+), 86 deletions(-) diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c index 0c6815e23f..2f51a66037 100644 --- a/fs/inode/fs_files.c +++ b/fs/inode/fs_files.c @@ -135,6 +135,98 @@ static void task_fssync(FAR struct tcb_s *tcb, FAR void *arg) nxmutex_unlock(&list->fl_lock); } +/**************************************************************************** + * Name: nx_dup3_from_tcb + * + * Description: + * nx_dup3_from_tcb() is similar to the standard 'dup3' interface + * except that is not a cancellation point and it does not modify the + * errno variable. + * + * nx_dup3_from_tcb() is an internal NuttX interface and should not be + * called from applications. + * + * Clone a file descriptor to a specific descriptor number and + * specific flags. + * + * Returned Value: + * fd2 is returned on success; a negated errno value is return on + * any failure. + * + ****************************************************************************/ + +static int nx_dup3_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2, + int flags) +{ + FAR struct filelist *list; + FAR struct file *filep; + FAR struct file file; + int ret; + + if (fd1 == fd2) + { + return fd1; + } + +#ifdef CONFIG_FDCHECK + fd1 = fdcheck_restore(fd1); + fd2 = fdcheck_restore(fd2); +#endif + + list = nxsched_get_files_from_tcb(tcb); + + /* Get the file descriptor list. It should not be NULL in this context. */ + + if (fd1 < 0 || fd1 >= CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * list->fl_rows || + fd2 < 0) + { + return -EBADF; + } + + ret = nxmutex_lock(&list->fl_lock); + if (ret < 0) + { + /* Probably canceled */ + + return ret; + } + + if (fd2 >= CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * list->fl_rows) + { + ret = files_extend(list, fd2 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + 1); + if (ret < 0) + { + nxmutex_unlock(&list->fl_lock); + return ret; + } + } + + filep = &list->fl_files[fd2 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK] + [fd2 % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]; + memcpy(&file, filep, sizeof(struct file)); + memset(filep, 0, sizeof(struct file)); + + /* Perform the dup3 operation */ + + ret = file_dup3(&list->fl_files[fd1 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK] + [fd1 % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK], + filep, flags); + +#ifdef CONFIG_FDSAN + filep->f_tag = file.f_tag; +#endif + + nxmutex_unlock(&list->fl_lock); + + file_close(&file); + +#ifdef CONFIG_FDCHECK + return ret < 0 ? ret : fdcheck_protect(fd2); +#else + return ret < 0 ? ret : fd2; +#endif +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -492,73 +584,7 @@ int fs_getfilep(int fd, FAR struct file **filep) int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2) { - FAR struct filelist *list; - FAR struct file *filep; - FAR struct file file; - int ret; - - if (fd1 == fd2) - { - return fd1; - } - -#ifdef CONFIG_FDCHECK - fd1 = fdcheck_restore(fd1); - fd2 = fdcheck_restore(fd2); -#endif - - list = nxsched_get_files_from_tcb(tcb); - - /* Get the file descriptor list. It should not be NULL in this context. */ - - if (fd1 < 0 || fd1 >= CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * list->fl_rows || - fd2 < 0) - { - return -EBADF; - } - - ret = nxmutex_lock(&list->fl_lock); - if (ret < 0) - { - /* Probably canceled */ - - return ret; - } - - if (fd2 >= CONFIG_NFILE_DESCRIPTORS_PER_BLOCK * list->fl_rows) - { - ret = files_extend(list, fd2 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK + 1); - if (ret < 0) - { - nxmutex_unlock(&list->fl_lock); - return ret; - } - } - - filep = &list->fl_files[fd2 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK] - [fd2 % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK]; - memcpy(&file, filep, sizeof(struct file)); - memset(filep, 0, sizeof(struct file)); - - /* Perform the dup2 operation */ - - ret = file_dup2(&list->fl_files[fd1 / CONFIG_NFILE_DESCRIPTORS_PER_BLOCK] - [fd1 % CONFIG_NFILE_DESCRIPTORS_PER_BLOCK], - filep); - -#ifdef CONFIG_FDSAN - filep->f_tag = file.f_tag; -#endif - - nxmutex_unlock(&list->fl_lock); - - file_close(&file); - -#ifdef CONFIG_FDCHECK - return ret < 0 ? ret : fdcheck_protect(fd2); -#else - return ret < 0 ? ret : fd2; -#endif + return nx_dup3_from_tcb(tcb, fd1, fd2, 0); } /**************************************************************************** @@ -607,6 +633,29 @@ int dup2(int fd1, int fd2) return ret; } +/**************************************************************************** + * Name: dup3 + * + * Description: + * Clone a file descriptor or socket descriptor to a specific descriptor + * number and specific flags. + * + ****************************************************************************/ + +int dup3(int fd1, int fd2, int flags) +{ + int ret; + + ret = nx_dup3_from_tcb(nxsched_self(), fd1, fd2, flags); + if (ret < 0) + { + set_errno(-ret); + ret = ERROR; + } + + return ret; +} + /**************************************************************************** * Name: nx_close_from_tcb * diff --git a/fs/vfs/fs_dup.c b/fs/vfs/fs_dup.c index 69f6e3a520..4736dab1d9 100644 --- a/fs/vfs/fs_dup.c +++ b/fs/vfs/fs_dup.c @@ -50,28 +50,21 @@ * ****************************************************************************/ -int file_dup(FAR struct file *filep, int minfd, bool cloexec) +int file_dup(FAR struct file *filep, int minfd, int flags) { struct file filep2; int fd2; int ret; - /* Let file_dup2() do the real work */ + /* Let file_dup3() do the real work */ memset(&filep2, 0, sizeof(filep2)); - ret = file_dup2(filep, &filep2); + ret = file_dup3(filep, &filep2, flags); if (ret < 0) { return ret; } - /* Then allocate a new file descriptor for the inode */ - - if (cloexec) - { - filep2.f_oflags |= O_CLOEXEC; - } - fd2 = file_allocate(filep2.f_inode, filep2.f_oflags, filep2.f_pos, filep2.f_priv, minfd, false); if (fd2 < 0) diff --git a/fs/vfs/fs_dup2.c b/fs/vfs/fs_dup2.c index 95ad2a4d1b..cdfb9809df 100644 --- a/fs/vfs/fs_dup2.c +++ b/fs/vfs/fs_dup2.c @@ -39,13 +39,13 @@ ****************************************************************************/ /**************************************************************************** - * Name: file_dup2 + * Name: file_dup3 * * Description: * Assign an inode to a specific files structure. This is the heart of - * dup2. + * dup3. * - * Equivalent to the non-standard dup2() function except that it + * Equivalent to the non-standard dup3() function except that it * accepts struct file instances instead of file descriptors and it does * not set the errno variable. * @@ -55,7 +55,7 @@ * ****************************************************************************/ -int file_dup2(FAR struct file *filep1, FAR struct file *filep2) +int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags) { FAR struct inode *inode; struct file temp; @@ -66,6 +66,11 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2) return -EBADF; } + if (flags != 0 && flags != O_CLOEXEC) + { + return -EINVAL; + } + if (filep1 == filep2) { return OK; @@ -86,7 +91,15 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2) /* The two filep don't share flags (the close-on-exec flag). */ - temp.f_oflags = filep1->f_oflags & ~O_CLOEXEC; + if (flags == O_CLOEXEC) + { + temp.f_oflags = filep1->f_oflags | O_CLOEXEC; + } + else + { + temp.f_oflags = filep1->f_oflags & ~O_CLOEXEC; + } + temp.f_pos = filep1->f_pos; temp.f_inode = inode; @@ -155,3 +168,25 @@ int file_dup2(FAR struct file *filep1, FAR struct file *filep2) memcpy(filep2, &temp, sizeof(temp)); return OK; } + +/**************************************************************************** + * Name: file_dup2 + * + * Description: + * Assign an inode to a specific files structure. This is the heart of + * dup2. + * + * Equivalent to the non-standard dup2() function except that it + * accepts struct file instances instead of file descriptors and it does + * not set the errno variable. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is return on + * any failure. + * + ****************************************************************************/ + +int file_dup2(FAR struct file *filep1, FAR struct file *filep2) +{ + return file_dup3(filep1, filep2, 0); +} diff --git a/fs/vfs/fs_fcntl.c b/fs/vfs/fs_fcntl.c index 65dede0c94..6cf31a0536 100644 --- a/fs/vfs/fs_fcntl.c +++ b/fs/vfs/fs_fcntl.c @@ -71,13 +71,13 @@ static int file_vfcntl(FAR struct file *filep, int cmd, va_list ap) { /* Does not set the errno variable in the event of a failure */ - ret = file_dup(filep, va_arg(ap, int), false); + ret = file_dup(filep, va_arg(ap, int), 0); } break; case F_DUPFD_CLOEXEC: { - ret = file_dup(filep, va_arg(ap, int), true); + ret = file_dup(filep, va_arg(ap, int), O_CLOEXEC); } break; diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 651f94ebab..8d59124859 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -911,7 +911,7 @@ int file_allocate(FAR struct inode *inode, int oflags, off_t pos, * ****************************************************************************/ -int file_dup(FAR struct file *filep, int minfd, bool cloexec); +int file_dup(FAR struct file *filep, int minfd, int flags); /**************************************************************************** * Name: file_dup2 @@ -970,6 +970,24 @@ int nx_dup2_from_tcb(FAR struct tcb_s *tcb, int fd1, int fd2); int nx_dup2(int fd1, int fd2); +/**************************************************************************** + * Name: file_dup3 + * + * Description: + * Assign an inode to a specific files structure. This is the heart of + * dup3. + * + * Equivalent to the non-standard dup3() function except that it + * accepts struct file instances instead of file descriptors. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is return on + * any failure. + * + ****************************************************************************/ + +int file_dup3(FAR struct file *filep1, FAR struct file *filep2, int flags); + /**************************************************************************** * Name: file_open * diff --git a/include/unistd.h b/include/unistd.h index 749f936435..cc88c84539 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -328,6 +328,7 @@ int daemon(int nochdir, int noclose); int close(int fd); int dup(int fd); int dup2(int fd1, int fd2); +int dup3(int fd1, int fd2, int flags); int fsync(int fd); off_t lseek(int fd, off_t offset, int whence); ssize_t read(int fd, FAR void *buf, size_t nbytes); diff --git a/net/local/local_recvmsg.c b/net/local/local_recvmsg.c index 57ac3bcf7c..05e6006f64 100644 --- a/net/local/local_recvmsg.c +++ b/net/local/local_recvmsg.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -175,7 +176,8 @@ static void local_recvctl(FAR struct local_conn_s *conn, count = peer->lc_cfpcount; for (i = 0; i < count; i++) { - fds[i] = file_dup(peer->lc_cfps[i], 0, !!(flags & MSG_CMSG_CLOEXEC)); + fds[i] = file_dup(peer->lc_cfps[i], 0, + flags & MSG_CMSG_CLOEXEC ? O_CLOEXEC : 0); file_close(peer->lc_cfps[i]); kmm_free(peer->lc_cfps[i]); peer->lc_cfps[i] = NULL;