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