github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/dup.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <fcntl.h>
    16  #include <unistd.h>
    17  
    18  #include "gtest/gtest.h"
    19  #include "test/util/eventfd_util.h"
    20  #include "test/util/file_descriptor.h"
    21  #include "test/util/fs_util.h"
    22  #include "test/util/posix_error.h"
    23  #include "test/util/temp_path.h"
    24  #include "test/util/test_util.h"
    25  
    26  namespace gvisor {
    27  namespace testing {
    28  
    29  namespace {
    30  
    31  PosixErrorOr<FileDescriptor> Dup2(const FileDescriptor& fd, int target_fd) {
    32    int new_fd = dup2(fd.get(), target_fd);
    33    if (new_fd < 0) {
    34      return PosixError(errno, "Dup2");
    35    }
    36    return FileDescriptor(new_fd);
    37  }
    38  
    39  PosixErrorOr<FileDescriptor> Dup3(const FileDescriptor& fd, int target_fd,
    40                                    int flags) {
    41    int new_fd = dup3(fd.get(), target_fd, flags);
    42    if (new_fd < 0) {
    43      return PosixError(errno, "Dup2");
    44    }
    45    return FileDescriptor(new_fd);
    46  }
    47  
    48  TEST(DupTest, Dup) {
    49    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    50    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY));
    51  
    52    // Dup the descriptor and make sure it's the same file.
    53    FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
    54    ASSERT_NE(fd.get(), nfd.get());
    55    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
    56  }
    57  
    58  TEST(DupTest, DupClearsCloExec) {
    59    // Open an eventfd file descriptor with FD_CLOEXEC descriptor flag set.
    60    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(NewEventFD(0, EFD_CLOEXEC));
    61    EXPECT_THAT(fcntl(fd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC));
    62  
    63    // Duplicate the descriptor. Ensure that it doesn't have FD_CLOEXEC set.
    64    FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
    65    ASSERT_NE(fd.get(), nfd.get());
    66    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
    67    EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(0));
    68  }
    69  
    70  TEST(DupTest, DupWithOpath) {
    71    SKIP_IF(IsRunningWithVFS1());
    72    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    73    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_PATH));
    74    int flags;
    75    ASSERT_THAT(flags = fcntl(fd.get(), F_GETFL), SyscallSucceeds());
    76  
    77    // Dup the descriptor and make sure it's the same file.
    78    FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
    79    ASSERT_NE(fd.get(), nfd.get());
    80    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
    81    EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags));
    82  }
    83  
    84  TEST(DupTest, Dup2) {
    85    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    86    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY));
    87  
    88    // Regular dup once.
    89    FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
    90  
    91    ASSERT_NE(fd.get(), nfd.get());
    92    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
    93  
    94    // Dup over the file above.
    95    int target_fd = nfd.release();
    96    FileDescriptor nfd2 = ASSERT_NO_ERRNO_AND_VALUE(Dup2(fd, target_fd));
    97    EXPECT_EQ(target_fd, nfd2.get());
    98    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd2));
    99  }
   100  
   101  TEST(DupTest, Dup2SameFD) {
   102    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   103    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY));
   104  
   105    // Should succeed.
   106    ASSERT_THAT(dup2(fd.get(), fd.get()), SyscallSucceedsWithValue(fd.get()));
   107  }
   108  
   109  TEST(DupTest, Dup2WithOpath) {
   110    SKIP_IF(IsRunningWithVFS1());
   111    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   112    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_PATH));
   113    int flags;
   114    ASSERT_THAT(flags = fcntl(fd.get(), F_GETFL), SyscallSucceeds());
   115  
   116    // Regular dup once.
   117    FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
   118  
   119    ASSERT_NE(fd.get(), nfd.get());
   120    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
   121    EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags));
   122  
   123    // Dup over the file above.
   124    int target_fd = nfd.release();
   125    FileDescriptor nfd2 = ASSERT_NO_ERRNO_AND_VALUE(Dup2(fd, target_fd));
   126    EXPECT_EQ(target_fd, nfd2.get());
   127    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd2));
   128    EXPECT_THAT(fcntl(nfd2.get(), F_GETFL), SyscallSucceedsWithValue(flags));
   129  }
   130  
   131  TEST(DupTest, Dup3) {
   132    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   133    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY));
   134  
   135    // Regular dup once.
   136    FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
   137    ASSERT_NE(fd.get(), nfd.get());
   138    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
   139  
   140    // Dup over the file above, check that it has no CLOEXEC.
   141    nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), 0));
   142    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
   143    EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(0));
   144  
   145    // Dup over the file again, check that it does not CLOEXEC.
   146    nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), O_CLOEXEC));
   147    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
   148    EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC));
   149  }
   150  
   151  TEST(DupTest, Dup3FailsSameFD) {
   152    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   153    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDONLY));
   154  
   155    // Only dup3 fails if the new and old fd are the same.
   156    ASSERT_THAT(dup3(fd.get(), fd.get(), 0), SyscallFailsWithErrno(EINVAL));
   157  }
   158  
   159  TEST(DupTest, Dup3WithOpath) {
   160    SKIP_IF(IsRunningWithVFS1());
   161    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   162    FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_PATH));
   163    EXPECT_THAT(fcntl(fd.get(), F_GETFD), SyscallSucceedsWithValue(0));
   164    int flags;
   165    ASSERT_THAT(flags = fcntl(fd.get(), F_GETFL), SyscallSucceeds());
   166  
   167    // Regular dup once.
   168    FileDescriptor nfd = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
   169    ASSERT_NE(fd.get(), nfd.get());
   170    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
   171  
   172    // Dup over the file above, check that it has no CLOEXEC.
   173    nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), 0));
   174    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
   175    EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(0));
   176    EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags));
   177  
   178    // Dup over the file again, check that it does not CLOEXEC.
   179    nfd = ASSERT_NO_ERRNO_AND_VALUE(Dup3(fd, nfd.release(), O_CLOEXEC));
   180    ASSERT_NO_ERRNO(CheckSameFile(fd, nfd));
   181    EXPECT_THAT(fcntl(nfd.get(), F_GETFD), SyscallSucceedsWithValue(FD_CLOEXEC));
   182    EXPECT_THAT(fcntl(nfd.get(), F_GETFL), SyscallSucceedsWithValue(flags));
   183  }
   184  
   185  }  // namespace
   186  
   187  }  // namespace testing
   188  }  // namespace gvisor