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.
2605 lines
78 KiB
2605 lines
78 KiB
//--------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1999, Microsoft Corporation
|
|
//
|
|
// File: dfsutil.cxx
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
extern "C" {
|
|
#include <stdio.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <shellapi.h>
|
|
#include <winldap.h>
|
|
#include <stdlib.h>
|
|
}
|
|
#include <lm.h>
|
|
#include <lmdfs.h>
|
|
#include <dfsfsctl.h>
|
|
#include <dsgetdc.h>
|
|
#include <ole2.h>
|
|
#include <activeds.h>
|
|
#include <dfsprefix.h>
|
|
#include <DfsServerLibrary.hxx>
|
|
#include <dfsmisc.h>
|
|
#include "dsgetdc.h"
|
|
#include "dsrole.h"
|
|
|
|
#include "dfsutil.hxx"
|
|
#include "dfspathname.hxx"
|
|
|
|
#include "struct.hxx"
|
|
#include "flush.hxx"
|
|
#include "misc.hxx"
|
|
#include "info.hxx"
|
|
#include "messages.h"
|
|
#include "dfsreparse.hxx"
|
|
|
|
#include "dfswmi.h"
|
|
|
|
#include "dfsroot.hxx"
|
|
#define WPP_BIT_CLI_DRV 0x01
|
|
|
|
#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)
|
|
#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_CLI_DRV ).Level >= lvl)
|
|
|
|
|
|
#define WPP_LEVEL_ERROR_FLAGS_LOGGER(lvl, error, flags) WPP_LEVEL_LOGGER(flags)
|
|
#define WPP_LEVEL_ERROR_FLAGS_ENABLED(lvl, error, flags) \
|
|
((!NT_SUCCESS(error) || WPP_LEVEL_ENABLED(flags)) && WPP_CONTROL(WPP_BIT_CLI_DRV ).Level >= lvl)
|
|
|
|
#include "dfsutil.tmh"
|
|
|
|
|
|
UNICODE_STRING DCToUseFlatDomainName;
|
|
UNICODE_STRING DCToUseDNSDomainName;
|
|
LPWSTR DCToUse = NULL;
|
|
DFSSTATUS DCInfoStatus = ERROR_SUCCESS;
|
|
|
|
extern
|
|
void
|
|
SetReferralControl(WPP_CB_TYPE * Control);
|
|
|
|
DFSSTATUS
|
|
ProcessRootForSite(
|
|
DfsRoot *pRoot );
|
|
|
|
DFSSTATUS
|
|
PurgeSiteInformationForRoot(
|
|
DfsRoot *pRoot );
|
|
|
|
DFSSTATUS
|
|
DumpSiteBlob(
|
|
PVOID pBuffer,
|
|
ULONG Size,
|
|
BOOLEAN Display );
|
|
|
|
//
|
|
// How we make args & switches
|
|
//
|
|
|
|
#define MAKEARG(x) \
|
|
WCHAR Arg##x[] = L"/" L#x L":"; \
|
|
LONG ArgLen##x = (sizeof(Arg##x) / sizeof(WCHAR)) - 1; \
|
|
BOOLEAN fArg##x;
|
|
|
|
#define SWITCH(x) \
|
|
WCHAR Sw##x[] = L"/" L#x ; \
|
|
BOOLEAN fSw##x;
|
|
|
|
#define FMAKEARG(x) \
|
|
static WCHAR Arg##x[] = L#x L":"; \
|
|
static LONG ArgLen##x = (sizeof(Arg##x) / sizeof(WCHAR)) - 1; \
|
|
static BOOLEAN fArg##x;
|
|
|
|
#define FSWITCH(x) \
|
|
static WCHAR Sw##x[] = L"/" L#x ; \
|
|
static BOOLEAN fSw##x;
|
|
|
|
DFSSTATUS
|
|
DfsReadFromAD(
|
|
LPWSTR DomainName,
|
|
LPWSTR Name,
|
|
LPWSTR FileName,
|
|
LPWSTR UseDC );
|
|
|
|
DFSSTATUS
|
|
DfsReadFromFile(
|
|
LPWSTR Name );
|
|
|
|
|
|
|
|
LPWSTR pwszServerName = NULL;
|
|
LPWSTR pwszDomainName = NULL;
|
|
LPWSTR pwszEntryToFlush = NULL;
|
|
LPWSTR pwszComment = NULL;
|
|
LPWSTR pwszShareName = NULL;
|
|
LPWSTR pwszLogicalName = NULL;
|
|
LPWSTR pwszHexValue = NULL;
|
|
LPWSTR ImportFile = NULL;
|
|
|
|
DfsPathName OperateNameSpace;
|
|
DfsPathName MasterNameSpace;
|
|
DfsPathName OldDomainName;
|
|
DfsPathName NewDomainName;
|
|
|
|
DfsString ClientForSiteName;
|
|
|
|
LPWSTR ExportBlobFile = NULL;
|
|
LPWSTR DisplayBlobFile = NULL;
|
|
|
|
BOOLEAN CmdRequiresDirect = FALSE;
|
|
LPWSTR ExportFile = NULL;
|
|
LPWSTR DebugFile = NULL;
|
|
LPWSTR BackupFile = NULL;
|
|
LPWSTR pwszVolumeName = NULL;
|
|
LPWSTR pwszDfsDirectoryName = NULL;
|
|
LPWSTR pwszDcName = NULL;
|
|
|
|
DFS_API_MODE Mode = MODE_EITHER;
|
|
|
|
DFSSTATUS DirectModeFailStatus = ERROR_SUCCESS;
|
|
|
|
|
|
HANDLE ShowHandle= INVALID_HANDLE_VALUE;
|
|
HANDLE DebugHandle= INVALID_HANDLE_VALUE;
|
|
HANDLE ExportHandle= INVALID_HANDLE_VALUE;
|
|
HANDLE BackupHandle = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
MAKEARG(RemFtRoot);
|
|
SWITCH(RemFtRoot);
|
|
|
|
MAKEARG(Domain);
|
|
MAKEARG(Server);
|
|
MAKEARG(Share);
|
|
|
|
SWITCH(DisplayBlob);
|
|
MAKEARG(DisplayBlob);
|
|
|
|
|
|
MAKEARG(Import);
|
|
SWITCH(Import); // The switch is just a cue for Help here.
|
|
MAKEARG(Export);
|
|
MAKEARG(Backup);
|
|
SWITCH(NoBackup);
|
|
SWITCH(Export);
|
|
MAKEARG(Root);
|
|
SWITCH(Root);
|
|
MAKEARG(DebugFile);
|
|
MAKEARG(OldDomain);
|
|
MAKEARG(NewDomain);
|
|
SWITCH(UnmapFtRoot);
|
|
SWITCH(Unmap);
|
|
MAKEARG(UnmapFtRoot);
|
|
|
|
MAKEARG(SiteName);
|
|
SWITCH(SiteName);
|
|
MAKEARG(Clean);
|
|
SWITCH(Clean);
|
|
SWITCH(Insite);
|
|
SWITCH(SiteCosting);
|
|
SWITCH(RootScalability);
|
|
|
|
SWITCH(ViewDfsDirs);
|
|
MAKEARG(ViewDfsDirs);
|
|
|
|
//MAKEARG(RemoveReparse);
|
|
MAKEARG(DebugDC);
|
|
SWITCH(RemoveReparse);
|
|
SWITCH(DC);
|
|
|
|
SWITCH(ExportBlob);
|
|
MAKEARG(ExportBlob);
|
|
|
|
MAKEARG(ImportRoot);
|
|
SWITCH(ImportRoot);
|
|
|
|
SWITCH(PurgeMupCache);
|
|
SWITCH(UpdateWin2kStaticSiteTable);
|
|
SWITCH(ShowWin2kStaticSiteTable);
|
|
SWITCH(PurgeWin2kStaticSiteTable);
|
|
|
|
SWITCH(CheckBlob);
|
|
SWITCH(BlobSize);
|
|
|
|
|
|
|
|
//
|
|
// Switches (ie '/arg')
|
|
//
|
|
|
|
SWITCH(AddStdRoot);
|
|
SWITCH(AddFtRoot);
|
|
SWITCH(Debug);
|
|
SWITCH(Verbose);
|
|
SWITCH(Help);
|
|
SWITCH(ScriptHelp);
|
|
SWITCH(PktInfo);
|
|
SWITCH(Dfs);
|
|
SWITCH(All);
|
|
SWITCH(Set);
|
|
SWITCH(Mirror);
|
|
SWITCH(RemStdRoot);
|
|
SWITCH(Api);
|
|
|
|
SWITCH(Compare);
|
|
SWITCH(Merge);
|
|
SWITCH(Direct);
|
|
SWITCH(RenameFtRoot);
|
|
SWITCH(View);
|
|
SWITCH(Disable);
|
|
SWITCH(Enable);
|
|
SWITCH(Display);
|
|
|
|
|
|
|
|
//
|
|
// Either a switch or an arg
|
|
//
|
|
MAKEARG(PktFlush);
|
|
SWITCH(PktFlush);
|
|
MAKEARG(SpcFlush);
|
|
SWITCH(SpcFlush);
|
|
MAKEARG(SpcInfo);
|
|
SWITCH(SpcInfo);
|
|
MAKEARG(Level);
|
|
|
|
|
|
//
|
|
// The macro can not make these
|
|
//
|
|
|
|
WCHAR SwQ[] = L"/?";
|
|
BOOLEAN fSwQ;
|
|
|
|
ULONG AddLinks, RemoveLinks, AddTargets, RemoveTargets, ErrorLinks,
|
|
DirectMode, ApiCalls, SetInfoState, SetInfoComment;
|
|
ULONG TotalNamespaceCost;
|
|
|
|
BOOLEAN CommandSucceeded = FALSE;
|
|
BOOLEAN ErrorDisplayed = FALSE;
|
|
static BOOLEAN LastOptionWasInsite = FALSE;
|
|
static BOOLEAN DirectModeOnly = FALSE;
|
|
static BOOLEAN UserRequiresDirectMode = FALSE;
|
|
|
|
DFSSTATUS
|
|
CmdInitializeDirectMode(
|
|
PBOOLEAN pCoInitialized);
|
|
|
|
DWORD
|
|
Usage();
|
|
|
|
DWORD
|
|
CmdProcessUserCreds(
|
|
VOID);
|
|
|
|
BOOLEAN
|
|
CmdProcessArg(
|
|
LPWSTR Arg);
|
|
|
|
|
|
DFSSTATUS
|
|
CmdCheckSyntax( BOOLEAN& Done );
|
|
|
|
DFSSTATUS
|
|
IsRootStandalone(
|
|
DfsPathName *PathComps,
|
|
PBOOLEAN pIsAdBlob );
|
|
|
|
DWORD
|
|
IsThisADomainName(
|
|
IN LPWSTR wszName,
|
|
OUT PWCHAR *ppList OPTIONAL);
|
|
|
|
DFSSTATUS
|
|
CmdCheckExceptions( DfsPathName *Namespace );
|
|
|
|
extern DFSSTATUS
|
|
DfsExtendedWin2kRootAttributes(
|
|
DfsPathName *Namespace,
|
|
PULONG pAttr,
|
|
BOOLEAN Set);
|
|
|
|
|
|
DFSSTATUS
|
|
GetDCInformation()
|
|
{
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pPrimaryDomainInfo = NULL;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
Status = DsRoleGetPrimaryDomainInformation( DCToUse,
|
|
DsRolePrimaryDomainInfoBasic,
|
|
(PBYTE *)&pPrimaryDomainInfo);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DCInfoStatus = Status;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
UNICODE_STRING DomainNameFlat;
|
|
Status = DfsRtlInitUnicodeStringEx( &DomainNameFlat,
|
|
pPrimaryDomainInfo->DomainNameFlat);
|
|
if(Status == ERROR_SUCCESS)
|
|
{
|
|
Status = DfsCreateUnicodeString( &DCToUseFlatDomainName,
|
|
&DomainNameFlat );
|
|
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
UNICODE_STRING DomainNameDNS;
|
|
Status = DfsRtlInitUnicodeStringEx( &DomainNameDNS,
|
|
pPrimaryDomainInfo->DomainNameDns);
|
|
if(Status == ERROR_SUCCESS)
|
|
{
|
|
Status = DfsCreateUnicodeString( &DCToUseDNSDomainName,
|
|
&DomainNameDNS );
|
|
|
|
}
|
|
}
|
|
|
|
DsRoleFreeMemory(pPrimaryDomainInfo);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
DfsEnumerateDomainDfs(
|
|
LPWSTR Domain)
|
|
{
|
|
DFSSTATUS Status;
|
|
PDFS_INFO_200 pBuffer = NULL, pCurBuffer;
|
|
DWORD dwEntriesRead = 0;
|
|
DWORD dwResumeHandle = 0;
|
|
DWORD dwTotalEntries = 0;
|
|
|
|
do {
|
|
|
|
dwEntriesRead = 0;
|
|
|
|
Status = NetDfsEnum( Domain,
|
|
200,
|
|
(DWORD)-1,
|
|
(LPBYTE *)&pBuffer,
|
|
&dwEntriesRead,
|
|
&dwResumeHandle );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pCurBuffer = pBuffer;
|
|
|
|
if (dwEntriesRead)
|
|
{
|
|
if (dwTotalEntries == 0) {
|
|
ShowInformation((L"\nRoots on Domain %ws\n\n", Domain));
|
|
}
|
|
for (DWORD i=0; i<dwEntriesRead; i++)
|
|
{
|
|
ShowInformation((L"\t%ws\n", pCurBuffer[i].FtDfsName));
|
|
dwTotalEntries++;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pBuffer)
|
|
{
|
|
NetApiBufferFree(pBuffer);
|
|
pBuffer = NULL;
|
|
}
|
|
} while ( Status == ERROR_SUCCESS && dwResumeHandle != NULL );
|
|
|
|
if (dwTotalEntries > 0)
|
|
{
|
|
ShowInformation((L"\nDone with Roots on Domain %ws\n", Domain));
|
|
|
|
if (Status == ERROR_NO_MORE_ITEMS) {
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShowInformation((L"\n\nNo roots exist on domain %ws\n\n", Domain));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
DfsEnumerateMachineDfs(
|
|
LPWSTR Server)
|
|
{
|
|
DFSSTATUS Status;
|
|
PDFS_INFO_300 pBuffer = NULL, pCurBuffer;
|
|
DWORD dwEntriesRead = 0;
|
|
DWORD dwResumeHandle = 0;
|
|
DWORD dwTotalEntries = 0;
|
|
|
|
do {
|
|
|
|
dwEntriesRead = 0;
|
|
|
|
Status = NetDfsEnum( Server,
|
|
300,
|
|
(DWORD)-1,
|
|
(LPBYTE *)&pBuffer,
|
|
&dwEntriesRead,
|
|
&dwResumeHandle );
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pCurBuffer = pBuffer;
|
|
if (dwEntriesRead)
|
|
{
|
|
if (dwTotalEntries == 0) {
|
|
ShowInformation((L"\nRoots on machine %ws\n\n", Server));
|
|
}
|
|
for (DWORD i=0; i<dwEntriesRead; i++)
|
|
{
|
|
ShowInformation((L"\t%ws\n", pCurBuffer[i].DfsName));
|
|
dwTotalEntries++;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pBuffer)
|
|
{
|
|
NetApiBufferFree(pBuffer);
|
|
pBuffer = NULL;
|
|
}
|
|
|
|
} while ( Status == ERROR_SUCCESS && dwResumeHandle != NULL );
|
|
|
|
if (dwTotalEntries > 0)
|
|
{
|
|
ShowInformation((L"\nDone with Roots on machine %ws\n", Server));
|
|
|
|
if (Status == ERROR_NO_MORE_ITEMS) {
|
|
Status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShowInformation((L"\n\nNo roots exist on machine %ws\n\n", Server));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
_cdecl
|
|
main(int argc, char *argv[])
|
|
{
|
|
UNREFERENCED_PARAMETER(argv);
|
|
UNREFERENCED_PARAMETER(argc);
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
LPWSTR CommandLine;
|
|
LPWSTR *argvw;
|
|
int argx;
|
|
int argcw;
|
|
BOOLEAN CoInitialized = FALSE;
|
|
BOOLEAN DirectModeInitialized = FALSE;
|
|
BOOLEAN Done;
|
|
|
|
WPP_CB_TYPE *pLogger = NULL;
|
|
|
|
pLogger = &WPP_CB[WPP_CTRL_NO(WPP_BIT_CLI_DRV)];
|
|
|
|
WPP_INIT_TRACING(L"DfsUtil");
|
|
SetReferralControl(pLogger);
|
|
|
|
ShowHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
DebugHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
//
|
|
// Do the work
|
|
//
|
|
do {
|
|
ErrorMessage( MSG_COPYRIGHT );
|
|
|
|
if ((dwErr = DfsPrefixTableInit()) != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the command line in Unicode
|
|
//
|
|
|
|
CommandLine = GetCommandLine();
|
|
|
|
argvw = CommandLineToArgvW(CommandLine, &argcw);
|
|
|
|
if ( argvw == NULL ) {
|
|
DebugInformation((L"DfsUtil:Can't convert command line to Unicode: %d\r\n", GetLastError()));
|
|
dwErr = GetLastError();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the arguments
|
|
//
|
|
if (argcw <= 1) {
|
|
dwErr = Usage();
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Process arguments. Direct mode is enabled by default.
|
|
//
|
|
fSwDirect = TRUE;
|
|
UserRequiresDirectMode = FALSE;
|
|
Done = FALSE;
|
|
|
|
for (argx = 1; argx < argcw && !Done; argx++) {
|
|
Done = CmdProcessArg(argvw[argx]);
|
|
}
|
|
if (Done) {
|
|
Usage();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Some sanity checking of cmd syntax.
|
|
// This also prints all appropriate error help messages.
|
|
//
|
|
dwErr = CmdCheckSyntax( Done );
|
|
if (Done) {
|
|
break;
|
|
}
|
|
|
|
if (fSwPktFlush == TRUE || fArgPktFlush == TRUE) {
|
|
dwErr = PktFlush(pwszEntryToFlush);
|
|
break;
|
|
} else if (fSwSpcFlush == TRUE || fArgSpcFlush == TRUE) {
|
|
dwErr = SpcFlush(pwszEntryToFlush);
|
|
break;
|
|
} else if (fSwPktInfo == TRUE) {
|
|
dwErr = PktInfo(fSwDfs, pwszHexValue);
|
|
break;
|
|
} else if (fSwSpcInfo == TRUE) {
|
|
dwErr = SpcInfo(fSwAll);
|
|
break;
|
|
}
|
|
|
|
if(fArgViewDfsDirs)
|
|
{
|
|
BOOL fRemove = FALSE;
|
|
|
|
if(fSwRemoveReparse)
|
|
{
|
|
fRemove =TRUE;
|
|
}
|
|
|
|
dwErr = CountReparsePoints(pwszVolumeName, fRemove);
|
|
break;
|
|
}
|
|
/*
|
|
BUG 736596: DeleteReparsePoint as implemented doesn't walk through
|
|
all subdirectories of a given directory. In fact, it doesn't seem to work
|
|
at all. We should probably address this in the longhorn timeframe.
|
|
|
|
if(fArgRemoveReparse)
|
|
{
|
|
dwErr = DeleteReparsePoint(pwszDfsDirectoryName);
|
|
break;
|
|
}
|
|
*/
|
|
if (fSwAddStdRoot == TRUE) {
|
|
dwErr = CmdAddRoot(
|
|
FALSE,
|
|
pwszServerName,
|
|
pwszShareName,
|
|
pwszShareName, // Enforce RootName = Sharename
|
|
pwszComment);
|
|
break;
|
|
}
|
|
|
|
if (fSwAddFtRoot == TRUE) {
|
|
dwErr = CmdAddRoot(
|
|
TRUE,
|
|
pwszServerName,
|
|
pwszShareName,
|
|
pwszShareName, // Enforce RootName = Sharename
|
|
pwszComment);
|
|
break;
|
|
}
|
|
|
|
if (fSwRemStdRoot == TRUE) {
|
|
dwErr = CmdRemRoot(
|
|
FALSE,
|
|
pwszServerName,
|
|
pwszShareName,
|
|
pwszShareName); // Sharename = logicalname.
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We allow users to delete roots whose logical name don't match
|
|
// their physical share names for compatibility reasons.
|
|
// DfsUtil itself doesn't allow people to create such roots however.
|
|
//
|
|
if (fArgRemFtRoot == TRUE || fSwRemFtRoot == TRUE) {
|
|
dwErr = CmdRemRoot(
|
|
TRUE,
|
|
pwszServerName,
|
|
pwszShareName,
|
|
pwszLogicalName); // logical name may differ.
|
|
break;
|
|
}
|
|
|
|
|
|
if (fSwClean) {
|
|
dwErr = CmdClean( pwszServerName, pwszShareName );
|
|
break;
|
|
}
|
|
|
|
if ((Mode == MODE_DIRECT) || (Mode == MODE_EITHER))
|
|
{
|
|
dwErr = CmdInitializeDirectMode( &CoInitialized);
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
DirectModeFailStatus = dwErr;
|
|
if (Mode == MODE_DIRECT)
|
|
{
|
|
DebugInformation((L"DfsUtil: Failed direct communication with DFS metadata, status 0x%x\n", dwErr));
|
|
ErrorMessage(MSG_ROOT_DIRECT_FAILED, dwErr);
|
|
break;
|
|
}
|
|
else if (CmdRequiresDirect == TRUE)
|
|
{
|
|
ErrorMessage(MSG_ROOT_DIRECT_REQUIRED_FAILED, dwErr);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Mode = MODE_API;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DirectModeInitialized = TRUE;
|
|
}
|
|
}
|
|
|
|
if (CmdRequiresDirect && (DirectModeInitialized == FALSE))
|
|
{
|
|
ErrorMessage(MSG_ROOT_DIRECT_REQUIRED);
|
|
break;
|
|
}
|
|
|
|
if (fSwUpdateWin2kStaticSiteTable)
|
|
{
|
|
DfsRoot *pOperateRoot = NULL;
|
|
dwErr = DfsBuildNameSpaceInformation( &OperateNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
TRUE, // site aware
|
|
&pOperateRoot);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = ProcessRootForSite(pOperateRoot );
|
|
}
|
|
|
|
if(pOperateRoot)
|
|
{
|
|
pOperateRoot->Close();
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
if (fSwPurgeWin2kStaticSiteTable)
|
|
{
|
|
DfsRoot *pOperateRoot = NULL;
|
|
dwErr = DfsBuildNameSpaceInformation( &OperateNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
FALSE,
|
|
&pOperateRoot);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = PurgeSiteInformationForRoot(pOperateRoot );
|
|
}
|
|
|
|
if(pOperateRoot)
|
|
{
|
|
pOperateRoot->Close();
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (fSwShowWin2kStaticSiteTable)
|
|
|
|
{
|
|
DfsRoot *pOperateRoot = NULL;
|
|
PVOID pBuffer = NULL;
|
|
ULONG Size = 0;
|
|
|
|
dwErr = DfsBuildNameSpaceInformation( &OperateNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
FALSE,
|
|
&pOperateRoot);
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = pOperateRoot->RootGetSiteBlob(&pBuffer, &Size);
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = DumpSiteBlob((PVOID)pBuffer, Size, TRUE);
|
|
}
|
|
if(pOperateRoot)
|
|
{
|
|
pOperateRoot->Close();
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Importing a namespace from a script file.
|
|
//
|
|
if (fArgImport) {
|
|
|
|
DfsRoot *pMasterRoot;
|
|
DfsRoot *pOperateRoot;
|
|
|
|
dwErr = DfsReadDocument( ImportFile,
|
|
&pMasterRoot );
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
if (fSwBlobSize)
|
|
{
|
|
ULONG RootBlobSize = 0;
|
|
|
|
extern DFSSTATUS SizeRoot(DfsRoot *pRoot, PULONG pSize);
|
|
|
|
dwErr = SizeRoot(pMasterRoot, &RootBlobSize);
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
ShowInformation((L"\n\nApproximate blob size for import file is %.2f Megabytes\n\n",
|
|
(DOUBLE)RootBlobSize / (1024 * 1024)));
|
|
|
|
}
|
|
}
|
|
else if (fSwView)
|
|
{
|
|
DumpRoots(pMasterRoot, ShowHandle, FALSE);
|
|
}
|
|
else
|
|
{
|
|
dwErr = DfsBuildNameSpaceInformation( &OperateNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
FALSE,
|
|
&pOperateRoot );
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Iterate over the (real) options.
|
|
//
|
|
if (fSwCompare)
|
|
{
|
|
VerifyDfsRoots(pOperateRoot, pMasterRoot);
|
|
}
|
|
else if (fSwSet)
|
|
{
|
|
dwErr = SetDfsRoots(pOperateRoot, pMasterRoot, BackupHandle, fSwNoBackup);
|
|
}
|
|
else if (fSwMerge)
|
|
{
|
|
dwErr = MergeDfsRoots( pOperateRoot, pMasterRoot, BackupHandle, fSwNoBackup);
|
|
}
|
|
|
|
pOperateRoot->Close();
|
|
}
|
|
}
|
|
pMasterRoot->Close();
|
|
}
|
|
break;
|
|
|
|
}
|
|
else if (fArgImportRoot)
|
|
{
|
|
DfsRoot *pMasterRoot;
|
|
DfsRoot *pOperateRoot;
|
|
|
|
dwErr = DfsBuildNameSpaceInformation( &OperateNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
FALSE,
|
|
&pOperateRoot );
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = DfsBuildNameSpaceInformation( &MasterNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
FALSE,
|
|
&pMasterRoot );
|
|
|
|
if ((dwErr == ERROR_SUCCESS) &&
|
|
(fSwVerbose == TRUE))
|
|
{
|
|
DumpRoots( pMasterRoot, ShowHandle, FALSE);
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Iterate over the (real) options.
|
|
//
|
|
if (fSwCompare)
|
|
{
|
|
VerifyDfsRoots(pOperateRoot, pMasterRoot);
|
|
}
|
|
|
|
else if (fSwMirror)
|
|
{
|
|
dwErr = SetDfsRoots(pOperateRoot, pMasterRoot, BackupHandle, fSwNoBackup);
|
|
}
|
|
pMasterRoot->Close();
|
|
}
|
|
pOperateRoot->Close();
|
|
}
|
|
|
|
break;
|
|
}
|
|
else if (fArgDisplayBlob)
|
|
{
|
|
dwErr = DfsReadFromFile( DisplayBlobFile );
|
|
break;
|
|
}
|
|
else if (fArgExportBlob)
|
|
{
|
|
dwErr = DfsReadFromAD( OperateNameSpace.GetServerString(),
|
|
OperateNameSpace.GetShareString(),
|
|
ExportBlobFile,
|
|
DCToUse);
|
|
break;
|
|
}
|
|
else if (fSwCheckBlob)
|
|
{
|
|
dwErr = DfsReadFromAD( OperateNameSpace.GetServerString(),
|
|
OperateNameSpace.GetShareString(),
|
|
NULL,
|
|
DCToUse);
|
|
break;
|
|
}
|
|
else if (fSwView)
|
|
{
|
|
if (fArgDomain)
|
|
{
|
|
dwErr = DfsEnumerateDomainDfs(pwszDomainName);
|
|
}
|
|
else if (fArgServer)
|
|
{
|
|
dwErr = DfsEnumerateMachineDfs(pwszServerName);
|
|
}
|
|
else
|
|
{
|
|
DfsRoot *pOperateRoot;
|
|
|
|
dwErr = DfsBuildNameSpaceInformation( &OperateNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
TRUE,
|
|
&pOperateRoot );
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = DumpRoots( pOperateRoot, ShowHandle, FALSE);
|
|
|
|
pOperateRoot->Close();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else if (fArgExport)
|
|
{
|
|
DfsRoot *pOperateRoot;
|
|
|
|
dwErr = DfsBuildNameSpaceInformation( &OperateNameSpace,
|
|
DCToUse,
|
|
Mode,
|
|
FALSE,
|
|
&pOperateRoot );
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = DumpRoots( pOperateRoot, ExportHandle, TRUE);
|
|
|
|
pOperateRoot->Close();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fSwRenameFtRoot) {
|
|
PVOID DirectModeHandle = NULL;
|
|
|
|
dwErr = DfsDirectApiOpen( OperateNameSpace.GetPathString(),
|
|
DCToUse,
|
|
&DirectModeHandle);
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Now do the rename. Note that we only use the first component.
|
|
// If users enter /olddomain:\\xx.y.com\z we simply use xx.y.com without
|
|
// the \\ or the sharename.
|
|
//
|
|
dwErr = DfsRenameLinksToDomain( &OperateNameSpace,
|
|
OldDomainName.GetServerString(),
|
|
NewDomainName.GetServerString());
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
SetDirectHandleWriteable(DirectModeHandle);
|
|
dwErr = DfsDirectApiCommitChanges( DirectModeHandle);
|
|
}
|
|
DfsDirectApiClose( DirectModeHandle);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (fSwUnmapFtRoot) {
|
|
dwErr = CmdUnmapRootReplica( OperateNameSpace.GetPathString(),
|
|
pwszServerName,
|
|
pwszShareName );
|
|
|
|
break;
|
|
}
|
|
|
|
if (fArgSiteName)
|
|
{
|
|
DfsString Site;
|
|
|
|
dwErr = GetSites( ClientForSiteName.GetString(),
|
|
&Site );
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
ShowInformation((L"\n\nSite for %wS is %wS\n\n",
|
|
ClientForSiteName.GetString(),
|
|
Site.GetString()));
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (fSwInsite || fSwSiteCosting || fSwRootScalability)
|
|
{
|
|
PVOID DirectModeHandle = NULL;
|
|
ULONG Attrib = 0;
|
|
ULONG AttribMask = 0;
|
|
LPWSTR AttribString;
|
|
|
|
if (fSwInsite)
|
|
{
|
|
AttribMask = PKT_ENTRY_TYPE_INSITE_ONLY;
|
|
AttribString = L"InSite Referrals";
|
|
}
|
|
else if (fSwSiteCosting)
|
|
{
|
|
AttribMask = PKT_ENTRY_TYPE_COST_BASED_SITE_SELECTION;
|
|
AttribString = L"Cost-based Site Selection";
|
|
}
|
|
else
|
|
{
|
|
AttribMask = PKT_ENTRY_TYPE_ROOT_SCALABILITY;
|
|
AttribString = L"Root Scalability";
|
|
}
|
|
|
|
dwErr = DfsDirectApiOpen( OperateNameSpace.GetPathString(),
|
|
DCToUse,
|
|
&DirectModeHandle);
|
|
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
|
|
dwErr = DfsExtendedRootAttributes( DirectModeHandle,
|
|
&Attrib,
|
|
OperateNameSpace.GetRemainingCountedString(),
|
|
FALSE );
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
if (fSwDisplay) {
|
|
MyPrintf(L"Namespace %ws: %ws %ws\n",
|
|
OperateNameSpace.GetPathString(),
|
|
AttribString,
|
|
((Attrib & AttribMask) == AttribMask) ? L"ENABLED" : L"DISABLED");
|
|
} else {
|
|
|
|
SetDirectHandleWriteable(DirectModeHandle);
|
|
|
|
if (fSwEnable) Attrib |= AttribMask;
|
|
else Attrib &= ~AttribMask;
|
|
|
|
dwErr = DfsExtendedRootAttributes( DirectModeHandle,
|
|
&Attrib,
|
|
OperateNameSpace.GetRemainingCountedString(),
|
|
TRUE );
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
dwErr = DfsDirectApiCommitChanges( DirectModeHandle);
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
(VOID) ReSynchronizeRootTargetsFromPath(&OperateNameSpace);
|
|
}
|
|
}
|
|
}
|
|
|
|
DfsDirectApiClose( DirectModeHandle);
|
|
}
|
|
else if (fSwInsite)
|
|
{
|
|
DWORD PrevErr = dwErr; // Save this error in case of failure
|
|
|
|
DebugInformation((L"Failure getting Windows .Net ExtendedAttributes for %wZ, Status 0x%x\n",
|
|
OperateNameSpace.GetPathCountedString(), dwErr));
|
|
|
|
// Get the existing attrs. The root name will have to match although it's win2k.
|
|
dwErr = DfsExtendedWin2kRootAttributes( &OperateNameSpace, &Attrib, FALSE );
|
|
if (dwErr == ERROR_SUCCESS)
|
|
{
|
|
if (fSwDisplay) {
|
|
MyPrintf(L"Namespace %ws: %ws %ws\n",
|
|
OperateNameSpace.GetPathString(),
|
|
AttribString,
|
|
((Attrib & AttribMask) == AttribMask) ? L"ENABLED" : L"DISABLED");
|
|
}
|
|
else
|
|
{
|
|
if (fSwEnable) Attrib |= AttribMask;
|
|
else Attrib &= ~AttribMask;
|
|
|
|
// Set or reset this attr.
|
|
dwErr = DfsExtendedWin2kRootAttributes( &OperateNameSpace, &Attrib, TRUE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we couldn't find a win2k root by this name, then return the original error.
|
|
//
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwErr = PrevErr;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (fSwPurgeMupCache) {
|
|
|
|
dwErr = PurgeMupCache(NULL);
|
|
break;
|
|
}
|
|
|
|
dwErr = Usage();
|
|
|
|
} while( FALSE );
|
|
|
|
|
|
|
|
if (CoInitialized)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
if (CommandSucceeded) {
|
|
ErrorMessage( MSG_SUCCESSFUL );
|
|
} else {
|
|
ErrorMessage( MSG_COMMAND_DONE );
|
|
}
|
|
} else {
|
|
LPWSTR MessageBuffer;
|
|
DWORD dwBufferLength;
|
|
|
|
dwBufferLength = FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
dwErr,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPWSTR) &MessageBuffer,
|
|
0,
|
|
NULL);
|
|
|
|
ErrorMessage(MSG_ERROR, dwErr);
|
|
if (dwBufferLength > 0) {
|
|
MyPrintf(L"%ws\r\n", MessageBuffer);
|
|
LocalFree(MessageBuffer);
|
|
}
|
|
ErrorMessage( MSG_COMMAND_DONE );
|
|
}
|
|
WPP_CLEANUP();
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//
|
|
// This is a laborious function that checks the current
|
|
// argument for a match. DfsDbgPrints here are just
|
|
// examples of random optimism: the /Verbose option has to
|
|
// come before the current argument in order for those
|
|
// lines to get printed.
|
|
//
|
|
BOOLEAN
|
|
CmdProcessArg(LPWSTR Arg)
|
|
{
|
|
LONG ArgLen;
|
|
BOOLEAN Terminate = FALSE;
|
|
BOOLEAN FoundAnArg = FALSE;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
if ( Arg != NULL && wcslen(Arg) > 1) {
|
|
|
|
Terminate = FALSE;
|
|
ArgLen = wcslen(Arg);
|
|
|
|
if (_wcsnicmp(Arg, ArgRemFtRoot, ArgLenRemFtRoot) == 0) {
|
|
FoundAnArg = fArgRemFtRoot = TRUE;
|
|
if (ArgLen > ArgLenRemFtRoot)
|
|
pwszLogicalName = &Arg[ArgLenRemFtRoot];
|
|
} else if (_wcsnicmp(Arg, ArgShare, ArgLenShare) == 0) {
|
|
FoundAnArg = fArgShare = TRUE;
|
|
if (ArgLen > ArgLenShare)
|
|
pwszShareName = &Arg[ArgLenShare];
|
|
if (pwszLogicalName == NULL)
|
|
pwszLogicalName = pwszShareName;
|
|
} else if (_wcsnicmp(Arg, ArgServer, ArgLenServer) == 0) {
|
|
FoundAnArg = fArgServer = TRUE;
|
|
if (ArgLen > ArgLenServer)
|
|
pwszServerName = &Arg[ArgLenServer];
|
|
} else if (_wcsnicmp(Arg, ArgDomain, ArgLenDomain) == 0) {
|
|
FoundAnArg = fArgDomain = TRUE;
|
|
if (ArgLen > ArgLenDomain)
|
|
pwszDomainName = &Arg[ArgLenDomain];
|
|
} else if (_wcsnicmp(Arg, ArgPktFlush, ArgLenPktFlush) == 0) {
|
|
FoundAnArg = fArgPktFlush = TRUE;
|
|
if (ArgLen > ArgLenPktFlush)
|
|
pwszEntryToFlush = &Arg[ArgLenPktFlush];
|
|
} else if (_wcsnicmp(Arg, ArgSpcFlush, ArgLenSpcFlush) == 0) {
|
|
FoundAnArg = fArgSpcFlush = TRUE;
|
|
if (ArgLen > ArgLenSpcFlush)
|
|
pwszEntryToFlush = &Arg[ArgLenSpcFlush];
|
|
} else if (_wcsnicmp(Arg, ArgLevel, ArgLenLevel) == 0) {
|
|
FoundAnArg = fArgLevel = TRUE;
|
|
if (ArgLen > ArgLenLevel)
|
|
pwszHexValue = &Arg[ArgLenLevel];
|
|
}
|
|
|
|
//
|
|
// DfsAdmin options
|
|
//
|
|
|
|
else if (_wcsnicmp(Arg, ArgImport, ArgLenImport) == 0)
|
|
{
|
|
FoundAnArg = fArgImport = TRUE;
|
|
ImportFile = &Arg[ArgLenImport];
|
|
if (wcslen(ImportFile) == 0)
|
|
{
|
|
ErrorMessage( MSG_USAGE_IMPORT );
|
|
Terminate = TRUE;
|
|
ImportFile = NULL;
|
|
}
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgDisplayBlob, ArgLenDisplayBlob) == 0)
|
|
{
|
|
FoundAnArg = fArgDisplayBlob = TRUE;
|
|
DisplayBlobFile = &Arg[ArgLenDisplayBlob];
|
|
if (wcslen(DisplayBlobFile) == 0)
|
|
{
|
|
ErrorMessage( MSG_USAGE_DISPLAY_BLOB );
|
|
Terminate = TRUE;
|
|
ImportFile = NULL;
|
|
}
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgExportBlob, ArgLenExportBlob) == 0)
|
|
{
|
|
FoundAnArg = fArgExportBlob = TRUE;
|
|
ExportBlobFile = &Arg[ArgLenExportBlob];
|
|
if (wcslen(ExportBlobFile)==0)
|
|
{
|
|
ErrorMessage( MSG_USAGE_EXPORT_BLOB );
|
|
Terminate = TRUE;
|
|
ExportBlobFile = NULL;
|
|
}
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgExport, ArgLenExport) == 0)
|
|
{
|
|
FoundAnArg = fArgExport = TRUE;
|
|
ExportFile = &Arg[ArgLenExport];
|
|
if (wcslen(ExportFile) == 0)
|
|
{
|
|
ErrorMessage( MSG_USAGE_EXPORT );
|
|
Terminate = TRUE;
|
|
ExportFile = NULL;
|
|
}
|
|
else
|
|
{
|
|
Status = CreateDfsFile(ExportFile, &ExportHandle);
|
|
}
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgBackup, ArgLenBackup) == 0)
|
|
{
|
|
FoundAnArg = fArgBackup = TRUE;
|
|
BackupFile = &Arg[ArgLenBackup];
|
|
if (wcslen(BackupFile) == 0)
|
|
{
|
|
ErrorMessage( MSG_USAGE_EXPORT );
|
|
Terminate = TRUE;
|
|
BackupFile = NULL;
|
|
}
|
|
else
|
|
{
|
|
Status = CreateDfsFile(BackupFile, &BackupHandle);
|
|
}
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgDebugDC, ArgLenDebugDC) == 0)
|
|
{
|
|
FoundAnArg = fArgDebugDC = TRUE;
|
|
DCToUse = &Arg[ArgLenDebugDC];
|
|
Status = GetDCInformation();
|
|
Mode = MODE_DIRECT;
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgRoot, ArgLenRoot) == 0)
|
|
{
|
|
FoundAnArg = fArgRoot = TRUE;
|
|
Status = OperateNameSpace.CreatePathName(&Arg[ArgLenRoot]);
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgImportRoot, ArgLenImportRoot) == 0)
|
|
{
|
|
FoundAnArg = fArgImportRoot = TRUE;
|
|
Status = MasterNameSpace.CreatePathName(&Arg[ArgLenImportRoot]);
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgDebugFile, ArgLenDebugFile) == 0)
|
|
{
|
|
FoundAnArg = fArgDebugFile = TRUE;
|
|
DebugFile = &Arg[ArgLenDebugFile];
|
|
if (wcslen(DebugFile) == 0)
|
|
{
|
|
//Status = ERROR_INVALID_PARAMETER;
|
|
Terminate = TRUE;
|
|
DebugFile = NULL;
|
|
}
|
|
else {
|
|
Status = CreateDfsFile(DebugFile, &DebugHandle);
|
|
}
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgOldDomain, ArgLenOldDomain) == 0)
|
|
{
|
|
FoundAnArg = fArgOldDomain = TRUE;
|
|
Status = OldDomainName.CreatePathName( &Arg[ArgLenOldDomain] );
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgNewDomain, ArgLenNewDomain) == 0)
|
|
{
|
|
FoundAnArg = fArgNewDomain = TRUE;
|
|
Status = NewDomainName.CreatePathName( &Arg[ArgLenNewDomain] );
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgUnmapFtRoot, ArgLenUnmapFtRoot) == 0)
|
|
{
|
|
FoundAnArg = fArgUnmapFtRoot = TRUE;
|
|
}
|
|
else if (_wcsnicmp(Arg, ArgViewDfsDirs, ArgLenViewDfsDirs) == 0) {
|
|
FoundAnArg = fArgViewDfsDirs = TRUE;
|
|
pwszVolumeName = &Arg[ArgLenViewDfsDirs];
|
|
}/*
|
|
else if (_wcsnicmp(Arg, ArgRemoveReparse, ArgLenRemoveReparse) == 0) {
|
|
FoundAnArg = fArgRemoveReparse = TRUE;
|
|
pwszDfsDirectoryName = &Arg[ArgLenRemoveReparse];
|
|
}*/
|
|
else if (_wcsnicmp(Arg, ArgSiteName, ArgLenSiteName) == 0)
|
|
{
|
|
FoundAnArg = fArgSiteName = TRUE;
|
|
Status = ClientForSiteName.CreateString(&Arg[ArgLenSiteName]);
|
|
}
|
|
|
|
|
|
|
|
// Switches go at the end!!
|
|
|
|
else if (_wcsicmp(Arg, SwDebug) == 0) {
|
|
FoundAnArg = fSwDebug = TRUE;
|
|
}
|
|
else if (_wcsicmp(Arg, SwNoBackup) == 0) {
|
|
FoundAnArg = fSwNoBackup = TRUE;
|
|
} else if (_wcsicmp(Arg, SwVerbose) == 0) {
|
|
FoundAnArg = fSwVerbose = TRUE;
|
|
} else if (_wcsicmp(Arg, SwPktFlush) == 0) {
|
|
FoundAnArg = fSwPktFlush = TRUE;
|
|
} else if (_wcsicmp(Arg, SwSpcFlush) == 0) {
|
|
FoundAnArg = fSwSpcFlush = TRUE;
|
|
} else if (_wcsicmp(Arg, SwPktInfo) == 0) {
|
|
FoundAnArg = fSwPktInfo = TRUE;
|
|
} else if (_wcsicmp(Arg, SwSpcInfo) == 0) {
|
|
FoundAnArg = fSwSpcInfo = TRUE;
|
|
} else if (_wcsicmp(Arg, SwDfs) == 0) {
|
|
FoundAnArg = fSwDfs = TRUE;
|
|
} else if (_wcsicmp(Arg, SwAll) == 0) {
|
|
FoundAnArg = fSwSpcInfo = TRUE;
|
|
} else if (_wcsicmp(Arg, SwQ) == 0) {
|
|
FoundAnArg = fSwQ = fSwHelp = TRUE;
|
|
} else if (_wcsicmp(Arg, SwScriptHelp) == 0) {
|
|
FoundAnArg = fSwScriptHelp = TRUE;
|
|
} else if (_wcsicmp(Arg, SwHelp) == 0) {
|
|
FoundAnArg = fSwHelp = TRUE;
|
|
} else if (_wcsicmp(Arg, SwSet) == 0) {
|
|
FoundAnArg = fSwSet = TRUE;
|
|
} else if (_wcsicmp(Arg, SwMirror) == 0) {
|
|
FoundAnArg = fSwMirror = TRUE;
|
|
} else if (_wcsicmp(Arg, SwRemStdRoot) == 0) {
|
|
FoundAnArg = fSwRemStdRoot = TRUE;
|
|
} else if (_wcsicmp(Arg, SwRemFtRoot) == 0) {
|
|
FoundAnArg = fSwRemFtRoot = TRUE;
|
|
} else if (_wcsicmp(Arg, SwCompare) == 0) {
|
|
FoundAnArg = fSwCompare = TRUE;
|
|
} else if (_wcsicmp(Arg, SwCheckBlob) == 0) {
|
|
FoundAnArg = fSwCheckBlob = TRUE;
|
|
} else if (_wcsicmp(Arg, SwMerge) == 0) {
|
|
FoundAnArg = fSwMerge = TRUE;
|
|
} else if (_wcsicmp(Arg, SwRenameFtRoot) == 0) {
|
|
FoundAnArg = fSwRenameFtRoot = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
} else if (_wcsicmp(Arg, SwDirect) == 0) {
|
|
//
|
|
// This is switched on by default when appropriate.
|
|
// If the user specifies this then it means that
|
|
// she only wants to operate in Direct mode.
|
|
//
|
|
FoundAnArg = TRUE;
|
|
fSwDirect = TRUE;
|
|
UserRequiresDirectMode = TRUE;
|
|
Mode = MODE_DIRECT;
|
|
} else if (_wcsicmp(Arg, SwView) == 0) {
|
|
FoundAnArg = fSwView = TRUE;
|
|
ExportHandle = ShowHandle;
|
|
} else if (_wcsicmp(Arg, SwImport) == 0) {
|
|
FoundAnArg = fSwImport = TRUE;
|
|
} else if (_wcsicmp(Arg, SwImportRoot) == 0) {
|
|
FoundAnArg = fSwImportRoot = TRUE;
|
|
} else if (_wcsicmp(Arg, SwBlobSize) == 0) {
|
|
FoundAnArg = fSwBlobSize = TRUE;
|
|
} else if (_wcsicmp(Arg, SwSiteName) == 0) {
|
|
FoundAnArg = fSwSiteName = TRUE;
|
|
} else if (_wcsicmp(Arg, SwExport) == 0) {
|
|
FoundAnArg = fSwExport = TRUE;
|
|
} else if (_wcsicmp(Arg, SwRoot) == 0) {
|
|
FoundAnArg = fSwRoot = TRUE;
|
|
} else if ((_wcsicmp(Arg, SwUnmapFtRoot) == 0) ||
|
|
(_wcsicmp(Arg, SwUnmap) == 0)) {
|
|
FoundAnArg = fSwUnmapFtRoot = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
} else if (_wcsicmp(Arg, SwClean) == 0) {
|
|
//
|
|
// This contacts the target registry directly but doesn't involve a
|
|
// direct mode to do so.
|
|
//
|
|
FoundAnArg = fSwClean = TRUE;
|
|
} else if (_wcsicmp(Arg, SwEnable) == 0) {
|
|
FoundAnArg = fSwEnable = TRUE;
|
|
} else if (_wcsicmp(Arg, SwDisable) == 0) {
|
|
FoundAnArg = fSwDisable = TRUE;
|
|
} else if (_wcsicmp(Arg, SwDisplay) == 0) {
|
|
FoundAnArg = fSwDisplay = TRUE;
|
|
} else if (_wcsicmp(Arg, SwInsite) == 0) {
|
|
FoundAnArg = fSwInsite = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
|
|
} else if (_wcsicmp(Arg, SwAddStdRoot) == 0) {
|
|
FoundAnArg = fSwAddStdRoot = TRUE;
|
|
} else if (_wcsicmp(Arg, SwAddFtRoot) == 0) {
|
|
FoundAnArg = fSwAddFtRoot = TRUE;
|
|
} else if (_wcsicmp(Arg, SwApi) == 0) {
|
|
FoundAnArg = fSwApi = TRUE;
|
|
Mode = MODE_API;
|
|
} else if (_wcsicmp(Arg, SwRemoveReparse) == 0) {
|
|
FoundAnArg = fSwRemoveReparse = TRUE;
|
|
} else if (_wcsicmp(Arg, SwSiteCosting) == 0) {
|
|
FoundAnArg = fSwSiteCosting = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
} else if (_wcsicmp(Arg, SwRootScalability) == 0) {
|
|
FoundAnArg = fSwRootScalability = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
} else if (_wcsicmp(Arg, SwPurgeMupCache) == 0) {
|
|
FoundAnArg = fSwPurgeMupCache = TRUE;
|
|
}
|
|
else if (_wcsicmp(Arg, SwUpdateWin2kStaticSiteTable) == 0) {
|
|
FoundAnArg = fSwUpdateWin2kStaticSiteTable = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
}
|
|
else if (_wcsicmp(Arg, SwShowWin2kStaticSiteTable) == 0) {
|
|
FoundAnArg = fSwShowWin2kStaticSiteTable = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
}
|
|
else if (_wcsicmp(Arg, SwPurgeWin2kStaticSiteTable) == 0) {
|
|
FoundAnArg = fSwPurgeWin2kStaticSiteTable = TRUE;
|
|
CmdRequiresDirect = TRUE;
|
|
}
|
|
else if (_wcsicmp(Arg, SwViewDfsDirs) == 0) {
|
|
FoundAnArg = fSwViewDfsDirs = TRUE;
|
|
}
|
|
else if (_wcsicmp(Arg, SwDisplayBlob) == 0) {
|
|
FoundAnArg = fSwDisplayBlob = TRUE;
|
|
}
|
|
else if (_wcsicmp(Arg, SwExportBlob) == 0) {
|
|
FoundAnArg = fSwExportBlob = TRUE;
|
|
}
|
|
|
|
//
|
|
// Done processing Arguments and Switches.
|
|
// Decide whether to terminate or not.
|
|
//
|
|
if (FoundAnArg == FALSE) {
|
|
ErrorMessage(MSG_UNRECOGNIZED_OPTION, &Arg[1]);
|
|
Terminate = TRUE;
|
|
}
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
ErrorMessage(MSG_ERROR, Status);
|
|
Terminate = TRUE;
|
|
}
|
|
}
|
|
|
|
return Terminate;
|
|
}
|
|
|
|
DWORD
|
|
Usage()
|
|
{
|
|
|
|
ErrorMessage(MSG_USAGE);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DFSSTATUS
|
|
CmdCheckSyntax( BOOLEAN& Done )
|
|
{
|
|
|
|
// the following require a namespace to work with
|
|
// BlobSize cmd works without a root.
|
|
#define REQUIRES_ROOT_NAME (fArgExport || fSwRenameFtRoot || fSwInsite || fSwMirror || \
|
|
(fArgImport && !fSwBlobSize) || \
|
|
fSwSiteCosting || fArgDebugDC || \
|
|
fArgImportRoot || fSwRootScalability || \
|
|
fArgExportBlob || fSwCheckBlob)
|
|
|
|
DFSSTATUS dwErr = ERROR_SUCCESS;
|
|
Done = FALSE;
|
|
|
|
do {
|
|
if ((fSwHelp == TRUE) ||
|
|
((OperateNameSpace.IsEmptyPath() == TRUE) && (REQUIRES_ROOT_NAME) ))
|
|
{
|
|
|
|
if (fArgImport || fSwImport || fSwBlobSize) {
|
|
ErrorMessage( MSG_USAGE_IMPORT );
|
|
} else if (fArgExport || fSwExport) {
|
|
ErrorMessage( MSG_USAGE_EXPORT );
|
|
} else if (fSwRenameFtRoot) {
|
|
ErrorMessage( MSG_USAGE_RENAME );
|
|
} else if (fSwUnmapFtRoot) {
|
|
ErrorMessage( MSG_USAGE_UNMAP );
|
|
} else if (fSwClean) {
|
|
ErrorMessage( MSG_USAGE_CLEAN );
|
|
} else if (fSwInsite) {
|
|
ErrorMessage( MSG_USAGE_INSITE );
|
|
} else if (fSwSiteCosting) {
|
|
ErrorMessage( MSG_USAGE_SITECOSTING );
|
|
} else if (fSwAddFtRoot || fSwAddStdRoot) {
|
|
ErrorMessage( MSG_USAGE_ADDROOT );
|
|
} else if (fSwRemFtRoot || fArgRemFtRoot) {
|
|
ErrorMessage( MSG_USAGE_REM_FTROOT );
|
|
} else if (fSwRemStdRoot) {
|
|
ErrorMessage( MSG_USAGE_REM_STDROOT );
|
|
} else if (fArgSiteName || fSwSiteName) {
|
|
ErrorMessage( MSG_USAGE_SITENAME );
|
|
} else if (fSwView) {
|
|
ErrorMessage( MSG_USAGE_VIEW );
|
|
} else if (fArgImportRoot || fSwImportRoot) {
|
|
ErrorMessage( MSG_USAGE_IMPORT_ROOT);
|
|
} else if (fSwCheckBlob) {
|
|
ErrorMessage( MSG_USAGE_CHECK_BLOB );
|
|
} else if (fSwExportBlob || fArgExportBlob) {
|
|
ErrorMessage( MSG_USAGE_EXPORT_BLOB );
|
|
} else if (fSwDisplayBlob || fArgDisplayBlob) {
|
|
ErrorMessage( MSG_USAGE_DISPLAY_BLOB );
|
|
} else if (fSwRootScalability) {
|
|
ErrorMessage( MSG_USAGE_ROOT_SCALABILITY );
|
|
} else if (fSwViewDfsDirs || fArgViewDfsDirs) {
|
|
ErrorMessage( MSG_USAGE_VIEW_DIRS );
|
|
} else if (fSwRemoveReparse) {
|
|
ErrorMessage( MSG_USAGE_VIEW_DIRS );
|
|
} else if (fSwPurgeMupCache) {
|
|
ErrorMessage( MSG_USAGE_PURGE_MUP_CACHE );
|
|
} else if (fSwUpdateWin2kStaticSiteTable ||
|
|
fSwPurgeWin2kStaticSiteTable ||
|
|
fSwShowWin2kStaticSiteTable) {
|
|
ErrorMessage( MSG_USAGE_W2K_SITETABLE );
|
|
} else if (fSwPktInfo) {
|
|
ErrorMessage( MSG_USAGE_PKT_INFO );
|
|
} else if (fSwPktFlush) {
|
|
ErrorMessage( MSG_USAGE_PKT_FLUSH );
|
|
} else if (fSwSpcInfo) {
|
|
ErrorMessage( MSG_USAGE_SPC_INFO );
|
|
} else if (fSwSpcFlush) {
|
|
ErrorMessage( MSG_USAGE_SPC_FLUSH );
|
|
} else {
|
|
dwErr = Usage();
|
|
}
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (fSwView)
|
|
{
|
|
if (!(fArgDomain || fArgRoot || fArgServer || fArgImport))
|
|
{
|
|
ErrorMessage(MSG_USAGE_VIEW);
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Set, merge and verify work with import.
|
|
if (fArgImport) {
|
|
|
|
if (!(fSwSet || fSwMerge || fSwCompare || fSwView || fSwBlobSize)) {
|
|
|
|
MyPrintf(L"You must specify one of /View, /Set, /Merge, /BlobSize or /Compare to Import\n");
|
|
ErrorMessage( MSG_USAGE_IMPORT );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (fSwInsite) {
|
|
if (!(fSwEnable || fSwDisable || fSwDisplay)) {
|
|
MyPrintf(L"You must specify one of /Enable, /Disable or /Display with /Insite command.\n");
|
|
ErrorMessage( MSG_USAGE_INSITE );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (OperateNameSpace.IsEmptyPath() == TRUE)
|
|
{
|
|
MyPrintf(L"You must specify a DFS root with /Insite command.\n");
|
|
ErrorMessage( MSG_USAGE_INSITE );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
if (fSwApi) {
|
|
MyPrintf(L"Insite command does not work in the /Api mode. Use default.\n");
|
|
ErrorMessage( MSG_USAGE_INSITE );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
} else if (fSwSiteCosting) {
|
|
if (!(fSwEnable || fSwDisable || fSwDisplay)) {
|
|
MyPrintf(L"You must specify one of /Enable, /Disable or /Display with /SiteCosting command.\n");
|
|
ErrorMessage( MSG_USAGE_SITECOSTING );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
if ((OperateNameSpace.IsEmptyPath() == TRUE) ||
|
|
(IsEmptyString(OperateNameSpace.GetRemainingString()) == FALSE))
|
|
{
|
|
MyPrintf(L"You must specify a well-formed DFS root with /SiteCosting command.\n");
|
|
ErrorMessage( MSG_USAGE_SITECOSTING );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (fSwApi) {
|
|
MyPrintf(L"SiteCosting command does not work in the /Api mode. Use default.\n");
|
|
ErrorMessage( MSG_USAGE_SITECOSTING );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
} else if (fSwRootScalability) {
|
|
if (!(fSwEnable || fSwDisable || fSwDisplay)) {
|
|
MyPrintf(L"You must specify one of /Enable, /Disable or /Display with /RootScalability command.\n");
|
|
// ErrorMessage( MSG_USAGE_ROOTSCALABILITY);
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
if ((OperateNameSpace.IsEmptyPath() == TRUE) ||
|
|
(IsEmptyString(OperateNameSpace.GetRemainingString()) == FALSE))
|
|
{
|
|
MyPrintf(L"You must specify a DFS root with /RootScalability command.\n");
|
|
// ErrorMessage( MSG_USAGE_ROOTSCALABILITY);
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (fSwApi) {
|
|
MyPrintf(L"RootScalability command does not work in the /Api mode. Use default.\n");
|
|
// ErrorMessage( MSG_USAGE_ROOTSCALABILITY);
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// These three dont work with any other command (except for /Set with Insite).
|
|
else if ((fSwSet || fSwMerge) &&
|
|
(!fArgImport)) {
|
|
|
|
MyPrintf(L"/Set and /Merge options apply only to /Import: command.\n");
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
else if ((fSwMirror) &&
|
|
(!fArgImportRoot)) {
|
|
|
|
MyPrintf(L"/Mirror option applies only to /ImportRoot: command.\n");
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
else if ((fSwCompare) &&
|
|
((!fArgImportRoot) && (!fArgImport))) {
|
|
|
|
MyPrintf(L"/Compare option applies only to /Import: or /ImportRoot: commands.\n");
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
|
|
if ((fSwView) &&
|
|
(fArgExport || fSwRenameFtRoot)) {
|
|
|
|
MyPrintf(L"The /View command cannot be combined with others.\n");
|
|
Usage();
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (fSwRenameFtRoot) {
|
|
|
|
if (NewDomainName.IsEmptyPath() == TRUE ||
|
|
OldDomainName.IsEmptyPath() == TRUE ||
|
|
(OperateNameSpace.IsEmptyPath() == TRUE))
|
|
{
|
|
ErrorMessage( MSG_USAGE_RENAME );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
DebugInformation((L"DfsUtil: New domain name will be %wS\n", NewDomainName.GetServerString()));
|
|
DebugInformation((L"DfsUtil: Old domain to be renamed is %wS\n", OldDomainName.GetServerString()));
|
|
}
|
|
|
|
|
|
|
|
if ((fArgUnmapFtRoot) || // Arg gets an automatic usage.
|
|
|
|
((fSwUnmapFtRoot) &&
|
|
( (OperateNameSpace.IsEmptyPath() == TRUE) ||
|
|
(pwszServerName == NULL) ||
|
|
(pwszShareName == NULL)))) {
|
|
|
|
ErrorMessage( MSG_USAGE_UNMAP );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ((fArgClean) || // Arg gets an automatic usage.
|
|
|
|
((fSwClean) &&
|
|
((pwszServerName == NULL) ||
|
|
(pwszShareName == NULL)))) {
|
|
|
|
ErrorMessage( MSG_USAGE_CLEAN );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (fSwClean)
|
|
{
|
|
DWORD Status;
|
|
|
|
//
|
|
// We don't allow domain names here. That can lead to incorrect
|
|
// results as well as data loss.
|
|
//
|
|
Status = IsThisADomainName( pwszServerName, NULL );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
MyPrintf(L"/Server: parameter must be the name of a DFS root server. It cannot be a domain name\n");
|
|
ErrorMessage( MSG_USAGE_CLEAN );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( fSwAddStdRoot &&
|
|
(IsEmptyString( pwszServerName ) || IsEmptyString( pwszShareName ))) {
|
|
MyPrintf(L"You must specify a valid target server and a share for the new root\n");
|
|
ErrorMessage( MSG_USAGE_ADDROOT );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if ((fArgRemFtRoot || fSwRemFtRoot || fSwRemStdRoot) &&
|
|
(IsEmptyString( pwszServerName ) || IsEmptyString( pwszShareName ))) {
|
|
|
|
MyPrintf(L"You must specify a valid target server and a share to remove.\n");
|
|
if (fSwRemStdRoot)
|
|
ErrorMessage( MSG_USAGE_REM_STDROOT );
|
|
else
|
|
ErrorMessage( MSG_USAGE_REM_FTROOT );
|
|
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
/*if ((fArgRemoveReparse) && // Arg gets an automatic usage.
|
|
|
|
(pwszDfsDirectoryName == NULL)) {
|
|
MyPrintf(L"You must specify a volume name\n");
|
|
Done = TRUE;
|
|
break;
|
|
}*/
|
|
|
|
if (fArgViewDfsDirs) {
|
|
if (pwszVolumeName == NULL) {
|
|
MyPrintf(L"You must specify a directory name\n");
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
if (wcschr(pwszVolumeName, ':') == NULL) {
|
|
MyPrintf(L"The volume drive letter must contain a colon at the end.\n");
|
|
ErrorMessage( MSG_USAGE_VIEW_DIRS );
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If at this point we have a root:\\x\y, we need to make sure that we have
|
|
// exactly two path components. It is too cumbersome to use REQUIRES_ROOT_NAME
|
|
// check here because there are options like /View that needs /Root only for some cases.
|
|
//
|
|
if ((OperateNameSpace.IsEmptyPath() != TRUE) &&
|
|
((IsEmptyString(OperateNameSpace.GetShareString()) == TRUE) ||
|
|
(IsEmptyString(OperateNameSpace.GetRemainingString()) == FALSE)) &&
|
|
(fSwInsite == FALSE))
|
|
{
|
|
MyPrintf(L"Root must be of the form \\\\DomainOrServer\\RootName.\n");
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (OperateNameSpace.IsEmptyPath() != TRUE)
|
|
{
|
|
//
|
|
// Now that we have valid args, check to see if there are any exceptions to
|
|
// the rules we've applied so far. For example, we Standalone roots
|
|
// and Direct mode won't mix well for some switches of /Import cmd.
|
|
//
|
|
dwErr = CmdCheckExceptions( &OperateNameSpace );
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (MasterNameSpace.IsEmptyPath() != TRUE)
|
|
{
|
|
dwErr = CmdCheckExceptions( &MasterNameSpace );
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fArgDebugDC != NULL)
|
|
{
|
|
if (DCInfoStatus != ERROR_SUCCESS)
|
|
{
|
|
MyPrintf(L"Could not get information from DC %wS, error 0x%x\n",
|
|
DCToUse, DCInfoStatus);
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
if (OperateNameSpace.IsEmptyPath() != TRUE)
|
|
{
|
|
if (DfsIsThisADomainName(OperateNameSpace.GetServerString()) == ERROR_SUCCESS)
|
|
{
|
|
if ((RtlCompareUnicodeString(OperateNameSpace.GetServerCountedString(), &DCToUseFlatDomainName, TRUE) != 0)
|
|
&&
|
|
(RtlCompareUnicodeString(OperateNameSpace.GetServerCountedString(), &DCToUseDNSDomainName, TRUE) != 0))
|
|
{
|
|
MyPrintf(L"DC %ws belongs to %wZ domain, and not to %wS domain\n",
|
|
DCToUse, &DCToUseDNSDomainName, OperateNameSpace.GetServerString());
|
|
|
|
Done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (MasterNameSpace.IsEmptyPath() != TRUE)
|
|
{
|
|
if (DfsIsThisADomainName(MasterNameSpace.GetServerString()) == ERROR_SUCCESS)
|
|
{
|
|
if ((RtlCompareUnicodeString(MasterNameSpace.GetServerCountedString(), &DCToUseFlatDomainName, TRUE) != 0)
|
|
&&
|
|
(RtlCompareUnicodeString(MasterNameSpace.GetServerCountedString(), &DCToUseDNSDomainName, TRUE) != 0))
|
|
{
|
|
MyPrintf(L"DC %ws belongs to %wZ domain, and not to %wS domain\n",
|
|
DCToUse, &DCToUseDNSDomainName, MasterNameSpace.GetServerString());
|
|
Done = TRUE;
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
DFSSTATUS
|
|
CmdInitializeDirectMode(
|
|
PBOOLEAN pCoInitialized)
|
|
{
|
|
DFSSTATUS Status;
|
|
HRESULT Hr = S_OK;
|
|
|
|
*pCoInitialized = FALSE;
|
|
|
|
Hr = CoInitializeEx(NULL,COINIT_MULTITHREADED| COINIT_DISABLE_OLE1DDE);
|
|
if (Hr == S_OK)
|
|
{
|
|
*pCoInitialized = TRUE;
|
|
Status = DfsServerLibraryInitialize(DFS_DIRECT_MODE|DFS_DONT_SUBSTITUTE_PATHS);
|
|
}
|
|
else
|
|
{
|
|
Status = DfsGetErrorFromHr(Hr);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ReSynchronizeRootTargets(
|
|
IN LPWSTR PathString)
|
|
{
|
|
DfsPathName PathName;
|
|
DFSSTATUS Status;
|
|
|
|
Status = PathName.CreatePathName(PathString);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = ReSynchronizeRootTargetsFromPath(&PathName);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ReSynchronizeRootTargetsFromPath(
|
|
IN DfsPathName *pPathName)
|
|
{
|
|
DFSSTATUS Status, SetStatus;
|
|
LPBYTE pBuffer = NULL;
|
|
DWORD ResumeHandle = 0;
|
|
DWORD EntriesRead = 0;
|
|
DWORD PrefMaxLen = 1;
|
|
DWORD Level = 4;
|
|
PDFS_INFO_4 pCurrentBuffer;
|
|
DWORD i;
|
|
PDFS_STORAGE_INFO pStorage;
|
|
LPWSTR DfsPathString;
|
|
|
|
DfsPathString = pPathName->GetPathString();
|
|
//
|
|
// We are reading in just the ROOT.
|
|
//
|
|
Status = DfsApiEnumerate( MODE_DIRECT,
|
|
DfsPathString,
|
|
Level,
|
|
PrefMaxLen,
|
|
&pBuffer,
|
|
&EntriesRead,
|
|
&ResumeHandle);
|
|
|
|
if ((Status == ERROR_SUCCESS) && EntriesRead != 0)
|
|
{
|
|
pCurrentBuffer = (PDFS_INFO_4)pBuffer;
|
|
|
|
//
|
|
// Now contact the appropriate server(s) for the root replicas
|
|
// and ask them to re-read their roots. Things have been
|
|
// changed under them.
|
|
//
|
|
|
|
for( i = 0, pStorage = pCurrentBuffer->Storage;
|
|
i < pCurrentBuffer->NumberOfStorages;
|
|
i++, pStorage = pCurrentBuffer->Storage + i )
|
|
{
|
|
SetStatus = SetInfoReSynchronize( pStorage->ServerName,
|
|
pPathName->GetShareString());
|
|
|
|
//
|
|
// We just go on to the next server since we don't do any undo's anyway.
|
|
//
|
|
if (SetStatus != ERROR_SUCCESS)
|
|
Status = SetStatus;
|
|
}
|
|
|
|
//
|
|
// Free the allocated memory.
|
|
//
|
|
|
|
DfsFreeApiBuffer(pBuffer);
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// the following code exists to read and write the old style static
|
|
// site table in the AD blob.
|
|
//
|
|
//
|
|
typedef struct _DFS_SITE_UPDATE
|
|
{
|
|
UNICODE_STRING Server;
|
|
UNICODE_STRING Site;
|
|
struct _DFS_SITE_UPDATE *pNext;
|
|
} DFS_SITE_UPDATE, *PDFS_SITE_UPDATE;
|
|
|
|
DFS_SITE_UPDATE *pSiteList = NULL;
|
|
PDFS_SITE_UPDATE pSiteNext = NULL;
|
|
struct _DFS_PREFIX_TABLE *pServerSiteTable;
|
|
|
|
|
|
VOID
|
|
DumpSiteInformation(
|
|
PUNICODE_STRING pServer,
|
|
PUNICODE_STRING pSite )
|
|
{
|
|
ShowInformation((L"Server %wZ, Site %wZ\n", pServer, pSite));
|
|
}
|
|
|
|
DFSSTATUS
|
|
DumpSiteBlob(
|
|
PVOID pBuffer,
|
|
ULONG Size,
|
|
BOOLEAN Display )
|
|
{
|
|
|
|
PVOID pUseBuffer = pBuffer;
|
|
ULONG RemainingSize = Size;
|
|
GUID SiteGuid;
|
|
UNICODE_STRING Server, Site;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
ULONG Objects = 0, SiteNum, NumSites, Flags;
|
|
|
|
if (Size == 0)
|
|
{
|
|
if (Display)
|
|
{
|
|
ShowInformation((L"\nSite Blob with %d sites\n", Objects));
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
Status = PackGetGuid(&SiteGuid, &pUseBuffer, &RemainingSize);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PackGetULong( &Objects, &pUseBuffer, &RemainingSize );
|
|
}
|
|
|
|
if (Display)
|
|
{
|
|
ShowInformation((L"\nSite Blob with %d sites\n", Objects));
|
|
}
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
for (SiteNum = 0; SiteNum < Objects; SiteNum++)
|
|
{
|
|
Status = PackGetString( &Server, &pUseBuffer, &RemainingSize);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PackGetULong( &NumSites, &pUseBuffer, &RemainingSize);
|
|
}
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PackGetULong( &Flags, &pUseBuffer, &RemainingSize);
|
|
}
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PackGetString( &Site, &pUseBuffer, &RemainingSize);
|
|
}
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (Display)
|
|
{
|
|
DumpSiteInformation(&Server, &Site);
|
|
}
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
AddServerToSiteList(
|
|
PUNICODE_STRING pServerName,
|
|
PUNICODE_STRING pSiteName )
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
BOOLEAN Insert = FALSE;
|
|
PDFS_SITE_UPDATE pSiteUpdate;
|
|
UNICODE_STRING RemainingName;
|
|
PVOID pData;
|
|
BOOLEAN SubStringMatch;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
NtStatus = DfsPrefixTableAcquireWriteLock( pServerSiteTable );
|
|
if ( NtStatus == STATUS_SUCCESS )
|
|
{
|
|
NtStatus = DfsFindUnicodePrefixLocked( pServerSiteTable,
|
|
pServerName,
|
|
&RemainingName,
|
|
&pData,
|
|
&SubStringMatch );
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
Insert = TRUE;
|
|
|
|
NtStatus = DfsInsertInPrefixTableLocked( pServerSiteTable,
|
|
pServerName,
|
|
pSiteName);
|
|
}
|
|
else
|
|
{
|
|
Insert = FALSE;
|
|
NtStatus = STATUS_SUCCESS;
|
|
}
|
|
DfsPrefixTableReleaseLock( pServerSiteTable );
|
|
}
|
|
|
|
if (NtStatus != STATUS_SUCCESS)
|
|
{
|
|
Status = RtlNtStatusToDosError(NtStatus);
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
if (Insert)
|
|
{
|
|
pSiteUpdate = new DFS_SITE_UPDATE;
|
|
|
|
if (pSiteUpdate == NULL)
|
|
{
|
|
Status = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = DfsCreateUnicodeString( &pSiteUpdate->Server, pServerName);
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = DfsCreateUnicodeString( &pSiteUpdate->Site, pSiteName);
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pSiteUpdate->pNext = NULL;
|
|
|
|
if (pSiteList == NULL)
|
|
{
|
|
pSiteList = pSiteUpdate;
|
|
|
|
}
|
|
else
|
|
{
|
|
pSiteNext->pNext = pSiteUpdate;
|
|
}
|
|
pSiteNext = pSiteUpdate;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
ProcessTargetForSite(
|
|
DfsTarget *pTarget )
|
|
{
|
|
PUNICODE_STRING pServer, pSite;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
for (;
|
|
pTarget != NULL;
|
|
pTarget = pTarget->GetNextTarget())
|
|
{
|
|
pServer = pTarget->GetTargetServerCountedString();
|
|
pSite = pTarget->GetTargetSiteCountedString();
|
|
if (pSite->Length != 0)
|
|
{
|
|
Status = AddServerToSiteList( pServer, pSite);
|
|
}
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
ULONG
|
|
SizeSiteInformationBlob(
|
|
PDFS_SITE_UPDATE pSiteUpdate)
|
|
{
|
|
ULONG Size = 0;
|
|
|
|
Size += PackSizeString(&pSiteUpdate->Server);
|
|
Size += PackSizeULong();
|
|
Size += PackSizeULong();
|
|
Size += PackSizeString(&pSiteUpdate->Site);
|
|
|
|
return Size;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
UpdateSiteBlob(
|
|
DfsRoot *pRoot)
|
|
{
|
|
PDFS_SITE_UPDATE pSiteUpdate;
|
|
|
|
GUID NewGuid;
|
|
ULONG TotalObjects = 0;
|
|
DFSSTATUS Status;
|
|
ULONG SiteBlobSize;
|
|
PBYTE pBuffer;
|
|
PVOID pUseBuffer;
|
|
ULONG SizeRemaining;
|
|
|
|
pSiteUpdate = pSiteList;
|
|
|
|
Status = UuidCreate(&NewGuid);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
SiteBlobSize = sizeof(ULONG) + sizeof(GUID);
|
|
|
|
pSiteUpdate = pSiteList;
|
|
while (pSiteUpdate != NULL)
|
|
{
|
|
SiteBlobSize += SizeSiteInformationBlob(pSiteUpdate);
|
|
TotalObjects++;
|
|
pSiteUpdate = pSiteUpdate->pNext;
|
|
}
|
|
|
|
pBuffer = new BYTE[SiteBlobSize];
|
|
if (pBuffer == NULL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
pUseBuffer = pBuffer;
|
|
SizeRemaining = SiteBlobSize;
|
|
|
|
Status = PackSetGuid( &NewGuid, &pUseBuffer, &SizeRemaining);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PackSetULong( TotalObjects, &pUseBuffer, &SizeRemaining );
|
|
}
|
|
|
|
pSiteUpdate = pSiteList;
|
|
while (pSiteUpdate != NULL)
|
|
{
|
|
Status = PackSetString( &pSiteUpdate->Server, &pUseBuffer, &SizeRemaining );
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// We allow only 1 site information for each server.
|
|
//
|
|
Status = PackSetULong( 1, &pUseBuffer, &SizeRemaining );
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Flags: alwyas 0.
|
|
//
|
|
|
|
Status = PackSetULong( 0, &pUseBuffer, &SizeRemaining );
|
|
}
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PackSetString( &pSiteUpdate->Site, &pUseBuffer, &SizeRemaining );
|
|
}
|
|
|
|
pSiteUpdate = (PDFS_SITE_UPDATE)(pSiteUpdate->pNext);
|
|
}
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
PUNICODE_STRING pRootToUpdate = pRoot->GetLinkNameCountedString();
|
|
pRoot->SetRootApiName(pRootToUpdate);
|
|
pRoot->SetRootWriteable();
|
|
|
|
Status = pRoot->RootSetSiteBlob(pBuffer, SiteBlobSize);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = pRoot->UpdateMetadata();
|
|
}
|
|
}
|
|
|
|
delete [] pBuffer;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
DFSSTATUS
|
|
PurgeSiteBlob(
|
|
DfsRoot *pRoot)
|
|
{
|
|
PDFS_SITE_UPDATE pSiteUpdate = NULL;
|
|
|
|
GUID NewGuid;
|
|
ULONG TotalObjects = 0;
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
ULONG SiteBlobSize = 0;
|
|
PBYTE pBuffer = NULL;
|
|
PVOID pUseBuffer = NULL;
|
|
ULONG SizeRemaining = 0;
|
|
|
|
pSiteUpdate = pSiteList;
|
|
|
|
Status = UuidCreate(&NewGuid);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
SiteBlobSize = sizeof(ULONG) + sizeof(GUID);
|
|
|
|
pBuffer = new BYTE[SiteBlobSize];
|
|
if (pBuffer == NULL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
pUseBuffer = pBuffer;
|
|
SizeRemaining = SiteBlobSize;
|
|
|
|
Status = PackSetGuid( &NewGuid, &pUseBuffer, &SizeRemaining);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PackSetULong( TotalObjects, &pUseBuffer, &SizeRemaining );
|
|
}
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
PUNICODE_STRING pRootToUpdate = pRoot->GetLinkNameCountedString();
|
|
pRoot->SetRootApiName(pRootToUpdate);
|
|
pRoot->SetRootWriteable();
|
|
|
|
Status = pRoot->RootSetSiteBlob(pBuffer, SiteBlobSize);
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
pRoot->UpdateMetadata();
|
|
}
|
|
}
|
|
|
|
delete [] pBuffer;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
DFSSTATUS
|
|
ProcessRootForSite(
|
|
DfsRoot *pRoot )
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
DfsLink *pLink = NULL;
|
|
|
|
|
|
Status = DfsInitializePrefixTable( &pServerSiteTable,
|
|
FALSE,
|
|
NULL );
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
Status = ProcessTargetForSite(pRoot->GetFirstTarget());
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
for (pLink = pRoot->GetFirstLink();
|
|
pLink != NULL;
|
|
pLink = pLink->GetNextLink())
|
|
{
|
|
Status = ProcessTargetForSite( pLink->GetFirstTarget());
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = UpdateSiteBlob(pRoot);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
PurgeSiteInformationForRoot(
|
|
DfsRoot *pRoot )
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
Status = DfsInitializePrefixTable( &pServerSiteTable,
|
|
FALSE,
|
|
NULL );
|
|
if ( Status != ERROR_SUCCESS )
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
|
|
if (Status == ERROR_SUCCESS)
|
|
{
|
|
Status = PurgeSiteBlob(pRoot);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
DFSSTATUS
|
|
IsRootStandalone(
|
|
DfsPathName *Namespace,
|
|
BOOLEAN& IsStandalone )
|
|
{
|
|
DFSSTATUS Status;
|
|
LPBYTE pBuffer = NULL;
|
|
DWORD RootFlavor = 0;
|
|
|
|
IsStandalone = FALSE;
|
|
Status = NetDfsGetInfo( Namespace->GetPathCountedString()->Buffer, NULL, NULL, 3, &pBuffer );
|
|
|
|
if (Status == ERROR_SUCCESS) {
|
|
RootFlavor = ((PDFS_INFO_3)pBuffer)->State & DFS_VOLUME_FLAVORS;
|
|
|
|
//
|
|
// There is no real easy way to find out the type of a Win2K root. The FLAVORS bit
|
|
// is post-win2k. In that case, err on the safe side and return Standalone.
|
|
//
|
|
if (RootFlavor == 0)
|
|
{
|
|
DebugInformation((L"NetDfsGetInfo returns 0 for DFS_VOLUME_FLAVORS. Assuming a standalone root\n"));
|
|
IsStandalone = TRUE;
|
|
}
|
|
else if (RootFlavor == DFS_VOLUME_FLAVOR_STANDALONE)
|
|
{
|
|
IsStandalone = TRUE;
|
|
}
|
|
NetApiBufferFree( pBuffer );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsThisADomainName
|
|
//
|
|
// Synopsis: Calls the mup to have it check the special name table to see if the
|
|
// name matches a domain name. Returns a list of DC's in the domain,
|
|
// as a list of strings. The list is terminated with a double-null.
|
|
//
|
|
// Arguments: [wszName] -- Name to check
|
|
// [ppList] -- Pointer to pointer for results.
|
|
//
|
|
// Returns: [ERROR_SUCCESS] -- Name is indeed a domain name.
|
|
//
|
|
// [ERROR_FILE_NOT_FOUND] -- Name is not a domain name
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
IsThisADomainName(
|
|
IN LPWSTR wszName,
|
|
OUT PWCHAR *ppList OPTIONAL)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
UNICODE_STRING DfsDriverName;
|
|
HANDLE DriverHandle = NULL;
|
|
DWORD dwErr;
|
|
PCHAR OutBuf = NULL;
|
|
ULONG Size = 0x100;
|
|
ULONG Count = 0;
|
|
|
|
RtlInitUnicodeString(&DfsDriverName, DFS_DRIVER_NAME);
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&DfsDriverName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtCreateFile(
|
|
&DriverHandle,
|
|
SYNCHRONIZE,
|
|
&objectAttributes,
|
|
&IoStatusBlock,
|
|
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(NtStatus)) {
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
Retry:
|
|
|
|
OutBuf = (PCHAR)malloc(Size);
|
|
|
|
if (OutBuf == NULL) {
|
|
|
|
NtClose(DriverHandle);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
}
|
|
|
|
NtStatus = NtFsControlFile(
|
|
DriverHandle,
|
|
NULL, // Event,
|
|
NULL, // ApcRoutine,
|
|
NULL, // ApcContext,
|
|
&IoStatusBlock,
|
|
FSCTL_DFS_GET_SPC_TABLE,
|
|
wszName,
|
|
(wcslen(wszName) + 1) * sizeof(WCHAR),
|
|
OutBuf,
|
|
Size
|
|
);
|
|
|
|
if (NtStatus == STATUS_SUCCESS) {
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
} else if (NtStatus == STATUS_BUFFER_OVERFLOW && ++Count < 5) {
|
|
|
|
Size = *((ULONG *)OutBuf);
|
|
free(OutBuf);
|
|
goto Retry;
|
|
|
|
} else {
|
|
|
|
dwErr = ERROR_FILE_NOT_FOUND;
|
|
|
|
}
|
|
|
|
NtClose(DriverHandle);
|
|
|
|
if (ppList == NULL)
|
|
{
|
|
free(OutBuf);
|
|
OutBuf = NULL;
|
|
}
|
|
else
|
|
{
|
|
*ppList = (WCHAR *)OutBuf;
|
|
}
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
DFSSTATUS
|
|
CmdCheckExceptions(
|
|
DfsPathName *pNameSpace)
|
|
{
|
|
DFSSTATUS Status = ERROR_SUCCESS;
|
|
|
|
//
|
|
// 733898 : disable /Import and /ImportRoot writable operations
|
|
// over direct mode for standalone roots. This is so that
|
|
// we won't race with DfsSvc's synchronize and possibly
|
|
// create inconsistencies.
|
|
// Besides since direct mode registry blob updates aren't
|
|
// 'atomic' import can create inconsistencies anyway.
|
|
//
|
|
if ((fArgImport && (fSwSet || fSwMerge))
|
|
||
|
|
(fArgImportRoot && (fSwMirror)))
|
|
{
|
|
BOOLEAN IsStandalone = FALSE;
|
|
do {
|
|
Status = IsRootStandalone( pNameSpace, IsStandalone );
|
|
|
|
// Err on the safe side if we get an error doing GetInfo.
|
|
if (Status != ERROR_SUCCESS || (IsStandalone))
|
|
{
|
|
if (UserRequiresDirectMode)
|
|
{
|
|
MyPrintf(L"Import /Set, /Merge and ImportRoot /Mirror commands on Standalone roots must use API mode.\n");
|
|
ErrorMessage( MSG_USAGE_IMPORT );
|
|
Status = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
DebugInformation((L"%ws is a Standalone root. Switching to API mode for this operation.\n",
|
|
pNameSpace->GetPathCountedString()->Buffer));
|
|
Mode = MODE_API;
|
|
}
|
|
|
|
// Don't return GetInfo errors. Those aren't fatal.
|
|
Status = ERROR_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|