1:
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
29:
30: #include <sys/param.h>
31: #include <sys/stat.h>
32:
33: #include <errno.h>
34: #include <stdlib.h>
35: #include <string.h>
36: #include <unistd.h>
37:
38: 39: 40: 41: 42: 43: 44:
45: char *
46: realpath2_eno(const char *path1, const char *path, char *resolved, int *eno)
47: {
48:
49: char *p, *q, *s;
50: size_t left_len, resolved_len;
51: unsigned symlinks;
52: int serrno, mem_allocated;
53: char left[PATH_MAX], next_token[PATH_MAX];
54:
55: if (path[0] == '\0') {
56: serrno = ENOENT;
57: goto e1;
58: }
59:
60:
61:
62: if (resolved == NULL) {
63: resolved = malloc(PATH_MAX);
64: if (resolved == NULL)
65: { serrno = ENOMEM; goto e1; }
66: mem_allocated = 1;
67: } else
68: mem_allocated = 0;
69:
70: symlinks = 0;
71: if (path[0] == '/') {
72: resolved[0] = '/';
73: resolved[1] = '\0';
74: if (path[1] == '\0')
75: return (resolved);
76: resolved_len = 1;
77: left_len = strlcpy(left, path + 1, sizeof(left));
78: } else {
79: if ((serrno = (path1 != NULL ? (realpath2_eno(NULL, path1, resolved, eno) != NULL ? 0 : *eno) : __libc_getcwd(resolved, PATH_MAX) & 0xffff)) != 0) {
80: if (mem_allocated)
81: free(resolved);
82: else
83: strlcpy(resolved, ".", PATH_MAX);
84: goto e1;
85: }
86: resolved_len = strlen(resolved);
87: left_len = strlcpy(left, path, sizeof(left));
88: }
89: if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
90: serrno = ENAMETOOLONG;
91: goto err;
92: }
93:
94: 95: 96:
97: while (left_len != 0) {
98: 99: 100: 101:
102: p = strchr(left, '/');
103: s = p ? p : left + left_len;
104: if (s - left >= sizeof(next_token)) {
105: serrno = ENAMETOOLONG;
106: goto err;
107: }
108: memcpy(next_token, left, s - left);
109: next_token[s - left] = '\0';
110: left_len -= s - left;
111: if (p != NULL)
112: memmove(left, s + 1, left_len + 1);
113: if (resolved[resolved_len - 1] != '/') {
114: if (resolved_len + 1 >= PATH_MAX) {
115: serrno = ENAMETOOLONG;
116: goto err;
117: }
118: resolved[resolved_len++] = '/';
119: resolved[resolved_len] = '\0';
120: }
121: if (next_token[0] == '\0')
122: continue;
123: else if (strcmp(next_token, ".") == 0)
124: continue;
125: else if (strcmp(next_token, "..") == 0) {
126: 127: 128: 129:
130: if (resolved_len > 1) {
131: resolved[resolved_len - 1] = '\0';
132: q = strrchr(resolved, '/') + 1;
133: *q = '\0';
134: resolved_len = q - resolved;
135: }
136: continue;
137: }
138:
139: 140: 141: 142: 143:
144: resolved_len = strlcat(resolved, next_token, PATH_MAX);
145: if (resolved_len >= PATH_MAX) {
146: serrno = ENAMETOOLONG;
147: goto err;}
148: #if 0
149: if (lstat(resolved, &sb) != 0) {
150: if (errno == ENOENT && p == NULL) {
151: errno = serrno;
152: return (resolved);
153: }
154: goto err;
155: }
156: if (S_ISLNK(sb.st_mode)) {
157: if (symlinks++ > MAXSYMLINKS) {
158: serrno = ELOOP;
159: goto err;
160: }
161: slen = readlink(resolved, symlink, sizeof(symlink) - 1);
162: if (slen < 0)
163: goto err;
164: symlink[slen] = '\0';
165: if (symlink[0] == '/') {
166: resolved[1] = 0;
167: resolved_len = 1;
168: } else if (resolved_len > 1) {
169:
170: resolved[resolved_len - 1] = '\0';
171: q = strrchr(resolved, '/') + 1;
172: *q = '\0';
173: resolved_len = q - resolved;
174: }
175:
176: 177: 178: 179: 180:
181: if (p != NULL) {
182: if (symlink[slen - 1] != '/') {
183: if (slen + 1 >= sizeof(symlink)) {
184: serrno = ENAMETOOLONG;
185: goto err;
186: }
187: symlink[slen] = '/';
188: symlink[slen + 1] = 0;
189: }
190: left_len = strlcat(symlink, left, sizeof(left));
191: if (left_len >= sizeof(left)) {
192: serrno = ENAMETOOLONG;
193: goto err;
194: }
195: }
196: left_len = strlcpy(left, symlink, sizeof(left));}
197: #endif
198: }
199:
200: 201: 202: 203:
204: if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
205: resolved[resolved_len - 1] = '\0';
206: return (resolved);
207:
208: err:
209: if (mem_allocated)
210: free(resolved);
211: e1: if (eno) *eno = serrno; return NULL;
212: } char *realpath2(const char *path1, const char *path2, char *resolved){return realpath2_eno(path1, path2, resolved, NULL);} char *realpath_eno(const char *path, char *resolved, int *eno){return realpath2_eno(NULL, path, resolved, eno);} char *realpath(const char *path, char *resolved){return realpath_eno(path, resolved, NULL);}