2025-04-27 07:49:33 -04:00

1017 lines
31 KiB
C++

//+----------------------------------------------------------------------------
//
// Copyright (C) 2000, Microsoft Corporation
//
// File: DfsApiFrontEnd.cxx
//
// Contents: Contains the support routines for the administering DFS
// The DFS api server implementation uses this.
// Also, any other admin tool that does not use the API
// can use the facilities provided here to administer DFS.
//
// Classes: none.
//
// History: Feb. 8 2000, Author: udayh
//
//-----------------------------------------------------------------------------
#include "DfsRootFolder.hxx"
#include "DfsReferral.hxx"
#include "lm.h"
#include "lmdfs.h"
#include "DfsRegistryStore.hxx"
#include "DfsADBlobStore.hxx"
#include "DfsInit.hxx"
#include "netdfs.h"
#include "DomainControllerSupport.hxx"
//
// logging specific includes
//
#include "DfsApiFrontEnd.tmh"
//
//dfsdev: validate input arguments.
//
#define API_VALIDATE_ARGUMENTS(_a, _b, _c, _d) ((_d) = ERROR_SUCCESS)
//+----------------------------------------------------------------------------
//
// Function: DfsAdd
//
// Arguments: DfsPathName - the pathname that is being added or updated
// ServerName - Name of server being added as target
// ShareName - Name of share on ServerName backing the link
// Comment - Comment associated if this is a new link
// Flags - If DFS_ADD_VOLUME, fail this request if link exists
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsAdd(
LPWSTR DfsPathName,
LPWSTR ServerName,
LPWSTR ShareName,
LPWSTR Comment,
DWORD Flags )
{
DFSSTATUS Status;
UNICODE_STRING DfsPath, LinkName;
DfsRootFolder *pRoot;
DFS_TRACE_NORM(API, "DfsAdd for path %ws, Server %ws Share %ws\n",
DfsPathName, ServerName, ShareName);
RtlInitUnicodeString( &DfsPath, DfsPathName );
API_VALIDATE_ARGUMENTS( DfsPathName, ServerName, ShareName, Status);
if (Status != ERROR_SUCCESS)
{
goto done;
}
//
// Get a root folder for the passed in path name.
//
Status = DfsGetRootFolder( &DfsPath,
&LinkName,
&pRoot );
if (Status == ERROR_SUCCESS)
{
//
// Let the root folder know that a new api request is coming in
// This will give it a chance to let us know if api requests
// are allowed, and to synchronize with the metadata as necessary.
//
Status = pRoot->RootApiRequestPrologue( TRUE );
//
// If we got a root folder, see if there is a link that matches
// the rest of the name beyond the root.
//
if (Status == ERROR_SUCCESS) {
//
// Check if this is a valid link name. A valid link is one that
// either is a perfect match of the LinkName, or the LinkName
// does not encompass as existing link.
//
Status = pRoot->ValidateLinkName( &LinkName );
DFSLOG("ValidateLink Name %wZ, status %x \n", &LinkName, Status );
//
// If validate link name succeeds, we can add the servername
// and share name as a target to this link
//
if (Status == ERROR_SUCCESS)
{
//
// If someone wanted to create this as a new link, we fail the request here.
// the link already exists.
//
if (Flags & DFS_ADD_VOLUME)
{
Status = ERROR_FILE_EXISTS;
}
else
{
//
// Add the target to this link.
//
Status = pRoot->AddMetadataLinkReplica( &LinkName,
ServerName,
ShareName );
DFSLOG("Add metadata Link replica %wZ, status %x\n", &DfsPath, Status);
}
}
else if (Status == ERROR_NOT_FOUND)
{
//
// If the link was not found, at this point we are assured that this link is
// neither a prefix of an existing link not is any link a prefix of this link
// name (validate prefix above provides that assurance)
// We add a new link to this root.
//
Status = pRoot->AddMetadataLink( &DfsPath,
ServerName,
ShareName,
Comment );
DFSLOG("Add metadata Link Name %wZ, status %x\n", &DfsPath, Status);
}
//
// We are done with this request, so release our reference on the root folder.
//
pRoot->RootApiRequestEpilogue( TRUE, Status );
}
pRoot->ReleaseReference();
}
done:
DFS_TRACE_ERROR_NORM(Status, API, "DfsAdd for path %ws, Status %x\n",
DfsPathName, Status );
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsRemove
//
// Arguments: DfsPathName - the pathname that is being added or updated
// ServerName - Name of server being added as target
// ShareName - Name of share on ServerName backing the link
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsRemove(
LPWSTR DfsPathName,
LPWSTR ServerName,
LPWSTR ShareName )
{
DFSSTATUS Status;
UNICODE_STRING DfsPath, LinkName;
DfsRootFolder *pRoot;
BOOLEAN LastReplica = FALSE;
DFS_TRACE_NORM(API, "DfsRemove for path %ws, Server Share \n", DfsPathName);
RtlInitUnicodeString( &DfsPath, DfsPathName );
API_VALIDATE_ARGUMENTS( DfsPathName, ServerName, ShareName, Status);
if (Status != ERROR_SUCCESS)
{
goto done;
}
//
//Get the root folder matching this name. We get a referenced root folder.
//
Status = DfsGetRootFolder( &DfsPath,
&LinkName,
&pRoot );
if (Status == ERROR_SUCCESS)
{
//
// Let the root folder know that a new api request is coming in
// This will give it a chance to let us know if api requests
// are allowed, and to synchronize with the metadata as necessary.
//
Status = pRoot->RootApiRequestPrologue( TRUE );
//
// If we got a root folder, see if there is a link that matches
// the rest of the name beyond the root.
//
if (Status == ERROR_SUCCESS)
{
if ((ServerName != NULL) && (ShareName != NULL))
{
//
// If the servername/sharename was provided, we just remove the matching target.
// If the serername/sharename was not provided, we remove the link itself.
//
Status = pRoot->RemoveMetadataLinkReplica( &LinkName,
ServerName,
ShareName,
&LastReplica );
//
// DFSDEV: REMOVE THIS FROM THE API!!!
//
if ((Status == ERROR_SUCCESS) && (LastReplica == TRUE))
{
Status = pRoot->RemoveMetadataLink( &LinkName );
}
}
else
{
Status = pRoot->RemoveMetadataLink( &LinkName );
}
//
// We now release the reference that we have on the root.
//
pRoot->RootApiRequestEpilogue( TRUE, Status );
}
pRoot->ReleaseReference();
}
done:
DFS_TRACE_ERROR_NORM(Status, API, "DfsRemove for path %ws, Status %x\n",
DfsPathName, Status);
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsEnumerate
//
// Arguments:
// LPWSTR DfsPathName - the pathname that is being added or updated
// DWORD Level - the level of information requested
// DWORD PrefMaxLen - a hint as to how many items to enumerate.
// LPBYTE pBuffer - the buffer to fill, passed in by the caller.
// LONG BufferSize, - the size of passed in buffer.
// LPDWORD pEntriesRead - the number of entries read, set on return
// LPDWORD pResumeHandle - the entry to start from, set to new value on return
// PLONG pNextSizeRequired - size required to successfully complete this call.
// usefule when this call return buffer overflow.
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsEnumerate(
LPWSTR DfsPathName,
DWORD Level,
DWORD PrefMaxLen,
LPBYTE pBuffer,
LONG BufferSize,
LPDWORD pEntriesRead,
LPDWORD pResumeHandle,
PLONG pNextSizeRequired )
{
DFSSTATUS Status;
UNICODE_STRING DfsPath, LinkName;
DfsRootFolder *pRoot;
LONG LevelInfoSize;
DFS_TRACE_NORM(API, "Dfs Enumerate for path Level %d ResumeHandle %d PrefMaxLen %d Size %d\n",
Level, *pResumeHandle, PrefMaxLen, BufferSize);
//
// Get the unicode dfs path.
//
RtlInitUnicodeString( &DfsPath, DfsPathName );
//
// validate the input parameters.
//
API_VALIDATE_ARGUMENTS( DfsPathName, NULL, NULL, Status);
if (Status != ERROR_SUCCESS)
{
goto done;
}
//
// For legacy reasons, we need to support this call coming in with a null name.
// This is where the server would host a single root, and we always knew which root
// we wanted.
// To workaround this situation, if we get a null pathname, we get the first root
// folder and use that.
//
if (DfsPathName != NULL)
{
Status = DfsGetRootFolder( &DfsPath,
&LinkName,
&pRoot );
}
else
{
Status = DfsGetOnlyRootFolder( &pRoot );
}
if (Status == ERROR_SUCCESS)
{
//
// Let the root folder know that a new api request is coming in
// This will give it a chance to let us know if api requests
// are allowed, and to synchronize with the metadata as necessary.
//
Status = pRoot->RootApiRequestPrologue( FALSE );
//
// If we got a root folder, see if there is a link that matches
// the rest of the name beyond the root.
//
if (Status == ERROR_SUCCESS)
{
//
// If PrefMAxLen is 0xffffffff, we need to read all entries. OTherwise we need
// to read a subset of the entries. Let PrefMaxLen decide the number in the array
// of info parameters we pass back. (This is how we document our NEtDfsEnum api)
//
DWORD EntriesToRead;
LevelInfoSize = DfsApiSizeLevelHeader(Level);
EntriesToRead = PrefMaxLen / LevelInfoSize;
if (EntriesToRead == 0) {
EntriesToRead = 1;
}
if (EntriesToRead > pRoot->RootEnumerationCount())
{
EntriesToRead = pRoot->RootEnumerationCount();
}
*pEntriesRead = EntriesToRead;
//
// Now enumerate the entries in the root in the passed in buffer.
//
Status = pRoot->EnumerateApiLinks( DfsPathName,
Level,
pBuffer,
BufferSize,
pEntriesRead,
pResumeHandle,
pNextSizeRequired );
//
// Release the root reference, and return status back to the caller.
//
pRoot->RootApiRequestEpilogue( FALSE, Status );
}
pRoot->ReleaseReference();
}
done:
DFS_TRACE_ERROR_NORM(Status, API, "Dfs Enumerate for path EntriesRead %d ResumeHandle %d Status %x Size %d\n",
*pEntriesRead, *pResumeHandle, Status, *pNextSizeRequired);
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsGetInfo
//
// Arguments:
// LPWSTR DfsPathName - the pathname that is of interest.
// DWORD Level - the level of information requested
// LPBYTE pBuffer - the buffer to fill, passed in by caller
// LONG BufferSize, - the size of passed in buffer.
// PLONG pSizeRequired - size required to successfully complete this call.
// usefule when this call return buffer overflow.
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsGetInfo(
LPWSTR DfsPathName,
DWORD Level,
LPBYTE pBuffer,
LONG BufferSize,
PLONG pSizeRequired )
{
DFSSTATUS Status;
UNICODE_STRING DfsPath, LinkName;
DfsRootFolder *pRoot;
DFS_TRACE_NORM(API, "Dfs get info for path %ws Level %d\n",
DfsPathName, Level );
RtlInitUnicodeString( &DfsPath, DfsPathName );
//
// Validate the input parameters.
//
API_VALIDATE_ARGUMENTS( DfsPathName, NULL, NULL, Status);
if (Status != ERROR_SUCCESS)
{
goto done;
}
//
// Get a referenced root folder for the passed in path.
//
Status = DfsGetRootFolder( &DfsPath,
&LinkName,
&pRoot );
if (Status == ERROR_SUCCESS)
{
Status = pRoot->RootApiRequestPrologue( FALSE );
//
// If we got a root folder, see if there is a link that matches
// the rest of the name beyond the root.
//
if (Status == ERROR_SUCCESS) {
//
// If we got a root folder, get the requested information into the passed
// in buffer.
//
Status = pRoot->GetApiInformation( &DfsPath,
&LinkName,
Level,
pBuffer,
BufferSize,
pSizeRequired );
//
//WE are done: release our reference on the root.
//
pRoot->RootApiRequestEpilogue( FALSE, Status );
}
pRoot->ReleaseReference();
}
done:
DFS_TRACE_ERROR_NORM(Status, API, "Dfs get info for path %ws Status %x\n",
DfsPathName, Status );
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsSetInfo
//
// Arguments:
// LPWSTR DfsPathName - the pathname that is being updated
// LPWSTR Server - the servername (optional) whose info is being set.
// LPWSTR Share - the share on the server.
// DWORD Level - the level of information being set
// LPBYTE pBuffer - the buffer holding the information to be set
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsSetInfo(
LPWSTR DfsPathName,
LPWSTR Server,
LPWSTR Share,
DWORD Level,
LPBYTE pBuffer )
{
DFSSTATUS Status;
UNICODE_STRING DfsPath, LinkName;
DfsRootFolder *pRoot;
DFS_TRACE_NORM(API, "Dfs set info for path %ws Level %d\n",
DfsPathName, Level);
RtlInitUnicodeString( &DfsPath, DfsPathName );
//
//validate the input arguments.
//
API_VALIDATE_ARGUMENTS( DfsPathName, NULL, NULL, Status);
if (Status != ERROR_SUCCESS)
{
goto done;
}
//
// Get a referenced root folder for the passed in path.
//
Status = DfsGetRootFolder( &DfsPath,
&LinkName,
&pRoot );
//
// For cluster, checkpointing may add stuff to the registry which
// we had not found when we started off. So, make an attempt
// to look into the registry.
// In future, this should work across all the roots, but for now
// this is sort of a quick means of getting clusters going.
//
if (Status == ERROR_NOT_FOUND)
{
DfsRegistryStore *pRegStore;
UNICODE_STRING DfsServer, DfsShare, NewDfsShare;
Status = DfsGetRegistryStore( &pRegStore );
if (Status == ERROR_SUCCESS)
{
Status = DfsGetPathComponents( &DfsPath,
&DfsServer,
&DfsShare,
NULL );
if (Status == ERROR_SUCCESS)
{
Status = DfsCreateUnicodeString( &NewDfsShare,
&DfsShare );
}
if (Status == ERROR_SUCCESS)
{
Status = pRegStore->LookupNewRootByName( NewDfsShare.Buffer,
&pRoot );
DfsFreeUnicodeString( &NewDfsShare );
}
pRegStore->ReleaseReference();
}
}
//
// dfsdev: special case master and standby here.
//
// We call into the service with the appropriate bits to
// set the root in a standby mode or a master mode.
//
if (Status == ERROR_SUCCESS)
{
BOOLEAN Done = FALSE;
if (Level == 101)
{
PDFS_INFO_101 pInfo101 = (PDFS_INFO_101)*((PULONG_PTR)pBuffer);
DFS_TRACE_NORM(API, "Dfs set info for path %ws Level %d State is %d\n",
DfsPathName, Level, pInfo101->State);
if (pInfo101->State == DFS_VOLUME_STATE_RESYNCHRONIZE)
{
DFS_TRACE_NORM(API, "Root folder set to Master\n");
pRoot->SetRootResynchronize();
Done = TRUE;
}
else if (pInfo101->State == DFS_VOLUME_STATE_STANDBY)
{
DFS_TRACE_NORM(API, "Root folder set to standby\n");
pRoot->SetRootStandby();
Done = TRUE;
}
}
if (Done)
{
goto done;
}
}
if (Status == ERROR_SUCCESS)
{
//
// Check if the root folder is available for api calls. If not,
// we return an error back to the caller:
// dfsdev: check if this error is a valid one to return.
//
Status = pRoot->RootApiRequestPrologue( TRUE );
if (Status == ERROR_SUCCESS)
{
//
// If we successfully got a root folder, set the specifed information
// on the passed in path/server/share combination.
//
Status = pRoot->SetApiInformation( &LinkName,
Server,
Share,
Level,
pBuffer );
//
// release our reference on the root folder.
//
pRoot->RootApiRequestEpilogue( TRUE, Status );
}
pRoot->ReleaseReference();
}
done:
DFS_TRACE_ERROR_NORM(Status, API, "Dfs set info for path %ws Status %x\n",
DfsPathName, Status );
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsAddStandaloneRoot
//
// Arguments:
// LPWSTR ShareName - the share name to use
// LPWSTR Comment - the comment for this root
// DWORD Flags - the flags for this root
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsAddStandaloneRoot(
LPWSTR MachineName,
LPWSTR ShareName,
LPWSTR Comment,
DWORD Flags )
{
DFS_TRACE_NORM(API, "Dfs add standalone root Machine Share %ws\n",
ShareName);
//
// dfsdev: use these parameters.
//
UNREFERENCED_PARAMETER(Comment);
UNREFERENCED_PARAMETER(Flags);
DfsRegistryStore *pRegStore;
DFSSTATUS Status;
//
// This is a registry store specific function. So finf the registry store.
// This gives us a referenced registry store pointer.
//
Status = DfsGetRegistryStore( &pRegStore );
if (Status == ERROR_SUCCESS)
{
//
// Create the standalone root, and release our reference on the registry
// store.
//
Status = pRegStore->CreateStandaloneRoot( MachineName,
ShareName,
Comment );
pRegStore->ReleaseReference();
}
DFS_TRACE_ERROR_NORM(Status, API, "Dfs add standalone root status %x Machine Share %ws\n",
Status, ShareName);
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsDeleteStandaloneRoot
//
// Arguments:
// LPWSTR ShareName - the root to delete
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsDeleteStandaloneRoot(
LPWSTR ShareName )
{
DfsRegistryStore *pRegStore;
DFSSTATUS Status;
DFS_TRACE_NORM(API, "Dfs delete standalone root Machine Share %ws\n",
ShareName);
//
// This is registry store specific function, so get the registry store.
//
Status = DfsGetRegistryStore( &pRegStore );
if (Status == ERROR_SUCCESS)
{
//
// Delete the standalone root specified by the passed in sharename
// and release our reference on the registry store.
//
Status = pRegStore->DeleteStandaloneRoot( NULL,
ShareName );
pRegStore->ReleaseReference();
}
DFS_TRACE_ERROR_NORM(Status, API, "Dfs delete standalone root status %x Machine Share %ws\n",
Status, ShareName);
return Status;
}
DFSSTATUS
DfsEnumerateLocalRoots(
LPWSTR MachineName,
LPBYTE pBuffer,
ULONG BufferSize,
PULONG pEntriesRead,
PULONG pSizeRequired )
{
UNREFERENCED_PARAMETER(MachineName);
DFSSTATUS Status = ERROR_SUCCESS;
ULONG TotalSize = 0;
ULONG EntriesRead = 0;
ULONG_PTR CurrentBuffer = (ULONG_PTR)pBuffer;
ULONG CurrentSize = BufferSize;
DfsStore *pStore;
BOOLEAN OverFlow = FALSE;
//
// Call the store recognizer of each registered store.
//
for (pStore = DfsServerGlobalData.pRegisteredStores;
(pStore != NULL) && (Status == ERROR_SUCCESS);
pStore = pStore->pNextRegisteredStore) {
Status = pStore->EnumerateRoots( &CurrentBuffer,
&CurrentSize,
&EntriesRead,
&TotalSize );
if (Status == ERROR_BUFFER_OVERFLOW)
{
OverFlow = TRUE;
Status = ERROR_SUCCESS;
}
}
if (Status == ERROR_SUCCESS)
{
if (OverFlow == TRUE)
{
Status = ERROR_BUFFER_OVERFLOW;
}
*pEntriesRead = EntriesRead;
*pSizeRequired = TotalSize;
}
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsEnumerateRoots
//
// Arguments:
// LPBYTE pBuffer - the buffer to fill, passed in by teh caller
// LONG BufferSize, - the size of passed in buffer.
// LPDWORD pEntriesRead - the number of entries read, set on return
// LPDWORD pResumeHandle - the entry to start from, set to new value on return
// PLONG pSizeRequired - size required to successfully complete this call.
// usefule when this call return buffer overflow.
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsEnumerateRoots(
LPWSTR DfsName,
LPBYTE pBuffer,
ULONG BufferSize,
PULONG pEntriesRead,
PULONG pResumeHandle,
PULONG pSizeRequired )
{
DFSSTATUS Status;
DFS_TRACE_NORM(API, "Dfs enumerate roots: resume handle %d\n",
*pResumeHandle);
//
// dfsdev: use this parameter.
//
UNREFERENCED_PARAMETER(pResumeHandle);
UNICODE_STRING DfsPath;
UNICODE_STRING NameContext;
UNICODE_STRING RemainingPart;
RtlInitUnicodeString( &DfsPath, DfsName );
Status = DfsGetFirstComponent( &DfsPath,
&NameContext,
&RemainingPart );
if (Status == ERROR_SUCCESS)
{
if (RemainingPart.Length != 0)
{
//
// return not found for now... dfsdev: fix on client.
//
Status = ERROR_PATH_NOT_FOUND;
}
}
if (Status == ERROR_SUCCESS)
{
if (DfsIsMachineDC() &&
DfsIsNameContextDomainName(&NameContext))
{
Status = DfsDcEnumerateRoots( NULL,
pBuffer,
BufferSize,
pEntriesRead,
pSizeRequired);
}
else
{
Status = DfsEnumerateLocalRoots( NULL,
pBuffer,
BufferSize,
pEntriesRead,
pSizeRequired );
}
}
DFS_TRACE_ERROR_NORM(Status, API, "Dfs enumerate roots, status %x\n",
Status );
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsAddADBlobRoot
//
// Arguments:
// LPWSTR MachineName,
// LPWSTR DcName,
// LPWSTR ShareName,
// LPWSTR LogicalShare,
// LPWSTR Comment,
// DWORD Flags,
// PDFSM_ROOT_LIST *ppRootList )
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsAddADBlobRoot(
LPWSTR MachineName,
LPWSTR DcName,
LPWSTR ShareName,
LPWSTR LogicalShare,
LPWSTR Comment,
BOOLEAN NewFtDfs,
DWORD Flags,
PVOID ppList )
{
DFS_TRACE_NORM(API, "Dfs add ad blob root Machine Share %ws\n",
ShareName);
PDFSM_ROOT_LIST *ppRootList = (PDFSM_ROOT_LIST *)ppList;
//
// dfsdev: use these parameters.
//
UNREFERENCED_PARAMETER(Comment);
UNREFERENCED_PARAMETER(Flags);
DfsADBlobStore *pADBlobStore;
DFSSTATUS Status;
//
// This is a registry store specific function. So finf the registry store.
// This gives us a referenced registry store pointer.
//
Status = DfsGetADBlobStore( &pADBlobStore );
if (Status == ERROR_SUCCESS)
{
//
// Create the standalone root, and release our reference on the registry
// store.
//
Status = pADBlobStore->CreateADBlobRoot( MachineName,
DcName,
ShareName,
LogicalShare,
Comment,
NewFtDfs,
ppRootList );
pADBlobStore->ReleaseReference();
}
DFS_TRACE_ERROR_NORM(Status, API, "Dfs add ad blob root status %x Machine Share %ws\n",
Status, ShareName);
return Status;
}
//+----------------------------------------------------------------------------
//
// Function: DfsDeleteADBlobRoot
//
// Arguments:
// LPWSTR MachineName,
// LPWSTR DcName,
// LPWSTR ShareName,
// LPWSTR LogicalShare,
// DWORD Flags,
// PDFSM_ROOT_LIST *ppRootList )
//
// Returns: ERROR_SUCCESS
// Error code other wise.
//
//-----------------------------------------------------------------------------
DFSSTATUS
DfsDeleteADBlobRoot(
LPWSTR MachineName,
LPWSTR DcName,
LPWSTR ShareName,
LPWSTR LogicalShare,
DWORD Flags,
PVOID ppList )
{
DFS_TRACE_NORM(API, "Dfs delete ad blob root Machine Share %ws\n",
ShareName);
PDFSM_ROOT_LIST *ppRootList = (PDFSM_ROOT_LIST *)ppList;
//
// dfsdev: use these parameters.
//
UNREFERENCED_PARAMETER(Flags);
DfsADBlobStore *pADBlobStore;
DFSSTATUS Status;
//
// This is a registry store specific function. So finf the registry store.
// This gives us a referenced registry store pointer.
//
Status = DfsGetADBlobStore( &pADBlobStore );
if (Status == ERROR_SUCCESS)
{
//
// Create the standalone root, and release our reference on the registry
// store.
//
Status = pADBlobStore->DeleteADBlobRoot( MachineName,
DcName,
ShareName,
LogicalShare,
ppRootList );
pADBlobStore->ReleaseReference();
}
DFS_TRACE_ERROR_NORM(Status, API, "Dfs delete ad blob root status %x Machine Share %ws\n",
Status, ShareName);
return Status;
}