root/maint/gnulib/tests/test-renameat.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. do_rename
  2. main

   1 /* Tests of renameat.
   2    Copyright (C) 2009-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Eric Blake <ebb9@byu.net>, 2009.  */
  18 
  19 #include <config.h>
  20 
  21 #include <stdio.h>
  22 
  23 #include "signature.h"
  24 SIGNATURE_CHECK (renameat, int, (int, char const *, int, char const *));
  25 
  26 #include <dirent.h>
  27 #include <fcntl.h>
  28 #include <errno.h>
  29 #include <stdbool.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <unistd.h>
  33 #include <sys/stat.h>
  34 
  35 #include "filenamecat.h"
  36 #include "ignore-value.h"
  37 #include "macros.h"
  38 
  39 #define BASE "test-renameat.t"
  40 
  41 #include "test-rename.h"
  42 
  43 static int dfd1 = AT_FDCWD;
  44 static int dfd2 = AT_FDCWD;
  45 
  46 /* Wrapper to test renameat like rename.  */
  47 static int
  48 do_rename (char const *name1, char const *name2)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50   return renameat (dfd1, name1, dfd2, name2);
  51 }
  52 
  53 int
  54 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56   int i;
  57   int dfd;
  58   char *cwd;
  59   int result;
  60 
  61   /* Clean up any trash from prior testsuite runs.  */
  62   ignore_value (system ("rm -rf " BASE "*"));
  63 
  64   /* Test behaviour for invalid file descriptors.  */
  65   {
  66     errno = 0;
  67     ASSERT (renameat (-1, "foo", AT_FDCWD, "bar") == -1);
  68     ASSERT (errno == EBADF);
  69   }
  70   {
  71     close (99);
  72     errno = 0;
  73     ASSERT (renameat (99, "foo", AT_FDCWD, "bar") == -1);
  74     ASSERT (errno == EBADF);
  75   }
  76   ASSERT (close (creat (BASE "oo", 0600)) == 0);
  77   {
  78     errno = 0;
  79     ASSERT (renameat (AT_FDCWD, BASE "oo", -1, "bar") == -1);
  80     ASSERT (errno == EBADF);
  81   }
  82   {
  83     errno = 0;
  84     ASSERT (renameat (AT_FDCWD, BASE "oo", 99, "bar") == -1);
  85     ASSERT (errno == EBADF);
  86   }
  87   ASSERT (unlink (BASE "oo") == 0);
  88 
  89   /* Test basic rename functionality, using current directory.  */
  90   result = test_rename (do_rename, false);
  91   dfd1 = open (".", O_RDONLY);
  92   ASSERT (0 <= dfd1);
  93   ASSERT (test_rename (do_rename, false) == result);
  94   dfd2 = dfd1;
  95   ASSERT (test_rename (do_rename, false) == result);
  96   dfd1 = AT_FDCWD;
  97   ASSERT (test_rename (do_rename, false) == result);
  98   ASSERT (close (dfd2) == 0);
  99 
 100   /* Create locations to manipulate.  */
 101   ASSERT (mkdir (BASE "sub1", 0700) == 0);
 102   ASSERT (mkdir (BASE "sub2", 0700) == 0);
 103   dfd = creat (BASE "00", 0600);
 104   ASSERT (0 <= dfd);
 105   ASSERT (close (dfd) == 0);
 106   cwd = getcwd (NULL, 0);
 107   ASSERT (cwd);
 108 
 109   dfd = open (BASE "sub1", O_RDONLY);
 110   ASSERT (0 <= dfd);
 111   ASSERT (chdir (BASE "sub2") == 0);
 112 
 113   /* There are 16 possible scenarios, based on whether an fd is
 114      AT_FDCWD or real, and whether a file is absolute or relative.
 115 
 116      To ensure that we test all of the code paths (rather than
 117      triggering early normalization optimizations), we use a loop to
 118      repeatedly rename a file in the parent directory, use an fd open
 119      on subdirectory 1, all while executing in subdirectory 2; all
 120      relative names are thus given with a leading "../".  Finally, the
 121      last scenario (two relative paths given, neither one AT_FDCWD)
 122      has two paths, based on whether the two fds are equivalent, so we
 123      do the other variant after the loop.  */
 124   for (i = 0; i < 16; i++)
 125     {
 126       int fd1 = (i & 8) ? dfd : AT_FDCWD;
 127       char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
 128       int fd2 = (i & 2) ? dfd : AT_FDCWD;
 129       char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
 130 
 131       ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
 132       ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
 133       ASSERT (renameat (fd1, file1, fd2, file2) == 0);
 134       free (file1);
 135       free (file2);
 136     }
 137   dfd2 = open ("..", O_RDONLY);
 138   ASSERT (0 <= dfd2);
 139   ASSERT (renameat (dfd, "../" BASE "16", dfd2, BASE "17") == 0);
 140   ASSERT (close (dfd2) == 0);
 141 
 142   /* Now we change back to the parent directory, and set dfd to ".";
 143      using dfd in remaining tests will expose any bugs if emulation
 144      via /proc/self/fd doesn't check for empty names.  */
 145   ASSERT (chdir ("..") == 0);
 146   ASSERT (close (dfd) == 0);
 147   dfd = open (".", O_RDONLY);
 148   ASSERT (0 <= dfd);
 149 
 150   ASSERT (close (creat (BASE "sub2/file", 0600)) == 0);
 151   errno = 0;
 152   ASSERT (renameat (dfd, BASE "sub1", dfd, BASE "sub2") == -1);
 153   ASSERT (errno == EEXIST || errno == ENOTEMPTY);
 154   ASSERT (unlink (BASE "sub2/file") == 0);
 155   errno = 0;
 156   ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1/.") == -1);
 157   ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY
 158           || errno == ENOTEMPTY || errno == EEXIST
 159           || errno == ENOENT /* WSL */);
 160   errno = 0;
 161   ASSERT (renameat (dfd, BASE "sub2/.", dfd, BASE "sub1") == -1);
 162   ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST
 163           || errno == ENOENT /* WSL */);
 164   errno = 0;
 165   ASSERT (renameat (dfd, BASE "17", dfd, BASE "sub1") == -1);
 166   ASSERT (errno == EISDIR);
 167   errno = 0;
 168   ASSERT (renameat (dfd, BASE "nosuch", dfd, BASE "18") == -1);
 169   ASSERT (errno == ENOENT);
 170   errno = 0;
 171   ASSERT (renameat (dfd, "", dfd, BASE "17") == -1);
 172   ASSERT (errno == ENOENT);
 173   errno = 0;
 174   ASSERT (renameat (dfd, BASE "17", dfd, "") == -1);
 175   ASSERT (errno == ENOENT);
 176   errno = 0;
 177   ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "17") == -1);
 178   ASSERT (errno == ENOTDIR);
 179   errno = 0;
 180   ASSERT (renameat (dfd, BASE "17/", dfd, BASE "18") == -1);
 181   ASSERT (errno == ENOTDIR);
 182   errno = 0;
 183   ASSERT (renameat (dfd, BASE "17", dfd, BASE "18/") == -1);
 184   ASSERT (errno == ENOTDIR || errno == ENOENT);
 185 
 186   /* Finally, make sure we can overwrite existing files.  */
 187   ASSERT (close (creat (BASE "sub2/file", 0600)) == 0);
 188   errno = 0;
 189   ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1") == 0);
 190   ASSERT (renameat (dfd, BASE "sub1/file", dfd, BASE "17") == 0);
 191 
 192   /* Cleanup.  */
 193   ASSERT (close (dfd) == 0);
 194   errno = 0;
 195   ASSERT (unlink (BASE "sub1/file") == -1);
 196   ASSERT (errno == ENOENT);
 197   ASSERT (unlink (BASE "17") == 0);
 198   ASSERT (rmdir (BASE "sub1") == 0);
 199   errno = 0;
 200   ASSERT (rmdir (BASE "sub2") == -1);
 201   ASSERT (errno == ENOENT);
 202   free (cwd);
 203 
 204   if (result)
 205     fputs ("skipping test: symlinks not supported on this file system\n",
 206            stderr);
 207   return result;
 208 }

/* [previous][next][first][last][top][bottom][index][help] */