diff options
| author | Eli Zaretskii | 2012-12-15 15:38:21 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2012-12-15 15:38:21 +0200 |
| commit | b07286179ec721bc44a7e32111318fb325789fe1 (patch) | |
| tree | 605b9464822cc82d4b9b2e437c6711622142c7d5 /src | |
| parent | 279f9b06fd693b67d1178cdb5ad1ecf513d199ad (diff) | |
| download | emacs-b07286179ec721bc44a7e32111318fb325789fe1.tar.gz emacs-b07286179ec721bc44a7e32111318fb325789fe1.zip | |
Fix bug #13079 on MS-Windows with temp files not being deleted.
src/w32.h (_child_process): New members input_file and
pending_deletion.
(register_child): First argument is now pid_t.
(record_infile, record_pending_deletion): New prototypes.
src/w32proc.c (new_child): Initialize input_file and
pending_deletion members of the child.
(delete_child): Delete the child's temporary input file, if any,
that is pending deletion.
(register_child): First argument is now pid_t.
(record_infile, record_pending_deletion): New functions.
(reap_subprocess): Fix a typo in DebPrint string.
(sys_spawnve, sys_kill): Use pid_t for PID arguments.
src/fileio.c (internal_delete_file): Return an int again: non-zero
if delete-file succeeds, zero otherwise.
src/lisp.h (internal_delete_file): Adjust prototype.
src/callproc.c (Fcall_process): Don't overwrite infile with result
of DECODE_FILE.
[WINDOWSNT] If BUFFER is an integer, i.e. we are launching an
asynchronous subprocess, record the name of the input file name,
if any.
(delete_temp_file) [WINDOWSNT]: If internal_delete_file fails to
delete the file, record it as pending deletion when the subprocess
exits.
nt/inc/ms-w32.h (sys_unlink): Provide prototype.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 31 | ||||
| -rw-r--r-- | src/callproc.c | 29 | ||||
| -rw-r--r-- | src/fileio.c | 11 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/w32.h | 10 | ||||
| -rw-r--r-- | src/w32proc.c | 66 |
6 files changed, 134 insertions, 15 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 960e4e52c59..34959cb691d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,34 @@ | |||
| 1 | 2012-12-15 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | Fix bug #13079 on MS-Windows with temp files not being deleted. | ||
| 4 | * w32.h (_child_process): New members input_file and | ||
| 5 | pending_deletion. | ||
| 6 | (register_child): First argument is now pid_t. | ||
| 7 | (record_infile, record_pending_deletion): New prototypes. | ||
| 8 | |||
| 9 | * w32proc.c (new_child): Initialize input_file and | ||
| 10 | pending_deletion members of the child. | ||
| 11 | (delete_child): Delete the child's temporary input file, if any, | ||
| 12 | that is pending deletion. | ||
| 13 | (register_child): First argument is now pid_t. | ||
| 14 | (record_infile, record_pending_deletion): New functions. | ||
| 15 | (reap_subprocess): Fix a typo in DebPrint string. | ||
| 16 | (sys_spawnve, sys_kill): Use pid_t for PID arguments. | ||
| 17 | |||
| 18 | * fileio.c (internal_delete_file): Return an int again: non-zero | ||
| 19 | if delete-file succeeds, zero otherwise. | ||
| 20 | |||
| 21 | * lisp.h (internal_delete_file): Adjust prototype. | ||
| 22 | |||
| 23 | * callproc.c (Fcall_process): Don't overwrite infile with result | ||
| 24 | of DECODE_FILE. | ||
| 25 | [WINDOWSNT] If BUFFER is an integer, i.e. we are launching an | ||
| 26 | asynchronous subprocess, record the name of the input file name, | ||
| 27 | if any. | ||
| 28 | (delete_temp_file) [WINDOWSNT]: If internal_delete_file fails to | ||
| 29 | delete the file, record it as pending deletion when the subprocess | ||
| 30 | exits. | ||
| 31 | |||
| 1 | 2012-12-14 Eli Zaretskii <eliz@gnu.org> | 32 | 2012-12-14 Eli Zaretskii <eliz@gnu.org> |
| 2 | 33 | ||
| 3 | * editfns.c [HAVE_PWD_H]: Include grp.h. | 34 | * editfns.c [HAVE_PWD_H]: Include grp.h. |
diff --git a/src/callproc.c b/src/callproc.c index e064dccd6d3..5eba3271358 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -402,10 +402,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 402 | 402 | ||
| 403 | filefd = emacs_open (SSDATA (infile), O_RDONLY, 0); | 403 | filefd = emacs_open (SSDATA (infile), O_RDONLY, 0); |
| 404 | if (filefd < 0) | 404 | if (filefd < 0) |
| 405 | { | 405 | report_file_error ("Opening process input file", |
| 406 | infile = DECODE_FILE (infile); | 406 | Fcons (DECODE_FILE (infile), Qnil)); |
| 407 | report_file_error ("Opening process input file", Fcons (infile, Qnil)); | ||
| 408 | } | ||
| 409 | 407 | ||
| 410 | if (STRINGP (output_file)) | 408 | if (STRINGP (output_file)) |
| 411 | { | 409 | { |
| @@ -612,6 +610,15 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 612 | 610 | ||
| 613 | #ifdef WINDOWSNT | 611 | #ifdef WINDOWSNT |
| 614 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); | 612 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
| 613 | /* We need to record the input file of this child, for when we are | ||
| 614 | called from call-process-region to create an async subprocess. | ||
| 615 | That's because call-process-region's unwind procedure will | ||
| 616 | attempt to delete the temporary input file, which will fail | ||
| 617 | because that file is still in use. Recording it with the child | ||
| 618 | will allow us to delete the file when the subprocess exits. | ||
| 619 | The second part of this is in delete_temp_file, q.v. */ | ||
| 620 | if (pid > 0 && INTEGERP (buffer) && nargs >= 2 && !NILP (args[1])) | ||
| 621 | record_infile (pid, xstrdup (SSDATA (infile))); | ||
| 615 | #else /* not WINDOWSNT */ | 622 | #else /* not WINDOWSNT */ |
| 616 | 623 | ||
| 617 | /* vfork, and prevent local vars from being clobbered by the vfork. */ | 624 | /* vfork, and prevent local vars from being clobbered by the vfork. */ |
| @@ -924,7 +931,21 @@ delete_temp_file (Lisp_Object name) | |||
| 924 | /* Suppress jka-compr handling, etc. */ | 931 | /* Suppress jka-compr handling, etc. */ |
| 925 | ptrdiff_t count = SPECPDL_INDEX (); | 932 | ptrdiff_t count = SPECPDL_INDEX (); |
| 926 | specbind (intern ("file-name-handler-alist"), Qnil); | 933 | specbind (intern ("file-name-handler-alist"), Qnil); |
| 934 | #ifdef WINDOWSNT | ||
| 935 | /* If this is called when the subprocess didn't exit yet, the | ||
| 936 | attempt to delete its input file will fail. In that case, we | ||
| 937 | schedule the file for deletion when the subprocess exits. This | ||
| 938 | is the 2nd part of handling this situation; see the call to | ||
| 939 | record_infile in call-process above, for the first part. */ | ||
| 940 | if (!internal_delete_file (name)) | ||
| 941 | { | ||
| 942 | Lisp_Object encoded_file = ENCODE_FILE (name); | ||
| 943 | |||
| 944 | record_pending_deletion (SSDATA (encoded_file)); | ||
| 945 | } | ||
| 946 | #else | ||
| 927 | internal_delete_file (name); | 947 | internal_delete_file (name); |
| 948 | #endif | ||
| 928 | unbind_to (count, Qnil); | 949 | unbind_to (count, Qnil); |
| 929 | return Qnil; | 950 | return Qnil; |
| 930 | } | 951 | } |
diff --git a/src/fileio.c b/src/fileio.c index c7df87bcdda..9f263e36943 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2203,14 +2203,17 @@ internal_delete_file_1 (Lisp_Object ignore) | |||
| 2203 | return Qt; | 2203 | return Qt; |
| 2204 | } | 2204 | } |
| 2205 | 2205 | ||
| 2206 | /* Delete file FILENAME. | 2206 | /* Delete file FILENAME, returning 1 if successful and 0 if failed. |
| 2207 | This ignores `delete-by-moving-to-trash'. */ | 2207 | This ignores `delete-by-moving-to-trash'. */ |
| 2208 | 2208 | ||
| 2209 | void | 2209 | int |
| 2210 | internal_delete_file (Lisp_Object filename) | 2210 | internal_delete_file (Lisp_Object filename) |
| 2211 | { | 2211 | { |
| 2212 | internal_condition_case_2 (Fdelete_file, filename, Qnil, | 2212 | Lisp_Object tem; |
| 2213 | Qt, internal_delete_file_1); | 2213 | |
| 2214 | tem = internal_condition_case_2 (Fdelete_file, filename, Qnil, | ||
| 2215 | Qt, internal_delete_file_1); | ||
| 2216 | return NILP (tem); | ||
| 2214 | } | 2217 | } |
| 2215 | 2218 | ||
| 2216 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, | 2219 | DEFUN ("rename-file", Frename_file, Srename_file, 2, 3, |
diff --git a/src/lisp.h b/src/lisp.h index c7a70feced7..84a97c17bba 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3199,7 +3199,7 @@ EXFUN (Fread_file_name, 6); /* Not a normal DEFUN. */ | |||
| 3199 | extern Lisp_Object close_file_unwind (Lisp_Object); | 3199 | extern Lisp_Object close_file_unwind (Lisp_Object); |
| 3200 | extern Lisp_Object restore_point_unwind (Lisp_Object); | 3200 | extern Lisp_Object restore_point_unwind (Lisp_Object); |
| 3201 | extern _Noreturn void report_file_error (const char *, Lisp_Object); | 3201 | extern _Noreturn void report_file_error (const char *, Lisp_Object); |
| 3202 | extern void internal_delete_file (Lisp_Object); | 3202 | extern int internal_delete_file (Lisp_Object); |
| 3203 | extern bool file_directory_p (const char *); | 3203 | extern bool file_directory_p (const char *); |
| 3204 | extern bool file_accessible_directory_p (const char *); | 3204 | extern bool file_accessible_directory_p (const char *); |
| 3205 | extern void syms_of_fileio (void); | 3205 | extern void syms_of_fileio (void); |
| @@ -103,6 +103,12 @@ typedef struct _child_process | |||
| 103 | OVERLAPPED ovl_read; | 103 | OVERLAPPED ovl_read; |
| 104 | /* Used for async write operations on serial comm ports. */ | 104 | /* Used for async write operations on serial comm ports. */ |
| 105 | OVERLAPPED ovl_write; | 105 | OVERLAPPED ovl_write; |
| 106 | /* Input file, if any, for this subprocess. Should only be non-NULL | ||
| 107 | for async subprocesses. */ | ||
| 108 | char *input_file; | ||
| 109 | /* If non-zero, the subprocess input file is temporary and should be | ||
| 110 | deleted when the subprocess exits. */ | ||
| 111 | int pending_deletion; | ||
| 106 | } child_process; | 112 | } child_process; |
| 107 | 113 | ||
| 108 | #define MAXDESC FD_SETSIZE | 114 | #define MAXDESC FD_SETSIZE |
| @@ -184,7 +190,9 @@ extern int sys_pipe (int *); | |||
| 184 | 190 | ||
| 185 | extern void set_process_dir (char *); | 191 | extern void set_process_dir (char *); |
| 186 | extern int sys_spawnve (int, char *, char **, char **); | 192 | extern int sys_spawnve (int, char *, char **, char **); |
| 187 | extern void register_child (int, int); | 193 | extern void register_child (pid_t, int); |
| 194 | extern void record_infile (pid_t, char *); | ||
| 195 | extern void record_pending_deletion (char *); | ||
| 188 | 196 | ||
| 189 | extern void sys_sleep (int); | 197 | extern void sys_sleep (int); |
| 190 | extern int sys_link (const char *, const char *); | 198 | extern int sys_link (const char *, const char *); |
diff --git a/src/w32proc.c b/src/w32proc.c index 3bdd9995340..43ecf4d68f3 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -812,6 +812,8 @@ new_child (void) | |||
| 812 | cp->pid = -1; | 812 | cp->pid = -1; |
| 813 | cp->procinfo.hProcess = NULL; | 813 | cp->procinfo.hProcess = NULL; |
| 814 | cp->status = STATUS_READ_ERROR; | 814 | cp->status = STATUS_READ_ERROR; |
| 815 | cp->input_file = NULL; | ||
| 816 | cp->pending_deletion = 0; | ||
| 815 | 817 | ||
| 816 | /* use manual reset event so that select() will function properly */ | 818 | /* use manual reset event so that select() will function properly */ |
| 817 | cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL); | 819 | cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL); |
| @@ -860,6 +862,21 @@ delete_child (child_process *cp) | |||
| 860 | if (!CHILD_ACTIVE (cp)) | 862 | if (!CHILD_ACTIVE (cp)) |
| 861 | return; | 863 | return; |
| 862 | 864 | ||
| 865 | /* Delete the child's temporary input file, if any, that is pending | ||
| 866 | deletion. */ | ||
| 867 | if (cp->input_file) | ||
| 868 | { | ||
| 869 | if (cp->pending_deletion) | ||
| 870 | { | ||
| 871 | if (unlink (cp->input_file)) | ||
| 872 | DebPrint (("delete_child.unlink (%s) failed, errno: %d\n", | ||
| 873 | cp->input_file, errno)); | ||
| 874 | cp->pending_deletion = 0; | ||
| 875 | } | ||
| 876 | xfree (cp->input_file); | ||
| 877 | cp->input_file = NULL; | ||
| 878 | } | ||
| 879 | |||
| 863 | /* reap thread if necessary */ | 880 | /* reap thread if necessary */ |
| 864 | if (cp->thrd) | 881 | if (cp->thrd) |
| 865 | { | 882 | { |
| @@ -1056,11 +1073,11 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, | |||
| 1056 | This way the select emulator knows how to match file handles with | 1073 | This way the select emulator knows how to match file handles with |
| 1057 | entries in child_procs. */ | 1074 | entries in child_procs. */ |
| 1058 | void | 1075 | void |
| 1059 | register_child (int pid, int fd) | 1076 | register_child (pid_t pid, int fd) |
| 1060 | { | 1077 | { |
| 1061 | child_process *cp; | 1078 | child_process *cp; |
| 1062 | 1079 | ||
| 1063 | cp = find_child_pid (pid); | 1080 | cp = find_child_pid ((DWORD)pid); |
| 1064 | if (cp == NULL) | 1081 | if (cp == NULL) |
| 1065 | { | 1082 | { |
| 1066 | DebPrint (("register_child unable to find pid %lu\n", pid)); | 1083 | DebPrint (("register_child unable to find pid %lu\n", pid)); |
| @@ -1087,6 +1104,45 @@ register_child (int pid, int fd) | |||
| 1087 | fd_info[fd].cp = cp; | 1104 | fd_info[fd].cp = cp; |
| 1088 | } | 1105 | } |
| 1089 | 1106 | ||
| 1107 | /* Record INFILE as an input file for process PID. */ | ||
| 1108 | void | ||
| 1109 | record_infile (pid_t pid, char *infile) | ||
| 1110 | { | ||
| 1111 | child_process *cp; | ||
| 1112 | |||
| 1113 | /* INFILE should never be NULL, since xstrdup would have signaled | ||
| 1114 | memory full condition in that case, see callproc.c where this | ||
| 1115 | function is called. */ | ||
| 1116 | eassert (infile); | ||
| 1117 | |||
| 1118 | cp = find_child_pid ((DWORD)pid); | ||
| 1119 | if (cp == NULL) | ||
| 1120 | { | ||
| 1121 | DebPrint (("record_infile is unable to find pid %lu\n", pid)); | ||
| 1122 | return; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | cp->input_file = infile; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | /* Mark the input file INFILE of the corresponding subprocess as | ||
| 1129 | temporary, to be deleted when the subprocess exits. */ | ||
| 1130 | void | ||
| 1131 | record_pending_deletion (char *infile) | ||
| 1132 | { | ||
| 1133 | child_process *cp; | ||
| 1134 | |||
| 1135 | eassert (infile); | ||
| 1136 | |||
| 1137 | for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) | ||
| 1138 | if (CHILD_ACTIVE (cp) | ||
| 1139 | && cp->input_file && xstrcasecmp (cp->input_file, infile) == 0) | ||
| 1140 | { | ||
| 1141 | cp->pending_deletion = 1; | ||
| 1142 | break; | ||
| 1143 | } | ||
| 1144 | } | ||
| 1145 | |||
| 1090 | /* Called from waitpid when a process exits. */ | 1146 | /* Called from waitpid when a process exits. */ |
| 1091 | static void | 1147 | static void |
| 1092 | reap_subprocess (child_process *cp) | 1148 | reap_subprocess (child_process *cp) |
| @@ -1097,7 +1153,7 @@ reap_subprocess (child_process *cp) | |||
| 1097 | #ifdef FULL_DEBUG | 1153 | #ifdef FULL_DEBUG |
| 1098 | /* Process should have already died before we are called. */ | 1154 | /* Process should have already died before we are called. */ |
| 1099 | if (WaitForSingleObject (cp->procinfo.hProcess, 0) != WAIT_OBJECT_0) | 1155 | if (WaitForSingleObject (cp->procinfo.hProcess, 0) != WAIT_OBJECT_0) |
| 1100 | DebPrint (("reap_subprocess: child fpr fd %d has not died yet!", cp->fd)); | 1156 | DebPrint (("reap_subprocess: child for fd %d has not died yet!", cp->fd)); |
| 1101 | #endif | 1157 | #endif |
| 1102 | CloseHandle (cp->procinfo.hProcess); | 1158 | CloseHandle (cp->procinfo.hProcess); |
| 1103 | cp->procinfo.hProcess = NULL; | 1159 | cp->procinfo.hProcess = NULL; |
| @@ -1465,7 +1521,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) | |||
| 1465 | Lisp_Object program, full; | 1521 | Lisp_Object program, full; |
| 1466 | char *cmdline, *env, *parg, **targ; | 1522 | char *cmdline, *env, *parg, **targ; |
| 1467 | int arglen, numenv; | 1523 | int arglen, numenv; |
| 1468 | int pid; | 1524 | pid_t pid; |
| 1469 | child_process *cp; | 1525 | child_process *cp; |
| 1470 | int is_dos_app, is_cygnus_app, is_gui_app; | 1526 | int is_dos_app, is_cygnus_app, is_gui_app; |
| 1471 | int do_quoting = 0; | 1527 | int do_quoting = 0; |
| @@ -2129,7 +2185,7 @@ find_child_console (HWND hwnd, LPARAM arg) | |||
| 2129 | 2185 | ||
| 2130 | /* Emulate 'kill', but only for other processes. */ | 2186 | /* Emulate 'kill', but only for other processes. */ |
| 2131 | int | 2187 | int |
| 2132 | sys_kill (int pid, int sig) | 2188 | sys_kill (pid_t pid, int sig) |
| 2133 | { | 2189 | { |
| 2134 | child_process *cp; | 2190 | child_process *cp; |
| 2135 | HANDLE proc_hand; | 2191 | HANDLE proc_hand; |