1 /* Tests of linkat.
2 Copyright (C) 2009-2023 Free Software Foundation, Inc.
3
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.
8
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.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 /* Written by Eric Blake <ebb9@byu.net>, 2009. */
18
19 #include <config.h>
20
21 #include <unistd.h>
22
23 #include "signature.h"
24 SIGNATURE_CHECK (linkat, int, (int, char const *, int, char const *, int));
25
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32
33 #include "areadlink.h"
34 #include "filenamecat.h"
35 #include "same-inode.h"
36 #include "ignore-value.h"
37 #include "macros.h"
38
39 #define BASE "test-linkat.t"
40
41 #include "test-link.h"
42
43 static int dfd1 = AT_FDCWD;
44 static int dfd2 = AT_FDCWD;
45 static int flag = AT_SYMLINK_FOLLOW;
46
47 /* Wrapper to test linkat like link. */
48 static int
49 do_link (char const *name1, char const *name2)
50 {
51 return linkat (dfd1, name1, dfd2, name2, flag);
52 }
53
54 /* Can we expect that link() and linkat(), when called on a symlink,
55 increment the link count of that symlink? */
56 #if LINK_FOLLOWS_SYMLINKS == 0
57 # define EXPECT_LINK_HARDLINKS_SYMLINKS 1
58 #elif LINK_FOLLOWS_SYMLINKS == -1
59 extern int __xpg4;
60 # define EXPECT_LINK_HARDLINKS_SYMLINKS (__xpg4 == 0)
61 #else
62 # define EXPECT_LINK_HARDLINKS_SYMLINKS 0
63 #endif
64
65 /* Wrapper to see if two symlinks act the same. */
66 static void
67 check_same_link (char const *name1, char const *name2)
68 {
69 struct stat st1;
70 struct stat st2;
71 char *contents1;
72 char *contents2;
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);
77 ASSERT (contents1);
78 ASSERT (contents2);
79 ASSERT (strcmp (contents1, contents2) == 0);
80 if (EXPECT_LINK_HARDLINKS_SYMLINKS)
81 ASSERT (SAME_INODE (st1, st2));
82 free (contents1);
83 free (contents2);
84 }
85
86 int
87 main (void)
88 {
89 int i;
90 int dfd;
91 char *cwd;
92 int result;
93
94 /* Clean up any trash from prior testsuite runs. */
95 ignore_value (system ("rm -rf " BASE "*"));
96
97 /* Test behaviour for invalid file descriptors. */
98 {
99 errno = 0;
100 ASSERT (linkat (-1, "foo", AT_FDCWD, "bar", 0) == -1);
101 ASSERT (errno == EBADF);
102 }
103 {
104 close (99);
105 errno = 0;
106 ASSERT (linkat (99, "foo", AT_FDCWD, "bar", 0) == -1);
107 ASSERT (errno == EBADF);
108 }
109 ASSERT (close (creat (BASE "oo", 0600)) == 0);
110 {
111 errno = 0;
112 ASSERT (linkat (AT_FDCWD, BASE "oo", -1, "bar", 0) == -1);
113 ASSERT (errno == EBADF);
114 }
115 {
116 errno = 0;
117 ASSERT (linkat (AT_FDCWD, BASE "oo", 99, "bar", 0) == -1);
118 ASSERT (errno == EBADF);
119 }
120 ASSERT (unlink (BASE "oo") == 0);
121
122 /* Test basic link functionality, without mentioning symlinks. */
123 result = test_link (do_link, true);
124 dfd1 = open (".", O_RDONLY);
125 ASSERT (0 <= dfd1);
126 ASSERT (test_link (do_link, false) == result);
127 dfd2 = dfd1;
128 ASSERT (test_link (do_link, false) == result);
129 dfd1 = AT_FDCWD;
130 ASSERT (test_link (do_link, false) == result);
131 flag = 0;
132 ASSERT (test_link (do_link, false) == result);
133 dfd1 = dfd2;
134 ASSERT (test_link (do_link, false) == result);
135 dfd2 = AT_FDCWD;
136 ASSERT (test_link (do_link, false) == result);
137 ASSERT (close (dfd1) == 0);
138 dfd1 = AT_FDCWD;
139 ASSERT (test_link (do_link, false) == result);
140
141 /* Skip the rest of the test if the file system does not support hard links
142 and symlinks. */
143 if (result)
144 return result;
145
146 /* Create locations to manipulate. */
147 ASSERT (mkdir (BASE "sub1", 0700) == 0);
148 ASSERT (mkdir (BASE "sub2", 0700) == 0);
149 ASSERT (close (creat (BASE "00", 0600)) == 0);
150 cwd = getcwd (NULL, 0);
151 ASSERT (cwd);
152
153 dfd = open (BASE "sub1", O_RDONLY);
154 ASSERT (0 <= dfd);
155 ASSERT (chdir (BASE "sub2") == 0);
156
157 /* There are 16 possible scenarios, based on whether an fd is
158 AT_FDCWD or real, whether a file is absolute or relative, coupled
159 with whether flag is set for 32 iterations.
160
161 To ensure that we test all of the code paths (rather than
162 triggering early normalization optimizations), we use a loop to
163 repeatedly rename a file in the parent directory, use an fd open
164 on subdirectory 1, all while executing in subdirectory 2; all
165 relative names are thus given with a leading "../". Finally, the
166 last scenario (two relative paths given, neither one AT_FDCWD)
167 has two paths, based on whether the two fds are equivalent, so we
168 do the other variant after the loop. */
169 for (i = 0; i < 32; i++)
170 {
171 int fd1 = (i & 8) ? dfd : AT_FDCWD;
172 char *file1 = mfile_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL);
173 int fd2 = (i & 2) ? dfd : AT_FDCWD;
174 char *file2 = mfile_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL);
175 ASSERT (file1);
176 ASSERT (file2);
177 flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0);
178
179 ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2);
180 ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2);
181 ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0);
182 ASSERT (unlinkat (fd1, file1, 0) == 0);
183 free (file1);
184 free (file2);
185 }
186 dfd2 = open ("..", O_RDONLY);
187 ASSERT (0 <= dfd2);
188 ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0);
189 ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34",
190 AT_SYMLINK_FOLLOW) == 0);
191 ASSERT (close (dfd2) == 0);
192
193 /* Now we change back to the parent directory, and set dfd to ".",
194 in order to test behavior on symlinks. */
195 ASSERT (chdir ("..") == 0);
196 ASSERT (close (dfd) == 0);
197 if (symlink (BASE "sub1", BASE "link1"))
198 {
199 ASSERT (unlink (BASE "32") == 0);
200 ASSERT (unlink (BASE "33") == 0);
201 ASSERT (unlink (BASE "34") == 0);
202 ASSERT (rmdir (BASE "sub1") == 0);
203 ASSERT (rmdir (BASE "sub2") == 0);
204 free (cwd);
205 if (!result)
206 fputs ("skipping test: symlinks not supported on this file system\n",
207 stderr);
208 return result;
209 }
210 dfd = open (".", O_RDONLY);
211 ASSERT (0 <= dfd);
212 ASSERT (symlink (BASE "34", BASE "link2") == 0);
213 ASSERT (symlink (BASE "link3", BASE "link3") == 0);
214 ASSERT (symlink (BASE "nowhere", BASE "link4") == 0);
215
216 /* Link cannot overwrite existing files. */
217 errno = 0;
218 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1);
219 ASSERT (errno == EEXIST);
220 errno = 0;
221 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1);
222 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
223 errno = 0;
224 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1);
225 ASSERT (errno == EEXIST || errno == ENOTDIR);
226 errno = 0;
227 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1",
228 AT_SYMLINK_FOLLOW) == -1);
229 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
230 errno = 0;
231 ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1",
232 AT_SYMLINK_FOLLOW) == -1);
233 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
234 || errno == EINVAL);
235 errno = 0;
236 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/",
237 AT_SYMLINK_FOLLOW) == -1);
238 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
239 || errno == EINVAL);
240 errno = 0;
241 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1);
242 ASSERT (errno == EEXIST);
243 errno = 0;
244 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2",
245 AT_SYMLINK_FOLLOW) == -1);
246 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
247 errno = 0;
248 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1);
249 ASSERT (errno == EEXIST || errno == ELOOP);
250 errno = 0;
251 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3",
252 AT_SYMLINK_FOLLOW) == -1);
253 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES
254 || errno == ELOOP);
255 errno = 0;
256 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1);
257 ASSERT (errno == EEXIST || errno == ELOOP);
258 errno = 0;
259 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3",
260 AT_SYMLINK_FOLLOW) == -1);
261 ASSERT (errno == EEXIST || errno == ELOOP);
262
263 /* AT_SYMLINK_FOLLOW only follows first argument, not second. */
264 errno = 0;
265 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1);
266 ASSERT (errno == EEXIST);
267 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4",
268 AT_SYMLINK_FOLLOW) == -1);
269 ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES);
270 errno = 0;
271 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1);
272 ASSERT (errno == EEXIST);
273 errno = 0;
274 ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1);
275 ASSERT (errno == EEXIST);
276
277 /* Trailing slash handling. */
278 errno = 0;
279 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1);
280 ASSERT (errno == ENOTDIR);
281 errno = 0;
282 ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5",
283 AT_SYMLINK_FOLLOW) == -1);
284 ASSERT (errno == ENOTDIR || errno == EINVAL);
285 errno = 0;
286 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1);
287 ASSERT (errno == ELOOP);
288 errno = 0;
289 ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5",
290 AT_SYMLINK_FOLLOW) == -1);
291 ASSERT (errno == ELOOP || errno == EINVAL);
292 errno = 0;
293 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1);
294 ASSERT (errno == ENOENT);
295 errno = 0;
296 ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5",
297 AT_SYMLINK_FOLLOW) == -1);
298 ASSERT (errno == ENOENT || errno == EINVAL);
299
300 /* Check for hard links to symlinks. */
301 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0);
302 check_same_link (BASE "link1", BASE "link5");
303 ASSERT (unlink (BASE "link5") == 0);
304 errno = 0;
305 ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5",
306 AT_SYMLINK_FOLLOW) == -1);
307 ASSERT (errno == EPERM || errno == EACCES);
308 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0);
309 check_same_link (BASE "link2", BASE "link5");
310 ASSERT (unlink (BASE "link5") == 0);
311 ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
312 errno = 0;
313 ASSERT (areadlink (BASE "file") == NULL);
314 ASSERT (errno == EINVAL);
315 ASSERT (unlink (BASE "file") == 0);
316 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0);
317 check_same_link (BASE "link3", BASE "link5");
318 ASSERT (unlink (BASE "link5") == 0);
319 errno = 0;
320 ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5",
321 AT_SYMLINK_FOLLOW) == -1);
322 ASSERT (errno == ELOOP);
323 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0);
324 check_same_link (BASE "link4", BASE "link5");
325 ASSERT (unlink (BASE "link5") == 0);
326 errno = 0;
327 ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5",
328 AT_SYMLINK_FOLLOW) == -1);
329 ASSERT (errno == ENOENT);
330
331 /* Check that symlink to symlink to file is followed all the way. */
332 ASSERT (symlink (BASE "link2", BASE "link5") == 0);
333 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0);
334 check_same_link (BASE "link5", BASE "link6");
335 ASSERT (unlink (BASE "link6") == 0);
336 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0);
337 errno = 0;
338 ASSERT (areadlink (BASE "file") == NULL);
339 ASSERT (errno == EINVAL);
340 ASSERT (unlink (BASE "file") == 0);
341 ASSERT (unlink (BASE "link5") == 0);
342 ASSERT (symlink (BASE "link3", BASE "link5") == 0);
343 errno = 0;
344 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
345 AT_SYMLINK_FOLLOW) == -1);
346 ASSERT (errno == ELOOP);
347 ASSERT (unlink (BASE "link5") == 0);
348 ASSERT (symlink (BASE "link4", BASE "link5") == 0);
349 errno = 0;
350 ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file",
351 AT_SYMLINK_FOLLOW) == -1);
352 ASSERT (errno == ENOENT);
353
354 /* Now for some real fun with directory crossing. */
355 ASSERT (symlink (cwd, BASE "sub1/link") == 0);
356 ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2",
357 BASE "sub2/link") == 0);
358 ASSERT (close (dfd) == 0);
359 dfd = open (BASE "sub1", O_RDONLY);
360 ASSERT (0 <= dfd);
361 dfd2 = open (BASE "sub2", O_RDONLY);
362 ASSERT (0 < dfd2);
363 ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file",
364 AT_SYMLINK_FOLLOW) == 0);
365 errno = 0;
366 ASSERT (areadlink (BASE "sub1/file") == NULL);
367 ASSERT (errno == EINVAL);
368
369 /* Cleanup. */
370 ASSERT (close (dfd) == 0);
371 ASSERT (close (dfd2) == 0);
372 ASSERT (unlink (BASE "sub1/file") == 0);
373 ASSERT (unlink (BASE "sub1/link") == 0);
374 ASSERT (unlink (BASE "sub2/link") == 0);
375 ASSERT (unlink (BASE "32") == 0);
376 ASSERT (unlink (BASE "33") == 0);
377 ASSERT (unlink (BASE "34") == 0);
378 ASSERT (rmdir (BASE "sub1") == 0);
379 ASSERT (rmdir (BASE "sub2") == 0);
380 ASSERT (unlink (BASE "link1") == 0);
381 ASSERT (unlink (BASE "link2") == 0);
382 ASSERT (unlink (BASE "link3") == 0);
383 ASSERT (unlink (BASE "link4") == 0);
384 ASSERT (unlink (BASE "link5") == 0);
385 free (cwd);
386 return result;
387 }