64-bit VFS_LSEEK_OFF
[minix3.git] / test / test43.c
blob9ca30010166db9246f2fb75571a898d9c475e5c7
1 /* Tests for MINIX3 realpath(3) - by Erik van der Kouwe */
2 #include <assert.h>
3 #include <dirent.h>
4 #include <errno.h>
5 #include <libgen.h>
6 #include <limits.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
13 int max_error = 3;
14 #include "common.h"
17 int subtest;
18 static const char *executable;
21 #define ERR (e(__LINE__))
23 static char *remove_last_path_component(char *path)
25 char *current, *last;
27 assert(path);
29 /* find last slash */
30 last = NULL;
31 for (current = path; *current; current++)
32 if (*current == '/')
33 last = current;
35 /* check path component */
36 if (last)
38 if (strcmp(last + 1, ".") == 0) ERR;
39 if (strcmp(last + 1, "..") == 0) ERR;
42 /* if only root path slash, we are done */
43 if (last <= path)
44 return NULL;
46 /* chop off last path component */
47 *last = 0;
48 return path;
51 static int check_path_components(const char *path)
53 char buffer[PATH_MAX + 1], *bufferpos;
54 struct stat statbuf;
56 assert(strlen(path) < sizeof(buffer));
58 bufferpos = buffer;
59 while (*path)
61 /* copy next path segment */
62 do
64 *(bufferpos++) = *(path++);
65 } while (*path && *path != '/');
66 *bufferpos = 0;
68 /*
69 * is this a valid path segment? if not, return errno.
70 * one exception: the last path component need not exist
71 * - unless it is actually a dangling symlink
73 if (stat(buffer, &statbuf) < 0 &&
74 (*path || errno != ENOENT ||
75 lstat(buffer, &statbuf) == 0))
76 return errno;
79 return 0;
82 static void check_realpath(const char *path, int expected_errno)
84 char buffer[PATH_MAX + 1], *resolved_path;
85 int expected_errno2;
86 struct stat statbuf[2];
88 assert(path);
90 /* any errors in the path that realpath should report? */
91 expected_errno2 = check_path_components(path);
93 /* run realpath */
94 errno = 0;
95 resolved_path = realpath(path, buffer);
97 /* do we get errors when expected? */
98 if (expected_errno || expected_errno2)
100 if (resolved_path) ERR;
101 if (errno != expected_errno && errno != expected_errno2) ERR;
102 return;
105 /* do we get success when expected? */
106 if (!resolved_path)
108 ERR;
109 return;
111 errno = 0;
113 /* do the paths point to the same file? (only check if exists) */
114 if (stat(path, &statbuf[0]) < 0)
116 if (errno != ENOENT) { ERR; return; }
118 else
120 if (stat(resolved_path, &statbuf[1]) < 0) { ERR; return; }
121 if (statbuf[0].st_dev != statbuf[1].st_dev) ERR;
122 if (statbuf[0].st_ino != statbuf[1].st_ino) ERR;
125 /* is the path absolute? */
126 if (resolved_path[0] != '/') ERR;
128 /* is each path element allowable? */
129 while (remove_last_path_component(resolved_path))
131 /* not a symlink? */
132 if (lstat(resolved_path, &statbuf[1]) < 0) { ERR; return; }
133 if ((statbuf[1].st_mode & S_IFMT) != S_IFDIR) ERR;
137 static void check_realpath_step_by_step(const char *path, int expected_errno)
139 char buffer[PATH_MAX + 1];
140 const char *path_current;
142 assert(path);
143 assert(strlen(path) < sizeof(buffer));
145 /* check the absolute path */
146 check_realpath(path, expected_errno);
148 /* try with different CWDs */
149 for (path_current = path; *path_current; path_current++)
150 if (path_current[0] == '/' && path_current[1])
152 /* set CWD */
153 memcpy(buffer, path, path_current - path + 1);
154 buffer[path_current - path + 1] = 0;
155 if (chdir(buffer) < 0) { ERR; continue; }
157 /* perform test */
158 check_realpath(path_current + 1, expected_errno);
162 static char *pathncat(char *buffer, size_t size, const char *path1, const char *path2)
164 size_t len1, len2, lenslash;
166 assert(buffer);
167 assert(path1);
168 assert(path2);
170 /* check whether it fits */
171 len1 = strlen(path1);
172 len2 = strlen(path2);
173 lenslash = (len1 > 0 && path1[len1 - 1] == '/') ? 0 : 1;
174 if (len1 >= size || /* check individual components to avoid overflow */
175 len2 >= size ||
176 len1 + len2 + lenslash >= size)
177 return NULL;
179 /* perform the copy */
180 memcpy(buffer, path1, len1);
181 if (lenslash)
182 buffer[len1] = '/';
184 memcpy(buffer + len1 + lenslash, path2, len2 + 1);
185 return buffer;
188 static void check_realpath_recurse(const char *path, int depth)
190 DIR *dir;
191 struct dirent *dirent;
192 char pathsub[PATH_MAX + 1];
193 struct stat st;
195 /* check with the path itself */
196 check_realpath_step_by_step(path, 0);
198 /* don't go too deep */
199 if (depth < 1)
200 return;
202 /* don't bother with non-directories. Due to timeouts in drivers we
203 * might not get expected results and takes way too long */
204 if (stat(path, &st) != 0) {
205 /* dangling symlinks may cause legitimate failures here */
206 if (lstat(path, &st) != 0) ERR;
207 return;
209 if (!S_ISDIR(st.st_mode))
210 return;
212 /* loop through subdirectories (including . and ..) */
213 if (!(dir = opendir(path)))
215 /* Opening some special files might result in errors when the
216 * corresponding hardware is not present, or simply when access
217 * rights prohibit access (e.g., /dev/log).
219 if (errno != ENOTDIR
220 && errno != ENXIO && errno != EIO && errno != EACCES) {
221 ERR;
223 return;
225 while ((dirent = readdir(dir)) != NULL)
227 /* build path */
228 if (!pathncat(pathsub, sizeof(pathsub), path, dirent->d_name))
230 ERR;
231 continue;
234 /* check path */
235 check_realpath_recurse(pathsub, depth - 1);
237 if (closedir(dir) < 0) ERR;
240 #define PATH_DEPTH 4
241 #define PATH_BASE "/."
242 #define L(x) PATH_BASE "/link_" #x ".tmp"
244 static char basepath[PATH_MAX + 1];
246 static char *addbasepath(char *buffer, const char *path)
248 size_t basepathlen, pathlen;
250 /* assumption: both start with slash and neither end with it */
251 assert(basepath[0] == '/');
252 assert(basepath[strlen(basepath) - 1] != '/');
253 assert(buffer);
254 assert(path);
255 assert(path[0] == '/');
257 /* check result length */
258 basepathlen = strlen(basepath);
259 pathlen = strlen(path);
260 if (basepathlen + pathlen > PATH_MAX)
262 printf("path too long\n");
263 exit(-1);
266 /* concatenate base path and path */
267 memcpy(buffer, basepath, basepathlen);
268 memcpy(buffer + basepathlen, path, pathlen + 1);
269 return buffer;
272 static void test_dirname(const char *path, const char *exp)
274 char buffer[PATH_MAX];
275 int i, j;
276 size_t pathlen = strlen(path);
277 char *pathout;
279 assert(pathlen + 3 < PATH_MAX);
281 /* try with no, one or two trailing slashes */
282 for (i = 0; i < 3; i++)
284 /* no trailing slashes for empty string */
285 if (pathlen < 1 && i > 0)
286 continue;
288 /* prepare buffer */
289 strcpy(buffer, path);
290 for (j = 0; j < i; j++)
291 buffer[pathlen + j] = '/';
293 buffer[pathlen + i] = 0;
295 /* perform test */
296 pathout = dirname(buffer);
297 if (strcmp(pathout, exp) != 0)
298 ERR;
302 int main(int argc, char **argv)
304 char buffer1[PATH_MAX + 1], buffer2[PATH_MAX + 1];
305 subtest = 1;
307 /* initialize */
308 start(43);
309 executable = argv[0];
310 getcwd(basepath, sizeof(basepath));
312 /* prepare some symlinks to make it more difficult */
313 if (symlink("/", addbasepath(buffer1, L(1))) < 0) ERR;
314 if (symlink(basepath, addbasepath(buffer1, L(2))) < 0) ERR;
316 /* perform some tests */
317 check_realpath_recurse(basepath, PATH_DEPTH);
319 /* now try with recursive symlinks */
320 if (symlink(addbasepath(buffer1, L(3)), addbasepath(buffer2, L(3))) < 0) ERR;
321 if (symlink(addbasepath(buffer1, L(5)), addbasepath(buffer2, L(4))) < 0) ERR;
322 if (symlink(addbasepath(buffer1, L(4)), addbasepath(buffer2, L(5))) < 0) ERR;
323 check_realpath_step_by_step(addbasepath(buffer1, L(3)), ELOOP);
324 check_realpath_step_by_step(addbasepath(buffer1, L(4)), ELOOP);
325 check_realpath_step_by_step(addbasepath(buffer1, L(5)), ELOOP);
327 /* delete the symlinks */
328 cleanup();
330 /* also test dirname */
331 test_dirname("", ".");
332 test_dirname(".", ".");
333 test_dirname("..", ".");
334 test_dirname("x", ".");
335 test_dirname("xy", ".");
336 test_dirname("x/y", "x");
337 test_dirname("xy/z", "xy");
338 test_dirname("x/yz", "x");
339 test_dirname("ab/cd", "ab");
340 test_dirname("x//y", "x");
341 test_dirname("xy//z", "xy");
342 test_dirname("x//yz", "x");
343 test_dirname("ab//cd", "ab");
344 test_dirname("/", "/");
345 test_dirname("/x", "/");
346 test_dirname("/xy", "/");
347 test_dirname("/x/y", "/x");
348 test_dirname("/xy/z", "/xy");
349 test_dirname("/x/yz", "/x");
350 test_dirname("/ab/cd", "/ab");
351 test_dirname("/x//y", "/x");
352 test_dirname("/xy//z", "/xy");
353 test_dirname("/x//yz", "/x");
354 test_dirname("/ab//cd", "/ab");
355 test_dirname("/usr/src", "/usr");
356 test_dirname("/usr/src/test", "/usr/src");
357 test_dirname("usr/src", "usr");
358 test_dirname("usr/src/test", "usr/src");
360 /* done */
361 quit();
362 return(-1); /* impossible */