979 lines
25 KiB
C++
979 lines
25 KiB
C++
//+-------------------------------------------------------------------------
|
||
//
|
||
// Copyright (C) 1997, Microsoft Corporation
|
||
//
|
||
// File: csites.cxx
|
||
//
|
||
// Contents: This module contains the functions which deal with the site table
|
||
//
|
||
// History: 02-Dec-1997 JHarper Created.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
#include "headers.hxx"
|
||
#pragma hdrstop
|
||
|
||
#include "dfsmsrv.h"
|
||
#include "csites.hxx"
|
||
#include "marshal.hxx"
|
||
|
||
INIT_DFS_SITENAME_INFO_MARSHAL_INFO();
|
||
INIT_DFS_SITELIST_INFO_MARSHAL_INFO()
|
||
INIT_DFSM_SITE_ENTRY_MARSHAL_INFO();
|
||
|
||
NTSTATUS
|
||
DfsSendDelete(
|
||
LPWSTR ServerName);
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::CSites
|
||
//
|
||
// Synopsis: Constructor for CSites - Initializes, but does not load, the site table
|
||
//
|
||
// Arguments: [pwszFileName] -- Name of the folder/LDAP_OBJECT to use
|
||
// [pdwErr] -- On return, the result of initializing the instance
|
||
//
|
||
// Returns: Result returned in pdwErr argument:
|
||
//
|
||
// [ERROR_SUCCESS] -- Successfully initialized
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Out of memory.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CSites::CSites(
|
||
LPWSTR pwszFileName,
|
||
LPDWORD pdwErr)
|
||
{
|
||
DWORD dwErr = 0;
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CSites::+CSites(0x%x)\n",
|
||
this));
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("+++CSites::CSites @0x%x\n", this);
|
||
#endif
|
||
|
||
_cRef = 0;
|
||
_fDirty = FALSE;
|
||
RtlZeroMemory(&_SiteTableGuid, sizeof(GUID));
|
||
InitializeListHead(&_SiteTableHead);
|
||
|
||
_pwszFileName = new WCHAR [wcslen(pwszFileName) + 1];
|
||
|
||
if (_pwszFileName != NULL) {
|
||
wcscpy(_pwszFileName, pwszFileName);
|
||
} else {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
*pdwErr = dwErr;
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::~CSites
|
||
//
|
||
// Synopsis: Destructor for CSites - Deallocates the CSites object
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
CSites::~CSites()
|
||
{
|
||
PLIST_ENTRY pListHead;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_TRACE, "CSites::~CSites(0x%x)\n",
|
||
this));
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("---CSites::~CSites @0x%x\n", this);
|
||
#endif
|
||
|
||
ASSERT (_cRef == 0);
|
||
|
||
if (_pwszFileName) {
|
||
delete [] _pwszFileName;
|
||
}
|
||
|
||
//
|
||
// Delete the linked list of SiteInfo's
|
||
//
|
||
|
||
pListHead = &_SiteTableHead;
|
||
|
||
while (pListHead->Flink != pListHead) {
|
||
pSiteInfo = CONTAINING_RECORD(pListHead->Flink, DFSM_SITE_ENTRY, Link);
|
||
RemoveEntryList(pListHead->Flink);
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CSites::~CSites: deleting SiteInfo@0x%x\n", pSiteInfo);
|
||
#endif
|
||
delete [] pSiteInfo;
|
||
}
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::AddRef
|
||
//
|
||
// Synopsis: Increases the ref count on the in-memory site table. If the
|
||
// refcount is going from 0 to 1, an attempt is made to refresh
|
||
// the in-memory site table from storage.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
VOID
|
||
CSites::AddRef()
|
||
{
|
||
DWORD dwErr = 0;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::AddRef()\n"));
|
||
|
||
_cRef++;
|
||
|
||
if (_cRef == 1) {
|
||
|
||
dwErr = _ReadSiteTable();
|
||
|
||
_fDirty = FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::Release
|
||
//
|
||
// Synopsis: Decrease the ref count on the in-memory site table. If the
|
||
// refcount is going from 1 to 0, then attempt to flush the
|
||
// table to storage, if something has changed.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
VOID
|
||
CSites::Release()
|
||
{
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::Release()\n"));
|
||
|
||
ASSERT (_cRef > 0);
|
||
|
||
_cRef--;
|
||
|
||
if (_cRef == 0) {
|
||
|
||
if (_fDirty == TRUE) {
|
||
|
||
_WriteSiteTable();
|
||
|
||
_fDirty = FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::AddOrUpdateSiteInfo
|
||
//
|
||
// Synopsis: Adds or updates an entry in the site table.
|
||
//
|
||
// Arguments: [pServerName] -- Server name to update
|
||
// [SiteCount] -- Number of entries in pSites
|
||
// [pSites] -- pointer to array of site information.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully updated the table
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CSites::AddOrUpdateSiteInfo(
|
||
LPWSTR pServerName,
|
||
ULONG SiteCount,
|
||
PDFS_SITENAME_INFO pSites)
|
||
{
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
PDFSM_SITE_ENTRY pExistingInfo;
|
||
DWORD dwErr;
|
||
ULONG i;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::AddOrUpdateSiteInfo(%ws)\n", pServerName));
|
||
|
||
dwErr = _AllocateSiteInfo(
|
||
pServerName,
|
||
SiteCount,
|
||
pSites,
|
||
&pSiteInfo);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
//
|
||
// Only put the new entry in if it supercedes one there,
|
||
// or is a new entry.
|
||
//
|
||
pExistingInfo = LookupSiteInfo(pServerName);
|
||
if (pExistingInfo != NULL) {
|
||
if (_CompareEntries(pSiteInfo,pExistingInfo) == TRUE ) {
|
||
//
|
||
// Same info - no update needed
|
||
//
|
||
delete [] pSiteInfo;
|
||
} else {
|
||
//
|
||
// Remove the existing entry
|
||
//
|
||
RemoveEntryList(&pExistingInfo->Link);
|
||
delete [] pExistingInfo;
|
||
//
|
||
// Put the new one in
|
||
//
|
||
DfsSendUpdate(pServerName,SiteCount,pSites);
|
||
InsertHeadList(&_SiteTableHead, &pSiteInfo->Link);
|
||
_fDirty = TRUE;
|
||
}
|
||
} else {
|
||
//
|
||
// Not in table - put it in
|
||
//
|
||
DfsSendUpdate(pServerName,SiteCount,pSites);
|
||
InsertHeadList(&_SiteTableHead, &pSiteInfo->Link);
|
||
_fDirty = TRUE;
|
||
}
|
||
}
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::LookupSiteInfo
|
||
//
|
||
// Synopsis: Finds a site table entry
|
||
//
|
||
// Arguments: [pServerName] -- Server name to look up
|
||
//
|
||
// Returns: [NULL] -- No entry found
|
||
// [PDFSM_SITE_ENTRY] -- pointer to found entry
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
PDFSM_SITE_ENTRY
|
||
CSites::LookupSiteInfo(
|
||
LPWSTR pServerName)
|
||
{
|
||
PLIST_ENTRY pListHead, pLink;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::LookupSiteInfo(%ws)\n", pServerName));
|
||
|
||
pListHead = &_SiteTableHead;
|
||
|
||
if (pListHead->Flink == pListHead) { // list empty
|
||
return NULL;
|
||
}
|
||
|
||
for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
|
||
pSiteInfo = CONTAINING_RECORD(pLink, DFSM_SITE_ENTRY, Link);
|
||
if (_wcsicmp(pSiteInfo->ServerName,pServerName) == 0) {
|
||
//
|
||
// If this was marked for delete, it isn't any more.
|
||
//
|
||
pSiteInfo->Flags &= ~DFSM_SITE_ENTRY_DELETE_PENDING;
|
||
return pSiteInfo;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::_AllocateSiteInfo, private
|
||
//
|
||
// Synopsis: Creates a DFSM_SITE_ENTRY struct, as one contiguous chunk of memory
|
||
//
|
||
// Arguments: [pServerName] -- Server name
|
||
// [SiteCount] -- Number of entries in pSites
|
||
// [pSites] -- pointer to array of site information.
|
||
// [ppSiteInfo] -- pointer to pointer for the results
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully allocated and filled in the structure
|
||
// [ERROR_OUTOFMEMORY] -- Couldn't allocate needed memory
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CSites::_AllocateSiteInfo(
|
||
PWSTR pServerName,
|
||
ULONG SiteCount,
|
||
PDFS_SITENAME_INFO pSites,
|
||
PDFSM_SITE_ENTRY *ppSiteInfo)
|
||
{
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
WCHAR *wCp;
|
||
ULONG i;
|
||
ULONG Size = 0;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::_AllocateSiteInfo(%ws)\n", pServerName));
|
||
|
||
//
|
||
// Calculate the size chunk of mem we'll need
|
||
//
|
||
|
||
Size = FIELD_OFFSET(DFSM_SITE_ENTRY,Info.Site[SiteCount]);
|
||
|
||
//
|
||
// Add space for server name
|
||
//
|
||
|
||
Size += (wcslen(pServerName) + 1) * sizeof(WCHAR);
|
||
|
||
//
|
||
// And space for all the sitenames
|
||
//
|
||
for (i = 0; i < SiteCount; i++) {
|
||
if (pSites[i].SiteName != NULL) {
|
||
Size += (wcslen(pSites[i].SiteName) + 1) * sizeof(WCHAR);
|
||
} else {
|
||
Size += sizeof(WCHAR);
|
||
}
|
||
}
|
||
|
||
pSiteInfo = (PDFSM_SITE_ENTRY) new CHAR [Size];
|
||
|
||
if (pSiteInfo == NULL) {
|
||
*ppSiteInfo = NULL;
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
RtlZeroMemory(pSiteInfo, Size);
|
||
|
||
//
|
||
// Marshal the info into the buffer
|
||
//
|
||
pSiteInfo->Flags = 0;
|
||
pSiteInfo->Info.cSites = SiteCount;
|
||
|
||
wCp = (WCHAR *) &pSiteInfo->Info.Site[SiteCount];
|
||
pSiteInfo->ServerName = wCp;
|
||
wcscpy(wCp, pServerName);
|
||
wCp += wcslen(pServerName) + 1;
|
||
|
||
for (i = 0; i < SiteCount; i++) {
|
||
pSiteInfo->Info.Site[i].SiteFlags = pSites[i].SiteFlags;
|
||
pSiteInfo->Info.Site[i].SiteName = wCp;
|
||
if (pSites[i].SiteName != NULL) {
|
||
wcscpy(wCp, pSites[i].SiteName);
|
||
wCp += wcslen(pSites[i].SiteName) + 1;
|
||
} else {
|
||
*wCp++ = UNICODE_NULL;
|
||
}
|
||
}
|
||
|
||
*ppSiteInfo = pSiteInfo;
|
||
|
||
return ERROR_SUCCESS;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::_ReadSiteTable,private
|
||
//
|
||
// Synopsis: Loads the site table from storage
|
||
//
|
||
// First we check if the GUID has changed. If it hasn't, we abort the
|
||
// load - the existing table is good.
|
||
//
|
||
// If the table is different (the GUID is different), we merge the new
|
||
// data in with the old. This allows us to track which entries need to
|
||
// be updated, which need to be deleted, and which haven't changed. The
|
||
// process is done in three steps:
|
||
//
|
||
// Step 1: Go through the table, marking all the entries DELETE_PENDING
|
||
// Step 2: Load the new entries. As they are loaded, the updated entries'
|
||
// DELETE_PENDING bit(s) are turned off.
|
||
// Step 3: Go though the table again, removing any entries that still
|
||
// have the DELETE_PENDING bit on, and issuing an FSCTL to dfs.sys
|
||
// to have it remove the entry from its table.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully loaded the table
|
||
// [ERROR_OUTOFMEMORY] -- Not enough memory
|
||
// [other] -- returned from LdapGetData/RegGetData/DfsRtlXXX
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CSites::_ReadSiteTable()
|
||
{
|
||
DWORD dwErr;
|
||
DWORD cbBuffer;
|
||
PBYTE pBuffer = NULL;
|
||
PBYTE bp;
|
||
ULONG cObjects = 0;
|
||
ULONG i;
|
||
ULONG j;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
GUID TempGuid;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::_ReadSiteTable()\n"));
|
||
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
|
||
dwErr = LdapGetData(
|
||
_pwszFileName,
|
||
&cbBuffer,
|
||
(PCHAR *)&pBuffer);
|
||
|
||
} else {
|
||
|
||
dwErr = RegGetData(
|
||
_pwszFileName,
|
||
SITE_VALUE_NAME,
|
||
&cbBuffer,
|
||
&pBuffer);
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS && cbBuffer >= sizeof(ULONG) + sizeof(GUID)) {
|
||
|
||
//
|
||
// Unmarshal all the objects (DFS_SITENAME_INFO's) in the buffer
|
||
//
|
||
//
|
||
// We marshal into a temporary buffer, big enough to hold whatever is
|
||
// in the buffer.
|
||
//
|
||
|
||
pSiteInfo = (PDFSM_SITE_ENTRY) new BYTE [cbBuffer + sizeof(DFSM_SITE_ENTRY)];
|
||
|
||
if (pSiteInfo == NULL) {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
cbBuffer,
|
||
pBuffer);
|
||
|
||
DfsRtlGetGuid(&marshalBuffer, &TempGuid);
|
||
|
||
//
|
||
// If the Guid hasn't changed, we abort the load.
|
||
//
|
||
|
||
if (RtlCompareMemory(&TempGuid, &_SiteTableGuid, sizeof(GUID)) == sizeof(GUID)) {
|
||
|
||
delete [] pSiteInfo;
|
||
delete [] pBuffer;
|
||
goto NoLoadNecessary;
|
||
|
||
}
|
||
|
||
//
|
||
// Ok, we're committed to loading this (supposedly different) version
|
||
// of the site table. Mark all the existing entries DFSM_SITE_ENTRY_DELETE_PENDING.
|
||
//
|
||
|
||
MarkEntriesForMerge();
|
||
|
||
//
|
||
// Grab the Guid
|
||
//
|
||
|
||
RtlCopyMemory(&_SiteTableGuid, &TempGuid, sizeof(GUID));
|
||
|
||
//
|
||
// Get number of entries we'll be loading
|
||
//
|
||
|
||
DfsRtlGetUlong(&marshalBuffer, &cObjects);
|
||
|
||
//
|
||
// Now unmarshal each object/entry
|
||
//
|
||
|
||
for (j = 0; dwErr == ERROR_SUCCESS && j < cObjects; j++) {
|
||
|
||
dwErr = DfsRtlGet(&marshalBuffer,&MiDfsmSiteEntry, pSiteInfo);
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// And put it in the site table
|
||
//
|
||
|
||
AddOrUpdateSiteInfo(
|
||
pSiteInfo->ServerName,
|
||
pSiteInfo->Info.cSites,
|
||
&pSiteInfo->Info.Site[0]);
|
||
|
||
//
|
||
// The unmarshalling routines allocate buffers; we need to
|
||
// free them.
|
||
//
|
||
|
||
for (i = 0; i < pSiteInfo->Info.cSites; i++) {
|
||
MarshalBufferFree(pSiteInfo->Info.Site[i].SiteName);
|
||
}
|
||
|
||
MarshalBufferFree(pSiteInfo->ServerName);
|
||
|
||
}
|
||
|
||
//
|
||
// Now sync up the PKT in dfs.sys with this table
|
||
//
|
||
SyncPktSiteTable();
|
||
|
||
}
|
||
|
||
delete [] pSiteInfo;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (pBuffer != NULL) {
|
||
|
||
delete [] pBuffer;
|
||
|
||
}
|
||
|
||
NoLoadNecessary:
|
||
|
||
return dwErr;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::_WriteSiteTable,private
|
||
//
|
||
// Synopsis: Writes the site table to storage
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- Successfully write the table
|
||
// [ERROR_OUTOFMEMORY] -- Not enough memory
|
||
// [other] -- returned from LdapGetData/RegGetData/DfsRtlXXX
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CSites::_WriteSiteTable()
|
||
{
|
||
DWORD dwErr;
|
||
DWORD cbBuffer;
|
||
PBYTE pBuffer;
|
||
ULONG cObjects;
|
||
ULONG i;
|
||
PLIST_ENTRY pListHead, pLink;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
MARSHAL_BUFFER marshalBuffer;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::_WriteSiteTable()\n"));
|
||
|
||
//
|
||
// Create a new Guid
|
||
//
|
||
|
||
UuidCreate(&_SiteTableGuid);
|
||
|
||
//
|
||
// The cObjects count
|
||
//
|
||
cbBuffer = sizeof(ULONG) + sizeof(GUID);
|
||
|
||
//
|
||
// Add up the number of entries we need to store, and the total size of all
|
||
// of them.
|
||
//
|
||
cObjects = 0;
|
||
pListHead = &_SiteTableHead;
|
||
for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
|
||
pSiteInfo = CONTAINING_RECORD(pLink, DFSM_SITE_ENTRY, Link);
|
||
DfsRtlSize(&MiDfsmSiteEntry, pSiteInfo, &cbBuffer);
|
||
cObjects++;
|
||
}
|
||
|
||
//
|
||
// Get a buffer big enough
|
||
//
|
||
|
||
pBuffer = new BYTE [cbBuffer];
|
||
|
||
if (pBuffer == NULL) {
|
||
|
||
return ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
//
|
||
// Put the guid, then the object count in the beginning of the buffer
|
||
//
|
||
|
||
MarshalBufferInitialize(
|
||
&marshalBuffer,
|
||
cbBuffer,
|
||
pBuffer);
|
||
|
||
DfsRtlPutGuid(&marshalBuffer, &_SiteTableGuid);
|
||
DfsRtlPutUlong(&marshalBuffer, &cObjects);
|
||
|
||
//
|
||
// Walk the linked list of objects, marshalling them into the buffer.
|
||
//
|
||
for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
|
||
pSiteInfo = CONTAINING_RECORD(pLink, DFSM_SITE_ENTRY, Link);
|
||
DfsRtlPut(&marshalBuffer,&MiDfsmSiteEntry, pSiteInfo);
|
||
}
|
||
|
||
//
|
||
// Push out to storage
|
||
//
|
||
if (ulDfsManagerType == DFS_MANAGER_FTDFS) {
|
||
|
||
dwErr = LdapPutData(
|
||
_pwszFileName,
|
||
cbBuffer,
|
||
(PCHAR)pBuffer);
|
||
|
||
} else {
|
||
|
||
dwErr = RegPutData(
|
||
_pwszFileName,
|
||
SITE_VALUE_NAME,
|
||
cbBuffer,
|
||
pBuffer);
|
||
|
||
}
|
||
|
||
//
|
||
// ...and free the marshal buffer we created.
|
||
//
|
||
delete [] pBuffer;
|
||
|
||
return dwErr;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::_CompareEntries,private
|
||
//
|
||
// Synopsis: Compare two site table entries - case insensitive, and allows the site
|
||
// lists to be in different order.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: [TRUE] -- The entries are essentially identical
|
||
// [FALSE] -- The entries differ in some important way
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
BOOLEAN
|
||
CSites::_CompareEntries(
|
||
PDFSM_SITE_ENTRY pDfsmInfo1,
|
||
PDFSM_SITE_ENTRY pDfsmInfo2)
|
||
{
|
||
ULONG i;
|
||
ULONG j;
|
||
BOOLEAN fFound;
|
||
|
||
//
|
||
// cSites has to be the same
|
||
//
|
||
|
||
if (pDfsmInfo1->Info.cSites != pDfsmInfo2->Info.cSites) {
|
||
goto ReturnFalse;
|
||
}
|
||
|
||
//
|
||
// Server name has to be identical (why are we calling this
|
||
// if they aren't?)
|
||
//
|
||
if (_wcsicmp(pDfsmInfo1->ServerName,pDfsmInfo2->ServerName) != 0) {
|
||
goto ReturnFalse;
|
||
}
|
||
|
||
//
|
||
// Check that every Site in pDfsmInfo1 is in pDfsmSiteInfo2
|
||
//
|
||
for (i = 0; i < pDfsmInfo1->Info.cSites; i++) {
|
||
fFound = FALSE;
|
||
for (j = 0; fFound == FALSE && j < pDfsmInfo2->Info.cSites; j++) {
|
||
if (_wcsicmp(
|
||
pDfsmInfo1->Info.Site[i].SiteName,
|
||
pDfsmInfo2->Info.Site[j].SiteName) == 0) {
|
||
fFound = TRUE;
|
||
}
|
||
}
|
||
if (fFound == FALSE) {
|
||
goto ReturnFalse;
|
||
}
|
||
}
|
||
|
||
//
|
||
// ...and check that every site in pDfsmInfo2 is in pDfsmInfo1
|
||
//
|
||
for (i = 0; i < pDfsmInfo2->Info.cSites; i++) {
|
||
fFound = FALSE;
|
||
for (j = 0; fFound == FALSE && j < pDfsmInfo1->Info.cSites; j++) {
|
||
if (_wcsicmp(
|
||
pDfsmInfo2->Info.Site[i].SiteName,
|
||
pDfsmInfo1->Info.Site[j].SiteName) == 0) {
|
||
fFound = TRUE;
|
||
}
|
||
}
|
||
if (fFound == FALSE) {
|
||
goto ReturnFalse;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
ReturnFalse:
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::MarkEntriesForMerge
|
||
//
|
||
// Synopsis: Mark all entries in preparation for a merge.
|
||
// (1) Mark all entries with delete_pending on
|
||
// (2) Load a new table - duplicate entries remove the delete_pending bit
|
||
// (3) Call SyncPktSiteTable(), which will bring the PKT in dfs.sys up to date,
|
||
// by deleting delete_pending entries
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
VOID
|
||
CSites::MarkEntriesForMerge()
|
||
{
|
||
PLIST_ENTRY pListHead, pLink;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
ULONG i;
|
||
|
||
pListHead = &_SiteTableHead;
|
||
|
||
for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
|
||
pSiteInfo = CONTAINING_RECORD(pLink, DFSM_SITE_ENTRY, Link);
|
||
pSiteInfo->Flags |= DFSM_SITE_ENTRY_DELETE_PENDING;
|
||
}
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::SyncPktSiteTable
|
||
//
|
||
// Synopsis: Step 3 of a table merge. Walk the table, removing any entries
|
||
// with the DFSM_SITE_ENTRY_DELETE_PENDING (and telling dfs.sys
|
||
// to do so)
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
VOID
|
||
CSites::SyncPktSiteTable()
|
||
{
|
||
PLIST_ENTRY pListHead;
|
||
PLIST_ENTRY pLink;
|
||
PLIST_ENTRY pNext;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::SyncPktSiteTable()\n"));
|
||
|
||
pListHead = &_SiteTableHead;
|
||
|
||
for (pLink = pListHead->Flink; pLink != pListHead; pLink = pNext) {
|
||
|
||
//
|
||
// Save next in case we delete this one
|
||
//
|
||
pNext = pLink->Flink;
|
||
|
||
pSiteInfo = CONTAINING_RECORD(pLink, DFSM_SITE_ENTRY, Link);
|
||
|
||
if ((pSiteInfo->Flags & DFSM_SITE_ENTRY_DELETE_PENDING) != 0) {
|
||
//
|
||
// call dfs.sys with the update
|
||
//
|
||
DfsSendDelete(pSiteInfo->ServerName);
|
||
RemoveEntryList(pLink);
|
||
delete [] pSiteInfo;
|
||
_fDirty = TRUE;
|
||
}
|
||
}
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CSites::SyncPktSiteTable exit\n"));
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CSites::_DumpSiteTable
|
||
//
|
||
// Synopsis: Spill dfs's guts about site table entries.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
VOID
|
||
CSites::_DumpSiteTable()
|
||
{
|
||
PLIST_ENTRY pListHead, pLink;
|
||
PDFSM_SITE_ENTRY pSiteInfo;
|
||
ULONG i;
|
||
|
||
pListHead = &_SiteTableHead;
|
||
|
||
//
|
||
// Print them (for debugging)
|
||
//
|
||
for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
|
||
pSiteInfo = CONTAINING_RECORD(pLink, DFSM_SITE_ENTRY, Link);
|
||
DbgPrint("\tpSiteInfo(%ws)\n", pSiteInfo->ServerName);
|
||
for (i = 0; i < pSiteInfo->Info.cSites; i++) {
|
||
DbgPrint("\t\t%02d:%ws\n", i, pSiteInfo->Info.Site[i].SiteName);
|
||
}
|
||
}
|
||
}
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsSendDelete, private
|
||
//
|
||
// Synopsis: Send a DFS_DELETE_SITE_ARG down to dfs.sys
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsSendDelete(
|
||
LPWSTR ServerName)
|
||
{
|
||
ULONG size;
|
||
DWORD dwErr;
|
||
PDFS_DELETE_SITE_INFO_ARG arg;
|
||
|
||
size = sizeof(DFS_DELETE_SITE_INFO_ARG) +
|
||
wcslen(ServerName) * sizeof(WCHAR);
|
||
|
||
arg = (PDFS_DELETE_SITE_INFO_ARG) new CHAR [size];
|
||
|
||
if (arg == NULL) {
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
arg->ServerName.Buffer = (WCHAR *) &arg[1];
|
||
arg->ServerName.Length = wcslen(ServerName) * sizeof(WCHAR);
|
||
arg->ServerName.MaximumLength = arg->ServerName.Length;
|
||
RtlCopyMemory(arg->ServerName.Buffer, ServerName, arg->ServerName.Length);
|
||
|
||
LPWSTR_TO_OFFSET(arg->ServerName.Buffer,arg);
|
||
|
||
dwErr = DfsDeleteSiteEntry((PCHAR)arg, size);
|
||
|
||
delete [] arg;
|
||
|
||
return dwErr;
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: DfsSendUpdate, private
|
||
//
|
||
// Synopsis: Send a DFS_CREATE_SITE_ARG down to dfs.sys
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
NTSTATUS
|
||
DfsSendUpdate(
|
||
LPWSTR ServerName,
|
||
ULONG SiteCount,
|
||
PDFS_SITENAME_INFO pSites)
|
||
{
|
||
ULONG size;
|
||
DWORD dwErr;
|
||
ULONG i;
|
||
PDFS_CREATE_SITE_INFO_ARG arg;
|
||
WCHAR *wCp;
|
||
|
||
size = FIELD_OFFSET(DFS_CREATE_SITE_INFO_ARG,SiteName[SiteCount]) +
|
||
wcslen(ServerName) * sizeof(WCHAR);
|
||
|
||
for (i = 0; i < SiteCount; i++) {
|
||
size += wcslen(pSites[i].SiteName) * sizeof(WCHAR);
|
||
}
|
||
|
||
arg = (PDFS_CREATE_SITE_INFO_ARG) new CHAR [size];
|
||
|
||
if (arg == NULL) {
|
||
return ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
wCp = (WCHAR *)(&arg->SiteName[SiteCount]);
|
||
|
||
arg->ServerName.Buffer = wCp;
|
||
wCp += wcslen(ServerName);
|
||
arg->ServerName.Length = wcslen(ServerName) * sizeof(WCHAR);
|
||
arg->ServerName.MaximumLength = arg->ServerName.Length;
|
||
RtlCopyMemory(arg->ServerName.Buffer, ServerName, arg->ServerName.Length);
|
||
LPWSTR_TO_OFFSET(arg->ServerName.Buffer,arg);
|
||
arg->SiteCount = SiteCount;
|
||
|
||
for (i = 0; i < SiteCount; i++) {
|
||
arg->SiteName[i].Buffer = wCp;
|
||
wCp += wcslen(pSites[i].SiteName);
|
||
arg->SiteName[i].Length = wcslen(pSites[i].SiteName) * sizeof(WCHAR);
|
||
arg->SiteName[i].MaximumLength = arg->SiteName[i].Length;
|
||
RtlCopyMemory(arg->SiteName[i].Buffer, pSites[i].SiteName, arg->SiteName[i].Length);
|
||
LPWSTR_TO_OFFSET(arg->SiteName[i].Buffer,arg);
|
||
}
|
||
|
||
dwErr = DfsCreateSiteEntry((PCHAR)arg, size);
|
||
|
||
delete [] arg;
|
||
|
||
return dwErr;
|
||
}
|