Skip to content

Commit d6f1eae

Browse files
kbleesdscho
authored andcommitted
Win32: support long paths
Windows paths are typically limited to MAX_PATH = 260 characters, even though the underlying NTFS file system supports paths up to 32,767 chars. This limitation is also evident in Windows Explorer, cmd.exe and many other applications (including IDEs). Particularly annoying is that most Windows APIs return bogus error codes if a relative path only barely exceeds MAX_PATH in conjunction with the current directory, e.g. ERROR_PATH_NOT_FOUND / ENOENT instead of the infinitely more helpful ERROR_FILENAME_EXCED_RANGE / ENAMETOOLONG. Many Windows wide char APIs support longer than MAX_PATH paths through the file namespace prefix ('\\?\' or '\\?\UNC\') followed by an absolute path. Notable exceptions include functions dealing with executables and the current directory (CreateProcess, LoadLibrary, Get/SetCurrentDirectory) as well as the entire shell API (ShellExecute, SHGetSpecialFolderPath...). Introduce a handle_long_path function to check the length of a specified path properly (and fail with ENAMETOOLONG), and to optionally expand long paths using the '\\?\' file namespace prefix. Short paths will not be modified, so we don't need to worry about device names (NUL, CON, AUX). Contrary to MSDN docs, the GetFullPathNameW function doesn't seem to be limited to MAX_PATH (at least not on Win7), so we can use it to do the heavy lifting of the conversion (translate '/' to '\', eliminate '.' and '..', and make an absolute path). Add long path error checking to xutftowcs_path for APIs with hard MAX_PATH limit. Add a new MAX_LONG_PATH constant and xutftowcs_long_path function for APIs that support long paths. While improved error checking is always active, long paths support must be explicitly enabled via 'core.longpaths' option. This is to prevent end users to shoot themselves in the foot by checking out files that Windows Explorer, cmd/bash or their favorite IDE cannot handle. Test suite: Test the case is when the full pathname length of a dir is close to 260 (MAX_PATH). Bug report and an original reproducer by Andrey Rogozhnikov: msysgit#122 (comment) Note that the test cannot rely on the presence of short names, as they are not enabled by default except on the system drive. [jes: adjusted test number to avoid conflicts, reinstated && chain, adjusted test to work without short names] Thanks-to: Martin W. Kirst <[email protected]> Thanks-to: Doug Kelly <[email protected]> Signed-off-by: Karsten Blees <[email protected]> Original-test-by: Andrey Rogozhnikov <[email protected]> Signed-off-by: Stepan Kasal <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 56c77f3 commit d6f1eae

File tree

2 files changed

+9
-7
lines changed

2 files changed

+9
-7
lines changed

compat/mingw.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,9 +548,8 @@ static int current_directory_len = 0;
548548
int mingw_chdir(const char *dirname)
549549
{
550550
int result;
551-
wchar_t wdirname[MAX_PATH];
552-
/* SetCurrentDirectoryW doesn't support long paths */
553-
if (xutftowcs_path(wdirname, dirname) < 0)
551+
wchar_t wdirname[MAX_LONG_PATH];
552+
if (xutftowcs_long_path(wdirname, dirname) < 0)
554553
return -1;
555554
result = _wchdir(wdirname);
556555
current_directory_len = GetCurrentDirectoryW(0, NULL);

t/t2027-checkout-long-paths.sh renamed to t/t2029-checkout-long-paths.sh

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ test_expect_success 'checkout of long paths without core.longpaths fails' '
3030
git config core.longpaths false &&
3131
test_must_fail git checkout -f 2>error &&
3232
grep -q "Filename too long" error &&
33-
test_path_is_missing longpa~1/longtestfile
33+
test ! -d longpa*
3434
'
3535

3636
test_expect_success 'checkout of long paths with core.longpaths works' '
3737
git config core.longpaths true &&
3838
git checkout -f &&
39-
test_path_is_file longpa~1/longtestfile
39+
test_path_is_file longpa*/longtestfile
4040
'
4141

4242
test_expect_success 'update of long paths' '
43-
echo frotz >> longpa~1/longtestfile &&
43+
echo frotz >>$(ls longpa*/longtestfile) &&
4444
echo $path > expect &&
4545
git ls-files -m > actual &&
4646
test_cmp expect actual &&
@@ -52,7 +52,10 @@ test_expect_success 'update of long paths' '
5252
test_expect_success cleanup '
5353
# bash cannot delete the trash dir if it contains a long path
5454
# lets help cleaning up (unless in debug mode)
55-
test ! -z "$debug" || rm -rf longpa~1
55+
if test -z "$debug"
56+
then
57+
rm -rf longpa~1
58+
fi
5659
'
5760

5861
# check that the template used in the test won't be too long:

0 commit comments

Comments
 (0)