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

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

DEFINITIONS

This source file includes following definitions.
  1. do_link
  2. check_same_link
  3. main

   1 /* Tests of linkat.
   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 <unistd.h>
  22 
  23 #include "signature.h"
  24 SIGNATURE_CHECK (linkat, int, (int, char const *, int, char const *, int));
  25 
  26 #include <fcntl.h>
  27 #include <errno.h>
  28 #include <stdbool.h>
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <sys/stat.h>
  33 
  34 #include "areadlink.h"
  35 #include "filenamecat.h"
  36 #include "same-inode.h"
  37 #include "ignore-value.h"
  38 #include "macros.h"
  39 
  40 #define BASE "test-linkat.t"
  41 
  42 #include "test-link.h"
  43 
  44 static int dfd1 = AT_FDCWD;
  45 static int dfd2 = AT_FDCWD;
  46 static int flag = AT_SYMLINK_FOLLOW;
  47 
  48 /* Wrapper to test linkat like link.  */
  49 static int
  50 do_link (char const *name1, char const *name2)
     /* [previous][next][first][last][top][bottom][index][help] */
  51 {
  52   return linkat (dfd1, name1, dfd2, name2, flag);
  53 }
  54 
  55 /* Can we expect that link() and linkat(), when called on a symlink,
  56    increment the link count of that symlink?  */
  57 #if LINK_FOLLOWS_SYMLINKS == 0
  58 # define EXPECT_LINK_HARDLINKS_SYMLINKS 1
  59 #elif LINK_FOLLOWS_SYMLINKS == -1
  60 extern int __xpg4;
  61 # define EXPECT_LINK_HARDLINKS_SYMLINKS (__xpg4 == 0)
  62 #else
  63 # define EXPECT_LINK_HARDLINKS_SYMLINKS 0
  64 #endif
  65 
  66 /* Wrapper to see if two symlinks act the same.  */
  67 static void
  68 check_same_link (char const *name1, char const *name2)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70   struct stat st1;
  71   struct stat st2;
  72   char *contents1;
  73   char *contents2;
  74   ASSERT (lstat (name1, &st1) == 0);
  75   ASSERT (lstat (name2, &st2) == 0);
  76   contents1 = areadlink_with_size (name1, st1.st_size);
  77   contents2 = areadlink_with_size (name2, st2.st_size);
  78   ASSERT (contents1);
  79   ASSERT (contents2);
  80   ASSERT (strcmp (contents1, contents2) == 0);
  81   if (EXPECT_LINK_HARDLINKS_SYMLINKS)
  82     ASSERT (SAME_INODE (st1, st2));
  83   free (contents1);
  84   free (contents2);
  85 }
  86 
  87 int
  88 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90   int i;
  91   int dfd;
  92   char *cwd;
  93   int result;
  94 
  95   /* Clean up any trash from prior testsuite runs.  */
  96   ignore_value (system ("rm -rf " BASE "*"));
  97 
  98   /* Test behaviour for invalid file descriptors.  */
  99   {
 100     errno = 0;
 101     ASSERT (linkat (-1, "foo", AT_FDCWD, "bar", 0) == -1);
 102     ASSERT (errno == EBADF);
 103   }
 104   {
 105     close (99);
 106     errno = 0;
 107     ASSERT (linkat (99, "foo", AT_FDCWD, "bar", 0) == -1);
 108     ASSERT (errno == EBADF);
 109   }
 110   ASSERT (close (creat (BASE "oo", 0600)) == 0);
 111   {
 112     errno = 0;
 113     ASSERT (linkat (AT_FDCWD, BASE "oo", -1, "bar", 0) == -1);
 114     ASSERT (errno == EBADF);
 115   }
 116   {
 117     errno = 0;
 118     ASSERT (linkat (AT_FDCWD, BASE "oo", 99, "bar", 0) == -1);
 119     ASSERT (errno == EBADF);
 120   }
 121   ASSERT (unlink (BASE "oo") == 0);
 122 
 123   /* Test basic link functionality, without mentioning symlinks.  */
 124   result = test_link (do_link, true);
 125   dfd1 = open (".", O_RDONLY);
 126   ASSERT (0 <= dfd1);
 127   ASSERT (test_link (do_link, false) == result);
 128   dfd2 = dfd1;
 129   ASSERT (test_link (do_link, false) == result);
 130   dfd1 = AT_FDCWD;
 131   ASSERT (test_link (do_link, false) == result);
 132   flag = 0;
 133   ASSERT (test_link (do_link, false) == result);
 134   dfd1 = dfd2;
 135   ASSERT (test_link (do_link, false) == result);
 136   dfd2 = AT_FDCWD;
 137   ASSERT (test_link (do_link, false) == result);
 138   ASSERT (close (dfd1) == 0);
 139   dfd1 = AT_FDCWD;
 140   ASSERT (test_link (do_link, false) == result);
 141 
 142   /* Create locations to manipulate.  */
 143   ASSERT (mkdir (BASE "sub1", 0700) == 0);
 144   ASSERT (mkdir (BASE "sub2", 0700) == 0);
 145   ASSERT (close (creat (BASE "00", 0600)) == 0);
 146   cwd = getcwd (NULL, 0);
 147   ASSERT (cwd);
 148 
 149   dfd = open (BASE "sub1", O_RDONLY);
 150   ASSERT (0 <= dfd);
 151   ASSERT (chdir (BASE "sub2") == 0);
 152 
 153   /* There are 16 possible scenarios, based on whether an fd is
 154      AT_FDCWD or real, whether a file is absolute or relative, coupled
 155      with whether flag is set for 32 iterations.
 156 
 157      To ensure that we test all of the code paths (rather than
 158      triggering early normalization optimizations), we use a loop to
 159      repeatedly rename a file in the parent directory, use an fd open
 160      on subdirectory 1, all while executing in subdirectory 2; all
 161      relative names are thus given with a leading "../".  Finally, the
 162      last scenario (two relative paths given, neither one AT_FDCWD)
 163      has two paths, based on whether the two fds are equivalent, so we
 164      do the other variant after the loop.  */
 165   for (i = 0; i < 32; i++)
 166     {
 167       int fd1 = (i & 8) ? dfd : AT_FDCWD;
 168       char *file1 = mfile_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
 169       int fd2 = (i & 2) ? dfd : AT_FDCWD;
 170       char *file2 = mfile_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
 171       ASSERT (file1);
 172       ASSERT (file2);
 173       flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
 174 
 175       ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
 176       ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
 177       ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
 178       ASSERT (unlinkat (fd1, file1, 0) == 0);
 179       free (file1);
 180       free (file2);
 181     }
 182   dfd2 = open ("..", O_RDONLY);
 183   ASSERT (0 <= dfd2);
 184   ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
 185   ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
 186                   AT_SYMLINK_FOLLOW) == 0);
 187   ASSERT (close (dfd2) == 0);
 188 
 189   /* Now we change back to the parent directory, and set dfd to ".",
 190      in order to test behavior on symlinks.  */
 191   ASSERT (chdir ("..") == 0);
 192   ASSERT (close (dfd) == 0);
 193   if (symlink (BASE "sub1", BASE "link1"))
 194     {
 195       ASSERT (unlink (BASE "32") == 0);
 196       ASSERT (unlink (BASE "33") == 0);
 197       ASSERT (unlink (BASE "34") == 0);
 198       ASSERT (rmdir (BASE "sub1") == 0);
 199       ASSERT (rmdir (BASE "sub2") == 0);
 200       free (cwd);
 201       if (!result)
 202         fputs ("skipping test: symlinks not supported on this file system\n",
 203                stderr);
 204       return result;
 205     }
 206   dfd = open (".", O_RDONLY);
 207   ASSERT (0 <= dfd);
 208   ASSERT (symlink (BASE "34", BASE "link2") == 0);
 209   ASSERT (symlink (BASE "link3", BASE "link3") == 0);
 210   ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
 211 
 212   /* Link cannot overwrite existing files.  */
 213   errno = 0;
 214   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
 215   ASSERT (errno == EEXIST);
 216   errno = 0;
 217   ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
 218   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
 219   errno = 0;
 220   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
 221   ASSERT (errno == EEXIST || errno == ENOTDIR);
 222   errno = 0;
 223   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
 224                   AT_SYMLINK_FOLLOW) == -1);
 225   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
 226   errno = 0;
 227   ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
 228                   AT_SYMLINK_FOLLOW) == -1);
 229   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
 230           || errno == EINVAL);
 231   errno = 0;
 232   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
 233                   AT_SYMLINK_FOLLOW) == -1);
 234   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
 235           || errno == EINVAL);
 236   errno = 0;
 237   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
 238   ASSERT (errno == EEXIST);
 239   errno = 0;
 240   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
 241                   AT_SYMLINK_FOLLOW) == -1);
 242   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
 243   errno = 0;
 244   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
 245   ASSERT (errno == EEXIST || errno == ELOOP);
 246   errno = 0;
 247   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
 248                   AT_SYMLINK_FOLLOW) == -1);
 249   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
 250           || errno == ELOOP);
 251   errno = 0;
 252   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
 253   ASSERT (errno == EEXIST || errno == ELOOP);
 254   errno = 0;
 255   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
 256                   AT_SYMLINK_FOLLOW) == -1);
 257   ASSERT (errno == EEXIST || errno == ELOOP);
 258 
 259   /* AT_SYMLINK_FOLLOW only follows first argument, not second.  */
 260   errno = 0;
 261   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
 262   ASSERT (errno == EEXIST);
 263   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
 264                   AT_SYMLINK_FOLLOW) == -1);
 265   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
 266   errno = 0;
 267   ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
 268   ASSERT (errno == EEXIST);
 269   errno = 0;
 270   ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
 271   ASSERT (errno == EEXIST);
 272 
 273   /* Trailing slash handling.  */
 274   errno = 0;
 275   ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
 276   ASSERT (errno == ENOTDIR);
 277   errno = 0;
 278   ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
 279                   AT_SYMLINK_FOLLOW) == -1);
 280   ASSERT (errno == ENOTDIR || errno == EINVAL);
 281   errno = 0;
 282   ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
 283   ASSERT (errno == ELOOP);
 284   errno = 0;
 285   ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
 286                   AT_SYMLINK_FOLLOW) == -1);
 287   ASSERT (errno == ELOOP || errno == EINVAL);
 288   errno = 0;
 289   ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
 290   ASSERT (errno == ENOENT);
 291   errno = 0;
 292   ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
 293                   AT_SYMLINK_FOLLOW) == -1);
 294   ASSERT (errno == ENOENT || errno == EINVAL);
 295 
 296   /* Check for hard links to symlinks.  */
 297   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
 298   check_same_link (BASE "link1", BASE "link5");
 299   ASSERT (unlink (BASE "link5") == 0);
 300   errno = 0;
 301   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
 302                   AT_SYMLINK_FOLLOW) == -1);
 303   ASSERT (errno == EPERM || errno == EACCES);
 304   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
 305   check_same_link (BASE "link2", BASE "link5");
 306   ASSERT (unlink (BASE "link5") == 0);
 307   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
 308   errno = 0;
 309   ASSERT (areadlink (BASE "file") == NULL);
 310   ASSERT (errno == EINVAL);
 311   ASSERT (unlink (BASE "file") == 0);
 312   ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
 313   check_same_link (BASE "link3", BASE "link5");
 314   ASSERT (unlink (BASE "link5") == 0);
 315   errno = 0;
 316   ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
 317                   AT_SYMLINK_FOLLOW) == -1);
 318   ASSERT (errno == ELOOP);
 319   ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
 320   check_same_link (BASE "link4", BASE "link5");
 321   ASSERT (unlink (BASE "link5") == 0);
 322   errno = 0;
 323   ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
 324                   AT_SYMLINK_FOLLOW) == -1);
 325   ASSERT (errno == ENOENT);
 326 
 327   /* Check that symlink to symlink to file is followed all the way.  */
 328   ASSERT (symlink (BASE "link2", BASE "link5") == 0);
 329   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
 330   check_same_link (BASE "link5", BASE "link6");
 331   ASSERT (unlink (BASE "link6") == 0);
 332   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
 333   errno = 0;
 334   ASSERT (areadlink (BASE "file") == NULL);
 335   ASSERT (errno == EINVAL);
 336   ASSERT (unlink (BASE "file") == 0);
 337   ASSERT (unlink (BASE "link5") == 0);
 338   ASSERT (symlink (BASE "link3", BASE "link5") == 0);
 339   errno = 0;
 340   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
 341                   AT_SYMLINK_FOLLOW) == -1);
 342   ASSERT (errno == ELOOP);
 343   ASSERT (unlink (BASE "link5") == 0);
 344   ASSERT (symlink (BASE "link4", BASE "link5") == 0);
 345   errno = 0;
 346   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
 347                   AT_SYMLINK_FOLLOW) == -1);
 348   ASSERT (errno == ENOENT);
 349 
 350   /* Now for some real fun with directory crossing.  */
 351   ASSERT (symlink (cwd, BASE "sub1/link") == 0);
 352   ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
 353                    BASE "sub2/link") == 0);
 354   ASSERT (close (dfd) == 0);
 355   dfd = open (BASE "sub1", O_RDONLY);
 356   ASSERT (0 <= dfd);
 357   dfd2 = open (BASE "sub2", O_RDONLY);
 358   ASSERT (0 < dfd2);
 359   ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
 360               AT_SYMLINK_FOLLOW) == 0);
 361   errno = 0;
 362   ASSERT (areadlink (BASE "sub1/file") == NULL);
 363   ASSERT (errno == EINVAL);
 364 
 365   /* Cleanup.  */
 366   ASSERT (close (dfd) == 0);
 367   ASSERT (close (dfd2) == 0);
 368   ASSERT (unlink (BASE "sub1/file") == 0);
 369   ASSERT (unlink (BASE "sub1/link") == 0);
 370   ASSERT (unlink (BASE "sub2/link") == 0);
 371   ASSERT (unlink (BASE "32") == 0);
 372   ASSERT (unlink (BASE "33") == 0);
 373   ASSERT (unlink (BASE "34") == 0);
 374   ASSERT (rmdir (BASE "sub1") == 0);
 375   ASSERT (rmdir (BASE "sub2") == 0);
 376   ASSERT (unlink (BASE "link1") == 0);
 377   ASSERT (unlink (BASE "link2") == 0);
 378   ASSERT (unlink (BASE "link3") == 0);
 379   ASSERT (unlink (BASE "link4") == 0);
 380   ASSERT (unlink (BASE "link5") == 0);
 381   free (cwd);
 382   return result;
 383 }

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