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