diff options
| author | Paul Eggert | 2013-07-17 10:24:54 -0700 |
|---|---|---|
| committer | Paul Eggert | 2013-07-17 10:24:54 -0700 |
| commit | a0931322f6c257bb4a4a678f62dcb4ae3b253221 (patch) | |
| tree | 2c597df44098b26fb66026354ef17738ee922635 /src | |
| parent | 5dc8a629877b040a5dd5904815ed885949614948 (diff) | |
| download | emacs-a0931322f6c257bb4a4a678f62dcb4ae3b253221.tar.gz emacs-a0931322f6c257bb4a4a678f62dcb4ae3b253221.zip | |
* lread.c: Fix file descriptor leaks and errno issues.
(Fload): Close some races that leaked fds or streams when 'load'
was interrupted.
(Fload, openp): Report error number of last nontrivial failure to open.
ENOENT counts as trivial.
* eval.c (do_nothing, clear_unwind_protect, set_unwind_protect_ptr):
New functions.
* fileio.c (close_file_unwind): No need to test whether FD is nonnegative,
now that the function is always called with a nonnegative arg.
* lisp.h (set_unwind_protect_ptr, set_unwind_protect_int): Remove.
All uses replaced with ...
(clear_unwind_protect, set_unwind_protect_ptr): New decls.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 13 | ||||
| -rw-r--r-- | src/editfns.c | 2 | ||||
| -rw-r--r-- | src/eval.c | 21 | ||||
| -rw-r--r-- | src/fileio.c | 7 | ||||
| -rw-r--r-- | src/lisp.h | 14 | ||||
| -rw-r--r-- | src/lread.c | 111 |
6 files changed, 103 insertions, 65 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 23334449ef3..189a353bde6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,18 @@ | |||
| 1 | 2013-07-17 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2013-07-17 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | * lread.c: Fix file descriptor leaks and errno issues. | ||
| 4 | (Fload): Close some races that leaked fds or streams when 'load' | ||
| 5 | was interrupted. | ||
| 6 | (Fload, openp): Report error number of last nontrivial failure to open. | ||
| 7 | ENOENT counts as trivial. | ||
| 8 | * eval.c (do_nothing, clear_unwind_protect, set_unwind_protect_ptr): | ||
| 9 | New functions. | ||
| 10 | * fileio.c (close_file_unwind): No need to test whether FD is nonnegative, | ||
| 11 | now that the function is always called with a nonnegative arg. | ||
| 12 | * lisp.h (set_unwind_protect_ptr, set_unwind_protect_int): Remove. | ||
| 13 | All uses replaced with ... | ||
| 14 | (clear_unwind_protect, set_unwind_protect_ptr): New decls. | ||
| 15 | |||
| 3 | A few more minor file errno-reporting bugs. | 16 | A few more minor file errno-reporting bugs. |
| 4 | * callproc.c (Fcall_process): | 17 | * callproc.c (Fcall_process): |
| 5 | * doc.c (Fsnarf_documentation): | 18 | * doc.c (Fsnarf_documentation): |
diff --git a/src/editfns.c b/src/editfns.c index b8fce7c1935..a4dea203a22 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -4238,7 +4238,7 @@ usage: (format STRING &rest OBJECTS) */) | |||
| 4238 | else | 4238 | else |
| 4239 | { | 4239 | { |
| 4240 | buf = xrealloc (buf, bufsize); | 4240 | buf = xrealloc (buf, bufsize); |
| 4241 | set_unwind_protect_ptr (buf_save_value_index, buf); | 4241 | set_unwind_protect_ptr (buf_save_value_index, xfree, buf); |
| 4242 | } | 4242 | } |
| 4243 | 4243 | ||
| 4244 | p = buf + used; | 4244 | p = buf + used; |
diff --git a/src/eval.c b/src/eval.c index 6632084146f..a4f94ee1415 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -3225,6 +3225,27 @@ record_unwind_protect_void (void (*function) (void)) | |||
| 3225 | grow_specpdl (); | 3225 | grow_specpdl (); |
| 3226 | } | 3226 | } |
| 3227 | 3227 | ||
| 3228 | static void | ||
| 3229 | do_nothing (void) | ||
| 3230 | {} | ||
| 3231 | |||
| 3232 | void | ||
| 3233 | clear_unwind_protect (ptrdiff_t count) | ||
| 3234 | { | ||
| 3235 | union specbinding *p = specpdl + count; | ||
| 3236 | p->unwind_void.kind = SPECPDL_UNWIND_VOID; | ||
| 3237 | p->unwind_void.func = do_nothing; | ||
| 3238 | } | ||
| 3239 | |||
| 3240 | void | ||
| 3241 | set_unwind_protect_ptr (ptrdiff_t count, void (*func) (void *), void *arg) | ||
| 3242 | { | ||
| 3243 | union specbinding *p = specpdl + count; | ||
| 3244 | p->unwind_ptr.kind = SPECPDL_UNWIND_PTR; | ||
| 3245 | p->unwind_ptr.func = func; | ||
| 3246 | p->unwind_ptr.arg = arg; | ||
| 3247 | } | ||
| 3248 | |||
| 3228 | Lisp_Object | 3249 | Lisp_Object |
| 3229 | unbind_to (ptrdiff_t count, Lisp_Object value) | 3250 | unbind_to (ptrdiff_t count, Lisp_Object value) |
| 3230 | { | 3251 | { |
diff --git a/src/fileio.c b/src/fileio.c index 06a0db2316f..28b2dc84726 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -217,8 +217,7 @@ report_file_error (char const *string, Lisp_Object name) | |||
| 217 | void | 217 | void |
| 218 | close_file_unwind (int fd) | 218 | close_file_unwind (int fd) |
| 219 | { | 219 | { |
| 220 | if (0 <= fd) | 220 | emacs_close (fd); |
| 221 | emacs_close (fd); | ||
| 222 | } | 221 | } |
| 223 | 222 | ||
| 224 | /* Restore point, having saved it as a marker. */ | 223 | /* Restore point, having saved it as a marker. */ |
| @@ -4029,7 +4028,7 @@ by calling `format-decode', which see. */) | |||
| 4029 | if (this < 0) | 4028 | if (this < 0) |
| 4030 | report_file_error ("Read error", orig_filename); | 4029 | report_file_error ("Read error", orig_filename); |
| 4031 | emacs_close (fd); | 4030 | emacs_close (fd); |
| 4032 | set_unwind_protect_int (fd_index, -1); | 4031 | clear_unwind_protect (fd_index); |
| 4033 | 4032 | ||
| 4034 | if (unprocessed > 0) | 4033 | if (unprocessed > 0) |
| 4035 | { | 4034 | { |
| @@ -4270,7 +4269,7 @@ by calling `format-decode', which see. */) | |||
| 4270 | Vdeactivate_mark = Qt; | 4269 | Vdeactivate_mark = Qt; |
| 4271 | 4270 | ||
| 4272 | emacs_close (fd); | 4271 | emacs_close (fd); |
| 4273 | set_unwind_protect_int (fd_index, -1); | 4272 | clear_unwind_protect (fd_index); |
| 4274 | 4273 | ||
| 4275 | if (how_much < 0) | 4274 | if (how_much < 0) |
| 4276 | report_file_error ("Read error", orig_filename); | 4275 | report_file_error ("Read error", orig_filename); |
diff --git a/src/lisp.h b/src/lisp.h index 26e9e18ec9a..231dbee2d21 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2744,18 +2744,6 @@ SPECPDL_INDEX (void) | |||
| 2744 | return specpdl_ptr - specpdl; | 2744 | return specpdl_ptr - specpdl; |
| 2745 | } | 2745 | } |
| 2746 | 2746 | ||
| 2747 | LISP_INLINE void | ||
| 2748 | set_unwind_protect_ptr (ptrdiff_t count, void *arg) | ||
| 2749 | { | ||
| 2750 | specpdl[count].unwind_ptr.arg = arg; | ||
| 2751 | } | ||
| 2752 | |||
| 2753 | LISP_INLINE void | ||
| 2754 | set_unwind_protect_int (ptrdiff_t count, int arg) | ||
| 2755 | { | ||
| 2756 | specpdl[count].unwind_int.arg = arg; | ||
| 2757 | } | ||
| 2758 | |||
| 2759 | /* Everything needed to describe an active condition case. | 2747 | /* Everything needed to describe an active condition case. |
| 2760 | 2748 | ||
| 2761 | Members are volatile if their values need to survive _longjmp when | 2749 | Members are volatile if their values need to survive _longjmp when |
| @@ -3755,6 +3743,8 @@ extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object); | |||
| 3755 | extern void record_unwind_protect_int (void (*) (int), int); | 3743 | extern void record_unwind_protect_int (void (*) (int), int); |
| 3756 | extern void record_unwind_protect_ptr (void (*) (void *), void *); | 3744 | extern void record_unwind_protect_ptr (void (*) (void *), void *); |
| 3757 | extern void record_unwind_protect_void (void (*) (void)); | 3745 | extern void record_unwind_protect_void (void (*) (void)); |
| 3746 | extern void clear_unwind_protect (ptrdiff_t); | ||
| 3747 | extern void set_unwind_protect_ptr (ptrdiff_t, void (*) (void *), void *); | ||
| 3758 | extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object); | 3748 | extern Lisp_Object unbind_to (ptrdiff_t, Lisp_Object); |
| 3759 | extern _Noreturn void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); | 3749 | extern _Noreturn void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2); |
| 3760 | extern _Noreturn void verror (const char *, va_list) | 3750 | extern _Noreturn void verror (const char *, va_list) |
diff --git a/src/lread.c b/src/lread.c index c4bc6fda812..ee387b832c5 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -1040,10 +1040,12 @@ While the file is in the process of being loaded, the variable | |||
| 1040 | is bound to the file's name. | 1040 | is bound to the file's name. |
| 1041 | 1041 | ||
| 1042 | Return t if the file exists and loads successfully. */) | 1042 | Return t if the file exists and loads successfully. */) |
| 1043 | (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage, Lisp_Object nosuffix, Lisp_Object must_suffix) | 1043 | (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage, |
| 1044 | Lisp_Object nosuffix, Lisp_Object must_suffix) | ||
| 1044 | { | 1045 | { |
| 1045 | register FILE *stream; | 1046 | FILE *stream; |
| 1046 | register int fd = -1; | 1047 | int fd; |
| 1048 | int fd_index; | ||
| 1047 | ptrdiff_t count = SPECPDL_INDEX (); | 1049 | ptrdiff_t count = SPECPDL_INDEX (); |
| 1048 | struct gcpro gcpro1, gcpro2, gcpro3; | 1050 | struct gcpro gcpro1, gcpro2, gcpro3; |
| 1049 | Lisp_Object found, efound, hist_file_name; | 1051 | Lisp_Object found, efound, hist_file_name; |
| @@ -1054,7 +1056,6 @@ Return t if the file exists and loads successfully. */) | |||
| 1054 | Lisp_Object handler; | 1056 | Lisp_Object handler; |
| 1055 | bool safe_p = 1; | 1057 | bool safe_p = 1; |
| 1056 | const char *fmode = "r"; | 1058 | const char *fmode = "r"; |
| 1057 | Lisp_Object tmp[2]; | ||
| 1058 | int version; | 1059 | int version; |
| 1059 | 1060 | ||
| 1060 | #ifdef DOS_NT | 1061 | #ifdef DOS_NT |
| @@ -1087,19 +1088,23 @@ Return t if the file exists and loads successfully. */) | |||
| 1087 | else | 1088 | else |
| 1088 | file = Fsubstitute_in_file_name (file); | 1089 | file = Fsubstitute_in_file_name (file); |
| 1089 | 1090 | ||
| 1090 | |||
| 1091 | /* Avoid weird lossage with null string as arg, | 1091 | /* Avoid weird lossage with null string as arg, |
| 1092 | since it would try to load a directory as a Lisp file. */ | 1092 | since it would try to load a directory as a Lisp file. */ |
| 1093 | if (SBYTES (file) > 0) | 1093 | if (SCHARS (file) == 0) |
| 1094 | { | 1094 | { |
| 1095 | ptrdiff_t size = SBYTES (file); | 1095 | fd = -1; |
| 1096 | 1096 | errno = ENOENT; | |
| 1097 | } | ||
| 1098 | else | ||
| 1099 | { | ||
| 1100 | Lisp_Object suffixes; | ||
| 1097 | found = Qnil; | 1101 | found = Qnil; |
| 1098 | GCPRO2 (file, found); | 1102 | GCPRO2 (file, found); |
| 1099 | 1103 | ||
| 1100 | if (! NILP (must_suffix)) | 1104 | if (! NILP (must_suffix)) |
| 1101 | { | 1105 | { |
| 1102 | /* Don't insist on adding a suffix if FILE already ends with one. */ | 1106 | /* Don't insist on adding a suffix if FILE already ends with one. */ |
| 1107 | ptrdiff_t size = SBYTES (file); | ||
| 1103 | if (size > 3 | 1108 | if (size > 3 |
| 1104 | && !strcmp (SSDATA (file) + size - 3, ".el")) | 1109 | && !strcmp (SSDATA (file) + size - 3, ".el")) |
| 1105 | must_suffix = Qnil; | 1110 | must_suffix = Qnil; |
| @@ -1112,20 +1117,28 @@ Return t if the file exists and loads successfully. */) | |||
| 1112 | must_suffix = Qnil; | 1117 | must_suffix = Qnil; |
| 1113 | } | 1118 | } |
| 1114 | 1119 | ||
| 1115 | fd = openp (Vload_path, file, | 1120 | if (!NILP (nosuffix)) |
| 1116 | (!NILP (nosuffix) ? Qnil | 1121 | suffixes = Qnil; |
| 1117 | : !NILP (must_suffix) ? Fget_load_suffixes () | 1122 | else |
| 1118 | : Fappend (2, (tmp[0] = Fget_load_suffixes (), | 1123 | { |
| 1119 | tmp[1] = Vload_file_rep_suffixes, | 1124 | suffixes = Fget_load_suffixes (); |
| 1120 | tmp))), | 1125 | if (NILP (must_suffix)) |
| 1121 | &found, Qnil); | 1126 | { |
| 1127 | Lisp_Object arg[2]; | ||
| 1128 | arg[0] = suffixes; | ||
| 1129 | arg[1] = Vload_file_rep_suffixes; | ||
| 1130 | suffixes = Fappend (2, arg); | ||
| 1131 | } | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | fd = openp (Vload_path, file, suffixes, &found, Qnil); | ||
| 1122 | UNGCPRO; | 1135 | UNGCPRO; |
| 1123 | } | 1136 | } |
| 1124 | 1137 | ||
| 1125 | if (fd == -1) | 1138 | if (fd == -1) |
| 1126 | { | 1139 | { |
| 1127 | if (NILP (noerror)) | 1140 | if (NILP (noerror)) |
| 1128 | xsignal2 (Qfile_error, build_string ("Cannot open load file"), file); | 1141 | report_file_error ("Cannot open load file", file); |
| 1129 | return Qnil; | 1142 | return Qnil; |
| 1130 | } | 1143 | } |
| 1131 | 1144 | ||
| @@ -1163,6 +1176,12 @@ Return t if the file exists and loads successfully. */) | |||
| 1163 | #endif | 1176 | #endif |
| 1164 | } | 1177 | } |
| 1165 | 1178 | ||
| 1179 | if (0 <= fd) | ||
| 1180 | { | ||
| 1181 | fd_index = SPECPDL_INDEX (); | ||
| 1182 | record_unwind_protect_int (close_file_unwind, fd); | ||
| 1183 | } | ||
| 1184 | |||
| 1166 | /* Check if we're stuck in a recursive load cycle. | 1185 | /* Check if we're stuck in a recursive load cycle. |
| 1167 | 1186 | ||
| 1168 | 2000-09-21: It's not possible to just check for the file loaded | 1187 | 2000-09-21: It's not possible to just check for the file loaded |
| @@ -1178,11 +1197,7 @@ Return t if the file exists and loads successfully. */) | |||
| 1178 | Lisp_Object tem; | 1197 | Lisp_Object tem; |
| 1179 | for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem)) | 1198 | for (tem = Vloads_in_progress; CONSP (tem); tem = XCDR (tem)) |
| 1180 | if (!NILP (Fequal (found, XCAR (tem))) && (++load_count > 3)) | 1199 | if (!NILP (Fequal (found, XCAR (tem))) && (++load_count > 3)) |
| 1181 | { | 1200 | signal_error ("Recursive load", Fcons (found, Vloads_in_progress)); |
| 1182 | if (fd >= 0) | ||
| 1183 | emacs_close (fd); | ||
| 1184 | signal_error ("Recursive load", Fcons (found, Vloads_in_progress)); | ||
| 1185 | } | ||
| 1186 | record_unwind_protect (record_load_unwind, Vloads_in_progress); | 1201 | record_unwind_protect (record_load_unwind, Vloads_in_progress); |
| 1187 | Vloads_in_progress = Fcons (found, Vloads_in_progress); | 1202 | Vloads_in_progress = Fcons (found, Vloads_in_progress); |
| 1188 | } | 1203 | } |
| @@ -1195,9 +1210,8 @@ Return t if the file exists and loads successfully. */) | |||
| 1195 | 1210 | ||
| 1196 | /* Get the name for load-history. */ | 1211 | /* Get the name for load-history. */ |
| 1197 | hist_file_name = (! NILP (Vpurify_flag) | 1212 | hist_file_name = (! NILP (Vpurify_flag) |
| 1198 | ? Fconcat (2, (tmp[0] = Ffile_name_directory (file), | 1213 | ? concat2 (Ffile_name_directory (file), |
| 1199 | tmp[1] = Ffile_name_nondirectory (found), | 1214 | Ffile_name_nondirectory (found)) |
| 1200 | tmp)) | ||
| 1201 | : found) ; | 1215 | : found) ; |
| 1202 | 1216 | ||
| 1203 | version = -1; | 1217 | version = -1; |
| @@ -1223,12 +1237,7 @@ Return t if the file exists and loads successfully. */) | |||
| 1223 | { | 1237 | { |
| 1224 | safe_p = 0; | 1238 | safe_p = 0; |
| 1225 | if (!load_dangerous_libraries) | 1239 | if (!load_dangerous_libraries) |
| 1226 | { | 1240 | error ("File `%s' was not compiled in Emacs", SDATA (found)); |
| 1227 | if (fd >= 0) | ||
| 1228 | emacs_close (fd); | ||
| 1229 | error ("File `%s' was not compiled in Emacs", | ||
| 1230 | SDATA (found)); | ||
| 1231 | } | ||
| 1232 | else if (!NILP (nomessage) && !force_load_messages) | 1241 | else if (!NILP (nomessage) && !force_load_messages) |
| 1233 | message_with_string ("File `%s' not compiled in Emacs", found, 1); | 1242 | message_with_string ("File `%s' not compiled in Emacs", found, 1); |
| 1234 | } | 1243 | } |
| @@ -1274,7 +1283,10 @@ Return t if the file exists and loads successfully. */) | |||
| 1274 | Lisp_Object val; | 1283 | Lisp_Object val; |
| 1275 | 1284 | ||
| 1276 | if (fd >= 0) | 1285 | if (fd >= 0) |
| 1277 | emacs_close (fd); | 1286 | { |
| 1287 | emacs_close (fd); | ||
| 1288 | clear_unwind_protect (fd_index); | ||
| 1289 | } | ||
| 1278 | val = call4 (Vload_source_file_function, found, hist_file_name, | 1290 | val = call4 (Vload_source_file_function, found, hist_file_name, |
| 1279 | NILP (noerror) ? Qnil : Qt, | 1291 | NILP (noerror) ? Qnil : Qt, |
| 1280 | (NILP (nomessage) || force_load_messages) ? Qnil : Qt); | 1292 | (NILP (nomessage) || force_load_messages) ? Qnil : Qt); |
| @@ -1284,26 +1296,28 @@ Return t if the file exists and loads successfully. */) | |||
| 1284 | 1296 | ||
| 1285 | GCPRO3 (file, found, hist_file_name); | 1297 | GCPRO3 (file, found, hist_file_name); |
| 1286 | 1298 | ||
| 1287 | #ifdef WINDOWSNT | 1299 | if (fd < 0) |
| 1288 | efound = ENCODE_FILE (found); | ||
| 1289 | /* If we somehow got here with fd == -2, meaning the file is deemed | ||
| 1290 | to be remote, don't even try to reopen the file locally; just | ||
| 1291 | force a failure instead. */ | ||
| 1292 | if (fd >= 0) | ||
| 1293 | { | 1300 | { |
| 1294 | emacs_close (fd); | 1301 | /* We somehow got here with fd == -2, meaning the file is deemed |
| 1295 | stream = emacs_fopen (SSDATA (efound), fmode); | 1302 | to be remote. Don't even try to reopen the file locally; |
| 1303 | just force a failure. */ | ||
| 1304 | stream = NULL; | ||
| 1305 | errno = EINVAL; | ||
| 1296 | } | 1306 | } |
| 1297 | else | 1307 | else |
| 1298 | stream = NULL; | ||
| 1299 | #else /* not WINDOWSNT */ | ||
| 1300 | stream = fdopen (fd, fmode); | ||
| 1301 | #endif /* not WINDOWSNT */ | ||
| 1302 | if (stream == 0) | ||
| 1303 | { | 1308 | { |
| 1309 | #ifdef WINDOWSNT | ||
| 1304 | emacs_close (fd); | 1310 | emacs_close (fd); |
| 1305 | error ("Failure to create stdio stream for %s", SDATA (file)); | 1311 | clear_unwind_protect (fd_index); |
| 1312 | efound = ENCODE_FILE (found); | ||
| 1313 | stream = emacs_fopen (SSDATA (efound), fmode); | ||
| 1314 | #else | ||
| 1315 | stream = fdopen (fd, fmode); | ||
| 1316 | #endif | ||
| 1306 | } | 1317 | } |
| 1318 | if (! stream) | ||
| 1319 | report_file_error ("Opening stdio stream", file); | ||
| 1320 | set_unwind_protect_ptr (fd_index, load_unwind, stream); | ||
| 1307 | 1321 | ||
| 1308 | if (! NILP (Vpurify_flag)) | 1322 | if (! NILP (Vpurify_flag)) |
| 1309 | Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); | 1323 | Vpreloaded_file_list = Fcons (Fpurecopy (file), Vpreloaded_file_list); |
| @@ -1322,7 +1336,6 @@ Return t if the file exists and loads successfully. */) | |||
| 1322 | message_with_string ("Loading %s...", file, 1); | 1336 | message_with_string ("Loading %s...", file, 1); |
| 1323 | } | 1337 | } |
| 1324 | 1338 | ||
| 1325 | record_unwind_protect_ptr (load_unwind, stream); | ||
| 1326 | specbind (Qload_file_name, found); | 1339 | specbind (Qload_file_name, found); |
| 1327 | specbind (Qinhibit_file_name_operation, Qnil); | 1340 | specbind (Qinhibit_file_name_operation, Qnil); |
| 1328 | specbind (Qload_in_progress, Qt); | 1341 | specbind (Qload_in_progress, Qt); |
| @@ -1521,7 +1534,6 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, | |||
| 1521 | if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate)) | 1534 | if ((!NILP (handler) || !NILP (predicate)) && !NATNUMP (predicate)) |
| 1522 | { | 1535 | { |
| 1523 | bool exists; | 1536 | bool exists; |
| 1524 | last_errno = ENOENT; | ||
| 1525 | if (NILP (predicate)) | 1537 | if (NILP (predicate)) |
| 1526 | exists = !NILP (Ffile_readable_p (string)); | 1538 | exists = !NILP (Ffile_readable_p (string)); |
| 1527 | else | 1539 | else |
| @@ -1576,7 +1588,10 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, | |||
| 1576 | { | 1588 | { |
| 1577 | fd = emacs_open (pfn, O_RDONLY, 0); | 1589 | fd = emacs_open (pfn, O_RDONLY, 0); |
| 1578 | if (fd < 0) | 1590 | if (fd < 0) |
| 1579 | last_errno = errno; | 1591 | { |
| 1592 | if (errno != ENOENT) | ||
| 1593 | last_errno = errno; | ||
| 1594 | } | ||
| 1580 | else | 1595 | else |
| 1581 | { | 1596 | { |
| 1582 | struct stat st; | 1597 | struct stat st; |