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