1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: #include <config.h>
20:
21: #include "canonicalize.h"
22:
23: #include <stdlib.h>
24: #include <string.h>
25:
26: #if HAVE_SYS_PARAM_H
27: # include <sys/param.h>
28: #endif
29:
30: #include <sys/stat.h>
31:
32: #include <unistd.h>
33:
34: #include <errno.h>
35: #include <stddef.h>
36:
37: #include "cycle-check.h"
38: #include "filenamecat.h"
39: #include "xalloc.h"
40: #include "xgetcwd.h"
41:
42: #ifndef ELOOP
43: # define ELOOP 0
44: #endif
45: #ifndef __set_errno
46: # define __set_errno(Val) errno = (Val)
47: #endif
48:
49: #include "pathmax.h"
50: #include "xreadlink.h"
51:
52: #if !HAVE_CANONICALIZE_FILE_NAME
53:
54:
55:
56:
57:
58: char *
59: canonicalize_file_name (const char *name)
60: {
61: # if HAVE_RESOLVEPATH
62:
63: char *resolved, *extra_buf = NULL;
64: size_t resolved_size;
65: ssize_t resolved_len;
66:
67: if (name == NULL)
68: {
69: __set_errno (EINVAL);
70: return NULL;
71: }
72:
73: if (name[0] == '\0')
74: {
75: __set_errno (ENOENT);
76: return NULL;
77: }
78:
79:
80:
81:
82: if (name[0] != '/')
83: {
84: char *wd;
85:
86: if (!(wd = xgetcwd ()))
87: return NULL;
88:
89: extra_buf = file_name_concat (wd, name, NULL);
90: name = extra_buf;
91: free (wd);
92: }
93:
94: resolved_size = strlen (name);
95: while (1)
96: {
97: resolved_size = 2 * resolved_size + 1;
98: resolved = xmalloc (resolved_size);
99: resolved_len = resolvepath (name, resolved, resolved_size);
100: if (resolved_len < 0)
101: {
102: free (resolved);
103: free (extra_buf);
104: return NULL;
105: }
106: if (resolved_len < resolved_size)
107: break;
108: free (resolved);
109: }
110:
111: free (extra_buf);
112:
113:
114: resolved[resolved_len] = '\0';
115:
116: return resolved;
117:
118: # else
119:
120: return canonicalize_filename_mode (name, CAN_EXISTING);
121:
122: # endif
123: }
124: #endif
125:
126:
127:
128:
129:
130:
131: char *
132: canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
133: {
134: char *rname, *dest, *extra_buf = NULL;
135: char const *start;
136: char const *end;
137: char const *rname_limit;
138: size_t extra_len = 0;
139: struct cycle_check_state cycle_state;
140:
141: if (name == NULL)
142: {
143: __set_errno (EINVAL);
144: return NULL;
145: }
146:
147: if (name[0] == '\0')
148: {
149: __set_errno (ENOENT);
150: return NULL;
151: }
152:
153: if (name[0] != '/')
154: {
155: rname = xgetcwd ();
156: if (!rname)
157: return NULL;
158: dest = strchr (rname, '\0');
159: if (dest - rname < PATH_MAX)
160: {
161: char *p = xrealloc (rname, PATH_MAX);
162: dest = p + (dest - rname);
163: rname = p;
164: rname_limit = rname + PATH_MAX;
165: }
166: else
167: {
168: rname_limit = dest;
169: }
170: }
171: else
172: {
173: rname = xmalloc (PATH_MAX);
174: rname_limit = rname + PATH_MAX;
175: rname[0] = '/';
176: dest = rname + 1;
177: }
178:
179: cycle_check_init (&cycle_state);
180: for (start = end = name; *start; start = end)
181: {
182:
183: while (*start == '/')
184: ++start;
185:
186:
187: for (end = start; *end && *end != '/'; ++end)
188: ;
189:
190: if (end - start == 0)
191: break;
192: else if (end - start == 1 && start[0] == '.')
193: ;
194: else if (end - start == 2 && start[0] == '.' && start[1] == '.')
195: {
196:
197: if (dest > rname + 1)
198: while ((--dest)[-1] != '/');
199: }
200: else
201: {
202: struct stat st;
203:
204: if (dest[-1] != '/')
205: *dest++ = '/';
206:
207: if (dest + (end - start) >= rname_limit)
208: {
209: ptrdiff_t dest_offset = dest - rname;
210: size_t new_size = rname_limit - rname;
211:
212: if (end - start + 1 > PATH_MAX)
213: new_size += end - start + 1;
214: else
215: new_size += PATH_MAX;
216: rname = xrealloc (rname, new_size);
217: rname_limit = rname + new_size;
218:
219: dest = rname + dest_offset;
220: }
221:
222: dest = memcpy (dest, start, end - start);
223: dest += end - start;
224: *dest = '\0';
225:
226: if (lstat (rname, &st) != 0)
227: {
228: if (can_mode == CAN_EXISTING)
229: goto error;
230: if (can_mode == CAN_ALL_BUT_LAST && *end)
231: goto error;
232: st.st_mode = 0;
233: }
234:
235: if (S_ISLNK (st.st_mode))
236: {
237: char *buf;
238: size_t n, len;
239:
240: if (cycle_check (&cycle_state, &st))
241: {
242: __set_errno (ELOOP);
243: if (can_mode == CAN_MISSING)
244: continue;
245: else
246: goto error;
247: }
248:
249: buf = xreadlink_with_size (rname, st.st_size);
250: if (!buf)
251: {
252: if (can_mode == CAN_MISSING)
253: continue;
254: else
255: goto error;
256: }
257:
258: n = strlen (buf);
259: len = strlen (end);
260:
261: if (!extra_len)
262: {
263: extra_len =
264: ((n + len + 1) > PATH_MAX) ? (n + len + 1) : PATH_MAX;
265: extra_buf = xmalloc (extra_len);
266: }
267: else if ((n + len + 1) > extra_len)
268: {
269: extra_len = n + len + 1;
270: extra_buf = xrealloc (extra_buf, extra_len);
271: }
272:
273:
274: memmove (&extra_buf[n], end, len + 1);
275: name = end = memcpy (extra_buf, buf, n);
276:
277: if (buf[0] == '/')
278: dest = rname + 1;
279: else
280:
281: if (dest > rname + 1)
282: while ((--dest)[-1] != '/');
283:
284: free (buf);
285: }
286: else
287: {
288: if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
289: {
290: errno = ENOTDIR;
291: goto error;
292: }
293: }
294: }
295: }
296: if (dest > rname + 1 && dest[-1] == '/')
297: --dest;
298: *dest = '\0';
299:
300: free (extra_buf);
301: return rname;
302:
303: error:
304: free (extra_buf);
305: free (rname);
306: return NULL;
307: }