Mercurial > hg > xemacs-beta
annotate src/realpath.c @ 5781:0853e1ec8529
Use alloca_{rawbytes,ibytes} in #'copy-file, #'insert-file-contents-internal
src/ChangeLog addition:
2014-01-20 Aidan Kehoe <kehoea@parhasard.net>
* fileio.c (Fcopy_file, Finsert_file_contents_internal):
Use alloca_{rawbytes,ibytes} here instead of the implicit alloca
on the stack; doesn't change where the buffers are allocated for
these two functions, but does mean that decisions about alloca
vs. malloc based on buffer size are made in the same place
(ultimately, the ALLOCA() macro).
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Mon, 20 Jan 2014 17:53:07 +0000 |
parents | 308d34e9f07d |
children |
rev | line source |
---|---|
428 | 1 /* |
2 * realpath.c -- canonicalize pathname by removing symlinks | |
3 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> | |
2526 | 4 * Copyright (C) 2001, 2002, 2004 Ben Wing. |
428 | 5 * |
6 | |
7 This file is part of XEmacs. | |
8 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
4982
diff
changeset
|
9 XEmacs is free software: you can redistribute it and/or modify it |
428 | 10 under the terms of the GNU General Public License as published by the |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
4982
diff
changeset
|
11 Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
4982
diff
changeset
|
12 option) any later version. |
428 | 13 |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
4982
diff
changeset
|
20 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
428 | 21 |
22 /* Synched up with: Not in FSF. */ | |
23 | |
771 | 24 /* This file has been Mule-ized, June 2001 by Ben Wing. |
25 | |
26 Everything in this file now works in terms of internal, not external, | |
27 data. This is the only way to be safe, and it makes the code cleaner. */ | |
28 | |
428 | 29 #include <config.h> |
446 | 30 #include "lisp.h" |
442 | 31 |
2526 | 32 #include "profile.h" |
33 | |
558 | 34 #include "sysfile.h" |
1116 | 35 #include "sysdir.h" |
428 | 36 |
771 | 37 #define MAX_READLINKS 32 |
38 | |
1116 | 39 #ifdef WIN32_ANY |
446 | 40 #include "syswindows.h" |
41 #ifndef ELOOP | |
42 #define ELOOP 10062 /* = WSAELOOP in winsock.h */ | |
43 #endif | |
1116 | 44 #endif |
45 | |
2526 | 46 Lisp_Object QSin_qxe_realpath; |
47 | |
446 | 48 /* Length of start of absolute filename. */ |
49 static int | |
1116 | 50 abs_start (const Ibyte *name) |
446 | 51 { |
1116 | 52 #ifdef WIN32_ANY |
446 | 53 if (isalpha (*name) && IS_DEVICE_SEP (name[1]) |
54 && IS_DIRECTORY_SEP (name[2])) | |
55 return 3; | |
56 else if (IS_DIRECTORY_SEP (*name)) | |
57 return IS_DIRECTORY_SEP (name[1]) ? 2 : 1; | |
58 else | |
59 return 0; | |
1116 | 60 #else /* not WIN32_ANY */ |
61 return IS_DIRECTORY_SEP (*name) ? 1 : 0; | |
62 #endif | |
446 | 63 } |
1116 | 64 |
2526 | 65 /* Find real name of a file by resolving symbolic links and/or shortcuts |
66 under Windows (.LNK links), if such support is enabled. | |
67 | |
68 If no link found, and LINKS_ONLY is false, look up the correct case in | |
69 the file system of the last component. | |
1116 | 70 |
71 Under Windows, UNC servers and shares are lower-cased. Directories must | |
72 be given without trailing '/'. One day, this could read Win2K's reparse | |
2526 | 73 points. |
74 | |
75 Returns length of characters copied info BUF. | |
76 DOES NOT ZERO TERMINATE!!!!! | |
77 */ | |
1116 | 78 |
4721
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
79 #ifdef REALPATH_CORRECTS_CASE /* Darwin */ |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
80 #include <sys/param.h> |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
81 #include <stdlib.h> |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
82 #endif |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
83 |
1116 | 84 static int |
2526 | 85 readlink_or_correct_case (const Ibyte *name, Ibyte *buf, Bytecount size, |
3042 | 86 #ifndef WIN32_ANY |
3044 | 87 Boolint UNUSED (links_only) |
3042 | 88 #else |
3044 | 89 Boolint links_only |
3042 | 90 #endif |
3044 | 91 ) |
1116 | 92 { |
93 #ifndef WIN32_ANY | |
4721
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
94 #ifdef REALPATH_CORRECTS_CASE |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
95 /* Darwin's realpath corrects file name case, so we want to use that |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
96 here, as well as our own, non-case-correcting, implementation |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
97 further down in this file. |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
98 |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
99 It might be reasonable to incorporate case correction in our own |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
100 realpath implementation, which would help things with |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
101 case-insensitive file systems on Linux; one way to do this would |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
102 be to make sure that init_initial_directory and |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
103 get_initial_directory always give the correct case. */ |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
104 int n = qxe_readlink (name, buf, (size_t) size); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
105 Extbyte realpath_buf[PATH_MAX], *tmp; |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
106 DECLARE_EISTRING (realpathing); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
107 |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
108 if (n >= 0 || errno != EINVAL) |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
109 return n; |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
110 |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
111 eicpy_rawz (realpathing, name); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
112 eito_external (realpathing, Qfile_name); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
113 tmp = realpath (eiextdata (realpathing), realpath_buf); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
114 |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
115 if (!tmp) |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
116 return -1; |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
117 |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
118 if (0 == memcmp (eiextdata (realpathing), realpath_buf, |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
119 eiextlen (realpathing))) |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
120 { |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
121 /* No case change needed; tell the caller that. */ |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
122 errno = EINVAL; |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
123 return -1; |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
124 } |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
125 |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
126 eireset (realpathing); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
127 eicpy_ext (realpathing, realpath_buf, Qfile_name); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
128 if (eilen (realpathing) > size) |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
129 { |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
130 errno = ERANGE; |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
131 return -1; |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
132 } |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
133 |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
134 memcpy (buf, eidata (realpathing), eilen (realpathing)); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
135 return eilen (realpathing); |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
136 #else /* !REALPATH_CORRECTS_CASE */ |
2526 | 137 return qxe_readlink (name, buf, (size_t) size); |
4721
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
138 #endif /* REALPATH_CORRECTS_CASE */ |
19d70297d866
Make readlink_or_correct_case function correctly on Darwin.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3044
diff
changeset
|
139 #else /* defined (WIN32_ANY) */ |
1116 | 140 # ifdef CYGWIN |
2526 | 141 int n = qxe_readlink (name, buf, (size_t) size); |
1116 | 142 if (n >= 0 || errno != EINVAL) |
143 return n; | |
144 | |
145 /* The file may exist, but isn't a symlink. Try to find the | |
146 right name. */ | |
4834
b3ea9c582280
Use new cygwin_conv_path API with Cygwin 1.7 for converting names between Win32 and POSIX, UTF-8-aware, with attendant changes elsewhere
Ben Wing <ben@xemacs.org>
parents:
4721
diff
changeset
|
147 LOCAL_FILE_FORMAT_TO_INTERNAL_MSWIN (name, name); |
2526 | 148 # else |
149 if (mswindows_shortcuts_are_symlinks) | |
150 { | |
151 Ibyte *tmp = mswindows_read_link (name); | |
152 | |
153 if (tmp != NULL) | |
154 { | |
155 /* Fucking fixed buffers. */ | |
156 Bytecount len = qxestrlen (tmp); | |
157 if (len > size) | |
158 { | |
159 errno = ENAMETOOLONG; | |
160 return -1; | |
161 } | |
162 memcpy (buf, tmp, len); | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
163 xfree (tmp); |
2526 | 164 return len; |
165 } | |
166 } | |
1116 | 167 # endif |
168 | |
2526 | 169 if (links_only) |
170 { | |
171 errno = EINVAL; | |
172 return -1; | |
173 } | |
174 | |
1116 | 175 { |
176 int len = 0; | |
177 int err = 0; | |
178 const Ibyte *lastname; | |
179 int count = 0; | |
1204 | 180 const Ibyte *nn; |
1116 | 181 DECLARE_EISTRING (result); |
182 | |
183 assert (*name); | |
184 | |
185 /* Sort of check we have a valid filename. */ | |
186 if (qxestrpbrk (name, "*?|<>\"")) | |
187 { | |
188 errno = ENOENT; | |
189 return -1; | |
190 } | |
2421 | 191 else if (qxestrlen (name) >= PATH_MAX_INTERNAL) |
1116 | 192 { |
193 errno = ENAMETOOLONG; | |
194 return -1; | |
195 } | |
196 | |
197 /* Find start of filename */ | |
198 lastname = name + qxestrlen (name); | |
199 while (lastname > name && !IS_DIRECTORY_SEP (lastname[-1])) | |
200 --lastname; | |
201 | |
202 /* Count slashes in unc path */ | |
203 if (abs_start (name) == 2) | |
1204 | 204 for (nn = name; *nn; nn++) |
205 if (IS_DIRECTORY_SEP (*nn)) | |
1116 | 206 count++; |
207 | |
208 if (count >= 2 && count < 4) | |
209 { | |
210 eicpy_rawz (result, lastname); | |
211 eilwr (result); | |
212 } | |
213 else | |
214 { | |
215 WIN32_FIND_DATAW find_data; | |
216 Extbyte *nameext; | |
217 HANDLE dir_handle; | |
218 | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
219 nameext = ITEXT_TO_TSTR (name); |
1116 | 220 dir_handle = qxeFindFirstFile (nameext, &find_data); |
221 if (dir_handle == INVALID_HANDLE_VALUE) | |
222 { | |
223 errno = ENOENT; | |
224 return -1; | |
225 } | |
226 eicpy_ext (result, (Extbyte *) find_data.cFileName, Qmswindows_tstr); | |
227 FindClose (dir_handle); | |
228 } | |
229 | |
2526 | 230 if ((len = eilen (result)) <= size) |
1116 | 231 { |
232 DECLARE_EISTRING (eilastname); | |
233 | |
234 eicpy_rawz (eilastname, lastname); | |
235 if (eicmp_ei (eilastname, result) == 0) | |
2526 | 236 /* Signal that the name is already OK. */ |
237 err = EINVAL; | |
1116 | 238 else |
2526 | 239 memcpy (buf, eidata (result), len); |
1116 | 240 } |
241 else | |
242 err = ENAMETOOLONG; | |
243 | |
244 errno = err; | |
245 return err ? -1 : len; | |
246 } | |
247 #endif /* WIN32_ANY */ | |
248 } | |
446 | 249 |
771 | 250 /* Mule Note: This function works with and returns |
2526 | 251 internally-formatted strings. |
252 | |
253 if LINKS_ONLY is true, don't do case canonicalization under | |
254 Windows. */ | |
440 | 255 |
867 | 256 Ibyte * |
2526 | 257 qxe_realpath (const Ibyte *path, Ibyte *resolved_path, Boolint links_only) |
428 | 258 { |
2421 | 259 Ibyte copy_path[PATH_MAX_INTERNAL]; |
867 | 260 Ibyte *new_path = resolved_path; |
261 Ibyte *max_path; | |
2526 | 262 Ibyte *retval = NULL; |
1116 | 263 #if defined (HAVE_READLINK) || defined (WIN32_ANY) |
428 | 264 int readlinks = 0; |
2421 | 265 Ibyte link_path[PATH_MAX_INTERNAL]; |
428 | 266 int n; |
1116 | 267 int abslen = abs_start (path); |
428 | 268 #endif |
269 | |
2526 | 270 PROFILE_DECLARE (); |
271 | |
272 PROFILE_RECORD_ENTERING_SECTION (QSin_qxe_realpath); | |
273 | |
1760 | 274 restart: |
275 | |
428 | 276 /* Make a copy of the source path since we may need to modify it. */ |
771 | 277 qxestrcpy (copy_path, path); |
428 | 278 path = copy_path; |
2421 | 279 max_path = copy_path + PATH_MAX_INTERNAL - 2; |
446 | 280 |
819 | 281 if (0) |
282 ; | |
1116 | 283 #ifdef WIN32_ANY |
446 | 284 /* Check for c:/... or //server/... */ |
988 | 285 else if (abslen == 3 || abslen == 2) |
428 | 286 { |
462 | 287 /* Make sure drive letter is lowercased. */ |
1116 | 288 if (abslen == 3) |
289 { | |
290 *new_path = tolower (*path); | |
291 new_path++; | |
292 path++; | |
293 abslen--; | |
294 } | |
988 | 295 /* Coerce directory chars. */ |
1116 | 296 while (abslen-- > 0) |
297 { | |
298 if (IS_DIRECTORY_SEP (*path)) | |
299 *new_path++ = DIRECTORY_SEP; | |
300 else | |
301 *new_path++ = *path; | |
302 path++; | |
303 } | |
428 | 304 } |
819 | 305 #endif |
306 #ifdef WIN32_NATIVE | |
446 | 307 /* No drive letter, but a beginning slash? Prepend drive letter. */ |
308 else if (abslen == 1) | |
428 | 309 { |
2421 | 310 get_initial_directory (new_path, PATH_MAX_INTERNAL - 1); |
428 | 311 new_path += 3; |
312 path++; | |
313 } | |
446 | 314 /* Just a path name, prepend the current directory */ |
1116 | 315 else |
428 | 316 { |
2421 | 317 get_initial_directory (new_path, PATH_MAX_INTERNAL - 1); |
771 | 318 new_path += qxestrlen (new_path); |
446 | 319 if (!IS_DIRECTORY_SEP (new_path[-1])) |
320 *new_path++ = DIRECTORY_SEP; | |
428 | 321 } |
322 #else | |
771 | 323 /* If it's a relative pathname use get_initial_directory for starters. */ |
819 | 324 else if (abslen == 0) |
428 | 325 { |
2421 | 326 get_initial_directory (new_path, PATH_MAX_INTERNAL - 1); |
771 | 327 new_path += qxestrlen (new_path); |
446 | 328 if (!IS_DIRECTORY_SEP (new_path[-1])) |
329 *new_path++ = DIRECTORY_SEP; | |
428 | 330 } |
331 else | |
332 { | |
446 | 333 /* Copy first directory sep. May have two on cygwin. */ |
771 | 334 qxestrncpy (new_path, path, abslen); |
446 | 335 new_path += abslen; |
336 path += abslen; | |
428 | 337 } |
338 #endif | |
339 /* Expand each slash-separated pathname component. */ | |
340 while (*path != '\0') | |
341 { | |
342 /* Ignore stray "/". */ | |
446 | 343 if (IS_DIRECTORY_SEP (*path)) |
428 | 344 { |
345 path++; | |
346 continue; | |
347 } | |
348 | |
349 if (*path == '.') | |
350 { | |
351 /* Ignore ".". */ | |
446 | 352 if (path[1] == '\0' || IS_DIRECTORY_SEP (path[1])) |
428 | 353 { |
354 path++; | |
355 continue; | |
356 } | |
357 | |
442 | 358 /* Handle ".." */ |
359 if (path[1] == '.' && | |
446 | 360 (path[2] == '\0' || IS_DIRECTORY_SEP (path[2]))) |
428 | 361 { |
442 | 362 path += 2; |
428 | 363 |
442 | 364 /* Ignore ".." at root. */ |
1116 | 365 if (new_path == resolved_path + abs_start (resolved_path)) |
442 | 366 continue; |
428 | 367 |
442 | 368 /* Handle ".." by backing up. */ |
446 | 369 --new_path; |
370 while (!IS_DIRECTORY_SEP (new_path[-1])) | |
371 --new_path; | |
442 | 372 continue; |
428 | 373 } |
374 } | |
375 | |
376 /* Safely copy the next pathname component. */ | |
446 | 377 while (*path != '\0' && !IS_DIRECTORY_SEP (*path)) |
428 | 378 { |
379 if (path > max_path) | |
380 { | |
381 errno = ENAMETOOLONG; | |
2526 | 382 goto done; |
428 | 383 } |
384 *new_path++ = *path++; | |
385 } | |
386 | |
1116 | 387 #if defined (HAVE_READLINK) || defined (WIN32_ANY) |
771 | 388 /* See if latest pathname component is a symlink or needs case |
389 correction. */ | |
428 | 390 *new_path = '\0'; |
2526 | 391 n = readlink_or_correct_case (resolved_path, link_path, |
392 PATH_MAX_INTERNAL - 1, links_only); | |
428 | 393 |
394 if (n < 0) | |
395 { | |
771 | 396 /* EINVAL means the file exists but isn't a symlink or doesn't |
397 need case correction. */ | |
1116 | 398 #ifdef WIN32_ANY |
462 | 399 if (errno != EINVAL && errno != ENOENT) |
400 #else | |
401 if (errno != EINVAL) | |
402 #endif | |
2526 | 403 goto done; |
428 | 404 } |
405 else | |
406 { | |
407 /* Protect against infinite loops. */ | |
408 if (readlinks++ > MAX_READLINKS) | |
409 { | |
410 errno = ELOOP; | |
2526 | 411 goto done; |
428 | 412 } |
413 | |
414 /* Note: readlink doesn't add the null byte. */ | |
415 link_path[n] = '\0'; | |
446 | 416 |
1760 | 417 abslen = abs_start (link_path); |
418 if (abslen > 0) | |
419 { | |
420 /* Start over for an absolute symlink. */ | |
421 new_path = resolved_path; | |
422 qxestrcat (link_path, path); | |
423 path = link_path; | |
424 goto restart; | |
425 } | |
426 | |
427 /* Otherwise back up over this component. */ | |
428 for (--new_path; !IS_DIRECTORY_SEP (*new_path); --new_path) | |
429 assert (new_path > resolved_path); | |
428 | 430 |
431 /* Safe sex check. */ | |
2421 | 432 if (qxestrlen (path) + n >= PATH_MAX_INTERNAL) |
428 | 433 { |
434 errno = ENAMETOOLONG; | |
2526 | 435 goto done; |
428 | 436 } |
437 | |
438 /* Insert symlink contents into path. */ | |
771 | 439 qxestrcat (link_path, path); |
440 qxestrcpy (copy_path, link_path); | |
428 | 441 path = copy_path; |
442 } | |
1116 | 443 #endif /* HAVE_READLINK || WIN32_ANY */ |
446 | 444 *new_path++ = DIRECTORY_SEP; |
428 | 445 } |
446 | |
447 /* Delete trailing slash but don't whomp a lone slash. */ | |
1116 | 448 if (new_path != resolved_path + abs_start (resolved_path) && |
771 | 449 IS_DIRECTORY_SEP (new_path[-1])) |
428 | 450 new_path--; |
451 | |
452 /* Make sure it's null terminated. */ | |
453 *new_path = '\0'; | |
446 | 454 |
2526 | 455 retval = resolved_path; |
456 done: | |
457 PROFILE_RECORD_EXITING_SECTION (QSin_qxe_realpath); | |
458 return retval; | |
428 | 459 } |
2526 | 460 |
461 void | |
462 vars_of_realpath (void) | |
463 { | |
464 QSin_qxe_realpath = | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4834
diff
changeset
|
465 build_defer_string ("(in qxe_realpath)"); |
2526 | 466 staticpro (&QSin_qxe_realpath); |
467 } |