usleep tests: Avoid failure due to known Cygwin 3.5.3 bug.
[gnulib.git] / tests / test-link.h
blob3e88f5e6e0aea7f8ac5430466eeb23d9c9bdc973
1 /* Test of link() function.
2 Copyright (C) 2009-2024 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 /* This file is designed to test both link(a,b) and
18 linkat(AT_FDCWD,a,AT_FDCWD,b,0). FUNC is the function to test.
19 Assumes that BASE and ASSERT are already defined, and that
20 appropriate headers are already included. If PRINT, warn before
21 skipping tests with status 77. This test does not try to create
22 hard links to symlinks, but does test other aspects of symlink. */
24 static int
25 test_link (int (*func) (char const *, char const *), bool print)
27 int fd;
28 int ret;
30 /* Create first file. */
31 fd = open (BASE "a", O_CREAT | O_EXCL | O_WRONLY, 0600);
32 ASSERT (0 <= fd);
33 ASSERT (write (fd, "hello", 5) == 5);
34 ASSERT (close (fd) == 0);
36 /* Not all file systems support link. Mingw doesn't have reliable
37 st_nlink on hard links, but our implementation does fail with
38 EPERM on poor file systems, and we can detect the inferior stat()
39 via st_ino. Cygwin 1.5.x copies rather than links files on those
40 file systems, but there, st_nlink and st_ino are reliable. */
41 ret = func (BASE "a", BASE "b");
42 if (!ret)
44 struct stat st;
45 ASSERT (stat (BASE "b", &st) == 0);
46 if (st.st_ino && st.st_nlink != 2)
48 ASSERT (unlink (BASE "b") == 0);
49 errno = EPERM;
50 ret = -1;
53 if (ret == -1)
55 /* If the device does not support hard links, errno is
56 EPERM on Linux,
57 EOPNOTSUPP on FreeBSD,
58 EACCES on Android within Termux. */
59 switch (errno)
61 case EPERM:
62 case EOPNOTSUPP:
63 #if defined __ANDROID__
64 case EACCES:
65 #endif
66 if (print)
67 fputs ("skipping test: "
68 "hard links not supported on this file system\n",
69 stderr);
70 ASSERT (unlink (BASE "a") == 0);
71 return 77;
72 default:
73 perror ("link");
74 return 1;
77 ASSERT (ret == 0);
79 /* Now, for some behavior tests. Modify the contents of 'b', and
80 ensure that 'a' can see it, both while 'b' exists and after. */
81 fd = open (BASE "b", O_APPEND | O_WRONLY);
82 ASSERT (0 <= fd);
83 ASSERT (write (fd, "world", 5) == 5);
84 ASSERT (close (fd) == 0);
86 char buf[11] = { 0 };
87 fd = open (BASE "a", O_RDONLY);
88 ASSERT (0 <= fd);
89 ASSERT (read (fd, buf, 10) == 10);
90 ASSERT (strcmp (buf, "helloworld") == 0);
91 ASSERT (close (fd) == 0);
92 ASSERT (unlink (BASE "b") == 0);
93 fd = open (BASE "a", O_RDONLY);
94 ASSERT (0 <= fd);
95 ASSERT (read (fd, buf, 10) == 10);
96 ASSERT (strcmp (buf, "helloworld") == 0);
97 ASSERT (close (fd) == 0);
100 /* Test for various error conditions. */
101 ASSERT (mkdir (BASE "d", 0700) == 0);
102 errno = 0;
103 ASSERT (func (BASE "a", ".") == -1);
104 ASSERT (errno == EEXIST || errno == EINVAL);
105 errno = 0;
106 ASSERT (func (BASE "a", BASE "a") == -1);
107 ASSERT (errno == EEXIST);
108 ASSERT (func (BASE "a", BASE "b") == 0);
109 errno = 0;
110 ASSERT (func (BASE "a", BASE "b") == -1);
111 ASSERT (errno == EEXIST);
112 errno = 0;
113 ASSERT (func (BASE "a", BASE "d") == -1);
114 ASSERT (errno == EEXIST);
115 errno = 0;
116 ASSERT (func (BASE "c", BASE "e") == -1);
117 ASSERT (errno == ENOENT);
118 errno = 0;
119 ASSERT (func (BASE "a", BASE "c/.") == -1);
120 ASSERT (errno == ENOENT);
121 errno = 0;
122 ASSERT (func (BASE "a/", BASE "c") == -1);
123 ASSERT (errno == ENOTDIR || errno == EINVAL);
124 errno = 0;
125 ASSERT (func (BASE "a", BASE "c/") == -1);
126 ASSERT (errno == ENOTDIR || errno == ENOENT || errno == EINVAL);
128 /* Most platforms reject hard links to directories, and even on
129 those that do permit it, most users can't create them. We assume
130 that if this test is run as root and we managed to create a hard
131 link, then unlink better be able to clean it up. */
133 int result;
134 errno = 0;
135 result = func (BASE "d", BASE "c");
136 if (result == 0)
138 /* Probably root on Solaris. */
139 ASSERT (unlink (BASE "c") == 0);
141 else
143 /* Most everyone else. */
144 ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR);
145 errno = 0;
146 ASSERT (func (BASE "d/.", BASE "c") == -1);
147 ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR
148 || errno == EINVAL);
149 errno = 0;
150 ASSERT (func (BASE "d/.//", BASE "c") == -1);
151 ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR
152 || errno == EINVAL);
155 ASSERT (unlink (BASE "a") == 0);
156 errno = 0;
157 ASSERT (unlink (BASE "c") == -1);
158 ASSERT (errno == ENOENT);
159 ASSERT (rmdir (BASE "d") == 0);
161 /* Test invalid use of symlink. */
162 if (symlink (BASE "a", BASE "link") != 0)
164 ASSERT (unlink (BASE "b") == 0);
165 if (print)
166 fputs ("skipping test: symlinks not supported on this file system\n",
167 stderr);
168 return 77;
170 errno = 0;
171 ASSERT (func (BASE "b", BASE "link/") == -1);
172 ASSERT (errno == ENOTDIR || errno == ENOENT || errno == EEXIST
173 || errno == EINVAL);
174 errno = 0;
175 ASSERT (func (BASE "b", BASE "link") == -1);
176 ASSERT (errno == EEXIST);
177 ASSERT (rename (BASE "b", BASE "a") == 0);
178 errno = 0;
179 ASSERT (func (BASE "link/", BASE "b") == -1);
180 ASSERT (errno == ENOTDIR || errno == EEXIST || errno == EINVAL);
182 /* Clean up. */
183 ASSERT (unlink (BASE "a") == 0);
184 ASSERT (unlink (BASE "link") == 0);
186 return 0;