diff options
| author | Stephen Leake | 2019-09-18 17:43:28 -0700 |
|---|---|---|
| committer | Stephen Leake | 2019-09-18 17:43:28 -0700 |
| commit | 34f1035e878a06ad181ff7fc533cd1fa0a565847 (patch) | |
| tree | 7708b0e62b09571ba5b2c625d810cd932c380508 /src/fileio.c | |
| parent | b478444099655f36f7b243e21e8f98051299ca8f (diff) | |
| parent | 107ce3050fc37b9a13d8304ae1bb73fac9de5f61 (diff) | |
| download | emacs-34f1035e878a06ad181ff7fc533cd1fa0a565847.tar.gz emacs-34f1035e878a06ad181ff7fc533cd1fa0a565847.zip | |
Merge commit '107ce3050fc37b9a13d8304ae1bb73fac9de5f61'
Diffstat (limited to 'src/fileio.c')
| -rw-r--r-- | src/fileio.c | 480 |
1 files changed, 276 insertions, 204 deletions
diff --git a/src/fileio.c b/src/fileio.c index 968a55e5956..5337ea5c800 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -134,60 +134,45 @@ static dev_t timestamp_file_system; | |||
| 134 | is added here. */ | 134 | is added here. */ |
| 135 | static Lisp_Object Vwrite_region_annotation_buffers; | 135 | static Lisp_Object Vwrite_region_annotation_buffers; |
| 136 | 136 | ||
| 137 | static Lisp_Object file_name_directory (Lisp_Object); | ||
| 137 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 138 | static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| 138 | Lisp_Object *, struct coding_system *); | 139 | Lisp_Object *, struct coding_system *); |
| 139 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | 140 | static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, |
| 140 | struct coding_system *); | 141 | struct coding_system *); |
| 141 | 142 | ||
| 142 | 143 | ||
| 143 | /* Return true if FILENAME exists, otherwise return false and set errno. */ | 144 | /* Test whether FILE is accessible for AMODE. |
| 145 | Return true if successful, false (setting errno) otherwise. */ | ||
| 144 | 146 | ||
| 145 | static bool | 147 | bool |
| 146 | check_existing (const char *filename) | 148 | file_access_p (char const *file, int amode) |
| 147 | { | ||
| 148 | return faccessat (AT_FDCWD, filename, F_OK, AT_EACCESS) == 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | /* Return true if file FILENAME exists and can be executed. */ | ||
| 152 | |||
| 153 | static bool | ||
| 154 | check_executable (char *filename) | ||
| 155 | { | ||
| 156 | return faccessat (AT_FDCWD, filename, X_OK, AT_EACCESS) == 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | /* Return true if file FILENAME exists and can be accessed | ||
| 160 | according to AMODE, which should include W_OK. | ||
| 161 | On failure, return false and set errno. */ | ||
| 162 | |||
| 163 | static bool | ||
| 164 | check_writable (const char *filename, int amode) | ||
| 165 | { | 149 | { |
| 166 | #ifdef MSDOS | 150 | #ifdef MSDOS |
| 167 | /* FIXME: an faccessat implementation should be added to the | 151 | if (amode & W_OK) |
| 168 | DOS/Windows ports and this #ifdef branch should be removed. */ | ||
| 169 | struct stat st; | ||
| 170 | if (stat (filename, &st) < 0) | ||
| 171 | return 0; | ||
| 172 | errno = EPERM; | ||
| 173 | return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode)); | ||
| 174 | #else /* not MSDOS */ | ||
| 175 | bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0; | ||
| 176 | #ifdef CYGWIN | ||
| 177 | /* faccessat may have returned failure because Cygwin couldn't | ||
| 178 | determine the file's UID or GID; if so, we return success. */ | ||
| 179 | if (!res) | ||
| 180 | { | 152 | { |
| 181 | int faccessat_errno = errno; | 153 | /* FIXME: The MS-DOS faccessat implementation should handle this. */ |
| 182 | struct stat st; | 154 | struct stat st; |
| 183 | if (stat (filename, &st) < 0) | 155 | if (stat (file, &st) != 0) |
| 184 | return 0; | 156 | return false; |
| 185 | res = (st.st_uid == -1 || st.st_gid == -1); | 157 | errno = EPERM; |
| 186 | errno = faccessat_errno; | 158 | return st.st_mode & S_IWRITE || S_ISDIR (st.st_mode); |
| 187 | } | 159 | } |
| 188 | #endif /* CYGWIN */ | 160 | #endif |
| 189 | return res; | 161 | |
| 190 | #endif /* not MSDOS */ | 162 | if (faccessat (AT_FDCWD, file, amode, AT_EACCESS) == 0) |
| 163 | return true; | ||
| 164 | |||
| 165 | #ifdef CYGWIN | ||
| 166 | /* Return success if faccessat failed because Cygwin couldn't | ||
| 167 | determine the file's UID or GID. */ | ||
| 168 | int err = errno; | ||
| 169 | struct stat st; | ||
| 170 | if (stat (file, &st) == 0 && (st.st_uid == -1 || st.st_gid == -1)) | ||
| 171 | return true; | ||
| 172 | errno = err; | ||
| 173 | #endif | ||
| 174 | |||
| 175 | return false; | ||
| 191 | } | 176 | } |
| 192 | 177 | ||
| 193 | /* Signal a file-access failure. STRING describes the failure, | 178 | /* Signal a file-access failure. STRING describes the failure, |
| @@ -250,6 +235,44 @@ report_file_notify_error (const char *string, Lisp_Object name) | |||
| 250 | } | 235 | } |
| 251 | #endif | 236 | #endif |
| 252 | 237 | ||
| 238 | /* ACTION failed for FILE with errno ERR. Signal an error if ERR | ||
| 239 | means the file's metadata could not be retrieved even though it may | ||
| 240 | exist, otherwise return nil. */ | ||
| 241 | |||
| 242 | static Lisp_Object | ||
| 243 | file_metadata_errno (char const *action, Lisp_Object file, int err) | ||
| 244 | { | ||
| 245 | if (err == ENOENT || err == ENOTDIR || err == 0) | ||
| 246 | return Qnil; | ||
| 247 | report_file_errno (action, file, err); | ||
| 248 | } | ||
| 249 | |||
| 250 | Lisp_Object | ||
| 251 | file_attribute_errno (Lisp_Object file, int err) | ||
| 252 | { | ||
| 253 | return file_metadata_errno ("Getting attributes", file, err); | ||
| 254 | } | ||
| 255 | |||
| 256 | /* In theory, EACCES errors for predicates like file-readable-p should | ||
| 257 | be checked further because they may be problems with an ancestor | ||
| 258 | directory instead of with the file itself, which means that we | ||
| 259 | don't have reliable info about the requested file. In practice, | ||
| 260 | though, such errors are common enough that signaling them can be | ||
| 261 | annoying even if the errors are real (e.g., Bug#37445). So return | ||
| 262 | nil for EACCES unless compiling with -DPICKY_EACCES, which is off | ||
| 263 | by default. */ | ||
| 264 | #ifndef PICKY_EACCES | ||
| 265 | enum { PICKY_EACCES = false }; | ||
| 266 | #endif | ||
| 267 | |||
| 268 | Lisp_Object | ||
| 269 | file_test_errno (Lisp_Object file, int err) | ||
| 270 | { | ||
| 271 | if (!PICKY_EACCES && err == EACCES) | ||
| 272 | return Qnil; | ||
| 273 | return file_metadata_errno ("Testing file", file, err); | ||
| 274 | } | ||
| 275 | |||
| 253 | void | 276 | void |
| 254 | close_file_unwind (int fd) | 277 | close_file_unwind (int fd) |
| 255 | { | 278 | { |
| @@ -356,6 +379,15 @@ Given a Unix syntax file name, returns a string ending in slash. */) | |||
| 356 | return STRINGP (handled_name) ? handled_name : Qnil; | 379 | return STRINGP (handled_name) ? handled_name : Qnil; |
| 357 | } | 380 | } |
| 358 | 381 | ||
| 382 | return file_name_directory (filename); | ||
| 383 | } | ||
| 384 | |||
| 385 | /* Return the directory component of FILENAME, or nil if FILENAME does | ||
| 386 | not contain a directory component. */ | ||
| 387 | |||
| 388 | static Lisp_Object | ||
| 389 | file_name_directory (Lisp_Object filename) | ||
| 390 | { | ||
| 359 | char *beg = SSDATA (filename); | 391 | char *beg = SSDATA (filename); |
| 360 | char const *p = beg + SBYTES (filename); | 392 | char const *p = beg + SBYTES (filename); |
| 361 | 393 | ||
| @@ -2369,41 +2401,48 @@ internal_delete_file (Lisp_Object filename) | |||
| 2369 | return NILP (tem); | 2401 | return NILP (tem); |
| 2370 | } | 2402 | } |
| 2371 | 2403 | ||
| 2372 | /* Filesystems are case-sensitive on all supported systems except | 2404 | /* Return -1 if FILE is a case-insensitive file name, 0 if not, |
| 2373 | MS-Windows, MS-DOS, Cygwin, and Mac OS X. They are always | 2405 | and a positive errno value if the result cannot be determined. */ |
| 2374 | case-insensitive on the first two, but they may or may not be | ||
| 2375 | case-insensitive on Cygwin and OS X. The following function | ||
| 2376 | attempts to provide a runtime test on those two systems. If the | ||
| 2377 | test is not conclusive, we assume case-insensitivity on Cygwin and | ||
| 2378 | case-sensitivity on Mac OS X. | ||
| 2379 | |||
| 2380 | FIXME: Mounted filesystems on Posix hosts, like Samba shares or | ||
| 2381 | NFS-mounted Windows volumes, might be case-insensitive. Can we | ||
| 2382 | detect this? */ | ||
| 2383 | 2406 | ||
| 2384 | static bool | 2407 | static int |
| 2385 | file_name_case_insensitive_p (const char *filename) | 2408 | file_name_case_insensitive_err (Lisp_Object file) |
| 2386 | { | 2409 | { |
| 2387 | /* Use pathconf with _PC_CASE_INSENSITIVE or _PC_CASE_SENSITIVE if | 2410 | /* Filesystems are case-sensitive on all supported systems except |
| 2388 | those flags are available. As of this writing (2017-05-20), | 2411 | MS-Windows, MS-DOS, Cygwin, and macOS. They are always |
| 2412 | case-insensitive on the first two, but they may or may not be | ||
| 2413 | case-insensitive on Cygwin and macOS so do a runtime test on | ||
| 2414 | those two systems. If the test is not conclusive, assume | ||
| 2415 | case-insensitivity on Cygwin and case-sensitivity on macOS. | ||
| 2416 | |||
| 2417 | FIXME: Mounted filesystems on Posix hosts, like Samba shares or | ||
| 2418 | NFS-mounted Windows volumes, might be case-insensitive. Can we | ||
| 2419 | detect this? | ||
| 2420 | |||
| 2421 | Use pathconf with _PC_CASE_INSENSITIVE or _PC_CASE_SENSITIVE if | ||
| 2422 | those flags are available. As of this writing (2019-09-15), | ||
| 2389 | Cygwin is the only platform known to support the former (starting | 2423 | Cygwin is the only platform known to support the former (starting |
| 2390 | with Cygwin-2.6.1), and macOS is the only platform known to | 2424 | with Cygwin-2.6.1), and macOS is the only platform known to |
| 2391 | support the latter. */ | 2425 | support the latter. */ |
| 2392 | 2426 | ||
| 2393 | #ifdef _PC_CASE_INSENSITIVE | 2427 | #if defined _PC_CASE_INSENSITIVE || defined _PC_CASE_SENSITIVE |
| 2394 | int res = pathconf (filename, _PC_CASE_INSENSITIVE); | 2428 | char *filename = SSDATA (ENCODE_FILE (file)); |
| 2429 | # ifdef _PC_CASE_INSENSITIVE | ||
| 2430 | long int res = pathconf (filename, _PC_CASE_INSENSITIVE); | ||
| 2395 | if (res >= 0) | 2431 | if (res >= 0) |
| 2396 | return res > 0; | 2432 | return - (res > 0); |
| 2397 | #elif defined _PC_CASE_SENSITIVE | 2433 | # else |
| 2398 | int res = pathconf (filename, _PC_CASE_SENSITIVE); | 2434 | long int res = pathconf (filename, _PC_CASE_SENSITIVE); |
| 2399 | if (res >= 0) | 2435 | if (res >= 0) |
| 2400 | return res == 0; | 2436 | return - (res == 0); |
| 2437 | # endif | ||
| 2438 | if (errno != EINVAL) | ||
| 2439 | return errno; | ||
| 2401 | #endif | 2440 | #endif |
| 2402 | 2441 | ||
| 2403 | #if defined CYGWIN || defined DOS_NT | 2442 | #if defined CYGWIN || defined DOS_NT |
| 2404 | return true; | 2443 | return -1; |
| 2405 | #else | 2444 | #else |
| 2406 | return false; | 2445 | return 0; |
| 2407 | #endif | 2446 | #endif |
| 2408 | } | 2447 | } |
| 2409 | 2448 | ||
| @@ -2426,21 +2465,22 @@ The arg must be a string. */) | |||
| 2426 | 2465 | ||
| 2427 | /* If the file doesn't exist, move up the filesystem tree until we | 2466 | /* If the file doesn't exist, move up the filesystem tree until we |
| 2428 | reach an existing directory or the root. */ | 2467 | reach an existing directory or the root. */ |
| 2429 | if (NILP (Ffile_exists_p (filename))) | 2468 | while (true) |
| 2430 | { | 2469 | { |
| 2431 | filename = Ffile_name_directory (filename); | 2470 | int err = file_name_case_insensitive_err (filename); |
| 2432 | while (NILP (Ffile_exists_p (filename))) | 2471 | switch (err) |
| 2433 | { | 2472 | { |
| 2434 | Lisp_Object newname = expand_and_dir_to_file (filename); | 2473 | case -1: return Qt; |
| 2435 | /* Avoid infinite loop if the root is reported as non-existing | 2474 | default: return file_test_errno (filename, err); |
| 2436 | (impossible?). */ | 2475 | case ENOENT: case ENOTDIR: break; |
| 2437 | if (!NILP (Fstring_equal (newname, filename))) | ||
| 2438 | break; | ||
| 2439 | filename = newname; | ||
| 2440 | } | 2476 | } |
| 2477 | Lisp_Object parent = file_name_directory (filename); | ||
| 2478 | /* Avoid infinite loop if the root is reported as non-existing | ||
| 2479 | (impossible?). */ | ||
| 2480 | if (!NILP (Fstring_equal (parent, filename))) | ||
| 2481 | return Qnil; | ||
| 2482 | filename = parent; | ||
| 2441 | } | 2483 | } |
| 2442 | filename = ENCODE_FILE (filename); | ||
| 2443 | return file_name_case_insensitive_p (SSDATA (filename)) ? Qt : Qnil; | ||
| 2444 | } | 2484 | } |
| 2445 | 2485 | ||
| 2446 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, | 2486 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, |
| @@ -2546,7 +2586,7 @@ This is what happens in interactive use with M-x. */) | |||
| 2546 | { | 2586 | { |
| 2547 | Lisp_Object symlink_target | 2587 | Lisp_Object symlink_target |
| 2548 | = (S_ISLNK (file_st.st_mode) | 2588 | = (S_ISLNK (file_st.st_mode) |
| 2549 | ? emacs_readlinkat (AT_FDCWD, SSDATA (encoded_file)) | 2589 | ? check_emacs_readlinkat (AT_FDCWD, file, SSDATA (encoded_file)) |
| 2550 | : Qnil); | 2590 | : Qnil); |
| 2551 | if (!NILP (symlink_target)) | 2591 | if (!NILP (symlink_target)) |
| 2552 | Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists); | 2592 | Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists); |
| @@ -2694,32 +2734,48 @@ file_name_absolute_p (char const *filename) | |||
| 2694 | || user_homedir (&filename[1])))); | 2734 | || user_homedir (&filename[1])))); |
| 2695 | } | 2735 | } |
| 2696 | 2736 | ||
| 2697 | DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, | 2737 | /* Return t if FILE exists and is accessible via OPERATION and AMODE, |
| 2698 | doc: /* Return t if file FILENAME exists (whether or not you can read it). | 2738 | nil (setting errno) if not. Signal an error if the result cannot |
| 2699 | See also `file-readable-p' and `file-attributes'. | 2739 | be determined. */ |
| 2700 | This returns nil for a symlink to a nonexistent file. | ||
| 2701 | Use `file-symlink-p' to test for such links. */) | ||
| 2702 | (Lisp_Object filename) | ||
| 2703 | { | ||
| 2704 | Lisp_Object absname; | ||
| 2705 | Lisp_Object handler; | ||
| 2706 | 2740 | ||
| 2707 | CHECK_STRING (filename); | 2741 | static Lisp_Object |
| 2708 | absname = Fexpand_file_name (filename, Qnil); | 2742 | check_file_access (Lisp_Object file, Lisp_Object operation, int amode) |
| 2709 | 2743 | { | |
| 2710 | /* If the file name has special constructs in it, | 2744 | file = Fexpand_file_name (file, Qnil); |
| 2711 | call the corresponding file name handler. */ | 2745 | Lisp_Object handler = Ffind_file_name_handler (file, operation); |
| 2712 | handler = Ffind_file_name_handler (absname, Qfile_exists_p); | ||
| 2713 | if (!NILP (handler)) | 2746 | if (!NILP (handler)) |
| 2714 | { | 2747 | { |
| 2715 | Lisp_Object result = call2 (handler, Qfile_exists_p, absname); | 2748 | Lisp_Object ok = call2 (handler, operation, file); |
| 2749 | /* This errno value is bogus. Any caller that depends on errno | ||
| 2750 | should be rethought anyway, to avoid a race between testing a | ||
| 2751 | handled file's accessibility and using the file. */ | ||
| 2716 | errno = 0; | 2752 | errno = 0; |
| 2717 | return result; | 2753 | return ok; |
| 2718 | } | 2754 | } |
| 2719 | 2755 | ||
| 2720 | absname = ENCODE_FILE (absname); | 2756 | char *encoded_file = SSDATA (ENCODE_FILE (file)); |
| 2757 | bool ok = file_access_p (encoded_file, amode); | ||
| 2758 | if (ok) | ||
| 2759 | return Qt; | ||
| 2760 | int err = errno; | ||
| 2761 | if (err == EROFS || err == ETXTBSY | ||
| 2762 | || (PICKY_EACCES && err == EACCES && amode != F_OK | ||
| 2763 | && file_access_p (encoded_file, F_OK))) | ||
| 2764 | { | ||
| 2765 | errno = err; | ||
| 2766 | return Qnil; | ||
| 2767 | } | ||
| 2768 | return file_test_errno (file, err); | ||
| 2769 | } | ||
| 2721 | 2770 | ||
| 2722 | return check_existing (SSDATA (absname)) ? Qt : Qnil; | 2771 | DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, |
| 2772 | doc: /* Return t if file FILENAME exists (whether or not you can read it). | ||
| 2773 | See also `file-readable-p' and `file-attributes'. | ||
| 2774 | This returns nil for a symlink to a nonexistent file. | ||
| 2775 | Use `file-symlink-p' to test for such links. */) | ||
| 2776 | (Lisp_Object filename) | ||
| 2777 | { | ||
| 2778 | return check_file_access (filename, Qfile_exists_p, F_OK); | ||
| 2723 | } | 2779 | } |
| 2724 | 2780 | ||
| 2725 | DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0, | 2781 | DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0, |
| @@ -2729,21 +2785,7 @@ For a directory, this means you can access files in that directory. | |||
| 2729 | purpose, though.) */) | 2785 | purpose, though.) */) |
| 2730 | (Lisp_Object filename) | 2786 | (Lisp_Object filename) |
| 2731 | { | 2787 | { |
| 2732 | Lisp_Object absname; | 2788 | return check_file_access (filename, Qfile_executable_p, X_OK); |
| 2733 | Lisp_Object handler; | ||
| 2734 | |||
| 2735 | CHECK_STRING (filename); | ||
| 2736 | absname = Fexpand_file_name (filename, Qnil); | ||
| 2737 | |||
| 2738 | /* If the file name has special constructs in it, | ||
| 2739 | call the corresponding file name handler. */ | ||
| 2740 | handler = Ffind_file_name_handler (absname, Qfile_executable_p); | ||
| 2741 | if (!NILP (handler)) | ||
| 2742 | return call2 (handler, Qfile_executable_p, absname); | ||
| 2743 | |||
| 2744 | absname = ENCODE_FILE (absname); | ||
| 2745 | |||
| 2746 | return (check_executable (SSDATA (absname)) ? Qt : Qnil); | ||
| 2747 | } | 2789 | } |
| 2748 | 2790 | ||
| 2749 | DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, | 2791 | DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, |
| @@ -2751,21 +2793,7 @@ DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, | |||
| 2751 | See also `file-exists-p' and `file-attributes'. */) | 2793 | See also `file-exists-p' and `file-attributes'. */) |
| 2752 | (Lisp_Object filename) | 2794 | (Lisp_Object filename) |
| 2753 | { | 2795 | { |
| 2754 | Lisp_Object absname; | 2796 | return check_file_access (filename, Qfile_readable_p, R_OK); |
| 2755 | Lisp_Object handler; | ||
| 2756 | |||
| 2757 | CHECK_STRING (filename); | ||
| 2758 | absname = Fexpand_file_name (filename, Qnil); | ||
| 2759 | |||
| 2760 | /* If the file name has special constructs in it, | ||
| 2761 | call the corresponding file name handler. */ | ||
| 2762 | handler = Ffind_file_name_handler (absname, Qfile_readable_p); | ||
| 2763 | if (!NILP (handler)) | ||
| 2764 | return call2 (handler, Qfile_readable_p, absname); | ||
| 2765 | |||
| 2766 | absname = ENCODE_FILE (absname); | ||
| 2767 | return (faccessat (AT_FDCWD, SSDATA (absname), R_OK, AT_EACCESS) == 0 | ||
| 2768 | ? Qt : Qnil); | ||
| 2769 | } | 2797 | } |
| 2770 | 2798 | ||
| 2771 | DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | 2799 | DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, |
| @@ -2775,7 +2803,6 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2775 | Lisp_Object absname, dir, encoded; | 2803 | Lisp_Object absname, dir, encoded; |
| 2776 | Lisp_Object handler; | 2804 | Lisp_Object handler; |
| 2777 | 2805 | ||
| 2778 | CHECK_STRING (filename); | ||
| 2779 | absname = Fexpand_file_name (filename, Qnil); | 2806 | absname = Fexpand_file_name (filename, Qnil); |
| 2780 | 2807 | ||
| 2781 | /* If the file name has special constructs in it, | 2808 | /* If the file name has special constructs in it, |
| @@ -2785,25 +2812,34 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2785 | return call2 (handler, Qfile_writable_p, absname); | 2812 | return call2 (handler, Qfile_writable_p, absname); |
| 2786 | 2813 | ||
| 2787 | encoded = ENCODE_FILE (absname); | 2814 | encoded = ENCODE_FILE (absname); |
| 2788 | if (check_writable (SSDATA (encoded), W_OK)) | 2815 | if (file_access_p (SSDATA (encoded), W_OK)) |
| 2789 | return Qt; | 2816 | return Qt; |
| 2790 | if (errno != ENOENT) | 2817 | if (errno != ENOENT) |
| 2791 | return Qnil; | 2818 | return Qnil; |
| 2792 | 2819 | ||
| 2793 | dir = Ffile_name_directory (absname); | 2820 | dir = file_name_directory (absname); |
| 2794 | eassert (!NILP (dir)); | 2821 | eassert (!NILP (dir)); |
| 2795 | #ifdef MSDOS | 2822 | #ifdef MSDOS |
| 2796 | dir = Fdirectory_file_name (dir); | 2823 | dir = Fdirectory_file_name (dir); |
| 2797 | #endif /* MSDOS */ | 2824 | #endif /* MSDOS */ |
| 2798 | 2825 | ||
| 2799 | dir = ENCODE_FILE (dir); | 2826 | encoded = ENCODE_FILE (dir); |
| 2800 | #ifdef WINDOWSNT | 2827 | #ifdef WINDOWSNT |
| 2801 | /* The read-only attribute of the parent directory doesn't affect | 2828 | /* The read-only attribute of the parent directory doesn't affect |
| 2802 | whether a file or directory can be created within it. Some day we | 2829 | whether a file or directory can be created within it. Some day we |
| 2803 | should check ACLs though, which do affect this. */ | 2830 | should check ACLs though, which do affect this. */ |
| 2804 | return file_directory_p (dir) ? Qt : Qnil; | 2831 | return file_directory_p (encoded) ? Qt : Qnil; |
| 2805 | #else | 2832 | #else |
| 2806 | return check_writable (SSDATA (dir), W_OK | X_OK) ? Qt : Qnil; | 2833 | if (file_access_p (SSDATA (encoded), W_OK | X_OK)) |
| 2834 | return Qt; | ||
| 2835 | int err = errno; | ||
| 2836 | if (err == EROFS | ||
| 2837 | || (err == EACCES && file_access_p (SSDATA (encoded), F_OK))) | ||
| 2838 | { | ||
| 2839 | errno = err; | ||
| 2840 | return Qnil; | ||
| 2841 | } | ||
| 2842 | return file_test_errno (absname, err); | ||
| 2807 | #endif | 2843 | #endif |
| 2808 | } | 2844 | } |
| 2809 | 2845 | ||
| @@ -2835,8 +2871,8 @@ If there is no error, returns nil. */) | |||
| 2835 | } | 2871 | } |
| 2836 | 2872 | ||
| 2837 | /* Relative to directory FD, return the symbolic link value of FILENAME. | 2873 | /* Relative to directory FD, return the symbolic link value of FILENAME. |
| 2838 | On failure, return nil. */ | 2874 | On failure, return nil (setting errno). */ |
| 2839 | Lisp_Object | 2875 | static Lisp_Object |
| 2840 | emacs_readlinkat (int fd, char const *filename) | 2876 | emacs_readlinkat (int fd, char const *filename) |
| 2841 | { | 2877 | { |
| 2842 | static struct allocator const emacs_norealloc_allocator = | 2878 | static struct allocator const emacs_norealloc_allocator = |
| @@ -2855,6 +2891,27 @@ emacs_readlinkat (int fd, char const *filename) | |||
| 2855 | return val; | 2891 | return val; |
| 2856 | } | 2892 | } |
| 2857 | 2893 | ||
| 2894 | /* Relative to directory FD, return the symbolic link value of FILE. | ||
| 2895 | If FILE is not a symbolic link, return nil (setting errno). | ||
| 2896 | Signal an error if the result cannot be determined. */ | ||
| 2897 | Lisp_Object | ||
| 2898 | check_emacs_readlinkat (int fd, Lisp_Object file, char const *encoded_file) | ||
| 2899 | { | ||
| 2900 | Lisp_Object val = emacs_readlinkat (fd, encoded_file); | ||
| 2901 | if (NILP (val)) | ||
| 2902 | { | ||
| 2903 | if (errno == EINVAL) | ||
| 2904 | return val; | ||
| 2905 | #ifdef CYGWIN | ||
| 2906 | /* Work around Cygwin bugs. */ | ||
| 2907 | if (errno == EIO || errno == EACCES) | ||
| 2908 | return val; | ||
| 2909 | #endif | ||
| 2910 | return file_metadata_errno ("Reading symbolic link", file, errno); | ||
| 2911 | } | ||
| 2912 | return val; | ||
| 2913 | } | ||
| 2914 | |||
| 2858 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, | 2915 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, |
| 2859 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. | 2916 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. |
| 2860 | The value is the link target, as a string. | 2917 | The value is the link target, as a string. |
| @@ -2874,9 +2931,8 @@ This function does not check whether the link target exists. */) | |||
| 2874 | if (!NILP (handler)) | 2931 | if (!NILP (handler)) |
| 2875 | return call2 (handler, Qfile_symlink_p, filename); | 2932 | return call2 (handler, Qfile_symlink_p, filename); |
| 2876 | 2933 | ||
| 2877 | filename = ENCODE_FILE (filename); | 2934 | return check_emacs_readlinkat (AT_FDCWD, filename, |
| 2878 | 2935 | SSDATA (ENCODE_FILE (filename))); | |
| 2879 | return emacs_readlinkat (AT_FDCWD, SSDATA (filename)); | ||
| 2880 | } | 2936 | } |
| 2881 | 2937 | ||
| 2882 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, | 2938 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, |
| @@ -2893,9 +2949,9 @@ See `file-symlink-p' to distinguish symlinks. */) | |||
| 2893 | if (!NILP (handler)) | 2949 | if (!NILP (handler)) |
| 2894 | return call2 (handler, Qfile_directory_p, absname); | 2950 | return call2 (handler, Qfile_directory_p, absname); |
| 2895 | 2951 | ||
| 2896 | absname = ENCODE_FILE (absname); | 2952 | if (file_directory_p (absname)) |
| 2897 | 2953 | return Qt; | |
| 2898 | return file_directory_p (absname) ? Qt : Qnil; | 2954 | return file_test_errno (absname, errno); |
| 2899 | } | 2955 | } |
| 2900 | 2956 | ||
| 2901 | /* Return true if FILE is a directory or a symlink to a directory. | 2957 | /* Return true if FILE is a directory or a symlink to a directory. |
| @@ -2905,7 +2961,10 @@ file_directory_p (Lisp_Object file) | |||
| 2905 | { | 2961 | { |
| 2906 | #ifdef DOS_NT | 2962 | #ifdef DOS_NT |
| 2907 | /* This is cheaper than 'stat'. */ | 2963 | /* This is cheaper than 'stat'. */ |
| 2908 | return faccessat (AT_FDCWD, SSDATA (file), D_OK, AT_EACCESS) == 0; | 2964 | bool retval = faccessat (AT_FDCWD, SSDATA (file), D_OK, AT_EACCESS) == 0; |
| 2965 | if (!retval && errno == EACCES) | ||
| 2966 | errno = ENOTDIR; /* like the non-DOS_NT branch below does */ | ||
| 2967 | return retval; | ||
| 2909 | #else | 2968 | #else |
| 2910 | # ifdef O_PATH | 2969 | # ifdef O_PATH |
| 2911 | /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ | 2970 | /* Use O_PATH if available, as it avoids races and EOVERFLOW issues. */ |
| @@ -2920,7 +2979,7 @@ file_directory_p (Lisp_Object file) | |||
| 2920 | /* O_PATH is defined but evidently this Linux kernel predates 2.6.39. | 2979 | /* O_PATH is defined but evidently this Linux kernel predates 2.6.39. |
| 2921 | Fall back on generic POSIX code. */ | 2980 | Fall back on generic POSIX code. */ |
| 2922 | # endif | 2981 | # endif |
| 2923 | /* Use file_accessible_directory, as it avoids stat EOVERFLOW | 2982 | /* Use file_accessible_directory_p, as it avoids stat EOVERFLOW |
| 2924 | problems and could be cheaper. However, if it fails because FILE | 2983 | problems and could be cheaper. However, if it fails because FILE |
| 2925 | is inaccessible, fall back on stat; if the latter fails with | 2984 | is inaccessible, fall back on stat; if the latter fails with |
| 2926 | EOVERFLOW then FILE must have been a directory unless a race | 2985 | EOVERFLOW then FILE must have been a directory unless a race |
| @@ -2976,8 +3035,13 @@ really is a readable and searchable directory. */) | |||
| 2976 | return r; | 3035 | return r; |
| 2977 | } | 3036 | } |
| 2978 | 3037 | ||
| 2979 | absname = ENCODE_FILE (absname); | 3038 | Lisp_Object encoded_absname = ENCODE_FILE (absname); |
| 2980 | return file_accessible_directory_p (absname) ? Qt : Qnil; | 3039 | if (file_accessible_directory_p (encoded_absname)) |
| 3040 | return Qt; | ||
| 3041 | int err = errno; | ||
| 3042 | if (err == EACCES && file_access_p (SSDATA (encoded_absname), F_OK)) | ||
| 3043 | return Qnil; | ||
| 3044 | return file_test_errno (absname, err); | ||
| 2981 | } | 3045 | } |
| 2982 | 3046 | ||
| 2983 | /* If FILE is a searchable directory or a symlink to a | 3047 | /* If FILE is a searchable directory or a symlink to a |
| @@ -3029,7 +3093,7 @@ file_accessible_directory_p (Lisp_Object file) | |||
| 3029 | dir = buf; | 3093 | dir = buf; |
| 3030 | } | 3094 | } |
| 3031 | 3095 | ||
| 3032 | ok = check_existing (dir); | 3096 | ok = file_access_p (dir, F_OK); |
| 3033 | saved_errno = errno; | 3097 | saved_errno = errno; |
| 3034 | SAFE_FREE (); | 3098 | SAFE_FREE (); |
| 3035 | errno = saved_errno; | 3099 | errno = saved_errno; |
| @@ -3053,27 +3117,21 @@ See `file-symlink-p' to distinguish symlinks. */) | |||
| 3053 | if (!NILP (handler)) | 3117 | if (!NILP (handler)) |
| 3054 | return call2 (handler, Qfile_regular_p, absname); | 3118 | return call2 (handler, Qfile_regular_p, absname); |
| 3055 | 3119 | ||
| 3056 | absname = ENCODE_FILE (absname); | ||
| 3057 | |||
| 3058 | #ifdef WINDOWSNT | 3120 | #ifdef WINDOWSNT |
| 3059 | { | 3121 | /* Tell stat to use expensive method to get accurate info. */ |
| 3060 | int result; | 3122 | Lisp_Object true_attributes = Vw32_get_true_file_attributes; |
| 3061 | Lisp_Object tem = Vw32_get_true_file_attributes; | 3123 | Vw32_get_true_file_attributes = Qt; |
| 3124 | #endif | ||
| 3062 | 3125 | ||
| 3063 | /* Tell stat to use expensive method to get accurate info. */ | 3126 | int stat_result = stat (SSDATA (absname), &st); |
| 3064 | Vw32_get_true_file_attributes = Qt; | ||
| 3065 | result = stat (SSDATA (absname), &st); | ||
| 3066 | Vw32_get_true_file_attributes = tem; | ||
| 3067 | 3127 | ||
| 3068 | if (result < 0) | 3128 | #ifdef WINDOWSNT |
| 3069 | return Qnil; | 3129 | Vw32_get_true_file_attributes = true_attributes; |
| 3070 | return S_ISREG (st.st_mode) ? Qt : Qnil; | ||
| 3071 | } | ||
| 3072 | #else | ||
| 3073 | if (stat (SSDATA (absname), &st) < 0) | ||
| 3074 | return Qnil; | ||
| 3075 | return S_ISREG (st.st_mode) ? Qt : Qnil; | ||
| 3076 | #endif | 3130 | #endif |
| 3131 | |||
| 3132 | if (stat_result == 0) | ||
| 3133 | return S_ISREG (st.st_mode) ? Qt : Qnil; | ||
| 3134 | return file_test_errno (absname, errno); | ||
| 3077 | } | 3135 | } |
| 3078 | 3136 | ||
| 3079 | DEFUN ("file-selinux-context", Ffile_selinux_context, | 3137 | DEFUN ("file-selinux-context", Ffile_selinux_context, |
| @@ -3083,7 +3141,7 @@ The return value is a list (USER ROLE TYPE RANGE), where the list | |||
| 3083 | elements are strings naming the user, role, type, and range of the | 3141 | elements are strings naming the user, role, type, and range of the |
| 3084 | file's SELinux security context. | 3142 | file's SELinux security context. |
| 3085 | 3143 | ||
| 3086 | Return (nil nil nil nil) if the file is nonexistent or inaccessible, | 3144 | Return (nil nil nil nil) if the file is nonexistent, |
| 3087 | or if SELinux is disabled, or if Emacs lacks SELinux support. */) | 3145 | or if SELinux is disabled, or if Emacs lacks SELinux support. */) |
| 3088 | (Lisp_Object filename) | 3146 | (Lisp_Object filename) |
| 3089 | { | 3147 | { |
| @@ -3097,13 +3155,11 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */) | |||
| 3097 | if (!NILP (handler)) | 3155 | if (!NILP (handler)) |
| 3098 | return call2 (handler, Qfile_selinux_context, absname); | 3156 | return call2 (handler, Qfile_selinux_context, absname); |
| 3099 | 3157 | ||
| 3100 | absname = ENCODE_FILE (absname); | ||
| 3101 | |||
| 3102 | #if HAVE_LIBSELINUX | 3158 | #if HAVE_LIBSELINUX |
| 3103 | if (is_selinux_enabled ()) | 3159 | if (is_selinux_enabled ()) |
| 3104 | { | 3160 | { |
| 3105 | security_context_t con; | 3161 | security_context_t con; |
| 3106 | int conlength = lgetfilecon (SSDATA (absname), &con); | 3162 | int conlength = lgetfilecon (SSDATA (ENCODE_FILE (absname)), &con); |
| 3107 | if (conlength > 0) | 3163 | if (conlength > 0) |
| 3108 | { | 3164 | { |
| 3109 | context_t context = context_new (con); | 3165 | context_t context = context_new (con); |
| @@ -3118,6 +3174,9 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */) | |||
| 3118 | context_free (context); | 3174 | context_free (context); |
| 3119 | freecon (con); | 3175 | freecon (con); |
| 3120 | } | 3176 | } |
| 3177 | else if (! (errno == ENOENT || errno == ENOTDIR || errno == ENODATA | ||
| 3178 | || errno == ENOTSUP)) | ||
| 3179 | report_file_error ("getting SELinux context", absname); | ||
| 3121 | } | 3180 | } |
| 3122 | #endif | 3181 | #endif |
| 3123 | 3182 | ||
| @@ -3213,8 +3272,7 @@ DEFUN ("file-acl", Ffile_acl, Sfile_acl, 1, 1, 0, | |||
| 3213 | doc: /* Return ACL entries of file named FILENAME. | 3272 | doc: /* Return ACL entries of file named FILENAME. |
| 3214 | The entries are returned in a format suitable for use in `set-file-acl' | 3273 | The entries are returned in a format suitable for use in `set-file-acl' |
| 3215 | but is otherwise undocumented and subject to change. | 3274 | but is otherwise undocumented and subject to change. |
| 3216 | Return nil if file does not exist or is not accessible, or if Emacs | 3275 | Return nil if file does not exist. */) |
| 3217 | was unable to determine the ACL entries. */) | ||
| 3218 | (Lisp_Object filename) | 3276 | (Lisp_Object filename) |
| 3219 | { | 3277 | { |
| 3220 | Lisp_Object acl_string = Qnil; | 3278 | Lisp_Object acl_string = Qnil; |
| @@ -3229,20 +3287,22 @@ was unable to determine the ACL entries. */) | |||
| 3229 | return call2 (handler, Qfile_acl, absname); | 3287 | return call2 (handler, Qfile_acl, absname); |
| 3230 | 3288 | ||
| 3231 | # ifdef HAVE_ACL_SET_FILE | 3289 | # ifdef HAVE_ACL_SET_FILE |
| 3232 | absname = ENCODE_FILE (absname); | ||
| 3233 | |||
| 3234 | # ifndef HAVE_ACL_TYPE_EXTENDED | 3290 | # ifndef HAVE_ACL_TYPE_EXTENDED |
| 3235 | acl_type_t ACL_TYPE_EXTENDED = ACL_TYPE_ACCESS; | 3291 | acl_type_t ACL_TYPE_EXTENDED = ACL_TYPE_ACCESS; |
| 3236 | # endif | 3292 | # endif |
| 3237 | acl_t acl = acl_get_file (SSDATA (absname), ACL_TYPE_EXTENDED); | 3293 | acl_t acl = acl_get_file (SSDATA (ENCODE_FILE (absname)), ACL_TYPE_EXTENDED); |
| 3238 | if (acl == NULL) | 3294 | if (acl == NULL) |
| 3239 | return Qnil; | 3295 | { |
| 3240 | 3296 | if (errno == ENOENT || errno == ENOTDIR || errno == ENOTSUP) | |
| 3297 | return Qnil; | ||
| 3298 | report_file_error ("Getting ACLs", absname); | ||
| 3299 | } | ||
| 3241 | char *str = acl_to_text (acl, NULL); | 3300 | char *str = acl_to_text (acl, NULL); |
| 3242 | if (str == NULL) | 3301 | if (str == NULL) |
| 3243 | { | 3302 | { |
| 3303 | int err = errno; | ||
| 3244 | acl_free (acl); | 3304 | acl_free (acl); |
| 3245 | return Qnil; | 3305 | report_file_errno ("Getting ACLs", absname, err); |
| 3246 | } | 3306 | } |
| 3247 | 3307 | ||
| 3248 | acl_string = build_string (str); | 3308 | acl_string = build_string (str); |
| @@ -3313,7 +3373,7 @@ support. */) | |||
| 3313 | 3373 | ||
| 3314 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, | 3374 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, |
| 3315 | doc: /* Return mode bits of file named FILENAME, as an integer. | 3375 | doc: /* Return mode bits of file named FILENAME, as an integer. |
| 3316 | Return nil, if file does not exist or is not accessible. */) | 3376 | Return nil if FILENAME does not exist. */) |
| 3317 | (Lisp_Object filename) | 3377 | (Lisp_Object filename) |
| 3318 | { | 3378 | { |
| 3319 | struct stat st; | 3379 | struct stat st; |
| @@ -3325,11 +3385,8 @@ Return nil, if file does not exist or is not accessible. */) | |||
| 3325 | if (!NILP (handler)) | 3385 | if (!NILP (handler)) |
| 3326 | return call2 (handler, Qfile_modes, absname); | 3386 | return call2 (handler, Qfile_modes, absname); |
| 3327 | 3387 | ||
| 3328 | absname = ENCODE_FILE (absname); | 3388 | if (stat (SSDATA (ENCODE_FILE (absname)), &st) != 0) |
| 3329 | 3389 | return file_attribute_errno (absname, errno); | |
| 3330 | if (stat (SSDATA (absname), &st) < 0) | ||
| 3331 | return Qnil; | ||
| 3332 | |||
| 3333 | return make_fixnum (st.st_mode & 07777); | 3390 | return make_fixnum (st.st_mode & 07777); |
| 3334 | } | 3391 | } |
| 3335 | 3392 | ||
| @@ -3473,14 +3530,27 @@ otherwise, if FILE2 does not exist, the answer is t. */) | |||
| 3473 | if (!NILP (handler)) | 3530 | if (!NILP (handler)) |
| 3474 | return call3 (handler, Qfile_newer_than_file_p, absname1, absname2); | 3531 | return call3 (handler, Qfile_newer_than_file_p, absname1, absname2); |
| 3475 | 3532 | ||
| 3476 | absname1 = ENCODE_FILE (absname1); | 3533 | int err1; |
| 3477 | absname2 = ENCODE_FILE (absname2); | 3534 | if (stat (SSDATA (ENCODE_FILE (absname1)), &st1) == 0) |
| 3535 | err1 = 0; | ||
| 3536 | else | ||
| 3537 | { | ||
| 3538 | err1 = errno; | ||
| 3539 | if (err1 != EOVERFLOW) | ||
| 3540 | return file_test_errno (absname1, err1); | ||
| 3541 | } | ||
| 3478 | 3542 | ||
| 3479 | if (stat (SSDATA (absname1), &st1) < 0) | 3543 | if (stat (SSDATA (ENCODE_FILE (absname2)), &st2) != 0) |
| 3480 | return Qnil; | 3544 | { |
| 3545 | file_test_errno (absname2, errno); | ||
| 3546 | return Qt; | ||
| 3547 | } | ||
| 3481 | 3548 | ||
| 3482 | if (stat (SSDATA (absname2), &st2) < 0) | 3549 | if (err1) |
| 3483 | return Qt; | 3550 | { |
| 3551 | file_test_errno (absname1, err1); | ||
| 3552 | eassume (false); | ||
| 3553 | } | ||
| 3484 | 3554 | ||
| 3485 | return (timespec_cmp (get_stat_mtime (&st2), get_stat_mtime (&st1)) < 0 | 3555 | return (timespec_cmp (get_stat_mtime (&st2), get_stat_mtime (&st1)) < 0 |
| 3486 | ? Qt : Qnil); | 3556 | ? Qt : Qnil); |
| @@ -3612,7 +3682,7 @@ file_offset (Lisp_Object val) | |||
| 3612 | static struct timespec | 3682 | static struct timespec |
| 3613 | time_error_value (int errnum) | 3683 | time_error_value (int errnum) |
| 3614 | { | 3684 | { |
| 3615 | int ns = (errnum == ENOENT || errnum == EACCES || errnum == ENOTDIR | 3685 | int ns = (errnum == ENOENT || errnum == ENOTDIR |
| 3616 | ? NONEXISTENT_MODTIME_NSECS | 3686 | ? NONEXISTENT_MODTIME_NSECS |
| 3617 | : UNKNOWN_MODTIME_NSECS); | 3687 | : UNKNOWN_MODTIME_NSECS); |
| 3618 | return make_timespec (0, ns); | 3688 | return make_timespec (0, ns); |
| @@ -5672,13 +5742,13 @@ in `current-time' or an integer flag as returned by `visited-file-modtime'. */) | |||
| 5672 | /* The handler can find the file name the same way we did. */ | 5742 | /* The handler can find the file name the same way we did. */ |
| 5673 | return call2 (handler, Qset_visited_file_modtime, Qnil); | 5743 | return call2 (handler, Qset_visited_file_modtime, Qnil); |
| 5674 | 5744 | ||
| 5675 | filename = ENCODE_FILE (filename); | 5745 | if (stat (SSDATA (ENCODE_FILE (filename)), &st) == 0) |
| 5676 | |||
| 5677 | if (stat (SSDATA (filename), &st) >= 0) | ||
| 5678 | { | 5746 | { |
| 5679 | current_buffer->modtime = get_stat_mtime (&st); | 5747 | current_buffer->modtime = get_stat_mtime (&st); |
| 5680 | current_buffer->modtime_size = st.st_size; | 5748 | current_buffer->modtime_size = st.st_size; |
| 5681 | } | 5749 | } |
| 5750 | else | ||
| 5751 | file_attribute_errno (filename, errno); | ||
| 5682 | } | 5752 | } |
| 5683 | 5753 | ||
| 5684 | return Qnil; | 5754 | return Qnil; |
| @@ -5822,7 +5892,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer. */) | |||
| 5822 | if (!NILP (Vrun_hooks)) | 5892 | if (!NILP (Vrun_hooks)) |
| 5823 | { | 5893 | { |
| 5824 | Lisp_Object dir; | 5894 | Lisp_Object dir; |
| 5825 | dir = Ffile_name_directory (listfile); | 5895 | dir = file_name_directory (listfile); |
| 5826 | if (NILP (Ffile_directory_p (dir))) | 5896 | if (NILP (Ffile_directory_p (dir))) |
| 5827 | internal_condition_case_1 (do_auto_save_make_dir, | 5897 | internal_condition_case_1 (do_auto_save_make_dir, |
| 5828 | dir, Qt, | 5898 | dir, Qt, |
| @@ -6067,16 +6137,18 @@ effect except for flushing STREAM's data. */) | |||
| 6067 | 6137 | ||
| 6068 | #ifndef DOS_NT | 6138 | #ifndef DOS_NT |
| 6069 | 6139 | ||
| 6070 | /* Yield a Lisp float as close as possible to BLOCKSIZE * BLOCKS, with | 6140 | /* Yield a Lisp number equal to BLOCKSIZE * BLOCKS, with the result |
| 6071 | the result negated if NEGATE. */ | 6141 | negated if NEGATE. */ |
| 6072 | static Lisp_Object | 6142 | static Lisp_Object |
| 6073 | blocks_to_bytes (uintmax_t blocksize, uintmax_t blocks, bool negate) | 6143 | blocks_to_bytes (uintmax_t blocksize, uintmax_t blocks, bool negate) |
| 6074 | { | 6144 | { |
| 6075 | /* On typical platforms the following code is accurate to 53 bits, | 6145 | intmax_t n; |
| 6076 | which is close enough. BLOCKSIZE is invariably a power of 2, so | 6146 | if (!INT_MULTIPLY_WRAPV (blocksize, blocks, &n)) |
| 6077 | converting it to double does not lose information. */ | 6147 | return make_int (negate ? -n : n); |
| 6078 | double bs = blocksize; | 6148 | Lisp_Object bs = make_uint (blocksize); |
| 6079 | return make_float (negate ? -bs * -blocks : bs * blocks); | 6149 | if (negate) |
| 6150 | bs = CALLN (Fminus, bs); | ||
| 6151 | return CALLN (Ftimes, bs, make_uint (blocks)); | ||
| 6080 | } | 6152 | } |
| 6081 | 6153 | ||
| 6082 | DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0, | 6154 | DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0, |
| @@ -6087,22 +6159,22 @@ storage available to a non-superuser. All 3 numbers are in bytes. | |||
| 6087 | If the underlying system call fails, value is nil. */) | 6159 | If the underlying system call fails, value is nil. */) |
| 6088 | (Lisp_Object filename) | 6160 | (Lisp_Object filename) |
| 6089 | { | 6161 | { |
| 6090 | Lisp_Object encoded = ENCODE_FILE (Fexpand_file_name (filename, Qnil)); | 6162 | filename = Fexpand_file_name (filename, Qnil); |
| 6091 | 6163 | ||
| 6092 | /* If the file name has special constructs in it, | 6164 | /* If the file name has special constructs in it, |
| 6093 | call the corresponding file name handler. */ | 6165 | call the corresponding file name handler. */ |
| 6094 | Lisp_Object handler = Ffind_file_name_handler (encoded, Qfile_system_info); | 6166 | Lisp_Object handler = Ffind_file_name_handler (filename, Qfile_system_info); |
| 6095 | if (!NILP (handler)) | 6167 | if (!NILP (handler)) |
| 6096 | { | 6168 | { |
| 6097 | Lisp_Object result = call2 (handler, Qfile_system_info, encoded); | 6169 | Lisp_Object result = call2 (handler, Qfile_system_info, filename); |
| 6098 | if (CONSP (result) || NILP (result)) | 6170 | if (CONSP (result) || NILP (result)) |
| 6099 | return result; | 6171 | return result; |
| 6100 | error ("Invalid handler in `file-name-handler-alist'"); | 6172 | error ("Invalid handler in `file-name-handler-alist'"); |
| 6101 | } | 6173 | } |
| 6102 | 6174 | ||
| 6103 | struct fs_usage u; | 6175 | struct fs_usage u; |
| 6104 | if (get_fs_usage (SSDATA (encoded), NULL, &u) != 0) | 6176 | if (get_fs_usage (SSDATA (ENCODE_FILE (filename)), NULL, &u) != 0) |
| 6105 | return Qnil; | 6177 | return errno == ENOSYS ? Qnil : file_attribute_errno (filename, errno); |
| 6106 | return list3 (blocks_to_bytes (u.fsu_blocksize, u.fsu_blocks, false), | 6178 | return list3 (blocks_to_bytes (u.fsu_blocksize, u.fsu_blocks, false), |
| 6107 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false), | 6179 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false), |
| 6108 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail, | 6180 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail, |