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. */
30 #include "areadlink.h"
31 #include "filenamecat.h"
32 #include "same-inode.h"
35 #define ASSERT(expr) \
40 fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
47 #define BASE "test-linkat.t"
49 #include "test-link.h"
51 static int dfd1 = AT_FDCWD;
52 static int dfd2 = AT_FDCWD;
53 static int flag = AT_SYMLINK_FOLLOW;
55 /* Wrapper to test linkat like link. */
57 do_link (char const *name1, char const *name2)
59 return linkat (dfd1, name1, dfd2, name2, flag);
62 /* Wrapper to see if two symlinks act the same. */
64 check_same_link (char const *name1, char const *name2)
70 ASSERT (lstat (name1, &st1) == 0);
71 ASSERT (lstat (name2, &st2) == 0);
72 contents1 = areadlink_with_size (name1, st1.st_size);
73 contents2 = areadlink_with_size (name2, st2.st_size);
76 ASSERT (strcmp (contents1, contents2) == 0);
77 if (!LINK_FOLLOWS_SYMLINKS)
78 ASSERT (SAME_INODE (st1, st2));
91 /* Clean up any trash from prior testsuite runs. */
92 ASSERT (system ("rm -rf " BASE "*") == 0);
94 /* Test basic link functionality, without mentioning symlinks. */
95 result = test_link (do_link, false);
96 dfd1 = open (".", O_RDONLY);
98 ASSERT (test_link (do_link, false) == result);
100 ASSERT (test_link (do_link, false) == result);
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);
109 ASSERT (close (dfd1) == 0);
111 ASSERT (test_link (do_link, false) == result);
113 /* Create locations to manipulate. */
114 ASSERT (mkdir (BASE "sub1", 0700) == 0);
115 ASSERT (mkdir (BASE "sub2", 0700) == 0);
116 ASSERT (close (creat (BASE "00", 0600)) == 0);
119 dfd = open (BASE "sub1", O_RDONLY);
121 ASSERT (chdir (BASE "sub2") == 0);
123 /* There are 16 possible scenarios, based on whether an fd is
124 AT_FDCWD or real, whether a file is absolute or relative, coupled
125 with whether flag is set for 32 iterations.
127 To ensure that we test all of the code paths (rather than
128 triggering early normalization optimizations), we use a loop to
129 repeatedly rename a file in the parent directory, use an fd open
130 on subdirectory 1, all while executing in subdirectory 2; all
131 relative names are thus given with a leading "../". Finally, the
132 last scenario (two relative paths given, neither one AT_FDCWD)
133 has two paths, based on whether the two fds are equivalent, so we
134 do the other variant after the loop. */
135 for (i = 0; i < 32; i++)
137 int fd1 = (i & 8) ? dfd : AT_FDCWD;
138 char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
139 int fd2 = (i & 2) ? dfd : AT_FDCWD;
140 char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
141 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
143 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
144 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
145 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
146 ASSERT (unlinkat (fd1, file1, 0) == 0);
150 dfd2 = open ("..", O_RDONLY);
152 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
153 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
154 AT_SYMLINK_FOLLOW) == 0);
155 ASSERT (close (dfd2) == 0);
157 /* Now we change back to the parent directory, and set dfd to ".",
158 in order to test behavior on symlinks. */
159 ASSERT (chdir ("..") == 0);
160 ASSERT (close (dfd) == 0);
161 if (symlink (BASE "sub1", BASE "link1"))
163 ASSERT (unlink (BASE "32") == 0);
164 ASSERT (unlink (BASE "33") == 0);
165 ASSERT (unlink (BASE "34") == 0);
166 ASSERT (rmdir (BASE "sub1") == 0);
167 ASSERT (rmdir (BASE "sub2") == 0);
169 fputs ("skipping test: symlinks not supported on this file system\n",
173 dfd = open (".", O_RDONLY);
175 ASSERT (symlink (BASE "34", BASE "link2") == 0);
176 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
177 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
179 /* Link cannot overwrite existing files. */
181 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
182 ASSERT (errno == EEXIST);
184 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
185 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
187 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
188 ASSERT (errno == EEXIST);
190 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
191 AT_SYMLINK_FOLLOW) == -1);
192 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
194 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
195 AT_SYMLINK_FOLLOW) == -1);
196 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
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 "link2", 0) == -1);
203 ASSERT (errno == EEXIST);
205 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
206 AT_SYMLINK_FOLLOW) == -1);
207 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
209 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
210 ASSERT (errno == EEXIST || errno == ELOOP);
212 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
213 AT_SYMLINK_FOLLOW) == -1);
214 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
217 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
218 ASSERT (errno == EEXIST || errno == ELOOP);
220 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
221 AT_SYMLINK_FOLLOW) == -1);
222 ASSERT (errno == EEXIST || errno == ELOOP);
224 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
226 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
227 ASSERT (errno == EEXIST);
228 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
229 AT_SYMLINK_FOLLOW) == -1);
230 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
232 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
233 ASSERT (errno == EEXIST);
235 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
236 ASSERT (errno == EEXIST);
238 /* Trailing slash handling. */
240 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
241 ASSERT (errno == ENOTDIR);
243 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
244 AT_SYMLINK_FOLLOW) == -1);
245 ASSERT (errno == ENOTDIR);
247 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
248 ASSERT (errno == ELOOP);
250 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
251 AT_SYMLINK_FOLLOW) == -1);
252 ASSERT (errno == ELOOP);
254 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
255 ASSERT (errno == ENOENT);
257 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
258 AT_SYMLINK_FOLLOW) == -1);
259 ASSERT (errno == ENOENT);
261 /* Check for hard links to symlinks. */
262 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
263 check_same_link (BASE "link1", BASE "link5");
264 ASSERT (unlink (BASE "link5") == 0);
266 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
267 AT_SYMLINK_FOLLOW) == -1);
268 ASSERT (errno == EPERM || errno == EACCES);
269 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
270 check_same_link (BASE "link2", BASE "link5");
271 ASSERT (unlink (BASE "link5") == 0);
272 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
274 ASSERT (areadlink (BASE "file") == NULL);
275 ASSERT (errno == EINVAL);
276 ASSERT (unlink (BASE "file") == 0);
277 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
278 check_same_link (BASE "link3", BASE "link5");
279 ASSERT (unlink (BASE "link5") == 0);
281 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
282 AT_SYMLINK_FOLLOW) == -1);
283 ASSERT (errno == ELOOP);
284 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
285 check_same_link (BASE "link4", BASE "link5");
286 ASSERT (unlink (BASE "link5") == 0);
288 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
289 AT_SYMLINK_FOLLOW) == -1);
290 ASSERT (errno == ENOENT);
292 /* Check that symlink to symlink to file is followed all the way. */
293 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
294 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
295 check_same_link (BASE "link5", BASE "link6");
296 ASSERT (unlink (BASE "link6") == 0);
297 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
299 ASSERT (areadlink (BASE "file") == NULL);
300 ASSERT (errno == EINVAL);
301 ASSERT (unlink (BASE "file") == 0);
302 ASSERT (unlink (BASE "link5") == 0);
303 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
305 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
306 AT_SYMLINK_FOLLOW) == -1);
307 ASSERT (errno == ELOOP);
308 ASSERT (unlink (BASE "link5") == 0);
309 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
311 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
312 AT_SYMLINK_FOLLOW) == -1);
313 ASSERT (errno == ENOENT);
315 /* Now for some real fun with directory crossing. */
316 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
317 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
318 BASE "sub2/link") == 0);
319 ASSERT (close (dfd) == 0);
320 dfd = open (BASE "sub1", O_RDONLY);
322 dfd2 = open (BASE "sub2", O_RDONLY);
324 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
325 AT_SYMLINK_FOLLOW) == 0);
327 ASSERT (areadlink (BASE "sub1/file") == NULL);
328 ASSERT (errno == EINVAL);
331 ASSERT (close (dfd) == 0);
332 ASSERT (close (dfd2) == 0);
333 ASSERT (unlink (BASE "sub1/file") == 0);
334 ASSERT (unlink (BASE "sub1/link") == 0);
335 ASSERT (unlink (BASE "sub2/link") == 0);
336 ASSERT (unlink (BASE "32") == 0);
337 ASSERT (unlink (BASE "33") == 0);
338 ASSERT (unlink (BASE "34") == 0);
339 ASSERT (rmdir (BASE "sub1") == 0);
340 ASSERT (rmdir (BASE "sub2") == 0);
341 ASSERT (unlink (BASE "link1") == 0);
342 ASSERT (unlink (BASE "link2") == 0);
343 ASSERT (unlink (BASE "link3") == 0);
344 ASSERT (unlink (BASE "link4") == 0);
345 ASSERT (unlink (BASE "link5") == 0);