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.
This commit is contained in:
Eli Zaretskii 2012-12-15 15:38:21 +02:00
parent 279f9b06fd
commit b07286179e
7 changed files with 138 additions and 15 deletions

View file

@ -178,6 +178,10 @@ extern char *getenv ();
#define strerror sys_strerror
#undef unlink
#define unlink sys_unlink
/* This prototype is needed because some files include config.h
_after_ the standard headers, so sys_unlink gets no prototype from
stdio.h or io.h. */
extern int sys_unlink (const char *);
#undef write
#define write sys_write

View file

@ -1,3 +1,34 @@
2012-12-15 Eli Zaretskii <eliz@gnu.org>
Fix bug #13079 on MS-Windows with temp files not being deleted.
* 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.
* 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.
* fileio.c (internal_delete_file): Return an int again: non-zero
if delete-file succeeds, zero otherwise.
* lisp.h (internal_delete_file): Adjust prototype.
* 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.
2012-12-14 Eli Zaretskii <eliz@gnu.org>
* editfns.c [HAVE_PWD_H]: Include grp.h.

View file

@ -402,10 +402,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
filefd = emacs_open (SSDATA (infile), O_RDONLY, 0);
if (filefd < 0)
{
infile = DECODE_FILE (infile);
report_file_error ("Opening process input file", Fcons (infile, Qnil));
}
report_file_error ("Opening process input file",
Fcons (DECODE_FILE (infile), Qnil));
if (STRINGP (output_file))
{
@ -612,6 +610,15 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */)
#ifdef WINDOWSNT
pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir);
/* We need to record the input file of this child, for when we are
called from call-process-region to create an async subprocess.
That's because call-process-region's unwind procedure will
attempt to delete the temporary input file, which will fail
because that file is still in use. Recording it with the child
will allow us to delete the file when the subprocess exits.
The second part of this is in delete_temp_file, q.v. */
if (pid > 0 && INTEGERP (buffer) && nargs >= 2 && !NILP (args[1]))
record_infile (pid, xstrdup (SSDATA (infile)));
#else /* not WINDOWSNT */
/* vfork, and prevent local vars from being clobbered by the vfork. */
@ -924,7 +931,21 @@ delete_temp_file (Lisp_Object name)
/* Suppress jka-compr handling, etc. */
ptrdiff_t count = SPECPDL_INDEX ();
specbind (intern ("file-name-handler-alist"), Qnil);
#ifdef WINDOWSNT
/* If this is called when the subprocess didn't exit yet, the
attempt to delete its input file will fail. In that case, we
schedule the file for deletion when the subprocess exits. This
is the 2nd part of handling this situation; see the call to
record_infile in call-process above, for the first part. */
if (!internal_delete_file (name))
{
Lisp_Object encoded_file = ENCODE_FILE (name);
record_pending_deletion (SSDATA (encoded_file));
}
#else
internal_delete_file (name);
#endif
unbind_to (count, Qnil);
return Qnil;
}

View file

@ -2203,14 +2203,17 @@ internal_delete_file_1 (Lisp_Object ignore)
return Qt;
}
/* Delete file FILENAME.
/* Delete file FILENAME, returning 1 if successful and 0 if failed.
This ignores `delete-by-moving-to-trash'. */
void
int
internal_delete_file (Lisp_Object filename)
{
internal_condition_case_2 (Fdelete_file, filename, Qnil,
Qt, internal_delete_file_1);
Lisp_Object tem;
tem = internal_condition_case_2 (Fdelete_file, filename, Qnil,
Qt, internal_delete_file_1);
return NILP (tem);
}
DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,

View file

@ -3199,7 +3199,7 @@ EXFUN (Fread_file_name, 6); /* Not a normal DEFUN. */
extern Lisp_Object close_file_unwind (Lisp_Object);
extern Lisp_Object restore_point_unwind (Lisp_Object);
extern _Noreturn void report_file_error (const char *, Lisp_Object);
extern void internal_delete_file (Lisp_Object);
extern int internal_delete_file (Lisp_Object);
extern bool file_directory_p (const char *);
extern bool file_accessible_directory_p (const char *);
extern void syms_of_fileio (void);

View file

@ -103,6 +103,12 @@ typedef struct _child_process
OVERLAPPED ovl_read;
/* Used for async write operations on serial comm ports. */
OVERLAPPED ovl_write;
/* Input file, if any, for this subprocess. Should only be non-NULL
for async subprocesses. */
char *input_file;
/* If non-zero, the subprocess input file is temporary and should be
deleted when the subprocess exits. */
int pending_deletion;
} child_process;
#define MAXDESC FD_SETSIZE
@ -184,7 +190,9 @@ extern int sys_pipe (int *);
extern void set_process_dir (char *);
extern int sys_spawnve (int, char *, char **, char **);
extern void register_child (int, int);
extern void register_child (pid_t, int);
extern void record_infile (pid_t, char *);
extern void record_pending_deletion (char *);
extern void sys_sleep (int);
extern int sys_link (const char *, const char *);

View file

@ -812,6 +812,8 @@ new_child (void)
cp->pid = -1;
cp->procinfo.hProcess = NULL;
cp->status = STATUS_READ_ERROR;
cp->input_file = NULL;
cp->pending_deletion = 0;
/* use manual reset event so that select() will function properly */
cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
@ -860,6 +862,21 @@ delete_child (child_process *cp)
if (!CHILD_ACTIVE (cp))
return;
/* Delete the child's temporary input file, if any, that is pending
deletion. */
if (cp->input_file)
{
if (cp->pending_deletion)
{
if (unlink (cp->input_file))
DebPrint (("delete_child.unlink (%s) failed, errno: %d\n",
cp->input_file, errno));
cp->pending_deletion = 0;
}
xfree (cp->input_file);
cp->input_file = NULL;
}
/* reap thread if necessary */
if (cp->thrd)
{
@ -1056,11 +1073,11 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
This way the select emulator knows how to match file handles with
entries in child_procs. */
void
register_child (int pid, int fd)
register_child (pid_t pid, int fd)
{
child_process *cp;
cp = find_child_pid (pid);
cp = find_child_pid ((DWORD)pid);
if (cp == NULL)
{
DebPrint (("register_child unable to find pid %lu\n", pid));
@ -1087,6 +1104,45 @@ register_child (int pid, int fd)
fd_info[fd].cp = cp;
}
/* Record INFILE as an input file for process PID. */
void
record_infile (pid_t pid, char *infile)
{
child_process *cp;
/* INFILE should never be NULL, since xstrdup would have signaled
memory full condition in that case, see callproc.c where this
function is called. */
eassert (infile);
cp = find_child_pid ((DWORD)pid);
if (cp == NULL)
{
DebPrint (("record_infile is unable to find pid %lu\n", pid));
return;
}
cp->input_file = infile;
}
/* Mark the input file INFILE of the corresponding subprocess as
temporary, to be deleted when the subprocess exits. */
void
record_pending_deletion (char *infile)
{
child_process *cp;
eassert (infile);
for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
if (CHILD_ACTIVE (cp)
&& cp->input_file && xstrcasecmp (cp->input_file, infile) == 0)
{
cp->pending_deletion = 1;
break;
}
}
/* Called from waitpid when a process exits. */
static void
reap_subprocess (child_process *cp)
@ -1097,7 +1153,7 @@ reap_subprocess (child_process *cp)
#ifdef FULL_DEBUG
/* Process should have already died before we are called. */
if (WaitForSingleObject (cp->procinfo.hProcess, 0) != WAIT_OBJECT_0)
DebPrint (("reap_subprocess: child fpr fd %d has not died yet!", cp->fd));
DebPrint (("reap_subprocess: child for fd %d has not died yet!", cp->fd));
#endif
CloseHandle (cp->procinfo.hProcess);
cp->procinfo.hProcess = NULL;
@ -1465,7 +1521,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
Lisp_Object program, full;
char *cmdline, *env, *parg, **targ;
int arglen, numenv;
int pid;
pid_t pid;
child_process *cp;
int is_dos_app, is_cygnus_app, is_gui_app;
int do_quoting = 0;
@ -2129,7 +2185,7 @@ find_child_console (HWND hwnd, LPARAM arg)
/* Emulate 'kill', but only for other processes. */
int
sys_kill (int pid, int sig)
sys_kill (pid_t pid, int sig)
{
child_process *cp;
HANDLE proc_hand;