From: Elizabeth Figura zfigura@codeweavers.com
--- programs/cmd/builtins.c | 62 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index aebd1136563..7bbf34df1ec 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -30,6 +30,10 @@
#include "wcmd.h" #include <shellapi.h> +#define WIN32_NO_STATUS +#include "winternl.h" +#include "winioctl.h" +#include "ddk/ntifs.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(cmd); @@ -3961,6 +3965,62 @@ RETURN_CODE WCMD_color(void) return errorlevel = return_code; }
+/* We cannot use SetVolumeMountPoint(), because that function forbids setting + * arbitrary directories as mount points, whereas mklink /j allows it. */ +BOOL create_mount_point(const WCHAR *link, const WCHAR *target) { + UNICODE_STRING nt_link, nt_target; + REPARSE_DATA_BUFFER *data; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + unsigned int size; + NTSTATUS status; + HANDLE file; + + TRACE( "link %s, target %s\n", debugstr_w(link), debugstr_w(target) ); + + status = RtlDosPathNameToNtPathName_U_WithStatus( link, &nt_link, NULL, NULL ); + if (status) return FALSE; + + status = RtlDosPathNameToNtPathName_U_WithStatus( target, &nt_target, NULL, NULL ); + if (status) + { + RtlFreeUnicodeString( &nt_link ); + return FALSE; + } + + size = offsetof( REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer ); + size += (nt_target.Length + sizeof(WCHAR)) * 2; + data = malloc( size ); + + data->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + data->ReparseDataLength = size - offsetof( REPARSE_DATA_BUFFER, MountPointReparseBuffer ); + data->Reserved = 0; + data->MountPointReparseBuffer.SubstituteNameOffset = 0; + data->MountPointReparseBuffer.SubstituteNameLength = nt_target.Length; + data->MountPointReparseBuffer.PrintNameOffset = nt_target.Length + sizeof(WCHAR); + data->MountPointReparseBuffer.PrintNameLength = nt_target.Length; + memcpy( data->MountPointReparseBuffer.PathBuffer, + nt_target.Buffer, nt_target.Length + sizeof(WCHAR) ); + memcpy( data->MountPointReparseBuffer.PathBuffer + (nt_target.Length / sizeof(WCHAR)) + 1, + nt_target.Buffer, nt_target.Length + sizeof(WCHAR) ); + RtlFreeUnicodeString( &nt_target ); + + InitializeObjectAttributes( &attr, &nt_link, OBJ_CASE_INSENSITIVE, 0, NULL ); + status = NtCreateFile( &file, GENERIC_WRITE, &attr, &io, NULL, 0, 0, FILE_OPEN_IF, + FILE_OPEN_REPARSE_POINT | FILE_DIRECTORY_FILE, NULL, 0 ); + RtlFreeUnicodeString( &nt_link ); + if (status) + { + free( data ); + return FALSE; + } + + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, FSCTL_SET_REPARSE_POINT, data, size, NULL, 0 ); + free( data ); + NtClose( file ); + return !status; +} + /**************************************************************************** * WCMD_mklink */ @@ -4011,7 +4071,7 @@ RETURN_CODE WCMD_mklink(WCHAR *args) else if(!junction) ret = CreateSymbolicLinkW(file1, file2, isdir); else - TRACE("Junction links currently not supported.\n"); + ret = create_mount_point(file1, file2); }
if (ret) return errorlevel = NO_ERROR;