1010#include "../config.h"
1111#include "dir.h"
1212#include "../attr.h"
13+ #include "../string-list.h"
14+ #include "win32/fscache.h"
1315
1416#define HCAST (type , handle ) ((type)(intptr_t)handle)
1517
@@ -1387,6 +1389,65 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
13871389 return NULL ;
13881390}
13891391
1392+ static char * path_lookup (const char * cmd , int exe_only );
1393+
1394+ static char * is_busybox_applet (const char * cmd )
1395+ {
1396+ static struct string_list applets = STRING_LIST_INIT_DUP ;
1397+ static char * busybox_path ;
1398+ static int busybox_path_initialized ;
1399+
1400+ /* Avoid infinite loop */
1401+ if (!strncasecmp (cmd , "busybox" , 7 ) &&
1402+ (!cmd [7 ] || !strcasecmp (cmd + 7 , ".exe" )))
1403+ return NULL ;
1404+
1405+ if (!busybox_path_initialized ) {
1406+ busybox_path = path_lookup ("busybox.exe" , 1 );
1407+ busybox_path_initialized = 1 ;
1408+ }
1409+
1410+ /* Assume that sh is compiled in... */
1411+ if (!busybox_path || !strcasecmp (cmd , "sh" ))
1412+ return xstrdup_or_null (busybox_path );
1413+
1414+ if (!applets .nr ) {
1415+ struct child_process cp = CHILD_PROCESS_INIT ;
1416+ struct strbuf buf = STRBUF_INIT ;
1417+ char * p ;
1418+
1419+ argv_array_pushl (& cp .args , busybox_path , "--help" , NULL );
1420+
1421+ if (capture_command (& cp , & buf , 2048 )) {
1422+ string_list_append (& applets , "" );
1423+ return NULL ;
1424+ }
1425+
1426+ /* parse output */
1427+ p = strstr (buf .buf , "Currently defined functions:\n" );
1428+ if (!p ) {
1429+ warning ("Could not parse output of busybox --help" );
1430+ string_list_append (& applets , "" );
1431+ return NULL ;
1432+ }
1433+ p = strchrnul (p , '\n' );
1434+ for (;;) {
1435+ size_t len ;
1436+
1437+ p += strspn (p , "\n\t ," );
1438+ len = strcspn (p , "\n\t ," );
1439+ if (!len )
1440+ break ;
1441+ p [len ] = '\0' ;
1442+ string_list_insert (& applets , p );
1443+ p = p + len + 1 ;
1444+ }
1445+ }
1446+
1447+ return string_list_has_string (& applets , cmd ) ?
1448+ xstrdup (busybox_path ) : NULL ;
1449+ }
1450+
13901451/*
13911452 * Determines the absolute path of cmd using the split path in path.
13921453 * If cmd contains a slash or backslash, no lookup is performed.
@@ -1415,6 +1476,9 @@ static char *path_lookup(const char *cmd, int exe_only)
14151476 path = sep + 1 ;
14161477 }
14171478
1479+ if (!prog && !isexe )
1480+ prog = is_busybox_applet (cmd );
1481+
14181482 return prog ;
14191483}
14201484
@@ -1606,11 +1670,16 @@ static int is_msys2_sh(const char *cmd)
16061670}
16071671
16081672static pid_t mingw_spawnve_fd (const char * cmd , const char * * argv , char * * deltaenv ,
1609- const char * dir ,
1610- int prepend_cmd , int fhin , int fhout , int fherr )
1673+ const char * dir , const char * prepend_cmd ,
1674+ int fhin , int fhout , int fherr )
16111675{
1612- STARTUPINFOW si ;
1676+ static int restrict_handle_inheritance = 1 ;
1677+ STARTUPINFOEXW si ;
16131678 PROCESS_INFORMATION pi ;
1679+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1680+ HANDLE stdhandles [3 ];
1681+ DWORD stdhandles_count = 0 ;
1682+ SIZE_T size ;
16141683 struct strbuf args ;
16151684 wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
16161685 unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1647,11 +1716,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16471716 CloseHandle (cons );
16481717 }
16491718 memset (& si , 0 , sizeof (si ));
1650- si .cb = sizeof (si );
1651- si .dwFlags = STARTF_USESTDHANDLES ;
1652- si .hStdInput = winansi_get_osfhandle (fhin );
1653- si .hStdOutput = winansi_get_osfhandle (fhout );
1654- si .hStdError = winansi_get_osfhandle (fherr );
1719+ si .StartupInfo .cb = sizeof (si );
1720+ si .StartupInfo .hStdInput = winansi_get_osfhandle (fhin );
1721+ si .StartupInfo .hStdOutput = winansi_get_osfhandle (fhout );
1722+ si .StartupInfo .hStdError = winansi_get_osfhandle (fherr );
1723+
1724+ /* The list of handles cannot contain duplicates */
1725+ if (si .StartupInfo .hStdInput != INVALID_HANDLE_VALUE )
1726+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdInput ;
1727+ if (si .StartupInfo .hStdOutput != INVALID_HANDLE_VALUE &&
1728+ si .StartupInfo .hStdOutput != si .StartupInfo .hStdInput )
1729+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdOutput ;
1730+ if (si .StartupInfo .hStdError != INVALID_HANDLE_VALUE &&
1731+ si .StartupInfo .hStdError != si .StartupInfo .hStdInput &&
1732+ si .StartupInfo .hStdError != si .StartupInfo .hStdOutput )
1733+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdError ;
1734+ if (stdhandles_count )
1735+ si .StartupInfo .dwFlags |= STARTF_USESTDHANDLES ;
16551736
16561737 if (* argv && !strcmp (cmd , * argv ))
16571738 wcmd [0 ] = L'\0' ;
@@ -1667,9 +1748,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16671748 /* concatenate argv, quoting args as we go */
16681749 strbuf_init (& args , 0 );
16691750 if (prepend_cmd ) {
1670- char * quoted = (char * )quote_arg (cmd );
1751+ char * quoted = (char * )quote_arg (prepend_cmd );
16711752 strbuf_addstr (& args , quoted );
1672- if (quoted != cmd )
1753+ if (quoted != prepend_cmd )
16731754 free (quoted );
16741755 }
16751756 for (; * argv ; argv ++ ) {
@@ -1713,16 +1794,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17131794 wenvblk = make_environment_block (deltaenv );
17141795
17151796 memset (& pi , 0 , sizeof (pi ));
1716- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1717- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1797+ if (restrict_handle_inheritance && stdhandles_count &&
1798+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1799+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1800+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1801+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1802+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1803+ UpdateProcThreadAttribute (attr_list , 0 ,
1804+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1805+ stdhandles ,
1806+ stdhandles_count * sizeof (HANDLE ),
1807+ NULL , NULL )) {
1808+ si .lpAttributeList = attr_list ;
1809+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1810+ }
1811+
1812+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1813+ stdhandles_count ? TRUE : FALSE,
1814+ flags , wenvblk , dir ? wdir : NULL ,
1815+ & si .StartupInfo , & pi );
1816+
1817+ /*
1818+ * On Windows 2008 R2, it seems that specifying certain types of handles
1819+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1820+ * error. Rather than playing finicky and fragile games, let's just try
1821+ * to detect this situation and simply try again without restricting any
1822+ * handle inheritance. This is still better than failing to create
1823+ * processes.
1824+ */
1825+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1826+ DWORD err = GetLastError ();
1827+ struct strbuf buf = STRBUF_INIT ;
1828+
1829+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1830+ /*
1831+ * On Windows 7 and earlier, handles on pipes and character
1832+ * devices are inherited automatically, and cannot be
1833+ * specified in the thread handle list. Rather than trying
1834+ * to catch each and every corner case (and running the
1835+ * chance of *still* forgetting a few), let's just fall
1836+ * back to creating the process without trying to limit the
1837+ * handle inheritance.
1838+ */
1839+ !(err == ERROR_INVALID_PARAMETER &&
1840+ GetVersion () >> 16 < 9200 ) &&
1841+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1842+ DWORD fl = 0 ;
1843+ int i ;
1844+
1845+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1846+
1847+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1848+ HANDLE h = stdhandles [i ];
1849+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1850+ "handle info (%d) %lx\n" , i , h ,
1851+ GetFileType (h ),
1852+ GetHandleInformation (h , & fl ),
1853+ fl );
1854+ }
1855+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1856+ "at\nhttps://github.com/git-for-windows/"
1857+ "git/issues/new\n\n"
1858+ "To suppress this warning, please set "
1859+ "the environment variable\n\n"
1860+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1861+ "\n" );
1862+ }
1863+ restrict_handle_inheritance = 0 ;
1864+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1865+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1866+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1867+ & si .StartupInfo , & pi );
1868+ if (ret && buf .len ) {
1869+ errno = err_win_to_posix (GetLastError ());
1870+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1871+ err , buf .buf );
1872+ }
1873+ strbuf_release (& buf );
1874+ } else if (!ret )
1875+ errno = err_win_to_posix (GetLastError ());
1876+
1877+ if (si .lpAttributeList )
1878+ DeleteProcThreadAttributeList (si .lpAttributeList );
1879+ if (attr_list )
1880+ HeapFree (GetProcessHeap (), 0 , attr_list );
17181881
17191882 free (wenvblk );
17201883 free (wargs );
17211884
1722- if (!ret ) {
1723- errno = ENOENT ;
1885+ if (!ret )
17241886 return -1 ;
1725- }
1887+
17261888 CloseHandle (pi .hThread );
17271889
17281890 /*
@@ -1746,7 +1908,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17461908 return (pid_t )pi .dwProcessId ;
17471909}
17481910
1749- static pid_t mingw_spawnv (const char * cmd , const char * * argv , int prepend_cmd )
1911+ static pid_t mingw_spawnv (const char * cmd , const char * * argv ,
1912+ const char * prepend_cmd )
17501913{
17511914 return mingw_spawnve_fd (cmd , argv , NULL , NULL , prepend_cmd , 0 , 1 , 2 );
17521915}
@@ -1774,14 +1937,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
17741937 pid = -1 ;
17751938 }
17761939 else {
1777- pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , 1 ,
1940+ pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , interpr ,
17781941 fhin , fhout , fherr );
17791942 free (iprog );
17801943 }
17811944 argv [0 ] = argv0 ;
17821945 }
17831946 else
1784- pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , 0 ,
1947+ pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , NULL ,
17851948 fhin , fhout , fherr );
17861949 free (prog );
17871950 }
@@ -1809,7 +1972,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
18091972 argv2 [0 ] = (char * )cmd ; /* full path to the script file */
18101973 memcpy (& argv2 [1 ], & argv [1 ], sizeof (* argv ) * argc );
18111974 exec_id = trace2_exec (prog , argv2 );
1812- pid = mingw_spawnv (prog , argv2 , 1 );
1975+ pid = mingw_spawnv (prog , argv2 , interpr );
18131976 if (pid >= 0 ) {
18141977 int status ;
18151978 if (waitpid (pid , & status , 0 ) < 0 )
@@ -1833,7 +1996,7 @@ int mingw_execv(const char *cmd, char *const *argv)
18331996 int exec_id ;
18341997
18351998 exec_id = trace2_exec (cmd , (const char * * )argv );
1836- pid = mingw_spawnv (cmd , (const char * * )argv , 0 );
1999+ pid = mingw_spawnv (cmd , (const char * * )argv , NULL );
18372000 if (pid < 0 ) {
18382001 trace2_exec_result (exec_id , -1 );
18392002 return -1 ;
@@ -3013,6 +3176,9 @@ int wmain(int argc, const wchar_t **wargv)
30133176 InitializeCriticalSection (& pinfo_cs );
30143177 InitializeCriticalSection (& phantom_symlinks_cs );
30153178
3179+ /* initialize critical section for fscache */
3180+ InitializeCriticalSection (& fscache_cs );
3181+
30163182 /* set up default file mode and file modes for stdin/out/err */
30173183 _fmode = _O_BINARY ;
30183184 _setmode (_fileno (stdin ), _O_BINARY );
0 commit comments