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"
38 #include "ignore-value.h"
41 #define BASE "test-linkat.t"
43 #include "test-link.h"
45 static int dfd1 = AT_FDCWD;
46 static int dfd2 = AT_FDCWD;
47 static int flag = AT_SYMLINK_FOLLOW;
49 /* Wrapper to test linkat like link. */
51 do_link (char const *name1, char const *name2)
53 return linkat (dfd1, name1, dfd2, name2, flag);
56 /* Can we expect that link() and linkat(), when called on a symlink,
57 increment the link count of that symlink? */
58 #if LINK_FOLLOWS_SYMLINKS == 0
59 # define EXPECT_LINK_HARDLINKS_SYMLINKS 1
60 #elif LINK_FOLLOWS_SYMLINKS == -1
62 # define EXPECT_LINK_HARDLINKS_SYMLINKS (__xpg4 == 0)
64 # define EXPECT_LINK_HARDLINKS_SYMLINKS 0
67 /* Wrapper to see if two symlinks act the same. */
69 check_same_link (char const *name1, char const *name2)
75 ASSERT (lstat (name1, &st1) == 0);
76 ASSERT (lstat (name2, &st2) == 0);
77 contents1 = areadlink_with_size (name1, st1.st_size);
78 contents2 = areadlink_with_size (name2, st2.st_size);
81 ASSERT (strcmp (contents1, contents2) == 0);
82 if (EXPECT_LINK_HARDLINKS_SYMLINKS)
83 ASSERT (SAME_INODE (st1, st2));
96 /* Clean up any trash from prior testsuite runs. */
97 ignore_value (system ("rm -rf " BASE "*"));
99 /* Test basic link functionality, without mentioning symlinks. */
100 result = test_link (do_link, true);
101 dfd1 = open (".", O_RDONLY);
103 ASSERT (test_link (do_link, false) == result);
105 ASSERT (test_link (do_link, false) == result);
107 ASSERT (test_link (do_link, false) == result);
109 ASSERT (test_link (do_link, false) == result);
111 ASSERT (test_link (do_link, false) == result);
113 ASSERT (test_link (do_link, false) == result);
114 ASSERT (close (dfd1) == 0);
116 ASSERT (test_link (do_link, false) == result);
118 /* Create locations to manipulate. */
119 ASSERT (mkdir (BASE "sub1", 0700) == 0);
120 ASSERT (mkdir (BASE "sub2", 0700) == 0);
121 ASSERT (close (creat (BASE "00", 0600)) == 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 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
144 int fd2 = (i & 2) ? dfd : AT_FDCWD;
145 char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
146 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
148 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
149 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
150 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
151 ASSERT (unlinkat (fd1, file1, 0) == 0);
155 dfd2 = open ("..", O_RDONLY);
157 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
158 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
159 AT_SYMLINK_FOLLOW) == 0);
160 ASSERT (close (dfd2) == 0);
162 /* Now we change back to the parent directory, and set dfd to ".",
163 in order to test behavior on symlinks. */
164 ASSERT (chdir ("..") == 0);
165 ASSERT (close (dfd) == 0);
166 if (symlink (BASE "sub1", BASE "link1"))
168 ASSERT (unlink (BASE "32") == 0);
169 ASSERT (unlink (BASE "33") == 0);
170 ASSERT (unlink (BASE "34") == 0);
171 ASSERT (rmdir (BASE "sub1") == 0);
172 ASSERT (rmdir (BASE "sub2") == 0);
175 fputs ("skipping test: symlinks not supported on this file system\n",
179 dfd = open (".", O_RDONLY);
181 ASSERT (symlink (BASE "34", BASE "link2") == 0);
182 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
183 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
185 /* Link cannot overwrite existing files. */
187 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
188 ASSERT (errno == EEXIST);
190 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
191 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
193 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
194 ASSERT (errno == EEXIST || errno == ENOTDIR);
196 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
197 AT_SYMLINK_FOLLOW) == -1);
198 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
200 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
201 AT_SYMLINK_FOLLOW) == -1);
202 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
204 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
205 AT_SYMLINK_FOLLOW) == -1);
206 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
208 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
209 ASSERT (errno == EEXIST);
211 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
212 AT_SYMLINK_FOLLOW) == -1);
213 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
215 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
216 ASSERT (errno == EEXIST || errno == ELOOP);
218 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
219 AT_SYMLINK_FOLLOW) == -1);
220 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
223 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
224 ASSERT (errno == EEXIST || errno == ELOOP);
226 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
227 AT_SYMLINK_FOLLOW) == -1);
228 ASSERT (errno == EEXIST || errno == ELOOP);
230 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
232 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
233 ASSERT (errno == EEXIST);
234 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
235 AT_SYMLINK_FOLLOW) == -1);
236 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
238 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
239 ASSERT (errno == EEXIST);
241 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
242 ASSERT (errno == EEXIST);
244 /* Trailing slash handling. */
246 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
247 ASSERT (errno == ENOTDIR);
249 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
250 AT_SYMLINK_FOLLOW) == -1);
251 ASSERT (errno == ENOTDIR);
253 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
254 ASSERT (errno == ELOOP);
256 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
257 AT_SYMLINK_FOLLOW) == -1);
258 ASSERT (errno == ELOOP);
260 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
261 ASSERT (errno == ENOENT);
263 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
264 AT_SYMLINK_FOLLOW) == -1);
265 ASSERT (errno == ENOENT);
267 /* Check for hard links to symlinks. */
268 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
269 check_same_link (BASE "link1", BASE "link5");
270 ASSERT (unlink (BASE "link5") == 0);
272 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
273 AT_SYMLINK_FOLLOW) == -1);
274 ASSERT (errno == EPERM || errno == EACCES);
275 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
276 check_same_link (BASE "link2", BASE "link5");
277 ASSERT (unlink (BASE "link5") == 0);
278 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
280 ASSERT (areadlink (BASE "file") == NULL);
281 ASSERT (errno == EINVAL);
282 ASSERT (unlink (BASE "file") == 0);
283 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
284 check_same_link (BASE "link3", BASE "link5");
285 ASSERT (unlink (BASE "link5") == 0);
287 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
288 AT_SYMLINK_FOLLOW) == -1);
289 ASSERT (errno == ELOOP);
290 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
291 check_same_link (BASE "link4", BASE "link5");
292 ASSERT (unlink (BASE "link5") == 0);
294 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
295 AT_SYMLINK_FOLLOW) == -1);
296 ASSERT (errno == ENOENT);
298 /* Check that symlink to symlink to file is followed all the way. */
299 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
300 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
301 check_same_link (BASE "link5", BASE "link6");
302 ASSERT (unlink (BASE "link6") == 0);
303 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
305 ASSERT (areadlink (BASE "file") == NULL);
306 ASSERT (errno == EINVAL);
307 ASSERT (unlink (BASE "file") == 0);
308 ASSERT (unlink (BASE "link5") == 0);
309 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
311 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
312 AT_SYMLINK_FOLLOW) == -1);
313 ASSERT (errno == ELOOP);
314 ASSERT (unlink (BASE "link5") == 0);
315 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
317 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
318 AT_SYMLINK_FOLLOW) == -1);
319 ASSERT (errno == ENOENT);
321 /* Now for some real fun with directory crossing. */
322 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
323 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
324 BASE "sub2/link") == 0);
325 ASSERT (close (dfd) == 0);
326 dfd = open (BASE "sub1", O_RDONLY);
328 dfd2 = open (BASE "sub2", O_RDONLY);
330 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
331 AT_SYMLINK_FOLLOW) == 0);
333 ASSERT (areadlink (BASE "sub1/file") == NULL);
334 ASSERT (errno == EINVAL);
337 ASSERT (close (dfd) == 0);
338 ASSERT (close (dfd2) == 0);
339 ASSERT (unlink (BASE "sub1/file") == 0);
340 ASSERT (unlink (BASE "sub1/link") == 0);
341 ASSERT (unlink (BASE "sub2/link") == 0);
342 ASSERT (unlink (BASE "32") == 0);
343 ASSERT (unlink (BASE "33") == 0);
344 ASSERT (unlink (BASE "34") == 0);
345 ASSERT (rmdir (BASE "sub1") == 0);
346 ASSERT (rmdir (BASE "sub2") == 0);
347 ASSERT (unlink (BASE "link1") == 0);
348 ASSERT (unlink (BASE "link2") == 0);
349 ASSERT (unlink (BASE "link3") == 0);
350 ASSERT (unlink (BASE "link4") == 0);
351 ASSERT (unlink (BASE "link5") == 0);