549 lines
15 KiB
C
549 lines
15 KiB
C
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Copyright (C) 1992, Microsoft Corporation.
|
|||
|
//
|
|||
|
// File: testsup.c
|
|||
|
//
|
|||
|
// Contents: This file contains functions which are purportedly
|
|||
|
// useful for testing the DsFs driver.
|
|||
|
//
|
|||
|
// Functions: DsfsCleanup -- Cleanup opened files, etc.
|
|||
|
// DsfsDefineLogicalRoot -- Define a logical root to the FSD
|
|||
|
// DsfsDefineProvider -- Define a DFS provider
|
|||
|
// DsfsAddPrefix - Add an entry path to the FSD's prefix table
|
|||
|
// DsfsDelPrefix - Delete a prefix table entry in the FSD
|
|||
|
// DsfsUpdReferralList - update the referral list of a prefix entry
|
|||
|
// DsfsReadStruct - Return dsfs data structures.
|
|||
|
// DfsCreateSymbolicLink - create a symbolic link for logical root
|
|||
|
//
|
|||
|
// History: 04 Feb 1992 alanw Created.
|
|||
|
// 30 May 1992 alanw Added DfsCreateSymbolicLink
|
|||
|
//
|
|||
|
// Notes: These functions are not necessarily multi-thread safe.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
#include "nt.h"
|
|||
|
#include "ntrtl.h"
|
|||
|
#include "nturtl.h"
|
|||
|
#include "wchar.h"
|
|||
|
|
|||
|
#include "dsfsctl.h"
|
|||
|
#include "testsup.h"
|
|||
|
#include "dfsstr.h"
|
|||
|
|
|||
|
#define MAX_ENTRY_PATH 80 // max. length of an entry path
|
|||
|
#define LOG_ROOT_LENGTH 16 // max. length of a logical root name
|
|||
|
|
|||
|
#define LMRDR L"\\Device\\LanmanRedirector\\"
|
|||
|
|
|||
|
extern PWSTR gpwszServer;
|
|||
|
HANDLE DsfsFile = NULL;
|
|||
|
PWSTR DsfsDeviceName = L"\\Dfs";
|
|||
|
PWSTR DsfsLogicalRootName = L"\\Device\\WinDFS";
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// from PKT.H
|
|||
|
//
|
|||
|
|
|||
|
#define DFS_SERVICE_TYPE_LOCAL (0x0004)
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DsfsOpenDevice, local
|
|||
|
//
|
|||
|
// Synopsis: Conditionally open the Dsfs file system device object.
|
|||
|
//
|
|||
|
// Arguments: -none-
|
|||
|
//
|
|||
|
// Returns: NTSTATUS - STATUS_SUCCESS if the device was opened
|
|||
|
// successfully.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DsfsOpenDevice(
|
|||
|
void
|
|||
|
) {
|
|||
|
NTSTATUS Stat;
|
|||
|
|
|||
|
OBJECT_ATTRIBUTES ObjAttrs;
|
|||
|
UNICODE_STRING DsfsName;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
|
|||
|
if (DsfsFile == NULL) {
|
|||
|
WCHAR wszServer[sizeof(LMRDR) / sizeof(WCHAR) +
|
|||
|
16 + // max NetBIOS machine name length
|
|||
|
sizeof(ROOT_SHARE_NAME) / sizeof(WCHAR) +
|
|||
|
1];
|
|||
|
if(gpwszServer != NULL) {
|
|||
|
swprintf(wszServer,
|
|||
|
L"%ws%ws%ws",
|
|||
|
LMRDR,
|
|||
|
gpwszServer,
|
|||
|
ROOT_SHARE_NAME);
|
|||
|
RtlInitUnicodeString( &DsfsName, wszServer );
|
|||
|
}
|
|||
|
else {
|
|||
|
RtlInitUnicodeString( &DsfsName, DsfsDeviceName );
|
|||
|
}
|
|||
|
|
|||
|
InitializeObjectAttributes( &ObjAttrs, &DsfsName,
|
|||
|
OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|||
|
|
|||
|
Stat = NtCreateFile(
|
|||
|
&DsfsFile,
|
|||
|
FILE_READ_DATA | SYNCHRONIZE,
|
|||
|
&ObjAttrs,
|
|||
|
&IoStatus,
|
|||
|
NULL,
|
|||
|
FILE_ATTRIBUTE_NORMAL,
|
|||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|||
|
FILE_OPEN_IF,
|
|||
|
FILE_CREATE_TREE_CONNECTION |
|
|||
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
|
|||
|
if ( NT_SUCCESS(Stat) )
|
|||
|
Stat = IoStatus.Status;
|
|||
|
|
|||
|
return Stat;
|
|||
|
}
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DsfsDoFsctl, local
|
|||
|
//
|
|||
|
// Synopsis: Issues an NtFsControlFile call to the Dsfs file system
|
|||
|
// driver. This is a helper routine that just assures that
|
|||
|
// the device is opened, and supplies some conventional
|
|||
|
// parameters.
|
|||
|
//
|
|||
|
// Arguments: [FsControlCode] -- The file system control code to be used
|
|||
|
// [InputBuffer] -- The fsctl input buffer
|
|||
|
// [InputBufferLength]
|
|||
|
// [OutputBuffer] -- The fsctl output buffer
|
|||
|
// [OutputBufferLength]
|
|||
|
//
|
|||
|
// Returns: NTSTATUS - the status of the open or fsctl operation.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DsfsDoFsctl(
|
|||
|
IN ULONG FsControlCode,
|
|||
|
IN PVOID InputBuffer OPTIONAL,
|
|||
|
IN ULONG InputBufferLength,
|
|||
|
OUT PVOID OutputBuffer OPTIONAL,
|
|||
|
IN ULONG OutputBufferLength
|
|||
|
) {
|
|||
|
NTSTATUS Stat;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
|
|||
|
Stat = DsfsOpenDevice();
|
|||
|
if (! NT_SUCCESS(Stat))
|
|||
|
return Stat;
|
|||
|
|
|||
|
Stat = NtFsControlFile(
|
|||
|
DsfsFile,
|
|||
|
NULL, // Event,
|
|||
|
NULL, // ApcRoutine,
|
|||
|
NULL, // ApcContext,
|
|||
|
&IoStatus,
|
|||
|
FsControlCode,
|
|||
|
InputBuffer,
|
|||
|
InputBufferLength,
|
|||
|
OutputBuffer,
|
|||
|
OutputBufferLength );
|
|||
|
|
|||
|
if ( NT_SUCCESS(Stat) ) {
|
|||
|
Stat = IoStatus.Status;
|
|||
|
}
|
|||
|
return Stat;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DsfsCleanup, public
|
|||
|
//
|
|||
|
// Synopsis: DsfsCleanup will release any resources held by the
|
|||
|
// module (the open file handle to the Dsfs device).
|
|||
|
//
|
|||
|
// Arguments: -none-
|
|||
|
//
|
|||
|
// Returns: -none-
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
VOID
|
|||
|
DsfsCleanup(
|
|||
|
void
|
|||
|
) {
|
|||
|
if (DsfsFile == NULL) {
|
|||
|
(VOID) NtClose(DsfsFile);
|
|||
|
DsfsFile = NULL;
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DsfsDefineLogicalRoot, public
|
|||
|
//
|
|||
|
// Synopsis: This routine will issue the Define Logical Root fsctl
|
|||
|
// to the Dsfs file system driver. If successful, this
|
|||
|
// will create a new DS logical root.
|
|||
|
//
|
|||
|
// Effects: A new DS logical root is created in the DSFS driver.
|
|||
|
// It may also be necessary to create a symbolic link to
|
|||
|
// \DosDevices and inform the Cairo OSM to complete the
|
|||
|
// operation.
|
|||
|
//
|
|||
|
// Arguments: [LogicalRoot] -- the name of the logical root to be
|
|||
|
// created
|
|||
|
//
|
|||
|
// Returns: NTSTATUS - the status of the operation.
|
|||
|
//
|
|||
|
// Notes: Generally, only one DS logical root will exist (org).
|
|||
|
// Others, such as domain and udomain will be symbolic links
|
|||
|
// to somewhere within org.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DsfsDefineLogicalRoot(
|
|||
|
IN PWSTR LogicalRoot
|
|||
|
) {
|
|||
|
NTSTATUS Stat;
|
|||
|
WCHAR Buffer[ LOG_ROOT_LENGTH + MAX_ENTRY_PATH ];
|
|||
|
PFILE_DFS_DEF_ROOT_BUFFER pDlrBuf =
|
|||
|
(PFILE_DFS_DEF_ROOT_BUFFER) &Buffer[0];
|
|||
|
int i;
|
|||
|
|
|||
|
for (i=0; i<15; i++) {
|
|||
|
pDlrBuf->LogicalRoot[i] = *LogicalRoot++;
|
|||
|
if (pDlrBuf->LogicalRoot[i] == (WCHAR) ':')
|
|||
|
break;
|
|||
|
if (pDlrBuf->LogicalRoot[i] == UNICODE_NULL)
|
|||
|
break;
|
|||
|
}
|
|||
|
pDlrBuf->LogicalRoot[i] = UNICODE_NULL;
|
|||
|
|
|||
|
// if (ARGUMENT_PRESENT(EntryPath)) {
|
|||
|
// for (i=0; i<MAX_ENTRY_PATH; i++) {
|
|||
|
// pDlrBuf->PrefixName[i] = *LogicalRoot++;
|
|||
|
// if (pDlrBuf->PrefixName[i] == (WCHAR) '/')
|
|||
|
// pDlrBuf->PrefixName[i] = (WCHAR) '\\';
|
|||
|
// if (pDlrBuf->PrefixName[i] == UNICODE_NULL)
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// if (i >= MAX_ENTRY_PATH) {
|
|||
|
// return STATUS_BUFFER_TOO_SMALL;
|
|||
|
// }
|
|||
|
// }
|
|||
|
|
|||
|
Stat = DsfsDoFsctl(
|
|||
|
FSCTL_DFS_DEFINE_LOGICAL_ROOT,
|
|||
|
(PVOID)pDlrBuf,
|
|||
|
sizeof *pDlrBuf,
|
|||
|
NULL,
|
|||
|
0);
|
|||
|
return Stat;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DsfsReadStruct, public
|
|||
|
//
|
|||
|
// Synopsis: A dsfs data structure is returned
|
|||
|
//
|
|||
|
// Arguments: [pRsParam] -- The Fsctl buffer which describes the
|
|||
|
// data structure to be returned.
|
|||
|
// [pucData] -- Pointer to a buffer where the data will
|
|||
|
// be returned.
|
|||
|
//
|
|||
|
// Returns: NTSTATUS - the status of the operation.
|
|||
|
//
|
|||
|
// Notes: This call will be effective on a debug build of the
|
|||
|
// dsfs driver only.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DsfsReadStruct(
|
|||
|
PFILE_DFS_READ_STRUCT_PARAM pRsParam,
|
|||
|
PUCHAR pucData
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Stat;
|
|||
|
|
|||
|
Stat = DsfsDoFsctl(
|
|||
|
FSCTL_DFS_INTERNAL_READSTRUCT,
|
|||
|
(PVOID)pRsParam,
|
|||
|
sizeof *pRsParam,
|
|||
|
(PVOID)pucData,
|
|||
|
(ULONG)pRsParam->ByteCount);
|
|||
|
|
|||
|
|
|||
|
return Stat;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsCreateSymbolicLink, public
|
|||
|
//
|
|||
|
// Synopsis: This function creates a symbolic link object for the specified
|
|||
|
// local device name which is linked to the logical root device
|
|||
|
// name that has a form of \Device\WinDFS\logicalrootname
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
// [Local] -- Supplies the local device name.
|
|||
|
// [DestStr] -- Supplies the string which is the link target of
|
|||
|
// the symbolic link object, if other than the local
|
|||
|
// name itself.
|
|||
|
//
|
|||
|
// Returns: NTSTATUS - STATUS_Success or reason for failure.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
DfsCreateSymbolicLink(
|
|||
|
IN PWSTR Local,
|
|||
|
IN PWSTR DestStr OPTIONAL
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
HANDLE SymbolicLink;
|
|||
|
UNICODE_STRING LinkStringU;
|
|||
|
UNICODE_STRING DestStringU;
|
|||
|
OBJECT_ATTRIBUTES LinkAttributes;
|
|||
|
|
|||
|
WCHAR LocalName[LOG_ROOT_LENGTH + 1];
|
|||
|
|
|||
|
WCHAR ExistLinkBuffer[MAXIMUM_FILENAME_LENGTH];
|
|||
|
UNICODE_STRING ExistLink;
|
|||
|
|
|||
|
ExistLink.MaximumLength = sizeof( ExistLinkBuffer );
|
|||
|
ExistLink.Buffer = ExistLinkBuffer;
|
|||
|
ExistLink.Length = 0;
|
|||
|
|
|||
|
|
|||
|
LinkStringU.Buffer = NULL;
|
|||
|
DestStringU.Buffer = NULL;
|
|||
|
|
|||
|
wcscpy(LocalName, Local);
|
|||
|
_wcsupr(LocalName);
|
|||
|
|
|||
|
//
|
|||
|
// Since the logical root name is like a disk device, we want to
|
|||
|
// make its name refer to the root directory before calling
|
|||
|
// RtlDosNameToNtPathName to convert to NT-style path name.
|
|||
|
//
|
|||
|
wcscat(LocalName, L"\\");
|
|||
|
|
|||
|
//
|
|||
|
// We expect this routine to generate an NT-style path name that is unique
|
|||
|
// per logon user using the Logon Id, so we have to be impersonating the
|
|||
|
// user at this point.
|
|||
|
//
|
|||
|
if (! RtlDosPathNameToNtPathName_U(LocalName, &LinkStringU, NULL, NULL)) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove the trailing slash character in order to create a symbolic
|
|||
|
// link of X: rather than X:/
|
|||
|
//
|
|||
|
LinkStringU.Length -= sizeof(WCHAR);
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(DestStr)) {
|
|||
|
if (! RtlDosPathNameToNtPathName_U(DestStr, &DestStringU, NULL, NULL)) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto FreeStrings;
|
|||
|
}
|
|||
|
RtlFreeUnicodeString(&DestStringU);
|
|||
|
|
|||
|
if (! DfsCreateLogicalRootName (DestStr, &DestStringU)) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto FreeStrings;
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (! DfsCreateLogicalRootName (Local, &DestStringU)) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto FreeStrings;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// About to create a new symbolic link object.
|
|||
|
//
|
|||
|
InitializeObjectAttributes(
|
|||
|
&LinkAttributes,
|
|||
|
&LinkStringU,
|
|||
|
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if there's already an existing symbolic link.
|
|||
|
//
|
|||
|
|
|||
|
if ((status = NtOpenSymbolicLinkObject(
|
|||
|
&SymbolicLink,
|
|||
|
DELETE | GENERIC_READ,
|
|||
|
&LinkAttributes
|
|||
|
)) == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|||
|
//
|
|||
|
// Logical root name has no link target. Go ahead and
|
|||
|
// create the new one.
|
|||
|
//
|
|||
|
goto CreateLink;
|
|||
|
}
|
|||
|
else if (! NT_SUCCESS(status)) {
|
|||
|
goto FreeStrings;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find out if the device specified is already
|
|||
|
// redirected
|
|||
|
//
|
|||
|
if (! NT_SUCCESS(NtQuerySymbolicLinkObject(
|
|||
|
SymbolicLink,
|
|||
|
&ExistLink,
|
|||
|
NULL
|
|||
|
))) {
|
|||
|
goto CloseSymbolicHandle;
|
|||
|
}
|
|||
|
|
|||
|
if (RtlPrefixString( (PSTRING) &DsfsLogicalRootName,
|
|||
|
(PSTRING) &ExistLink,
|
|||
|
TRUE) == FALSE) {
|
|||
|
//
|
|||
|
// Device is already redirected to something else
|
|||
|
//
|
|||
|
status = STATUS_DEVICE_ALREADY_ATTACHED;
|
|||
|
goto CloseSymbolicHandle;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Device is a DFS symbolic link, let's delete it so that we can create
|
|||
|
// a new symbolic link to the DFS logical root.
|
|||
|
//
|
|||
|
if (! NT_SUCCESS(NtMakeTemporaryObject(
|
|||
|
SymbolicLink
|
|||
|
))) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
CloseSymbolicHandle:
|
|||
|
NtClose(SymbolicLink);
|
|||
|
|
|||
|
if (! NT_SUCCESS(status)) {
|
|||
|
goto FreeStrings;
|
|||
|
}
|
|||
|
|
|||
|
CreateLink:
|
|||
|
//
|
|||
|
// Create a symbolic link object to the device we are redirecting only
|
|||
|
// if one does not already exist; or if one existed, it was deleted
|
|||
|
// successfully.
|
|||
|
//
|
|||
|
status = NtCreateSymbolicLinkObject(
|
|||
|
&SymbolicLink,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
&LinkAttributes,
|
|||
|
&DestStringU
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
NtClose(SymbolicLink);
|
|||
|
}
|
|||
|
|
|||
|
FreeStrings:
|
|||
|
if (DestStringU.Buffer != NULL)
|
|||
|
RtlFreeUnicodeString(&DestStringU);
|
|||
|
|
|||
|
//
|
|||
|
// Free memory allocated by RtlDosPathNameToNtPathName
|
|||
|
//
|
|||
|
if (LinkStringU.Buffer != NULL)
|
|||
|
RtlFreeUnicodeString(&LinkStringU);
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//+-------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Function: DfsCreateLogicalRootName, private
|
|||
|
//
|
|||
|
// Synopsis: An input logical root style name is converted to be
|
|||
|
// an absolute name referring to the NT DFS logical
|
|||
|
// root device directory.
|
|||
|
//
|
|||
|
// Arguments: [Name] -- The input logical root based path name.
|
|||
|
// [Dest] -- Pointer to a string in which the translated
|
|||
|
// name will be returned.
|
|||
|
//
|
|||
|
// Returns: BOOLEAN - FALSE if the operation failed.
|
|||
|
//
|
|||
|
// Notes: The buffer for the string is allocated and should be
|
|||
|
// freed by the caller.
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
DfsCreateLogicalRootName (
|
|||
|
PWSTR Name,
|
|||
|
PUNICODE_STRING Dest
|
|||
|
)
|
|||
|
{
|
|||
|
PWSTR Buf = NULL;
|
|||
|
PWSTR Src;
|
|||
|
int FoundColon = 0;
|
|||
|
|
|||
|
Dest->MaximumLength = (wcslen(Name) + wcslen(DsfsLogicalRootName) + 2 ) * sizeof (WCHAR);
|
|||
|
Buf = RtlAllocateHeap( RtlProcessHeap(), 0, Dest->MaximumLength);
|
|||
|
if (Buf == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Dest->Buffer = Buf;
|
|||
|
|
|||
|
for (Src = DsfsLogicalRootName; *Buf++ = *Src++; )
|
|||
|
;
|
|||
|
Buf[-1] = (WCHAR) '\\';
|
|||
|
|
|||
|
for (Src = Name; *Buf = *Src++; Buf++)
|
|||
|
if (*Buf == (WCHAR) ':' && !FoundColon) {
|
|||
|
Buf--;
|
|||
|
FoundColon++;
|
|||
|
}
|
|||
|
if (Buf[-1] == (WCHAR) '\\')
|
|||
|
Buf--;
|
|||
|
|
|||
|
Dest->Length = (PCHAR)Buf - (PCHAR)Dest->Buffer;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|