2 Copyright (C) 2009 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));
33 #include "areadlink.h"
34 #include "filenamecat.h"
35 #include "same-inode.h"
39 #define BASE "test-linkat.t"
41 #include "test-link.h"
43 static int dfd1 = AT_FDCWD;
44 static int dfd2 = AT_FDCWD;
45 static int flag = AT_SYMLINK_FOLLOW;
47 /* Wrapper to test linkat like link. */
49 do_link (char const *name1, char const *name2)
51 return linkat (dfd1, name1, dfd2, name2, flag);
54 /* Wrapper to see if two symlinks act the same. */
56 check_same_link (char const *name1, char const *name2)
62 ASSERT (lstat (name1, &st1) == 0);
63 ASSERT (lstat (name2, &st2) == 0);
64 contents1 = areadlink_with_size (name1, st1.st_size);
65 contents2 = areadlink_with_size (name2, st2.st_size);
68 ASSERT (strcmp (contents1, contents2) == 0);
69 if (!LINK_FOLLOWS_SYMLINKS)
70 ASSERT (SAME_INODE (st1, st2));
83 /* Clean up any trash from prior testsuite runs. */
84 ASSERT (system ("rm -rf " BASE "*") == 0);
86 /* Test basic link functionality, without mentioning symlinks. */
87 result = test_link (do_link, true);
88 dfd1 = open (".", O_RDONLY);
90 ASSERT (test_link (do_link, false) == result);
92 ASSERT (test_link (do_link, false) == result);
94 ASSERT (test_link (do_link, false) == result);
96 ASSERT (test_link (do_link, false) == result);
98 ASSERT (test_link (do_link, false) == result);
100 ASSERT (test_link (do_link, false) == result);
101 ASSERT (close (dfd1) == 0);
103 ASSERT (test_link (do_link, false) == result);
105 /* Create locations to manipulate. */
106 ASSERT (mkdir (BASE "sub1", 0700) == 0);
107 ASSERT (mkdir (BASE "sub2", 0700) == 0);
108 ASSERT (close (creat (BASE "00", 0600)) == 0);
111 dfd = open (BASE "sub1", O_RDONLY);
113 ASSERT (chdir (BASE "sub2") == 0);
115 /* There are 16 possible scenarios, based on whether an fd is
116 AT_FDCWD or real, whether a file is absolute or relative, coupled
117 with whether flag is set for 32 iterations.
119 To ensure that we test all of the code paths (rather than
120 triggering early normalization optimizations), we use a loop to
121 repeatedly rename a file in the parent directory, use an fd open
122 on subdirectory 1, all while executing in subdirectory 2; all
123 relative names are thus given with a leading "../". Finally, the
124 last scenario (two relative paths given, neither one AT_FDCWD)
125 has two paths, based on whether the two fds are equivalent, so we
126 do the other variant after the loop. */
127 for (i = 0; i < 32; i++)
129 int fd1 = (i & 8) ? dfd : AT_FDCWD;
130 char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
131 int fd2 = (i & 2) ? dfd : AT_FDCWD;
132 char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
133 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
135 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
136 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
137 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
138 ASSERT (unlinkat (fd1, file1, 0) == 0);
142 dfd2 = open ("..", O_RDONLY);
144 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
145 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
146 AT_SYMLINK_FOLLOW) == 0);
147 ASSERT (close (dfd2) == 0);
149 /* Now we change back to the parent directory, and set dfd to ".",
150 in order to test behavior on symlinks. */
151 ASSERT (chdir ("..") == 0);
152 ASSERT (close (dfd) == 0);
153 if (symlink (BASE "sub1", BASE "link1"))
155 ASSERT (unlink (BASE "32") == 0);
156 ASSERT (unlink (BASE "33") == 0);
157 ASSERT (unlink (BASE "34") == 0);
158 ASSERT (rmdir (BASE "sub1") == 0);
159 ASSERT (rmdir (BASE "sub2") == 0);
162 fputs ("skipping test: symlinks not supported on this file system\n",
166 dfd = open (".", O_RDONLY);
168 ASSERT (symlink (BASE "34", BASE "link2") == 0);
169 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
170 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
172 /* Link cannot overwrite existing files. */
174 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
175 ASSERT (errno == EEXIST);
177 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
178 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
180 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
181 ASSERT (errno == EEXIST);
183 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
184 AT_SYMLINK_FOLLOW) == -1);
185 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
187 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
188 AT_SYMLINK_FOLLOW) == -1);
189 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
191 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
192 AT_SYMLINK_FOLLOW) == -1);
193 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
195 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
196 ASSERT (errno == EEXIST);
198 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
199 AT_SYMLINK_FOLLOW) == -1);
200 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
202 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
203 ASSERT (errno == EEXIST || errno == ELOOP);
205 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
206 AT_SYMLINK_FOLLOW) == -1);
207 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
210 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
211 ASSERT (errno == EEXIST || errno == ELOOP);
213 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
214 AT_SYMLINK_FOLLOW) == -1);
215 ASSERT (errno == EEXIST || errno == ELOOP);
217 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
219 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
220 ASSERT (errno == EEXIST);
221 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
222 AT_SYMLINK_FOLLOW) == -1);
223 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
225 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
226 ASSERT (errno == EEXIST);
228 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
229 ASSERT (errno == EEXIST);
231 /* Trailing slash handling. */
233 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
234 ASSERT (errno == ENOTDIR);
236 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
237 AT_SYMLINK_FOLLOW) == -1);
238 ASSERT (errno == ENOTDIR);
240 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
241 ASSERT (errno == ELOOP);
243 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
244 AT_SYMLINK_FOLLOW) == -1);
245 ASSERT (errno == ELOOP);
247 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
248 ASSERT (errno == ENOENT);
250 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
251 AT_SYMLINK_FOLLOW) == -1);
252 ASSERT (errno == ENOENT);
254 /* Check for hard links to symlinks. */
255 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
256 check_same_link (BASE "link1", BASE "link5");
257 ASSERT (unlink (BASE "link5") == 0);
259 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
260 AT_SYMLINK_FOLLOW) == -1);
261 ASSERT (errno == EPERM || errno == EACCES);
262 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
263 check_same_link (BASE "link2", BASE "link5");
264 ASSERT (unlink (BASE "link5") == 0);
265 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
267 ASSERT (areadlink (BASE "file") == NULL);
268 ASSERT (errno == EINVAL);
269 ASSERT (unlink (BASE "file") == 0);
270 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
271 check_same_link (BASE "link3", BASE "link5");
272 ASSERT (unlink (BASE "link5") == 0);
274 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
275 AT_SYMLINK_FOLLOW) == -1);
276 ASSERT (errno == ELOOP);
277 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
278 check_same_link (BASE "link4", BASE "link5");
279 ASSERT (unlink (BASE "link5") == 0);
281 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
282 AT_SYMLINK_FOLLOW) == -1);
283 ASSERT (errno == ENOENT);
285 /* Check that symlink to symlink to file is followed all the way. */
286 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
287 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
288 check_same_link (BASE "link5", BASE "link6");
289 ASSERT (unlink (BASE "link6") == 0);
290 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
292 ASSERT (areadlink (BASE "file") == NULL);
293 ASSERT (errno == EINVAL);
294 ASSERT (unlink (BASE "file") == 0);
295 ASSERT (unlink (BASE "link5") == 0);
296 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
298 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
299 AT_SYMLINK_FOLLOW) == -1);
300 ASSERT (errno == ELOOP);
301 ASSERT (unlink (BASE "link5") == 0);
302 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
304 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
305 AT_SYMLINK_FOLLOW) == -1);
306 ASSERT (errno == ENOENT);
308 /* Now for some real fun with directory crossing. */
309 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
310 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
311 BASE "sub2/link") == 0);
312 ASSERT (close (dfd) == 0);
313 dfd = open (BASE "sub1", O_RDONLY);
315 dfd2 = open (BASE "sub2", O_RDONLY);
317 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
318 AT_SYMLINK_FOLLOW) == 0);
320 ASSERT (areadlink (BASE "sub1/file") == NULL);
321 ASSERT (errno == EINVAL);
324 ASSERT (close (dfd) == 0);
325 ASSERT (close (dfd2) == 0);
326 ASSERT (unlink (BASE "sub1/file") == 0);
327 ASSERT (unlink (BASE "sub1/link") == 0);
328 ASSERT (unlink (BASE "sub2/link") == 0);
329 ASSERT (unlink (BASE "32") == 0);
330 ASSERT (unlink (BASE "33") == 0);
331 ASSERT (unlink (BASE "34") == 0);
332 ASSERT (rmdir (BASE "sub1") == 0);
333 ASSERT (rmdir (BASE "sub2") == 0);
334 ASSERT (unlink (BASE "link1") == 0);
335 ASSERT (unlink (BASE "link2") == 0);
336 ASSERT (unlink (BASE "link3") == 0);
337 ASSERT (unlink (BASE "link4") == 0);
338 ASSERT (unlink (BASE "link5") == 0);