aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-08-21 12:11:46 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-09-26 21:09:57 -0400
commit8280d16172243702ed43432f826ca6130edb4086 (patch)
tree020dff359c5b717a110432159bcc3ec1acf6594e /fs/file.c
parentfe17f22d7fd0e344ef6447238f799bb49f670c6f (diff)
new helper: replace_fd()
analog of dup2(), except that it takes struct file * as source. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c91
1 files changed, 62 insertions, 29 deletions
diff --git a/fs/file.c b/fs/file.c
index 7f29544755d0..a7bbe0324478 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -821,29 +821,12 @@ bool get_close_on_exec(unsigned int fd)
821 return res; 821 return res;
822} 822}
823 823
824SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) 824static int do_dup2(struct files_struct *files,
825 struct file *file, unsigned fd, unsigned flags)
825{ 826{
826 int err = -EBADF; 827 struct file *tofree;
827 struct file * file, *tofree;
828 struct files_struct * files = current->files;
829 struct fdtable *fdt; 828 struct fdtable *fdt;
830 829
831 if ((flags & ~O_CLOEXEC) != 0)
832 return -EINVAL;
833
834 if (newfd >= rlimit(RLIMIT_NOFILE))
835 return -EMFILE;
836
837 spin_lock(&files->file_lock);
838 err = expand_files(files, newfd);
839 file = fcheck(oldfd);
840 if (unlikely(!file))
841 goto Ebadf;
842 if (unlikely(err < 0)) {
843 if (err == -EMFILE)
844 goto Ebadf;
845 goto out_unlock;
846 }
847 /* 830 /*
848 * We need to detect attempts to do dup2() over allocated but still 831 * We need to detect attempts to do dup2() over allocated but still
849 * not finished descriptor. NB: OpenBSD avoids that at the price of 832 * not finished descriptor. NB: OpenBSD avoids that at the price of
@@ -858,24 +841,74 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
858 * scope of POSIX or SUS, since neither considers shared descriptor 841 * scope of POSIX or SUS, since neither considers shared descriptor
859 * tables and this condition does not arise without those. 842 * tables and this condition does not arise without those.
860 */ 843 */
861 err = -EBUSY;
862 fdt = files_fdtable(files); 844 fdt = files_fdtable(files);
863 tofree = fdt->fd[newfd]; 845 tofree = fdt->fd[fd];
864 if (!tofree && fd_is_open(newfd, fdt)) 846 if (!tofree && fd_is_open(fd, fdt))
865 goto out_unlock; 847 goto Ebusy;
866 get_file(file); 848 get_file(file);
867 rcu_assign_pointer(fdt->fd[newfd], file); 849 rcu_assign_pointer(fdt->fd[fd], file);
868 __set_open_fd(newfd, fdt); 850 __set_open_fd(fd, fdt);
869 if (flags & O_CLOEXEC) 851 if (flags & O_CLOEXEC)
870 __set_close_on_exec(newfd, fdt); 852 __set_close_on_exec(fd, fdt);
871 else 853 else
872 __clear_close_on_exec(newfd, fdt); 854 __clear_close_on_exec(fd, fdt);
873 spin_unlock(&files->file_lock); 855 spin_unlock(&files->file_lock);
874 856
875 if (tofree) 857 if (tofree)
876 filp_close(tofree, files); 858 filp_close(tofree, files);
877 859
878 return newfd; 860 return fd;
861
862Ebusy:
863 spin_unlock(&files->file_lock);
864 return -EBUSY;
865}
866
867int replace_fd(unsigned fd, struct file *file, unsigned flags)
868{
869 int err;
870 struct files_struct *files = current->files;
871
872 if (!file)
873 return __close_fd(files, fd);
874
875 if (fd >= rlimit(RLIMIT_NOFILE))
876 return -EMFILE;
877
878 spin_lock(&files->file_lock);
879 err = expand_files(files, fd);
880 if (unlikely(err < 0))
881 goto out_unlock;
882 return do_dup2(files, file, fd, flags);
883
884out_unlock:
885 spin_unlock(&files->file_lock);
886 return err;
887}
888
889SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
890{
891 int err = -EBADF;
892 struct file *file;
893 struct files_struct *files = current->files;
894
895 if ((flags & ~O_CLOEXEC) != 0)
896 return -EINVAL;
897
898 if (newfd >= rlimit(RLIMIT_NOFILE))
899 return -EMFILE;
900
901 spin_lock(&files->file_lock);
902 err = expand_files(files, newfd);
903 file = fcheck(oldfd);
904 if (unlikely(!file))
905 goto Ebadf;
906 if (unlikely(err < 0)) {
907 if (err == -EMFILE)
908 goto Ebadf;
909 goto out_unlock;
910 }
911 return do_dup2(files, file, newfd, flags);
879 912
880Ebadf: 913Ebadf:
881 err = -EBADF; 914 err = -EBADF;