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
if (* argv && !strcmp (cmd , * argv ))
1657
1738
wcmd [0 ] = L'\0' ;
@@ -1667,9 +1748,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1667
1748
/* concatenate argv, quoting args as we go */
1668
1749
strbuf_init (& args , 0 );
1669
1750
if (prepend_cmd ) {
1670
- char * quoted = (char * )quote_arg (cmd );
1751
+ char * quoted = (char * )quote_arg (prepend_cmd );
1671
1752
strbuf_addstr (& args , quoted );
1672
- if (quoted != cmd )
1753
+ if (quoted != prepend_cmd )
1673
1754
free (quoted );
1674
1755
}
1675
1756
for (; * argv ; argv ++ ) {
@@ -1713,16 +1794,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1713
1794
wenvblk = make_environment_block (deltaenv );
1714
1795
1715
1796
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 );
1718
1881
1719
1882
free (wenvblk );
1720
1883
free (wargs );
1721
1884
1722
- if (!ret ) {
1723
- errno = ENOENT ;
1885
+ if (!ret )
1724
1886
return -1 ;
1725
- }
1887
+
1726
1888
CloseHandle (pi .hThread );
1727
1889
1728
1890
/*
@@ -1746,7 +1908,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1746
1908
return (pid_t )pi .dwProcessId ;
1747
1909
}
1748
1910
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 )
1750
1913
{
1751
1914
return mingw_spawnve_fd (cmd , argv , NULL , NULL , prepend_cmd , 0 , 1 , 2 );
1752
1915
}
@@ -1774,14 +1937,14 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
1774
1937
pid = -1 ;
1775
1938
}
1776
1939
else {
1777
- pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , 1 ,
1940
+ pid = mingw_spawnve_fd (iprog , argv , deltaenv , dir , interpr ,
1778
1941
fhin , fhout , fherr );
1779
1942
free (iprog );
1780
1943
}
1781
1944
argv [0 ] = argv0 ;
1782
1945
}
1783
1946
else
1784
- pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , 0 ,
1947
+ pid = mingw_spawnve_fd (prog , argv , deltaenv , dir , NULL ,
1785
1948
fhin , fhout , fherr );
1786
1949
free (prog );
1787
1950
}
@@ -1809,7 +1972,7 @@ static int try_shell_exec(const char *cmd, char *const *argv)
1809
1972
argv2 [0 ] = (char * )cmd ; /* full path to the script file */
1810
1973
memcpy (& argv2 [1 ], & argv [1 ], sizeof (* argv ) * argc );
1811
1974
exec_id = trace2_exec (prog , argv2 );
1812
- pid = mingw_spawnv (prog , argv2 , 1 );
1975
+ pid = mingw_spawnv (prog , argv2 , interpr );
1813
1976
if (pid >= 0 ) {
1814
1977
int status ;
1815
1978
if (waitpid (pid , & status , 0 ) < 0 )
@@ -1833,7 +1996,7 @@ int mingw_execv(const char *cmd, char *const *argv)
1833
1996
int exec_id ;
1834
1997
1835
1998
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 );
1837
2000
if (pid < 0 ) {
1838
2001
trace2_exec_result (exec_id , -1 );
1839
2002
return -1 ;
@@ -3013,6 +3176,9 @@ int wmain(int argc, const wchar_t **wargv)
3013
3176
InitializeCriticalSection (& pinfo_cs );
3014
3177
InitializeCriticalSection (& phantom_symlinks_cs );
3015
3178
3179
+ /* initialize critical section for fscache */
3180
+ InitializeCriticalSection (& fscache_cs );
3181
+
3016
3182
/* set up default file mode and file modes for stdin/out/err */
3017
3183
_fmode = _O_BINARY ;
3018
3184
_setmode (_fileno (stdin ), _O_BINARY );
0 commit comments