Commit 7a9ebae1 authored by Erich E. Hoover's avatar Erich E. Hoover Committed by Vitaly Lipatov

ntdll: Add support for reading junction points.

parent a3ea9152
......@@ -5364,14 +5364,15 @@ static void test_reparse_points(void)
static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0};
WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH];
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
INT buffer_len, string_len, path_len, total_len;
static const WCHAR fooW[] = {'f','o','o',0};
static WCHAR volW[] = {'c',':','\\',0};
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags;
UNICODE_STRING nameW;
INT buffer_len;
HANDLE handle;
WCHAR *dest;
BOOL bret;
/* Create a temporary folder for the junction point tests */
......@@ -5419,6 +5420,23 @@ static void test_reparse_points(void)
buffer_len = build_reparse_buffer(nameW.Buffer, &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());
/* Read back the junction point */
HeapFree(GetProcessHeap(), 0, buffer);
buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR);
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
ok(bret, "Failed to read junction point!\n");
string_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
ok((memcmp(dest, nameW.Buffer, string_len) == 0), "Junction point destination does not match ('%s' != '%s')!\n",
wine_dbgstr_w(dest), wine_dbgstr_w(nameW.Buffer));
path_len = buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR);
path_len += buffer->MountPointReparseBuffer.PrintNameLength/sizeof(WCHAR);
total_len = FIELD_OFFSET(typeof(*buffer), MountPointReparseBuffer.PathBuffer[path_len+1])
- FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer);
ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n",
buffer->ReparseDataLength, total_len);
CloseHandle(handle);
cleanup:
......
......@@ -6082,6 +6082,127 @@ cleanup:
}
/*
* Retrieve the unix name corresponding to a file handle and use that to find the destination of the
* symlink corresponding to that file handle.
*/
NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *size)
{
char *unix_src, unix_dest[PATH_MAX];
INT prefix_len, path_len, total_len;
VOID *subst_name, *print_name;
SIZE_T nt_dest_len = PATH_MAX;
BOOL dest_allocated = FALSE;
int dest_fd, needs_close;
ULONG out_size = *size;
int unix_dest_len;
DWORD max_length;
NTSTATUS status;
WCHAR *nt_dest;
ssize_t ret;
char *p;
int i;
if ((status = server_get_unix_fd( handle, FILE_ANY_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
return status;
if ((status = server_get_unix_name( handle, &unix_src )))
goto cleanup;
ret = readlink( unix_src, unix_dest, sizeof(unix_dest) );
if (ret < 0)
{
status = errno_to_status( errno );
goto cleanup;
}
unix_dest_len = ret;
/* Decode the reparse tag from the symlink */
p = unix_dest;
if (*p++ != '/')
{
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
buffer->ReparseTag = 0;
for (i = 0; i < sizeof(ULONG)*8; i++)
{
char c = *p++;
int val;
if (c == '/')
val = 0;
else if (c == '.' && *p++ == '/')
val = 1;
else
{
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
buffer->ReparseTag |= (val << i);
}
unix_dest_len -= (p - unix_dest);
memmove(unix_dest, p, unix_dest_len);
unix_dest[unix_dest_len] = 0;
for (;;)
{
nt_dest = malloc( nt_dest_len * sizeof(WCHAR) );
if (!nt_dest)
{
status = STATUS_NO_MEMORY;
goto cleanup;
}
status = wine_unix_to_nt_file_name( unix_dest, nt_dest, &nt_dest_len );
if (status != STATUS_BUFFER_TOO_SMALL) break;
free( nt_dest );
}
dest_allocated = TRUE;
if (status != STATUS_SUCCESS)
goto cleanup;
nt_dest_len *= sizeof(WCHAR);
prefix_len = strlen("\\??\\");
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
max_length = out_size-FIELD_OFFSET(typeof(*buffer), MountPointReparseBuffer.PathBuffer[1]);
path_len = 0;
buffer->MountPointReparseBuffer.SubstituteNameOffset = path_len;
buffer->MountPointReparseBuffer.SubstituteNameLength = nt_dest_len;
path_len += nt_dest_len + sizeof(WCHAR);
subst_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
buffer->MountPointReparseBuffer.PrintNameOffset = path_len;
buffer->MountPointReparseBuffer.PrintNameLength = nt_dest_len - prefix_len*sizeof(WCHAR);
print_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
path_len += (nt_dest_len - prefix_len*sizeof(WCHAR)) + sizeof(WCHAR);
total_len = FIELD_OFFSET(typeof(*buffer), MountPointReparseBuffer.PathBuffer[path_len/sizeof(WCHAR)]);
break;
default:
/* unrecognized (regular) files should probably be treated as symlinks */
WARN("unrecognized symbolic link\n");
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
if (nt_dest_len > max_length)
{
status = STATUS_BUFFER_TOO_SMALL;
goto cleanup;
}
memcpy( subst_name, nt_dest, nt_dest_len );
memcpy( print_name, &nt_dest[prefix_len], nt_dest_len - prefix_len*sizeof(WCHAR) );
*size = total_len;
buffer->ReparseDataLength = total_len - FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer);
status = STATUS_SUCCESS;
cleanup:
if (dest_allocated) free( nt_dest );
if (needs_close) close( dest_fd );
return status;
}
/******************************************************************************
* NtFsControlFile (NTDLL.@)
*/
......@@ -6164,6 +6285,14 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
}
case FSCTL_GET_REPARSE_POINT:
{
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
ULONG size = out_size;
status = get_reparse_point( handle, buffer, &size );
io->Information = size;
break;
}
case FSCTL_SET_REPARSE_POINT:
{
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment