1 | /* Test program for returning the canonical absolute name of a given file. |
2 | Copyright (C) 1996-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | /* This file must be run from within a directory called "stdlib". */ |
20 | |
21 | #include <errno.h> |
22 | #include <fcntl.h> |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | #include <unistd.h> |
27 | #include <sys/param.h> |
28 | #include <sys/stat.h> |
29 | |
30 | #include <support/xunistd.h> |
31 | |
32 | /* Prototype for our test function. */ |
33 | extern int do_test (int argc, char *argv[]); |
34 | #include <test-skeleton.c> |
35 | |
36 | #ifndef PATH_MAX |
37 | # define PATH_MAX 4096 |
38 | #endif |
39 | static char cwd[PATH_MAX]; |
40 | static size_t cwd_len; |
41 | |
42 | struct { |
43 | const char * name; |
44 | const char * value; |
45 | } symlinks[] = { |
46 | {"SYMLINK_LOOP" , "SYMLINK_LOOP" }, |
47 | {"SYMLINK_1" , "." }, |
48 | {"SYMLINK_2" , "//////./../../etc" }, |
49 | {"SYMLINK_3" , "SYMLINK_1" }, |
50 | {"SYMLINK_4" , "SYMLINK_2" }, |
51 | {"SYMLINK_5" , "doesNotExist" }, |
52 | }; |
53 | |
54 | struct { |
55 | const char * in, * out, * resolved; |
56 | int error; |
57 | } tests[] = { |
58 | /* 0 */ |
59 | {"/" , "/" }, |
60 | {"/////////////////////////////////" , "/" }, |
61 | {"/.././.././.././..///" , "/" }, |
62 | {"/etc" , "/etc" }, |
63 | {"/etc/../etc" , "/etc" }, |
64 | /* 5 */ |
65 | {"/doesNotExist/../etc" , 0, "/doesNotExist" , ENOENT}, |
66 | {"./././././././././." , "." }, |
67 | {"/etc/.//doesNotExist" , 0, "/etc/doesNotExist" , ENOENT}, |
68 | {"./doesExist" , "./doesExist" }, |
69 | {"./doesExist/" , "./doesExist" }, |
70 | /* 10 */ |
71 | {"./doesExist/../doesExist" , "./doesExist" }, |
72 | {"foobar" , 0, "./foobar" , ENOENT}, |
73 | {"." , "." }, |
74 | {"./foobar" , 0, "./foobar" , ENOENT}, |
75 | {"SYMLINK_LOOP" , 0, "./SYMLINK_LOOP" , ELOOP}, |
76 | /* 15 */ |
77 | {"./SYMLINK_LOOP" , 0, "./SYMLINK_LOOP" , ELOOP}, |
78 | {"SYMLINK_1" , "." }, |
79 | {"SYMLINK_1/foobar" , 0, "./foobar" , ENOENT}, |
80 | {"SYMLINK_2" , "/etc" }, |
81 | {"SYMLINK_3" , "." }, |
82 | /* 20 */ |
83 | {"SYMLINK_4" , "/etc" }, |
84 | {"../stdlib/SYMLINK_1" , "." }, |
85 | {"../stdlib/SYMLINK_2" , "/etc" }, |
86 | {"../stdlib/SYMLINK_3" , "." }, |
87 | {"../stdlib/SYMLINK_4" , "/etc" }, |
88 | /* 25 */ |
89 | {"./SYMLINK_5" , 0, "./doesNotExist" , ENOENT}, |
90 | {"SYMLINK_5" , 0, "./doesNotExist" , ENOENT}, |
91 | {"SYMLINK_5/foobar" , 0, "./doesNotExist" , ENOENT}, |
92 | {"doesExist/../../stdlib/doesExist" , "./doesExist" }, |
93 | {"doesExist/.././../stdlib/." , "." }, |
94 | /* 30 */ |
95 | {"./doesExist/someFile/" , 0, "./doesExist/someFile" , ENOTDIR}, |
96 | {"./doesExist/someFile/.." , 0, "./doesExist/someFile" , ENOTDIR}, |
97 | }; |
98 | |
99 | |
100 | static int |
101 | check_path (const char * result, const char * expected) |
102 | { |
103 | int good; |
104 | |
105 | if (!result) |
106 | return (expected == NULL); |
107 | |
108 | if (!expected) |
109 | return 0; |
110 | |
111 | if (expected[0] == '.' && (expected[1] == '/' || expected[1] == '\0')) |
112 | good = (strncmp (result, cwd, cwd_len) == 0 |
113 | && strcmp (result + cwd_len, expected + 1) == 0); |
114 | else |
115 | good = (strcmp (expected, result) == 0); |
116 | |
117 | return good; |
118 | } |
119 | |
120 | |
121 | int |
122 | do_test (int argc, char ** argv) |
123 | { |
124 | char * result; |
125 | int i, errors = 0; |
126 | char buf[PATH_MAX]; |
127 | |
128 | if (getcwd (buf: cwd, size: sizeof (buf))) |
129 | cwd_len = strlen (cwd); |
130 | else |
131 | { |
132 | printf (format: "%s: current working directory couldn't be retrieved\n" , argv[0]); |
133 | ++errors; |
134 | } |
135 | |
136 | errno = 0; |
137 | if (realpath (NULL, resolved: buf) != NULL || errno != EINVAL) |
138 | { |
139 | printf (format: "%s: expected return value NULL and errno set to EINVAL" |
140 | " for realpath(NULL,...)\n" , argv[0]); |
141 | ++errors; |
142 | } |
143 | |
144 | #if 0 |
145 | /* This is now allowed. The test is invalid. */ |
146 | errno = 0; |
147 | if (realpath ("/" , NULL) != NULL || errno != EINVAL) |
148 | { |
149 | printf ("%s: expected return value NULL and errno set to EINVAL" |
150 | " for realpath(...,NULL)\n" , argv[0]); |
151 | ++errors; |
152 | } |
153 | #endif |
154 | |
155 | errno = 0; |
156 | if (realpath (name: "" , resolved: buf) != NULL || errno != ENOENT) |
157 | { |
158 | printf (format: "%s: expected return value NULL and set errno to ENOENT" |
159 | " for realpath(\"\",...)\n" , argv[0]); |
160 | ++errors; |
161 | } |
162 | |
163 | for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i) |
164 | xsymlink (target: symlinks[i].value, linkpath: symlinks[i].name); |
165 | |
166 | int has_dir = mkdir (path: "doesExist" , mode: 0777) == 0; |
167 | |
168 | int fd = has_dir ? creat (file: "doesExist/someFile" , mode: 0777) : -1; |
169 | |
170 | for (i = 0; i < (int) (sizeof (tests) / sizeof (tests[0])); ++i) |
171 | { |
172 | buf[0] = '\0'; |
173 | result = realpath (name: tests[i].in, resolved: buf); |
174 | |
175 | if (!check_path (result, expected: tests[i].out)) |
176 | { |
177 | printf (format: "%s: flunked test %d (expected `%s', got `%s')\n" , |
178 | argv[0], i, tests[i].out ? tests[i].out : "NULL" , |
179 | result ? result : "NULL" ); |
180 | ++errors; |
181 | continue; |
182 | } |
183 | |
184 | /* Verify buf contents if the call succeeded or failed with ENOENT. */ |
185 | if ((result != NULL || errno == ENOENT) |
186 | && !check_path (result: buf, expected: tests[i].out ? tests[i].out : tests[i].resolved)) |
187 | { |
188 | printf (format: "%s: flunked test %d (expected resolved `%s', got `%s')\n" , |
189 | argv[0], i, tests[i].out ? tests[i].out : tests[i].resolved, |
190 | buf); |
191 | ++errors; |
192 | continue; |
193 | } |
194 | |
195 | if (!tests[i].out && errno != tests[i].error) |
196 | { |
197 | printf (format: "%s: flunked test %d (expected errno %d, got %d)\n" , |
198 | argv[0], i, tests[i].error, errno); |
199 | ++errors; |
200 | continue; |
201 | } |
202 | |
203 | char *result2 = realpath (name: tests[i].in, NULL); |
204 | if ((result2 == NULL && result != NULL) |
205 | || (result2 != NULL && strcmp (result, result2) != 0)) |
206 | { |
207 | printf (format: "\ |
208 | %s: realpath(..., NULL) produced different result than realpath(..., buf): '%s' vs '%s'\n" , |
209 | argv[0], result2, result); |
210 | ++errors; |
211 | } |
212 | free (ptr: result2); |
213 | } |
214 | |
215 | if (!getcwd (buf: buf, size: sizeof (buf))) |
216 | { |
217 | printf (format: "%s: current working directory couldn't be retrieved\n" , argv[0]); |
218 | ++errors; |
219 | } |
220 | |
221 | if (strcmp (buf, cwd)) |
222 | { |
223 | printf (format: "%s: current working directory changed from %s to %s\n" , |
224 | argv[0], cwd, buf); |
225 | ++errors; |
226 | } |
227 | |
228 | if (fd >= 0) |
229 | { |
230 | close (fd: fd); |
231 | unlink (name: "doesExist/someFile" ); |
232 | } |
233 | |
234 | if (has_dir) |
235 | rmdir (path: "doesExist" ); |
236 | |
237 | for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i) |
238 | unlink (name: symlinks[i].name); |
239 | |
240 | if (errors != 0) |
241 | { |
242 | printf (format: "%d errors.\n" , errors); |
243 | return EXIT_FAILURE; |
244 | } |
245 | |
246 | puts (s: "No errors." ); |
247 | return EXIT_SUCCESS; |
248 | } |
249 | |