You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
791 lines
21 KiB
791 lines
21 KiB
#define UNICODE 1
|
|
#define _UNICODE 1
|
|
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntstatus.h>
|
|
#include <ntioapi.h>
|
|
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <dbt.h>
|
|
#include <devguid.h>
|
|
#include <eh.h>
|
|
|
|
#include <shlwapi.h>
|
|
#include <dfsutil.hxx>
|
|
#define UNICODE_PATH_SEP L'\\'
|
|
|
|
DWORD
|
|
DeleteLinkReparsePoint(
|
|
PUNICODE_STRING pDirectoryName,
|
|
HANDLE ParentHandle );
|
|
|
|
DWORD DisplayFileName(
|
|
PTSTR pszVolume,
|
|
HANDLE hVolume,
|
|
LONGLONG llFileId,
|
|
BOOL fRemoveDirectory);
|
|
|
|
void
|
|
CountReparsePoints(PCTSTR pcszInput);
|
|
|
|
DWORD
|
|
xGetRootDirectory(PCTSTR pcszInput, PTSTR* pszRootDir);
|
|
|
|
HANDLE xOpenReparseIndex(PCTSTR pcszVolume);
|
|
HANDLE xOpenVolume(PCTSTR pcszVolume);
|
|
BOOL xGetNextReparseRecord(
|
|
HANDLE hIndex,
|
|
PFILE_REPARSE_POINT_INFORMATION ReparseInfo);
|
|
|
|
|
|
|
|
|
|
DWORD CountReparsePoints(LPWSTR pcszInput, BOOL fRemoveDirectory)
|
|
{
|
|
PTSTR pszVolume = NULL;
|
|
DWORD dwCount = 0;
|
|
DWORD Error = 0;
|
|
BOOL fDone = TRUE;
|
|
HANDLE hIndex = INVALID_HANDLE_VALUE;
|
|
HANDLE hVolume = INVALID_HANDLE_VALUE;
|
|
FILE_REPARSE_POINT_INFORMATION ReparseInfo;
|
|
|
|
Error = xGetRootDirectory(
|
|
pcszInput,
|
|
&pszVolume);
|
|
if(Error != 0)
|
|
{
|
|
return Error;
|
|
}
|
|
|
|
hIndex = xOpenReparseIndex(
|
|
pszVolume);
|
|
if(hIndex == INVALID_HANDLE_VALUE)
|
|
{
|
|
Error = GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
hVolume = xOpenVolume(
|
|
pszVolume);
|
|
|
|
if(hVolume == INVALID_HANDLE_VALUE)
|
|
{
|
|
Error = GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
fDone = xGetNextReparseRecord(
|
|
hIndex,
|
|
&ReparseInfo);
|
|
|
|
while (!fDone)
|
|
{
|
|
if (IO_REPARSE_TAG_DFS == ReparseInfo.Tag)
|
|
{
|
|
dwCount++;
|
|
DisplayFileName(
|
|
pszVolume,
|
|
hVolume,
|
|
ReparseInfo.FileReference,
|
|
fRemoveDirectory);
|
|
}
|
|
|
|
fDone = xGetNextReparseRecord(
|
|
hIndex,
|
|
&ReparseInfo);
|
|
|
|
}
|
|
|
|
|
|
Error = GetLastError();
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
if(hIndex != INVALID_HANDLE_VALUE )
|
|
{
|
|
CloseHandle(hIndex);
|
|
hIndex = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
_tprintf(
|
|
_T("This volume (%ws) contains %u DFS Directories.\n"),
|
|
pszVolume,
|
|
dwCount);
|
|
|
|
if (hVolume!=INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hVolume);
|
|
}
|
|
|
|
if(pszVolume)
|
|
{
|
|
delete []pszVolume;
|
|
}
|
|
|
|
return Error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
xGetRootDirectory(PCTSTR pcszInput, PTSTR* pszRootDir)
|
|
{
|
|
DWORD dwBufferSize = MAX_PATH;
|
|
PTSTR pszTemp = NULL;
|
|
BOOL bResult = FALSE;
|
|
DWORD dwGleCode = 0;
|
|
|
|
*pszRootDir = NULL;
|
|
|
|
|
|
do
|
|
{
|
|
pszTemp = new TCHAR[dwBufferSize];
|
|
if(pszTemp == NULL)
|
|
{
|
|
dwGleCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
return dwGleCode;
|
|
|
|
}
|
|
bResult = GetVolumePathName(
|
|
pcszInput,
|
|
pszTemp,
|
|
dwBufferSize);
|
|
|
|
if (!bResult)
|
|
{
|
|
delete []pszTemp;
|
|
dwGleCode = GetLastError();
|
|
if (ERROR_BUFFER_OVERFLOW==dwGleCode)
|
|
{
|
|
dwBufferSize *= 2;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
} while (!bResult);
|
|
|
|
*pszRootDir = pszTemp;
|
|
|
|
return dwGleCode;
|
|
}
|
|
|
|
|
|
HANDLE xOpenReparseIndex(PCTSTR pcszVolume)
|
|
{
|
|
HANDLE hReparseIndex = INVALID_HANDLE_VALUE;
|
|
PTSTR pszReparseIndex = NULL;
|
|
DWORD Error = 0;
|
|
|
|
pszReparseIndex = new TCHAR[_tcslen(pcszVolume)+64];
|
|
if(pszReparseIndex == NULL)
|
|
{
|
|
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
|
|
return hReparseIndex;
|
|
|
|
}
|
|
_tcscpy(
|
|
pszReparseIndex,
|
|
pcszVolume);
|
|
PathAddBackslash(pszReparseIndex);
|
|
_tcscat(
|
|
pszReparseIndex,
|
|
_T("$Extend\\$Reparse:$R:$INDEX_ALLOCATION"));
|
|
|
|
hReparseIndex = CreateFile(
|
|
pszReparseIndex,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
|
|
NULL);
|
|
|
|
Error = GetLastError ();
|
|
|
|
delete []pszReparseIndex;
|
|
|
|
SetLastError (Error);
|
|
|
|
return hReparseIndex;
|
|
}
|
|
|
|
|
|
HANDLE xOpenVolume(PCTSTR pcszVolume)
|
|
{
|
|
HANDLE hVolume = INVALID_HANDLE_VALUE;
|
|
PTSTR pszVolumeName = NULL;
|
|
DWORD Error = 0;
|
|
|
|
pszVolumeName = new TCHAR[MAX_PATH];
|
|
|
|
BOOL bResult = GetVolumeNameForVolumeMountPoint(
|
|
pcszVolume,
|
|
pszVolumeName,
|
|
MAX_PATH);
|
|
|
|
if (bResult)
|
|
{
|
|
hVolume = CreateFile(
|
|
pszVolumeName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
|
|
NULL);
|
|
|
|
Error = GetLastError ();
|
|
|
|
}
|
|
else
|
|
{
|
|
Error = GetLastError ();
|
|
}
|
|
|
|
delete []pszVolumeName;
|
|
|
|
SetLastError (Error);
|
|
|
|
return hVolume;
|
|
}
|
|
|
|
|
|
BOOL xGetNextReparseRecord(
|
|
HANDLE hIndex,
|
|
PFILE_REPARSE_POINT_INFORMATION ReparseInfo)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
DWORD Error = 0;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
|
|
NTSTATUS status = NtQueryDirectoryFile(hIndex,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatus,
|
|
ReparseInfo,
|
|
sizeof(FILE_REPARSE_POINT_INFORMATION),
|
|
FileReparsePointInformation,
|
|
TRUE,
|
|
NULL,
|
|
FALSE);
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
Error = RtlNtStatusToDosError(status);
|
|
if(Error == ERROR_NO_MORE_FILES)
|
|
{
|
|
Error = 0;
|
|
}
|
|
|
|
bResult = TRUE;
|
|
}
|
|
|
|
SetLastError(Error);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
DWORD
|
|
DeleteDirectory(LPWSTR VolumeName, LPWSTR pDfsDirectory)
|
|
{
|
|
DWORD Status = 0;
|
|
DWORD BuffLen = 0;
|
|
LPWSTR lpExistingFileName = NULL;
|
|
UNICODE_STRING UnicodeFileName;
|
|
|
|
BuffLen = (wcslen(L"\\??\\") + 1) * sizeof(WCHAR);
|
|
BuffLen += ((wcslen((const wchar_t *)pDfsDirectory) + 1)* sizeof(WCHAR));
|
|
BuffLen += ((wcslen((const wchar_t *)VolumeName) + 1)* sizeof(WCHAR));
|
|
|
|
lpExistingFileName = (LPWSTR)HeapAlloc (GetProcessHeap(), 0, BuffLen);
|
|
if(lpExistingFileName == NULL)
|
|
{
|
|
wprintf(L"Out of memory\n");
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
return Status;
|
|
}
|
|
|
|
wcscpy(lpExistingFileName, L"\\??\\");
|
|
wcscat(lpExistingFileName, (const wchar_t *) VolumeName);
|
|
wcscat(lpExistingFileName, (const wchar_t *) pDfsDirectory);
|
|
|
|
UnicodeFileName.Buffer = lpExistingFileName ;
|
|
UnicodeFileName.Length = wcslen(lpExistingFileName) * sizeof(WCHAR);
|
|
UnicodeFileName.MaximumLength = UnicodeFileName.Length;
|
|
|
|
Status = DeleteLinkReparsePoint( &UnicodeFileName,
|
|
NULL);
|
|
HeapFree(GetProcessHeap(), 0, lpExistingFileName);
|
|
|
|
return Status;
|
|
}
|
|
|
|
DWORD DisplayFileName(
|
|
PTSTR pszVolume,
|
|
HANDLE hVolume,
|
|
LONGLONG llFileId,
|
|
BOOL fRemoveDirectory)
|
|
{
|
|
UNICODE_STRING usIdString;
|
|
NTSTATUS status = 0;
|
|
DWORD ErrorCode = 0;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
struct {
|
|
FILE_NAME_INFORMATION FileInformation;
|
|
WCHAR FileName[MAX_PATH];
|
|
} NameFile;
|
|
|
|
fRemoveDirectory;
|
|
|
|
ZeroMemory(
|
|
&NameFile,
|
|
sizeof(NameFile));
|
|
|
|
usIdString.Length = sizeof(LONGLONG);
|
|
usIdString.MaximumLength = sizeof(LONGLONG);
|
|
usIdString.Buffer = (PWCHAR)&llFileId;
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&usIdString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hVolume,
|
|
NULL); // security descriptor
|
|
|
|
status = NtCreateFile(
|
|
&hFile,
|
|
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL, // allocation size
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
FILE_OPEN,
|
|
FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_BY_FILE_ID,
|
|
NULL, // EA buffer
|
|
0); // EA length
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
status = NtQueryInformationFile(
|
|
hFile,
|
|
&IoStatusBlock,
|
|
&(NameFile.FileInformation),
|
|
sizeof(NameFile),
|
|
FileNameInformation);
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
wprintf(L"%ws%ws\n",pszVolume, NameFile.FileInformation.FileName+1);
|
|
}
|
|
else
|
|
{
|
|
ErrorCode = RtlNtStatusToDosError(status);
|
|
SetLastError(ErrorCode);
|
|
|
|
_tprintf(_T("Unable to query file name.\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorCode = RtlNtStatusToDosError(status);
|
|
SetLastError(ErrorCode);
|
|
|
|
_tprintf(_T("Unable to open file by ID.\n"));
|
|
}
|
|
|
|
if (hFile!=INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if((ErrorCode == 0) && fRemoveDirectory)
|
|
{
|
|
DeleteDirectory(pszVolume, NameFile.FileInformation.FileName+1);
|
|
}
|
|
|
|
return ErrorCode;
|
|
|
|
}
|
|
|
|
VOID
|
|
CloseDirectory(
|
|
HANDLE DirHandle )
|
|
{
|
|
NtClose( DirHandle );
|
|
}
|
|
|
|
NTSTATUS
|
|
ClearDfsReparsePoint(
|
|
IN HANDLE DirHandle )
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
REPARSE_DATA_BUFFER ReparseDataBuffer;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
//
|
|
// Attempt to set a reparse point on the directory
|
|
//
|
|
RtlZeroMemory( &ReparseDataBuffer, sizeof(ReparseDataBuffer) );
|
|
|
|
ReparseDataBuffer.ReparseTag = IO_REPARSE_TAG_DFS;
|
|
ReparseDataBuffer.ReparseDataLength = 0;
|
|
|
|
NtStatus = NtFsControlFile( DirHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
FSCTL_DELETE_REPARSE_POINT,
|
|
&ReparseDataBuffer,
|
|
REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataBuffer.ReparseDataLength,
|
|
NULL,
|
|
0 );
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
OpenDirectory(
|
|
PUNICODE_STRING pDirectoryName,
|
|
ULONG ShareMode,
|
|
HANDLE RelativeHandle,
|
|
PHANDLE pOpenedHandle,
|
|
PBOOLEAN pIsNewlyCreated )
|
|
{
|
|
|
|
NTSTATUS NtStatus;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
ACCESS_MASK DesiredAccess;
|
|
PLARGE_INTEGER AllocationSize;
|
|
ULONG FileAttributes;
|
|
ULONG CreateDisposition;
|
|
ULONG CreateOptions;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
AllocationSize = NULL;
|
|
FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
CreateDisposition = FILE_OPEN_IF;
|
|
CreateOptions = FILE_DIRECTORY_FILE |
|
|
FILE_OPEN_REPARSE_POINT |
|
|
FILE_SYNCHRONOUS_IO_NONALERT;
|
|
|
|
DesiredAccess = FILE_READ_DATA |
|
|
FILE_WRITE_DATA |
|
|
FILE_READ_ATTRIBUTES |
|
|
FILE_WRITE_ATTRIBUTES |
|
|
SYNCHRONIZE;
|
|
|
|
InitializeObjectAttributes (
|
|
&ObjectAttributes,
|
|
pDirectoryName, //Object Name
|
|
0, //Attributes
|
|
RelativeHandle, //Root handle
|
|
NULL); //Security descriptor.
|
|
|
|
NtStatus = NtCreateFile(pOpenedHandle,
|
|
DesiredAccess,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
AllocationSize,
|
|
FileAttributes,
|
|
ShareMode,
|
|
CreateDisposition,
|
|
CreateOptions,
|
|
NULL, // EaBuffer
|
|
0 ); // EaLength
|
|
|
|
|
|
if ( (NtStatus == STATUS_SUCCESS) && (pIsNewlyCreated != NULL) )
|
|
{
|
|
*pIsNewlyCreated = (IoStatusBlock.Information == FILE_CREATED)? TRUE : FALSE;
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
IsDirectoryReparsePoint(
|
|
IN HANDLE DirHandle,
|
|
OUT PBOOLEAN pReparsePoint,
|
|
OUT PBOOLEAN pDfsReparsePoint )
|
|
{
|
|
NTSTATUS NtStatus;
|
|
FILE_BASIC_INFORMATION BasicInfo;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
//
|
|
//we assume these are not reparse points.
|
|
//
|
|
*pReparsePoint = FALSE;
|
|
*pDfsReparsePoint = FALSE;
|
|
|
|
//
|
|
// Query for the basic information, which has the attributes.
|
|
//
|
|
NtStatus = NtQueryInformationFile( DirHandle,
|
|
&IoStatusBlock,
|
|
(PVOID)&BasicInfo,
|
|
sizeof(BasicInfo),
|
|
FileBasicInformation );
|
|
|
|
if (NtStatus == STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// If the attributes indicate reparse point, we have a reparse
|
|
// point directory on our hands.
|
|
//
|
|
if ( BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
|
|
{
|
|
FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
|
|
|
|
*pReparsePoint = TRUE;
|
|
|
|
NtStatus = NtQueryInformationFile( DirHandle,
|
|
&IoStatusBlock,
|
|
(PVOID)&FileTagInformation,
|
|
sizeof(FileTagInformation),
|
|
FileAttributeTagInformation );
|
|
|
|
if (NtStatus == STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Checkif the tag indicates its a DFS reparse point,
|
|
// and setup the return accordingly.
|
|
//
|
|
if (FileTagInformation.ReparseTag == IO_REPARSE_TAG_DFS)
|
|
{
|
|
*pDfsReparsePoint = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IsEmptyDirectory(
|
|
HANDLE DirectoryHandle,
|
|
PVOID pDirectoryBuffer,
|
|
ULONG DirectoryBufferSize )
|
|
{
|
|
NTSTATUS NtStatus;
|
|
FILE_NAMES_INFORMATION *pFileInfo;
|
|
ULONG NumberOfFiles = 1;
|
|
BOOLEAN ReturnValue = FALSE;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
|
|
NtStatus = NtQueryDirectoryFile ( DirectoryHandle,
|
|
NULL, // no event
|
|
NULL, // no apc routine
|
|
NULL, // no apc context
|
|
&IoStatus,
|
|
pDirectoryBuffer,
|
|
DirectoryBufferSize,
|
|
FileNamesInformation,
|
|
FALSE, // return single entry = false
|
|
NULL, // filename
|
|
FALSE ); // restart scan = false
|
|
if (NtStatus == ERROR_SUCCESS)
|
|
{
|
|
pFileInfo = (FILE_NAMES_INFORMATION *)pDirectoryBuffer;
|
|
|
|
while (pFileInfo->NextEntryOffset) {
|
|
NumberOfFiles++;
|
|
if (NumberOfFiles > 3)
|
|
{
|
|
break;
|
|
}
|
|
pFileInfo = (FILE_NAMES_INFORMATION *)((ULONG_PTR)(pFileInfo) +
|
|
pFileInfo->NextEntryOffset);
|
|
}
|
|
|
|
if (NumberOfFiles <= 2)
|
|
{
|
|
ReturnValue = TRUE;
|
|
}
|
|
}
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
NTSTATUS
|
|
DeleteLinkDirectories(
|
|
PUNICODE_STRING pLinkName,
|
|
HANDLE RelativeHandle )
|
|
{
|
|
UNICODE_STRING DirectoryToDelete = *pLinkName;
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
HANDLE CurrentDirectory = NULL;
|
|
ULONG ShareMode = 0;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
ShareMode = FILE_SHARE_READ;
|
|
//
|
|
// dfsdev: fix this fixed size limit. it will hurt us in the future.
|
|
//
|
|
ULONG DirectoryBufferSize = 4096;
|
|
PBYTE pDirectoryBuffer = new BYTE [DirectoryBufferSize];
|
|
|
|
if (pDirectoryBuffer == NULL)
|
|
{
|
|
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// BUG 701594: Don't delete all directories under a reparse dir.
|
|
// Just remove the reparse dir.
|
|
if ( (NtStatus == STATUS_SUCCESS) && (DirectoryToDelete.Length != 0) )
|
|
{
|
|
NtStatus = OpenDirectory( &DirectoryToDelete,
|
|
ShareMode,
|
|
RelativeHandle,
|
|
&CurrentDirectory,
|
|
NULL );
|
|
if (NtStatus == ERROR_SUCCESS)
|
|
{
|
|
if (IsEmptyDirectory(CurrentDirectory,
|
|
pDirectoryBuffer,
|
|
DirectoryBufferSize) == FALSE)
|
|
{
|
|
CloseDirectory( CurrentDirectory );
|
|
}
|
|
else
|
|
{
|
|
CloseDirectory( CurrentDirectory );
|
|
InitializeObjectAttributes (
|
|
&ObjectAttributes,
|
|
&DirectoryToDelete,
|
|
0,
|
|
RelativeHandle,
|
|
NULL);
|
|
|
|
NtStatus = NtDeleteFile( &ObjectAttributes );
|
|
DebugInformation((L"Removed Directory %wZ, Status 0x%x\n",
|
|
&DirectoryToDelete, NtStatus));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pDirectoryBuffer != NULL)
|
|
{
|
|
delete [] pDirectoryBuffer;
|
|
}
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
DWORD
|
|
DeleteLinkReparsePoint(
|
|
PUNICODE_STRING pDirectoryName,
|
|
HANDLE ParentHandle )
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
DWORD DosStatus = ERROR_SUCCESS;
|
|
HANDLE LinkDirectoryHandle = INVALID_HANDLE_VALUE;
|
|
BOOLEAN IsReparsePoint = FALSE;
|
|
BOOLEAN IsDfsReparsePoint = FALSE;
|
|
|
|
NtStatus = OpenDirectory( pDirectoryName,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
ParentHandle,
|
|
&LinkDirectoryHandle,
|
|
NULL );
|
|
if (NtStatus == STATUS_SUCCESS)
|
|
{
|
|
NtStatus = IsDirectoryReparsePoint( LinkDirectoryHandle,
|
|
&IsReparsePoint,
|
|
&IsDfsReparsePoint );
|
|
|
|
if ((NtStatus == STATUS_SUCCESS) &&
|
|
(IsDfsReparsePoint == TRUE) )
|
|
{
|
|
|
|
NtStatus = ClearDfsReparsePoint( LinkDirectoryHandle );
|
|
DosStatus = RtlNtStatusToDosError(NtStatus);
|
|
|
|
wprintf(L"ClearDfsReparsePoint for %ws returned %x\n", pDirectoryName->Buffer, DosStatus);
|
|
}
|
|
else if(NtStatus != STATUS_SUCCESS)
|
|
{
|
|
DosStatus = RtlNtStatusToDosError(NtStatus);
|
|
wprintf(L"Clearing DFS reparse point for %ws failed %x\n", pDirectoryName->Buffer, DosStatus);
|
|
}
|
|
else if(IsDfsReparsePoint == FALSE)
|
|
{
|
|
DosStatus = RtlNtStatusToDosError(NtStatus);
|
|
|
|
wprintf(L"%ws does not have a DFS reparse point %x\n", pDirectoryName->Buffer, DosStatus);
|
|
}
|
|
|
|
NtClose( LinkDirectoryHandle );
|
|
}
|
|
else
|
|
{
|
|
NtStatus = RtlNtStatusToDosError(NtStatus);
|
|
wprintf(L"Open for %ws returned %x\n", pDirectoryName->Buffer, NtStatus);
|
|
}
|
|
|
|
if (NtStatus == STATUS_SUCCESS)
|
|
{
|
|
NtStatus = DeleteLinkDirectories( pDirectoryName,
|
|
NULL);
|
|
}
|
|
|
|
DosStatus = RtlNtStatusToDosError(NtStatus);
|
|
|
|
return DosStatus;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
DeleteReparsePoint(LPWSTR pDfsDirectory)
|
|
{
|
|
DWORD Status = 0;
|
|
DWORD BuffLen = 0;
|
|
LPWSTR lpExistingFileName = NULL;
|
|
UNICODE_STRING UnicodeFileName;
|
|
|
|
BuffLen = (wcslen(L"\\??\\") + 1) * sizeof(WCHAR);
|
|
BuffLen += ((wcslen((const wchar_t *)pDfsDirectory) + 1)* sizeof(WCHAR));
|
|
|
|
lpExistingFileName = (LPWSTR)HeapAlloc (GetProcessHeap(), 0, BuffLen);
|
|
if(lpExistingFileName == NULL)
|
|
{
|
|
wprintf(L"Out of memory\n");
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
return Status;
|
|
}
|
|
|
|
wcscpy(lpExistingFileName, L"\\??\\");
|
|
wcscat(lpExistingFileName, (const wchar_t *) pDfsDirectory);
|
|
|
|
UnicodeFileName.Buffer = lpExistingFileName ;
|
|
UnicodeFileName.Length = wcslen(lpExistingFileName) * sizeof(WCHAR);
|
|
UnicodeFileName.MaximumLength = UnicodeFileName.Length;
|
|
|
|
Status = DeleteLinkReparsePoint( &UnicodeFileName,
|
|
NULL);
|
|
|
|
HeapFree(GetProcessHeap(), 0, lpExistingFileName);
|
|
|
|
return Status;
|
|
}
|
|
|