maint: update all copyright year number ranges
[gnulib.git] / tests / test-linkat.c
1 /* Tests of linkat.
2    Copyright (C) 2009-2013 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 <http://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)
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)
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)
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     errno = 0;
106     ASSERT (linkat (99, "foo", AT_FDCWD, "bar", 0) == -1);
107     ASSERT (errno == EBADF);
108   }
109   ASSERT (close (creat (BASE "oo", 0600)) == 0);
110   {
111     errno = 0;
112     ASSERT (linkat (AT_FDCWD, BASE "oo", -1, "bar", 0) == -1);
113     ASSERT (errno == EBADF);
114   }
115   {
116     errno = 0;
117     ASSERT (linkat (AT_FDCWD, BASE "oo", 99, "bar", 0) == -1);
118     ASSERT (errno == EBADF);
119   }
120   ASSERT (unlink (BASE "oo") == 0);
121
122   /* Test basic link functionality, without mentioning symlinks.  */
123   result = test_link (do_link, true);
124   dfd1 = open (".", O_RDONLY);
125   ASSERT (0 <= dfd1);
126   ASSERT (test_link (do_link, false) == result);
127   dfd2 = dfd1;
128   ASSERT (test_link (do_link, false) == result);
129   dfd1 = AT_FDCWD;
130   ASSERT (test_link (do_link, false) == result);
131   flag = 0;
132   ASSERT (test_link (do_link, false) == result);
133   dfd1 = dfd2;
134   ASSERT (test_link (do_link, false) == result);
135   dfd2 = AT_FDCWD;
136   ASSERT (test_link (do_link, false) == result);
137   ASSERT (close (dfd1) == 0);
138   dfd1 = AT_FDCWD;
139   ASSERT (test_link (do_link, false) == result);
140
141   /* Create locations to manipulate.  */
142   ASSERT (mkdir (BASE "sub1", 0700) == 0);
143   ASSERT (mkdir (BASE "sub2", 0700) == 0);
144   ASSERT (close (creat (BASE "00", 0600)) == 0);
145   cwd = getcwd (NULL, 0);
146   ASSERT (cwd);
147
148   dfd = open (BASE "sub1", O_RDONLY);
149   ASSERT (0 <= dfd);
150   ASSERT (chdir (BASE "sub2") == 0);
151
152   /* There are 16 possible scenarios, based on whether an fd is
153      AT_FDCWD or real, whether a file is absolute or relative, coupled
154      with whether flag is set for 32 iterations.
155
156      To ensure that we test all of the code paths (rather than
157      triggering early normalization optimizations), we use a loop to
158      repeatedly rename a file in the parent directory, use an fd open
159      on subdirectory 1, all while executing in subdirectory 2; all
160      relative names are thus given with a leading "../".  Finally, the
161      last scenario (two relative paths given, neither one AT_FDCWD)
162      has two paths, based on whether the two fds are equivalent, so we
163      do the other variant after the loop.  */
164   for (i = 0; i < 32; i++)
165     {
166       int fd1 = (i & 8) ? dfd : AT_FDCWD;
167       char *file1 = mfile_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
168       int fd2 = (i & 2) ? dfd : AT_FDCWD;
169       char *file2 = mfile_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
170       ASSERT (file1);
171       ASSERT (file2);
172       flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
173
174       ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
175       ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
176       ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
177       ASSERT (unlinkat (fd1, file1, 0) == 0);
178       free (file1);
179       free (file2);
180     }
181   dfd2 = open ("..", O_RDONLY);
182   ASSERT (0 <= dfd2);
183   ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
184   ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
185                   AT_SYMLINK_FOLLOW) == 0);
186   ASSERT (close (dfd2) == 0);
187
188   /* Now we change back to the parent directory, and set dfd to ".",
189      in order to test behavior on symlinks.  */
190   ASSERT (chdir ("..") == 0);
191   ASSERT (close (dfd) == 0);
192   if (symlink (BASE "sub1", BASE "link1"))
193     {
194       ASSERT (unlink (BASE "32") == 0);
195       ASSERT (unlink (BASE "33") == 0);
196       ASSERT (unlink (BASE "34") == 0);
197       ASSERT (rmdir (BASE "sub1") == 0);
198       ASSERT (rmdir (BASE "sub2") == 0);
199       free (cwd);
200       if (!result)
201         fputs ("skipping test: symlinks not supported on this file system\n",
202                stderr);
203       return result;
204     }
205   dfd = open (".", O_RDONLY);
206   ASSERT (0 <= dfd);
207   ASSERT (symlink (BASE "34", BASE "link2") == 0);
208   ASSERT (symlink (BASE "link3", BASE "link3") == 0);
209   ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
210
211   /* Link cannot overwrite existing files.  */
212   errno = 0;
213   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
214   ASSERT (errno == EEXIST);
215   errno = 0;
216   ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
217   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
218   errno = 0;
219   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
220   ASSERT (errno == EEXIST || errno == ENOTDIR);
221   errno = 0;
222   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
223                   AT_SYMLINK_FOLLOW) == -1);
224   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
225   errno = 0;
226   ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
227                   AT_SYMLINK_FOLLOW) == -1);
228   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
229           || errno == EINVAL);
230   errno = 0;
231   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
232                   AT_SYMLINK_FOLLOW) == -1);
233   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
234           || errno == EINVAL);
235   errno = 0;
236   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
237   ASSERT (errno == EEXIST);
238   errno = 0;
239   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
240                   AT_SYMLINK_FOLLOW) == -1);
241   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
242   errno = 0;
243   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
244   ASSERT (errno == EEXIST || errno == ELOOP);
245   errno = 0;
246   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
247                   AT_SYMLINK_FOLLOW) == -1);
248   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
249           || errno == ELOOP);
250   errno = 0;
251   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
252   ASSERT (errno == EEXIST || errno == ELOOP);
253   errno = 0;
254   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
255                   AT_SYMLINK_FOLLOW) == -1);
256   ASSERT (errno == EEXIST || errno == ELOOP);
257
258   /* AT_SYMLINK_FOLLOW only follows first argument, not second.  */
259   errno = 0;
260   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
261   ASSERT (errno == EEXIST);
262   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
263                   AT_SYMLINK_FOLLOW) == -1);
264   ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
265   errno = 0;
266   ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
267   ASSERT (errno == EEXIST);
268   errno = 0;
269   ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
270   ASSERT (errno == EEXIST);
271
272   /* Trailing slash handling.  */
273   errno = 0;
274   ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
275   ASSERT (errno == ENOTDIR);
276   errno = 0;
277   ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
278                   AT_SYMLINK_FOLLOW) == -1);
279   ASSERT (errno == ENOTDIR || errno == EINVAL);
280   errno = 0;
281   ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
282   ASSERT (errno == ELOOP);
283   errno = 0;
284   ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
285                   AT_SYMLINK_FOLLOW) == -1);
286   ASSERT (errno == ELOOP || errno == EINVAL);
287   errno = 0;
288   ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
289   ASSERT (errno == ENOENT);
290   errno = 0;
291   ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
292                   AT_SYMLINK_FOLLOW) == -1);
293   ASSERT (errno == ENOENT || errno == EINVAL);
294
295   /* Check for hard links to symlinks.  */
296   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
297   check_same_link (BASE "link1", BASE "link5");
298   ASSERT (unlink (BASE "link5") == 0);
299   errno = 0;
300   ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
301                   AT_SYMLINK_FOLLOW) == -1);
302   ASSERT (errno == EPERM || errno == EACCES);
303   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
304   check_same_link (BASE "link2", BASE "link5");
305   ASSERT (unlink (BASE "link5") == 0);
306   ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
307   errno = 0;
308   ASSERT (areadlink (BASE "file") == NULL);
309   ASSERT (errno == EINVAL);
310   ASSERT (unlink (BASE "file") == 0);
311   ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
312   check_same_link (BASE "link3", BASE "link5");
313   ASSERT (unlink (BASE "link5") == 0);
314   errno = 0;
315   ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
316                   AT_SYMLINK_FOLLOW) == -1);
317   ASSERT (errno == ELOOP);
318   ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
319   check_same_link (BASE "link4", BASE "link5");
320   ASSERT (unlink (BASE "link5") == 0);
321   errno = 0;
322   ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
323                   AT_SYMLINK_FOLLOW) == -1);
324   ASSERT (errno == ENOENT);
325
326   /* Check that symlink to symlink to file is followed all the way.  */
327   ASSERT (symlink (BASE "link2", BASE "link5") == 0);
328   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
329   check_same_link (BASE "link5", BASE "link6");
330   ASSERT (unlink (BASE "link6") == 0);
331   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
332   errno = 0;
333   ASSERT (areadlink (BASE "file") == NULL);
334   ASSERT (errno == EINVAL);
335   ASSERT (unlink (BASE "file") == 0);
336   ASSERT (unlink (BASE "link5") == 0);
337   ASSERT (symlink (BASE "link3", BASE "link5") == 0);
338   errno = 0;
339   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
340                   AT_SYMLINK_FOLLOW) == -1);
341   ASSERT (errno == ELOOP);
342   ASSERT (unlink (BASE "link5") == 0);
343   ASSERT (symlink (BASE "link4", BASE "link5") == 0);
344   errno = 0;
345   ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
346                   AT_SYMLINK_FOLLOW) == -1);
347   ASSERT (errno == ENOENT);
348
349   /* Now for some real fun with directory crossing.  */
350   ASSERT (symlink (cwd, BASE "sub1/link") == 0);
351   ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
352                    BASE "sub2/link") == 0);
353   ASSERT (close (dfd) == 0);
354   dfd = open (BASE "sub1", O_RDONLY);
355   ASSERT (0 <= dfd);
356   dfd2 = open (BASE "sub2", O_RDONLY);
357   ASSERT (0 < dfd2);
358   ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
359               AT_SYMLINK_FOLLOW) == 0);
360   errno = 0;
361   ASSERT (areadlink (BASE "sub1/file") == NULL);
362   ASSERT (errno == EINVAL);
363
364   /* Cleanup.  */
365   ASSERT (close (dfd) == 0);
366   ASSERT (close (dfd2) == 0);
367   ASSERT (unlink (BASE "sub1/file") == 0);
368   ASSERT (unlink (BASE "sub1/link") == 0);
369   ASSERT (unlink (BASE "sub2/link") == 0);
370   ASSERT (unlink (BASE "32") == 0);
371   ASSERT (unlink (BASE "33") == 0);
372   ASSERT (unlink (BASE "34") == 0);
373   ASSERT (rmdir (BASE "sub1") == 0);
374   ASSERT (rmdir (BASE "sub2") == 0);
375   ASSERT (unlink (BASE "link1") == 0);
376   ASSERT (unlink (BASE "link2") == 0);
377   ASSERT (unlink (BASE "link3") == 0);
378   ASSERT (unlink (BASE "link4") == 0);
379   ASSERT (unlink (BASE "link5") == 0);
380   free (cwd);
381   return result;
382 }