From: "Erich E. Hoover" Subject: [PATCH 3/7] ntdll: Add support for deleting junction points. Message-Id: Date: Wed, 20 Jun 2012 17:28:36 -0600 This patch adds support for the FSCTL_DELETE_REPARSE_POINT ioctl for the reparse tag IO_REPARSE_TAG_MOUNT_POINT (junction points). Allowing for the deletion of junction points created from the feature in part 1. From 89095b3ca55ee963a0e5f3b78c6c33f4fccf2ca6 Mon Sep 17 00:00:00 2001 From: Erich Hoover Date: Wed, 20 Jun 2012 17:18:36 -0600 Subject: ntdll: Add support for deleting junction points. --- dlls/ntdll/file.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/tests/file.c | 8 +++++++ include/ntifs.h | 11 ++++++++++ 3 files changed, 70 insertions(+), 0 deletions(-) diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index efa94cd..593785b 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -1473,6 +1473,41 @@ cleanup: } +/* + * Retrieve the unix name corresponding to a file handle, remove that symlink, and then recreate + * a directory at the location of the old filename. + */ +NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer) +{ + int dest_fd, needs_close; + ANSI_STRING unix_name; + NTSTATUS status; + + if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &dest_fd, &needs_close, NULL, NULL ))) + return status; + + if ((status = server_get_unix_name( handle, &unix_name ))) + goto cleanup; + + TRACE("Deleting symlink %s\n", unix_name.Buffer); + if (unlink( unix_name.Buffer ) < 0) + { + status = FILE_GetNtStatus(); + goto cleanup; + } + if (mkdir( unix_name.Buffer, 0775 ) < 0) + { + status = FILE_GetNtStatus(); + goto cleanup; + } + status = STATUS_SUCCESS; + +cleanup: + if (needs_close) close( dest_fd ); + return status; +} + + /************************************************************************** * NtFsControlFile [NTDLL.@] * ZwFsControlFile [NTDLL.@] @@ -1620,6 +1655,22 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc break; } + case FSCTL_DELETE_REPARSE_POINT: + { + REPARSE_GUID_DATA_BUFFER *buffer = (REPARSE_GUID_DATA_BUFFER *)in_buffer; + + switch(buffer->ReparseTag) + { + case IO_REPARSE_TAG_MOUNT_POINT: + status = FILE_RemoveSymlink( handle, buffer ); + break; + default: + FIXME("stub: FSCTL_DELETE_REPARSE_POINT(%x)\n", buffer->ReparseTag); + status = STATUS_NOT_IMPLEMENTED; + break; + } + break; + } case FSCTL_GET_REPARSE_POINT: { REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer; diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 62eb1a3..b626e44 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1747,6 +1747,7 @@ static void test_junction_points(void) static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; static const WCHAR fooW[] = {'f','o','o',0}; static WCHAR volW[] = {'c',':','\\',0}; + REPARSE_GUID_DATA_BUFFER guid_buffer; static const WCHAR dotW[] = {'.',0}; REPARSE_DATA_BUFFER *buffer = NULL; DWORD dwret, dwLen, dwFlags; @@ -1812,6 +1813,13 @@ static void test_junction_points(void) ok(bret, "Failed to read junction point!\n"); 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)); + + /* Delete the junction point */ + memset(&guid_buffer, 0x00, sizeof(guid_buffer)); + guid_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + bret = DeviceIoControl(hJunction, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer, + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0); + ok(bret, "Failed to delete junction point! (0x%x)\n", GetLastError()); CloseHandle(hJunction); cleanup: diff --git a/include/ntifs.h b/include/ntifs.h index db07c28..cb8638b 100644 --- a/include/ntifs.h +++ b/include/ntifs.h @@ -47,6 +47,17 @@ typedef struct _REPARSE_DATA_BUFFER { }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; +typedef struct _REPARSE_GUID_DATA_BUFFER { + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; + GUID ReparseGuid; + struct { + BYTE DataBuffer[1]; + } GenericReparseBuffer; +} REPARSE_GUID_DATA_BUFFER, *PREPARSE_GUID_DATA_BUFFER; + #define IO_REPARSE_TAG_MOUNT_POINT 0xa0000003 +#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer) #endif /* __WINE_NTIFS_H */ -- 1.7.5.4