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);
121 /* Test basic link functionality, without mentioning symlinks. */
122 result = test_link (do_link, true);
123 dfd1 = open (".", O_RDONLY);
125 ASSERT (test_link (do_link, false) == result);
127 ASSERT (test_link (do_link, false) == result);
129 ASSERT (test_link (do_link, false) == result);
131 ASSERT (test_link (do_link, false) == result);
133 ASSERT (test_link (do_link, false) == result);
135 ASSERT (test_link (do_link, false) == result);
136 ASSERT (close (dfd1) == 0);
138 ASSERT (test_link (do_link, false) == result);
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);
147 dfd = open (BASE "sub1", O_RDONLY);
149 ASSERT (chdir (BASE "sub2") == 0);
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.
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++)
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);
171 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
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);
180 dfd2 = open ("..", O_RDONLY);
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);
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"))
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);
200 fputs ("skipping test: symlinks not supported on this file system\n",
204 dfd = open (".", O_RDONLY);
206 ASSERT (symlink (BASE "34", BASE "link2") == 0);
207 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
208 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
210 /* Link cannot overwrite existing files. */
212 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
213 ASSERT (errno == EEXIST);
215 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
216 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
218 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
219 ASSERT (errno == EEXIST || errno == ENOTDIR);
221 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
222 AT_SYMLINK_FOLLOW) == -1);
223 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
225 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
226 AT_SYMLINK_FOLLOW) == -1);
227 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
230 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
231 AT_SYMLINK_FOLLOW) == -1);
232 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
235 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
236 ASSERT (errno == EEXIST);
238 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
239 AT_SYMLINK_FOLLOW) == -1);
240 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
242 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
243 ASSERT (errno == EEXIST || errno == ELOOP);
245 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
246 AT_SYMLINK_FOLLOW) == -1);
247 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
250 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
251 ASSERT (errno == EEXIST || errno == ELOOP);
253 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
254 AT_SYMLINK_FOLLOW) == -1);
255 ASSERT (errno == EEXIST || errno == ELOOP);
257 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
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);
265 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
266 ASSERT (errno == EEXIST);
268 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
269 ASSERT (errno == EEXIST);
271 /* Trailing slash handling. */
273 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
274 ASSERT (errno == ENOTDIR);
276 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
277 AT_SYMLINK_FOLLOW) == -1);
278 ASSERT (errno == ENOTDIR || errno == EINVAL);
280 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
281 ASSERT (errno == ELOOP);
283 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
284 AT_SYMLINK_FOLLOW) == -1);
285 ASSERT (errno == ELOOP || errno == EINVAL);
287 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
288 ASSERT (errno == ENOENT);
290 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
291 AT_SYMLINK_FOLLOW) == -1);
292 ASSERT (errno == ENOENT || errno == EINVAL);
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);
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);
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);
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);
321 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
322 AT_SYMLINK_FOLLOW) == -1);
323 ASSERT (errno == ENOENT);
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);
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);
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);
344 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
345 AT_SYMLINK_FOLLOW) == -1);
346 ASSERT (errno == ENOENT);
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);
355 dfd2 = open (BASE "sub2", O_RDONLY);
357 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
358 AT_SYMLINK_FOLLOW) == 0);
360 ASSERT (areadlink (BASE "sub1/file") == NULL);
361 ASSERT (errno == EINVAL);
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);