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