2 Copyright (C) 2009-2011 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* Written by Eric Blake <ebb9@byu.net>, 2009. */
23 #include "signature.h"
24 SIGNATURE_CHECK (linkat, int, (int, char const *, int, char const *, int));
34 #include "areadlink.h"
35 #include "filenamecat.h"
36 #include "same-inode.h"
37 #include "ignore-value.h"
40 #define BASE "test-linkat.t"
42 #include "test-link.h"
44 static int dfd1 = AT_FDCWD;
45 static int dfd2 = AT_FDCWD;
46 static int flag = AT_SYMLINK_FOLLOW;
48 /* Wrapper to test linkat like link. */
50 do_link (char const *name1, char const *name2)
52 return linkat (dfd1, name1, dfd2, name2, flag);
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
61 # define EXPECT_LINK_HARDLINKS_SYMLINKS (__xpg4 == 0)
63 # define EXPECT_LINK_HARDLINKS_SYMLINKS 0
66 /* Wrapper to see if two symlinks act the same. */
68 check_same_link (char const *name1, char const *name2)
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);
80 ASSERT (strcmp (contents1, contents2) == 0);
81 if (EXPECT_LINK_HARDLINKS_SYMLINKS)
82 ASSERT (SAME_INODE (st1, st2));
95 /* Clean up any trash from prior testsuite runs. */
96 ignore_value (system ("rm -rf " BASE "*"));
98 /* Test behaviour for invalid file descriptors. */
101 ASSERT (linkat (-1, "foo", AT_FDCWD, "bar", 0) == -1);
102 ASSERT (errno == EBADF);
106 ASSERT (linkat (99, "foo", AT_FDCWD, "bar", 0) == -1);
107 ASSERT (errno == EBADF);
109 ASSERT (close (creat (BASE "oo", 0600)) == 0);
112 ASSERT (linkat (AT_FDCWD, BASE "oo", -1, "bar", 0) == -1);
113 ASSERT (errno == EBADF);
117 ASSERT (linkat (AT_FDCWD, BASE "oo", 99, "bar", 0) == -1);
118 ASSERT (errno == EBADF);
120 ASSERT (unlink (BASE "oo") == 0);
122 /* Test basic link functionality, without mentioning symlinks. */
123 result = test_link (do_link, true);
124 dfd1 = open (".", O_RDONLY);
126 ASSERT (test_link (do_link, false) == result);
128 ASSERT (test_link (do_link, false) == result);
130 ASSERT (test_link (do_link, false) == result);
132 ASSERT (test_link (do_link, false) == result);
134 ASSERT (test_link (do_link, false) == result);
136 ASSERT (test_link (do_link, false) == result);
137 ASSERT (close (dfd1) == 0);
139 ASSERT (test_link (do_link, false) == result);
141 /* Create locations to manipulate. */
142 ASSERT (mkdir (BASE "sub1", 0700) == 0);
143 ASSERT (mkdir (BASE "sub2", 0700) == 0);
144 ASSERT (close (creat (BASE "00", 0600)) == 0);
145 cwd = getcwd (NULL, 0);
148 dfd = open (BASE "sub1", O_RDONLY);
150 ASSERT (chdir (BASE "sub2") == 0);
152 /* There are 16 possible scenarios, based on whether an fd is
153 AT_FDCWD or real, whether a file is absolute or relative, coupled
154 with whether flag is set for 32 iterations.
156 To ensure that we test all of the code paths (rather than
157 triggering early normalization optimizations), we use a loop to
158 repeatedly rename a file in the parent directory, use an fd open
159 on subdirectory 1, all while executing in subdirectory 2; all
160 relative names are thus given with a leading "../". Finally, the
161 last scenario (two relative paths given, neither one AT_FDCWD)
162 has two paths, based on whether the two fds are equivalent, so we
163 do the other variant after the loop. */
164 for (i = 0; i < 32; i++)
166 int fd1 = (i & 8) ? dfd : AT_FDCWD;
167 char *file1 = mfile_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
168 int fd2 = (i & 2) ? dfd : AT_FDCWD;
169 char *file2 = mfile_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
172 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
174 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
175 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
176 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
177 ASSERT (unlinkat (fd1, file1, 0) == 0);
181 dfd2 = open ("..", O_RDONLY);
183 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
184 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
185 AT_SYMLINK_FOLLOW) == 0);
186 ASSERT (close (dfd2) == 0);
188 /* Now we change back to the parent directory, and set dfd to ".",
189 in order to test behavior on symlinks. */
190 ASSERT (chdir ("..") == 0);
191 ASSERT (close (dfd) == 0);
192 if (symlink (BASE "sub1", BASE "link1"))
194 ASSERT (unlink (BASE "32") == 0);
195 ASSERT (unlink (BASE "33") == 0);
196 ASSERT (unlink (BASE "34") == 0);
197 ASSERT (rmdir (BASE "sub1") == 0);
198 ASSERT (rmdir (BASE "sub2") == 0);
201 fputs ("skipping test: symlinks not supported on this file system\n",
205 dfd = open (".", O_RDONLY);
207 ASSERT (symlink (BASE "34", BASE "link2") == 0);
208 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
209 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
211 /* Link cannot overwrite existing files. */
213 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
214 ASSERT (errno == EEXIST);
216 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
217 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
219 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
220 ASSERT (errno == EEXIST || errno == ENOTDIR);
222 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
223 AT_SYMLINK_FOLLOW) == -1);
224 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
226 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
227 AT_SYMLINK_FOLLOW) == -1);
228 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
231 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
232 AT_SYMLINK_FOLLOW) == -1);
233 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
236 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
237 ASSERT (errno == EEXIST);
239 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
240 AT_SYMLINK_FOLLOW) == -1);
241 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
243 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
244 ASSERT (errno == EEXIST || errno == ELOOP);
246 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
247 AT_SYMLINK_FOLLOW) == -1);
248 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
251 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
252 ASSERT (errno == EEXIST || errno == ELOOP);
254 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
255 AT_SYMLINK_FOLLOW) == -1);
256 ASSERT (errno == EEXIST || errno == ELOOP);
258 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
260 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
261 ASSERT (errno == EEXIST);
262 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
263 AT_SYMLINK_FOLLOW) == -1);
264 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
266 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
267 ASSERT (errno == EEXIST);
269 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
270 ASSERT (errno == EEXIST);
272 /* Trailing slash handling. */
274 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
275 ASSERT (errno == ENOTDIR);
277 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
278 AT_SYMLINK_FOLLOW) == -1);
279 ASSERT (errno == ENOTDIR || errno == EINVAL);
281 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
282 ASSERT (errno == ELOOP);
284 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
285 AT_SYMLINK_FOLLOW) == -1);
286 ASSERT (errno == ELOOP || errno == EINVAL);
288 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
289 ASSERT (errno == ENOENT);
291 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
292 AT_SYMLINK_FOLLOW) == -1);
293 ASSERT (errno == ENOENT || errno == EINVAL);
295 /* Check for hard links to symlinks. */
296 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
297 check_same_link (BASE "link1", BASE "link5");
298 ASSERT (unlink (BASE "link5") == 0);
300 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
301 AT_SYMLINK_FOLLOW) == -1);
302 ASSERT (errno == EPERM || errno == EACCES);
303 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
304 check_same_link (BASE "link2", BASE "link5");
305 ASSERT (unlink (BASE "link5") == 0);
306 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
308 ASSERT (areadlink (BASE "file") == NULL);
309 ASSERT (errno == EINVAL);
310 ASSERT (unlink (BASE "file") == 0);
311 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
312 check_same_link (BASE "link3", BASE "link5");
313 ASSERT (unlink (BASE "link5") == 0);
315 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
316 AT_SYMLINK_FOLLOW) == -1);
317 ASSERT (errno == ELOOP);
318 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
319 check_same_link (BASE "link4", BASE "link5");
320 ASSERT (unlink (BASE "link5") == 0);
322 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
323 AT_SYMLINK_FOLLOW) == -1);
324 ASSERT (errno == ENOENT);
326 /* Check that symlink to symlink to file is followed all the way. */
327 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
328 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
329 check_same_link (BASE "link5", BASE "link6");
330 ASSERT (unlink (BASE "link6") == 0);
331 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
333 ASSERT (areadlink (BASE "file") == NULL);
334 ASSERT (errno == EINVAL);
335 ASSERT (unlink (BASE "file") == 0);
336 ASSERT (unlink (BASE "link5") == 0);
337 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
339 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
340 AT_SYMLINK_FOLLOW) == -1);
341 ASSERT (errno == ELOOP);
342 ASSERT (unlink (BASE "link5") == 0);
343 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
345 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
346 AT_SYMLINK_FOLLOW) == -1);
347 ASSERT (errno == ENOENT);
349 /* Now for some real fun with directory crossing. */
350 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
351 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
352 BASE "sub2/link") == 0);
353 ASSERT (close (dfd) == 0);
354 dfd = open (BASE "sub1", O_RDONLY);
356 dfd2 = open (BASE "sub2", O_RDONLY);
358 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
359 AT_SYMLINK_FOLLOW) == 0);
361 ASSERT (areadlink (BASE "sub1/file") == NULL);
362 ASSERT (errno == EINVAL);
365 ASSERT (close (dfd) == 0);
366 ASSERT (close (dfd2) == 0);
367 ASSERT (unlink (BASE "sub1/file") == 0);
368 ASSERT (unlink (BASE "sub1/link") == 0);
369 ASSERT (unlink (BASE "sub2/link") == 0);
370 ASSERT (unlink (BASE "32") == 0);
371 ASSERT (unlink (BASE "33") == 0);
372 ASSERT (unlink (BASE "34") == 0);
373 ASSERT (rmdir (BASE "sub1") == 0);
374 ASSERT (rmdir (BASE "sub2") == 0);
375 ASSERT (unlink (BASE "link1") == 0);
376 ASSERT (unlink (BASE "link2") == 0);
377 ASSERT (unlink (BASE "link3") == 0);
378 ASSERT (unlink (BASE "link4") == 0);
379 ASSERT (unlink (BASE "link5") == 0);