Leaked source code of windows server 2003
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

#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;
}