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 }