+ /* If it failed, only allow case where IO mount point was ignored */
+ if (Status != STATUS_IO_REPARSE_TAG_NOT_HANDLED)
+ {
+ goto Cleanup;
+ }
+
+ /* Reopen with reparse point support */
+ Status = NtOpenFile(&DirectoryHandle,
+ DELETE | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
+ FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
+ if (NT_SUCCESS(Status))
+ {
+ /* And mark for delete */
+ goto MarkFileForDelete;
+ }
+
+ goto Cleanup;
+ }
+
+ /* Here, we have a mount point, prepare to query information about it */
+ ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ if (!ReparseDataBuffer)
+ {
+ RtlReleaseRelativeName(&RelativeName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
+ NtClose(DirectoryHandle);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ /* Query */
+ if (!DeviceIoControl(DirectoryHandle,
+ FSCTL_GET_REPARSE_POINT,
+ NULL, 0,
+ ReparseDataBuffer,
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
+ &BytesReturned,
+ NULL))
+ {
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
+ goto MarkFileForDelete;
+ }
+
+ /* Get volume name */
+ SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
+ ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
+ if (!IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength))
+ {
+ /* This is not a volume, we can safely delete */
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
+ goto MarkFileForDelete;
+ }
+
+ /* Prepare to delete mount point */
+ RtlInitUnicodeString(&PathName, lpPathName);
+ PathName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathName.Length + 2 * sizeof(WCHAR));
+ if (!PathName.Buffer)
+ {
+ RtlReleaseRelativeName(&RelativeName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
+ NtClose(DirectoryHandle);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ RtlCopyMemory(&PathName.Buffer, lpPathName, PathName.Length);
+ if (PathName.Buffer[PathName.Length / sizeof(WCHAR)] != L'\\')
+ {
+ PathName.Buffer[PathName.Length / sizeof(WCHAR)] = L'\\';
+ PathName.Buffer[(PathName.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
+ }
+
+ /* Delete mount point for that volume */
+ DeleteVolumeMountPointW(PathName.Buffer);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
+
+ /* And mark directory for delete */
+MarkFileForDelete:
+ RtlReleaseRelativeName(&RelativeName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
+
+ /* Mark & set */
+ FileDispInfo.DeleteFile = TRUE;
+ Status = NtSetInformationFile(DirectoryHandle,
+ &IoStatusBlock,
+ &FileDispInfo,
+ sizeof(FILE_DISPOSITION_INFORMATION),
+ FileDispositionInformation);
+ NtClose(DirectoryHandle);
+
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError (Status);
+ return FALSE;
+ }
+
+ return TRUE;
+
+CleanupHandle:
+ NtClose(DirectoryHandle);
+
+Cleanup:
+ RtlReleaseRelativeName(&RelativeName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
+ BaseSetLastNTError(Status);
+ return FALSE;