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"
38 #define ASSERT(expr) \
43 fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
50 #define BASE "test-linkat.t"
52 #include "test-link.h"
54 static int dfd1 = AT_FDCWD;
55 static int dfd2 = AT_FDCWD;
56 static int flag = AT_SYMLINK_FOLLOW;
58 /* Wrapper to test linkat like link. */
60 do_link (char const *name1, char const *name2)
62 return linkat (dfd1, name1, dfd2, name2, flag);
65 /* Wrapper to see if two symlinks act the same. */
67 check_same_link (char const *name1, char const *name2)
73 ASSERT (lstat (name1, &st1) == 0);
74 ASSERT (lstat (name2, &st2) == 0);
75 contents1 = areadlink_with_size (name1, st1.st_size);
76 contents2 = areadlink_with_size (name2, st2.st_size);
79 ASSERT (strcmp (contents1, contents2) == 0);
80 if (!LINK_FOLLOWS_SYMLINKS)
81 ASSERT (SAME_INODE (st1, st2));
94 /* Clean up any trash from prior testsuite runs. */
95 ASSERT (system ("rm -rf " BASE "*") == 0);
97 /* Test basic link functionality, without mentioning symlinks. */
98 result = test_link (do_link, true);
99 dfd1 = open (".", O_RDONLY);
101 ASSERT (test_link (do_link, false) == result);
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);
112 ASSERT (close (dfd1) == 0);
114 ASSERT (test_link (do_link, false) == result);
116 /* Create locations to manipulate. */
117 ASSERT (mkdir (BASE "sub1", 0700) == 0);
118 ASSERT (mkdir (BASE "sub2", 0700) == 0);
119 ASSERT (close (creat (BASE "00", 0600)) == 0);
122 dfd = open (BASE "sub1", O_RDONLY);
124 ASSERT (chdir (BASE "sub2") == 0);
126 /* There are 16 possible scenarios, based on whether an fd is
127 AT_FDCWD or real, whether a file is absolute or relative, coupled
128 with whether flag is set for 32 iterations.
130 To ensure that we test all of the code paths (rather than
131 triggering early normalization optimizations), we use a loop to
132 repeatedly rename a file in the parent directory, use an fd open
133 on subdirectory 1, all while executing in subdirectory 2; all
134 relative names are thus given with a leading "../". Finally, the
135 last scenario (two relative paths given, neither one AT_FDCWD)
136 has two paths, based on whether the two fds are equivalent, so we
137 do the other variant after the loop. */
138 for (i = 0; i < 32; i++)
140 int fd1 = (i & 8) ? dfd : AT_FDCWD;
141 char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
142 int fd2 = (i & 2) ? dfd : AT_FDCWD;
143 char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
144 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
146 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
147 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
148 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
149 ASSERT (unlinkat (fd1, file1, 0) == 0);
153 dfd2 = open ("..", O_RDONLY);
155 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
156 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
157 AT_SYMLINK_FOLLOW) == 0);
158 ASSERT (close (dfd2) == 0);
160 /* Now we change back to the parent directory, and set dfd to ".",
161 in order to test behavior on symlinks. */
162 ASSERT (chdir ("..") == 0);
163 ASSERT (close (dfd) == 0);
164 if (symlink (BASE "sub1", BASE "link1"))
166 ASSERT (unlink (BASE "32") == 0);
167 ASSERT (unlink (BASE "33") == 0);
168 ASSERT (unlink (BASE "34") == 0);
169 ASSERT (rmdir (BASE "sub1") == 0);
170 ASSERT (rmdir (BASE "sub2") == 0);
173 fputs ("skipping test: symlinks not supported on this file system\n",
177 dfd = open (".", O_RDONLY);
179 ASSERT (symlink (BASE "34", BASE "link2") == 0);
180 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
181 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
183 /* Link cannot overwrite existing files. */
185 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
186 ASSERT (errno == EEXIST);
188 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
189 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
191 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
192 ASSERT (errno == EEXIST);
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 "sub1/",
203 AT_SYMLINK_FOLLOW) == -1);
204 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
206 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
207 ASSERT (errno == EEXIST);
209 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
210 AT_SYMLINK_FOLLOW) == -1);
211 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
213 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
214 ASSERT (errno == EEXIST || errno == ELOOP);
216 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
217 AT_SYMLINK_FOLLOW) == -1);
218 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
221 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
222 ASSERT (errno == EEXIST || errno == ELOOP);
224 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
225 AT_SYMLINK_FOLLOW) == -1);
226 ASSERT (errno == EEXIST || errno == ELOOP);
228 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
230 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
231 ASSERT (errno == EEXIST);
232 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
233 AT_SYMLINK_FOLLOW) == -1);
234 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
236 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
237 ASSERT (errno == EEXIST);
239 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
240 ASSERT (errno == EEXIST);
242 /* Trailing slash handling. */
244 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
245 ASSERT (errno == ENOTDIR);
247 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
248 AT_SYMLINK_FOLLOW) == -1);
249 ASSERT (errno == ENOTDIR);
251 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
252 ASSERT (errno == ELOOP);
254 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
255 AT_SYMLINK_FOLLOW) == -1);
256 ASSERT (errno == ELOOP);
258 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
259 ASSERT (errno == ENOENT);
261 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
262 AT_SYMLINK_FOLLOW) == -1);
263 ASSERT (errno == ENOENT);
265 /* Check for hard links to symlinks. */
266 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
267 check_same_link (BASE "link1", BASE "link5");
268 ASSERT (unlink (BASE "link5") == 0);
270 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
271 AT_SYMLINK_FOLLOW) == -1);
272 ASSERT (errno == EPERM || errno == EACCES);
273 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
274 check_same_link (BASE "link2", BASE "link5");
275 ASSERT (unlink (BASE "link5") == 0);
276 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
278 ASSERT (areadlink (BASE "file") == NULL);
279 ASSERT (errno == EINVAL);
280 ASSERT (unlink (BASE "file") == 0);
281 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
282 check_same_link (BASE "link3", BASE "link5");
283 ASSERT (unlink (BASE "link5") == 0);
285 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
286 AT_SYMLINK_FOLLOW) == -1);
287 ASSERT (errno == ELOOP);
288 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
289 check_same_link (BASE "link4", BASE "link5");
290 ASSERT (unlink (BASE "link5") == 0);
292 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
293 AT_SYMLINK_FOLLOW) == -1);
294 ASSERT (errno == ENOENT);
296 /* Check that symlink to symlink to file is followed all the way. */
297 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
298 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
299 check_same_link (BASE "link5", BASE "link6");
300 ASSERT (unlink (BASE "link6") == 0);
301 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
303 ASSERT (areadlink (BASE "file") == NULL);
304 ASSERT (errno == EINVAL);
305 ASSERT (unlink (BASE "file") == 0);
306 ASSERT (unlink (BASE "link5") == 0);
307 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
309 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
310 AT_SYMLINK_FOLLOW) == -1);
311 ASSERT (errno == ELOOP);
312 ASSERT (unlink (BASE "link5") == 0);
313 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
315 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
316 AT_SYMLINK_FOLLOW) == -1);
317 ASSERT (errno == ENOENT);
319 /* Now for some real fun with directory crossing. */
320 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
321 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
322 BASE "sub2/link") == 0);
323 ASSERT (close (dfd) == 0);
324 dfd = open (BASE "sub1", O_RDONLY);
326 dfd2 = open (BASE "sub2", O_RDONLY);
328 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
329 AT_SYMLINK_FOLLOW) == 0);
331 ASSERT (areadlink (BASE "sub1/file") == NULL);
332 ASSERT (errno == EINVAL);
335 ASSERT (close (dfd) == 0);
336 ASSERT (close (dfd2) == 0);
337 ASSERT (unlink (BASE "sub1/file") == 0);
338 ASSERT (unlink (BASE "sub1/link") == 0);
339 ASSERT (unlink (BASE "sub2/link") == 0);
340 ASSERT (unlink (BASE "32") == 0);
341 ASSERT (unlink (BASE "33") == 0);
342 ASSERT (unlink (BASE "34") == 0);
343 ASSERT (rmdir (BASE "sub1") == 0);
344 ASSERT (rmdir (BASE "sub2") == 0);
345 ASSERT (unlink (BASE "link1") == 0);
346 ASSERT (unlink (BASE "link2") == 0);
347 ASSERT (unlink (BASE "link3") == 0);
348 ASSERT (unlink (BASE "link4") == 0);
349 ASSERT (unlink (BASE "link5") == 0);