Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
7c791f3d
Unverified
Commit
7c791f3d
authored
Oct 20, 2018
by
Edward Thomson
Committed by
GitHub
Oct 20, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4852 from libgit2/ethomson/unc_paths
Win32 path canonicalization refactoring
parents
6cc14ae3
a34f5b0d
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
172 additions
and
97 deletions
+172
-97
src/win32/path_w32.c
+101
-7
src/win32/path_w32.h
+18
-0
src/win32/posix_w32.c
+3
-3
src/win32/w32_util.c
+0
-68
src/win32/w32_util.h
+0
-18
tests/path/win32.c
+50
-1
No files found.
src/win32/path_w32.c
View file @
7c791f3d
...
...
@@ -220,7 +220,7 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
goto
on_error
;
}
/* Skip the drive letter specification ("C:") */
/* Skip the drive letter specification ("C:") */
if
(
git__utf8_to_16
(
dest
+
2
,
MAX_PATH
-
2
,
src
)
<
0
)
goto
on_error
;
}
...
...
@@ -315,7 +315,7 @@ static bool path_is_volume(wchar_t *target, size_t target_len)
}
/* On success, returns the length, in characters, of the path stored in dest.
* On failure, returns a negative value. */
* On failure, returns a negative value. */
int
git_win32_path_readlink_w
(
git_win32_path
dest
,
const
git_win32_path
path
)
{
BYTE
buf
[
MAXIMUM_REPARSE_DATA_BUFFER_SIZE
];
...
...
@@ -360,16 +360,16 @@ int git_win32_path_readlink_w(git_win32_path dest, const git_win32_path path)
if
(
path_is_volume
(
target
,
target_len
))
{
/* This path is a reparse point that represents another volume mounted
* at this location, it is not a symbolic link our input was canonical.
*/
* at this location, it is not a symbolic link our input was canonical.
*/
errno
=
EINVAL
;
error
=
-
1
;
}
else
if
(
target_len
)
{
/* The path may need to have a prefix removed. */
target_len
=
git_win32_
_canonicalize_path
(
target
,
target_len
);
/* The path may need to have a
namespace
prefix removed. */
target_len
=
git_win32_
path_remove_namespace
(
target
,
target_len
);
/* Need one additional character in the target buffer
* for the terminating NULL. */
* for the terminating NULL. */
if
(
GIT_WIN_PATH_UTF16
>
target_len
)
{
wcscpy
(
dest
,
target
);
error
=
(
int
)
target_len
;
...
...
@@ -380,3 +380,97 @@ on_error:
CloseHandle
(
handle
);
return
error
;
}
/**
* Removes any trailing backslashes from a path, except in the case of a drive
* letter path (C:\, D:\, etc.). This function cannot fail.
*
* @param path The path which should be trimmed.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32_path_trim_end
(
wchar_t
*
str
,
size_t
len
)
{
while
(
1
)
{
if
(
!
len
||
str
[
len
-
1
]
!=
L'\\'
)
break
;
/*
* Don't trim backslashes from drive letter paths, which
* are 3 characters long and of the form C:\, D:\, etc.
*/
if
(
len
==
3
&&
git_win32__isalpha
(
str
[
0
])
&&
str
[
1
]
==
':'
)
break
;
len
--
;
}
str
[
len
]
=
L'\0'
;
return
len
;
}
/**
* Removes any of the following namespace prefixes from a path,
* if found: "\??\", "\\?\", "\\?\UNC\". This function cannot fail.
*
* @param path The path which should be converted.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32_path_remove_namespace
(
wchar_t
*
str
,
size_t
len
)
{
static
const
wchar_t
dosdevices_namespace
[]
=
L"
\\
\?\?
\\
"
;
static
const
wchar_t
nt_namespace
[]
=
L"
\\\\
?
\\
"
;
static
const
wchar_t
unc_namespace_remainder
[]
=
L"UNC
\\
"
;
static
const
wchar_t
unc_prefix
[]
=
L"
\\\\
"
;
const
wchar_t
*
prefix
=
NULL
,
*
remainder
=
NULL
;
size_t
prefix_len
=
0
,
remainder_len
=
0
;
/* "\??\" -- DOS Devices prefix */
if
(
len
>=
CONST_STRLEN
(
dosdevices_namespace
)
&&
!
wcsncmp
(
str
,
dosdevices_namespace
,
CONST_STRLEN
(
dosdevices_namespace
)))
{
remainder
=
str
+
CONST_STRLEN
(
dosdevices_namespace
);
remainder_len
=
len
-
CONST_STRLEN
(
dosdevices_namespace
);
}
/* "\\?\" -- NT namespace prefix */
else
if
(
len
>=
CONST_STRLEN
(
nt_namespace
)
&&
!
wcsncmp
(
str
,
nt_namespace
,
CONST_STRLEN
(
nt_namespace
)))
{
remainder
=
str
+
CONST_STRLEN
(
nt_namespace
);
remainder_len
=
len
-
CONST_STRLEN
(
nt_namespace
);
}
/* "\??\UNC\", "\\?\UNC\" -- UNC prefix */
if
(
remainder_len
>=
CONST_STRLEN
(
unc_namespace_remainder
)
&&
!
wcsncmp
(
remainder
,
unc_namespace_remainder
,
CONST_STRLEN
(
unc_namespace_remainder
)))
{
/*
* The proper Win32 path for a UNC share has "\\" at beginning of it
* and looks like "\\server\share\<folderStructure>". So remove the
* UNC namespace and add a prefix of "\\" in its place.
*/
remainder
+=
CONST_STRLEN
(
unc_namespace_remainder
);
remainder_len
-=
CONST_STRLEN
(
unc_namespace_remainder
);
prefix
=
unc_prefix
;
prefix_len
=
CONST_STRLEN
(
unc_prefix
);
}
if
(
remainder
)
{
/*
* Sanity check that the new string isn't longer than the old one.
* (This could only happen due to programmer error introducing a
* prefix longer than the namespace it replaces.)
*/
assert
(
len
>=
remainder_len
+
prefix_len
);
if
(
prefix
)
memmove
(
str
,
prefix
,
prefix_len
*
sizeof
(
wchar_t
));
memmove
(
str
+
prefix_len
,
remainder
,
remainder_len
*
sizeof
(
wchar_t
));
len
=
remainder_len
+
prefix_len
;
str
[
len
]
=
L'\0'
;
}
return
git_win32_path_trim_end
(
str
,
len
);
}
src/win32/path_w32.h
View file @
7c791f3d
...
...
@@ -83,4 +83,22 @@ extern char *git_win32_path_8dot3_name(const char *path);
extern
int
git_win32_path_readlink_w
(
git_win32_path
dest
,
const
git_win32_path
path
);
/**
* Removes any trailing backslashes from a path, except in the case of a drive
* letter path (C:\, D:\, etc.). This function cannot fail.
*
* @param path The path which should be trimmed.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32_path_trim_end
(
wchar_t
*
str
,
size_t
len
);
/**
* Removes any of the following namespace prefixes from a path,
* if found: "\??\", "\\?\", "\\?\UNC\". This function cannot fail.
*
* @param path The path which should be converted.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32_path_remove_namespace
(
wchar_t
*
str
,
size_t
len
);
#endif
src/win32/posix_w32.c
View file @
7c791f3d
...
...
@@ -354,7 +354,7 @@ static int do_lstat(const char *path, struct stat *buf, bool posixly_correct)
if
((
len
=
git_win32_path_from_utf8
(
path_w
,
path
))
<
0
)
return
-
1
;
git_win32_
_
path_trim_end
(
path_w
,
len
);
git_win32_path_trim_end
(
path_w
,
len
);
return
lstat_w
(
path_w
,
buf
,
posixly_correct
);
}
...
...
@@ -648,8 +648,8 @@ static int getfinalpath_w(
if
(
!
dwChars
||
dwChars
>=
GIT_WIN_PATH_UTF16
)
return
-
1
;
/* The path may be delivered to us with a
prefix; canonicaliz
e */
return
(
int
)
git_win32_
_canonicalize_path
(
dest
,
dwChars
);
/* The path may be delivered to us with a
namespace prefix; remov
e */
return
(
int
)
git_win32_
path_remove_namespace
(
dest
,
dwChars
);
}
static
int
follow_and_lstat_link
(
git_win32_path
path
,
struct
stat
*
buf
)
...
...
src/win32/w32_util.c
View file @
7c791f3d
...
...
@@ -93,71 +93,3 @@ int git_win32__hidden(bool *out, const char *path)
*
out
=
(
attrs
&
FILE_ATTRIBUTE_HIDDEN
)
?
true
:
false
;
return
0
;
}
/**
* Removes any trailing backslashes from a path, except in the case of a drive
* letter path (C:\, D:\, etc.). This function cannot fail.
*
* @param path The path which should be trimmed.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32__path_trim_end
(
wchar_t
*
str
,
size_t
len
)
{
while
(
1
)
{
if
(
!
len
||
str
[
len
-
1
]
!=
L'\\'
)
break
;
/* Don't trim backslashes from drive letter paths, which
* are 3 characters long and of the form C:\, D:\, etc. */
if
(
len
==
3
&&
git_win32__isalpha
(
str
[
0
])
&&
str
[
1
]
==
':'
)
break
;
len
--
;
}
str
[
len
]
=
L'\0'
;
return
len
;
}
/**
* Removes any of the following namespace prefixes from a path,
* if found: "\??\", "\\?\", "\\?\UNC\". This function cannot fail.
*
* @param path The path which should be converted.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32__canonicalize_path
(
wchar_t
*
str
,
size_t
len
)
{
static
const
wchar_t
dosdevices_prefix
[]
=
L"
\\
\?\?
\\
"
;
static
const
wchar_t
nt_prefix
[]
=
L"
\\\\
?
\\
"
;
static
const
wchar_t
unc_prefix
[]
=
L"UNC
\\
"
;
size_t
to_advance
=
0
;
/* "\??\" -- DOS Devices prefix */
if
(
len
>=
CONST_STRLEN
(
dosdevices_prefix
)
&&
!
wcsncmp
(
str
,
dosdevices_prefix
,
CONST_STRLEN
(
dosdevices_prefix
)))
{
to_advance
+=
CONST_STRLEN
(
dosdevices_prefix
);
len
-=
CONST_STRLEN
(
dosdevices_prefix
);
}
/* "\\?\" -- NT namespace prefix */
else
if
(
len
>=
CONST_STRLEN
(
nt_prefix
)
&&
!
wcsncmp
(
str
,
nt_prefix
,
CONST_STRLEN
(
nt_prefix
)))
{
to_advance
+=
CONST_STRLEN
(
nt_prefix
);
len
-=
CONST_STRLEN
(
nt_prefix
);
}
/* "\??\UNC\", "\\?\UNC\" -- UNC prefix */
if
(
to_advance
&&
len
>=
CONST_STRLEN
(
unc_prefix
)
&&
!
wcsncmp
(
str
+
to_advance
,
unc_prefix
,
CONST_STRLEN
(
unc_prefix
)))
{
to_advance
+=
CONST_STRLEN
(
unc_prefix
);
len
-=
CONST_STRLEN
(
unc_prefix
);
}
if
(
to_advance
)
{
memmove
(
str
,
str
+
to_advance
,
len
*
sizeof
(
wchar_t
));
str
[
len
]
=
L'\0'
;
}
return
git_win32__path_trim_end
(
str
,
len
);
}
src/win32/w32_util.h
View file @
7c791f3d
...
...
@@ -60,24 +60,6 @@ extern int git_win32__set_hidden(const char *path, bool hidden);
extern
int
git_win32__hidden
(
bool
*
hidden
,
const
char
*
path
);
/**
* Removes any trailing backslashes from a path, except in the case of a drive
* letter path (C:\, D:\, etc.). This function cannot fail.
*
* @param path The path which should be trimmed.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32__path_trim_end
(
wchar_t
*
str
,
size_t
len
);
/**
* Removes any of the following namespace prefixes from a path,
* if found: "\??\", "\\?\", "\\?\UNC\". This function cannot fail.
*
* @param path The path which should be converted.
* @return The length of the modified string (<= the input length)
*/
size_t
git_win32__canonicalize_path
(
wchar_t
*
str
,
size_t
len
);
/**
* Converts a FILETIME structure to a struct timespec.
*
* @param FILETIME A pointer to a FILETIME
...
...
tests/path/win32.c
View file @
7c791f3d
...
...
@@ -129,7 +129,7 @@ void test_path_win32__absolute_from_relative(void)
#endif
}
void
test_canonicalize
(
const
wchar_t
*
in
,
const
wchar_t
*
expected
)
static
void
test_canonicalize
(
const
wchar_t
*
in
,
const
wchar_t
*
expected
)
{
#ifdef GIT_WIN32
git_win32_path
canonical
;
...
...
@@ -145,6 +145,55 @@ void test_canonicalize(const wchar_t *in, const wchar_t *expected)
#endif
}
static
void
test_remove_namespace
(
const
wchar_t
*
in
,
const
wchar_t
*
expected
)
{
#ifdef GIT_WIN32
git_win32_path
canonical
;
cl_assert
(
wcslen
(
in
)
<
MAX_PATH
);
wcscpy
(
canonical
,
in
);
cl_must_pass
(
git_win32_path_remove_namespace
(
canonical
,
wcslen
(
in
)));
cl_assert_equal_wcs
(
expected
,
canonical
);
#else
GIT_UNUSED
(
in
);
GIT_UNUSED
(
expected
);
#endif
}
void
test_path_win32__remove_namespace
(
void
)
{
test_remove_namespace
(
L"
\\\\
?
\\
C:
\\
Temp
\\
Foo"
,
L"C:
\\
Temp
\\
Foo"
);
test_remove_namespace
(
L"
\\\\
?
\\
C:
\\
"
,
L"C:
\\
"
);
test_remove_namespace
(
L"
\\\\
?
\\
"
,
L""
);
test_remove_namespace
(
L"
\\
??
\\
C:
\\
Temp
\\
Foo"
,
L"C:
\\
Temp
\\
Foo"
);
test_remove_namespace
(
L"
\\
??
\\
C:
\\
"
,
L"C:
\\
"
);
test_remove_namespace
(
L"
\\
??
\\
"
,
L""
);
test_remove_namespace
(
L"
\\\\
?
\\
UNC
\\
server
\\
C$
\\
folder"
,
L"
\\\\
server
\\
C$
\\
folder"
);
test_remove_namespace
(
L"
\\\\
?
\\
UNC
\\
server
\\
C$
\\
folder"
,
L"
\\\\
server
\\
C$
\\
folder"
);
test_remove_namespace
(
L"
\\\\
?
\\
UNC
\\
server
\\
C$"
,
L"
\\\\
server
\\
C$"
);
test_remove_namespace
(
L"
\\\\
?
\\
UNC
\\
server
\\
"
,
L"
\\\\
server"
);
test_remove_namespace
(
L"
\\\\
?
\\
UNC
\\
server"
,
L"
\\\\
server"
);
test_remove_namespace
(
L"
\\
??
\\
UNC
\\
server
\\
C$
\\
folder"
,
L"
\\\\
server
\\
C$
\\
folder"
);
test_remove_namespace
(
L"
\\
??
\\
UNC
\\
server
\\
C$
\\
folder"
,
L"
\\\\
server
\\
C$
\\
folder"
);
test_remove_namespace
(
L"
\\
??
\\
UNC
\\
server
\\
C$"
,
L"
\\\\
server
\\
C$"
);
test_remove_namespace
(
L"
\\
??
\\
UNC
\\
server
\\
"
,
L"
\\\\
server"
);
test_remove_namespace
(
L"
\\
??
\\
UNC
\\
server"
,
L"
\\\\
server"
);
test_remove_namespace
(
L"
\\\\
server
\\
C$
\\
folder"
,
L"
\\\\
server
\\
C$
\\
folder"
);
test_remove_namespace
(
L"
\\\\
server
\\
C$"
,
L"
\\\\
server
\\
C$"
);
test_remove_namespace
(
L"
\\\\
server
\\
"
,
L"
\\\\
server"
);
test_remove_namespace
(
L"
\\\\
server"
,
L"
\\\\
server"
);
test_remove_namespace
(
L"C:
\\
Foo
\\
Bar"
,
L"C:
\\
Foo
\\
Bar"
);
test_remove_namespace
(
L"C:
\\
"
,
L"C:
\\
"
);
test_remove_namespace
(
L""
,
L""
);
}
void
test_path_win32__canonicalize
(
void
)
{
#ifdef GIT_WIN32
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment