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