Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-fonts
Project
Project
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
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Aleksandr Isakov
wine-fonts
Commits
f282c8e7
Commit
f282c8e7
authored
Apr 11, 2019
by
Erich E. Hoover
Committed by
Vitaly Lipatov
Jul 30, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Add support for relative symlink creation.
Signed-off-by:
Erich E. Hoover
<
erich.e.hoover@gmail.com
>
parent
036638bf
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
113 additions
and
14 deletions
+113
-14
file.c
dlls/ntdll/tests/file.c
+24
-6
file.c
dlls/ntdll/unix/file.c
+86
-8
ntifs.h
include/ntifs.h
+2
-0
winternl.h
include/winternl.h
+1
-0
No files found.
dlls/ntdll/tests/file.c
View file @
f282c8e7
...
...
@@ -5333,7 +5333,8 @@ static void test_mailslot_name(void)
CloseHandle
(
device
);
}
static
INT
build_reparse_buffer
(
const
WCHAR
*
filename
,
ULONG
tag
,
REPARSE_DATA_BUFFER
**
pbuffer
)
static
INT
build_reparse_buffer
(
const
WCHAR
*
filename
,
ULONG
tag
,
ULONG
flags
,
REPARSE_DATA_BUFFER
**
pbuffer
)
{
static
INT
header_size
=
offsetof
(
REPARSE_DATA_BUFFER
,
GenericReparseBuffer
);
INT
buffer_size
,
struct_size
,
data_size
,
string_len
,
prefix_len
;
...
...
@@ -5351,7 +5352,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_B
default:
return
0
;
}
prefix_len
=
strlen
(
"
\\
??
\\
"
);
prefix_len
=
(
flags
==
SYMLINK_FLAG_RELATIVE
)
?
0
:
strlen
(
"
\\
??
\\
"
);
string_len
=
lstrlenW
(
&
filename
[
prefix_len
]);
data_size
=
(
prefix_len
+
2
*
string_len
+
2
)
*
sizeof
(
WCHAR
);
buffer_size
=
struct_size
+
data_size
;
...
...
@@ -5371,6 +5372,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_B
buffer
->
SymbolicLinkReparseBuffer
.
SubstituteNameLength
=
(
prefix_len
+
string_len
)
*
sizeof
(
WCHAR
);
buffer
->
SymbolicLinkReparseBuffer
.
PrintNameOffset
=
(
prefix_len
+
string_len
+
1
)
*
sizeof
(
WCHAR
);
buffer
->
SymbolicLinkReparseBuffer
.
PrintNameLength
=
string_len
*
sizeof
(
WCHAR
);
buffer
->
SymbolicLinkReparseBuffer
.
Flags
=
flags
;
subst_dest
=
&
buffer
->
SymbolicLinkReparseBuffer
.
PathBuffer
[
0
];
print_dest
=
&
buffer
->
SymbolicLinkReparseBuffer
.
PathBuffer
[
prefix_len
+
string_len
+
1
];
break
;
...
...
@@ -5453,7 +5455,7 @@ static void test_reparse_points(void)
}
dwret
=
NtQueryInformationFile
(
handle
,
&
iosb
,
&
old_attrib
,
sizeof
(
old_attrib
),
FileBasicInformation
);
ok
(
dwret
==
STATUS_SUCCESS
,
"Failed to get junction point folder's attributes (0x%x).
\n
"
,
dwret
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_MOUNT_POINT
,
&
buffer
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_MOUNT_POINT
,
0
,
&
buffer
);
bret
=
DeviceIoControl
(
handle
,
FSCTL_SET_REPARSE_POINT
,
(
LPVOID
)
buffer
,
buffer_len
,
NULL
,
0
,
&
dwret
,
0
);
ok
(
bret
,
"Failed to create junction point! (0x%x)
\n
"
,
GetLastError
());
...
...
@@ -5500,7 +5502,7 @@ static void test_reparse_points(void)
HeapFree
(
GetProcessHeap
(),
0
,
buffer
);
handle
=
CreateFileW
(
reparse_path
,
GENERIC_READ
|
GENERIC_WRITE
,
0
,
0
,
OPEN_EXISTING
,
FILE_FLAG_BACKUP_SEMANTICS
|
FILE_FLAG_OPEN_REPARSE_POINT
,
0
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_MOUNT_POINT
,
&
buffer
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_MOUNT_POINT
,
0
,
&
buffer
);
bret
=
DeviceIoControl
(
handle
,
FSCTL_SET_REPARSE_POINT
,
(
LPVOID
)
buffer
,
buffer_len
,
NULL
,
0
,
&
dwret
,
0
);
ok
(
bret
,
"Failed to create junction point! (0x%x)
\n
"
,
GetLastError
());
CloseHandle
(
handle
);
...
...
@@ -5515,7 +5517,7 @@ static void test_reparse_points(void)
ok
(
bret
,
"Failed to create junction point target directory.
\n
"
);
handle
=
CreateFileW
(
reparse_path
,
GENERIC_READ
|
GENERIC_WRITE
,
0
,
0
,
OPEN_EXISTING
,
FILE_FLAG_BACKUP_SEMANTICS
|
FILE_FLAG_OPEN_REPARSE_POINT
,
0
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_MOUNT_POINT
,
&
buffer
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_MOUNT_POINT
,
0
,
&
buffer
);
bret
=
DeviceIoControl
(
handle
,
FSCTL_SET_REPARSE_POINT
,
(
LPVOID
)
buffer
,
buffer_len
,
NULL
,
0
,
&
dwret
,
0
);
ok
(
bret
,
"Failed to create junction point! (0x%x)
\n
"
,
GetLastError
());
CloseHandle
(
handle
);
...
...
@@ -5577,7 +5579,7 @@ static void test_reparse_points(void)
}
dwret
=
NtQueryInformationFile
(
handle
,
&
iosb
,
&
old_attrib
,
sizeof
(
old_attrib
),
FileBasicInformation
);
ok
(
dwret
==
STATUS_SUCCESS
,
"Failed to get symlink folder's attributes (0x%x).
\n
"
,
dwret
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_SYMLINK
,
&
buffer
);
buffer_len
=
build_reparse_buffer
(
nameW
.
Buffer
,
IO_REPARSE_TAG_SYMLINK
,
0
,
&
buffer
);
bret
=
DeviceIoControl
(
handle
,
FSCTL_SET_REPARSE_POINT
,
(
LPVOID
)
buffer
,
buffer_len
,
NULL
,
0
,
&
dwret
,
0
);
ok
(
bret
,
"Failed to create symlink! (0x%x)
\n
"
,
GetLastError
());
...
...
@@ -5620,6 +5622,22 @@ static void test_reparse_points(void)
"Symlink folder's access time does not match.
\n
"
);
CloseHandle
(
handle
);
/* Create a relative directory symlink */
HeapFree
(
GetProcessHeap
(),
0
,
buffer
);
handle
=
CreateFileW
(
reparse_path
,
GENERIC_READ
|
GENERIC_WRITE
,
0
,
0
,
OPEN_EXISTING
,
FILE_FLAG_BACKUP_SEMANTICS
|
FILE_FLAG_OPEN_REPARSE_POINT
,
0
);
if
(
handle
==
INVALID_HANDLE_VALUE
)
{
win_skip
(
"Failed to open symlink directory handle (0x%x).
\n
"
,
GetLastError
());
goto
cleanup
;
}
dwret
=
NtQueryInformationFile
(
handle
,
&
iosb
,
&
old_attrib
,
sizeof
(
old_attrib
),
FileBasicInformation
);
ok
(
dwret
==
STATUS_SUCCESS
,
"Failed to get symlink folder's attributes (0x%x).
\n
"
,
dwret
);
buffer_len
=
build_reparse_buffer
(
&
targetW
[
1
],
IO_REPARSE_TAG_SYMLINK
,
SYMLINK_FLAG_RELATIVE
,
&
buffer
);
bret
=
DeviceIoControl
(
handle
,
FSCTL_SET_REPARSE_POINT
,
(
LPVOID
)
buffer
,
buffer_len
,
NULL
,
0
,
&
dwret
,
0
);
CloseHandle
(
handle
);
ok
(
bret
,
"Failed to create symlink! (0x%x)
\n
"
,
GetLastError
());
cleanup:
/* Cleanup */
pRtlFreeUnicodeString
(
&
nameW
);
...
...
dlls/ntdll/unix/file.c
View file @
f282c8e7
...
...
@@ -3327,7 +3327,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
for
(
ptr
=
name
,
end
=
name
+
name_len
;
ptr
<
end
;
ptr
++
)
{
if
(
*
ptr
==
'\\'
)
return
STATUS_OBJECT_NAME_INVALID
;
/* duplicate backslash */
if
(
*
ptr
==
'.'
)
if
(
*
ptr
==
'.'
&&
disposition
!=
FILE_WINE_PATH
)
{
if
(
ptr
+
1
==
end
)
return
STATUS_OBJECT_NAME_INVALID
;
/* "." element */
if
(
ptr
[
1
]
==
'\\'
)
return
STATUS_OBJECT_NAME_INVALID
;
/* "." element */
...
...
@@ -5978,17 +5978,20 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer,
*/
NTSTATUS
create_reparse_point
(
HANDLE
handle
,
REPARSE_DATA_BUFFER
*
buffer
)
{
BOOL
src_allocated
=
FALSE
,
dest_allocated
=
FALSE
,
tempdir_created
=
FALSE
;
BOOL
src_allocated
=
FALSE
,
path_allocated
=
FALSE
,
dest_allocated
=
FALSE
;
BOOL
nt_dest_allocated
=
FALSE
,
tempdir_created
=
FALSE
;
char
*
unix_src
,
*
unix_dest
,
*
unix_path
=
NULL
;
char
tmpdir
[
PATH_MAX
],
tmplink
[
PATH_MAX
],
*
d
;
SIZE_T
unix_dest_len
=
PATH_MAX
;
char
*
unix_src
,
*
unix_dest
;
char
magic_dest
[
PATH_MAX
];
int
dest_fd
,
needs_close
;
int
relative_offset
=
0
;
UNICODE_STRING
nt_dest
;
int
dest_len
,
offset
;
NTSTATUS
status
;
struct
stat
st
;
WCHAR
*
dest
;
ULONG
flags
;
int
i
;
switch
(
buffer
->
ReparseTag
)
...
...
@@ -5997,11 +6000,13 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
dest_len
=
buffer
->
MountPointReparseBuffer
.
SubstituteNameLength
;
offset
=
buffer
->
MountPointReparseBuffer
.
SubstituteNameOffset
;
dest
=
&
buffer
->
MountPointReparseBuffer
.
PathBuffer
[
offset
];
flags
=
0
;
break
;
case
IO_REPARSE_TAG_SYMLINK
:
dest_len
=
buffer
->
SymbolicLinkReparseBuffer
.
SubstituteNameLength
;
offset
=
buffer
->
SymbolicLinkReparseBuffer
.
SubstituteNameOffset
;
dest
=
&
buffer
->
SymbolicLinkReparseBuffer
.
PathBuffer
[
offset
];
flags
=
buffer
->
SymbolicLinkReparseBuffer
.
Flags
;
break
;
default:
FIXME
(
"stub: FSCTL_SET_REPARSE_POINT(%x)
\n
"
,
buffer
->
ReparseTag
);
...
...
@@ -6014,8 +6019,66 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
if
((
status
=
server_get_unix_name
(
handle
,
&
unix_src
)))
goto
cleanup
;
src_allocated
=
TRUE
;
nt_dest
.
Buffer
=
dest
;
nt_dest
.
Length
=
dest_len
;
if
(
flags
==
SYMLINK_FLAG_RELATIVE
)
{
ULONG
nt_path_len
=
PATH_MAX
,
unix_path_len
=
PATH_MAX
;
WCHAR
*
nt_path
;
/* resolve the NT path of the source */
unix_path
=
malloc
(
strlen
(
unix_src
)
+
2
);
path_allocated
=
TRUE
;
strcpy
(
unix_path
,
unix_src
);
d
=
dirname
(
unix_path
);
if
(
d
!=
unix_path
)
strcpy
(
unix_path
,
d
);
strcat
(
unix_path
,
"/"
);
for
(;;)
{
nt_path
=
malloc
(
nt_path_len
*
sizeof
(
WCHAR
)
);
if
(
!
nt_path
)
{
status
=
STATUS_NO_MEMORY
;
goto
cleanup
;
}
status
=
wine_unix_to_nt_file_name
(
unix_path
,
nt_path
,
&
nt_path_len
);
if
(
status
!=
STATUS_BUFFER_TOO_SMALL
)
break
;
free
(
nt_path
);
}
if
(
status
!=
STATUS_SUCCESS
)
goto
cleanup
;
free
(
unix_path
);
/* re-resolve the unix path for the source */
for
(;;)
{
UNICODE_STRING
nt_path_tmp
;
unix_path
=
malloc
(
unix_path_len
);
if
(
!
unix_path
)
{
status
=
STATUS_NO_MEMORY
;
goto
cleanup
;
}
nt_path_tmp
.
Buffer
=
nt_path
;
nt_path_tmp
.
Length
=
wcslen
(
nt_path
)
*
sizeof
(
WCHAR
);
status
=
wine_nt_to_unix_file_name
(
&
nt_path_tmp
,
unix_path
,
&
unix_path_len
,
FALSE
);
if
(
status
!=
STATUS_BUFFER_TOO_SMALL
)
break
;
free
(
unix_path
);
}
/* append the destination */
nt_dest
.
MaximumLength
=
dest_len
+
(
wcslen
(
nt_path
)
+
1
)
*
sizeof
(
WCHAR
);
nt_dest
.
Buffer
=
malloc
(
nt_dest
.
MaximumLength
);
wcscpy
(
nt_dest
.
Buffer
,
nt_path
);
free
(
nt_path
);
memcpy
(
&
nt_dest
.
Buffer
[
wcslen
(
nt_dest
.
Buffer
)],
dest
,
dest_len
+
sizeof
(
WCHAR
));
nt_dest
.
Length
=
wcslen
(
nt_dest
.
Buffer
)
*
sizeof
(
WCHAR
);
}
else
{
nt_dest
.
MaximumLength
=
(
wcslen
(
dest
)
+
1
)
*
sizeof
(
WCHAR
);
nt_dest
.
Buffer
=
malloc
(
nt_dest
.
MaximumLength
);
wcscpy
(
nt_dest
.
Buffer
,
dest
);
nt_dest
.
Length
=
dest_len
;
}
nt_dest_allocated
=
TRUE
;
/* resolve the NT path of the destination */
for
(;;)
{
unix_dest
=
malloc
(
unix_dest_len
);
...
...
@@ -6031,11 +6094,24 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
if
(
status
!=
STATUS_SUCCESS
&&
status
!=
STATUS_NO_SUCH_FILE
)
goto
cleanup
;
dest_allocated
=
TRUE
;
/* check that the source and destination paths are the same up to the relative path */
if
(
flags
==
SYMLINK_FLAG_RELATIVE
)
{
relative_offset
=
strlen
(
unix_path
);
if
(
strncmp
(
unix_path
,
unix_dest
,
relative_offset
)
!=
0
)
{
status
=
STATUS_IO_REPARSE_DATA_INVALID
;
goto
cleanup
;
}
}
TRACE
(
"Linking %s to %s
\n
"
,
unix_src
,
unix_dest
);
TRACE
(
"Linking %s to %s
\n
"
,
unix_src
,
&
unix_dest
[
relative_offset
]
);
/* Encode the reparse tag into the symlink */
strcpy
(
magic_dest
,
"/"
);
strcpy
(
magic_dest
,
""
);
if
(
flags
==
SYMLINK_FLAG_RELATIVE
)
strcat
(
magic_dest
,
"."
);
strcat
(
magic_dest
,
"/"
);
for
(
i
=
0
;
i
<
sizeof
(
ULONG
)
*
8
;
i
++
)
{
if
((
buffer
->
ReparseTag
>>
i
)
&
1
)
...
...
@@ -6056,7 +6132,7 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
strcat
(
magic_dest
,
"."
);
strcat
(
magic_dest
,
"/"
);
}
strcat
(
magic_dest
,
unix_dest
);
strcat
(
magic_dest
,
&
unix_dest
[
relative_offset
]
);
/* Produce the link in a temporary location in the same folder */
strcpy
(
tmpdir
,
unix_src
);
...
...
@@ -6106,7 +6182,9 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
cleanup:
if
(
tempdir_created
)
rmdir
(
tmpdir
);
if
(
path_allocated
)
free
(
unix_path
);
if
(
dest_allocated
)
free
(
unix_dest
);
if
(
nt_dest_allocated
)
free
(
nt_dest
.
Buffer
);
if
(
src_allocated
)
free
(
unix_src
);
if
(
needs_close
)
close
(
dest_fd
);
return
status
;
...
...
include/ntifs.h
View file @
f282c8e7
...
...
@@ -61,4 +61,6 @@ typedef struct _REPARSE_GUID_DATA_BUFFER {
#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer)
#define SYMLINK_FLAG_RELATIVE 0x00000001
#endif
/* __WINE_NTIFS_H */
include/winternl.h
View file @
f282c8e7
...
...
@@ -2866,6 +2866,7 @@ typedef struct _RTL_ATOM_TABLE
#define FILE_OVERWRITE 4
#define FILE_OVERWRITE_IF 5
#define FILE_MAXIMUM_DISPOSITION 5
#define FILE_WINE_PATH 6
/* Characteristics of a File System */
#define FILE_REMOVABLE_MEDIA 0x00000001
...
...
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