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 basic link functionality, without mentioning symlinks. */
99 result = test_link (do_link, true);
100 dfd1 = open (".", O_RDONLY);
102 ASSERT (test_link (do_link, false) == result);
104 ASSERT (test_link (do_link, false) == result);
106 ASSERT (test_link (do_link, false) == result);
108 ASSERT (test_link (do_link, false) == result);
110 ASSERT (test_link (do_link, false) == result);
112 ASSERT (test_link (do_link, false) == result);
113 ASSERT (close (dfd1) == 0);
115 ASSERT (test_link (do_link, false) == result);
117 /* Create locations to manipulate. */
118 ASSERT (mkdir (BASE "sub1", 0700) == 0);
119 ASSERT (mkdir (BASE "sub2", 0700) == 0);
120 ASSERT (close (creat (BASE "00", 0600)) == 0);
121 cwd = getcwd (NULL, 0);
124 dfd = open (BASE "sub1", O_RDONLY);
126 ASSERT (chdir (BASE "sub2") == 0);
128 /* There are 16 possible scenarios, based on whether an fd is
129 AT_FDCWD or real, whether a file is absolute or relative, coupled
130 with whether flag is set for 32 iterations.
132 To ensure that we test all of the code paths (rather than
133 triggering early normalization optimizations), we use a loop to
134 repeatedly rename a file in the parent directory, use an fd open
135 on subdirectory 1, all while executing in subdirectory 2; all
136 relative names are thus given with a leading "../". Finally, the
137 last scenario (two relative paths given, neither one AT_FDCWD)
138 has two paths, based on whether the two fds are equivalent, so we
139 do the other variant after the loop. */
140 for (i = 0; i < 32; i++)
142 int fd1 = (i & 8) ? dfd : AT_FDCWD;
143 char *file1 = mfile_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
144 int fd2 = (i & 2) ? dfd : AT_FDCWD;
145 char *file2 = mfile_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
148 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
150 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
151 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
152 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
153 ASSERT (unlinkat (fd1, file1, 0) == 0);
157 dfd2 = open ("..", O_RDONLY);
159 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
160 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
161 AT_SYMLINK_FOLLOW) == 0);
162 ASSERT (close (dfd2) == 0);
164 /* Now we change back to the parent directory, and set dfd to ".",
165 in order to test behavior on symlinks. */
166 ASSERT (chdir ("..") == 0);
167 ASSERT (close (dfd) == 0);
168 if (symlink (BASE "sub1", BASE "link1"))
170 ASSERT (unlink (BASE "32") == 0);
171 ASSERT (unlink (BASE "33") == 0);
172 ASSERT (unlink (BASE "34") == 0);
173 ASSERT (rmdir (BASE "sub1") == 0);
174 ASSERT (rmdir (BASE "sub2") == 0);
177 fputs ("skipping test: symlinks not supported on this file system\n",
181 dfd = open (".", O_RDONLY);
183 ASSERT (symlink (BASE "34", BASE "link2") == 0);
184 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
185 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
187 /* Link cannot overwrite existing files. */
189 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
190 ASSERT (errno == EEXIST);
192 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
193 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
195 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
196 ASSERT (errno == EEXIST || errno == ENOTDIR);
198 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
199 AT_SYMLINK_FOLLOW) == -1);
200 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
202 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
203 AT_SYMLINK_FOLLOW) == -1);
204 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
207 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
208 AT_SYMLINK_FOLLOW) == -1);
209 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
212 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
213 ASSERT (errno == EEXIST);
215 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
216 AT_SYMLINK_FOLLOW) == -1);
217 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
219 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
220 ASSERT (errno == EEXIST || errno == ELOOP);
222 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
223 AT_SYMLINK_FOLLOW) == -1);
224 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
227 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
228 ASSERT (errno == EEXIST || errno == ELOOP);
230 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
231 AT_SYMLINK_FOLLOW) == -1);
232 ASSERT (errno == EEXIST || errno == ELOOP);
234 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
236 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
237 ASSERT (errno == EEXIST);
238 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
239 AT_SYMLINK_FOLLOW) == -1);
240 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
242 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
243 ASSERT (errno == EEXIST);
245 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
246 ASSERT (errno == EEXIST);
248 /* Trailing slash handling. */
250 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
251 ASSERT (errno == ENOTDIR);
253 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
254 AT_SYMLINK_FOLLOW) == -1);
255 ASSERT (errno == ENOTDIR || errno == EINVAL);
257 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
258 ASSERT (errno == ELOOP);
260 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
261 AT_SYMLINK_FOLLOW) == -1);
262 ASSERT (errno == ELOOP || errno == EINVAL);
264 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
265 ASSERT (errno == ENOENT);
267 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
268 AT_SYMLINK_FOLLOW) == -1);
269 ASSERT (errno == ENOENT || errno == EINVAL);
271 /* Check for hard links to symlinks. */
272 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
273 check_same_link (BASE "link1", BASE "link5");
274 ASSERT (unlink (BASE "link5") == 0);
276 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
277 AT_SYMLINK_FOLLOW) == -1);
278 ASSERT (errno == EPERM || errno == EACCES);
279 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
280 check_same_link (BASE "link2", BASE "link5");
281 ASSERT (unlink (BASE "link5") == 0);
282 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
284 ASSERT (areadlink (BASE "file") == NULL);
285 ASSERT (errno == EINVAL);
286 ASSERT (unlink (BASE "file") == 0);
287 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
288 check_same_link (BASE "link3", BASE "link5");
289 ASSERT (unlink (BASE "link5") == 0);
291 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
292 AT_SYMLINK_FOLLOW) == -1);
293 ASSERT (errno == ELOOP);
294 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
295 check_same_link (BASE "link4", BASE "link5");
296 ASSERT (unlink (BASE "link5") == 0);
298 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
299 AT_SYMLINK_FOLLOW) == -1);
300 ASSERT (errno == ENOENT);
302 /* Check that symlink to symlink to file is followed all the way. */
303 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
304 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
305 check_same_link (BASE "link5", BASE "link6");
306 ASSERT (unlink (BASE "link6") == 0);
307 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
309 ASSERT (areadlink (BASE "file") == NULL);
310 ASSERT (errno == EINVAL);
311 ASSERT (unlink (BASE "file") == 0);
312 ASSERT (unlink (BASE "link5") == 0);
313 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
315 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
316 AT_SYMLINK_FOLLOW) == -1);
317 ASSERT (errno == ELOOP);
318 ASSERT (unlink (BASE "link5") == 0);
319 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
321 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
322 AT_SYMLINK_FOLLOW) == -1);
323 ASSERT (errno == ENOENT);
325 /* Now for some real fun with directory crossing. */
326 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
327 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
328 BASE "sub2/link") == 0);
329 ASSERT (close (dfd) == 0);
330 dfd = open (BASE "sub1", O_RDONLY);
332 dfd2 = open (BASE "sub2", O_RDONLY);
334 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
335 AT_SYMLINK_FOLLOW) == 0);
337 ASSERT (areadlink (BASE "sub1/file") == NULL);
338 ASSERT (errno == EINVAL);
341 ASSERT (close (dfd) == 0);
342 ASSERT (close (dfd2) == 0);
343 ASSERT (unlink (BASE "sub1/file") == 0);
344 ASSERT (unlink (BASE "sub1/link") == 0);
345 ASSERT (unlink (BASE "sub2/link") == 0);
346 ASSERT (unlink (BASE "32") == 0);
347 ASSERT (unlink (BASE "33") == 0);
348 ASSERT (unlink (BASE "34") == 0);
349 ASSERT (rmdir (BASE "sub1") == 0);
350 ASSERT (rmdir (BASE "sub2") == 0);
351 ASSERT (unlink (BASE "link1") == 0);
352 ASSERT (unlink (BASE "link2") == 0);
353 ASSERT (unlink (BASE "link3") == 0);
354 ASSERT (unlink (BASE "link4") == 0);
355 ASSERT (unlink (BASE "link5") == 0);