Mercurial > hg > xemacs-beta
comparison src/realpath.c @ 2526:902d5bd9b75c
[xemacs-hg @ 2005-01-28 02:36:11 by ben]
Support symlinks under Windows
nt.c, fileio.c: Fix sync comments.
config.h.in, dired-msw.c, emacs.c, event-msw.c, fileio.c, glyphs.c, lisp.h, nt.c, process-nt.c, realpath.c, sound.c, symsinit.h, sysdep.c, sysfile.h, syswindows.h, win32.c: Add support for treating shortcuts under Windows as symbolic links.
Enabled with mswindows-shortcuts-are-links (t by default). Rewrite
lots of places to use PATHNAME_CONVERT_OUT, which is moved to
sysfile.h. Add PATHNAME_RESOLVE_LINKS, which only does things
under Windows.
Add profiling section for expand_file_name calls.
nt.c, sysdep.c: Unicode-ize.
realpath.c: Renamed from readlink_and_correct_case. Fix some problems with
Windows implementation due to incorrect understanding of workings
of the function.
sound.c, ntplay.c, sound.h: Rename play_sound_file to nt_play_sound_file and pass
internally-formatted data to it to avoid converting out and back
again.
text.h: is_c -> is_ascii.
author | ben |
---|---|
date | Fri, 28 Jan 2005 02:36:28 +0000 |
parents | ab71ad6ff3dd |
children | 967fea9dfad5 |
comparison
equal
deleted
inserted
replaced
2525:52f00344a629 | 2526:902d5bd9b75c |
---|---|
1 /* | 1 /* |
2 * realpath.c -- canonicalize pathname by removing symlinks | 2 * realpath.c -- canonicalize pathname by removing symlinks |
3 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> | 3 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> |
4 * Copyright (C) 2001, 2002 Ben Wing. | 4 * Copyright (C) 2001, 2002, 2004 Ben Wing. |
5 * | 5 * |
6 | 6 |
7 This file is part of XEmacs. | 7 This file is part of XEmacs. |
8 | 8 |
9 XEmacs is free software; you can redistribute it and/or modify it | 9 XEmacs is free software; you can redistribute it and/or modify it |
29 data. This is the only way to be safe, and it makes the code cleaner. */ | 29 data. This is the only way to be safe, and it makes the code cleaner. */ |
30 | 30 |
31 #include <config.h> | 31 #include <config.h> |
32 #include "lisp.h" | 32 #include "lisp.h" |
33 | 33 |
34 #include "profile.h" | |
35 | |
34 #include "sysfile.h" | 36 #include "sysfile.h" |
35 #include "sysdir.h" | 37 #include "sysdir.h" |
36 | 38 |
37 #define MAX_READLINKS 32 | 39 #define MAX_READLINKS 32 |
38 | 40 |
40 #include "syswindows.h" | 42 #include "syswindows.h" |
41 #ifndef ELOOP | 43 #ifndef ELOOP |
42 #define ELOOP 10062 /* = WSAELOOP in winsock.h */ | 44 #define ELOOP 10062 /* = WSAELOOP in winsock.h */ |
43 #endif | 45 #endif |
44 #endif | 46 #endif |
47 | |
48 Lisp_Object QSin_qxe_realpath; | |
45 | 49 |
46 /* Length of start of absolute filename. */ | 50 /* Length of start of absolute filename. */ |
47 static int | 51 static int |
48 abs_start (const Ibyte *name) | 52 abs_start (const Ibyte *name) |
49 { | 53 { |
58 #else /* not WIN32_ANY */ | 62 #else /* not WIN32_ANY */ |
59 return IS_DIRECTORY_SEP (*name) ? 1 : 0; | 63 return IS_DIRECTORY_SEP (*name) ? 1 : 0; |
60 #endif | 64 #endif |
61 } | 65 } |
62 | 66 |
63 /* Find real name of a file by resolving symbolic links and (under Windows) | 67 /* Find real name of a file by resolving symbolic links and/or shortcuts |
64 looking up the correct case of the file as it appears on the file | 68 under Windows (.LNK links), if such support is enabled. |
65 system. | 69 |
70 If no link found, and LINKS_ONLY is false, look up the correct case in | |
71 the file system of the last component. | |
66 | 72 |
67 Under Windows, UNC servers and shares are lower-cased. Directories must | 73 Under Windows, UNC servers and shares are lower-cased. Directories must |
68 be given without trailing '/'. One day, this could read Win2K's reparse | 74 be given without trailing '/'. One day, this could read Win2K's reparse |
69 points. */ | 75 points. |
76 | |
77 Returns length of characters copied info BUF. | |
78 DOES NOT ZERO TERMINATE!!!!! | |
79 */ | |
70 | 80 |
71 static int | 81 static int |
72 readlink_and_correct_case (const Ibyte *name, Ibyte *buf, | 82 readlink_or_correct_case (const Ibyte *name, Ibyte *buf, Bytecount size, |
73 int size) | 83 Boolint links_only) |
74 { | 84 { |
75 #ifndef WIN32_ANY | 85 #ifndef WIN32_ANY |
76 return qxe_readlink (name, buf, size); | 86 return qxe_readlink (name, buf, (size_t) size); |
77 #else | 87 #else |
78 # ifdef CYGWIN | 88 # ifdef CYGWIN |
79 Ibyte *tmp; | 89 Ibyte *tmp; |
80 int n = qxe_readlink (name, buf, size); | 90 int n = qxe_readlink (name, buf, (size_t) size); |
81 if (n >= 0 || errno != EINVAL) | 91 if (n >= 0 || errno != EINVAL) |
82 return n; | 92 return n; |
83 | 93 |
84 /* The file may exist, but isn't a symlink. Try to find the | 94 /* The file may exist, but isn't a symlink. Try to find the |
85 right name. */ | 95 right name. */ |
86 tmp = | 96 tmp = |
87 alloca_ibytes (cygwin_posix_to_win32_path_list_buf_size ((char *) name)); | 97 alloca_ibytes (cygwin_posix_to_win32_path_list_buf_size ((char *) name)); |
88 cygwin_posix_to_win32_path_list ((char *) name, (char *) tmp); | 98 cygwin_posix_to_win32_path_list ((char *) name, (char *) tmp); |
89 name = tmp; | 99 name = tmp; |
100 # else | |
101 if (mswindows_shortcuts_are_symlinks) | |
102 { | |
103 Ibyte *tmp = mswindows_read_link (name); | |
104 | |
105 if (tmp != NULL) | |
106 { | |
107 /* Fucking fixed buffers. */ | |
108 Bytecount len = qxestrlen (tmp); | |
109 if (len > size) | |
110 { | |
111 errno = ENAMETOOLONG; | |
112 return -1; | |
113 } | |
114 memcpy (buf, tmp, len); | |
115 xfree (tmp, Ibyte *); | |
116 return len; | |
117 } | |
118 } | |
90 # endif | 119 # endif |
120 | |
121 if (links_only) | |
122 { | |
123 errno = EINVAL; | |
124 return -1; | |
125 } | |
91 | 126 |
92 { | 127 { |
93 int len = 0; | 128 int len = 0; |
94 int err = 0; | 129 int err = 0; |
95 const Ibyte *lastname; | 130 const Ibyte *lastname; |
142 } | 177 } |
143 eicpy_ext (result, (Extbyte *) find_data.cFileName, Qmswindows_tstr); | 178 eicpy_ext (result, (Extbyte *) find_data.cFileName, Qmswindows_tstr); |
144 FindClose (dir_handle); | 179 FindClose (dir_handle); |
145 } | 180 } |
146 | 181 |
147 if ((len = eilen (result)) < size) | 182 if ((len = eilen (result)) <= size) |
148 { | 183 { |
149 DECLARE_EISTRING (eilastname); | 184 DECLARE_EISTRING (eilastname); |
150 | 185 |
151 eicpy_rawz (eilastname, lastname); | 186 eicpy_rawz (eilastname, lastname); |
152 if (eicmp_ei (eilastname, result) == 0) | 187 if (eicmp_ei (eilastname, result) == 0) |
153 /* Signal that the name is already OK. */ | 188 /* Signal that the name is already OK. */ |
154 err = EINVAL; | 189 err = EINVAL; |
155 else | 190 else |
156 memcpy (buf, eidata (result), len + 1); | 191 memcpy (buf, eidata (result), len); |
157 } | 192 } |
158 else | 193 else |
159 err = ENAMETOOLONG; | 194 err = ENAMETOOLONG; |
160 | 195 |
161 errno = err; | 196 errno = err; |
163 } | 198 } |
164 #endif /* WIN32_ANY */ | 199 #endif /* WIN32_ANY */ |
165 } | 200 } |
166 | 201 |
167 /* Mule Note: This function works with and returns | 202 /* Mule Note: This function works with and returns |
168 internally-formatted strings. */ | 203 internally-formatted strings. |
204 | |
205 if LINKS_ONLY is true, don't do case canonicalization under | |
206 Windows. */ | |
169 | 207 |
170 Ibyte * | 208 Ibyte * |
171 qxe_realpath (const Ibyte *path, Ibyte *resolved_path) | 209 qxe_realpath (const Ibyte *path, Ibyte *resolved_path, Boolint links_only) |
172 { | 210 { |
173 Ibyte copy_path[PATH_MAX_INTERNAL]; | 211 Ibyte copy_path[PATH_MAX_INTERNAL]; |
174 Ibyte *new_path = resolved_path; | 212 Ibyte *new_path = resolved_path; |
175 Ibyte *max_path; | 213 Ibyte *max_path; |
214 Ibyte *retval = NULL; | |
176 #if defined (HAVE_READLINK) || defined (WIN32_ANY) | 215 #if defined (HAVE_READLINK) || defined (WIN32_ANY) |
177 int readlinks = 0; | 216 int readlinks = 0; |
178 Ibyte link_path[PATH_MAX_INTERNAL]; | 217 Ibyte link_path[PATH_MAX_INTERNAL]; |
179 int n; | 218 int n; |
180 int abslen = abs_start (path); | 219 int abslen = abs_start (path); |
181 #endif | 220 #endif |
182 | 221 |
222 PROFILE_DECLARE (); | |
223 | |
224 PROFILE_RECORD_ENTERING_SECTION (QSin_qxe_realpath); | |
225 | |
183 restart: | 226 restart: |
184 | 227 |
185 /* Make a copy of the source path since we may need to modify it. */ | 228 /* Make a copy of the source path since we may need to modify it. */ |
186 qxestrcpy (copy_path, path); | 229 qxestrcpy (copy_path, path); |
187 path = copy_path; | 230 path = copy_path; |
286 while (*path != '\0' && !IS_DIRECTORY_SEP (*path)) | 329 while (*path != '\0' && !IS_DIRECTORY_SEP (*path)) |
287 { | 330 { |
288 if (path > max_path) | 331 if (path > max_path) |
289 { | 332 { |
290 errno = ENAMETOOLONG; | 333 errno = ENAMETOOLONG; |
291 return NULL; | 334 goto done; |
292 } | 335 } |
293 *new_path++ = *path++; | 336 *new_path++ = *path++; |
294 } | 337 } |
295 | 338 |
296 #if defined (HAVE_READLINK) || defined (WIN32_ANY) | 339 #if defined (HAVE_READLINK) || defined (WIN32_ANY) |
297 /* See if latest pathname component is a symlink or needs case | 340 /* See if latest pathname component is a symlink or needs case |
298 correction. */ | 341 correction. */ |
299 *new_path = '\0'; | 342 *new_path = '\0'; |
300 n = readlink_and_correct_case (resolved_path, link_path, PATH_MAX_INTERNAL - 1); | 343 n = readlink_or_correct_case (resolved_path, link_path, |
344 PATH_MAX_INTERNAL - 1, links_only); | |
301 | 345 |
302 if (n < 0) | 346 if (n < 0) |
303 { | 347 { |
304 /* EINVAL means the file exists but isn't a symlink or doesn't | 348 /* EINVAL means the file exists but isn't a symlink or doesn't |
305 need case correction. */ | 349 need case correction. */ |
306 #ifdef WIN32_ANY | 350 #ifdef WIN32_ANY |
307 if (errno != EINVAL && errno != ENOENT) | 351 if (errno != EINVAL && errno != ENOENT) |
308 #else | 352 #else |
309 if (errno != EINVAL) | 353 if (errno != EINVAL) |
310 #endif | 354 #endif |
311 return NULL; | 355 goto done; |
312 } | 356 } |
313 else | 357 else |
314 { | 358 { |
315 /* Protect against infinite loops. */ | 359 /* Protect against infinite loops. */ |
316 if (readlinks++ > MAX_READLINKS) | 360 if (readlinks++ > MAX_READLINKS) |
317 { | 361 { |
318 errno = ELOOP; | 362 errno = ELOOP; |
319 return NULL; | 363 goto done; |
320 } | 364 } |
321 | 365 |
322 /* Note: readlink doesn't add the null byte. */ | 366 /* Note: readlink doesn't add the null byte. */ |
323 link_path[n] = '\0'; | 367 link_path[n] = '\0'; |
324 | 368 |
338 | 382 |
339 /* Safe sex check. */ | 383 /* Safe sex check. */ |
340 if (qxestrlen (path) + n >= PATH_MAX_INTERNAL) | 384 if (qxestrlen (path) + n >= PATH_MAX_INTERNAL) |
341 { | 385 { |
342 errno = ENAMETOOLONG; | 386 errno = ENAMETOOLONG; |
343 return NULL; | 387 goto done; |
344 } | 388 } |
345 | 389 |
346 /* Insert symlink contents into path. */ | 390 /* Insert symlink contents into path. */ |
347 qxestrcat (link_path, path); | 391 qxestrcat (link_path, path); |
348 qxestrcpy (copy_path, link_path); | 392 qxestrcpy (copy_path, link_path); |
358 new_path--; | 402 new_path--; |
359 | 403 |
360 /* Make sure it's null terminated. */ | 404 /* Make sure it's null terminated. */ |
361 *new_path = '\0'; | 405 *new_path = '\0'; |
362 | 406 |
363 return resolved_path; | 407 retval = resolved_path; |
408 done: | |
409 PROFILE_RECORD_EXITING_SECTION (QSin_qxe_realpath); | |
410 return retval; | |
364 } | 411 } |
412 | |
413 void | |
414 vars_of_realpath (void) | |
415 { | |
416 QSin_qxe_realpath = | |
417 build_msg_string ("(in qxe_realpath)"); | |
418 staticpro (&QSin_qxe_realpath); | |
419 } |