@@ -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
{
@@ -309,8 +330,8 @@ static wchar_t *normalize_ntpath(wchar_t *wbuf)
309
330
int mingw_unlink (const char * pathname )
310
331
{
311
332
int ret , tries = 0 ;
312
- wchar_t wpathname [MAX_PATH ];
313
- if (xutftowcs_path (wpathname , pathname ) < 0 )
333
+ wchar_t wpathname [MAX_LONG_PATH ];
334
+ if (xutftowcs_long_path (wpathname , pathname ) < 0 )
314
335
return -1 ;
315
336
316
337
if (DeleteFileW (wpathname ))
@@ -342,7 +363,7 @@ static int is_dir_empty(const wchar_t *wpath)
342
363
{
343
364
WIN32_FIND_DATAW findbuf ;
344
365
HANDLE handle ;
345
- wchar_t wbuf [MAX_PATH + 2 ];
366
+ wchar_t wbuf [MAX_LONG_PATH + 2 ];
346
367
wcscpy (wbuf , wpath );
347
368
wcscat (wbuf , L"\\*" );
348
369
handle = FindFirstFileW (wbuf , & findbuf );
@@ -363,7 +384,7 @@ static int is_dir_empty(const wchar_t *wpath)
363
384
int mingw_rmdir (const char * pathname )
364
385
{
365
386
int ret , tries = 0 ;
366
- wchar_t wpathname [MAX_PATH ];
387
+ wchar_t wpathname [MAX_LONG_PATH ];
367
388
struct stat st ;
368
389
369
390
/*
@@ -385,7 +406,7 @@ int mingw_rmdir(const char *pathname)
385
406
return -1 ;
386
407
}
387
408
388
- if (xutftowcs_path (wpathname , pathname ) < 0 )
409
+ if (xutftowcs_long_path (wpathname , pathname ) < 0 )
389
410
return -1 ;
390
411
391
412
while ((ret = _wrmdir (wpathname )) == -1 && tries < ARRAY_SIZE (delay )) {
@@ -464,15 +485,18 @@ static int set_hidden_flag(const wchar_t *path, int set)
464
485
int mingw_mkdir (const char * path , int mode )
465
486
{
466
487
int ret ;
467
- wchar_t wpath [MAX_PATH ];
488
+ wchar_t wpath [MAX_LONG_PATH ];
468
489
469
490
if (!is_valid_win32_path (path , 0 )) {
470
491
errno = EINVAL ;
471
492
return -1 ;
472
493
}
473
494
474
- if (xutftowcs_path (wpath , path ) < 0 )
495
+ /* CreateDirectoryW path limit is 248 (MAX_PATH - 8.3 file name) */
496
+ if (xutftowcs_path_ex (wpath , path , MAX_LONG_PATH , -1 , 248 ,
497
+ are_long_paths_enabled ()) < 0 )
475
498
return -1 ;
499
+
476
500
ret = _wmkdir (wpath );
477
501
if (!ret && needs_hiding (path ))
478
502
return set_hidden_flag (wpath , 1 );
@@ -559,7 +583,7 @@ int mingw_open (const char *filename, int oflags, ...)
559
583
va_list args ;
560
584
unsigned mode ;
561
585
int fd , create = (oflags & (O_CREAT | O_EXCL )) == (O_CREAT | O_EXCL );
562
- wchar_t wfilename [MAX_PATH ];
586
+ wchar_t wfilename [MAX_LONG_PATH ];
563
587
open_fn_t open_fn ;
564
588
565
589
va_start (args , oflags );
@@ -587,7 +611,7 @@ int mingw_open (const char *filename, int oflags, ...)
587
611
588
612
if (filename && !strcmp (filename , "/dev/null" ))
589
613
wcscpy (wfilename , L"nul" );
590
- else if (xutftowcs_path (wfilename , filename ) < 0 )
614
+ else if (xutftowcs_long_path (wfilename , filename ) < 0 )
591
615
return -1 ;
592
616
593
617
fd = open_fn (wfilename , oflags , mode );
@@ -645,14 +669,14 @@ FILE *mingw_fopen (const char *filename, const char *otype)
645
669
{
646
670
int hide = needs_hiding (filename );
647
671
FILE * file ;
648
- wchar_t wfilename [MAX_PATH ], wotype [4 ];
672
+ wchar_t wfilename [MAX_LONG_PATH ], wotype [4 ];
649
673
if (filename && !strcmp (filename , "/dev/null" ))
650
674
wcscpy (wfilename , L"nul" );
651
675
else if (!is_valid_win32_path (filename , 1 )) {
652
676
int create = otype && strchr (otype , 'w' );
653
677
errno = create ? EINVAL : ENOENT ;
654
678
return NULL ;
655
- } else if (xutftowcs_path (wfilename , filename ) < 0 )
679
+ } else if (xutftowcs_long_path (wfilename , filename ) < 0 )
656
680
return NULL ;
657
681
658
682
if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
@@ -674,14 +698,14 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
674
698
{
675
699
int hide = needs_hiding (filename );
676
700
FILE * file ;
677
- wchar_t wfilename [MAX_PATH ], wotype [4 ];
701
+ wchar_t wfilename [MAX_LONG_PATH ], wotype [4 ];
678
702
if (filename && !strcmp (filename , "/dev/null" ))
679
703
wcscpy (wfilename , L"nul" );
680
704
else if (!is_valid_win32_path (filename , 1 )) {
681
705
int create = otype && strchr (otype , 'w' );
682
706
errno = create ? EINVAL : ENOENT ;
683
707
return NULL ;
684
- } else if (xutftowcs_path (wfilename , filename ) < 0 )
708
+ } else if (xutftowcs_long_path (wfilename , filename ) < 0 )
685
709
return NULL ;
686
710
687
711
if (xutftowcs (wotype , otype , ARRAY_SIZE (wotype )) < 0 )
@@ -730,7 +754,7 @@ ssize_t mingw_write(int fd, const void *buf, size_t len)
730
754
if (GetFileType (h ) == FILE_TYPE_PIPE )
731
755
errno = EPIPE ;
732
756
else {
733
- wchar_t path [MAX_PATH ];
757
+ wchar_t path [MAX_LONG_PATH ];
734
758
DWORD ret = GetFinalPathNameByHandleW (h , path ,
735
759
ARRAY_SIZE (path ), 0 );
736
760
UINT drive_type = ret > 0 && ret < ARRAY_SIZE (path ) ?
@@ -756,27 +780,33 @@ ssize_t mingw_write(int fd, const void *buf, size_t len)
756
780
757
781
int mingw_access (const char * filename , int mode )
758
782
{
759
- wchar_t wfilename [MAX_PATH ];
783
+ wchar_t wfilename [MAX_LONG_PATH ];
760
784
if (!strcmp ("nul" , filename ) || !strcmp ("/dev/null" , filename ))
761
785
return 0 ;
762
- if (xutftowcs_path (wfilename , filename ) < 0 )
786
+ if (xutftowcs_long_path (wfilename , filename ) < 0 )
763
787
return -1 ;
764
788
/* X_OK is not supported by the MSVCRT version */
765
789
return _waccess (wfilename , mode & ~X_OK );
766
790
}
767
791
792
+ /* cached length of current directory for handle_long_path */
793
+ static int current_directory_len = 0 ;
794
+
768
795
int mingw_chdir (const char * dirname )
769
796
{
770
- wchar_t wdirname [MAX_PATH ];
771
- if (xutftowcs_path (wdirname , dirname ) < 0 )
797
+ int result ;
798
+ wchar_t wdirname [MAX_LONG_PATH ];
799
+ if (xutftowcs_long_path (wdirname , dirname ) < 0 )
772
800
return -1 ;
773
- return _wchdir (wdirname );
801
+ result = _wchdir (wdirname );
802
+ current_directory_len = GetCurrentDirectoryW (0 , NULL );
803
+ return result ;
774
804
}
775
805
776
806
int mingw_chmod (const char * filename , int mode )
777
807
{
778
- wchar_t wfilename [MAX_PATH ];
779
- if (xutftowcs_path (wfilename , filename ) < 0 )
808
+ wchar_t wfilename [MAX_LONG_PATH ];
809
+ if (xutftowcs_long_path (wfilename , filename ) < 0 )
780
810
return -1 ;
781
811
return _wchmod (wfilename , mode );
782
812
}
@@ -824,8 +854,8 @@ static int has_valid_directory_prefix(wchar_t *wfilename)
824
854
static int do_lstat (int follow , const char * file_name , struct stat * buf )
825
855
{
826
856
WIN32_FILE_ATTRIBUTE_DATA fdata ;
827
- wchar_t wfilename [MAX_PATH ];
828
- if (xutftowcs_path (wfilename , file_name ) < 0 )
857
+ wchar_t wfilename [MAX_LONG_PATH ];
858
+ if (xutftowcs_long_path (wfilename , file_name ) < 0 )
829
859
return -1 ;
830
860
831
861
if (GetFileAttributesExW (wfilename , GetFileExInfoStandard , & fdata )) {
@@ -896,7 +926,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
896
926
static int do_stat_internal (int follow , const char * file_name , struct stat * buf )
897
927
{
898
928
int namelen ;
899
- char alt_name [PATH_MAX ];
929
+ char alt_name [MAX_LONG_PATH ];
900
930
901
931
if (!do_lstat (follow , file_name , buf ))
902
932
return 0 ;
@@ -912,7 +942,7 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
912
942
return -1 ;
913
943
while (namelen && file_name [namelen - 1 ] == '/' )
914
944
-- namelen ;
915
- if (!namelen || namelen >= PATH_MAX )
945
+ if (!namelen || namelen >= MAX_LONG_PATH )
916
946
return -1 ;
917
947
918
948
memcpy (alt_name , file_name , namelen );
@@ -996,10 +1026,10 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
996
1026
FILETIME mft , aft ;
997
1027
int rc ;
998
1028
DWORD attrs ;
999
- wchar_t wfilename [MAX_PATH ];
1029
+ wchar_t wfilename [MAX_LONG_PATH ];
1000
1030
HANDLE osfilehandle ;
1001
1031
1002
- if (xutftowcs_path (wfilename , file_name ) < 0 )
1032
+ if (xutftowcs_long_path (wfilename , file_name ) < 0 )
1003
1033
return -1 ;
1004
1034
1005
1035
/* must have write permission */
@@ -1082,6 +1112,7 @@ char *mingw_mktemp(char *template)
1082
1112
wchar_t wtemplate [MAX_PATH ];
1083
1113
int offset = 0 ;
1084
1114
1115
+ /* we need to return the path, thus no long paths here! */
1085
1116
if (xutftowcs_path (wtemplate , template ) < 0 )
1086
1117
return NULL ;
1087
1118
@@ -1733,6 +1764,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1733
1764
1734
1765
if (* argv && !strcmp (cmd , * argv ))
1735
1766
wcmd [0 ] = L'\0' ;
1767
+ /*
1768
+ * Paths to executables and to the current directory do not support
1769
+ * long paths, therefore we cannot use xutftowcs_long_path() here.
1770
+ */
1736
1771
else if (xutftowcs_path (wcmd , cmd ) < 0 )
1737
1772
return -1 ;
1738
1773
if (dir && xutftowcs_path (wdir , dir ) < 0 )
@@ -2381,8 +2416,9 @@ int mingw_rename(const char *pold, const char *pnew)
2381
2416
{
2382
2417
DWORD attrs , gle ;
2383
2418
int tries = 0 ;
2384
- wchar_t wpold [MAX_PATH ], wpnew [MAX_PATH ];
2385
- if (xutftowcs_path (wpold , pold ) < 0 || xutftowcs_path (wpnew , pnew ) < 0 )
2419
+ wchar_t wpold [MAX_LONG_PATH ], wpnew [MAX_LONG_PATH ];
2420
+ if (xutftowcs_long_path (wpold , pold ) < 0 ||
2421
+ xutftowcs_long_path (wpnew , pnew ) < 0 )
2386
2422
return -1 ;
2387
2423
2388
2424
/*
@@ -2696,9 +2732,9 @@ int mingw_raise(int sig)
2696
2732
2697
2733
int link (const char * oldpath , const char * newpath )
2698
2734
{
2699
- wchar_t woldpath [MAX_PATH ], wnewpath [MAX_PATH ];
2700
- if (xutftowcs_path (woldpath , oldpath ) < 0 ||
2701
- xutftowcs_path (wnewpath , newpath ) < 0 )
2735
+ wchar_t woldpath [MAX_LONG_PATH ], wnewpath [MAX_LONG_PATH ];
2736
+ if (xutftowcs_long_path (woldpath , oldpath ) < 0 ||
2737
+ xutftowcs_long_path (wnewpath , newpath ) < 0 )
2702
2738
return -1 ;
2703
2739
2704
2740
if (!CreateHardLinkW (wnewpath , woldpath , NULL )) {
@@ -2766,8 +2802,8 @@ int mingw_is_mount_point(struct strbuf *path)
2766
2802
{
2767
2803
WIN32_FIND_DATAW findbuf = { 0 };
2768
2804
HANDLE handle ;
2769
- wchar_t wfilename [MAX_PATH ];
2770
- int wlen = xutftowcs_path (wfilename , path -> buf );
2805
+ wchar_t wfilename [MAX_LONG_PATH ];
2806
+ int wlen = xutftowcs_long_path (wfilename , path -> buf );
2771
2807
if (wlen < 0 )
2772
2808
die (_ ("could not get long path for '%s'" ), path -> buf );
2773
2809
@@ -2912,9 +2948,9 @@ static size_t append_system_bin_dirs(char *path, size_t size)
2912
2948
2913
2949
static int is_system32_path (const char * path )
2914
2950
{
2915
- WCHAR system32 [MAX_PATH ], wpath [MAX_PATH ];
2951
+ WCHAR system32 [MAX_LONG_PATH ], wpath [MAX_LONG_PATH ];
2916
2952
2917
- if (xutftowcs_path (wpath , path ) < 0 ||
2953
+ if (xutftowcs_long_path (wpath , path ) < 0 ||
2918
2954
!GetSystemDirectoryW (system32 , ARRAY_SIZE (system32 )) ||
2919
2955
_wcsicmp (system32 , wpath ))
2920
2956
return 0 ;
@@ -3282,6 +3318,68 @@ int is_valid_win32_path(const char *path, int allow_literal_nul)
3282
3318
}
3283
3319
}
3284
3320
3321
+ int handle_long_path (wchar_t * path , int len , int max_path , int expand )
3322
+ {
3323
+ int result ;
3324
+ wchar_t buf [MAX_LONG_PATH ];
3325
+
3326
+ /*
3327
+ * we don't need special handling if path is relative to the current
3328
+ * directory, and current directory + path don't exceed the desired
3329
+ * max_path limit. This should cover > 99 % of cases with minimal
3330
+ * performance impact (git almost always uses relative paths).
3331
+ */
3332
+ if ((len < 2 || (!is_dir_sep (path [0 ]) && path [1 ] != ':' )) &&
3333
+ (current_directory_len + len < max_path ))
3334
+ return len ;
3335
+
3336
+ /*
3337
+ * handle everything else:
3338
+ * - absolute paths: "C:\dir\file"
3339
+ * - absolute UNC paths: "\\server\share\dir\file"
3340
+ * - absolute paths on current drive: "\dir\file"
3341
+ * - relative paths on other drive: "X:file"
3342
+ * - prefixed paths: "\\?\...", "\\.\..."
3343
+ */
3344
+
3345
+ /* convert to absolute path using GetFullPathNameW */
3346
+ result = GetFullPathNameW (path , MAX_LONG_PATH , buf , NULL );
3347
+ if (!result ) {
3348
+ errno = err_win_to_posix (GetLastError ());
3349
+ return -1 ;
3350
+ }
3351
+
3352
+ /*
3353
+ * return absolute path if it fits within max_path (even if
3354
+ * "cwd + path" doesn't due to '..' components)
3355
+ */
3356
+ if (result < max_path ) {
3357
+ wcscpy (path , buf );
3358
+ return result ;
3359
+ }
3360
+
3361
+ /* error out if we shouldn't expand the path or buf is too small */
3362
+ if (!expand || result >= MAX_LONG_PATH - 6 ) {
3363
+ errno = ENAMETOOLONG ;
3364
+ return -1 ;
3365
+ }
3366
+
3367
+ /* prefix full path with "\\?\" or "\\?\UNC\" */
3368
+ if (buf [0 ] == '\\' ) {
3369
+ /* ...unless already prefixed */
3370
+ if (buf [1 ] == '\\' && (buf [2 ] == '?' || buf [2 ] == '.' ))
3371
+ return len ;
3372
+
3373
+ wcscpy (path , L"\\\\?\\UNC\\" );
3374
+ wcscpy (path + 8 , buf + 2 );
3375
+ return result + 6 ;
3376
+ } else {
3377
+ wcscpy (path , L"\\\\?\\" );
3378
+ wcscpy (path + 4 , buf );
3379
+ return result + 4 ;
3380
+ }
3381
+ }
3382
+
3285
3383
#if !defined(_MSC_VER )
3286
3384
/*
3287
3385
* Disable MSVCRT command line wildcard expansion (__getmainargs called from
@@ -3443,6 +3541,9 @@ int wmain(int argc, const wchar_t **wargv)
3443
3541
/* initialize Unicode console */
3444
3542
winansi_init ();
3445
3543
3544
+ /* init length of current directory for handle_long_path */
3545
+ current_directory_len = GetCurrentDirectoryW (0 , NULL );
3546
+
3446
3547
/* invoke the real main() using our utf8 version of argv. */
3447
3548
exit_status = main (argc , argv );
3448
3549
0 commit comments