667 lines
17 KiB
C++
667 lines
17 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1996, Microsoft Corporation
|
|
//
|
|
// File: localvol.cxx
|
|
//
|
|
// Contents: Code to validate local volume knowledge with the root server
|
|
// of the Dfs
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions: DfsManagerValidateLocalVolumes
|
|
//
|
|
// DfspGetRemoteConfigInfo
|
|
// DfspValidateLocalPartition
|
|
// DfspPruneLocalPartition
|
|
// StringToGuid
|
|
//
|
|
// History: April 29, 1996 Milans Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//#include <ntos.h>
|
|
//#include <ntrtl.h>
|
|
//#include <nturtl.h>
|
|
//#include <dfsfsctl.h>
|
|
//#include <windows.h>
|
|
|
|
#include <headers.hxx>
|
|
#pragma hdrstop
|
|
|
|
#include <dsgetdc.h>
|
|
#include "dfsmwml.h"
|
|
|
|
extern "C" NET_API_STATUS
|
|
NetDfsManagerGetConfigInfo(
|
|
LPWSTR wszServer,
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
GUID guidLocalVolume,
|
|
LPDFSM_RELATION_INFO *ppDfsmRelationInfo);
|
|
|
|
extern "C" NET_API_STATUS
|
|
NetDfsManagerSendSiteInfo(
|
|
LPWSTR wszServer,
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
LPDFS_SITELIST_INFO pSiteInfo);
|
|
|
|
DWORD
|
|
DfspGetRemoteConfigInfo(
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
LPWSTR wszLocalVolumeGuid,
|
|
LPDFSM_RELATION_INFO *ppDfsmRelationInfo);
|
|
|
|
VOID
|
|
DfspValidateLocalPartition(
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
LPWSTR wszLocalVolumeGuid,
|
|
LPDFSM_RELATION_INFO pDfsmRelationInfo);
|
|
|
|
VOID
|
|
DfspPruneLocalPartition(
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
LPWSTR wszLocalVolumeGuid);
|
|
|
|
VOID StringToGuid(
|
|
IN PWSTR pwszGuid,
|
|
OUT GUID *pGuid);
|
|
|
|
BOOLEAN
|
|
DfspGetCoveredSiteInfo(
|
|
LPWSTR ServerName,
|
|
LPDFS_SITELIST_INFO *ppSiteInfo);
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfsManagerValidateLocalVolumes
|
|
//
|
|
// Synopsis: Validates the relation info of all local volumes with the
|
|
// Dfs Root server
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: TRUE if validation attempt succeeded, FALSE if could not
|
|
// validate all local volumes
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
extern "C" BOOLEAN
|
|
DfsManagerValidateLocalVolumes()
|
|
{
|
|
DWORD dwErr, i;
|
|
HKEY hkeyLv, hkeyThisLv;
|
|
WCHAR wszLocalVolGuid[ 2 * sizeof(GUID) + 1 ];
|
|
BOOLEAN fValidateNextVolume;
|
|
BOOLEAN fHaveCoveredSiteInfo;
|
|
LPDFS_SITELIST_INFO pSiteInfo = NULL;
|
|
|
|
if (pwszComputerName == NULL)
|
|
return FALSE;
|
|
|
|
//
|
|
// Get covered site info
|
|
//
|
|
fHaveCoveredSiteInfo = DfspGetCoveredSiteInfo(
|
|
pwszComputerName,
|
|
&pSiteInfo);
|
|
|
|
//
|
|
// For each local volume, ask the root for its relation info and then
|
|
// fsctl it down to the driver so it can validate its relation info.
|
|
//
|
|
|
|
IDfsVolInlineDebOut((DEB_TRACE, "DfsManagerValidateLocalVolumes()\n"));
|
|
|
|
dwErr = RegOpenKey( HKEY_LOCAL_MACHINE, REG_KEY_LOCAL_VOLUMES, &hkeyLv);
|
|
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
|
|
if (fHaveCoveredSiteInfo == TRUE) {
|
|
|
|
MIDL_user_free(pSiteInfo);
|
|
|
|
}
|
|
|
|
return( FALSE );
|
|
|
|
}
|
|
|
|
i = 0;
|
|
|
|
do {
|
|
|
|
WCHAR wszEntryPath[MAX_PATH + 1];
|
|
LPDFSM_RELATION_INFO pDfsmRelationInfo;
|
|
|
|
fValidateNextVolume = TRUE;
|
|
|
|
//
|
|
// Local volumes are stored with their stringized guids as key names
|
|
//
|
|
|
|
dwErr = RegEnumKey(
|
|
hkeyLv,
|
|
i,
|
|
wszLocalVolGuid,
|
|
sizeof(wszLocalVolGuid) );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = RegOpenKey(hkeyLv, wszLocalVolGuid, &hkeyThisLv);
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
DWORD cbBuffer = sizeof(wszEntryPath);
|
|
DWORD dwType;
|
|
|
|
dwErr = RegQueryValueEx(
|
|
hkeyThisLv,
|
|
REG_VALUE_ENTRY_PATH,
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) wszEntryPath,
|
|
&cbBuffer);
|
|
|
|
RegCloseKey( hkeyThisLv );
|
|
|
|
}
|
|
|
|
} else if (dwErr == ERROR_NO_MORE_ITEMS) {
|
|
|
|
fValidateNextVolume = FALSE;
|
|
|
|
}
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwErr = DfspGetRemoteConfigInfo(
|
|
wszEntryPath,
|
|
wszLocalVolGuid,
|
|
&pDfsmRelationInfo);
|
|
|
|
switch (dwErr) {
|
|
|
|
case ERROR_SUCCESS:
|
|
|
|
DfspValidateLocalPartition(
|
|
wszEntryPath,
|
|
wszLocalVolGuid,
|
|
pDfsmRelationInfo);
|
|
|
|
NetApiBufferFree(pDfsmRelationInfo);
|
|
|
|
break;
|
|
|
|
|
|
case NERR_DfsNoSuchVolume:
|
|
case NERR_DfsNoSuchShare:
|
|
|
|
DfspPruneLocalPartition(
|
|
wszEntryPath,
|
|
wszLocalVolGuid);
|
|
|
|
break;
|
|
|
|
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
fValidateNextVolume = FALSE;
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Tell the root what sites we cover
|
|
//
|
|
|
|
if (fHaveCoveredSiteInfo == TRUE && pwszComputerName != NULL) {
|
|
|
|
NetDfsManagerSendSiteInfo(
|
|
pwszComputerName, // Who's sending this
|
|
wszEntryPath, // The dfs root to send to
|
|
pSiteInfo); // the site info itself
|
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
} while ( fValidateNextVolume );
|
|
|
|
RegCloseKey( hkeyLv );
|
|
|
|
if (fHaveCoveredSiteInfo == TRUE) {
|
|
|
|
MIDL_user_free(pSiteInfo);
|
|
|
|
}
|
|
|
|
IDfsVolInlineDebOut((DEB_TRACE, "DfsManagerValidateLocalVolumes: i=%d on exit\n", i));
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
DfspGetCoveredSiteInfo(
|
|
LPWSTR ServerName,
|
|
LPDFS_SITELIST_INFO *ppSiteInfo)
|
|
{
|
|
DWORD status;
|
|
LPWSTR ThisSite;
|
|
LPWSTR CoveredSites = NULL;
|
|
LPDFS_SITELIST_INFO pSiteInfo = NULL;
|
|
ULONG Size;
|
|
ULONG cSites;
|
|
LPWSTR pSiteName;
|
|
LPWSTR pNames;
|
|
ULONG iSite;
|
|
ULONG j;
|
|
DWORD dwType;
|
|
DWORD dwUnused;
|
|
ULONG cbBuffer;
|
|
HKEY hkey;
|
|
BOOLEAN fUsingDefault = TRUE;
|
|
|
|
status = RegOpenKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
REG_KEY_COVERED_SITES,
|
|
&hkey);
|
|
|
|
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, DfspGetCoveredSiteInfo_Error_RegOpenKey,
|
|
LOGSTATUS(status)
|
|
LOGWSTR(ServerName));
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
status = RegQueryInfoKey(
|
|
hkey, // Key
|
|
NULL, // Class string
|
|
NULL, // Size of class string
|
|
NULL, // Reserved
|
|
&dwUnused, // # of subkeys
|
|
&dwUnused, // max size of subkey name
|
|
&dwUnused, // max size of class name
|
|
&dwUnused, // # of values
|
|
&dwUnused, // max size of value name
|
|
&cbBuffer, // max size of value data,
|
|
NULL, // security descriptor
|
|
NULL); // Last write time
|
|
|
|
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, DfspGetCoveredSiteInfo_Error_RegQueryInfoKey,
|
|
LOGSTATUS(status)
|
|
LOGWSTR(ServerName));
|
|
|
|
//
|
|
// Check if there's a value the same name as the servername passed in,
|
|
// if so, use it. Else default to value REG_VALUE_COVERED_SITES.
|
|
//
|
|
|
|
if (status == ERROR_SUCCESS) {
|
|
|
|
CoveredSites = (LPWSTR)MIDL_user_allocate(cbBuffer);
|
|
|
|
if (CoveredSites != NULL) {
|
|
|
|
status = RegQueryValueEx(
|
|
hkey,
|
|
ServerName,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR)CoveredSites,
|
|
&cbBuffer);
|
|
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, DfspGetCoveredSiteInfo_Error_RegQueryValueEx,
|
|
LOGSTATUS(status)
|
|
LOGWSTR(ServerName));
|
|
|
|
if (status == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
|
|
|
|
fUsingDefault = FALSE;
|
|
|
|
} else {
|
|
|
|
status = RegQueryValueEx(
|
|
hkey,
|
|
REG_VALUE_COVERED_SITES,
|
|
NULL,
|
|
&dwType,
|
|
(PUCHAR)CoveredSites,
|
|
&cbBuffer);
|
|
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, DfspGetCoveredSiteInfo_Error_RegQueryValueEx2,
|
|
LOGSTATUS(status)
|
|
LOGWSTR(ServerName));
|
|
|
|
if ( status != ERROR_SUCCESS || dwType != REG_MULTI_SZ) {
|
|
|
|
MIDL_user_free(CoveredSites);
|
|
|
|
CoveredSites = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
//
|
|
// Size the return buffer
|
|
//
|
|
|
|
Size = 0;
|
|
|
|
for (cSites = 0, pNames = CoveredSites; pNames && *pNames; cSites++) {
|
|
|
|
Size += (wcslen(pNames) + 1) * sizeof(WCHAR);
|
|
|
|
pNames += wcslen(pNames) + 1;
|
|
|
|
}
|
|
|
|
//
|
|
// Get site we belong to, if we're using the defaults
|
|
//
|
|
|
|
ThisSite = NULL;
|
|
|
|
if (fUsingDefault == TRUE) {
|
|
|
|
status = DsGetSiteName(NULL, &ThisSite);
|
|
DFSM_TRACE_ERROR_HIGH(status, ALL_ERROR, DfspGetCoveredSiteInfo_Error_DsGetSiteName,
|
|
LOGSTATUS(status)
|
|
LOGWSTR(ServerName));
|
|
|
|
|
|
if (status == NO_ERROR && ThisSite != NULL) {
|
|
|
|
Size += (wcslen(ThisSite) + 1) * sizeof(WCHAR);
|
|
|
|
cSites++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If no sites are configured, and we couldn't determine our site,
|
|
// then we fail.
|
|
//
|
|
|
|
if (cSites == 0) {
|
|
|
|
goto ErrorReturn;
|
|
|
|
}
|
|
|
|
Size += FIELD_OFFSET(DFS_SITELIST_INFO,Site[cSites]);
|
|
|
|
pSiteInfo = (LPDFS_SITELIST_INFO)MIDL_user_allocate(Size);
|
|
|
|
if (pSiteInfo == NULL) {
|
|
|
|
goto ErrorReturn;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(pSiteInfo, Size);
|
|
|
|
pSiteInfo->cSites = cSites;
|
|
|
|
pSiteName = (LPWSTR) ((PCHAR)pSiteInfo +
|
|
sizeof(DFS_SITELIST_INFO) +
|
|
sizeof(DFS_SITENAME_INFO) * (cSites - 1));
|
|
|
|
//
|
|
// Marshall the site strings into the buffer
|
|
//
|
|
|
|
iSite = 0;
|
|
|
|
if (ThisSite != NULL) {
|
|
|
|
wcscpy(pSiteName, ThisSite);
|
|
|
|
pSiteInfo->Site[iSite].SiteFlags = DFS_SITE_PRIMARY;
|
|
|
|
pSiteInfo->Site[iSite++].SiteName = pSiteName;
|
|
|
|
pSiteName += wcslen(ThisSite) + 1;
|
|
|
|
}
|
|
|
|
for (pNames = CoveredSites; pNames && *pNames; pNames += wcslen(pNames) + 1) {
|
|
|
|
wcscpy(pSiteName, pNames);
|
|
|
|
pSiteInfo->Site[iSite++].SiteName = pSiteName;
|
|
|
|
pSiteName += wcslen(pSiteName) + 1;
|
|
|
|
}
|
|
|
|
*ppSiteInfo = pSiteInfo;
|
|
|
|
if (CoveredSites != NULL) {
|
|
|
|
MIDL_user_free(CoveredSites);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
ErrorReturn:
|
|
|
|
//
|
|
// Free anything we allocated
|
|
//
|
|
|
|
if (pSiteInfo != NULL) {
|
|
|
|
MIDL_user_free(pSiteInfo);
|
|
|
|
}
|
|
|
|
if (CoveredSites != NULL) {
|
|
|
|
MIDL_user_free(CoveredSites);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspGetRemoteConfigInfo
|
|
//
|
|
// Synopsis: Gets the config info for a local volume from the Dfs root
|
|
// server.
|
|
//
|
|
// Arguments: [wszLocalVolumeEntryPath] -- Entry path of local volume.
|
|
//
|
|
// [wszLocalVolumeGuid] -- Stringized guid of local volume.
|
|
//
|
|
// [ppDfsmRelationInfo] -- On successful return, contains pointer
|
|
// to allocated DFSM_RELATION_INFO structure.
|
|
//
|
|
// Returns: Error code from NetDfsManagerGetConfigInfo or
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
DfspGetRemoteConfigInfo(
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
LPWSTR wszLocalVolumeGuid,
|
|
LPDFSM_RELATION_INFO *ppDfsmRelationInfo)
|
|
{
|
|
DWORD dwErr;
|
|
GUID guidLocalVolume;
|
|
|
|
if (pwszComputerName == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
StringToGuid( wszLocalVolumeGuid, &guidLocalVolume );
|
|
|
|
dwErr = NetDfsManagerGetConfigInfo(
|
|
pwszComputerName,
|
|
wszLocalVolumeEntryPath,
|
|
guidLocalVolume,
|
|
ppDfsmRelationInfo);
|
|
|
|
DFSM_TRACE_ERROR_HIGH(dwErr, ALL_ERROR, DfspGetRemoteConfigInfo_Error_NetDfsManagerGetConfigInfo,
|
|
LOGSTATUS(dwErr)
|
|
LOGWSTR(wszLocalVolumeEntryPath));
|
|
|
|
return( dwErr );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspValidateLocalPartition
|
|
//
|
|
// Synopsis: Given a remote config info, this API will fsctl to the local
|
|
// dfs driver to take actions and match up its local volume info
|
|
// with the remote one.
|
|
//
|
|
// Arguments: [wszLocalVolumeEntryPath] -- local volume entry path to
|
|
// validate
|
|
// [wszLocalVolumeGuid] -- Guid of local volume to validate
|
|
// [pDfsmRelationInfo] -- The DFSM_RELATION_INFO that this local
|
|
// volume should have.
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DfspValidateLocalPartition(
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
LPWSTR wszLocalVolumeGuid,
|
|
LPDFSM_RELATION_INFO pDfsmRelationInfo)
|
|
{
|
|
DFS_PKT_RELATION_INFO DfsRelationInfo;
|
|
DWORD i;
|
|
|
|
//
|
|
// Massage the DFSM_RELATION_INFO into a DFS_PKT_RELATION_INFO
|
|
//
|
|
|
|
StringToGuid( wszLocalVolumeGuid, &DfsRelationInfo.EntryId.Uid );
|
|
|
|
RtlInitUnicodeString(
|
|
&DfsRelationInfo.EntryId.Prefix,
|
|
wszLocalVolumeEntryPath);
|
|
|
|
RtlInitUnicodeString( &DfsRelationInfo.EntryId.ShortPrefix, NULL );
|
|
|
|
DfsRelationInfo.SubordinateIdList =
|
|
new DFS_PKT_ENTRY_ID[ pDfsmRelationInfo->cSubordinates ];
|
|
|
|
if (DfsRelationInfo.SubordinateIdList == NULL)
|
|
return;
|
|
|
|
|
|
DfsRelationInfo.SubordinateIdCount = pDfsmRelationInfo->cSubordinates;
|
|
|
|
for (i = 0; i < pDfsmRelationInfo->cSubordinates; i++) {
|
|
|
|
DfsRelationInfo.SubordinateIdList[i].Uid =
|
|
pDfsmRelationInfo->eid[i].idSubordinate;
|
|
|
|
RtlInitUnicodeString(
|
|
&DfsRelationInfo.SubordinateIdList[i].Prefix,
|
|
pDfsmRelationInfo->eid[i].wszSubordinate);
|
|
|
|
RtlInitUnicodeString(
|
|
&DfsRelationInfo.SubordinateIdList[i].ShortPrefix,
|
|
NULL);
|
|
|
|
}
|
|
|
|
PktValidateLocalVolumeInfo( &DfsRelationInfo );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DfspPruneLocalPartition
|
|
//
|
|
// Synopsis: Deletes a local volume that the root server says is an extra
|
|
// volume.
|
|
//
|
|
// Arguments: [wszLocalVolumeEntryPath] -- local volume entry path to
|
|
// delete
|
|
// [wszLocalVolumeGuid] -- Guid of local volume to delete
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DfspPruneLocalPartition(
|
|
LPWSTR wszLocalVolumeEntryPath,
|
|
LPWSTR wszLocalVolumeGuid)
|
|
{
|
|
DFS_PKT_ENTRY_ID EntryId;
|
|
|
|
RtlZeroMemory(&EntryId, sizeof(EntryId));
|
|
|
|
StringToGuid( wszLocalVolumeGuid, &EntryId.Uid );
|
|
|
|
RtlInitUnicodeString( &EntryId.Prefix, wszLocalVolumeEntryPath );
|
|
|
|
PktPruneLocalPartition( &EntryId );
|
|
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: StringToGuid
|
|
//
|
|
// Synopsis: Converts a 32 wchar null terminated string to a GUID.
|
|
//
|
|
// Arguments: [pwszGuid] -- the string to convert
|
|
// [pGuid] -- Pointer to destination GUID.
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define HEX_DIGIT_TO_INT(d, i) \
|
|
ASSERT(((d) >= L'0' && (d) <= L'9') || \
|
|
((d) >= L'A' && (d) <= L'F')); \
|
|
if ((d) <= L'9') { \
|
|
i = (d) - L'0'; \
|
|
} else { \
|
|
i = (d) - L'A' + 10; \
|
|
}
|
|
|
|
VOID StringToGuid(
|
|
IN PWSTR pwszGuid,
|
|
OUT GUID *pGuid)
|
|
{
|
|
PBYTE pbBuffer = (PBYTE) pGuid;
|
|
USHORT i, n;
|
|
|
|
for (i = 0; i < sizeof(GUID); i++) {
|
|
HEX_DIGIT_TO_INT(pwszGuid[2 * i], n);
|
|
pbBuffer[i] = n << 4;
|
|
HEX_DIGIT_TO_INT(pwszGuid[2 * i + 1], n);
|
|
pbBuffer[i] |= n;
|
|
}
|
|
}
|
|
|