Attachment Details
Not logged in
Overview

Artifact ID: ca27aac2bf8e9a941dfbc2a7b4c15ae0de87f59b
Ticket: 11622724e5b46818396db583ac839391f70c8d64
Date: 2010-08-26 09:04:55
User: anonymous
Artifact Attached: d2dbbd685c4b68cc142df74c4fb2f73486a642e1
Filename:my_popen.h
Description:subroutine "popen2" on win32.
Content Appended
     1  #if defined(__MINGW32__)
     2  #include <sys/fcntl.h>
     3  #include <tchar.h>
     4  #include <windows.h>
     5  
     6  /*
     7   * Display the error message of Windows system call 
     8   */
     9  void ErrorExit(LPTSTR lpszFunction) 
    10  { 
    11      /* Retrieve the system error message for the last-error code */
    12      TCHAR buff[1024] = {};
    13      DWORD dw = GetLastError(); 
    14  
    15      FormatMessage(
    16          FORMAT_MESSAGE_FROM_SYSTEM |
    17          FORMAT_MESSAGE_IGNORE_INSERTS,
    18          NULL,
    19          dw,
    20          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    21          &buff,
    22          sizeof(buff)/sizeof(buff[0]), 
    23          NULL );
    24  
    25      /* Display the error message and exit the process */
    26      _ftprintf(stderr, "%s\n%s\n", buff, lpszFunction);
    27  
    28      ExitProcess(dw); 
    29  }
    30  
    31  /*
    32   * Convert a Windows file handle to crt type FILE*
    33   */
    34  FILE* fhopen(HANDLE hFile, const char *zMode){
    35      int fd = _open_osfhandle((intptr_t)hFile, _O_BINARY);
    36  
    37      if( fd != -1)
    38          return _fdopen(fd, zMode);
    39      else
    40          return NULL;
    41  }
    42  
    43  
    44  /*
    45   * Spawn child process and redirect its io to our handles
    46   */
    47  static DWORD SpawnChild(LPTSTR lpCmdLine, HANDLE hIn, HANDLE hOut, HANDLE hErr)
    48  {
    49      STARTUPINFO si;
    50      PROCESS_INFORMATION pi;
    51      BOOL success;
    52  
    53      memset((void *)&si, 0, sizeof(STARTUPINFO));
    54      si.cb = sizeof (STARTUPINFO);
    55  
    56      /*
    57       * Indicate the hStdInput, hStdOutput, and hStdError members are valid. 
    58       */
    59      si.dwFlags = STARTF_USESTDHANDLES;
    60  
    61      si.hStdInput  = hIn;
    62      si.hStdOutput = hOut;
    63      si.hStdError  = hErr;
    64  
    65      /*
    66       * Ensure stdio inheritable.
    67       */
    68      success = SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT, TRUE);
    69      if(!success) {
    70          ErrorExit("SetHandleInformation failed");
    71      }
    72  
    73      success = SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, TRUE);
    74      if(!success) {
    75          ErrorExit("SetHandleInformation failed");
    76      }
    77  
    78      success = SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT, TRUE);
    79      if(!success) {
    80          ErrorExit("SetHandleInformation failed");
    81      }
    82  
    83      /* 
    84       * Create child process
    85       */
    86      success = CreateProcess(NULL,	/* LPCSTR address of module name */
    87              lpCmdLine,           /* LPCSTR address of command line */
    88              NULL,		/* Process security attributes */
    89              NULL,		/* Thread security attributes */
    90              TRUE,		/* Inheritable Handes inherited. */
    91              0,		    /* DWORD creation flags  */
    92              NULL,       /* Use parent environment block */
    93              NULL,		/* Address of current directory name */
    94              &si,   /* Address of STARTUPINFO  */
    95              &pi);	/* Address of PROCESS_INFORMATION   */
    96  
    97      if(!success){
    98          ErrorExit("CreateProcess failed");
    99      }
   100  
   101      /* Close process and thread handles. */
   102      CloseHandle( pi.hProcess );
   103      CloseHandle( pi.hThread );
   104  
   105      return pi.dwProcessId;
   106  }
   107  
   108  static DWORD win32_create_child(const char *zCmd, HANDLE *hIn, HANDLE *hOut)
   109  {
   110     HANDLE hChildStdinRd, hChildStdinWr, 
   111            hChildStdoutRd, hChildStdoutWr;
   112     HANDLE hStderr;
   113   
   114     SECURITY_ATTRIBUTES saAttr; 
   115     BOOL fSuccess; 
   116   
   117  
   118     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
   119     saAttr.bInheritHandle = TRUE; /* Set the bInheritHandle flag so pipe handles are inherited. */
   120     saAttr.lpSecurityDescriptor = NULL; 
   121  
   122  #if defined(FOSSIL_CHILD_DEBUG)
   123     char zDebugFName[200] = {0};
   124     const char *zTempPrefix = "sever_child_debug_output";
   125  
   126     static volatile long i = 0;
   127  
   128     InterlockedIncrement(&i);
   129  
   130     snprintf(zDebugFName, sizeof(zDebugFName), "%s_%05ld.txt", zTempPrefix, i);
   131  
   132     hStderr = CreateFile(zDebugFName,    // file to open
   133             GENERIC_WRITE,          // open for reading
   134             FILE_SHARE_READ,       // share for reading
   135             NULL,                  // default security
   136             CREATE_ALWAYS,         // existing file only
   137             FILE_ATTRIBUTE_NORMAL, // normal file
   138             NULL);                 // no attr. template
   139  
   140     SetHandleInformation( hStderr, HANDLE_FLAG_INHERIT, TRUE);
   141  #else
   142     /* Get the handle to the current STDERR. */
   143     hStderr = GetStdHandle(STD_ERROR_HANDLE);
   144  #endif
   145   
   146     /* Create a pipe for the child process's STDOUT. */
   147     if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 4096)) 
   148        ErrorExit("Stdout pipe creation failed\n"); 
   149  
   150     /* Ensure the read handle to the pipe for STDOUT is not inherited. */
   151     SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
   152  
   153     /* Create a pipe for the child process's STDIN. */
   154     if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 4096)) 
   155        ErrorExit("Stdin pipe creation failed\n"); 
   156  
   157     /* Ensure the write handle to the pipe for STDIN is not inherited. */
   158     SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, FALSE);
   159    
   160     /* Spawn child and redirect its io */
   161    DWORD processId = SpawnChild(zCmd, hChildStdinRd, hChildStdoutWr, hStderr);
   162  
   163    /* Close pipe handles that used by child to read and write */
   164    CloseHandle(hChildStdinRd); 
   165    CloseHandle(hChildStdoutWr);
   166  #if defined(FOSSIL_CHILD_DEBUG)
   167    CloseHandle(hStderr);
   168  #endif
   169  
   170    *hIn = hChildStdoutRd;
   171    *hOut = hChildStdinWr; 
   172  
   173    return processId;
   174  }
   175  
   176  int popen2(const char *zCmd, FILE **ppIn, FILE **ppOut, int *pChildPid){
   177    HANDLE in, out;
   178    DWORD childProcessId = win32_create_child(zCmd, &in, &out);
   179  
   180    if(childProcessId == 0){
   181        fossil_fatal("create child process failed");
   182    }
   183  
   184    *ppIn = fhopen(in, "rb");
   185    *ppOut = fhopen(out, "wb");
   186  
   187    if( (*ppIn) == NULL || (*ppOut) == NULL){
   188        fossil_fatal("fhopen failed!");
   189    }
   190  
   191    *pChildPid = childProcessId;
   192  }
   193  #endif /* __MINGW32__ */