10
10
#include "../config.h"
11
11
#include "dir.h"
12
12
#include "../attr.h"
13
+ #include "../string-list.h"
14
+ #include "win32/fscache.h"
13
15
14
16
#define HCAST (type , handle ) ((type)(intptr_t)handle)
15
17
@@ -1387,6 +1389,65 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
1387
1389
return NULL ;
1388
1390
}
1389
1391
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
+
1390
1451
/*
1391
1452
* Determines the absolute path of cmd using the split path in path.
1392
1453
* 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)
1415
1476
path = sep + 1 ;
1416
1477
}
1417
1478
1479
+ if (!prog && !isexe )
1480
+ prog = is_busybox_applet (cmd );
1481
+
1418
1482
return prog ;
1419
1483
}
1420
1484
@@ -1606,11 +1670,16 @@ static int is_msys2_sh(const char *cmd)
1606
1670
}
1607
1671
1608
1672
static 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 )
1611
1675
{
1612
- STARTUPINFOW si ;
1676
+ static int restrict_handle_inheritance = 1 ;
1677
+ STARTUPINFOEXW si ;
1613
1678
PROCESS_INFORMATION pi ;
1679
+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1680
+ HANDLE stdhandles [3 ];
1681
+ DWORD stdhandles_count = 0 ;
1682
+ SIZE_T size ;
1614
1683
struct strbuf args ;
1615
1684
wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
1616
1685
unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1647,11 +1716,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1647
1716
CloseHandle (cons );
1648
1717
}
1649
1718
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 ;
1655
1736
1656
1737
/* executables and the current directory don't support long paths */
1657
1738
if (* argv && !strcmp (cmd , * argv ))
@@ -1664,9 +1745,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1664
1745
/* concatenate argv, quoting args as we go */
1665
1746
strbuf_init (& args , 0 );
1666
1747
if (prepend_cmd ) {
1667
- char * quoted = (char * )quote_arg (cmd );
1748
+ char * quoted = (char * )quote_arg (prepend_cmd );
1668
1749
strbuf_addstr (& args , quoted );
1669
- if (quoted != cmd )
1750
+ if (quoted != prepend_cmd )
1670
1751
free (quoted );
1671
1752
}
1672
1753
for (; * argv ; argv ++ ) {
@@ -1710,16 +1791,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1710
1791
wenvblk = make_environment_block (deltaenv );
1711
1792
1712
1793
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 );
1715
1878
1716
1879
free (wenvblk );
1717
1880
free (wargs );
1718
1881
1719
- if (!ret ) {
1720
- errno = ENOENT ;
1882
+ if (!ret )
1721
1883
return -1 ;
1722
- }
1884
+
1723
1885
CloseHandle (pi .hThread );
1724
1886
1725
1887
/*
@@ -1743,7 +1905,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1743
1905
return (pid_t )pi .dwProcessId ;
1744
1906
}
1745
1907
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 )
1747
1910
{
1748
1911
return mingw_spawnve_fd (cmd , argv , NULL , NULL , prepend_cmd , 0 , 1 , 2 );
1749
1912
}
@@ -1771,14 +1934,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1771
1934
pid = -1 ;
1772
1935
}
1773
1936
else {
1774
- pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , 1 ,
1937
+ pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , interpr ,
1775
1938
fhin , fhout , fherr );
1776
1939
free (iprog );
1777
1940
}
1778
1941
argv [0 ] = argv0 ;
1779
1942
}
1780
1943
else
1781
- pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , 0 ,
1944
+ pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , NULL ,
1782
1945
fhin , fhout , fherr );
1783
1946
free (prog );
1784
1947
}
@@ -1806,7 +1969,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
1806
1969
argv2 [0 ] = (char * )cmd ; /* full path to the script file */
1807
1970
memcpy (& argv2 [1 ], & argv [1 ], sizeof (* argv ) * argc );
1808
1971
exec_id = trace2_exec (prog , argv2 );
1809
- pid = mingw_spawnv (prog , argv2 , 1 );
1972
+ pid = mingw_spawnv (prog , argv2 , interpr );
1810
1973
if (pid >= 0 ) {
1811
1974
int status ;
1812
1975
if (waitpid (pid , & status , 0 ) < 0 )
@@ -1830,7 +1993,7 @@ int mingw_execv(const char *cmd, char *const *argv)
1830
1993
int exec_id ;
1831
1994
1832
1995
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 );
1834
1997
if (pid < 0 ) {
1835
1998
trace2_exec_result (exec_id , -1 );
1836
1999
return -1 ;
@@ -3001,6 +3164,9 @@ int wmain(int argc, const wchar_t **wargv)
3001
3164
InitializeCriticalSection (& pinfo_cs );
3002
3165
InitializeCriticalSection (& phantom_symlinks_cs );
3003
3166
3167
+ /* initialize critical section for fscache */
3168
+ InitializeCriticalSection (& fscache_cs );
3169
+
3004
3170
/* set up default file mode and file modes for stdin/out/err */
3005
3171
_fmode = _O_BINARY ;
3006
3172
_setmode (_fileno (stdin ), _O_BINARY );
0 commit comments