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));
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 /* Wrapper to see if two symlinks act the same. */
58 check_same_link (char const *name1, char const *name2)
64 ASSERT (lstat (name1, &st1) == 0);
65 ASSERT (lstat (name2, &st2) == 0);
66 contents1 = areadlink_with_size (name1, st1.st_size);
67 contents2 = areadlink_with_size (name2, st2.st_size);
70 ASSERT (strcmp (contents1, contents2) == 0);
71 if (!LINK_FOLLOWS_SYMLINKS)
72 ASSERT (SAME_INODE (st1, st2));
85 /* Clean up any trash from prior testsuite runs. */
86 ignore_value (system ("rm -rf " BASE "*"));
88 /* Test basic link functionality, without mentioning symlinks. */
89 result = test_link (do_link, true);
90 dfd1 = open (".", O_RDONLY);
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);
102 ASSERT (test_link (do_link, false) == result);
103 ASSERT (close (dfd1) == 0);
105 ASSERT (test_link (do_link, false) == result);
107 /* Create locations to manipulate. */
108 ASSERT (mkdir (BASE "sub1", 0700) == 0);
109 ASSERT (mkdir (BASE "sub2", 0700) == 0);
110 ASSERT (close (creat (BASE "00", 0600)) == 0);
113 dfd = open (BASE "sub1", O_RDONLY);
115 ASSERT (chdir (BASE "sub2") == 0);
117 /* There are 16 possible scenarios, based on whether an fd is
118 AT_FDCWD or real, whether a file is absolute or relative, coupled
119 with whether flag is set for 32 iterations.
121 To ensure that we test all of the code paths (rather than
122 triggering early normalization optimizations), we use a loop to
123 repeatedly rename a file in the parent directory, use an fd open
124 on subdirectory 1, all while executing in subdirectory 2; all
125 relative names are thus given with a leading "../". Finally, the
126 last scenario (two relative paths given, neither one AT_FDCWD)
127 has two paths, based on whether the two fds are equivalent, so we
128 do the other variant after the loop. */
129 for (i = 0; i < 32; i++)
131 int fd1 = (i & 8) ? dfd : AT_FDCWD;
132 char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
133 int fd2 = (i & 2) ? dfd : AT_FDCWD;
134 char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
135 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
137 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
138 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
139 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
140 ASSERT (unlinkat (fd1, file1, 0) == 0);
144 dfd2 = open ("..", O_RDONLY);
146 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
147 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
148 AT_SYMLINK_FOLLOW) == 0);
149 ASSERT (close (dfd2) == 0);
151 /* Now we change back to the parent directory, and set dfd to ".",
152 in order to test behavior on symlinks. */
153 ASSERT (chdir ("..") == 0);
154 ASSERT (close (dfd) == 0);
155 if (symlink (BASE "sub1", BASE "link1"))
157 ASSERT (unlink (BASE "32") == 0);
158 ASSERT (unlink (BASE "33") == 0);
159 ASSERT (unlink (BASE "34") == 0);
160 ASSERT (rmdir (BASE "sub1") == 0);
161 ASSERT (rmdir (BASE "sub2") == 0);
164 fputs ("skipping test: symlinks not supported on this file system\n",
168 dfd = open (".", O_RDONLY);
170 ASSERT (symlink (BASE "34", BASE "link2") == 0);
171 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
172 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
174 /* Link cannot overwrite existing files. */
176 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
177 ASSERT (errno == EEXIST);
179 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
180 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
182 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
183 ASSERT (errno == EEXIST);
185 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
186 AT_SYMLINK_FOLLOW) == -1);
187 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
189 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
190 AT_SYMLINK_FOLLOW) == -1);
191 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
193 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
194 AT_SYMLINK_FOLLOW) == -1);
195 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
197 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
198 ASSERT (errno == EEXIST);
200 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
201 AT_SYMLINK_FOLLOW) == -1);
202 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
204 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
205 ASSERT (errno == EEXIST || errno == ELOOP);
207 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
208 AT_SYMLINK_FOLLOW) == -1);
209 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
212 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
213 ASSERT (errno == EEXIST || errno == ELOOP);
215 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
216 AT_SYMLINK_FOLLOW) == -1);
217 ASSERT (errno == EEXIST || errno == ELOOP);
219 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
221 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
222 ASSERT (errno == EEXIST);
223 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
224 AT_SYMLINK_FOLLOW) == -1);
225 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
227 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
228 ASSERT (errno == EEXIST);
230 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
231 ASSERT (errno == EEXIST);
233 /* Trailing slash handling. */
235 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
236 ASSERT (errno == ENOTDIR);
238 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
239 AT_SYMLINK_FOLLOW) == -1);
240 ASSERT (errno == ENOTDIR);
242 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
243 ASSERT (errno == ELOOP);
245 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
246 AT_SYMLINK_FOLLOW) == -1);
247 ASSERT (errno == ELOOP);
249 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
250 ASSERT (errno == ENOENT);
252 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
253 AT_SYMLINK_FOLLOW) == -1);
254 ASSERT (errno == ENOENT);
256 /* Check for hard links to symlinks. */
257 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
258 check_same_link (BASE "link1", BASE "link5");
259 ASSERT (unlink (BASE "link5") == 0);
261 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
262 AT_SYMLINK_FOLLOW) == -1);
263 ASSERT (errno == EPERM || errno == EACCES);
264 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
265 check_same_link (BASE "link2", BASE "link5");
266 ASSERT (unlink (BASE "link5") == 0);
267 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
269 ASSERT (areadlink (BASE "file") == NULL);
270 ASSERT (errno == EINVAL);
271 ASSERT (unlink (BASE "file") == 0);
272 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
273 check_same_link (BASE "link3", BASE "link5");
274 ASSERT (unlink (BASE "link5") == 0);
276 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
277 AT_SYMLINK_FOLLOW) == -1);
278 ASSERT (errno == ELOOP);
279 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
280 check_same_link (BASE "link4", BASE "link5");
281 ASSERT (unlink (BASE "link5") == 0);
283 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
284 AT_SYMLINK_FOLLOW) == -1);
285 ASSERT (errno == ENOENT);
287 /* Check that symlink to symlink to file is followed all the way. */
288 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
289 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
290 check_same_link (BASE "link5", BASE "link6");
291 ASSERT (unlink (BASE "link6") == 0);
292 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
294 ASSERT (areadlink (BASE "file") == NULL);
295 ASSERT (errno == EINVAL);
296 ASSERT (unlink (BASE "file") == 0);
297 ASSERT (unlink (BASE "link5") == 0);
298 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
300 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
301 AT_SYMLINK_FOLLOW) == -1);
302 ASSERT (errno == ELOOP);
303 ASSERT (unlink (BASE "link5") == 0);
304 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
306 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
307 AT_SYMLINK_FOLLOW) == -1);
308 ASSERT (errno == ENOENT);
310 /* Now for some real fun with directory crossing. */
311 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
312 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
313 BASE "sub2/link") == 0);
314 ASSERT (close (dfd) == 0);
315 dfd = open (BASE "sub1", O_RDONLY);
317 dfd2 = open (BASE "sub2", O_RDONLY);
319 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
320 AT_SYMLINK_FOLLOW) == 0);
322 ASSERT (areadlink (BASE "sub1/file") == NULL);
323 ASSERT (errno == EINVAL);
326 ASSERT (close (dfd) == 0);
327 ASSERT (close (dfd2) == 0);
328 ASSERT (unlink (BASE "sub1/file") == 0);
329 ASSERT (unlink (BASE "sub1/link") == 0);
330 ASSERT (unlink (BASE "sub2/link") == 0);
331 ASSERT (unlink (BASE "32") == 0);
332 ASSERT (unlink (BASE "33") == 0);
333 ASSERT (unlink (BASE "34") == 0);
334 ASSERT (rmdir (BASE "sub1") == 0);
335 ASSERT (rmdir (BASE "sub2") == 0);
336 ASSERT (unlink (BASE "link1") == 0);
337 ASSERT (unlink (BASE "link2") == 0);
338 ASSERT (unlink (BASE "link3") == 0);
339 ASSERT (unlink (BASE "link4") == 0);
340 ASSERT (unlink (BASE "link5") == 0);