]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/uclibc/lib/contrib/uclibc/libc/stdlib/realpath.c
Update
[l4.git] / l4 / pkg / l4re-core / uclibc / lib / contrib / uclibc / libc / stdlib / realpath.c
1 /*
2  * realpath.c -- canonicalize pathname by removing symlinks
3  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
4  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
5  *
6  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <sys/types.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <limits.h>                             /* for PATH_MAX */
18 #include <sys/param.h>                  /* for MAXPATHLEN */
19 #include <errno.h>
20 #include <stdlib.h>
21
22 #include <sys/stat.h>                   /* for S_IFLNK */
23
24
25 #ifndef PATH_MAX
26 #ifdef _POSIX_VERSION
27 #define PATH_MAX _POSIX_PATH_MAX
28 #else
29 #ifdef MAXPATHLEN
30 #define PATH_MAX MAXPATHLEN
31 #else
32 #define PATH_MAX 1024
33 #endif
34 #endif
35 #endif
36
37 #define MAX_READLINKS 32
38
39 char *realpath(const char *path, char got_path[])
40 {
41         char copy_path[PATH_MAX];
42         char *max_path, *new_path, *allocated_path;
43         size_t path_len;
44         int readlinks = 0;
45 #ifdef S_IFLNK
46         int link_len;
47 #endif
48
49         if (path == NULL) {
50                 __set_errno(EINVAL);
51                 return NULL;
52         }
53         if (*path == '\0') {
54                 __set_errno(ENOENT);
55                 return NULL;
56         }
57         /* Make a copy of the source path since we may need to modify it. */
58         path_len = strlen(path);
59         if (path_len >= PATH_MAX - 2) {
60                 __set_errno(ENAMETOOLONG);
61                 return NULL;
62         }
63         /* Copy so that path is at the end of copy_path[] */
64         strcpy(copy_path + (PATH_MAX-1) - path_len, path);
65         path = copy_path + (PATH_MAX-1) - path_len;
66         allocated_path = got_path ? NULL : (got_path = malloc(PATH_MAX));
67         max_path = got_path + PATH_MAX - 2; /* points to last non-NUL char */
68         new_path = got_path;
69         if (*path != '/') {
70                 /* If it's a relative pathname use getcwd for starters. */
71                 if (!getcwd(new_path, PATH_MAX - 1))
72                         goto err;
73                 new_path += strlen(new_path);
74                 if (new_path[-1] != '/')
75                         *new_path++ = '/';
76         } else {
77                 *new_path++ = '/';
78                 path++;
79         }
80         /* Expand each slash-separated pathname component. */
81         while (*path != '\0') {
82                 /* Ignore stray "/". */
83                 if (*path == '/') {
84                         path++;
85                         continue;
86                 }
87                 if (*path == '.') {
88                         /* Ignore ".". */
89                         if (path[1] == '\0' || path[1] == '/') {
90                                 path++;
91                                 continue;
92                         }
93                         if (path[1] == '.') {
94                                 if (path[2] == '\0' || path[2] == '/') {
95                                         path += 2;
96                                         /* Ignore ".." at root. */
97                                         if (new_path == got_path + 1)
98                                                 continue;
99                                         /* Handle ".." by backing up. */
100                                         while ((--new_path)[-1] != '/');
101                                         continue;
102                                 }
103                         }
104                 }
105                 /* Safely copy the next pathname component. */
106                 while (*path != '\0' && *path != '/') {
107                         if (new_path > max_path) {
108                                 __set_errno(ENAMETOOLONG);
109  err:
110                                 free(allocated_path);
111                                 return NULL;
112                         }
113                         *new_path++ = *path++;
114                 }
115 #ifdef S_IFLNK
116                 /* Protect against infinite loops. */
117                 if (readlinks++ > MAX_READLINKS) {
118                         __set_errno(ELOOP);
119                         goto err;
120                 }
121                 path_len = strlen(path);
122                 /* See if last (so far) pathname component is a symlink. */
123                 *new_path = '\0';
124                 {
125                         int sv_errno = errno;
126                         link_len = readlink(got_path, copy_path, PATH_MAX - 1);
127                         if (link_len < 0) {
128                                 /* EINVAL means the file exists but isn't a symlink. */
129                                 if (errno != EINVAL) {
130                                         goto err;
131                                 }
132                         } else {
133                                 /* Safe sex check. */
134                                 if (path_len + link_len >= PATH_MAX - 2) {
135                                         __set_errno(ENAMETOOLONG);
136                                         goto err;
137                                 }
138                                 /* Note: readlink doesn't add the null byte. */
139                                 /* copy_path[link_len] = '\0'; - we don't need it too */
140                                 if (*copy_path == '/')
141                                         /* Start over for an absolute symlink. */
142                                         new_path = got_path;
143                                 else
144                                         /* Otherwise back up over this component. */
145                                         while (*(--new_path) != '/');
146                                 /* Prepend symlink contents to path. */
147                                 memmove(copy_path + (PATH_MAX-1) - link_len - path_len, copy_path, link_len);
148                                 path = copy_path + (PATH_MAX-1) - link_len - path_len;
149                         }
150                         __set_errno(sv_errno);
151                 }
152 #endif                                                  /* S_IFLNK */
153                 *new_path++ = '/';
154         }
155         /* Delete trailing slash but don't whomp a lone slash. */
156         if (new_path != got_path + 1 && new_path[-1] == '/')
157                 new_path--;
158         /* Make sure it's null terminated. */
159         *new_path = '\0';
160         return got_path;
161 }
162 libc_hidden_def(realpath)