877 lines
24 KiB
C
877 lines
24 KiB
C
//+----------------------------------------------------------------------------
|
||
//
|
||
// Copyright (C) 1995, Microsoft Corporation
|
||
//
|
||
// File: dcfsctl.c
|
||
//
|
||
// Contents: This file has all the fsctrl routines that typically execute
|
||
// on a DC.
|
||
//
|
||
// Classes:
|
||
//
|
||
// Functions: DfsFsctrlDCSetVolumeState -
|
||
// DfsFsctrlDCSetVolumeState -
|
||
// DfsFsctrlSetServiceState -
|
||
// DfsFsctrlGetServerInfo -
|
||
// DfsFsctrlCheckStgIdInUse -
|
||
//
|
||
// DfspGetServerConfigInfo -
|
||
// IsPathAPrefixOf -
|
||
//
|
||
//
|
||
// History: April 5, 1995 Milans created
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
#include "dfsprocs.h"
|
||
#include <dfserr.h>
|
||
#include <netevent.h>
|
||
#include "fsctrl.h"
|
||
#include "log.h"
|
||
|
||
NTSTATUS
|
||
DfspGetServerConfigInfo(
|
||
IN GUID *pMachine,
|
||
IN PDFS_PKT pPkt,
|
||
IN PDFS_PKT_ENTRY pPktEntry,
|
||
OUT PDFS_LOCAL_VOLUME_CONFIG pConfigInfo);
|
||
|
||
BOOLEAN
|
||
IsPathAPrefixOf(
|
||
IN PUNICODE_STRING pustrPath1,
|
||
IN PUNICODE_STRING pustrPath2);
|
||
|
||
#pragma alloc_text( PAGE, DfsFsctrlDCSetVolumeState )
|
||
#pragma alloc_text( PAGE, DfsFsctrlSetVolumeTimeout )
|
||
#pragma alloc_text( PAGE, DfsFsctrlSetServiceState )
|
||
#pragma alloc_text( PAGE, DfsFsctrlGetServerInfo )
|
||
#pragma alloc_text( PAGE, DfsFsctrlCheckStgIdInUse )
|
||
|
||
#pragma alloc_text( PAGE, DfspGetServerConfigInfo )
|
||
#pragma alloc_text( PAGE, IsPathAPrefixOf )
|
||
|
||
#define Dbg (DEBUG_TRACE_LOCALVOL)
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFsctrlDCSetVolumeState, public
|
||
//
|
||
// Synopsis: Marks the specified replica offline for the particular volume
|
||
//
|
||
// Arguments: [Irp]
|
||
//
|
||
// [InputBuffer] -- Marshalled DFS_SETSTATE_ARG structure
|
||
// that specifies the volume and the state to set it to.
|
||
//
|
||
// [InputBufferLength] -- Length in bytes of InputBuffer
|
||
//
|
||
// Returns: [STATUS_SUCCESS] -- The specified replica was set
|
||
// online/offline as speficied.
|
||
//
|
||
// [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not
|
||
// found.
|
||
//
|
||
// [STATUS_DATA_ERROR] -- The InputBuffer could not be
|
||
// correctly unmarshalled.
|
||
//
|
||
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsFsctrlDCSetVolumeState(
|
||
IN PIRP Irp,
|
||
IN PVOID InputBuffer,
|
||
IN ULONG InputBufferLength)
|
||
{
|
||
NTSTATUS status;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
DFS_SETSTATE_ARG setStateArg;
|
||
PDFS_PKT pkt;
|
||
PDFS_PKT_ENTRY pktEntry;
|
||
|
||
STD_FSCTRL_PROLOGUE(DfsFsctrlDCSetVolumeState, TRUE, FALSE);
|
||
|
||
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
||
|
||
status = DfsRtlGet(
|
||
&marshalBuffer,
|
||
&MiSetStateArg,
|
||
&setStateArg);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
DebugTrace(
|
||
0, Dbg, "Setting volume state for %[wZ]\n",
|
||
&setStateArg.Id.Prefix);
|
||
|
||
pkt = _GetPkt();
|
||
|
||
PktAcquireShared( pkt, TRUE );
|
||
|
||
pktEntry = PktLookupEntryById( pkt, &setStateArg.Id );
|
||
|
||
if (pktEntry != NULL) {
|
||
|
||
if (setStateArg.Type == PKT_ENTRY_TYPE_OFFLINE) {
|
||
|
||
pktEntry->Type |= PKT_ENTRY_TYPE_OFFLINE;
|
||
|
||
} else {
|
||
|
||
pktEntry->Type &= ~PKT_ENTRY_TYPE_OFFLINE;
|
||
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
DebugTrace(0, Dbg, "Unable to find PKT Entry!\n", 0);
|
||
|
||
status = DFS_STATUS_NO_SUCH_ENTRY;
|
||
|
||
}
|
||
|
||
PktRelease( pkt );
|
||
|
||
PktEntryIdDestroy(&setStateArg.Id, FALSE);
|
||
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "DfsFsctrlDCSetVolumeState: Exit %08lx\n", ULongToPtr( status ));
|
||
|
||
DfsCompleteRequest( Irp, status );
|
||
|
||
return( status );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFsctrlSetServiceState, public
|
||
//
|
||
// Synopsis: Marks the specified replica offline for the particular volume
|
||
//
|
||
// Arguments: [Irp]
|
||
//
|
||
// [InputBuffer] -- Marshalled DFS_DC_SET_REPLICA_STATE structure
|
||
// that specifies the volume and the replica to be set
|
||
// offline/online.
|
||
//
|
||
// [InputBufferLength] -- Length in bytes of InputBuffer
|
||
//
|
||
// Returns: [STATUS_SUCCESS] -- The specified replica was set
|
||
// online/offline as speficied.
|
||
//
|
||
// [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not
|
||
// found, or the specified replica is not a server for
|
||
// the volume.
|
||
//
|
||
// [STATUS_DATA_ERROR] -- The InputBuffer could not be
|
||
// correctly unmarshalled.
|
||
//
|
||
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsFsctrlSetServiceState(
|
||
IN PIRP Irp,
|
||
IN PVOID InputBuffer,
|
||
IN ULONG InputBufferLength)
|
||
{
|
||
NTSTATUS status;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
DFS_DC_SET_SERVICE_STATE setSvcState;
|
||
PDFS_PKT pkt;
|
||
PDFS_PKT_ENTRY pktEntry;
|
||
|
||
STD_FSCTRL_PROLOGUE(DfsFsctrlSetServiceState, TRUE, FALSE);
|
||
|
||
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
||
|
||
status = DfsRtlGet(
|
||
&marshalBuffer,
|
||
&MiDCSetServiceState,
|
||
&setSvcState);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
DebugTrace(
|
||
0, Dbg, "Setting service state for [%wZ]\n",
|
||
&setSvcState.Id.Prefix);
|
||
|
||
DebugTrace(
|
||
0, Dbg, "For Service [%wZ]\n", &setSvcState.ServiceName);
|
||
|
||
pkt = _GetPkt();
|
||
|
||
PktAcquireShared( pkt, TRUE );
|
||
|
||
pktEntry = PktLookupEntryById( pkt, &setSvcState.Id );
|
||
|
||
if (pktEntry != NULL) {
|
||
|
||
PDFS_SERVICE pSvc;
|
||
ULONG i, cSvc;
|
||
|
||
status = DFS_STATUS_NO_SUCH_ENTRY;
|
||
|
||
for (i = 0, cSvc = pktEntry->Info.ServiceCount;
|
||
i < cSvc && status != STATUS_SUCCESS;
|
||
i++) {
|
||
|
||
pSvc = &pktEntry->Info.ServiceList[i];
|
||
|
||
if (RtlEqualUnicodeString(
|
||
&setSvcState.ServiceName, &pSvc->Name, TRUE)) {
|
||
|
||
DebugTrace(0, Dbg, "Found Svc @ %08lx\n", pSvc );
|
||
|
||
if (setSvcState.State == DFS_SERVICE_TYPE_OFFLINE) {
|
||
|
||
pSvc->Type |= DFS_SERVICE_TYPE_OFFLINE;
|
||
|
||
} else {
|
||
|
||
pSvc->Type &= ~DFS_SERVICE_TYPE_OFFLINE;
|
||
|
||
}
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
} // For each service
|
||
|
||
} else {
|
||
|
||
DebugTrace(0, Dbg, "Unable to find PKT Entry!\n", 0);
|
||
|
||
status = DFS_STATUS_NO_SUCH_ENTRY;
|
||
|
||
}
|
||
|
||
PktRelease( pkt );
|
||
|
||
//
|
||
// Free up the unmarshalled arguments
|
||
//
|
||
|
||
PktEntryIdDestroy(&setSvcState.Id, FALSE);
|
||
MarshalBufferFree( setSvcState.ServiceName.Buffer );
|
||
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "DfsFsctrlSetServiceState: Exit %08lx\n", ULongToPtr( status ));
|
||
|
||
DfsCompleteRequest( Irp, status );
|
||
|
||
return( status );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFsctrlSetVolumeTimeout, public
|
||
//
|
||
// Synopsis: Sets the specified volume's referral timeout
|
||
//
|
||
// Arguments: [Irp]
|
||
//
|
||
// [InputBuffer] -- Marshalled DFS_SET_VOLUME_TIMEOUT_ARG structure
|
||
// that specifies the volume and the timeout to associate
|
||
// with the volume.
|
||
//
|
||
// [InputBufferLength] -- Length in bytes of InputBuffer
|
||
//
|
||
// Returns: [STATUS_SUCCESS] -- The specified timeout was set.
|
||
//
|
||
// [DFS_STATUS_NO_SUCH_ENTRY] -- The specified volume was not
|
||
// found.
|
||
//
|
||
// [STATUS_DATA_ERROR] -- The InputBuffer could not be
|
||
// correctly unmarshalled.
|
||
//
|
||
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory situation.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsFsctrlSetVolumeTimeout(
|
||
IN PIRP Irp,
|
||
IN PVOID InputBuffer,
|
||
IN ULONG InputBufferLength)
|
||
{
|
||
NTSTATUS status;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
DFS_SET_VOLUME_TIMEOUT_ARG setVolTimeoutArg;
|
||
PDFS_PKT pkt;
|
||
PDFS_PKT_ENTRY pktEntry;
|
||
|
||
STD_FSCTRL_PROLOGUE(DfsFsctrlSetVolumeTimeout, TRUE, FALSE);
|
||
|
||
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
||
|
||
status = DfsRtlGet(
|
||
&marshalBuffer,
|
||
&MiSetVolTimeoutArg,
|
||
&setVolTimeoutArg);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
DebugTrace(
|
||
0, Dbg, "Setting volume timeout for %[wZ]\n",
|
||
&setVolTimeoutArg.Id.Prefix);
|
||
|
||
pkt = _GetPkt();
|
||
|
||
PktAcquireShared( pkt, TRUE );
|
||
|
||
pktEntry = PktLookupEntryById( pkt, &setVolTimeoutArg.Id );
|
||
|
||
if (pktEntry != NULL) {
|
||
|
||
pktEntry->Info.Timeout = setVolTimeoutArg.Timeout;
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
DebugTrace(0, Dbg, "Unable to find PKT Entry!\n", 0);
|
||
|
||
status = DFS_STATUS_NO_SUCH_ENTRY;
|
||
|
||
}
|
||
|
||
PktRelease( pkt );
|
||
|
||
//
|
||
// Free the unmarshalled input arguments
|
||
//
|
||
|
||
PktEntryIdDestroy(&setVolTimeoutArg.Id, FALSE);
|
||
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "DfsFsctrlSetVolumeTimeout: Exit %08lx\n", ULongToPtr( status ));
|
||
|
||
DfsCompleteRequest( Irp, status );
|
||
|
||
return( status );
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFsctrlGetServerInfo
|
||
//
|
||
// Synopsis: Given the machine guid of a server, this routine will return
|
||
// the entire local volume knowledge that a dfs server should
|
||
// have. This routine is intended to be called on the DC only.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Returns: [STATUS_SUCCESS] -- The info is successfully returned.
|
||
//
|
||
// [STATUS_BUFFER_OVERFLOW] -- The output buffer is too small.
|
||
// The needed size is returned in the first 4 bytes of
|
||
// this buffer.
|
||
//
|
||
// [STATUS_DATA_ERROR] -- The input buffer could not be
|
||
// unmarshalled
|
||
//
|
||
// [STATUS_BUFFER_TOO_SMALL] -- The output buffer is < 4 bytes.
|
||
//
|
||
// [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsFsctrlGetServerInfo(
|
||
IN PIRP Irp,
|
||
IN PVOID InputBuffer,
|
||
IN ULONG InputBufferLength,
|
||
IN PVOID OutputBuffer,
|
||
IN ULONG OutputBufferLength)
|
||
{
|
||
NTSTATUS Status, MarshalStatus;
|
||
PDFS_PKT pPkt;
|
||
PDFS_PKT_ENTRY pPktEntry;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
DFS_PKT_ENTRY_ID EntryId;
|
||
DFS_LOCAL_VOLUME_CONFIG ConfigInfo;
|
||
ULONG i, cInfo, cbBuffer;
|
||
|
||
STD_FSCTRL_PROLOGUE(DfsFsctrlGetServerInfo, TRUE, FALSE);
|
||
|
||
pPkt = _GetPkt();
|
||
|
||
//
|
||
// Get the input arguments
|
||
//
|
||
|
||
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
||
|
||
Status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &EntryId );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
DebugTrace(0, Dbg,
|
||
"Getting Server Info for server [%wZ]\n", &EntryId.Prefix);
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
OutputBufferLength,
|
||
OutputBuffer );
|
||
|
||
//
|
||
// We'll marshal in a count of 0 at the beginning of the output
|
||
// buffer. Later, we'll revisit this and put in the actual count of
|
||
// relation info's.
|
||
//
|
||
|
||
cInfo = 0;
|
||
|
||
MarshalStatus = DfsRtlPutUlong( &marshalBuffer, &cInfo );
|
||
|
||
cbBuffer = sizeof(ULONG);
|
||
|
||
//
|
||
// For each Pkt entry, create and marshal a relation info if the
|
||
// Dfs volume is a local volume for the server.
|
||
//
|
||
|
||
PktAcquireShared( pPkt, TRUE );
|
||
|
||
pPktEntry =
|
||
CONTAINING_RECORD(pPkt->EntryList.Flink, DFS_PKT_ENTRY, Link);
|
||
|
||
for (i = 0; i < pPkt->EntryCount && NT_SUCCESS(Status); i++) {
|
||
|
||
Status = DfspGetServerConfigInfo(
|
||
&EntryId.Uid,
|
||
pPkt,
|
||
pPktEntry,
|
||
&ConfigInfo);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
DebugTrace(0, Dbg, "Found [%wZ]\n", &pPktEntry->Id.Prefix);
|
||
|
||
Status = DfsRtlSize( &MiLocalVolumeConfig, &ConfigInfo, &cbBuffer);
|
||
|
||
if (NT_SUCCESS(Status) && NT_SUCCESS(MarshalStatus)) {
|
||
|
||
MarshalStatus = DfsRtlPut(
|
||
&marshalBuffer,
|
||
&MiLocalVolumeConfig,
|
||
&ConfigInfo);
|
||
|
||
cInfo++;
|
||
|
||
}
|
||
|
||
LocalVolumeConfigInfoDestroy( &ConfigInfo, FALSE );
|
||
|
||
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||
|
||
//
|
||
// Means volume is not local to server - go on to the next
|
||
// Pkt Entry
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
} else if (Status == STATUS_OBJECT_TYPE_MISMATCH) {
|
||
|
||
//
|
||
// Means volume is a Machine, Domain, or Orgroot volume -
|
||
// we ignore it.
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
DebugTrace(0, Dbg,
|
||
"Error %08lx constructing relation info!\n", ULongToPtr( Status ));
|
||
|
||
}
|
||
|
||
pPktEntry =
|
||
CONTAINING_RECORD(pPktEntry->Link.Flink, DFS_PKT_ENTRY, Link);
|
||
|
||
} // End for each Pkt Entry
|
||
|
||
PktRelease( pPkt );
|
||
|
||
//
|
||
// Free the unmarshalled input arguments
|
||
//
|
||
|
||
PktEntryIdDestroy(&EntryId, FALSE);
|
||
|
||
} else {
|
||
|
||
DebugTrace( 0, Dbg, "Error %08lx unmarshalling input\n", ULongToPtr( Status ));
|
||
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
if (NT_SUCCESS(MarshalStatus)) {
|
||
|
||
//
|
||
// Everything went successfully - Marshal in the number of
|
||
// relation info's we are returning at the beginning of the
|
||
// output buffer
|
||
//
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
OutputBufferLength,
|
||
OutputBuffer);
|
||
|
||
Status = DfsRtlPutUlong( &marshalBuffer, &cInfo );
|
||
|
||
ASSERT( NT_SUCCESS(Status) );
|
||
|
||
ASSERT( cbBuffer <= OutputBufferLength );
|
||
|
||
Irp->IoStatus.Information = cbBuffer;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If we hit a marshalling error along the way, we'll try and
|
||
// tell the caller how much buffer we need
|
||
//
|
||
|
||
RETURN_BUFFER_SIZE( cbBuffer, Status );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
DfsCompleteRequest( Irp, Status );
|
||
|
||
DebugTrace(-1, Dbg, "DfsFsctrlGetServerInfo: returning %08lx\n", ULongToPtr( Status ));
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsFsctrlCheckStgIdInUse
|
||
//
|
||
// Synopsis: Given a storage id and the machine guid of a server, this
|
||
// routine will say whether the storage id can be legally shared
|
||
// by the server. This routine is intended to be called on the
|
||
// DC only.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Returns: [STATUS_SUCCESS] -- It is legal for the server to share the
|
||
// storage id.
|
||
//
|
||
// [STATUS_DEVICE_BUSY] -- Some parent or child of the
|
||
// storage id is already shared in Dfs. The shared
|
||
// volume is returned in OutputBuffer.
|
||
//
|
||
// [STATUS_BUFFER_OVERFLOW] -- OutputBuffer too small to return
|
||
// prefix of shared volume - the required size is
|
||
// returned in the first 4 bytes of OutputBuffer
|
||
//
|
||
// [STATUS_BUFFER_TOO_SMALL] -- OutputBuffer is < 4 bytes.
|
||
//
|
||
// [STATUS_DATA_ERROR] -- Unable to unmarshall the arguments.
|
||
//
|
||
// [STATUS_INSUFFICIENT_RESOURCES] -- Unable to unmarshall the
|
||
// arguments.
|
||
//
|
||
// Notes: The Input buffer is a marshalled PKT_ENTRY_ID, where the
|
||
// GUID is the server's machine id, and the Prefix is the
|
||
// storage id to be verified.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsFsctrlCheckStgIdInUse(
|
||
IN PIRP Irp,
|
||
IN PVOID InputBuffer,
|
||
IN ULONG InputBufferLength,
|
||
IN PVOID OutputBuffer,
|
||
IN ULONG OutputBufferLength)
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS; // Innocent till proven...
|
||
PDFS_PKT pPkt;
|
||
PDFS_PKT_ENTRY pPktEntry;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
DFS_PKT_ENTRY_ID EntryId;
|
||
ULONG i;
|
||
|
||
STD_FSCTRL_PROLOGUE(DfsFsctrlIsStgIdLegalOnServer, TRUE, FALSE);
|
||
|
||
MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
|
||
|
||
Status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &EntryId );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
DebugTrace(0, Dbg, "Verifying Storage Id [%wZ]\n", &EntryId.Prefix );
|
||
|
||
pPkt = _GetPkt();
|
||
|
||
pPktEntry =
|
||
CONTAINING_RECORD(pPkt->EntryList.Flink, DFS_PKT_ENTRY, Link);
|
||
|
||
for (i = 0; i < pPkt->EntryCount && NT_SUCCESS(Status); i++) {
|
||
|
||
//
|
||
// For every pkt entry, we iterate through all the services. If a
|
||
// service matches the input service, then we see if the storage
|
||
// id is a prefix or child of the service's storage id. If so,
|
||
// the storage id is not legal.
|
||
//
|
||
|
||
ULONG j;
|
||
|
||
for (j = 0;
|
||
j < pPktEntry->Info.ServiceCount && NT_SUCCESS(Status);
|
||
j++) {
|
||
|
||
PDFS_SERVICE pService = &pPktEntry->Info.ServiceList[j];
|
||
|
||
if ( GuidEqual( &pService->pMachEntry->pMachine->guidMachine,
|
||
&EntryId.Uid ) ) {
|
||
|
||
|
||
if (IsPathAPrefixOf(
|
||
&EntryId.Prefix,
|
||
&pService->StgId ) ||
|
||
IsPathAPrefixOf(
|
||
&pService->StgId,
|
||
&EntryId.Prefix )) {
|
||
|
||
DebugTrace(0, Dbg,
|
||
"Stg Id Not legal - Conflicts with [%wZ]\n",
|
||
&pPktEntry->Id.Prefix);
|
||
|
||
DebugTrace(0, Dbg,
|
||
"Storage Id for share is [%wZ]\n",
|
||
&pService->StgId);
|
||
|
||
Status = STATUS_DEVICE_BUSY;
|
||
|
||
}
|
||
|
||
//
|
||
// We found a matching service, no need to look at the
|
||
// rest of the services
|
||
//
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
pPktEntry =
|
||
CONTAINING_RECORD(pPktEntry->Link.Flink, DFS_PKT_ENTRY, Link);
|
||
|
||
}
|
||
|
||
//
|
||
// Free the unmarshalled input arguments
|
||
//
|
||
|
||
PktEntryIdDestroy(&EntryId, FALSE);
|
||
|
||
} else {
|
||
|
||
DebugTrace( 0, Dbg, "Unmarshalling Error - %08lx\n", ULongToPtr( Status ));
|
||
|
||
}
|
||
|
||
DfsCompleteRequest( Irp, Status );
|
||
|
||
DebugTrace(-1, Dbg,
|
||
"DfsFsctrlIsStgIdLegalOnServer - returning %08lx\n", ULongToPtr( Status ));
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfspGetServerConfigInfo
|
||
//
|
||
// Synopsis: Given a machine guid and a pkt entry, this routine will
|
||
// return the relation info for the entry if the machine is a
|
||
// server for the entry.
|
||
//
|
||
// Arguments: [pMachine] -- Pointer to machine guid
|
||
// [pPkt] -- The pkt to examine
|
||
// [pPktEntry] -- The pkt entry to examine
|
||
// [pConfigInfo] -- If the machine is a server for this entry, a
|
||
// relation info is returned here.
|
||
//
|
||
// Returns: [STATUS_SUCCESS] -- Machine is a server, and relation info
|
||
// constructed successfully
|
||
//
|
||
// [STATUS_OBJECT_NAME_NOT_FOUND] -- Machine is not a server for
|
||
// the given pkt entry
|
||
//
|
||
// [STATUS_OBJECT_TYPE_MISMATCH] -- pPktEntry is for a machine,
|
||
// domain, or orgroot volume. Can't get config info for
|
||
// these volumes.
|
||
//
|
||
// [STATUS_INSUFFICIENT_RESOURCES] -- Machine is a server, but
|
||
// out of memory constructing relation info
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfspGetServerConfigInfo(
|
||
IN GUID *pMachine,
|
||
IN PDFS_PKT pPkt,
|
||
IN PDFS_PKT_ENTRY pPktEntry,
|
||
OUT PDFS_LOCAL_VOLUME_CONFIG pConfigInfo)
|
||
{
|
||
ULONG j;
|
||
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||
|
||
//
|
||
// We can't get a config info for a machine volume.
|
||
//
|
||
|
||
if ( ((pPktEntry->Type & PKT_ENTRY_TYPE_MACHINE) != 0) ||
|
||
(pPktEntry == pPkt->DomainPktEntry) ||
|
||
(pPktEntry->Id.Prefix.Length == sizeof(WCHAR))) {
|
||
|
||
return( STATUS_OBJECT_TYPE_MISMATCH );
|
||
|
||
}
|
||
|
||
for (j = 0; j < pPktEntry->Info.ServiceCount; j++) {
|
||
|
||
PDFS_SERVICE pService = &pPktEntry->Info.ServiceList[j];
|
||
|
||
if ( GuidEqual(
|
||
&pService->pMachEntry->pMachine->guidMachine,
|
||
pMachine ) ) {
|
||
|
||
Status = PktRelationInfoConstruct(
|
||
&pConfigInfo->RelationInfo,
|
||
pPkt,
|
||
&pPktEntry->Id);
|
||
|
||
ASSERT( Status != DFS_STATUS_NO_SUCH_ENTRY );
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
ASSERT( pService->StgId.Length != 0 );
|
||
|
||
pConfigInfo->StgId.Length = 0;
|
||
pConfigInfo->StgId.MaximumLength =
|
||
pService->StgId.MaximumLength;
|
||
pConfigInfo->StgId.Buffer = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
pService->StgId.Length,
|
||
' sfD');
|
||
|
||
if (pConfigInfo->StgId.Buffer != NULL) {
|
||
|
||
RtlCopyUnicodeString(
|
||
&pConfigInfo->StgId,
|
||
&pService->StgId);
|
||
|
||
} else {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
ASSERT( pPktEntry->Type & PKT_ENTRY_TYPE_CAIRO );
|
||
|
||
//
|
||
// Send only the PKT_ENTRY_TYPE_CAIRO bit.
|
||
//
|
||
|
||
pConfigInfo->EntryType = PKT_ENTRY_TYPE_CAIRO;
|
||
|
||
//
|
||
// Send only the service online/offline bit
|
||
//
|
||
|
||
pConfigInfo->ServiceType = pService->Type &
|
||
DFS_SERVICE_TYPE_OFFLINE;
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return( Status );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: IsPathAPrefixOf
|
||
//
|
||
// Synopsis: Given two paths, this will return TRUE if the first path is
|
||
// a prefix of the second.
|
||
//
|
||
// Arguments: [pustrPath1] -- The two paths
|
||
// [pustrPath2]
|
||
//
|
||
// Returns: TRUE if pustrPath1 is a prefix of pustrPath2, FALSE otherwise
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
BOOLEAN
|
||
IsPathAPrefixOf(
|
||
IN PUNICODE_STRING pustrPath1,
|
||
IN PUNICODE_STRING pustrPath2)
|
||
{
|
||
BOOLEAN fResult;
|
||
|
||
fResult = RtlPrefixUnicodeString( pustrPath1, pustrPath2, FALSE );
|
||
|
||
if (fResult) {
|
||
|
||
//
|
||
// Path1 is a prefix of Path2. However, this is not a sufficient test.
|
||
// We have to catch cases like d:\test1 being a prefix of d:\test10
|
||
//
|
||
|
||
fResult =
|
||
(pustrPath2->Length == pustrPath1->Length)
|
||
||
|
||
(pustrPath2->Buffer[ pustrPath1->Length / sizeof(WCHAR) ] ==
|
||
UNICODE_PATH_SEP);
|
||
|
||
}
|
||
|
||
return( fResult );
|
||
|
||
}
|
||
|
||
|