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 /* executables and the current directory don't support long paths */
16571738 if (* argv && !strcmp (cmd , * argv ))
@@ -1664,9 +1745,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16641745 /* concatenate argv, quoting args as we go */
16651746 strbuf_init (& args , 0 );
16661747 if (prepend_cmd ) {
1667- char * quoted = (char * )quote_arg (cmd );
1748+ char * quoted = (char * )quote_arg (prepend_cmd );
16681749 strbuf_addstr (& args , quoted );
1669- if (quoted != cmd )
1750+ if (quoted != prepend_cmd )
16701751 free (quoted );
16711752 }
16721753 for (; * argv ; argv ++ ) {
@@ -1710,16 +1791,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17101791 wenvblk = make_environment_block (deltaenv );
17111792
17121793 memset (& pi , 0 , sizeof (pi ));
1713- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1714- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1794+ if (restrict_handle_inheritance && stdhandles_count &&
1795+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1796+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1797+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1798+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1799+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1800+ UpdateProcThreadAttribute (attr_list , 0 ,
1801+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1802+ stdhandles ,
1803+ stdhandles_count * sizeof (HANDLE ),
1804+ NULL , NULL )) {
1805+ si .lpAttributeList = attr_list ;
1806+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1807+ }
1808+
1809+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1810+ stdhandles_count ? TRUE : FALSE,
1811+ flags , wenvblk , dir ? wdir : NULL ,
1812+ & si .StartupInfo , & pi );
1813+
1814+ /*
1815+ * On Windows 2008 R2, it seems that specifying certain types of handles
1816+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1817+ * error. Rather than playing finicky and fragile games, let's just try
1818+ * to detect this situation and simply try again without restricting any
1819+ * handle inheritance. This is still better than failing to create
1820+ * processes.
1821+ */
1822+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1823+ DWORD err = GetLastError ();
1824+ struct strbuf buf = STRBUF_INIT ;
1825+
1826+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1827+ /*
1828+ * On Windows 7 and earlier, handles on pipes and character
1829+ * devices are inherited automatically, and cannot be
1830+ * specified in the thread handle list. Rather than trying
1831+ * to catch each and every corner case (and running the
1832+ * chance of *still* forgetting a few), let's just fall
1833+ * back to creating the process without trying to limit the
1834+ * handle inheritance.
1835+ */
1836+ !(err == ERROR_INVALID_PARAMETER &&
1837+ GetVersion () >> 16 < 9200 ) &&
1838+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1839+ DWORD fl = 0 ;
1840+ int i ;
1841+
1842+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1843+
1844+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1845+ HANDLE h = stdhandles [i ];
1846+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1847+ "handle info (%d) %lx\n" , i , h ,
1848+ GetFileType (h ),
1849+ GetHandleInformation (h , & fl ),
1850+ fl );
1851+ }
1852+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1853+ "at\nhttps://github.com/git-for-windows/"
1854+ "git/issues/new\n\n"
1855+ "To suppress this warning, please set "
1856+ "the environment variable\n\n"
1857+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1858+ "\n" );
1859+ }
1860+ restrict_handle_inheritance = 0 ;
1861+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1862+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1863+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1864+ & si .StartupInfo , & pi );
1865+ if (ret && buf .len ) {
1866+ errno = err_win_to_posix (GetLastError ());
1867+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1868+ err , buf .buf );
1869+ }
1870+ strbuf_release (& buf );
1871+ } else if (!ret )
1872+ errno = err_win_to_posix (GetLastError ());
1873+
1874+ if (si .lpAttributeList )
1875+ DeleteProcThreadAttributeList (si .lpAttributeList );
1876+ if (attr_list )
1877+ HeapFree (GetProcessHeap (), 0 , attr_list );
17151878
17161879 free (wenvblk );
17171880 free (wargs );
17181881
1719- if (!ret ) {
1720- errno = ENOENT ;
1882+ if (!ret )
17211883 return -1 ;
1722- }
1884+
17231885 CloseHandle (pi .hThread );
17241886
17251887 /*
@@ -1743,7 +1905,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17431905 return (pid_t )pi .dwProcessId ;
17441906}
17451907
1746- static pid_t mingw_spawnv (const char * cmd , const char * * argv , int prepend_cmd )
1908+ static pid_t mingw_spawnv (const char * cmd , const char * * argv ,
1909+ const char * prepend_cmd )
17471910{
17481911 return mingw_spawnve_fd (cmd , argv , NULL , NULL , prepend_cmd , 0 , 1 , 2 );
17491912}
@@ -1771,14 +1934,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
17711934 pid = -1 ;
17721935 }
17731936 else {
1774- pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , 1 ,
1937+ pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , interpr ,
17751938 fhin , fhout , fherr );
17761939 free (iprog );
17771940 }
17781941 argv [0 ] = argv0 ;
17791942 }
17801943 else
1781- pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , 0 ,
1944+ pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , NULL ,
17821945 fhin , fhout , fherr );
17831946 free (prog );
17841947 }
@@ -1806,7 +1969,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
18061969 argv2 [0 ] = (char * )cmd ; /* full path to the script file */
18071970 memcpy (& argv2 [1 ], & argv [1 ], sizeof (* argv ) * argc );
18081971 exec_id = trace2_exec (prog , argv2 );
1809- pid = mingw_spawnv (prog , argv2 , 1 );
1972+ pid = mingw_spawnv (prog , argv2 , interpr );
18101973 if (pid >= 0 ) {
18111974 int status ;
18121975 if (waitpid (pid , & status , 0 ) < 0 )
@@ -1830,7 +1993,7 @@ int mingw_execv(const char *cmd, char *const *argv)
18301993 int exec_id ;
18311994
18321995 exec_id = trace2_exec (cmd , (const char * * )argv );
1833- pid = mingw_spawnv (cmd , (const char * * )argv , 0 );
1996+ pid = mingw_spawnv (cmd , (const char * * )argv , NULL );
18341997 if (pid < 0 ) {
18351998 trace2_exec_result (exec_id , -1 );
18361999 return -1 ;
@@ -3007,6 +3170,9 @@ int wmain(int argc, const wchar_t **wargv)
30073170 InitializeCriticalSection (& pinfo_cs );
30083171 InitializeCriticalSection (& phantom_symlinks_cs );
30093172
3173+ /* initialize critical section for fscache */
3174+ InitializeCriticalSection (& fscache_cs );
3175+
30103176 /* set up default file mode and file modes for stdin/out/err */
30113177 _fmode = _O_BINARY ;
30123178 _setmode (_fileno (stdin ), _O_BINARY );
0 commit comments