Mercurial > hg > xemacs-beta
comparison src/fileio.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 | 3d8143fc88e1 |
children | 6c7605dfcf07 |
comparison
equal
deleted
inserted
replaced
2525:52f00344a629 | 2526:902d5bd9b75c |
---|---|
21 | 21 |
22 /* Synched up with: Mule 2.0, FSF 19.30. */ | 22 /* Synched up with: Mule 2.0, FSF 19.30. */ |
23 /* More syncing: FSF Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> | 23 /* More syncing: FSF Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> |
24 (Note: Sync messages from Marc Paquette may indicate | 24 (Note: Sync messages from Marc Paquette may indicate |
25 incomplete synching, so beware.) */ | 25 incomplete synching, so beware.) */ |
26 /* Some functions synched with FSF 21.0.103. */ | |
26 /* Mule-ized completely except for the #if 0-code including decrypt-string | 27 /* Mule-ized completely except for the #if 0-code including decrypt-string |
27 and encrypt-string. --ben 7-2-00 */ | 28 and encrypt-string. --ben 7-2-00 */ |
28 /* #if 0-code Mule-ized, 2-22-03. --ben */ | 29 /* #if 0-code Mule-ized, 2-22-03. --ben */ |
29 | 30 |
30 | 31 |
36 #include "events.h" | 37 #include "events.h" |
37 #include "file-coding.h" | 38 #include "file-coding.h" |
38 #include "frame.h" | 39 #include "frame.h" |
39 #include "insdel.h" | 40 #include "insdel.h" |
40 #include "lstream.h" | 41 #include "lstream.h" |
42 #include "profile.h" | |
41 #include "process.h" | 43 #include "process.h" |
42 #include "redisplay.h" | 44 #include "redisplay.h" |
43 #include "sysdep.h" | 45 #include "sysdep.h" |
44 #include "window-impl.h" | 46 #include "window-impl.h" |
45 | 47 |
126 Lisp_Object Qauto_saving; | 128 Lisp_Object Qauto_saving; |
127 | 129 |
128 Lisp_Object Qcar_less_than_car; | 130 Lisp_Object Qcar_less_than_car; |
129 | 131 |
130 Lisp_Object Qcompute_buffer_file_truename; | 132 Lisp_Object Qcompute_buffer_file_truename; |
133 | |
134 Lisp_Object QSin_expand_file_name; | |
131 | 135 |
132 EXFUN (Frunning_temacs_p, 0); | 136 EXFUN (Frunning_temacs_p, 0); |
133 | 137 |
134 /* DATA can be anything acceptable to signal_error (). | 138 /* DATA can be anything acceptable to signal_error (). |
135 */ | 139 */ |
323 CHECK_STRING (result); | 327 CHECK_STRING (result); |
324 return result; | 328 return result; |
325 } | 329 } |
326 | 330 |
327 | 331 |
332 | |
333 Ibyte * | |
334 find_end_of_directory_component (const Ibyte *path, Bytecount len) | |
335 { | |
336 const Ibyte *p = path + len; | |
337 | |
338 while (p != path && !IS_DIRECTORY_SEP (p[-1]) | |
339 #ifdef WIN32_FILENAMES | |
340 /* only recognise drive specifier at the beginning */ | |
341 && !(p[-1] == ':' | |
342 /* handle the "/:d:foo" and "/:foo" cases correctly */ | |
343 && ((p == path + 2 && !IS_DIRECTORY_SEP (*path)) | |
344 || (p == path + 4 && IS_DIRECTORY_SEP (*path)))) | |
345 #endif | |
346 ) p--; | |
347 | |
348 return (Ibyte *) p; | |
349 } | |
350 | |
328 DEFUN ("file-name-directory", Ffile_name_directory, 1, 1, 0, /* | 351 DEFUN ("file-name-directory", Ffile_name_directory, 1, 1, 0, /* |
329 Return the directory component in file name FILENAME. | 352 Return the directory component in file name FILENAME. |
330 Return nil if FILENAME does not include a directory. | 353 Return nil if FILENAME does not include a directory. |
331 Otherwise return a directory spec. | 354 Otherwise return a directory spec. |
332 Given a Unix syntax file name, returns a string ending in slash. | 355 Given a Unix syntax file name, returns a string ending in slash. |
350 #ifdef FILE_SYSTEM_CASE | 373 #ifdef FILE_SYSTEM_CASE |
351 filename = FILE_SYSTEM_CASE (filename); | 374 filename = FILE_SYSTEM_CASE (filename); |
352 #endif | 375 #endif |
353 beg = XSTRING_DATA (filename); | 376 beg = XSTRING_DATA (filename); |
354 /* XEmacs: no need to alloca-copy here */ | 377 /* XEmacs: no need to alloca-copy here */ |
355 p = beg + XSTRING_LENGTH (filename); | 378 p = find_end_of_directory_component (beg, XSTRING_LENGTH (filename)); |
356 | |
357 while (p != beg && !IS_DIRECTORY_SEP (p[-1]) | |
358 #ifdef WIN32_FILENAMES | |
359 /* only recognise drive specifier at the beginning */ | |
360 && !(p[-1] == ':' | |
361 /* handle the "/:d:foo" and "/:foo" cases correctly */ | |
362 && ((p == beg + 2 && !IS_DIRECTORY_SEP (*beg)) | |
363 || (p == beg + 4 && IS_DIRECTORY_SEP (*beg)))) | |
364 #endif | |
365 ) p--; | |
366 | 379 |
367 if (p == beg) | 380 if (p == beg) |
368 return Qnil; | 381 return Qnil; |
369 #ifdef WIN32_NATIVE | 382 #ifdef WIN32_NATIVE |
370 /* Expansion of "c:" to drive and default directory. */ | 383 /* Expansion of "c:" to drive and default directory. */ |
520 handler = Ffind_file_name_handler (filename, Qfile_name_as_directory); | 533 handler = Ffind_file_name_handler (filename, Qfile_name_as_directory); |
521 if (!NILP (handler)) | 534 if (!NILP (handler)) |
522 return call2_check_string (handler, Qfile_name_as_directory, filename); | 535 return call2_check_string (handler, Qfile_name_as_directory, filename); |
523 | 536 |
524 buf = alloca_ibytes (XSTRING_LENGTH (filename) + 10); | 537 buf = alloca_ibytes (XSTRING_LENGTH (filename) + 10); |
525 return build_intstring (file_name_as_directory (buf, XSTRING_DATA (filename))); | 538 file_name_as_directory (buf, XSTRING_DATA (filename)); |
539 if (qxestrcmp (buf, XSTRING_DATA (filename))) | |
540 return build_intstring (buf); | |
541 else | |
542 return filename; | |
526 } | 543 } |
527 | 544 |
528 /* | 545 /* |
529 * Convert from directory name to filename. | 546 * Convert from directory name to filename. |
530 * On UNIX, it's simple: just make sure there isn't a terminating / | 547 * On UNIX, it's simple: just make sure there isn't a terminating / |
733 struct passwd *pw; | 750 struct passwd *pw; |
734 #endif | 751 #endif |
735 int length; | 752 int length; |
736 Lisp_Object handler = Qnil; | 753 Lisp_Object handler = Qnil; |
737 struct gcpro gcpro1, gcpro2, gcpro3; | 754 struct gcpro gcpro1, gcpro2, gcpro3; |
755 PROFILE_DECLARE (); | |
756 | |
757 PROFILE_RECORD_ENTERING_SECTION (QSin_expand_file_name); | |
738 | 758 |
739 /* both of these get set below */ | 759 /* both of these get set below */ |
740 GCPRO3 (name, default_directory, handler); | 760 GCPRO3 (name, default_directory, handler); |
741 | 761 |
742 CHECK_STRING (name); | 762 CHECK_STRING (name); |
743 | 763 |
744 /* If the file name has special constructs in it, | 764 /* If the file name has special constructs in it, |
745 call the corresponding file handler. */ | 765 call the corresponding file handler. */ |
746 handler = Ffind_file_name_handler (name, Qexpand_file_name); | 766 handler = Ffind_file_name_handler (name, Qexpand_file_name); |
747 if (!NILP (handler)) | 767 if (!NILP (handler)) |
748 RETURN_UNGCPRO (call3_check_string (handler, Qexpand_file_name, | 768 RETURN_UNGCPRO_EXIT_PROFILING (QSin_expand_file_name, |
749 name, default_directory)); | 769 call3_check_string |
770 (handler, Qexpand_file_name, | |
771 name, default_directory)); | |
750 | 772 |
751 /* Use the buffer's default-directory if DEFAULT_DIRECTORY is omitted. */ | 773 /* Use the buffer's default-directory if DEFAULT_DIRECTORY is omitted. */ |
752 if (NILP (default_directory)) | 774 if (NILP (default_directory)) |
753 default_directory = current_buffer->directory; | 775 default_directory = current_buffer->directory; |
754 if (! STRINGP (default_directory)) | 776 if (! STRINGP (default_directory)) |
760 | 782 |
761 if (!NILP (default_directory)) | 783 if (!NILP (default_directory)) |
762 { | 784 { |
763 handler = Ffind_file_name_handler (default_directory, Qexpand_file_name); | 785 handler = Ffind_file_name_handler (default_directory, Qexpand_file_name); |
764 if (!NILP (handler)) | 786 if (!NILP (handler)) |
765 RETURN_UNGCPRO (call3 (handler, Qexpand_file_name, | 787 RETURN_UNGCPRO_EXIT_PROFILING (QSin_expand_file_name, |
766 name, default_directory)); | 788 call3 (handler, Qexpand_file_name, |
789 name, default_directory)); | |
767 } | 790 } |
768 | 791 |
769 o = XSTRING_DATA (default_directory); | 792 o = XSTRING_DATA (default_directory); |
770 | 793 |
771 /* Make sure DEFAULT_DIRECTORY is properly expanded. | 794 /* Make sure DEFAULT_DIRECTORY is properly expanded. |
925 XSTRING_DATA (name)[0] = DRIVE_LETTER (drive); | 948 XSTRING_DATA (name)[0] = DRIVE_LETTER (drive); |
926 XSTRING_DATA (name)[1] = ':'; | 949 XSTRING_DATA (name)[1] = ':'; |
927 } | 950 } |
928 } | 951 } |
929 xfree (newnm, Ibyte *); | 952 xfree (newnm, Ibyte *); |
930 RETURN_UNGCPRO (name); | 953 RETURN_UNGCPRO_EXIT_PROFILING (QSin_expand_file_name, name); |
931 } | 954 } |
932 #endif /* WIN32_FILENAMES */ | 955 #endif /* WIN32_FILENAMES */ |
933 #ifndef WIN32_NATIVE | 956 #ifndef WIN32_NATIVE |
934 if (nm == XSTRING_DATA (name)) | 957 if (nm == XSTRING_DATA (name)) |
935 RETURN_UNGCPRO (name); | 958 RETURN_UNGCPRO_EXIT_PROFILING (QSin_expand_file_name, name); |
936 RETURN_UNGCPRO (build_intstring (nm)); | 959 RETURN_UNGCPRO_EXIT_PROFILING (QSin_expand_file_name, |
960 build_intstring (nm)); | |
937 #endif /* not WIN32_NATIVE */ | 961 #endif /* not WIN32_NATIVE */ |
938 } | 962 } |
939 } | 963 } |
940 | 964 |
941 /* At this point, nm might or might not be an absolute file name. We | 965 /* At this point, nm might or might not be an absolute file name. We |
1299 { | 1323 { |
1300 Ibyte *newtarget = mswindows_canonicalize_filename (target); | 1324 Ibyte *newtarget = mswindows_canonicalize_filename (target); |
1301 Lisp_Object result = build_intstring (newtarget); | 1325 Lisp_Object result = build_intstring (newtarget); |
1302 xfree (newtarget, Ibyte *); | 1326 xfree (newtarget, Ibyte *); |
1303 | 1327 |
1304 RETURN_UNGCPRO (result); | 1328 RETURN_UNGCPRO_EXIT_PROFILING (QSin_expand_file_name, result); |
1305 } | 1329 } |
1306 #else /* not WIN32_FILENAMES */ | 1330 #else /* not WIN32_FILENAMES */ |
1307 RETURN_UNGCPRO (make_string (target, o - target)); | 1331 RETURN_UNGCPRO_EXIT_PROFILING (QSin_expand_file_name, |
1332 make_string (target, o - target)); | |
1308 #endif /* not WIN32_FILENAMES */ | 1333 #endif /* not WIN32_FILENAMES */ |
1309 } | 1334 } |
1310 | 1335 |
1311 DEFUN ("file-truename", Ffile_truename, 1, 2, 0, /* | 1336 DEFUN ("file-truename", Ffile_truename, 1, 2, 0, /* |
1312 Return the canonical name of FILENAME. | 1337 Return the canonical name of FILENAME. |
1358 } | 1383 } |
1359 #endif | 1384 #endif |
1360 p = path; | 1385 p = path; |
1361 | 1386 |
1362 /* Try doing it all at once. */ | 1387 /* Try doing it all at once. */ |
1363 if (!qxe_realpath (path, resolved_path)) | 1388 if (!qxe_realpath (path, resolved_path, 0)) |
1364 { | 1389 { |
1365 /* Didn't resolve it -- have to do it one component at a time. */ | 1390 /* Didn't resolve it -- have to do it one component at a time. */ |
1366 /* "realpath" is a typically useless, stupid un*x piece of crap. | 1391 /* "realpath" is a typically useless, stupid un*x piece of crap. |
1367 It claims to return a useful value in the "error" case, but since | 1392 It claims to return a useful value in the "error" case, but since |
1368 there is no indication provided of how far along the pathname | 1393 there is no indication provided of how far along the pathname |
1377 returns a null pointer and sets errno to indicate the | 1402 returns a null pointer and sets errno to indicate the |
1378 error, and the contents of the buffer pointed to by | 1403 error, and the contents of the buffer pointed to by |
1379 resolved_name are undefined." | 1404 resolved_name are undefined." |
1380 | 1405 |
1381 Since we depend on undocumented semantics of various system | 1406 Since we depend on undocumented semantics of various system |
1382 realpath()s, we just use our own version in realpath.c. */ | 1407 realpath()s, we just use our own version in realpath.c. |
1408 | |
1409 Note also that our own version differs in its semantics from any | |
1410 standard version, since it accepts and returns internal-format | |
1411 text, not external-format. */ | |
1383 for (;;) | 1412 for (;;) |
1384 { | 1413 { |
1385 Ibyte *pos; | 1414 Ibyte *pos; |
1386 | 1415 |
1387 #ifdef WIN32_FILENAMES | 1416 #ifdef WIN32_FILENAMES |
1400 break; | 1429 break; |
1401 } | 1430 } |
1402 if (p != pos) | 1431 if (p != pos) |
1403 p = 0; | 1432 p = 0; |
1404 | 1433 |
1405 if (qxe_realpath (path, resolved_path)) | 1434 if (qxe_realpath (path, resolved_path, 0)) |
1406 { | 1435 { |
1407 if (p) | 1436 if (p) |
1408 *p = DIRECTORY_SEP; | 1437 *p = DIRECTORY_SEP; |
1409 else | 1438 else |
1410 break; | 1439 break; |
2336 call the corresponding file handler. */ | 2365 call the corresponding file handler. */ |
2337 handler = Ffind_file_name_handler (abspath, Qfile_readable_p); | 2366 handler = Ffind_file_name_handler (abspath, Qfile_readable_p); |
2338 if (!NILP (handler)) | 2367 if (!NILP (handler)) |
2339 RETURN_UNGCPRO (call2 (handler, Qfile_readable_p, abspath)); | 2368 RETURN_UNGCPRO (call2 (handler, Qfile_readable_p, abspath)); |
2340 | 2369 |
2341 #if defined(WIN32_FILENAMES) | 2370 #if defined (WIN32_FILENAMES) |
2342 /* Under MS-DOS and Windows, open does not work for directories. */ | 2371 /* Under MS-DOS and Windows, open does not work for directories. */ |
2343 UNGCPRO; | 2372 UNGCPRO; |
2344 if (qxe_access (XSTRING_DATA (abspath), 0) == 0) | 2373 if (qxe_access (XSTRING_DATA (abspath), 0) == 0) |
2345 return Qt; | 2374 return Qt; |
2346 else | 2375 else |
2441 return Qnil; | 2470 return Qnil; |
2442 } | 2471 } |
2443 val = make_string (buf, valsize); | 2472 val = make_string (buf, valsize); |
2444 xfree (buf, Ibyte *); | 2473 xfree (buf, Ibyte *); |
2445 return val; | 2474 return val; |
2446 #else /* not HAVE_READLINK */ | 2475 #elif defined (WIN32_NATIVE) |
2476 if (mswindows_shortcuts_are_symlinks) | |
2477 { | |
2478 /* We want to resolve the directory component and leave the rest | |
2479 alone. */ | |
2480 Ibyte *path = XSTRING_DATA (filename); | |
2481 Ibyte *dirend = | |
2482 find_end_of_directory_component (path, XSTRING_LENGTH (filename)); | |
2483 Ibyte *fname; | |
2484 DECLARE_EISTRING (dir); | |
2485 | |
2486 if (dirend != path) | |
2487 { | |
2488 Ibyte *resdir; | |
2489 DECLARE_EISTRING (resname); | |
2490 | |
2491 eicpy_raw (dir, path, dirend - path); | |
2492 PATHNAME_RESOLVE_LINKS (eidata (dir), resdir); | |
2493 eicpy_rawz (resname, resdir); | |
2494 eicat_rawz (resname, dirend); | |
2495 path = eidata (resname); | |
2496 } | |
2497 | |
2498 fname = mswindows_read_link (path); | |
2499 if (!fname) | |
2500 return Qnil; | |
2501 { | |
2502 Lisp_Object val = build_intstring (fname); | |
2503 xfree (fname, Ibyte *); | |
2504 return val; | |
2505 } | |
2506 } | |
2447 return Qnil; | 2507 return Qnil; |
2448 #endif /* not HAVE_READLINK */ | 2508 #else |
2509 return Qnil; | |
2510 #endif | |
2449 } | 2511 } |
2450 | 2512 |
2451 DEFUN ("file-directory-p", Ffile_directory_p, 1, 1, 0, /* | 2513 DEFUN ("file-directory-p", Ffile_directory_p, 1, 1, 0, /* |
2452 Return t if file FILENAME is the name of a directory as a file. | 2514 Return t if file FILENAME is the name of a directory as a file. |
2453 A directory name spec may be given instead; then the value is t | 2515 A directory name spec may be given instead; then the value is t |
2497 handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p); | 2559 handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p); |
2498 if (!NILP (handler)) | 2560 if (!NILP (handler)) |
2499 return call2 (handler, Qfile_accessible_directory_p, | 2561 return call2 (handler, Qfile_accessible_directory_p, |
2500 filename); | 2562 filename); |
2501 | 2563 |
2502 #if !defined(WIN32_NATIVE) | 2564 #if !defined (WIN32_NATIVE) |
2503 if (NILP (Ffile_directory_p (filename))) | 2565 if (NILP (Ffile_directory_p (filename))) |
2504 return (Qnil); | 2566 return (Qnil); |
2505 else | 2567 else |
2506 return Ffile_executable_p (filename); | 2568 return Ffile_executable_p (filename); |
2507 #else | 2569 #else |
4298 } | 4360 } |
4299 | 4361 |
4300 void | 4362 void |
4301 vars_of_fileio (void) | 4363 vars_of_fileio (void) |
4302 { | 4364 { |
4365 QSin_expand_file_name = | |
4366 build_msg_string ("(in expand-file-name)"); | |
4367 staticpro (&QSin_expand_file_name); | |
4368 | |
4303 DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format /* | 4369 DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format /* |
4304 *Format in which to write auto-save files. | 4370 *Format in which to write auto-save files. |
4305 Should be a list of symbols naming formats that are defined in `format-alist'. | 4371 Should be a list of symbols naming formats that are defined in `format-alist'. |
4306 If it is t, which is the default, auto-save files are written in the | 4372 If it is t, which is the default, auto-save files are written in the |
4307 same format as a regular save would use. | 4373 same format as a regular save would use. |