diff options
| author | Paul Eggert | 2019-09-17 19:18:14 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-09-17 19:24:38 -0700 |
| commit | 9dc306b1db08196684d05a474148e16305adbad0 (patch) | |
| tree | 78a401e0156a34ef1d2ae99acad31fb3ad9cb806 /src | |
| parent | ae3edf0ac3f1e893338917497b55859d6aca7d42 (diff) | |
| download | emacs-9dc306b1db08196684d05a474148e16305adbad0.tar.gz emacs-9dc306b1db08196684d05a474148e16305adbad0.zip | |
Improve reporting of I/O, access errors
Signal an error for file-oriented errors that are not tame
errors like ENOENT and ENOTDIR (Bug#37389).
Do this for primitives exposed to Lisp; the lower
level internal C API merely makes errno values available
to higher-level C code.
* doc/lispref/files.texi (Testing Accessibility)
(File Attributes, Extended Attributes): Do not say that the
functions return nil when the return value cannot be determined.
* etc/NEWS: Mention the change.
* src/dired.c (Ffile_attributes): Fix doc string confusion
about opening a file vs getting its attributes.
(file_attributes): Signal serious errors.
* src/fileio.c (check_existing, check_executable)
(check_writable): Remove. All callers changed to use
check_file_access or file_access_p.
(file_access_p, file_metadata_errno, file_attribute_errno)
(file_test_errno, check_file_access, check_emacs_readlinkat):
New functions.
* src/fileio.c (Ffile_executable_p, Ffile_readable_p)
(Ffile_name_case_insensitive_p, Frename_file, Ffile_exists_p):
(Ffile_symlink_p, Ffile_directory_p)
(Ffile_accessible_directory_p, Ffile_regular_p)
(Ffile_selinux_context, Ffile_acl, Ffile_modes)
(Ffile_newer_than_file_p, Fset_visited_file_modtime)
(Ffile_system_info):
* src/filelock.c (unlock_file, Ffile_locked_p):
* src/lread.c (Fload):
Signal serious errors.
* src/fileio.c (Ffile_writable_p): Remove unnecessary CHECK_STRING.
(emacs_readlinkat): Now static.
* src/filelock.c (current_lock_owner, lock_if_free): Return a
positive errno on error, and the negative of the old old value
on success. All callers changed.
* src/lread.c (openp): Propagate serious errno values to caller.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dired.c | 9 | ||||
| -rw-r--r-- | src/emacs.c | 2 | ||||
| -rw-r--r-- | src/fileio.c | 359 | ||||
| -rw-r--r-- | src/filelock.c | 86 | ||||
| -rw-r--r-- | src/lisp.h | 5 | ||||
| -rw-r--r-- | src/lread.c | 21 |
6 files changed, 267 insertions, 215 deletions
diff --git a/src/dired.c b/src/dired.c index df03bc32cef..3768b6dbb7c 100644 --- a/src/dired.c +++ b/src/dired.c | |||
| @@ -819,7 +819,7 @@ stat_gname (struct stat *st) | |||
| 819 | 819 | ||
| 820 | DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0, | 820 | DEFUN ("file-attributes", Ffile_attributes, Sfile_attributes, 1, 2, 0, |
| 821 | doc: /* Return a list of attributes of file FILENAME. | 821 | doc: /* Return a list of attributes of file FILENAME. |
| 822 | Value is nil if specified file cannot be opened. | 822 | Value is nil if specified file does not exist. |
| 823 | 823 | ||
| 824 | ID-FORMAT specifies the preferred format of attributes uid and gid (see | 824 | ID-FORMAT specifies the preferred format of attributes uid and gid (see |
| 825 | below) - valid values are `string' and `integer'. The latter is the | 825 | below) - valid values are `string' and `integer'. The latter is the |
| @@ -939,15 +939,14 @@ file_attributes (int fd, char const *name, | |||
| 939 | information to be accurate. */ | 939 | information to be accurate. */ |
| 940 | w32_stat_get_owner_group = 1; | 940 | w32_stat_get_owner_group = 1; |
| 941 | #endif | 941 | #endif |
| 942 | if (fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) | 942 | err = fstatat (fd, name, &s, AT_SYMLINK_NOFOLLOW) == 0 ? 0 : errno; |
| 943 | err = 0; | ||
| 944 | #ifdef WINDOWSNT | 943 | #ifdef WINDOWSNT |
| 945 | w32_stat_get_owner_group = 0; | 944 | w32_stat_get_owner_group = 0; |
| 946 | #endif | 945 | #endif |
| 947 | } | 946 | } |
| 948 | 947 | ||
| 949 | if (err != 0) | 948 | if (err != 0) |
| 950 | return unbind_to (count, Qnil); | 949 | return unbind_to (count, file_attribute_errno (filename, err)); |
| 951 | 950 | ||
| 952 | Lisp_Object file_type; | 951 | Lisp_Object file_type; |
| 953 | if (S_ISLNK (s.st_mode)) | 952 | if (S_ISLNK (s.st_mode)) |
| @@ -956,7 +955,7 @@ file_attributes (int fd, char const *name, | |||
| 956 | symlink is replaced between the call to fstatat and the call | 955 | symlink is replaced between the call to fstatat and the call |
| 957 | to emacs_readlinkat. Detect this race unless the replacement | 956 | to emacs_readlinkat. Detect this race unless the replacement |
| 958 | is also a symlink. */ | 957 | is also a symlink. */ |
| 959 | file_type = emacs_readlinkat (fd, name); | 958 | file_type = check_emacs_readlinkat (fd, filename, name); |
| 960 | if (NILP (file_type)) | 959 | if (NILP (file_type)) |
| 961 | return unbind_to (count, Qnil); | 960 | return unbind_to (count, Qnil); |
| 962 | } | 961 | } |
diff --git a/src/emacs.c b/src/emacs.c index 558dd11a351..eb732810db4 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -746,7 +746,7 @@ load_pdump_find_executable (char const *argv0, ptrdiff_t *candidate_size) | |||
| 746 | candidate[path_part_length] = DIRECTORY_SEP; | 746 | candidate[path_part_length] = DIRECTORY_SEP; |
| 747 | memcpy (candidate + path_part_length + 1, argv0, argv0_length + 1); | 747 | memcpy (candidate + path_part_length + 1, argv0, argv0_length + 1); |
| 748 | struct stat st; | 748 | struct stat st; |
| 749 | if (check_executable (candidate) | 749 | if (file_access_p (candidate, X_OK) |
| 750 | && stat (candidate, &st) == 0 && S_ISREG (st.st_mode)) | 750 | && stat (candidate, &st) == 0 && S_ISREG (st.st_mode)) |
| 751 | return candidate; | 751 | return candidate; |
| 752 | *candidate = '\0'; | 752 | *candidate = '\0'; |
diff --git a/src/fileio.c b/src/fileio.c index 81c29ca0cca..0977516f019 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -141,54 +141,38 @@ static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, | |||
| 141 | struct coding_system *); | 141 | struct coding_system *); |
| 142 | 142 | ||
| 143 | 143 | ||
| 144 | /* Return true if FILENAME exists, otherwise return false and set errno. */ | 144 | /* Test whether FILE is accessible for AMODE. |
| 145 | 145 | Return true if successful, false (setting errno) otherwise. */ | |
| 146 | static bool | ||
| 147 | check_existing (const char *filename) | ||
| 148 | { | ||
| 149 | return faccessat (AT_FDCWD, filename, F_OK, AT_EACCESS) == 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* Return true if file FILENAME exists and can be executed. */ | ||
| 153 | 146 | ||
| 154 | bool | 147 | bool |
| 155 | check_executable (char *filename) | 148 | file_access_p (char const *file, int amode) |
| 156 | { | ||
| 157 | return faccessat (AT_FDCWD, filename, X_OK, AT_EACCESS) == 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* Return true if file FILENAME exists and can be accessed | ||
| 161 | according to AMODE, which should include W_OK. | ||
| 162 | On failure, return false and set errno. */ | ||
| 163 | |||
| 164 | static bool | ||
| 165 | check_writable (const char *filename, int amode) | ||
| 166 | { | 149 | { |
| 167 | #ifdef MSDOS | 150 | #ifdef MSDOS |
| 168 | /* FIXME: an faccessat implementation should be added to the | 151 | if (amode & W_OK) |
| 169 | DOS/Windows ports and this #ifdef branch should be removed. */ | ||
| 170 | struct stat st; | ||
| 171 | if (stat (filename, &st) < 0) | ||
| 172 | return 0; | ||
| 173 | errno = EPERM; | ||
| 174 | return (st.st_mode & S_IWRITE || S_ISDIR (st.st_mode)); | ||
| 175 | #else /* not MSDOS */ | ||
| 176 | bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0; | ||
| 177 | #ifdef CYGWIN | ||
| 178 | /* faccessat may have returned failure because Cygwin couldn't | ||
| 179 | determine the file's UID or GID; if so, we return success. */ | ||
| 180 | if (!res) | ||
| 181 | { | 152 | { |
| 182 | int faccessat_errno = errno; | 153 | /* FIXME: The MS-DOS faccessat implementation should handle this. */ |
| 183 | struct stat st; | 154 | struct stat st; |
| 184 | if (stat (filename, &st) < 0) | 155 | if (stat (file, &st) != 0) |
| 185 | return 0; | 156 | return false; |
| 186 | res = (st.st_uid == -1 || st.st_gid == -1); | 157 | errno = EPERM; |
| 187 | errno = faccessat_errno; | 158 | return st.st_mode & S_IWRITE || S_ISDIR (st.st_mode); |
| 188 | } | 159 | } |
| 189 | #endif /* CYGWIN */ | 160 | #endif |
| 190 | return res; | 161 | |
| 191 | #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; | ||
| 192 | } | 176 | } |
| 193 | 177 | ||
| 194 | /* Signal a file-access failure. STRING describes the failure, | 178 | /* Signal a file-access failure. STRING describes the failure, |
| @@ -251,6 +235,30 @@ report_file_notify_error (const char *string, Lisp_Object name) | |||
| 251 | } | 235 | } |
| 252 | #endif | 236 | #endif |
| 253 | 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 | static Lisp_Object | ||
| 257 | file_test_errno (Lisp_Object file, int err) | ||
| 258 | { | ||
| 259 | return file_metadata_errno ("Testing file", file, err); | ||
| 260 | } | ||
| 261 | |||
| 254 | void | 262 | void |
| 255 | close_file_unwind (int fd) | 263 | close_file_unwind (int fd) |
| 256 | { | 264 | { |
| @@ -2446,8 +2454,12 @@ The arg must be a string. */) | |||
| 2446 | while (true) | 2454 | while (true) |
| 2447 | { | 2455 | { |
| 2448 | int err = file_name_case_insensitive_err (filename); | 2456 | int err = file_name_case_insensitive_err (filename); |
| 2449 | if (! (err == ENOENT || err == ENOTDIR)) | 2457 | switch (err) |
| 2450 | return err < 0 ? Qt : Qnil; | 2458 | { |
| 2459 | case -1: return Qt; | ||
| 2460 | default: return file_test_errno (filename, err); | ||
| 2461 | case ENOENT: case ENOTDIR: break; | ||
| 2462 | } | ||
| 2451 | Lisp_Object parent = file_name_directory (filename); | 2463 | Lisp_Object parent = file_name_directory (filename); |
| 2452 | /* Avoid infinite loop if the root is reported as non-existing | 2464 | /* Avoid infinite loop if the root is reported as non-existing |
| 2453 | (impossible?). */ | 2465 | (impossible?). */ |
| @@ -2560,7 +2572,7 @@ This is what happens in interactive use with M-x. */) | |||
| 2560 | { | 2572 | { |
| 2561 | Lisp_Object symlink_target | 2573 | Lisp_Object symlink_target |
| 2562 | = (S_ISLNK (file_st.st_mode) | 2574 | = (S_ISLNK (file_st.st_mode) |
| 2563 | ? emacs_readlinkat (AT_FDCWD, SSDATA (encoded_file)) | 2575 | ? check_emacs_readlinkat (AT_FDCWD, file, SSDATA (encoded_file)) |
| 2564 | : Qnil); | 2576 | : Qnil); |
| 2565 | if (!NILP (symlink_target)) | 2577 | if (!NILP (symlink_target)) |
| 2566 | Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists); | 2578 | Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists); |
| @@ -2708,32 +2720,48 @@ file_name_absolute_p (char const *filename) | |||
| 2708 | || user_homedir (&filename[1])))); | 2720 | || user_homedir (&filename[1])))); |
| 2709 | } | 2721 | } |
| 2710 | 2722 | ||
| 2711 | DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, | 2723 | /* Return t if FILE exists and is accessible via OPERATION and AMODE, |
| 2712 | doc: /* Return t if file FILENAME exists (whether or not you can read it). | 2724 | nil (setting errno) if not. Signal an error if the result cannot |
| 2713 | See also `file-readable-p' and `file-attributes'. | 2725 | be determined. */ |
| 2714 | This returns nil for a symlink to a nonexistent file. | ||
| 2715 | Use `file-symlink-p' to test for such links. */) | ||
| 2716 | (Lisp_Object filename) | ||
| 2717 | { | ||
| 2718 | Lisp_Object absname; | ||
| 2719 | Lisp_Object handler; | ||
| 2720 | 2726 | ||
| 2721 | CHECK_STRING (filename); | 2727 | static Lisp_Object |
| 2722 | absname = Fexpand_file_name (filename, Qnil); | 2728 | check_file_access (Lisp_Object file, Lisp_Object operation, int amode) |
| 2723 | 2729 | { | |
| 2724 | /* If the file name has special constructs in it, | 2730 | file = Fexpand_file_name (file, Qnil); |
| 2725 | call the corresponding file name handler. */ | 2731 | Lisp_Object handler = Ffind_file_name_handler (file, operation); |
| 2726 | handler = Ffind_file_name_handler (absname, Qfile_exists_p); | ||
| 2727 | if (!NILP (handler)) | 2732 | if (!NILP (handler)) |
| 2728 | { | 2733 | { |
| 2729 | Lisp_Object result = call2 (handler, Qfile_exists_p, absname); | 2734 | Lisp_Object ok = call2 (handler, operation, file); |
| 2735 | /* This errno value is bogus. Any caller that depends on errno | ||
| 2736 | should be rethought anyway, to avoid a race between testing a | ||
| 2737 | handled file's accessibility and using the file. */ | ||
| 2730 | errno = 0; | 2738 | errno = 0; |
| 2731 | return result; | 2739 | return ok; |
| 2732 | } | 2740 | } |
| 2733 | 2741 | ||
| 2734 | absname = ENCODE_FILE (absname); | 2742 | char *encoded_file = SSDATA (ENCODE_FILE (file)); |
| 2743 | bool ok = file_access_p (encoded_file, amode); | ||
| 2744 | if (ok) | ||
| 2745 | return Qt; | ||
| 2746 | int err = errno; | ||
| 2747 | if (err == EROFS || err == ETXTBSY | ||
| 2748 | || (err == EACCES && amode != F_OK | ||
| 2749 | && file_access_p (encoded_file, F_OK))) | ||
| 2750 | { | ||
| 2751 | errno = err; | ||
| 2752 | return Qnil; | ||
| 2753 | } | ||
| 2754 | return file_test_errno (file, err); | ||
| 2755 | } | ||
| 2735 | 2756 | ||
| 2736 | return check_existing (SSDATA (absname)) ? Qt : Qnil; | 2757 | DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, |
| 2758 | doc: /* Return t if file FILENAME exists (whether or not you can read it). | ||
| 2759 | See also `file-readable-p' and `file-attributes'. | ||
| 2760 | This returns nil for a symlink to a nonexistent file. | ||
| 2761 | Use `file-symlink-p' to test for such links. */) | ||
| 2762 | (Lisp_Object filename) | ||
| 2763 | { | ||
| 2764 | return check_file_access (filename, Qfile_exists_p, F_OK); | ||
| 2737 | } | 2765 | } |
| 2738 | 2766 | ||
| 2739 | DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0, | 2767 | DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0, |
| @@ -2743,21 +2771,7 @@ For a directory, this means you can access files in that directory. | |||
| 2743 | purpose, though.) */) | 2771 | purpose, though.) */) |
| 2744 | (Lisp_Object filename) | 2772 | (Lisp_Object filename) |
| 2745 | { | 2773 | { |
| 2746 | Lisp_Object absname; | 2774 | return check_file_access (filename, Qfile_executable_p, X_OK); |
| 2747 | Lisp_Object handler; | ||
| 2748 | |||
| 2749 | CHECK_STRING (filename); | ||
| 2750 | absname = Fexpand_file_name (filename, Qnil); | ||
| 2751 | |||
| 2752 | /* If the file name has special constructs in it, | ||
| 2753 | call the corresponding file name handler. */ | ||
| 2754 | handler = Ffind_file_name_handler (absname, Qfile_executable_p); | ||
| 2755 | if (!NILP (handler)) | ||
| 2756 | return call2 (handler, Qfile_executable_p, absname); | ||
| 2757 | |||
| 2758 | absname = ENCODE_FILE (absname); | ||
| 2759 | |||
| 2760 | return (check_executable (SSDATA (absname)) ? Qt : Qnil); | ||
| 2761 | } | 2775 | } |
| 2762 | 2776 | ||
| 2763 | DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, | 2777 | DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, |
| @@ -2765,21 +2779,7 @@ DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0, | |||
| 2765 | See also `file-exists-p' and `file-attributes'. */) | 2779 | See also `file-exists-p' and `file-attributes'. */) |
| 2766 | (Lisp_Object filename) | 2780 | (Lisp_Object filename) |
| 2767 | { | 2781 | { |
| 2768 | Lisp_Object absname; | 2782 | return check_file_access (filename, Qfile_readable_p, R_OK); |
| 2769 | Lisp_Object handler; | ||
| 2770 | |||
| 2771 | CHECK_STRING (filename); | ||
| 2772 | absname = Fexpand_file_name (filename, Qnil); | ||
| 2773 | |||
| 2774 | /* If the file name has special constructs in it, | ||
| 2775 | call the corresponding file name handler. */ | ||
| 2776 | handler = Ffind_file_name_handler (absname, Qfile_readable_p); | ||
| 2777 | if (!NILP (handler)) | ||
| 2778 | return call2 (handler, Qfile_readable_p, absname); | ||
| 2779 | |||
| 2780 | absname = ENCODE_FILE (absname); | ||
| 2781 | return (faccessat (AT_FDCWD, SSDATA (absname), R_OK, AT_EACCESS) == 0 | ||
| 2782 | ? Qt : Qnil); | ||
| 2783 | } | 2783 | } |
| 2784 | 2784 | ||
| 2785 | DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | 2785 | DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, |
| @@ -2789,7 +2789,6 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2789 | Lisp_Object absname, dir, encoded; | 2789 | Lisp_Object absname, dir, encoded; |
| 2790 | Lisp_Object handler; | 2790 | Lisp_Object handler; |
| 2791 | 2791 | ||
| 2792 | CHECK_STRING (filename); | ||
| 2793 | absname = Fexpand_file_name (filename, Qnil); | 2792 | absname = Fexpand_file_name (filename, Qnil); |
| 2794 | 2793 | ||
| 2795 | /* If the file name has special constructs in it, | 2794 | /* If the file name has special constructs in it, |
| @@ -2799,7 +2798,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2799 | return call2 (handler, Qfile_writable_p, absname); | 2798 | return call2 (handler, Qfile_writable_p, absname); |
| 2800 | 2799 | ||
| 2801 | encoded = ENCODE_FILE (absname); | 2800 | encoded = ENCODE_FILE (absname); |
| 2802 | if (check_writable (SSDATA (encoded), W_OK)) | 2801 | if (file_access_p (SSDATA (encoded), W_OK)) |
| 2803 | return Qt; | 2802 | return Qt; |
| 2804 | if (errno != ENOENT) | 2803 | if (errno != ENOENT) |
| 2805 | return Qnil; | 2804 | return Qnil; |
| @@ -2810,14 +2809,23 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0, | |||
| 2810 | dir = Fdirectory_file_name (dir); | 2809 | dir = Fdirectory_file_name (dir); |
| 2811 | #endif /* MSDOS */ | 2810 | #endif /* MSDOS */ |
| 2812 | 2811 | ||
| 2813 | dir = ENCODE_FILE (dir); | 2812 | encoded = ENCODE_FILE (dir); |
| 2814 | #ifdef WINDOWSNT | 2813 | #ifdef WINDOWSNT |
| 2815 | /* The read-only attribute of the parent directory doesn't affect | 2814 | /* The read-only attribute of the parent directory doesn't affect |
| 2816 | whether a file or directory can be created within it. Some day we | 2815 | whether a file or directory can be created within it. Some day we |
| 2817 | should check ACLs though, which do affect this. */ | 2816 | should check ACLs though, which do affect this. */ |
| 2818 | return file_directory_p (dir) ? Qt : Qnil; | 2817 | return file_directory_p (encoded) ? Qt : Qnil; |
| 2819 | #else | 2818 | #else |
| 2820 | return check_writable (SSDATA (dir), W_OK | X_OK) ? Qt : Qnil; | 2819 | if (file_access_p (SSDATA (encoded), W_OK | X_OK)) |
| 2820 | return Qt; | ||
| 2821 | int err = errno; | ||
| 2822 | if (err == EROFS | ||
| 2823 | || (err == EACCES && file_access_p (SSDATA (encoded), F_OK))) | ||
| 2824 | { | ||
| 2825 | errno = err; | ||
| 2826 | return Qnil; | ||
| 2827 | } | ||
| 2828 | return file_test_errno (absname, err); | ||
| 2821 | #endif | 2829 | #endif |
| 2822 | } | 2830 | } |
| 2823 | 2831 | ||
| @@ -2849,8 +2857,8 @@ If there is no error, returns nil. */) | |||
| 2849 | } | 2857 | } |
| 2850 | 2858 | ||
| 2851 | /* Relative to directory FD, return the symbolic link value of FILENAME. | 2859 | /* Relative to directory FD, return the symbolic link value of FILENAME. |
| 2852 | On failure, return nil. */ | 2860 | On failure, return nil (setting errno). */ |
| 2853 | Lisp_Object | 2861 | static Lisp_Object |
| 2854 | emacs_readlinkat (int fd, char const *filename) | 2862 | emacs_readlinkat (int fd, char const *filename) |
| 2855 | { | 2863 | { |
| 2856 | static struct allocator const emacs_norealloc_allocator = | 2864 | static struct allocator const emacs_norealloc_allocator = |
| @@ -2869,6 +2877,27 @@ emacs_readlinkat (int fd, char const *filename) | |||
| 2869 | return val; | 2877 | return val; |
| 2870 | } | 2878 | } |
| 2871 | 2879 | ||
| 2880 | /* Relative to directory FD, return the symbolic link value of FILE. | ||
| 2881 | If FILE is not a symbolic link, return nil (setting errno). | ||
| 2882 | Signal an error if the result cannot be determined. */ | ||
| 2883 | Lisp_Object | ||
| 2884 | check_emacs_readlinkat (int fd, Lisp_Object file, char const *encoded_file) | ||
| 2885 | { | ||
| 2886 | Lisp_Object val = emacs_readlinkat (fd, encoded_file); | ||
| 2887 | if (NILP (val)) | ||
| 2888 | { | ||
| 2889 | if (errno == EINVAL) | ||
| 2890 | return val; | ||
| 2891 | #ifdef CYGWIN | ||
| 2892 | /* Work around Cygwin bugs. */ | ||
| 2893 | if (errno == EIO || errno == EACCES) | ||
| 2894 | return val; | ||
| 2895 | #endif | ||
| 2896 | return file_metadata_errno ("Reading symbolic link", file, errno); | ||
| 2897 | } | ||
| 2898 | return val; | ||
| 2899 | } | ||
| 2900 | |||
| 2872 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, | 2901 | DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0, |
| 2873 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. | 2902 | doc: /* Return non-nil if file FILENAME is the name of a symbolic link. |
| 2874 | The value is the link target, as a string. | 2903 | The value is the link target, as a string. |
| @@ -2888,9 +2917,8 @@ This function does not check whether the link target exists. */) | |||
| 2888 | if (!NILP (handler)) | 2917 | if (!NILP (handler)) |
| 2889 | return call2 (handler, Qfile_symlink_p, filename); | 2918 | return call2 (handler, Qfile_symlink_p, filename); |
| 2890 | 2919 | ||
| 2891 | filename = ENCODE_FILE (filename); | 2920 | return check_emacs_readlinkat (AT_FDCWD, filename, |
| 2892 | 2921 | SSDATA (ENCODE_FILE (filename))); | |
| 2893 | return emacs_readlinkat (AT_FDCWD, SSDATA (filename)); | ||
| 2894 | } | 2922 | } |
| 2895 | 2923 | ||
| 2896 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, | 2924 | DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0, |
| @@ -2907,9 +2935,9 @@ See `file-symlink-p' to distinguish symlinks. */) | |||
| 2907 | if (!NILP (handler)) | 2935 | if (!NILP (handler)) |
| 2908 | return call2 (handler, Qfile_directory_p, absname); | 2936 | return call2 (handler, Qfile_directory_p, absname); |
| 2909 | 2937 | ||
| 2910 | absname = ENCODE_FILE (absname); | 2938 | if (file_directory_p (absname)) |
| 2911 | 2939 | return Qt; | |
| 2912 | return file_directory_p (absname) ? Qt : Qnil; | 2940 | return file_test_errno (absname, errno); |
| 2913 | } | 2941 | } |
| 2914 | 2942 | ||
| 2915 | /* Return true if FILE is a directory or a symlink to a directory. | 2943 | /* Return true if FILE is a directory or a symlink to a directory. |
| @@ -2934,7 +2962,7 @@ file_directory_p (Lisp_Object file) | |||
| 2934 | /* O_PATH is defined but evidently this Linux kernel predates 2.6.39. | 2962 | /* O_PATH is defined but evidently this Linux kernel predates 2.6.39. |
| 2935 | Fall back on generic POSIX code. */ | 2963 | Fall back on generic POSIX code. */ |
| 2936 | # endif | 2964 | # endif |
| 2937 | /* Use file_accessible_directory, as it avoids stat EOVERFLOW | 2965 | /* Use file_accessible_directory_p, as it avoids stat EOVERFLOW |
| 2938 | problems and could be cheaper. However, if it fails because FILE | 2966 | problems and could be cheaper. However, if it fails because FILE |
| 2939 | is inaccessible, fall back on stat; if the latter fails with | 2967 | is inaccessible, fall back on stat; if the latter fails with |
| 2940 | EOVERFLOW then FILE must have been a directory unless a race | 2968 | EOVERFLOW then FILE must have been a directory unless a race |
| @@ -2990,8 +3018,13 @@ really is a readable and searchable directory. */) | |||
| 2990 | return r; | 3018 | return r; |
| 2991 | } | 3019 | } |
| 2992 | 3020 | ||
| 2993 | absname = ENCODE_FILE (absname); | 3021 | Lisp_Object encoded_absname = ENCODE_FILE (absname); |
| 2994 | return file_accessible_directory_p (absname) ? Qt : Qnil; | 3022 | if (file_accessible_directory_p (encoded_absname)) |
| 3023 | return Qt; | ||
| 3024 | int err = errno; | ||
| 3025 | if (err == EACCES && file_access_p (SSDATA (encoded_absname), F_OK)) | ||
| 3026 | return Qnil; | ||
| 3027 | return file_test_errno (absname, err); | ||
| 2995 | } | 3028 | } |
| 2996 | 3029 | ||
| 2997 | /* If FILE is a searchable directory or a symlink to a | 3030 | /* If FILE is a searchable directory or a symlink to a |
| @@ -3043,7 +3076,7 @@ file_accessible_directory_p (Lisp_Object file) | |||
| 3043 | dir = buf; | 3076 | dir = buf; |
| 3044 | } | 3077 | } |
| 3045 | 3078 | ||
| 3046 | ok = check_existing (dir); | 3079 | ok = file_access_p (dir, F_OK); |
| 3047 | saved_errno = errno; | 3080 | saved_errno = errno; |
| 3048 | SAFE_FREE (); | 3081 | SAFE_FREE (); |
| 3049 | errno = saved_errno; | 3082 | errno = saved_errno; |
| @@ -3067,27 +3100,21 @@ See `file-symlink-p' to distinguish symlinks. */) | |||
| 3067 | if (!NILP (handler)) | 3100 | if (!NILP (handler)) |
| 3068 | return call2 (handler, Qfile_regular_p, absname); | 3101 | return call2 (handler, Qfile_regular_p, absname); |
| 3069 | 3102 | ||
| 3070 | absname = ENCODE_FILE (absname); | ||
| 3071 | |||
| 3072 | #ifdef WINDOWSNT | 3103 | #ifdef WINDOWSNT |
| 3073 | { | 3104 | /* Tell stat to use expensive method to get accurate info. */ |
| 3074 | int result; | 3105 | Lisp_Object true_attributes = Vw32_get_true_file_attributes; |
| 3075 | Lisp_Object tem = Vw32_get_true_file_attributes; | 3106 | Vw32_get_true_file_attributes = Qt; |
| 3107 | #endif | ||
| 3076 | 3108 | ||
| 3077 | /* Tell stat to use expensive method to get accurate info. */ | 3109 | int stat_result = stat (SSDATA (absname), &st); |
| 3078 | Vw32_get_true_file_attributes = Qt; | ||
| 3079 | result = stat (SSDATA (absname), &st); | ||
| 3080 | Vw32_get_true_file_attributes = tem; | ||
| 3081 | 3110 | ||
| 3082 | if (result < 0) | 3111 | #ifdef WINDOWSNT |
| 3083 | return Qnil; | 3112 | Vw32_get_true_file_attributes = true_attributes; |
| 3084 | return S_ISREG (st.st_mode) ? Qt : Qnil; | ||
| 3085 | } | ||
| 3086 | #else | ||
| 3087 | if (stat (SSDATA (absname), &st) < 0) | ||
| 3088 | return Qnil; | ||
| 3089 | return S_ISREG (st.st_mode) ? Qt : Qnil; | ||
| 3090 | #endif | 3113 | #endif |
| 3114 | |||
| 3115 | if (stat_result == 0) | ||
| 3116 | return S_ISREG (st.st_mode) ? Qt : Qnil; | ||
| 3117 | return file_test_errno (absname, errno); | ||
| 3091 | } | 3118 | } |
| 3092 | 3119 | ||
| 3093 | DEFUN ("file-selinux-context", Ffile_selinux_context, | 3120 | DEFUN ("file-selinux-context", Ffile_selinux_context, |
| @@ -3097,7 +3124,7 @@ The return value is a list (USER ROLE TYPE RANGE), where the list | |||
| 3097 | elements are strings naming the user, role, type, and range of the | 3124 | elements are strings naming the user, role, type, and range of the |
| 3098 | file's SELinux security context. | 3125 | file's SELinux security context. |
| 3099 | 3126 | ||
| 3100 | Return (nil nil nil nil) if the file is nonexistent or inaccessible, | 3127 | Return (nil nil nil nil) if the file is nonexistent, |
| 3101 | or if SELinux is disabled, or if Emacs lacks SELinux support. */) | 3128 | or if SELinux is disabled, or if Emacs lacks SELinux support. */) |
| 3102 | (Lisp_Object filename) | 3129 | (Lisp_Object filename) |
| 3103 | { | 3130 | { |
| @@ -3111,13 +3138,11 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */) | |||
| 3111 | if (!NILP (handler)) | 3138 | if (!NILP (handler)) |
| 3112 | return call2 (handler, Qfile_selinux_context, absname); | 3139 | return call2 (handler, Qfile_selinux_context, absname); |
| 3113 | 3140 | ||
| 3114 | absname = ENCODE_FILE (absname); | ||
| 3115 | |||
| 3116 | #if HAVE_LIBSELINUX | 3141 | #if HAVE_LIBSELINUX |
| 3117 | if (is_selinux_enabled ()) | 3142 | if (is_selinux_enabled ()) |
| 3118 | { | 3143 | { |
| 3119 | security_context_t con; | 3144 | security_context_t con; |
| 3120 | int conlength = lgetfilecon (SSDATA (absname), &con); | 3145 | int conlength = lgetfilecon (SSDATA (ENCODE_FILE (absname)), &con); |
| 3121 | if (conlength > 0) | 3146 | if (conlength > 0) |
| 3122 | { | 3147 | { |
| 3123 | context_t context = context_new (con); | 3148 | context_t context = context_new (con); |
| @@ -3132,6 +3157,9 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */) | |||
| 3132 | context_free (context); | 3157 | context_free (context); |
| 3133 | freecon (con); | 3158 | freecon (con); |
| 3134 | } | 3159 | } |
| 3160 | else if (! (errno == ENOENT || errno == ENOTDIR || errno == ENODATA | ||
| 3161 | || errno == ENOTSUP)) | ||
| 3162 | report_file_error ("getting SELinux context", absname); | ||
| 3135 | } | 3163 | } |
| 3136 | #endif | 3164 | #endif |
| 3137 | 3165 | ||
| @@ -3227,8 +3255,7 @@ DEFUN ("file-acl", Ffile_acl, Sfile_acl, 1, 1, 0, | |||
| 3227 | doc: /* Return ACL entries of file named FILENAME. | 3255 | doc: /* Return ACL entries of file named FILENAME. |
| 3228 | The entries are returned in a format suitable for use in `set-file-acl' | 3256 | The entries are returned in a format suitable for use in `set-file-acl' |
| 3229 | but is otherwise undocumented and subject to change. | 3257 | but is otherwise undocumented and subject to change. |
| 3230 | Return nil if file does not exist or is not accessible, or if Emacs | 3258 | Return nil if file does not exist. */) |
| 3231 | was unable to determine the ACL entries. */) | ||
| 3232 | (Lisp_Object filename) | 3259 | (Lisp_Object filename) |
| 3233 | { | 3260 | { |
| 3234 | Lisp_Object acl_string = Qnil; | 3261 | Lisp_Object acl_string = Qnil; |
| @@ -3243,20 +3270,22 @@ was unable to determine the ACL entries. */) | |||
| 3243 | return call2 (handler, Qfile_acl, absname); | 3270 | return call2 (handler, Qfile_acl, absname); |
| 3244 | 3271 | ||
| 3245 | # ifdef HAVE_ACL_SET_FILE | 3272 | # ifdef HAVE_ACL_SET_FILE |
| 3246 | absname = ENCODE_FILE (absname); | ||
| 3247 | |||
| 3248 | # ifndef HAVE_ACL_TYPE_EXTENDED | 3273 | # ifndef HAVE_ACL_TYPE_EXTENDED |
| 3249 | acl_type_t ACL_TYPE_EXTENDED = ACL_TYPE_ACCESS; | 3274 | acl_type_t ACL_TYPE_EXTENDED = ACL_TYPE_ACCESS; |
| 3250 | # endif | 3275 | # endif |
| 3251 | acl_t acl = acl_get_file (SSDATA (absname), ACL_TYPE_EXTENDED); | 3276 | acl_t acl = acl_get_file (SSDATA (ENCODE_FILE (absname)), ACL_TYPE_EXTENDED); |
| 3252 | if (acl == NULL) | 3277 | if (acl == NULL) |
| 3253 | return Qnil; | 3278 | { |
| 3254 | 3279 | if (errno == ENOENT || errno == ENOTDIR || errno == ENOTSUP) | |
| 3280 | return Qnil; | ||
| 3281 | report_file_error ("Getting ACLs", absname); | ||
| 3282 | } | ||
| 3255 | char *str = acl_to_text (acl, NULL); | 3283 | char *str = acl_to_text (acl, NULL); |
| 3256 | if (str == NULL) | 3284 | if (str == NULL) |
| 3257 | { | 3285 | { |
| 3286 | int err = errno; | ||
| 3258 | acl_free (acl); | 3287 | acl_free (acl); |
| 3259 | return Qnil; | 3288 | report_file_errno ("Getting ACLs", absname, err); |
| 3260 | } | 3289 | } |
| 3261 | 3290 | ||
| 3262 | acl_string = build_string (str); | 3291 | acl_string = build_string (str); |
| @@ -3327,7 +3356,7 @@ support. */) | |||
| 3327 | 3356 | ||
| 3328 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, | 3357 | DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, |
| 3329 | doc: /* Return mode bits of file named FILENAME, as an integer. | 3358 | doc: /* Return mode bits of file named FILENAME, as an integer. |
| 3330 | Return nil, if file does not exist or is not accessible. */) | 3359 | Return nil if FILENAME does not exist. */) |
| 3331 | (Lisp_Object filename) | 3360 | (Lisp_Object filename) |
| 3332 | { | 3361 | { |
| 3333 | struct stat st; | 3362 | struct stat st; |
| @@ -3339,11 +3368,8 @@ Return nil, if file does not exist or is not accessible. */) | |||
| 3339 | if (!NILP (handler)) | 3368 | if (!NILP (handler)) |
| 3340 | return call2 (handler, Qfile_modes, absname); | 3369 | return call2 (handler, Qfile_modes, absname); |
| 3341 | 3370 | ||
| 3342 | absname = ENCODE_FILE (absname); | 3371 | if (stat (SSDATA (ENCODE_FILE (absname)), &st) != 0) |
| 3343 | 3372 | return file_attribute_errno (absname, errno); | |
| 3344 | if (stat (SSDATA (absname), &st) < 0) | ||
| 3345 | return Qnil; | ||
| 3346 | |||
| 3347 | return make_fixnum (st.st_mode & 07777); | 3373 | return make_fixnum (st.st_mode & 07777); |
| 3348 | } | 3374 | } |
| 3349 | 3375 | ||
| @@ -3487,14 +3513,27 @@ otherwise, if FILE2 does not exist, the answer is t. */) | |||
| 3487 | if (!NILP (handler)) | 3513 | if (!NILP (handler)) |
| 3488 | return call3 (handler, Qfile_newer_than_file_p, absname1, absname2); | 3514 | return call3 (handler, Qfile_newer_than_file_p, absname1, absname2); |
| 3489 | 3515 | ||
| 3490 | absname1 = ENCODE_FILE (absname1); | 3516 | int err1; |
| 3491 | absname2 = ENCODE_FILE (absname2); | 3517 | if (stat (SSDATA (ENCODE_FILE (absname1)), &st1) == 0) |
| 3518 | err1 = 0; | ||
| 3519 | else | ||
| 3520 | { | ||
| 3521 | err1 = errno; | ||
| 3522 | if (err1 != EOVERFLOW) | ||
| 3523 | return file_test_errno (absname1, err1); | ||
| 3524 | } | ||
| 3492 | 3525 | ||
| 3493 | if (stat (SSDATA (absname1), &st1) < 0) | 3526 | if (stat (SSDATA (ENCODE_FILE (absname2)), &st2) != 0) |
| 3494 | return Qnil; | 3527 | { |
| 3528 | file_test_errno (absname2, errno); | ||
| 3529 | return Qt; | ||
| 3530 | } | ||
| 3495 | 3531 | ||
| 3496 | if (stat (SSDATA (absname2), &st2) < 0) | 3532 | if (err1) |
| 3497 | return Qt; | 3533 | { |
| 3534 | file_test_errno (absname1, err1); | ||
| 3535 | eassume (false); | ||
| 3536 | } | ||
| 3498 | 3537 | ||
| 3499 | return (timespec_cmp (get_stat_mtime (&st2), get_stat_mtime (&st1)) < 0 | 3538 | return (timespec_cmp (get_stat_mtime (&st2), get_stat_mtime (&st1)) < 0 |
| 3500 | ? Qt : Qnil); | 3539 | ? Qt : Qnil); |
| @@ -5686,13 +5725,13 @@ in `current-time' or an integer flag as returned by `visited-file-modtime'. */) | |||
| 5686 | /* The handler can find the file name the same way we did. */ | 5725 | /* The handler can find the file name the same way we did. */ |
| 5687 | return call2 (handler, Qset_visited_file_modtime, Qnil); | 5726 | return call2 (handler, Qset_visited_file_modtime, Qnil); |
| 5688 | 5727 | ||
| 5689 | filename = ENCODE_FILE (filename); | 5728 | if (stat (SSDATA (ENCODE_FILE (filename)), &st) == 0) |
| 5690 | |||
| 5691 | if (stat (SSDATA (filename), &st) >= 0) | ||
| 5692 | { | 5729 | { |
| 5693 | current_buffer->modtime = get_stat_mtime (&st); | 5730 | current_buffer->modtime = get_stat_mtime (&st); |
| 5694 | current_buffer->modtime_size = st.st_size; | 5731 | current_buffer->modtime_size = st.st_size; |
| 5695 | } | 5732 | } |
| 5733 | else | ||
| 5734 | file_attribute_errno (filename, errno); | ||
| 5696 | } | 5735 | } |
| 5697 | 5736 | ||
| 5698 | return Qnil; | 5737 | return Qnil; |
| @@ -6103,22 +6142,22 @@ storage available to a non-superuser. All 3 numbers are in bytes. | |||
| 6103 | If the underlying system call fails, value is nil. */) | 6142 | If the underlying system call fails, value is nil. */) |
| 6104 | (Lisp_Object filename) | 6143 | (Lisp_Object filename) |
| 6105 | { | 6144 | { |
| 6106 | Lisp_Object encoded = ENCODE_FILE (Fexpand_file_name (filename, Qnil)); | 6145 | filename = Fexpand_file_name (filename, Qnil); |
| 6107 | 6146 | ||
| 6108 | /* If the file name has special constructs in it, | 6147 | /* If the file name has special constructs in it, |
| 6109 | call the corresponding file name handler. */ | 6148 | call the corresponding file name handler. */ |
| 6110 | Lisp_Object handler = Ffind_file_name_handler (encoded, Qfile_system_info); | 6149 | Lisp_Object handler = Ffind_file_name_handler (filename, Qfile_system_info); |
| 6111 | if (!NILP (handler)) | 6150 | if (!NILP (handler)) |
| 6112 | { | 6151 | { |
| 6113 | Lisp_Object result = call2 (handler, Qfile_system_info, encoded); | 6152 | Lisp_Object result = call2 (handler, Qfile_system_info, filename); |
| 6114 | if (CONSP (result) || NILP (result)) | 6153 | if (CONSP (result) || NILP (result)) |
| 6115 | return result; | 6154 | return result; |
| 6116 | error ("Invalid handler in `file-name-handler-alist'"); | 6155 | error ("Invalid handler in `file-name-handler-alist'"); |
| 6117 | } | 6156 | } |
| 6118 | 6157 | ||
| 6119 | struct fs_usage u; | 6158 | struct fs_usage u; |
| 6120 | if (get_fs_usage (SSDATA (encoded), NULL, &u) != 0) | 6159 | if (get_fs_usage (SSDATA (ENCODE_FILE (filename)), NULL, &u) != 0) |
| 6121 | return Qnil; | 6160 | return errno == ENOSYS ? Qnil : file_attribute_errno (filename, errno); |
| 6122 | return list3 (blocks_to_bytes (u.fsu_blocksize, u.fsu_blocks, false), | 6161 | return list3 (blocks_to_bytes (u.fsu_blocksize, u.fsu_blocks, false), |
| 6123 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false), | 6162 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false), |
| 6124 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail, | 6163 | blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail, |
diff --git a/src/filelock.c b/src/filelock.c index 46349a63e4a..ff25d6475de 100644 --- a/src/filelock.c +++ b/src/filelock.c | |||
| @@ -504,9 +504,9 @@ read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1]) | |||
| 504 | } | 504 | } |
| 505 | 505 | ||
| 506 | /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, | 506 | /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, |
| 507 | 1 if another process owns it (and set OWNER (if non-null) to info), | 507 | -1 if another process owns it (and set OWNER (if non-null) to info), |
| 508 | 2 if the current process owns it, | 508 | -2 if the current process owns it, |
| 509 | or -1 if something is wrong with the locking mechanism. */ | 509 | or an errno value if something is wrong with the locking mechanism. */ |
| 510 | 510 | ||
| 511 | static int | 511 | static int |
| 512 | current_lock_owner (lock_info_type *owner, char *lfname) | 512 | current_lock_owner (lock_info_type *owner, char *lfname) |
| @@ -525,23 +525,23 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 525 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ | 525 | /* If nonexistent lock file, all is well; otherwise, got strange error. */ |
| 526 | lfinfolen = read_lock_data (lfname, owner->user); | 526 | lfinfolen = read_lock_data (lfname, owner->user); |
| 527 | if (lfinfolen < 0) | 527 | if (lfinfolen < 0) |
| 528 | return errno == ENOENT ? 0 : -1; | 528 | return errno == ENOENT ? 0 : errno; |
| 529 | if (MAX_LFINFO < lfinfolen) | 529 | if (MAX_LFINFO < lfinfolen) |
| 530 | return -1; | 530 | return ENAMETOOLONG; |
| 531 | owner->user[lfinfolen] = 0; | 531 | owner->user[lfinfolen] = 0; |
| 532 | 532 | ||
| 533 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */ | 533 | /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return EINVAL. */ |
| 534 | /* The USER is everything before the last @. */ | 534 | /* The USER is everything before the last @. */ |
| 535 | owner->at = at = memrchr (owner->user, '@', lfinfolen); | 535 | owner->at = at = memrchr (owner->user, '@', lfinfolen); |
| 536 | if (!at) | 536 | if (!at) |
| 537 | return -1; | 537 | return EINVAL; |
| 538 | owner->dot = dot = strrchr (at, '.'); | 538 | owner->dot = dot = strrchr (at, '.'); |
| 539 | if (!dot) | 539 | if (!dot) |
| 540 | return -1; | 540 | return EINVAL; |
| 541 | 541 | ||
| 542 | /* The PID is everything from the last '.' to the ':' or equivalent. */ | 542 | /* The PID is everything from the last '.' to the ':' or equivalent. */ |
| 543 | if (! c_isdigit (dot[1])) | 543 | if (! c_isdigit (dot[1])) |
| 544 | return -1; | 544 | return EINVAL; |
| 545 | errno = 0; | 545 | errno = 0; |
| 546 | pid = strtoimax (dot + 1, &owner->colon, 10); | 546 | pid = strtoimax (dot + 1, &owner->colon, 10); |
| 547 | if (errno == ERANGE) | 547 | if (errno == ERANGE) |
| @@ -562,20 +562,20 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 562 | mistakenly transliterate ':' to U+F022 in symlink contents. | 562 | mistakenly transliterate ':' to U+F022 in symlink contents. |
| 563 | See <https://bugzilla.redhat.com/show_bug.cgi?id=1384153>. */ | 563 | See <https://bugzilla.redhat.com/show_bug.cgi?id=1384153>. */ |
| 564 | if (! (boot[0] == '\200' && boot[1] == '\242')) | 564 | if (! (boot[0] == '\200' && boot[1] == '\242')) |
| 565 | return -1; | 565 | return EINVAL; |
| 566 | boot += 2; | 566 | boot += 2; |
| 567 | FALLTHROUGH; | 567 | FALLTHROUGH; |
| 568 | case ':': | 568 | case ':': |
| 569 | if (! c_isdigit (boot[0])) | 569 | if (! c_isdigit (boot[0])) |
| 570 | return -1; | 570 | return EINVAL; |
| 571 | boot_time = strtoimax (boot, &lfinfo_end, 10); | 571 | boot_time = strtoimax (boot, &lfinfo_end, 10); |
| 572 | break; | 572 | break; |
| 573 | 573 | ||
| 574 | default: | 574 | default: |
| 575 | return -1; | 575 | return EINVAL; |
| 576 | } | 576 | } |
| 577 | if (lfinfo_end != owner->user + lfinfolen) | 577 | if (lfinfo_end != owner->user + lfinfolen) |
| 578 | return -1; | 578 | return EINVAL; |
| 579 | 579 | ||
| 580 | /* On current host? */ | 580 | /* On current host? */ |
| 581 | Lisp_Object system_name = Fsystem_name (); | 581 | Lisp_Object system_name = Fsystem_name (); |
| @@ -584,22 +584,22 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 584 | && memcmp (at + 1, SSDATA (system_name), SBYTES (system_name)) == 0) | 584 | && memcmp (at + 1, SSDATA (system_name), SBYTES (system_name)) == 0) |
| 585 | { | 585 | { |
| 586 | if (pid == getpid ()) | 586 | if (pid == getpid ()) |
| 587 | ret = 2; /* We own it. */ | 587 | ret = -2; /* We own it. */ |
| 588 | else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t) | 588 | else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t) |
| 589 | && (kill (pid, 0) >= 0 || errno == EPERM) | 589 | && (kill (pid, 0) >= 0 || errno == EPERM) |
| 590 | && (boot_time == 0 | 590 | && (boot_time == 0 |
| 591 | || (boot_time <= TYPE_MAXIMUM (time_t) | 591 | || (boot_time <= TYPE_MAXIMUM (time_t) |
| 592 | && within_one_second (boot_time, get_boot_time ())))) | 592 | && within_one_second (boot_time, get_boot_time ())))) |
| 593 | ret = 1; /* An existing process on this machine owns it. */ | 593 | ret = -1; /* An existing process on this machine owns it. */ |
| 594 | /* The owner process is dead or has a strange pid, so try to | 594 | /* The owner process is dead or has a strange pid, so try to |
| 595 | zap the lockfile. */ | 595 | zap the lockfile. */ |
| 596 | else | 596 | else |
| 597 | return unlink (lfname); | 597 | return unlink (lfname) < 0 ? errno : 0; |
| 598 | } | 598 | } |
| 599 | else | 599 | else |
| 600 | { /* If we wanted to support the check for stale locks on remote machines, | 600 | { /* If we wanted to support the check for stale locks on remote machines, |
| 601 | here's where we'd do it. */ | 601 | here's where we'd do it. */ |
| 602 | ret = 1; | 602 | ret = -1; |
| 603 | } | 603 | } |
| 604 | 604 | ||
| 605 | return ret; | 605 | return ret; |
| @@ -608,9 +608,9 @@ current_lock_owner (lock_info_type *owner, char *lfname) | |||
| 608 | 608 | ||
| 609 | /* Lock the lock named LFNAME if possible. | 609 | /* Lock the lock named LFNAME if possible. |
| 610 | Return 0 in that case. | 610 | Return 0 in that case. |
| 611 | Return positive if some other process owns the lock, and info about | 611 | Return negative if some other process owns the lock, and info about |
| 612 | that process in CLASHER. | 612 | that process in CLASHER. |
| 613 | Return -1 if cannot lock for any other reason. */ | 613 | Return positive errno value if cannot lock for any other reason. */ |
| 614 | 614 | ||
| 615 | static int | 615 | static int |
| 616 | lock_if_free (lock_info_type *clasher, char *lfname) | 616 | lock_if_free (lock_info_type *clasher, char *lfname) |
| @@ -618,20 +618,18 @@ lock_if_free (lock_info_type *clasher, char *lfname) | |||
| 618 | int err; | 618 | int err; |
| 619 | while ((err = lock_file_1 (lfname, 0)) == EEXIST) | 619 | while ((err = lock_file_1 (lfname, 0)) == EEXIST) |
| 620 | { | 620 | { |
| 621 | switch (current_lock_owner (clasher, lfname)) | 621 | err = current_lock_owner (clasher, lfname); |
| 622 | if (err != 0) | ||
| 622 | { | 623 | { |
| 623 | case 2: | 624 | if (err < 0) |
| 624 | return 0; /* We ourselves locked it. */ | 625 | return -2 - err; /* We locked it, or someone else has it. */ |
| 625 | case 1: | 626 | break; /* current_lock_owner returned strange error. */ |
| 626 | return 1; /* Someone else has it. */ | ||
| 627 | case -1: | ||
| 628 | return -1; /* current_lock_owner returned strange error. */ | ||
| 629 | } | 627 | } |
| 630 | 628 | ||
| 631 | /* We deleted a stale lock; try again to lock the file. */ | 629 | /* We deleted a stale lock; try again to lock the file. */ |
| 632 | } | 630 | } |
| 633 | 631 | ||
| 634 | return err ? -1 : 0; | 632 | return err; |
| 635 | } | 633 | } |
| 636 | 634 | ||
| 637 | /* lock_file locks file FN, | 635 | /* lock_file locks file FN, |
| @@ -697,8 +695,9 @@ lock_file (Lisp_Object fn) | |||
| 697 | /* Create the name of the lock-file for file fn */ | 695 | /* Create the name of the lock-file for file fn */ |
| 698 | MAKE_LOCK_NAME (lfname, encoded_fn); | 696 | MAKE_LOCK_NAME (lfname, encoded_fn); |
| 699 | 697 | ||
| 700 | /* Try to lock the lock. */ | 698 | /* Try to lock the lock. FIXME: This ignores errors when |
| 701 | if (0 < lock_if_free (&lock_info, lfname)) | 699 | lock_if_free returns a positive errno value. */ |
| 700 | if (lock_if_free (&lock_info, lfname) < 0) | ||
| 702 | { | 701 | { |
| 703 | /* Someone else has the lock. Consider breaking it. */ | 702 | /* Someone else has the lock. Consider breaking it. */ |
| 704 | Lisp_Object attack; | 703 | Lisp_Object attack; |
| @@ -725,13 +724,16 @@ unlock_file (Lisp_Object fn) | |||
| 725 | char *lfname; | 724 | char *lfname; |
| 726 | USE_SAFE_ALLOCA; | 725 | USE_SAFE_ALLOCA; |
| 727 | 726 | ||
| 728 | fn = Fexpand_file_name (fn, Qnil); | 727 | Lisp_Object filename = Fexpand_file_name (fn, Qnil); |
| 729 | fn = ENCODE_FILE (fn); | 728 | fn = ENCODE_FILE (filename); |
| 730 | 729 | ||
| 731 | MAKE_LOCK_NAME (lfname, fn); | 730 | MAKE_LOCK_NAME (lfname, fn); |
| 732 | 731 | ||
| 733 | if (current_lock_owner (0, lfname) == 2) | 732 | int err = current_lock_owner (0, lfname); |
| 734 | unlink (lfname); | 733 | if (err == -2 && unlink (lfname) != 0 && errno != ENOENT) |
| 734 | err = errno; | ||
| 735 | if (0 < err) | ||
| 736 | report_file_errno ("Unlocking file", filename, err); | ||
| 735 | 737 | ||
| 736 | SAFE_FREE (); | 738 | SAFE_FREE (); |
| 737 | } | 739 | } |
| @@ -822,17 +824,17 @@ t if it is locked by you, else a string saying which user has locked it. */) | |||
| 822 | USE_SAFE_ALLOCA; | 824 | USE_SAFE_ALLOCA; |
| 823 | 825 | ||
| 824 | filename = Fexpand_file_name (filename, Qnil); | 826 | filename = Fexpand_file_name (filename, Qnil); |
| 825 | filename = ENCODE_FILE (filename); | 827 | Lisp_Object encoded_filename = ENCODE_FILE (filename); |
| 826 | 828 | MAKE_LOCK_NAME (lfname, encoded_filename); | |
| 827 | MAKE_LOCK_NAME (lfname, filename); | ||
| 828 | 829 | ||
| 829 | owner = current_lock_owner (&locker, lfname); | 830 | owner = current_lock_owner (&locker, lfname); |
| 830 | if (owner <= 0) | 831 | switch (owner) |
| 831 | ret = Qnil; | 832 | { |
| 832 | else if (owner == 2) | 833 | case -2: ret = Qt; break; |
| 833 | ret = Qt; | 834 | case -1: ret = make_string (locker.user, locker.at - locker.user); break; |
| 834 | else | 835 | case 0: ret = Qnil; break; |
| 835 | ret = make_string (locker.user, locker.at - locker.user); | 836 | default: report_file_errno ("Testing file lock", filename, owner); |
| 837 | } | ||
| 836 | 838 | ||
| 837 | SAFE_FREE (); | 839 | SAFE_FREE (); |
| 838 | return ret; | 840 | return ret; |
diff --git a/src/lisp.h b/src/lisp.h index 02f8a7b6686..e68d2732e21 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4299,7 +4299,6 @@ extern void syms_of_marker (void); | |||
| 4299 | 4299 | ||
| 4300 | /* Defined in fileio.c. */ | 4300 | /* Defined in fileio.c. */ |
| 4301 | 4301 | ||
| 4302 | extern bool check_executable (char *); | ||
| 4303 | extern char *splice_dir_file (char *, char const *, char const *); | 4302 | extern char *splice_dir_file (char *, char const *, char const *); |
| 4304 | extern bool file_name_absolute_p (const char *); | 4303 | extern bool file_name_absolute_p (const char *); |
| 4305 | extern char const *get_homedir (void); | 4304 | extern char const *get_homedir (void); |
| @@ -4310,12 +4309,14 @@ extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object, | |||
| 4310 | extern void close_file_unwind (int); | 4309 | extern void close_file_unwind (int); |
| 4311 | extern void fclose_unwind (void *); | 4310 | extern void fclose_unwind (void *); |
| 4312 | extern void restore_point_unwind (Lisp_Object); | 4311 | extern void restore_point_unwind (Lisp_Object); |
| 4312 | extern bool file_access_p (char const *, int); | ||
| 4313 | extern Lisp_Object get_file_errno_data (const char *, Lisp_Object, int); | 4313 | extern Lisp_Object get_file_errno_data (const char *, Lisp_Object, int); |
| 4314 | extern AVOID report_file_errno (const char *, Lisp_Object, int); | 4314 | 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 bool internal_delete_file (Lisp_Object); | 4318 | extern bool internal_delete_file (Lisp_Object); |
| 4318 | extern Lisp_Object emacs_readlinkat (int, const char *); | 4319 | extern Lisp_Object check_emacs_readlinkat (int, Lisp_Object, char const *); |
| 4319 | extern bool file_directory_p (Lisp_Object); | 4320 | extern bool file_directory_p (Lisp_Object); |
| 4320 | extern bool file_accessible_directory_p (Lisp_Object); | 4321 | extern bool file_accessible_directory_p (Lisp_Object); |
| 4321 | extern void init_fileio (void); | 4322 | extern void init_fileio (void); |
diff --git a/src/lread.c b/src/lread.c index 6ae7a0d8ba0..d8883db46c1 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -1346,15 +1346,22 @@ Return t if the file exists and loads successfully. */) | |||
| 1346 | if (!load_prefer_newer && is_elc) | 1346 | if (!load_prefer_newer && is_elc) |
| 1347 | { | 1347 | { |
| 1348 | result = stat (SSDATA (efound), &s1); | 1348 | result = stat (SSDATA (efound), &s1); |
| 1349 | int err = errno; | ||
| 1349 | if (result == 0) | 1350 | if (result == 0) |
| 1350 | { | 1351 | { |
| 1351 | SSET (efound, SBYTES (efound) - 1, 0); | 1352 | SSET (efound, SBYTES (efound) - 1, 0); |
| 1352 | result = stat (SSDATA (efound), &s2); | 1353 | result = stat (SSDATA (efound), &s2); |
| 1354 | err = errno; | ||
| 1353 | SSET (efound, SBYTES (efound) - 1, 'c'); | 1355 | SSET (efound, SBYTES (efound) - 1, 'c'); |
| 1356 | if (result != 0) | ||
| 1357 | found = Fsubstring (found, make_fixnum (0), | ||
| 1358 | make_fixnum (-1)); | ||
| 1354 | } | 1359 | } |
| 1355 | 1360 | if (result != 0) | |
| 1356 | if (result == 0 | 1361 | file_attribute_errno (found, err); |
| 1357 | && timespec_cmp (get_stat_mtime (&s1), get_stat_mtime (&s2)) < 0) | 1362 | else if (timespec_cmp (get_stat_mtime (&s1), |
| 1363 | get_stat_mtime (&s2)) | ||
| 1364 | < 0) | ||
| 1358 | { | 1365 | { |
| 1359 | /* Make the progress messages mention that source is newer. */ | 1366 | /* Make the progress messages mention that source is newer. */ |
| 1360 | newer = 1; | 1367 | newer = 1; |
| @@ -1748,16 +1755,20 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, | |||
| 1748 | { | 1755 | { |
| 1749 | if (file_directory_p (encoded_fn)) | 1756 | if (file_directory_p (encoded_fn)) |
| 1750 | last_errno = EISDIR; | 1757 | last_errno = EISDIR; |
| 1751 | else | 1758 | else if (errno == ENOENT || errno == ENOTDIR) |
| 1752 | fd = 1; | 1759 | fd = 1; |
| 1760 | else | ||
| 1761 | last_errno = errno; | ||
| 1753 | } | 1762 | } |
| 1763 | else if (! (errno == ENOENT || errno == ENOTDIR)) | ||
| 1764 | last_errno = errno; | ||
| 1754 | } | 1765 | } |
| 1755 | else | 1766 | else |
| 1756 | { | 1767 | { |
| 1757 | fd = emacs_open (pfn, O_RDONLY, 0); | 1768 | fd = emacs_open (pfn, O_RDONLY, 0); |
| 1758 | if (fd < 0) | 1769 | if (fd < 0) |
| 1759 | { | 1770 | { |
| 1760 | if (errno != ENOENT) | 1771 | if (! (errno == ENOENT || errno == ENOTDIR)) |
| 1761 | last_errno = errno; | 1772 | last_errno = errno; |
| 1762 | } | 1773 | } |
| 1763 | else | 1774 | else |