gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/mkdir.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 <sys/stat.h>
    17  #include <sys/types.h>
    18  #include <unistd.h>
    19  
    20  #include "gtest/gtest.h"
    21  #include "test/util/capability_util.h"
    22  #include "test/util/fs_util.h"
    23  #include "test/util/temp_path.h"
    24  #include "test/util/temp_umask.h"
    25  #include "test/util/test_util.h"
    26  
    27  namespace gvisor {
    28  namespace testing {
    29  
    30  namespace {
    31  
    32  class MkdirTest : public ::testing::Test {
    33   protected:
    34    // SetUp creates various configurations of files.
    35    void SetUp() override { dirname_ = NewTempAbsPath(); }
    36  
    37    // TearDown unlinks created files.
    38    void TearDown() override {
    39      EXPECT_THAT(rmdir(dirname_.c_str()), SyscallSucceeds());
    40    }
    41  
    42    std::string dirname_;
    43  };
    44  
    45  TEST_F(MkdirTest, CanCreateWritableDir) {
    46    ASSERT_THAT(mkdir(dirname_.c_str(), 0777), SyscallSucceeds());
    47    std::string filename = JoinPath(dirname_, "anything");
    48    int fd;
    49    ASSERT_THAT(fd = open(filename.c_str(), O_RDWR | O_CREAT, 0666),
    50                SyscallSucceeds());
    51    EXPECT_THAT(close(fd), SyscallSucceeds());
    52    ASSERT_THAT(unlink(filename.c_str()), SyscallSucceeds());
    53  }
    54  
    55  TEST_F(MkdirTest, HonorsUmask) {
    56    constexpr mode_t kMask = 0111;
    57    TempUmask mask(kMask);
    58    ASSERT_THAT(mkdir(dirname_.c_str(), 0777), SyscallSucceeds());
    59    struct stat statbuf;
    60    ASSERT_THAT(stat(dirname_.c_str(), &statbuf), SyscallSucceeds());
    61    EXPECT_EQ(0777 & ~kMask, statbuf.st_mode & 0777);
    62  }
    63  
    64  TEST_F(MkdirTest, HonorsUmask2) {
    65    constexpr mode_t kMask = 0142;
    66    TempUmask mask(kMask);
    67    ASSERT_THAT(mkdir(dirname_.c_str(), 0777), SyscallSucceeds());
    68    struct stat statbuf;
    69    ASSERT_THAT(stat(dirname_.c_str(), &statbuf), SyscallSucceeds());
    70    EXPECT_EQ(0777 & ~kMask, statbuf.st_mode & 0777);
    71  }
    72  
    73  TEST_F(MkdirTest, FailsOnDirWithoutWritePerms) {
    74    // Drop capabilities that allow us to override file and directory permissions.
    75    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
    76    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
    77  
    78    ASSERT_THAT(mkdir(dirname_.c_str(), 0555), SyscallSucceeds());
    79    auto dir = JoinPath(dirname_.c_str(), "foo");
    80    EXPECT_THAT(mkdir(dir.c_str(), 0777), SyscallFailsWithErrno(EACCES));
    81    EXPECT_THAT(open(JoinPath(dirname_, "file").c_str(), O_RDWR | O_CREAT, 0666),
    82                SyscallFailsWithErrno(EACCES));
    83  }
    84  
    85  TEST_F(MkdirTest, DirAlreadyExists) {
    86    // Drop capabilities that allow us to override file and directory permissions.
    87    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
    88    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
    89  
    90    ASSERT_THAT(mkdir(dirname_.c_str(), 0777), SyscallSucceeds());
    91    auto dir = JoinPath(dirname_.c_str(), "foo");
    92    EXPECT_THAT(mkdir(dir.c_str(), 0777), SyscallSucceeds());
    93  
    94    struct {
    95      int mode;
    96      int err;
    97    } tests[] = {
    98        {.mode = 0000, .err = EACCES},  // No perm
    99        {.mode = 0100, .err = EEXIST},  // Exec only
   100        {.mode = 0200, .err = EACCES},  // Write only
   101        {.mode = 0300, .err = EEXIST},  // Write+exec
   102        {.mode = 0400, .err = EACCES},  // Read only
   103        {.mode = 0500, .err = EEXIST},  // Read+exec
   104        {.mode = 0600, .err = EACCES},  // Read+write
   105        {.mode = 0700, .err = EEXIST},  // All
   106    };
   107    for (const auto& t : tests) {
   108      printf("mode: 0%o\n", t.mode);
   109      EXPECT_THAT(chmod(dirname_.c_str(), t.mode), SyscallSucceeds());
   110      EXPECT_THAT(mkdir(dir.c_str(), 0777), SyscallFailsWithErrno(t.err));
   111    }
   112  
   113    // Clean up.
   114    EXPECT_THAT(chmod(dirname_.c_str(), 0777), SyscallSucceeds());
   115    ASSERT_THAT(rmdir(dir.c_str()), SyscallSucceeds());
   116  }
   117  
   118  TEST_F(MkdirTest, MkdirAtEmptyPath) {
   119    ASSERT_THAT(mkdir(dirname_.c_str(), 0777), SyscallSucceeds());
   120    auto fd =
   121        ASSERT_NO_ERRNO_AND_VALUE(Open(dirname_, O_RDONLY | O_DIRECTORY, 0666));
   122    EXPECT_THAT(mkdirat(fd.get(), "", 0777), SyscallFailsWithErrno(ENOENT));
   123  }
   124  
   125  TEST_F(MkdirTest, TrailingSlash) {
   126    ASSERT_THAT(mkdir((dirname_ + "/").c_str(), 0777), SyscallSucceeds());
   127  }
   128  
   129  }  // namespace
   130  
   131  }  // namespace testing
   132  }  // namespace gvisor