diff options
| author | Paul Eggert | 2019-09-21 11:27:46 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-09-21 11:38:36 -0700 |
| commit | d49d6ea9677eea1d30aae4244934b1c7336e35a3 (patch) | |
| tree | c671f33693f458a7ba992a2a97250f620aec861d /src | |
| parent | 56213b15e65a350f3f8cd9426a97691d8ff217ee (diff) | |
| download | emacs-d49d6ea9677eea1d30aae4244934b1c7336e35a3.tar.gz emacs-d49d6ea9677eea1d30aae4244934b1c7336e35a3.zip | |
Revert too-picky file-access tests
Problem reported by Andreas Schwab (Bug#37475).
* doc/lispref/files.texi (Writing to Files)
(Testing Accessibility, Kinds of Files):
Document that accessibility and file-type predicates return nil
if there is trouble determining accessibility or type.
* etc/NEWS: Adjust, and list the affected primitives.
* src/callproc.c (init_callproc): Go back to Ffile_exists_p.
* src/fileio.c (PICKY_EACCES, file_test_errno):
Remove. All uses removed.
(Ffile_name_case_insensitive_p, Ffile_exists_p, Ffile_symlink_p)
(Ffile_directory_p, Ffile_regular_p): Document that these
functions return nil if there is trouble.
(Ffile_name_case_insensitive_p, check_file_access)
(Ffile_writable_p, Ffile_symlink_p, Ffile_directory_p)
(Ffile_accessible_directory_p, Ffile_regular_p)
* src/lread.c (Fload):
Go back to treating trouble in determining the answer as if the
file were missing.
* src/fileio.c (Ffile_newer_than_file_p): Use file_attribute_errno
not file_test_errno, since returning nil is not appropriate when
there are two files to test; e.g., in the rare cases where both
file timestamps have overflowed then neither t nor nil is correct.
Diffstat (limited to 'src')
| -rw-r--r-- | src/callproc.c | 4 | ||||
| -rw-r--r-- | src/fileio.c | 108 | ||||
| -rw-r--r-- | src/lisp.h | 1 | ||||
| -rw-r--r-- | src/lread.c | 14 |
4 files changed, 32 insertions, 95 deletions
diff --git a/src/callproc.c b/src/callproc.c index dbbf15c792a..007465cd405 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -1567,12 +1567,12 @@ init_callproc (void) | |||
| 1567 | 1567 | ||
| 1568 | tem = Fexpand_file_name (build_string ("NEWS"), Vdata_directory); | 1568 | tem = Fexpand_file_name (build_string ("NEWS"), Vdata_directory); |
| 1569 | if (!NILP (Fequal (srcdir, Vinvocation_directory)) | 1569 | if (!NILP (Fequal (srcdir, Vinvocation_directory)) |
| 1570 | || !file_access_p (SSDATA (tem), F_OK)) | 1570 | || NILP (Ffile_exists_p (tem))) |
| 1571 | { | 1571 | { |
| 1572 | Lisp_Object newdir; | 1572 | Lisp_Object newdir; |
| 1573 | newdir = Fexpand_file_name (build_string ("../etc/"), lispdir); | 1573 | newdir = Fexpand_file_name (build_string ("../etc/"), lispdir); |
| 1574 | tem = Fexpand_file_name (build_string ("NEWS"), newdir); | 1574 | tem = Fexpand_file_name (build_string ("NEWS"), newdir); |
| 1575 | if (file_access_p (SSDATA (tem), F_OK)) | 1575 | if (!NILP (Ffile_exists_p (tem))) |
| 1576 | Vdata_directory = newdir; | 1576 | Vdata_directory = newdir; |
| 1577 | } | 1577 | } |
| 1578 | } | 1578 | } |
diff --git a/src/fileio.c b/src/fileio.c index b2896c1fe1e..b510d48dbaa 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -253,30 +253,6 @@ file_attribute_errno (Lisp_Object file, int err) | |||
| 253 | return file_metadata_errno ("Getting attributes", file, err); | 253 | return file_metadata_errno ("Getting attributes", file, err); |
| 254 | } | 254 | } |
| 255 | 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, DOS_NT platforms set errno to EACCES for missing files like | ||
| 261 | "/var/mail", so signaling EACCES errors would be a mistake there. | ||
| 262 | So return nil for EACCES unless PICKY_EACCES, which is false by | ||
| 263 | default on DOS_NT. */ | ||
| 264 | #ifndef PICKY_EACCES | ||
| 265 | # ifdef DOS_NT | ||
| 266 | enum { PICKY_EACCES = false }; | ||
| 267 | # else | ||
| 268 | enum { PICKY_EACCES = true }; | ||
| 269 | # endif | ||
| 270 | #endif | ||
| 271 | |||
| 272 | Lisp_Object | ||
| 273 | file_test_errno (Lisp_Object file, int err) | ||
| 274 | { | ||
| 275 | if (!PICKY_EACCES && err == EACCES) | ||
| 276 | return Qnil; | ||
| 277 | return file_metadata_errno ("Testing file", file, err); | ||
| 278 | } | ||
| 279 | |||
| 280 | void | 256 | void |
| 281 | close_file_unwind (int fd) | 257 | close_file_unwind (int fd) |
| 282 | { | 258 | { |
| @@ -2453,7 +2429,9 @@ file_name_case_insensitive_err (Lisp_Object file) | |||
| 2453 | DEFUN ("file-name-case-insensitive-p", Ffile_name_case_insensitive_p, | 2429 | DEFUN ("file-name-case-insensitive-p", Ffile_name_case_insensitive_p, |
| 2454 | Sfile_name_case_insensitive_p, 1, 1, 0, | 2430 | Sfile_name_case_insensitive_p, 1, 1, 0, |
| 2455 | doc: /* Return t if file FILENAME is on a case-insensitive filesystem. | 2431 | doc: /* Return t if file FILENAME is on a case-insensitive filesystem. |
| 2456 | The arg must be a string. */) | 2432 | Return nil if FILENAME does not exist or is not on a case-insensitive |
| 2433 | filesystem, or if there was trouble determining whether the filesystem | ||
| 2434 | is case-insensitive. */) | ||
| 2457 | (Lisp_Object filename) | 2435 | (Lisp_Object filename) |
| 2458 | { | 2436 | { |
| 2459 | Lisp_Object handler; | 2437 | Lisp_Object handler; |
| @@ -2467,19 +2445,16 @@ The arg must be a string. */) | |||
| 2467 | if (!NILP (handler)) | 2445 | if (!NILP (handler)) |
| 2468 | return call2 (handler, Qfile_name_case_insensitive_p, filename); | 2446 | return call2 (handler, Qfile_name_case_insensitive_p, filename); |
| 2469 | 2447 | ||
| 2470 | /* If the file doesn't exist, move up the filesystem tree until we | 2448 | /* If the file doesn't exist or there is trouble checking its |
| 2471 | reach an existing directory or the root. */ | 2449 | filesystem, move up the filesystem tree until we reach an |
| 2450 | existing, trouble-free directory or the root. */ | ||
| 2472 | while (true) | 2451 | while (true) |
| 2473 | { | 2452 | { |
| 2474 | int err = file_name_case_insensitive_err (filename); | 2453 | int err = file_name_case_insensitive_err (filename); |
| 2475 | switch (err) | 2454 | if (err <= 0) |
| 2476 | { | 2455 | return err < 0 ? Qt : Qnil; |
| 2477 | case -1: return Qt; | ||
| 2478 | default: return file_test_errno (filename, err); | ||
| 2479 | case ENOENT: case ENOTDIR: break; | ||
| 2480 | } | ||
| 2481 | Lisp_Object parent = file_name_directory (filename); | 2456 | Lisp_Object parent = file_name_directory (filename); |
| 2482 | /* Avoid infinite loop if the root is reported as non-existing | 2457 | /* Avoid infinite loop if the root has trouble |
| 2483 | (impossible?). */ | 2458 | (impossible?). */ |
| 2484 | if (!NILP (Fstring_equal (parent, filename))) | 2459 | if (!NILP (Fstring_equal (parent, filename))) |
| 2485 | return Qnil; | 2460 | return Qnil; |
| @@ -2739,8 +2714,7 @@ file_name_absolute_p (char const *filename) | |||
| 2739 | } | 2714 | } |
| 2740 | 2715 | ||
| 2741 | /* Return t if FILE exists and is accessible via OPERATION and AMODE, | 2716 | /* Return t if FILE exists and is accessible via OPERATION and AMODE, |
| 2742 | nil (setting errno) if not. Signal an error if the result cannot | 2717 | nil (setting errno) if not. */ |
| 2743 | be determined. */ | ||
| 2744 | 2718 | ||
| 2745 | static Lisp_Object | 2719 | static Lisp_Object |
| 2746 | check_file_access (Lisp_Object file, Lisp_Object operation, int amode) | 2720 | check_file_access (Lisp_Object file, Lisp_Object operation, int amode) |
| @@ -2758,22 +2732,13 @@ check_file_access (Lisp_Object file, Lisp_Object operation, int amode) | |||
| 2758 | } | 2732 | } |
| 2759 | 2733 | ||
| 2760 | char *encoded_file = SSDATA (ENCODE_FILE (file)); | 2734 | char *encoded_file = SSDATA (ENCODE_FILE (file)); |
| 2761 | bool ok = file_access_p (encoded_file, amode); | 2735 | return file_access_p (encoded_file, amode) ? Qt : Qnil; |
| 2762 | if (ok) | ||
| 2763 | return Qt; | ||
| 2764 | int err = errno; | ||
| 2765 | if (err == EROFS || err == ETXTBSY | ||
| 2766 | || (PICKY_EACCES && err == EACCES && amode != F_OK | ||
| 2767 | && file_access_p (encoded_file, F_OK))) | ||
| 2768 | { | ||
| 2769 | errno = err; | ||
| 2770 | return Qnil; | ||
| 2771 | } | ||
| 2772 | return file_test_errno (file, err); | ||
| 2773 | } | 2736 | } |
| 2774 | 2737 | ||
| 2775 | DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, | 2738 | DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, |
| 2776 | doc: /* Return t if file FILENAME exists (whether or not you can read it). | 2739 | doc: /* Return t if file FILENAME exists (whether or not you can read it). |
| 2740 | Return nil if FILENAME does not exist, or if there was trouble | ||
| 2741 | determining whether the file exists. | ||
| 2777 | See also `file-readable-p' and `file-attributes'. | 2742 | See also `file-readable-p' and `file-attributes'. |
| 2778 | This returns nil for a symlink to a nonexistent file. | 2743 | This returns nil for a symlink to a nonexistent file. |
| 2779 | Use `file-symlink-p' to test for such links. */) | 2744 | Use `file-symlink-p' to test for such links. */) |
| @@ -2834,16 +2799,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2834 | should check ACLs though, which do affect this. */ | 2799 | should check ACLs though, which do affect this. */ |
| 2835 | return file_directory_p (encoded) ? Qt : Qnil; | 2800 | return file_directory_p (encoded) ? Qt : Qnil; |
| 2836 | #else | 2801 | #else |
| 2837 | if (file_access_p (SSDATA (encoded), W_OK | X_OK)) | 2802 | return file_access_p (SSDATA (encoded), W_OK | X_OK) ? Qt : Qnil; |
| 2838 | return Qt; | ||
| 2839 | int err = errno; | ||
| 2840 | if (err == EROFS | ||
| 2841 | || (err == EACCES && file_access_p (SSDATA (encoded), F_OK))) | ||
| 2842 | { | ||
| 2843 | errno = err; | ||
| 2844 | return Qnil; | ||
| 2845 | } | ||
| 2846 | return file_test_errno (absname, err); | ||
| 2847 | #endif | 2803 | #endif |
| 2848 | } | 2804 | } |
| 2849 | 2805 | ||
| @@ -2919,7 +2875,8 @@ check_emacs_readlinkat (int fd, Lisp_Object file, char const *encoded_file) | |||
| 2919 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, | 2875 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, |
| 2920 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. | 2876 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. |
| 2921 | The value is the link target, as a string. | 2877 | The value is the link target, as a string. |
| 2922 | Otherwise it returns nil. | 2878 | Return nil if FILENAME does not exist or is not a symbolic link, |
| 2879 | of there was trouble determining whether the file is a symbolic link. | ||
| 2923 | 2880 | ||
| 2924 | This function does not check whether the link target exists. */) | 2881 | This function does not check whether the link target exists. */) |
| 2925 | (Lisp_Object filename) | 2882 | (Lisp_Object filename) |
| @@ -2935,12 +2892,13 @@ This function does not check whether the link target exists. */) | |||
| 2935 | if (!NILP (handler)) | 2892 | if (!NILP (handler)) |
| 2936 | return call2 (handler, Qfile_symlink_p, filename); | 2893 | return call2 (handler, Qfile_symlink_p, filename); |
| 2937 | 2894 | ||
| 2938 | return check_emacs_readlinkat (AT_FDCWD, filename, | 2895 | return emacs_readlinkat (AT_FDCWD, SSDATA (ENCODE_FILE (filename))); |
| 2939 | SSDATA (ENCODE_FILE (filename))); | ||
| 2940 | } | 2896 | } |
| 2941 | 2897 | ||
| 2942 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, | 2898 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, |
| 2943 | doc: /* Return t if FILENAME names an existing directory. | 2899 | doc: /* Return t if FILENAME names an existing directory. |
| 2900 | Return nil if FILENAME does not name a directory, or if there | ||
| 2901 | was trouble determining whether FILENAME is a directory. | ||
| 2944 | Symbolic links to directories count as directories. | 2902 | Symbolic links to directories count as directories. |
| 2945 | See `file-symlink-p' to distinguish symlinks. */) | 2903 | See `file-symlink-p' to distinguish symlinks. */) |
| 2946 | (Lisp_Object filename) | 2904 | (Lisp_Object filename) |
| @@ -2953,9 +2911,7 @@ See `file-symlink-p' to distinguish symlinks. */) | |||
| 2953 | if (!NILP (handler)) | 2911 | if (!NILP (handler)) |
| 2954 | return call2 (handler, Qfile_directory_p, absname); | 2912 | return call2 (handler, Qfile_directory_p, absname); |
| 2955 | 2913 | ||
| 2956 | if (file_directory_p (absname)) | 2914 | return file_directory_p (absname) ? Qt : Qnil; |
| 2957 | return Qt; | ||
| 2958 | return file_test_errno (absname, errno); | ||
| 2959 | } | 2915 | } |
| 2960 | 2916 | ||
| 2961 | /* Return true if FILE is a directory or a symlink to a directory. | 2917 | /* Return true if FILE is a directory or a symlink to a directory. |
| @@ -3040,12 +2996,7 @@ really is a readable and searchable directory. */) | |||
| 3040 | } | 2996 | } |
| 3041 | 2997 | ||
| 3042 | Lisp_Object encoded_absname = ENCODE_FILE (absname); | 2998 | Lisp_Object encoded_absname = ENCODE_FILE (absname); |
| 3043 | if (file_accessible_directory_p (encoded_absname)) | 2999 | return file_accessible_directory_p (encoded_absname) ? Qt : Qnil; |
| 3044 | return Qt; | ||
| 3045 | int err = errno; | ||
| 3046 | if (err == EACCES && file_access_p (SSDATA (encoded_absname), F_OK)) | ||
| 3047 | return Qnil; | ||
| 3048 | return file_test_errno (absname, err); | ||
| 3049 | } | 3000 | } |
| 3050 | 3001 | ||
| 3051 | /* If FILE is a searchable directory or a symlink to a | 3002 | /* If FILE is a searchable directory or a symlink to a |
| @@ -3108,6 +3059,8 @@ file_accessible_directory_p (Lisp_Object file) | |||
| 3108 | DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, | 3059 | DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0, |
| 3109 | doc: /* Return t if FILENAME names a regular file. | 3060 | doc: /* Return t if FILENAME names a regular file. |
| 3110 | This is the sort of file that holds an ordinary stream of data bytes. | 3061 | This is the sort of file that holds an ordinary stream of data bytes. |
| 3062 | Return nil if FILENAME does not exist or is not a regular file, | ||
| 3063 | or there was trouble determining whether FILENAME is a regular file. | ||
| 3111 | Symbolic links to regular files count as regular files. | 3064 | Symbolic links to regular files count as regular files. |
| 3112 | See `file-symlink-p' to distinguish symlinks. */) | 3065 | See `file-symlink-p' to distinguish symlinks. */) |
| 3113 | (Lisp_Object filename) | 3066 | (Lisp_Object filename) |
| @@ -3133,9 +3086,7 @@ See `file-symlink-p' to distinguish symlinks. */) | |||
| 3133 | Vw32_get_true_file_attributes = true_attributes; | 3086 | Vw32_get_true_file_attributes = true_attributes; |
| 3134 | #endif | 3087 | #endif |
| 3135 | 3088 | ||
| 3136 | if (stat_result == 0) | 3089 | return stat_result == 0 && S_ISREG (st.st_mode) ? Qt : Qnil; |
| 3137 | return S_ISREG (st.st_mode) ? Qt : Qnil; | ||
| 3138 | return file_test_errno (absname, errno); | ||
| 3139 | } | 3090 | } |
| 3140 | 3091 | ||
| 3141 | DEFUN ("file-selinux-context", Ffile_selinux_context, | 3092 | DEFUN ("file-selinux-context", Ffile_selinux_context, |
| @@ -3541,20 +3492,15 @@ otherwise, if FILE2 does not exist, the answer is t. */) | |||
| 3541 | { | 3492 | { |
| 3542 | err1 = errno; | 3493 | err1 = errno; |
| 3543 | if (err1 != EOVERFLOW) | 3494 | if (err1 != EOVERFLOW) |
| 3544 | return file_test_errno (absname1, err1); | 3495 | return file_attribute_errno (absname1, err1); |
| 3545 | } | 3496 | } |
| 3546 | |||
| 3547 | if (stat (SSDATA (ENCODE_FILE (absname2)), &st2) != 0) | 3497 | if (stat (SSDATA (ENCODE_FILE (absname2)), &st2) != 0) |
| 3548 | { | 3498 | { |
| 3549 | file_test_errno (absname2, errno); | 3499 | file_attribute_errno (absname2, errno); |
| 3550 | return Qt; | 3500 | return Qt; |
| 3551 | } | 3501 | } |
| 3552 | |||
| 3553 | if (err1) | 3502 | if (err1) |
| 3554 | { | 3503 | file_attribute_errno (absname1, err1); |
| 3555 | file_test_errno (absname1, err1); | ||
| 3556 | eassume (false); | ||
| 3557 | } | ||
| 3558 | 3504 | ||
| 3559 | return (timespec_cmp (get_stat_mtime (&st2), get_stat_mtime (&st1)) < 0 | 3505 | return (timespec_cmp (get_stat_mtime (&st2), get_stat_mtime (&st1)) < 0 |
| 3560 | ? Qt : Qnil); | 3506 | ? Qt : Qnil); |
diff --git a/src/lisp.h b/src/lisp.h index b081ae1cee8..e68d2732e21 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4315,7 +4315,6 @@ extern AVOID report_file_errno (const char *, Lisp_Object, int); | |||
| 4315 | extern AVOID report_file_error (const char *, Lisp_Object); | 4315 | extern AVOID report_file_error (const char *, Lisp_Object); |
| 4316 | extern AVOID report_file_notify_error (const char *, Lisp_Object); | 4316 | extern AVOID report_file_notify_error (const char *, Lisp_Object); |
| 4317 | extern Lisp_Object file_attribute_errno (Lisp_Object, int); | 4317 | extern Lisp_Object file_attribute_errno (Lisp_Object, int); |
| 4318 | extern Lisp_Object file_test_errno (Lisp_Object, int); | ||
| 4319 | extern bool internal_delete_file (Lisp_Object); | 4318 | extern bool internal_delete_file (Lisp_Object); |
| 4320 | extern Lisp_Object check_emacs_readlinkat (int, Lisp_Object, char const *); | 4319 | extern Lisp_Object check_emacs_readlinkat (int, Lisp_Object, char const *); |
| 4321 | extern bool file_directory_p (Lisp_Object); | 4320 | extern bool file_directory_p (Lisp_Object); |
diff --git a/src/lread.c b/src/lread.c index 4f3446b09db..151731a81d9 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -1343,26 +1343,18 @@ Return t if the file exists and loads successfully. */) | |||
| 1343 | /* openp already checked for newness, no point doing it again. | 1343 | /* openp already checked for newness, no point doing it again. |
| 1344 | FIXME would be nice to get a message when openp | 1344 | FIXME would be nice to get a message when openp |
| 1345 | ignores suffix order due to load_prefer_newer. */ | 1345 | ignores suffix order due to load_prefer_newer. */ |
| 1346 | Lisp_Object notfound = found; | ||
| 1347 | if (!load_prefer_newer && is_elc) | 1346 | if (!load_prefer_newer && is_elc) |
| 1348 | { | 1347 | { |
| 1349 | result = stat (SSDATA (efound), &s1); | 1348 | result = stat (SSDATA (efound), &s1); |
| 1350 | int err = errno; | ||
| 1351 | if (result == 0) | 1349 | if (result == 0) |
| 1352 | { | 1350 | { |
| 1353 | SSET (efound, SBYTES (efound) - 1, 0); | 1351 | SSET (efound, SBYTES (efound) - 1, 0); |
| 1354 | result = stat (SSDATA (efound), &s2); | 1352 | result = stat (SSDATA (efound), &s2); |
| 1355 | err = errno; | ||
| 1356 | SSET (efound, SBYTES (efound) - 1, 'c'); | 1353 | SSET (efound, SBYTES (efound) - 1, 'c'); |
| 1357 | if (result != 0) | ||
| 1358 | notfound = Fsubstring (found, make_fixnum (0), | ||
| 1359 | make_fixnum (-1)); | ||
| 1360 | } | 1354 | } |
| 1361 | if (result != 0) | 1355 | |
| 1362 | file_test_errno (notfound, err); | 1356 | if (result == 0 |
| 1363 | else if (timespec_cmp (get_stat_mtime (&s1), | 1357 | && timespec_cmp (get_stat_mtime (&s1), get_stat_mtime (&s2)) < 0) |
| 1364 | get_stat_mtime (&s2)) | ||
| 1365 | < 0) | ||
| 1366 | { | 1358 | { |
| 1367 | /* Make the progress messages mention that source is newer. */ | 1359 | /* Make the progress messages mention that source is newer. */ |
| 1368 | newer = 1; | 1360 | newer = 1; |