@@ -247,6 +247,27 @@ static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
247
247
static char * unset_environment_variables ;
248
248
int core_fscache ;
249
249
250
+ int are_long_paths_enabled (void )
251
+ {
252
+ /* default to `false` during initialization */
253
+ static const int fallback = 0 ;
254
+
255
+ static int enabled = -1 ;
256
+
257
+ if (enabled < 0 ) {
258
+ /* avoid infinite recursion */
259
+ if (!the_repository )
260
+ return fallback ;
261
+
262
+ if (the_repository -> config &&
263
+ the_repository -> config -> hash_initialized &&
264
+ git_config_get_bool ("core.longpaths" , & enabled ) < 0 )
265
+ enabled = 0 ;
266
+ }
267
+
268
+ return enabled < 0 ? fallback : enabled ;
269
+ }
270
+
250
271
int mingw_core_config (const char * var , const char * value ,
251
272
const struct config_context * ctx , void * cb )
252
273
{
@@ -311,8 +332,8 @@ static wchar_t *normalize_ntpath(wchar_t *wbuf)
311
332
int mingw_unlink (const char * pathname )
312
333
{
313
334
int ret , tries = 0 ;
314
- wchar_t wpathname [MAX_PATH ];
315
- if (xutftowcs_path (wpathname , pathname ) < 0 )
335
+ wchar_t wpathname [MAX_LONG_PATH ];
336
+ if (xutftowcs_long_path (wpathname , pathname ) < 0 )
316
337
return -1 ;
317
338
318
339
if (DeleteFileW (wpathname ))
@@ -344,7 +365,7 @@ static int is_dir_empty(const wchar_t *wpath)
344
365
{
345
366
WIN32_FIND_DATAW findbuf ;
346
367
HANDLE handle ;
347
- wchar_t wbuf [MAX_PATH + 2 ];
368
+ wchar_t wbuf [MAX_LONG_PATH + 2 ];
348
369
wcscpy (wbuf , wpath );
349
370
wcscat (wbuf , L"\\*" );
350
371
handle = FindFirstFileW (wbuf , & findbuf );
@@ -365,7 +386,7 @@ static int is_dir_empty(const wchar_t *wpath)
365
386
int mingw_rmdir (const char * pathname )
366
387
{
367
388
int ret , tries = 0 ;
368
- wchar_t wpathname [MAX_PATH ];
389
+ wchar_t wpathname [MAX_LONG_PATH ];
369
390
struct stat st ;
370
391
371
392
/*
@@ -387,7 +408,7 @@ int mingw_rmdir(const char *pathname)
387
408
return -1 ;
388
409
}
389
410
390
- if (xutftowcs_path (wpathname , pathname ) < 0 )
411
+ if (xutftowcs_long_path (wpathname , pathname ) < 0 )
391
412
return -1 ;
392
413
393
414
while ((ret = _wrmdir (wpathname )) == -1 && tries < ARRAY_SIZE (delay )) {
@@ -466,15 +487,18 @@ static int set_hidden_flag(const wchar_t *path, int set)
466
487
int mingw_mkdir (const char * path , int mode )
467
488
{
468
489
int ret ;
469
- wchar_t wpath [MAX_PATH ];
490
+ wchar_t wpath [MAX_LONG_PATH ];
470
491
471
492
if (!is_valid_win32_path (path , 0 )) {
472
493
errno = EINVAL ;
473
494
return -1 ;
474
495
}
475
496
476
- if (xutftowcs_path (wpath , path ) < 0 )
497
+ /* CreateDirectoryW path limit is 248 (MAX_PATH - 8.3 file name) */
498
+ if (xutftowcs_path_ex (wpath , path , MAX_LONG_PATH , -1 , 248 ,
499
+ are_long_paths_enabled ()) < 0 )
477
500
return -1 ;
501
+
478
502
ret = _wmkdir (wpath );
479
503
if (!ret && needs_hiding (path ))
480
504
return set_hidden_flag (wpath , 1 );
@@ -561,7 +585,7 @@ int mingw_open (const char *filename, int oflags, ...)
561
585
va_list args ;
562
586
unsigned mode ;
563
587
int fd , create = (oflags & (O_CREAT | O_EXCL )) == (O_CREAT | O_EXCL );
564
- wchar_t wfilename [MAX_PATH ];
588
+ wchar_t wfilename [MAX_LONG_PATH ];
565
589
open_fn_t open_fn ;
566
590
567
591
va_start (args , oflags );
@@ -589,7 +613,7 @@ int mingw_open (const char *filename, int oflags, ...)
589
613
590
614
if (filename && !strcmp (filename , "/dev/null" ))
591
615
wcscpy (wfilename , L"nul" );
592
- else if (xutftowcs_path (wfilename , filename ) < 0 )
616
+ else if (xutftowcs_long_path (wfilename , filename ) < 0 )
593
617
return -1 ;
594
618
595
619
fd = open_fn (wfilename , oflags , mode );
@@ -647,14 +671,14 @@ FILE *mingw_fopen (const char *filename, const char *otype)
647
671
{
648
672
int hide = needs_hiding (filename );
649
673
FILE * file ;
650
- wchar_t wfilename [MAX_PATH ], wotype [4 ];
674
+ wchar_t wfilename [MAX_LONG_PATH ], wotype [4 ];
651
675
if (filename && !strcmp (filename , "/dev/null" ))
652
676
wcscpy (wfilename , L"nul" );
653
677
else if (!is_valid_win32_path (filename , 1 )) {
654
678
int create = otype && strchr (otype , 'w' );
655
679
errno = create ? EINVAL : ENOENT ;
656
680
return NULL ;
657
- } else if (xutftowcs_path (wfilename , filename ) < 0 )
681
+ } else if (xutftowcs_long_path (wfilename , filename ) < 0 )
658
682
return NULL ;
659
683
660
684
if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
@@ -676,14 +700,14 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
676
700
{
677
701
int hide = needs_hiding (filename );
678
702
FILE * file ;
679
- wchar_t wfilename [MAX_PATH ], wotype [4 ];
703
+ wchar_t wfilename [MAX_LONG_PATH ], wotype [4 ];
680
704
if (filename && !strcmp (filename , "/dev/null" ))
681
705
wcscpy (wfilename , L"nul" );
682
706
else if (!is_valid_win32_path (filename , 1 )) {
683
707
int create = otype && strchr (otype , 'w' );
684
708
errno = create ? EINVAL : ENOENT ;
685
709
return NULL ;
686
- } else if (xutftowcs_path (wfilename , filename ) < 0 )
710
+ } else if (xutftowcs_long_path (wfilename , filename ) < 0 )
687
711
return NULL ;
688
712
689
713
if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
@@ -733,7 +757,7 @@ ssize_t mingw_write(int fd, const void *buf, size_t len)
733
757
HANDLE h = (HANDLE ) _get_osfhandle (fd );
734
758
if (GetFileType (h ) != FILE_TYPE_PIPE ) {
735
759
if (orig == EINVAL ) {
736
- wchar_t path [MAX_PATH ];
760
+ wchar_t path [MAX_LONG_PATH ];
737
761
DWORD ret = GetFinalPathNameByHandleW (h , path ,
738
762
ARRAY_SIZE (path ), 0 );
739
763
UINT drive_type = ret > 0 && ret < ARRAY_SIZE (path ) ?
@@ -770,27 +794,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t len)
770
794
771
795
int mingw_access (const char * filename , int mode )
772
796
{
773
- wchar_t wfilename [MAX_PATH ];
797
+ wchar_t wfilename [MAX_LONG_PATH ];
774
798
if (!strcmp ("nul" , filename ) || !strcmp ("/dev/null" , filename ))
775
799
return 0 ;
776
- if (xutftowcs_path (wfilename , filename ) < 0 )
800
+ if (xutftowcs_long_path (wfilename , filename ) < 0 )
777
801
return -1 ;
778
802
/* X_OK is not supported by the MSVCRT version */
779
803
return _waccess (wfilename , mode & ~X_OK );
780
804
}
781
805
806
+ /* cached length of current directory for handle_long_path */
807
+ static int current_directory_len = 0 ;
808
+
782
809
int mingw_chdir (const char * dirname )
783
810
{
784
- wchar_t wdirname [MAX_PATH ];
785
- if (xutftowcs_path (wdirname , dirname ) < 0 )
811
+ int result ;
812
+ wchar_t wdirname [MAX_LONG_PATH ];
813
+ if (xutftowcs_long_path (wdirname , dirname ) < 0 )
786
814
return -1 ;
787
- return _wchdir (wdirname );
815
+ result = _wchdir (wdirname );
816
+ current_directory_len = GetCurrentDirectoryW (0 , NULL );
817
+ return result ;
788
818
}
789
819
790
820
int mingw_chmod (const char * filename , int mode )
791
821
{
792
- wchar_t wfilename [MAX_PATH ];
793
- if (xutftowcs_path (wfilename , filename ) < 0 )
822
+ wchar_t wfilename [MAX_LONG_PATH ];
823
+ if (xutftowcs_long_path (wfilename , filename ) < 0 )
794
824
return -1 ;
795
825
return _wchmod (wfilename , mode );
796
826
}
@@ -838,8 +868,8 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
838
868
static int do_lstat (int follow , const char * file_name , struct stat * buf )
839
869
{
840
870
WIN32_FILE_ATTRIBUTE_DATA fdata ;
841
- wchar_t wfilename [MAX_PATH ];
842
- if (xutftowcs_path (wfilename , file_name ) < 0 )
871
+ wchar_t wfilename [MAX_LONG_PATH ];
872
+ if (xutftowcs_long_path (wfilename , file_name ) < 0 )
843
873
return -1 ;
844
874
845
875
if (GetFileAttributesExW (wfilename , GetFileExInfoStandard , & fdata )) {
@@ -1010,10 +1040,10 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
1010
1040
FILETIME mft , aft ;
1011
1041
int rc ;
1012
1042
DWORD attrs ;
1013
- wchar_t wfilename [MAX_PATH ];
1043
+ wchar_t wfilename [MAX_LONG_PATH ];
1014
1044
HANDLE osfilehandle ;
1015
1045
1016
- if (xutftowcs_path (wfilename , file_name ) < 0 )
1046
+ if (xutftowcs_long_path (wfilename , file_name ) < 0 )
1017
1047
return -1 ;
1018
1048
1019
1049
/* must have write permission */
@@ -1096,6 +1126,7 @@ char *mingw_mktemp(char *template)
1096
1126
wchar_t wtemplate [MAX_PATH ];
1097
1127
int offset = 0 ;
1098
1128
1129
+ /* we need to return the path, thus no long paths here! */
1099
1130
if (xutftowcs_path (wtemplate , template ) < 0 )
1100
1131
return NULL ;
1101
1132
@@ -1747,6 +1778,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1747
1778
1748
1779
if (* argv && !strcmp (cmd , * argv ))
1749
1780
wcmd [0 ] = L'\0' ;
1781
+ /*
1782
+ * Paths to executables and to the current directory do not support
1783
+ * long paths, therefore we cannot use xutftowcs_long_path() here.
1784
+ */
1750
1785
else if (xutftowcs_path (wcmd , cmd ) < 0 )
1751
1786
return -1 ;
1752
1787
if (dir && xutftowcs_path (wdir , dir ) < 0 )
@@ -2395,8 +2430,9 @@ int mingw_rename(const char *pold, const char *pnew)
2395
2430
{
2396
2431
DWORD attrs , gle ;
2397
2432
int tries = 0 ;
2398
- wchar_t wpold [MAX_PATH ], wpnew [MAX_PATH ];
2399
- if (xutftowcs_path (wpold , pold ) < 0 || xutftowcs_path (wpnew , pnew ) < 0 )
2433
+ wchar_t wpold [MAX_LONG_PATH ], wpnew [MAX_LONG_PATH ];
2434
+ if (xutftowcs_long_path (wpold , pold ) < 0 ||
2435
+ xutftowcs_long_path (wpnew , pnew ) < 0 )
2400
2436
return -1 ;
2401
2437
2402
2438
/*
@@ -2710,9 +2746,9 @@ int mingw_raise(int sig)
2710
2746
2711
2747
int link (const char * oldpath , const char * newpath )
2712
2748
{
2713
- wchar_t woldpath [MAX_PATH ], wnewpath [MAX_PATH ];
2714
- if (xutftowcs_path (woldpath , oldpath ) < 0 ||
2715
- xutftowcs_path (wnewpath , newpath ) < 0 )
2749
+ wchar_t woldpath [MAX_LONG_PATH ], wnewpath [MAX_LONG_PATH ];
2750
+ if (xutftowcs_long_path (woldpath , oldpath ) < 0 ||
2751
+ xutftowcs_long_path (wnewpath , newpath ) < 0 )
2716
2752
return -1 ;
2717
2753
2718
2754
if (!CreateHardLinkW (wnewpath , woldpath , NULL )) {
@@ -2780,8 +2816,8 @@ int mingw_is_mount_point(struct strbuf *path)
2780
2816
{
2781
2817
WIN32_FIND_DATAW findbuf = { 0 };
2782
2818
HANDLE handle ;
2783
- wchar_t wfilename [MAX_PATH ];
2784
- int wlen = xutftowcs_path (wfilename , path -> buf );
2819
+ wchar_t wfilename [MAX_LONG_PATH ];
2820
+ int wlen = xutftowcs_long_path (wfilename , path -> buf );
2785
2821
if (wlen < 0 )
2786
2822
die (_ ("could not get long path for '%s'" ), path -> buf );
2787
2823
@@ -2926,9 +2962,9 @@ static size_t append_system_bin_dirs(char *path, size_t size)
2926
2962
2927
2963
static int is_system32_path (const char * path )
2928
2964
{
2929
- WCHAR system32 [MAX_PATH ], wpath [MAX_PATH ];
2965
+ WCHAR system32 [MAX_LONG_PATH ], wpath [MAX_LONG_PATH ];
2930
2966
2931
- if (xutftowcs_path (wpath , path ) < 0 ||
2967
+ if (xutftowcs_long_path (wpath , path ) < 0 ||
2932
2968
!GetSystemDirectoryW (system32 , ARRAY_SIZE (system32 )) ||
2933
2969
_wcsicmp (system32 , wpath ))
2934
2970
return 0 ;
@@ -3340,6 +3376,68 @@ int is_valid_win32_path(const char *path, int allow_literal_nul)
3340
3376
}
3341
3377
}
3342
3378
3379
+ int handle_long_path (wchar_t * path , int len , int max_path , int expand )
3380
+ {
3381
+ int result ;
3382
+ wchar_t buf [MAX_LONG_PATH ];
3383
+
3384
+ /*
3385
+ * we don't need special handling if path is relative to the current
3386
+ * directory, and current directory + path don't exceed the desired
3387
+ * max_path limit. This should cover > 99 % of cases with minimal
3388
+ * performance impact (git almost always uses relative paths).
3389
+ */
3390
+ if ((len < 2 || (!is_dir_sep (path [0 ]) && path [1 ] != ':' )) &&
3391
+ (current_directory_len + len < max_path ))
3392
+ return len ;
3393
+
3394
+ /*
3395
+ * handle everything else:
3396
+ * - absolute paths: "C:\dir\file"
3397
+ * - absolute UNC paths: "\\server\share\dir\file"
3398
+ * - absolute paths on current drive: "\dir\file"
3399
+ * - relative paths on other drive: "X:file"
3400
+ * - prefixed paths: "\\?\...", "\\.\..."
3401
+ */
3402
+
3403
+ /* convert to absolute path using GetFullPathNameW */
3404
+ result = GetFullPathNameW (path , MAX_LONG_PATH , buf , NULL );
3405
+ if (!result ) {
3406
+ errno = err_win_to_posix (GetLastError ());
3407
+ return -1 ;
3408
+ }
3409
+
3410
+ /*
3411
+ * return absolute path if it fits within max_path (even if
3412
+ * "cwd + path" doesn't due to '..' components)
3413
+ */
3414
+ if (result < max_path ) {
3415
+ wcscpy (path , buf );
3416
+ return result ;
3417
+ }
3418
+
3419
+ /* error out if we shouldn't expand the path or buf is too small */
3420
+ if (!expand || result >= MAX_LONG_PATH - 6 ) {
3421
+ errno = ENAMETOOLONG ;
3422
+ return -1 ;
3423
+ }
3424
+
3425
+ /* prefix full path with "\\?\" or "\\?\UNC\" */
3426
+ if (buf [0 ] == '\\' ) {
3427
+ /* ...unless already prefixed */
3428
+ if (buf [1 ] == '\\' && (buf [2 ] == '?' || buf [2 ] == '.' ))
3429
+ return len ;
3430
+
3431
+ wcscpy (path , L"\\\\?\\UNC\\" );
3432
+ wcscpy (path + 8 , buf + 2 );
3433
+ return result + 6 ;
3434
+ } else {
3435
+ wcscpy (path , L"\\\\?\\" );
3436
+ wcscpy (path + 4 , buf );
3437
+ return result + 4 ;
3438
+ }
3439
+ }
3440
+
3343
3441
#if !defined(_MSC_VER )
3344
3442
/*
3345
3443
* Disable MSVCRT command line wildcard expansion (__getmainargs called from
@@ -3501,6 +3599,9 @@ int wmain(int argc, const wchar_t **wargv)
3501
3599
/* initialize Unicode console */
3502
3600
winansi_init ();
3503
3601
3602
+ /* init length of current directory for handle_long_path */
3603
+ current_directory_len = GetCurrentDirectoryW (0 , NULL );
3604
+
3504
3605
/* invoke the real main() using our utf8 version of argv. */
3505
3606
exit_status = main (argc , argv );
3506
3607
0 commit comments