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

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

DEFINITIONS

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

   1 /* Test renameatu.
   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 <renameatu.h>
  22 
  23 #include <stdio.h>
  24 
  25 #include "signature.h"
  26 SIGNATURE_CHECK (renameatu, int,
  27                  (int, char const *, int, char const *, unsigned int));
  28 
  29 #include <dirent.h>
  30 #include <fcntl.h>
  31 #include <errno.h>
  32 #include <stdbool.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <unistd.h>
  36 #include <sys/stat.h>
  37 
  38 #include "filenamecat.h"
  39 #include "ignore-value.h"
  40 #include "macros.h"
  41 
  42 #define BASE "test-renameatu.t"
  43 
  44 #include "test-rename.h"
  45 
  46 static int dfd1 = AT_FDCWD;
  47 static int dfd2 = AT_FDCWD;
  48 
  49 /* Wrapper to test renameatu like rename.  */
  50 static int
  51 do_rename (char const *name1, char const *name2)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53   return renameatu (dfd1, name1, dfd2, name2, 0);
  54 }
  55 
  56 int
  57 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59   int i;
  60   int dfd;
  61   char *cwd;
  62   int result;
  63 
  64   /* Clean up any trash from prior testsuite runs.  */
  65   ignore_value (system ("rm -rf " BASE "*"));
  66 
  67   /* Test behaviour for invalid file descriptors.  */
  68   {
  69     errno = 0;
  70     ASSERT (renameatu (-1, "foo", AT_FDCWD, "bar", 0) == -1);
  71     ASSERT (errno == EBADF);
  72   }
  73   {
  74     close (99);
  75     errno = 0;
  76     ASSERT (renameatu (99, "foo", AT_FDCWD, "bar", 0) == -1);
  77     ASSERT (errno == EBADF);
  78   }
  79   ASSERT (close (creat (BASE "oo", 0600)) == 0);
  80   {
  81     errno = 0;
  82     ASSERT (renameatu (AT_FDCWD, BASE "oo", -1, "bar", 0) == -1);
  83     ASSERT (errno == EBADF);
  84   }
  85   {
  86     errno = 0;
  87     ASSERT (renameatu (AT_FDCWD, BASE "oo", 99, "bar", 0) == -1);
  88     ASSERT (errno == EBADF);
  89   }
  90   ASSERT (unlink (BASE "oo") == 0);
  91 
  92   /* Test basic rename functionality, using current directory.  */
  93   result = test_rename (do_rename, false);
  94   dfd1 = open (".", O_RDONLY);
  95   ASSERT (0 <= dfd1);
  96   ASSERT (test_rename (do_rename, false) == result);
  97   dfd2 = dfd1;
  98   ASSERT (test_rename (do_rename, false) == result);
  99   dfd1 = AT_FDCWD;
 100   ASSERT (test_rename (do_rename, false) == result);
 101   ASSERT (close (dfd2) == 0);
 102 
 103   /* Create locations to manipulate.  */
 104   ASSERT (mkdir (BASE "sub1", 0700) == 0);
 105   ASSERT (mkdir (BASE "sub2", 0700) == 0);
 106   dfd = creat (BASE "00", 0600);
 107   ASSERT (0 <= dfd);
 108   ASSERT (close (dfd) == 0);
 109   cwd = getcwd (NULL, 0);
 110   ASSERT (cwd);
 111 
 112   dfd = open (BASE "sub1", O_RDONLY);
 113   ASSERT (0 <= dfd);
 114   ASSERT (chdir (BASE "sub2") == 0);
 115 
 116   /* There are 16 possible scenarios, based on whether an fd is
 117      AT_FDCWD or real, and whether a file is absolute or relative.
 118 
 119      To ensure that we test all of the code paths (rather than
 120      triggering early normalization optimizations), we use a loop to
 121      repeatedly rename a file in the parent directory, use an fd open
 122      on subdirectory 1, all while executing in subdirectory 2; all
 123      relative names are thus given with a leading "../".  Finally, the
 124      last scenario (two relative paths given, neither one AT_FDCWD)
 125      has two paths, based on whether the two fds are equivalent, so we
 126      do the other variant after the loop.  */
 127   for (i = 0; i < 16; i++)
 128     {
 129       int fd1 = (i & 8) ? dfd : AT_FDCWD;
 130       char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
 131       int fd2 = (i & 2) ? dfd : AT_FDCWD;
 132       char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
 133 
 134       ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
 135       ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
 136       ASSERT (renameatu (fd1, file1, fd2, file2, 0) == 0);
 137       free (file1);
 138       free (file2);
 139     }
 140   dfd2 = open ("..", O_RDONLY);
 141   ASSERT (0 <= dfd2);
 142   ASSERT (renameatu (dfd, "../" BASE "16", dfd2, BASE "17", 0) == 0);
 143   ASSERT (close (dfd2) == 0);
 144 
 145   /* Now we change back to the parent directory, and set dfd to ".";
 146      using dfd in remaining tests will expose any bugs if emulation
 147      via /proc/self/fd doesn't check for empty names.  */
 148   ASSERT (chdir ("..") == 0);
 149   ASSERT (close (dfd) == 0);
 150   dfd = open (".", O_RDONLY);
 151   ASSERT (0 <= dfd);
 152 
 153   ASSERT (close (creat (BASE "sub2/file", 0600)) == 0);
 154   errno = 0;
 155   ASSERT (renameatu (dfd, BASE "sub1", dfd, BASE "sub2", 0) == -1);
 156   ASSERT (errno == EEXIST || errno == ENOTEMPTY);
 157   ASSERT (unlink (BASE "sub2/file") == 0);
 158   errno = 0;
 159   ASSERT (renameatu (dfd, BASE "sub2", dfd, BASE "sub1/.", 0) == -1);
 160   ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY
 161           || errno == ENOTEMPTY || errno == EEXIST
 162           || errno == ENOENT /* WSL */);
 163   errno = 0;
 164   ASSERT (renameatu (dfd, BASE "sub2/.", dfd, BASE "sub1", 0) == -1);
 165   ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST
 166           || errno == ENOENT /* WSL */);
 167   errno = 0;
 168   ASSERT (renameatu (dfd, BASE "17", dfd, BASE "sub1", 0) == -1);
 169   ASSERT (errno == EISDIR);
 170   errno = 0;
 171   ASSERT (renameatu (dfd, BASE "nosuch", dfd, BASE "18", 0) == -1);
 172   ASSERT (errno == ENOENT);
 173   errno = 0;
 174   ASSERT (renameatu (dfd, "", dfd, BASE "17", 0) == -1);
 175   ASSERT (errno == ENOENT);
 176   errno = 0;
 177   ASSERT (renameatu (dfd, BASE "17", dfd, "", 0) == -1);
 178   ASSERT (errno == ENOENT);
 179   errno = 0;
 180   ASSERT (renameatu (dfd, BASE "sub2", dfd, BASE "17", 0) == -1);
 181   ASSERT (errno == ENOTDIR);
 182   errno = 0;
 183   ASSERT (renameatu (dfd, BASE "17/", dfd, BASE "18", 0) == -1);
 184   ASSERT (errno == ENOTDIR);
 185   errno = 0;
 186   ASSERT (renameatu (dfd, BASE "17", dfd, BASE "18/", 0) == -1);
 187   ASSERT (errno == ENOTDIR || errno == ENOENT);
 188 
 189   /* Finally, make sure we cannot overwrite existing files.  */
 190   ASSERT (close (creat (BASE "sub2/file", 0600)) == 0);
 191   errno = 0;
 192   ASSERT ((renameatu (dfd, BASE "sub2/file", dfd, BASE "sub2/file",
 193                       RENAME_NOREPLACE)
 194            == -1)
 195           && errno == EEXIST);
 196   errno = 0;
 197   ASSERT ((renameatu (dfd, BASE "sub2", dfd, BASE "sub2", RENAME_NOREPLACE)
 198            == -1)
 199           && errno == EEXIST);
 200   errno = 0;
 201   ASSERT ((renameatu (dfd, BASE "sub2", dfd, BASE "sub1", RENAME_NOREPLACE)
 202            == -1)
 203           && errno == EEXIST);
 204   errno = 0;
 205   ASSERT ((renameatu (dfd, BASE "sub2/file", dfd, BASE "17", RENAME_NOREPLACE)
 206            == -1)
 207           && errno == EEXIST);
 208 
 209   /* Cleanup.  */
 210   ASSERT (close (dfd) == 0);
 211   ASSERT (unlink (BASE "sub2/file") == 0);
 212   ASSERT (unlink (BASE "17") == 0);
 213   ASSERT (rmdir (BASE "sub1") == 0);
 214   ASSERT (rmdir (BASE "sub2") == 0);
 215   free (cwd);
 216 
 217   if (result)
 218     fputs ("skipping test: symlinks not supported on this file system\n",
 219            stderr);
 220   return result;
 221 }

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