github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/rename.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 <stdio.h>
    17  
    18  #include <string>
    19  
    20  #include "gtest/gtest.h"
    21  #include "absl/strings/string_view.h"
    22  #include "test/util/capability_util.h"
    23  #include "test/util/cleanup.h"
    24  #include "test/util/file_descriptor.h"
    25  #include "test/util/fs_util.h"
    26  #include "test/util/temp_path.h"
    27  #include "test/util/test_util.h"
    28  
    29  using ::testing::AnyOf;
    30  
    31  namespace gvisor {
    32  namespace testing {
    33  
    34  namespace {
    35  
    36  TEST(RenameTest, RootToAnything) {
    37    ASSERT_THAT(rename("/", "/bin"), SyscallFailsWithErrno(EBUSY));
    38  }
    39  
    40  TEST(RenameTest, AnythingToRoot) {
    41    ASSERT_THAT(rename("/bin", "/"), SyscallFailsWithErrno(EBUSY));
    42  }
    43  
    44  TEST(RenameTest, SourceIsAncestorOfTarget) {
    45    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    46    auto subdir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path()));
    47    ASSERT_THAT(rename(dir.path().c_str(), subdir.path().c_str()),
    48                SyscallFailsWithErrno(EINVAL));
    49  
    50    // Try an even deeper directory.
    51    auto deep_subdir =
    52        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(subdir.path()));
    53    ASSERT_THAT(rename(dir.path().c_str(), deep_subdir.path().c_str()),
    54                SyscallFailsWithErrno(EINVAL));
    55  }
    56  
    57  TEST(RenameTest, TargetIsAncestorOfSource) {
    58    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    59    auto subdir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir.path()));
    60    ASSERT_THAT(rename(subdir.path().c_str(), dir.path().c_str()),
    61                SyscallFailsWithErrno(ENOTEMPTY));
    62  
    63    // Try an even deeper directory.
    64    auto deep_subdir =
    65        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(subdir.path()));
    66    ASSERT_THAT(rename(deep_subdir.path().c_str(), dir.path().c_str()),
    67                SyscallFailsWithErrno(ENOTEMPTY));
    68  }
    69  
    70  TEST(RenameTest, FileToSelf) {
    71    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    72    EXPECT_THAT(rename(f.path().c_str(), f.path().c_str()), SyscallSucceeds());
    73  }
    74  
    75  TEST(RenameTest, DirectoryToSelf) {
    76    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    77    EXPECT_THAT(rename(f.path().c_str(), f.path().c_str()), SyscallSucceeds());
    78  }
    79  
    80  TEST(RenameTest, FileToSameDirectory) {
    81    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
    82    std::string const newpath = NewTempAbsPath();
    83    ASSERT_THAT(rename(f.path().c_str(), newpath.c_str()), SyscallSucceeds());
    84    std::string const oldpath = f.release();
    85    f.reset(newpath);
    86    EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false));
    87    EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true));
    88  }
    89  
    90  TEST(RenameTest, DirectoryToSameDirectory) {
    91    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
    92    std::string const newpath = NewTempAbsPath();
    93    ASSERT_THAT(rename(dir.path().c_str(), newpath.c_str()), SyscallSucceeds());
    94    std::string const oldpath = dir.release();
    95    dir.reset(newpath);
    96    EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false));
    97    EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true));
    98  }
    99  
   100  TEST(RenameTest, FileToParentDirectory) {
   101    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   102    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path()));
   103    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir2.path()));
   104    std::string const newpath = NewTempAbsPathInDir(dir1.path());
   105    ASSERT_THAT(rename(f.path().c_str(), newpath.c_str()), SyscallSucceeds());
   106    std::string const oldpath = f.release();
   107    f.reset(newpath);
   108    EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false));
   109    EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true));
   110  }
   111  
   112  TEST(RenameTest, DirectoryToParentDirectory) {
   113    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   114    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path()));
   115    auto dir3 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir2.path()));
   116    EXPECT_THAT(IsDirectory(dir3.path()), IsPosixErrorOkAndHolds(true));
   117    std::string const newpath = NewTempAbsPathInDir(dir1.path());
   118    ASSERT_THAT(rename(dir3.path().c_str(), newpath.c_str()), SyscallSucceeds());
   119    std::string const oldpath = dir3.release();
   120    dir3.reset(newpath);
   121    EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false));
   122    EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true));
   123    EXPECT_THAT(IsDirectory(newpath), IsPosixErrorOkAndHolds(true));
   124  }
   125  
   126  TEST(RenameTest, FileToChildDirectory) {
   127    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   128    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path()));
   129    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
   130    std::string const newpath = NewTempAbsPathInDir(dir2.path());
   131    ASSERT_THAT(rename(f.path().c_str(), newpath.c_str()), SyscallSucceeds());
   132    std::string const oldpath = f.release();
   133    f.reset(newpath);
   134    EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false));
   135    EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true));
   136  }
   137  
   138  TEST(RenameTest, DirectoryToChildDirectory) {
   139    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   140    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path()));
   141    auto dir3 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path()));
   142    std::string const newpath = NewTempAbsPathInDir(dir2.path());
   143    ASSERT_THAT(rename(dir3.path().c_str(), newpath.c_str()), SyscallSucceeds());
   144    std::string const oldpath = dir3.release();
   145    dir3.reset(newpath);
   146    EXPECT_THAT(Exists(oldpath), IsPosixErrorOkAndHolds(false));
   147    EXPECT_THAT(Exists(newpath), IsPosixErrorOkAndHolds(true));
   148    EXPECT_THAT(IsDirectory(newpath), IsPosixErrorOkAndHolds(true));
   149  }
   150  
   151  TEST(RenameTest, DirectoryToOwnChildDirectory) {
   152    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   153    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(dir1.path()));
   154    std::string const newpath = NewTempAbsPathInDir(dir2.path());
   155    ASSERT_THAT(rename(dir1.path().c_str(), newpath.c_str()),
   156                SyscallFailsWithErrno(EINVAL));
   157  }
   158  
   159  TEST(RenameTest, FileOverwritesFile) {
   160    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   161    auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   162        dir.path(), "first", TempPath::kDefaultFileMode));
   163    auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   164        dir.path(), "second", TempPath::kDefaultFileMode));
   165    ASSERT_THAT(rename(f1.path().c_str(), f2.path().c_str()), SyscallSucceeds());
   166    EXPECT_THAT(Exists(f1.path()), IsPosixErrorOkAndHolds(false));
   167  
   168    f1.release();
   169    std::string f2_contents;
   170    ASSERT_NO_ERRNO(GetContents(f2.path(), &f2_contents));
   171    EXPECT_EQ("first", f2_contents);
   172  }
   173  
   174  TEST(RenameTest, DirectoryOverwritesDirectoryLinkCount) {
   175    // Directory link counts are synthetic on overlay filesystems.
   176    SKIP_IF(ASSERT_NO_ERRNO_AND_VALUE(IsOverlayfs(GetAbsoluteTestTmpdir())));
   177  
   178    auto parent1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   179    EXPECT_THAT(Links(parent1.path()), IsPosixErrorOkAndHolds(2));
   180  
   181    auto parent2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   182    EXPECT_THAT(Links(parent2.path()), IsPosixErrorOkAndHolds(2));
   183  
   184    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent1.path()));
   185    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(parent2.path()));
   186  
   187    EXPECT_THAT(Links(parent1.path()), IsPosixErrorOkAndHolds(3));
   188    EXPECT_THAT(Links(parent2.path()), IsPosixErrorOkAndHolds(3));
   189  
   190    ASSERT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()),
   191                SyscallSucceeds());
   192  
   193    EXPECT_THAT(Links(parent1.path()), IsPosixErrorOkAndHolds(2));
   194    EXPECT_THAT(Links(parent2.path()), IsPosixErrorOkAndHolds(3));
   195  }
   196  
   197  TEST(RenameTest, FileDoesNotExist) {
   198    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   199    const std::string source = JoinPath(dir.path(), "source");
   200    const std::string dest = JoinPath(dir.path(), "dest");
   201    ASSERT_THAT(rename(source.c_str(), dest.c_str()),
   202                SyscallFailsWithErrno(ENOENT));
   203  }
   204  
   205  TEST(RenameTest, FileDoesNotOverwriteDirectory) {
   206    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   207    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   208    ASSERT_THAT(rename(f.path().c_str(), dir.path().c_str()),
   209                SyscallFailsWithErrno(EISDIR));
   210  }
   211  
   212  TEST(RenameTest, DirectoryDoesNotOverwriteFile) {
   213    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   214    auto dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   215    ASSERT_THAT(rename(dir.path().c_str(), f.path().c_str()),
   216                SyscallFailsWithErrno(ENOTDIR));
   217  }
   218  
   219  TEST(RenameTest, DirectoryOverwritesEmptyDirectory) {
   220    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   221    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
   222    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   223    EXPECT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()),
   224                SyscallSucceeds());
   225    EXPECT_THAT(Exists(dir1.path()), IsPosixErrorOkAndHolds(false));
   226    dir1.release();
   227    EXPECT_THAT(Exists(JoinPath(dir2.path(), Basename(f.path()))),
   228                IsPosixErrorOkAndHolds(true));
   229    f.release();
   230  }
   231  
   232  TEST(RenameTest, FailsWithDots) {
   233    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   234    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   235    auto dir1_dot = absl::StrCat(dir1.path(), "/.");
   236    auto dir2_dot = absl::StrCat(dir2.path(), "/.");
   237    auto dir1_dot_dot = absl::StrCat(dir1.path(), "/..");
   238    auto dir2_dot_dot = absl::StrCat(dir2.path(), "/..");
   239  
   240    // Try with dot paths in the first argument
   241    EXPECT_THAT(rename(dir1_dot.c_str(), dir2.path().c_str()),
   242                SyscallFailsWithErrno(EBUSY));
   243    EXPECT_THAT(rename(dir1_dot_dot.c_str(), dir2.path().c_str()),
   244                SyscallFailsWithErrno(EBUSY));
   245  
   246    // Try with dot paths in the second argument
   247    EXPECT_THAT(rename(dir1.path().c_str(), dir2_dot.c_str()),
   248                SyscallFailsWithErrno(EBUSY));
   249    EXPECT_THAT(rename(dir1.path().c_str(), dir2_dot_dot.c_str()),
   250                SyscallFailsWithErrno(EBUSY));
   251  }
   252  
   253  TEST(RenameTest, DirectoryDoesNotOverwriteNonemptyDirectory) {
   254    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   255    auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
   256    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   257    auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir2.path()));
   258    ASSERT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()),
   259                SyscallFailsWithErrno(ENOTEMPTY));
   260  }
   261  
   262  TEST(RenameTest, FailsWhenOldParentNotWritable) {
   263    // Drop capabilities that allow us to override file and directory permissions.
   264    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
   265    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
   266  
   267    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   268    auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
   269    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   270    // dir1 is not writable.
   271    ASSERT_THAT(chmod(dir1.path().c_str(), 0555), SyscallSucceeds());
   272  
   273    std::string const newpath = NewTempAbsPathInDir(dir2.path());
   274    EXPECT_THAT(rename(f1.path().c_str(), newpath.c_str()),
   275                SyscallFailsWithErrno(EACCES));
   276  }
   277  
   278  TEST(RenameTest, FailsWhenNewParentNotWritable) {
   279    // Drop capabilities that allow us to override file and directory permissions.
   280    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
   281    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
   282  
   283    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   284    auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
   285    // dir2 is not writable.
   286    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(
   287        TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0555));
   288  
   289    std::string const newpath = NewTempAbsPathInDir(dir2.path());
   290    EXPECT_THAT(rename(f1.path().c_str(), newpath.c_str()),
   291                SyscallFailsWithErrno(EACCES));
   292  }
   293  
   294  // Equivalent to FailsWhenNewParentNotWritable, but with a destination file
   295  // to overwrite.
   296  TEST(RenameTest, OverwriteFailsWhenNewParentNotWritable) {
   297    // Drop capabilities that allow us to override file and directory permissions.
   298    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
   299    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
   300  
   301    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   302    auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
   303  
   304    // dir2 is not writable.
   305    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   306    auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir2.path()));
   307    ASSERT_THAT(chmod(dir2.path().c_str(), 0555), SyscallSucceeds());
   308  
   309    EXPECT_THAT(rename(f1.path().c_str(), f2.path().c_str()),
   310                SyscallFailsWithErrno(EACCES));
   311  }
   312  
   313  // If the parent directory of source is not accessible, rename returns EACCES
   314  // because the user cannot determine if source exists.
   315  TEST(RenameTest, FileDoesNotExistWhenNewParentNotExecutable) {
   316    // Drop capabilities that allow us to override file and directory permissions.
   317    AutoCapability cap1(CAP_DAC_OVERRIDE, false);
   318    AutoCapability cap2(CAP_DAC_READ_SEARCH, false);
   319  
   320    // No execute permission.
   321    auto dir = ASSERT_NO_ERRNO_AND_VALUE(
   322        TempPath::CreateDirWith(GetAbsoluteTestTmpdir(), 0400));
   323  
   324    const std::string source = JoinPath(dir.path(), "source");
   325    const std::string dest = JoinPath(dir.path(), "dest");
   326    ASSERT_THAT(rename(source.c_str(), dest.c_str()),
   327                SyscallFailsWithErrno(EACCES));
   328  }
   329  
   330  TEST(RenameTest, DirectoryWithOpenFdOverwritesEmptyDirectory) {
   331    auto dir1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   332    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileIn(dir1.path()));
   333    auto dir2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   334  
   335    // Get an fd on dir1
   336    int fd;
   337    ASSERT_THAT(fd = open(dir1.path().c_str(), O_DIRECTORY), SyscallSucceeds());
   338    auto close_f = Cleanup([fd] {
   339      // Close the fd on f.
   340      EXPECT_THAT(close(fd), SyscallSucceeds());
   341    });
   342  
   343    EXPECT_THAT(rename(dir1.path().c_str(), dir2.path().c_str()),
   344                SyscallSucceeds());
   345  
   346    const std::string new_f_path = JoinPath(dir2.path(), Basename(f.path()));
   347  
   348    auto remove_f = Cleanup([&] {
   349      // Delete f in its new location.
   350      ASSERT_NO_ERRNO(Delete(new_f_path));
   351      f.release();
   352    });
   353  
   354    EXPECT_THAT(Exists(dir1.path()), IsPosixErrorOkAndHolds(false));
   355    dir1.release();
   356    EXPECT_THAT(Exists(new_f_path), IsPosixErrorOkAndHolds(true));
   357  }
   358  
   359  TEST(RenameTest, FileWithOpenFd) {
   360    TempPath root_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   361    TempPath dir1 =
   362        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path()));
   363    TempPath dir2 =
   364        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path()));
   365    TempPath dir3 =
   366        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path()));
   367  
   368    // Create file in dir1.
   369    constexpr char kContents[] = "foo";
   370    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   371        dir1.path(), kContents, TempPath::kDefaultFileMode));
   372  
   373    // Get fd on file.
   374    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(f.path(), O_RDWR));
   375  
   376    // Move f to dir2.
   377    const std::string path2 = NewTempAbsPathInDir(dir2.path());
   378    ASSERT_THAT(rename(f.path().c_str(), path2.c_str()), SyscallSucceeds());
   379  
   380    // Read f's kContents.
   381    char buf[sizeof(kContents)];
   382    EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(kContents), 0),
   383                SyscallSucceedsWithValue(sizeof(kContents) - 1));
   384    EXPECT_EQ(absl::string_view(buf, sizeof(buf) - 1), kContents);
   385  
   386    // Move f to dir3.
   387    const std::string path3 = NewTempAbsPathInDir(dir3.path());
   388    ASSERT_THAT(rename(path2.c_str(), path3.c_str()), SyscallSucceeds());
   389  
   390    // Read f's kContents.
   391    EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(kContents), 0),
   392                SyscallSucceedsWithValue(sizeof(kContents) - 1));
   393    EXPECT_EQ(absl::string_view(buf, sizeof(buf) - 1), kContents);
   394  }
   395  
   396  // Tests that calling rename with file path ending with . or .. causes EBUSY.
   397  TEST(RenameTest, PathEndingWithDots) {
   398    TempPath root_dir = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   399    TempPath dir1 =
   400        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path()));
   401    TempPath dir2 =
   402        ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDirIn(root_dir.path()));
   403  
   404    // Try to move dir1 into dir2 but mess up the paths.
   405    auto dir1Dot = JoinPath(dir1.path(), ".");
   406    auto dir2Dot = JoinPath(dir2.path(), ".");
   407    auto dir1DotDot = JoinPath(dir1.path(), "..");
   408    auto dir2DotDot = JoinPath(dir2.path(), "..");
   409    ASSERT_THAT(rename(dir1.path().c_str(), dir2Dot.c_str()),
   410                SyscallFailsWithErrno(EBUSY));
   411    ASSERT_THAT(rename(dir1.path().c_str(), dir2DotDot.c_str()),
   412                SyscallFailsWithErrno(EBUSY));
   413    ASSERT_THAT(rename(dir1Dot.c_str(), dir2.path().c_str()),
   414                SyscallFailsWithErrno(EBUSY));
   415    ASSERT_THAT(rename(dir1DotDot.c_str(), dir2.path().c_str()),
   416                SyscallFailsWithErrno(EBUSY));
   417  }
   418  
   419  // Calling rename with file path ending with . or .. causes EBUSY in sysfs.
   420  TEST(RenameTest, SysfsPathEndingWithDots) {
   421    // If a non-root user tries to rename inside /sys then we get EPERM.
   422    SKIP_IF(geteuid() != 0);
   423    ASSERT_THAT(rename("/sys/devices/system/cpu/online", "/sys/."),
   424                SyscallFailsWithErrno(EBUSY));
   425    ASSERT_THAT(rename("/sys/devices/system/cpu/online", "/sys/.."),
   426                SyscallFailsWithErrno(EBUSY));
   427  }
   428  
   429  TEST(RenameTest, SysfsFileToSelf) {
   430    // If a non-root user tries to rename inside /sys then we get EPERM.
   431    SKIP_IF(geteuid() != 0);
   432    std::string const path = "/sys/devices/system/cpu/online";
   433    EXPECT_THAT(rename(path.c_str(), path.c_str()), SyscallSucceeds());
   434  }
   435  
   436  TEST(RenameTest, SysfsDirectoryToSelf) {
   437    // If a non-root user tries to rename inside /sys then we get EPERM.
   438    SKIP_IF(geteuid() != 0);
   439    std::string const path = "/sys/devices";
   440    EXPECT_THAT(rename(path.c_str(), path.c_str()), SyscallSucceeds());
   441  }
   442  
   443  #ifndef SYS_renameat2
   444  #if defined(__x86_64__)
   445  #define SYS_renameat2 316
   446  #elif defined(__aarch64__)
   447  #define SYS_renameat2 276
   448  #else
   449  #error "Unknown architecture"
   450  #endif
   451  #endif  // SYS_renameat2
   452  
   453  #ifndef RENAME_NOREPLACE
   454  #define RENAME_NOREPLACE (1 << 0)
   455  #endif  // RENAME_NOREPLACE
   456  
   457  int renameat2(int olddirfd, const char* oldpath, int newdirfd,
   458                const char* newpath, unsigned int flags) {
   459    return syscall(SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags);
   460  }
   461  
   462  TEST(Renameat2Test, NoReplaceSuccess) {
   463    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   464    std::string const newpath = NewTempAbsPath();
   465    // renameat2 may fail with ENOSYS (if the syscall is unsupported) or EINVAL
   466    // (if flags are unsupported), or succeed (if RENAME_NOREPLACE is operating
   467    // correctly).
   468    EXPECT_THAT(
   469        renameat2(AT_FDCWD, f.path().c_str(), AT_FDCWD, newpath.c_str(),
   470                  RENAME_NOREPLACE),
   471        AnyOf(SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL)), SyscallSucceeds()));
   472  }
   473  
   474  TEST(Renameat2Test, NoReplaceExisting) {
   475    auto f1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   476    auto f2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   477    // renameat2 may fail with ENOSYS (if the syscall is unsupported), EINVAL (if
   478    // flags are unsupported), or EEXIST (if RENAME_NOREPLACE is operating
   479    // correctly).
   480    EXPECT_THAT(renameat2(AT_FDCWD, f1.path().c_str(), AT_FDCWD,
   481                          f2.path().c_str(), RENAME_NOREPLACE),
   482                SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL, EEXIST)));
   483  }
   484  
   485  TEST(Renameat2Test, NoReplaceDot) {
   486    auto d1 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   487    auto d2 = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
   488    // renameat2 may fail with ENOSYS (if the syscall is unsupported), EINVAL (if
   489    // flags are unsupported), or EEXIST (if RENAME_NOREPLACE is operating
   490    // correctly).
   491    EXPECT_THAT(
   492        renameat2(AT_FDCWD, d1.path().c_str(), AT_FDCWD,
   493                  absl::StrCat(d2.path(), "/.").c_str(), RENAME_NOREPLACE),
   494        SyscallFailsWithErrno(AnyOf(ENOSYS, EINVAL, EEXIST)));
   495  }
   496  
   497  }  // namespace
   498  
   499  }  // namespace testing
   500  }  // namespace gvisor