fs/dup3: impletement dup3/nx_dup3_from_tcb function
refs: https://man7.org/linux/man-pages/man2/dup.2.html Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
parent
dc2dac2377
commit
73dc8f84cc
@ -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
|
||||
*
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user