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