From 1f40a4205b23f7c7f58b55a89cad0d0c5bd65bda Mon Sep 17 00:00:00 2001 From: Brad King Date: Sat, 13 Dec 2003 14:13:54 -0500 Subject: ENH: Added SetPipeFile method to allow the process pipeline stdin, stdout, and stderr to be redirected from/to files. --- Source/kwsys/Process.h.in | 17 +++- Source/kwsys/ProcessUNIX.c | 207 +++++++++++++++++++++++++++++++++++++++----- Source/kwsys/ProcessWin32.c | 189 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 383 insertions(+), 30 deletions(-) diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index adca44b..6119cd3 100644 --- a/Source/kwsys/Process.h.in +++ b/Source/kwsys/Process.h.in @@ -33,6 +33,7 @@ #define kwsysProcess_AddCommand kwsys(Process_AddCommand) #define kwsysProcess_SetTimeout kwsys(Process_SetTimeout) #define kwsysProcess_SetWorkingDirectory kwsys(Process_SetWorkingDirectory) +#define kwsysProcess_SetPipeFile kwsys(Process_SetPipeFile) #define kwsysProcess_Option_HideWindow kwsys(Process_Option_HideWindow) #define kwsysProcess_GetOption kwsys(Process_GetOption) #define kwsysProcess_SetOption kwsys(Process_SetOption) @@ -61,6 +62,7 @@ #define kwsysProcess_WaitForData kwsys(Process_WaitForData) #define kwsysProcess_Pipes_e kwsys(Process_Pipes_e) #define kwsysProcess_Pipe_None kwsys(Process_Pipe_None) +#define kwsysProcess_Pipe_STDIN kwsys(Process_Pipe_STDIN) #define kwsysProcess_Pipe_STDOUT kwsys(Process_Pipe_STDOUT) #define kwsysProcess_Pipe_STDERR kwsys(Process_Pipe_STDERR) #define kwsysProcess_Pipe_Timeout kwsys(Process_Pipe_Timeout) @@ -118,9 +120,17 @@ kwsysEXPORT void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout); /** * Set the working directory for the child process. The working * directory can be absolute or relative to the current directory. + * Returns 1 for success and 0 for failure. */ -kwsysEXPORT void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, - const char* dir); +kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, + const char* dir); + +/** + * Set the name of a file to be attached to the given pipe. Returns 1 + * for success and 0 for failure. + */ +kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, + const char* file); /** * Get/Set a platform-specific option. Possible options are: @@ -243,6 +253,7 @@ kwsysEXPORT int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, enum kwsysProcess_Pipes_e { kwsysProcess_Pipe_None, + kwsysProcess_Pipe_STDIN, kwsysProcess_Pipe_STDOUT, kwsysProcess_Pipe_STDERR, kwsysProcess_Pipe_Timeout=255 @@ -292,6 +303,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); # undef kwsysProcess_AddCommand # undef kwsysProcess_SetTimeout # undef kwsysProcess_SetWorkingDirectory +# undef kwsysProcess_SetPipeFile # undef kwsysProcess_Option_HideWindow # undef kwsysProcess_GetOption # undef kwsysProcess_SetOption @@ -320,6 +332,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); # undef kwsysProcess_WaitForData # undef kwsysProcess_Pipes_e # undef kwsysProcess_Pipe_None +# undef kwsysProcess_Pipe_STDIN # undef kwsysProcess_Pipe_STDOUT # undef kwsysProcess_Pipe_STDERR # undef kwsysProcess_Pipe_Timeout diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 6888d59..42c9dad 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -86,6 +86,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error); static void kwsysProcessCleanupDescriptor(int* pfd); static int kwsysProcessCreate(kwsysProcess* cp, int index, kwsysProcessCreateInformation* si, int* readEnd); +static int kwsysProcessSetupOutputPipeFile(int* p, const char* name); static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, kwsysProcessTime* timeoutTime); static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, @@ -164,6 +165,15 @@ struct kwsysProcess_s /* The exit codes of each child process in the pipeline. */ int* CommandExitCodes; + + /* Name of files to which stdin and stdout pipes are attached. */ + char* PipeFileSTDIN; + char* PipeFileSTDOUT; + char* PipeFileSTDERR; + + /* The real working directory of this process. */ + int RealWorkingDirectoryLength; + char* RealWorkingDirectory; }; /*--------------------------------------------------------------------------*/ @@ -198,6 +208,9 @@ void kwsysProcess_Delete(kwsysProcess* cp) /* Free memory. */ kwsysProcess_SetCommand(cp, 0); kwsysProcess_SetWorkingDirectory(cp, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); if(cp->CommandExitCodes) { free(cp->CommandExitCodes); @@ -322,19 +335,19 @@ void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout) } /*--------------------------------------------------------------------------*/ -void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) +int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) { if(!cp) { - return; + return 0; } if(cp->WorkingDirectory == dir) { - return; + return 1; } if(cp->WorkingDirectory && dir && strcmp(cp->WorkingDirectory, dir) == 0) { - return; + return 1; } if(cp->WorkingDirectory) { @@ -344,8 +357,45 @@ void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) if(dir) { cp->WorkingDirectory = (char*)malloc(strlen(dir) + 1); + if(!cp->WorkingDirectory) + { + return 0; + } strcpy(cp->WorkingDirectory, dir); } + return 1; +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file) +{ + char** pfile; + if(!cp) + { + return 0; + } + switch(pipe) + { + case kwsysProcess_Pipe_STDIN: pfile = &cp->PipeFileSTDIN; break; + case kwsysProcess_Pipe_STDOUT: pfile = &cp->PipeFileSTDOUT; break; + case kwsysProcess_Pipe_STDERR: pfile = &cp->PipeFileSTDERR; break; + default: return 0; + } + if(*pfile) + { + free(*pfile); + *pfile = 0; + } + if(file) + { + *pfile = malloc(strlen(file)+1); + if(!*pfile) + { + return 0; + } + strcpy(*pfile, file); + } + return 1; } /*--------------------------------------------------------------------------*/ @@ -423,6 +473,27 @@ void kwsysProcess_Execute(kwsysProcess* cp) return; } + /* Save the real working directory of this process and change to + the working directory for the child processes. This is needed + to make pipe file paths evaluate correctly. */ + if(cp->WorkingDirectory) + { + int r; + if(!getcwd(cp->RealWorkingDirectory, cp->RealWorkingDirectoryLength)) + { + kwsysProcessCleanup(cp, 1); + return; + } + + /* Some platforms specify that the chdir call may be + interrupted. Repeat the call until it finishes. */ + while(((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)); + if(r < 0) + { + kwsysProcessCleanup(cp, 1); + } + } + /* We want no special handling of SIGCHLD. Repeat call until it is not interrupted. */ memset(&newSigChldAction, 0, sizeof(struct sigaction)); @@ -463,6 +534,20 @@ void kwsysProcess_Execute(kwsysProcess* cp) } } + /* Replace the stderr pipe with a file if requested. In this case + the select call will report that stderr is closed immediately. */ + if(cp->PipeFileSTDERR) + { + if(!kwsysProcessSetupOutputPipeFile(&si.StdErr, cp->PipeFileSTDERR)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupDescriptor(&si.StdErr); + kwsysProcessCleanupDescriptor(&si.TermPipe); + return; + } + } + + /* The timeout period starts now. */ cp->StartTime = kwsysProcessTimeGetCurrent(); cp->TimeoutTime.tv_sec = -1; @@ -479,11 +564,11 @@ void kwsysProcess_Execute(kwsysProcess* cp) /* Release resources that may have been allocated for this process before an error occurred. */ - kwsysProcessCleanupDescriptor(&readEnd); - if(i > 0) + if(i > 0 || si.StdIn > 0) { kwsysProcessCleanupDescriptor(&si.StdIn); } + kwsysProcessCleanupDescriptor(&readEnd); kwsysProcessCleanupDescriptor(&si.StdOut); kwsysProcessCleanupDescriptor(&si.StdErr); kwsysProcessCleanupDescriptor(&si.TermPipe); @@ -500,6 +585,16 @@ void kwsysProcess_Execute(kwsysProcess* cp) kwsysProcessCleanupDescriptor(&si.StdErr); kwsysProcessCleanupDescriptor(&si.TermPipe); + /* Restore the working directory. */ + if(cp->RealWorkingDirectory) + { + /* Some platforms specify that the chdir call may be + interrupted. Repeat the call until it finishes. */ + while((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)); + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } + /* All the pipes are now open. */ cp->PipesLeft = KWSYSPE_PIPE_COUNT; @@ -895,6 +990,22 @@ static int kwsysProcessInitialize(kwsysProcess* cp) } memset(cp->CommandExitCodes, 0, sizeof(int)*cp->NumberOfCommands); + /* Allocate memory to save the real working directory. */ + { +#if defined(MAXPATHLEN) + cp->RealWorkingDirectoryLength = MAXPATHLEN; +#elif defined(PATH_MAX) + cp->RealWorkingDirectoryLength = PATH_MAX; +#else + cp->RealWorkingDirectoryLength = 4096; +#endif + cp->RealWorkingDirectory = malloc(cp->RealWorkingDirectoryLength); + if(!cp->RealWorkingDirectory) + { + return 0; + } + } + return 1; } @@ -928,6 +1039,12 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error) } } } + + /* Restore the working directory. */ + if(cp->RealWorkingDirectory) + { + while((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR)); + } } /* Restore the SIGCHLD handler. */ @@ -940,6 +1057,11 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error) free(cp->ForkPIDs); cp->ForkPIDs = 0; } + if(cp->RealWorkingDirectory) + { + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } /* Close pipe handles. */ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) @@ -971,6 +1093,21 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, si->StdIn = *readEnd; *readEnd = 0; } + else if(cp->PipeFileSTDIN) + { + /* Open a file for the child's stdin to read. */ + si->StdIn = open(cp->PipeFileSTDIN, O_RDONLY); + if(si->StdIn < 0) + { + return 0; + } + + /* Set close-on-exec flag on the pipe's end. */ + if(fcntl(si->StdIn, F_SETFD, FD_CLOEXEC) < 0) + { + return 0; + } + } else { si->StdIn = 0; @@ -995,6 +1132,16 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, } } + /* Replace the stdout pipe with a file if requested. In this case + the select call will report that stdout is closed immediately. */ + if(index == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT) + { + if(!kwsysProcessSetupOutputPipeFile(&si->StdOut, cp->PipeFileSTDOUT)) + { + return 0; + } + } + /* Create the error reporting pipe. */ if(pipe(si->ErrorPipe) < 0) { @@ -1020,7 +1167,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, close(si->ErrorPipe[0]); /* Setup the stdin, stdout, and stderr pipes. */ - if(index > 0) + if(index > 0 || si->StdIn > 0) { dup2(si->StdIn, 0); } @@ -1038,20 +1185,6 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, /* Restore all default signal handlers. */ kwsysProcessRestoreDefaultSignalHandlers(); - /* Change to the working directory specified, if any. */ - if(cp->WorkingDirectory) - { - /* Some platforms specify that the chdir call may be - interrupted. Repeat the call until it finishes. */ - int r; - while(((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR)); - if(r < 0) - { - /* Failure. Report error to parent and terminate. */ - kwsysProcessChildErrorExit(si->ErrorPipe[1]); - } - } - /* Execute the real process. If successful, this does not return. */ execvp(cp->Commands[index][0], cp->Commands[index]); @@ -1091,7 +1224,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, } /* Successfully created this child process. */ - if(index > 0) + if(index > 0 || si->StdIn > 0) { /* The parent process does not need the input pipe read end. */ kwsysProcessCleanupDescriptor(&si->StdIn); @@ -1104,6 +1237,36 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, } /*--------------------------------------------------------------------------*/ +static int kwsysProcessSetupOutputPipeFile(int* p, const char* name) +{ + int fout; + if(!name) + { + return 1; + } + + /* Close the existing descriptor. */ + kwsysProcessCleanupDescriptor(p); + + /* Open a file for the pipe to write (permissions 644). */ + if((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) + { + return 0; + } + + /* Set close-on-exec flag on the pipe's end. */ + if(fcntl(fout, F_SETFD, FD_CLOEXEC) < 0) + { + return 0; + } + + /* Assign the replacement descriptor. */ + *p = fout; + return 1; +} + +/*--------------------------------------------------------------------------*/ /* Get the time at which either the process or user timeout will expire. Returns 1 if the user timeout is first, and 0 otherwise. */ static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 6563fc9..90f54b60 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -80,6 +80,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, kwsysProcessCreateInformation* si, PHANDLE readEnd); static void kwsysProcessDestroy(kwsysProcess* cp, int event); +static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name); static void kwsysProcessCleanupHandle(PHANDLE h); static void kwsysProcessCleanup(kwsysProcess* cp, int error); static void kwsysProcessCleanErrorMessage(kwsysProcess* cp); @@ -181,6 +182,11 @@ struct kwsysProcess_s /* Data specific to each pipe and its thread. */ kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT]; + /* Name of files to which stdin and stdout pipes are attached. */ + char* PipeFileSTDIN; + char* PipeFileSTDOUT; + char* PipeFileSTDERR; + /* ------------- Data managed per call to Execute ------------- */ /* The exceptional behavior that terminated the process, if any. */ @@ -229,6 +235,10 @@ struct kwsysProcess_s /* Data and process termination events for which to wait. */ PHANDLE ProcessEvents; int ProcessEventsLength; + + /* Real working directory of our own process. */ + DWORD RealWorkingDirectoryLength; + char* RealWorkingDirectory; }; /*--------------------------------------------------------------------------*/ @@ -456,6 +466,9 @@ void kwsysProcess_Delete(kwsysProcess* cp) /* Free memory. */ kwsysProcess_SetCommand(cp, 0); kwsysProcess_SetWorkingDirectory(cp, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); + kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); if(cp->CommandExitCodes) { free(cp->CommandExitCodes); @@ -715,11 +728,11 @@ void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout) } /*--------------------------------------------------------------------------*/ -void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) +int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) { if(!cp) { - return; + return 0; } if(cp->WorkingDirectory) { @@ -733,13 +746,51 @@ void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir) if(length > 0) { cp->WorkingDirectory = (char*)malloc(length); + if(!cp->WorkingDirectory) + { + return 0; + } if(!GetFullPathName(dir, length, cp->WorkingDirectory, 0)) { free(cp->WorkingDirectory); cp->WorkingDirectory = 0; + return 0; } } } + return 1; +} + +/*--------------------------------------------------------------------------*/ +int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file) +{ + char** pfile; + if(!cp) + { + return 0; + } + switch(pipe) + { + case kwsysProcess_Pipe_STDIN: pfile = &cp->PipeFileSTDIN; break; + case kwsysProcess_Pipe_STDOUT: pfile = &cp->PipeFileSTDOUT; break; + case kwsysProcess_Pipe_STDERR: pfile = &cp->PipeFileSTDERR; break; + default: return 0; + } + if(*pfile) + { + free(*pfile); + *pfile = 0; + } + if(file) + { + *pfile = malloc(strlen(file)+1); + if(!*pfile) + { + return 0; + } + strcpy(*pfile, file); + } + return 1; } /*--------------------------------------------------------------------------*/ @@ -832,6 +883,20 @@ void kwsysProcess_Execute(kwsysProcess* cp) return; } + /* Save the real working directory of this process and change to + the working directory for the child processes. This is needed + to make pipe file paths evaluate correctly. */ + if(cp->WorkingDirectory) + { + if(!GetCurrentDirectory(cp->RealWorkingDirectoryLength, + cp->RealWorkingDirectory)) + { + kwsysProcessCleanup(cp, 1); + return; + } + SetCurrentDirectory(cp->WorkingDirectory); + } + /* Reset the Win9x resume and kill events. */ if(cp->Win9x) { @@ -880,6 +945,19 @@ void kwsysProcess_Execute(kwsysProcess* cp) return; } + /* Replace the stderr pipe with a file if requested. In this case + the pipe thread will still run but never report data. */ + if(cp->PipeFileSTDERR) + { + if(!kwsysProcessSetupOutputPipeFile(&si.StartupInfo.hStdError, + cp->PipeFileSTDERR)) + { + kwsysProcessCleanup(cp, 1); + kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); + return; + } + } + /* Create the pipeline of processes. */ { HANDLE readEnd = 0; @@ -916,6 +994,14 @@ void kwsysProcess_Execute(kwsysProcess* cp) processes in the pipeline. */ kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); + /* Restore the working directory. */ + if(cp->RealWorkingDirectory) + { + SetCurrentDirectory(cp->RealWorkingDirectory); + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } + /* The timeout period starts now. */ cp->StartTime = kwsysProcessTimeGetCurrent(); cp->TimeoutTime = kwsysProcessTimeFromDouble(-1); @@ -1372,6 +1458,20 @@ int kwsysProcessInitialize(kwsysProcess* cp) cp->ProcessEvents[0] = cp->Full; cp->ProcessEventsLength = cp->NumberOfCommands+1; + /* Allocate space to save the real working directory of this process. */ + if(cp->WorkingDirectory) + { + cp->RealWorkingDirectoryLength = GetCurrentDirectory(0, 0); + if(cp->RealWorkingDirectoryLength > 0) + { + cp->RealWorkingDirectory = malloc(cp->RealWorkingDirectoryLength); + if(!cp->RealWorkingDirectory) + { + return 0; + } + } + } + return 1; } @@ -1398,6 +1498,26 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, /* This function is done with this handle. */ *readEnd = 0; } + else if(cp->PipeFileSTDIN) + { + /* Create a handle to read a file for stdin. */ + HANDLE fin = CreateFile(cp->PipeFileSTDIN, GENERIC_READ, + FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if(fin == INVALID_HANDLE_VALUE) + { + return 0; + } + /* Create an inherited duplicate of the handle. This also closes + the non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), fin, + GetCurrentProcess(), &fin, + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + si->StartupInfo.hStdInput = fin; + } else { si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); @@ -1424,13 +1544,25 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, maybeClose = 0; } if(!DuplicateHandle(GetCurrentProcess(), writeEnd, - GetCurrentProcess(), &si->StartupInfo.hStdOutput, + GetCurrentProcess(), &writeEnd, 0, TRUE, (maybeClose | DUPLICATE_SAME_ACCESS))) { return 0; } + si->StartupInfo.hStdOutput = writeEnd; } + /* Replace the stdout pipe with a file if requested. In this case + the pipe thread will still run but never report data. */ + if(index == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT) + { + if(!kwsysProcessSetupOutputPipeFile(&si->StartupInfo.hStdOutput, + cp->PipeFileSTDOUT)) + { + return 0; + } + } + /* Create the child process. */ { BOOL r; @@ -1473,9 +1605,8 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, /* Create the child in a suspended state so we can wait until all children have been created before running any one. */ r = CreateProcess(0, realCommand, 0, 0, TRUE, - cp->Win9x? 0 : CREATE_SUSPENDED, 0, - cp->WorkingDirectory, &si->StartupInfo, - &cp->ProcessInformation[index]); + cp->Win9x? 0 : CREATE_SUSPENDED, 0, 0, + &si->StartupInfo, &cp->ProcessInformation[index]); if(cp->Win9x) { @@ -1582,6 +1713,41 @@ void kwsysProcessDestroy(kwsysProcess* cp, int event) } /*--------------------------------------------------------------------------*/ +int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name) +{ + HANDLE fout; + if(!name) + { + return 1; + } + + /* Close the existing inherited handle. */ + kwsysProcessCleanupHandle(phandle); + + /* Create a handle to write a file for the pipe. */ + fout = CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ, 0, + CREATE_ALWAYS, 0, 0); + if(fout == INVALID_HANDLE_VALUE) + { + return 0; + } + + /* Create an inherited duplicate of the handle. This also closes + the non-inherited version. */ + if(!DuplicateHandle(GetCurrentProcess(), fout, + GetCurrentProcess(), &fout, + 0, TRUE, (DUPLICATE_CLOSE_SOURCE | + DUPLICATE_SAME_ACCESS))) + { + return 0; + } + + /* Assign the replacement handle. */ + *phandle = fout; + return 1; +} + +/*--------------------------------------------------------------------------*/ /* Close the given handle if it is open. Reset its value to 0. */ void kwsysProcessCleanupHandle(PHANDLE h) @@ -1652,6 +1818,12 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error) kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); } } + + /* Restore the working directory. */ + if(cp->RealWorkingDirectory) + { + SetCurrentDirectory(cp->RealWorkingDirectory); + } } /* Free memory. */ @@ -1665,6 +1837,11 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error) free(cp->ProcessEvents); cp->ProcessEvents = 0; } + if(cp->RealWorkingDirectory) + { + free(cp->RealWorkingDirectory); + cp->RealWorkingDirectory = 0; + } /* Close each pipe. */ for(i=0; i < KWSYSPE_PIPE_COUNT; ++i) -- cgit v0.12