2 Copyright (C) 2009, 2010 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"
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 /* Wrapper to see if two symlinks act the same. */
57 check_same_link (char const *name1, char const *name2)
63 ASSERT (lstat (name1, &st1) == 0);
64 ASSERT (lstat (name2, &st2) == 0);
65 contents1 = areadlink_with_size (name1, st1.st_size);
66 contents2 = areadlink_with_size (name2, st2.st_size);
69 ASSERT (strcmp (contents1, contents2) == 0);
70 if (!LINK_FOLLOWS_SYMLINKS)
71 ASSERT (SAME_INODE (st1, st2));
84 /* Clean up any trash from prior testsuite runs. */
85 ignore_value (system ("rm -rf " BASE "*"));
87 /* Test basic link functionality, without mentioning symlinks. */
88 result = test_link (do_link, true);
89 dfd1 = open (".", O_RDONLY);
91 ASSERT (test_link (do_link, false) == result);
93 ASSERT (test_link (do_link, false) == result);
95 ASSERT (test_link (do_link, false) == result);
97 ASSERT (test_link (do_link, false) == result);
99 ASSERT (test_link (do_link, false) == result);
101 ASSERT (test_link (do_link, false) == result);
102 ASSERT (close (dfd1) == 0);
104 ASSERT (test_link (do_link, false) == result);
106 /* Create locations to manipulate. */
107 ASSERT (mkdir (BASE "sub1", 0700) == 0);
108 ASSERT (mkdir (BASE "sub2", 0700) == 0);
109 ASSERT (close (creat (BASE "00", 0600)) == 0);
112 dfd = open (BASE "sub1", O_RDONLY);
114 ASSERT (chdir (BASE "sub2") == 0);
116 /* There are 16 possible scenarios, based on whether an fd is
117 AT_FDCWD or real, whether a file is absolute or relative, coupled
118 with whether flag is set for 32 iterations.
120 To ensure that we test all of the code paths (rather than
121 triggering early normalization optimizations), we use a loop to
122 repeatedly rename a file in the parent directory, use an fd open
123 on subdirectory 1, all while executing in subdirectory 2; all
124 relative names are thus given with a leading "../". Finally, the
125 last scenario (two relative paths given, neither one AT_FDCWD)
126 has two paths, based on whether the two fds are equivalent, so we
127 do the other variant after the loop. */
128 for (i = 0; i < 32; i++)
130 int fd1 = (i & 8) ? dfd : AT_FDCWD;
131 char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
132 int fd2 = (i & 2) ? dfd : AT_FDCWD;
133 char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
134 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
136 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
137 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
138 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
139 ASSERT (unlinkat (fd1, file1, 0) == 0);
143 dfd2 = open ("..", O_RDONLY);
145 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
146 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
147 AT_SYMLINK_FOLLOW) == 0);
148 ASSERT (close (dfd2) == 0);
150 /* Now we change back to the parent directory, and set dfd to ".",
151 in order to test behavior on symlinks. */
152 ASSERT (chdir ("..") == 0);
153 ASSERT (close (dfd) == 0);
154 if (symlink (BASE "sub1", BASE "link1"))
156 ASSERT (unlink (BASE "32") == 0);
157 ASSERT (unlink (BASE "33") == 0);
158 ASSERT (unlink (BASE "34") == 0);
159 ASSERT (rmdir (BASE "sub1") == 0);
160 ASSERT (rmdir (BASE "sub2") == 0);
163 fputs ("skipping test: symlinks not supported on this file system\n",
167 dfd = open (".", O_RDONLY);
169 ASSERT (symlink (BASE "34", BASE "link2") == 0);
170 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
171 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
173 /* Link cannot overwrite existing files. */
175 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
176 ASSERT (errno == EEXIST);
178 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
179 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
181 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
182 ASSERT (errno == EEXIST);
184 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
185 AT_SYMLINK_FOLLOW) == -1);
186 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
188 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
189 AT_SYMLINK_FOLLOW) == -1);
190 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
192 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
193 AT_SYMLINK_FOLLOW) == -1);
194 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
196 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
197 ASSERT (errno == EEXIST);
199 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
200 AT_SYMLINK_FOLLOW) == -1);
201 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
203 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
204 ASSERT (errno == EEXIST || errno == ELOOP);
206 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
207 AT_SYMLINK_FOLLOW) == -1);
208 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
211 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
212 ASSERT (errno == EEXIST || errno == ELOOP);
214 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
215 AT_SYMLINK_FOLLOW) == -1);
216 ASSERT (errno == EEXIST || errno == ELOOP);
218 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
220 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
221 ASSERT (errno == EEXIST);
222 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
223 AT_SYMLINK_FOLLOW) == -1);
224 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
226 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
227 ASSERT (errno == EEXIST);
229 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
230 ASSERT (errno == EEXIST);
232 /* Trailing slash handling. */
234 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
235 ASSERT (errno == ENOTDIR);
237 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
238 AT_SYMLINK_FOLLOW) == -1);
239 ASSERT (errno == ENOTDIR);
241 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
242 ASSERT (errno == ELOOP);
244 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
245 AT_SYMLINK_FOLLOW) == -1);
246 ASSERT (errno == ELOOP);
248 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
249 ASSERT (errno == ENOENT);
251 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
252 AT_SYMLINK_FOLLOW) == -1);
253 ASSERT (errno == ENOENT);
255 /* Check for hard links to symlinks. */
256 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
257 check_same_link (BASE "link1", BASE "link5");
258 ASSERT (unlink (BASE "link5") == 0);
260 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
261 AT_SYMLINK_FOLLOW) == -1);
262 ASSERT (errno == EPERM || errno == EACCES);
263 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
264 check_same_link (BASE "link2", BASE "link5");
265 ASSERT (unlink (BASE "link5") == 0);
266 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
268 ASSERT (areadlink (BASE "file") == NULL);
269 ASSERT (errno == EINVAL);
270 ASSERT (unlink (BASE "file") == 0);
271 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
272 check_same_link (BASE "link3", BASE "link5");
273 ASSERT (unlink (BASE "link5") == 0);
275 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
276 AT_SYMLINK_FOLLOW) == -1);
277 ASSERT (errno == ELOOP);
278 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
279 check_same_link (BASE "link4", BASE "link5");
280 ASSERT (unlink (BASE "link5") == 0);
282 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
283 AT_SYMLINK_FOLLOW) == -1);
284 ASSERT (errno == ENOENT);
286 /* Check that symlink to symlink to file is followed all the way. */
287 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
288 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
289 check_same_link (BASE "link5", BASE "link6");
290 ASSERT (unlink (BASE "link6") == 0);
291 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
293 ASSERT (areadlink (BASE "file") == NULL);
294 ASSERT (errno == EINVAL);
295 ASSERT (unlink (BASE "file") == 0);
296 ASSERT (unlink (BASE "link5") == 0);
297 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
299 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
300 AT_SYMLINK_FOLLOW) == -1);
301 ASSERT (errno == ELOOP);
302 ASSERT (unlink (BASE "link5") == 0);
303 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
305 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
306 AT_SYMLINK_FOLLOW) == -1);
307 ASSERT (errno == ENOENT);
309 /* Now for some real fun with directory crossing. */
310 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
311 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
312 BASE "sub2/link") == 0);
313 ASSERT (close (dfd) == 0);
314 dfd = open (BASE "sub1", O_RDONLY);
316 dfd2 = open (BASE "sub2", O_RDONLY);
318 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
319 AT_SYMLINK_FOLLOW) == 0);
321 ASSERT (areadlink (BASE "sub1/file") == NULL);
322 ASSERT (errno == EINVAL);
325 ASSERT (close (dfd) == 0);
326 ASSERT (close (dfd2) == 0);
327 ASSERT (unlink (BASE "sub1/file") == 0);
328 ASSERT (unlink (BASE "sub1/link") == 0);
329 ASSERT (unlink (BASE "sub2/link") == 0);
330 ASSERT (unlink (BASE "32") == 0);
331 ASSERT (unlink (BASE "33") == 0);
332 ASSERT (unlink (BASE "34") == 0);
333 ASSERT (rmdir (BASE "sub1") == 0);
334 ASSERT (rmdir (BASE "sub2") == 0);
335 ASSERT (unlink (BASE "link1") == 0);
336 ASSERT (unlink (BASE "link2") == 0);
337 ASSERT (unlink (BASE "link3") == 0);
338 ASSERT (unlink (BASE "link4") == 0);
339 ASSERT (unlink (BASE "link5") == 0);