1873 lines
49 KiB
C++
1873 lines
49 KiB
C++
//-------------------------------------------------------------
|
||
//
|
||
// Microsoft Windows
|
||
//
|
||
// Copyright (CC) Microsoft Corporation 1992, 1992
|
||
//
|
||
// File: idfsvsup.cxx
|
||
//
|
||
// Contents: This contains support methods for the IDfsVol interface
|
||
// implementation.
|
||
//
|
||
//-------------------------------------------------------------
|
||
//#include <ntos.h>
|
||
//#include <ntrtl.h>
|
||
//#include <nturtl.h>
|
||
//#include <dfsfsctl.h>
|
||
//#include <windows.h>
|
||
|
||
#include <headers.hxx>
|
||
#pragma hdrstop
|
||
|
||
#include <dfserr.h>
|
||
#include "cdfsvol.hxx"
|
||
#include "dfsmwml.h"
|
||
|
||
NTSTATUS
|
||
DfspCreateExitPoint (
|
||
IN HANDLE DriverHandle,
|
||
IN LPGUID Uid,
|
||
IN LPWSTR Prefix,
|
||
IN ULONG Type,
|
||
IN ULONG ShortPrefixLen,
|
||
OUT LPWSTR ShortPrefix);
|
||
|
||
NTSTATUS
|
||
DfspDeleteExitPoint (
|
||
IN HANDLE DriverHandle,
|
||
IN LPGUID Uid,
|
||
IN LPWSTR Prefix,
|
||
IN ULONG Type);
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Member: CDfsVolume::CreateObject, public
|
||
//
|
||
// Synopsis: This method merely creates a volume object. This has no
|
||
// distributed operations associated with this operation.
|
||
//
|
||
// Arguments: [pwzVolObjName] -- VOlume object Name
|
||
// [EntryPath] -- The EntryPath
|
||
// [VolType] -- VolumeType
|
||
// [pReplicaInfo] -- ReplicaInfo. This is optional.
|
||
//
|
||
// Returns:
|
||
//
|
||
// Notes: Raid: 455299 This function could potentially fail and leave an
|
||
// object hanging around??
|
||
//
|
||
// History: 17-May-1993 SudK Created.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
DWORD
|
||
CDfsVolume::CreateObject(
|
||
PWSTR pwszVolObjName,
|
||
LPWSTR pwszPrefix,
|
||
ULONG ulVolType,
|
||
PDFS_REPLICA_INFO pReplicaInfo,
|
||
PWCHAR pwszComment,
|
||
GUID *pUid
|
||
)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
CDfsService *pService;
|
||
SYSTEMTIME st;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateVolObject(%ws,%ws,0x%x,%ws)\n",
|
||
pwszVolObjName, pwszPrefix, ulVolType, pwszComment));
|
||
|
||
//
|
||
// First put this name in the private section.
|
||
//
|
||
ULONG volLen = wcslen(pwszVolObjName);
|
||
if (volLen > MAX_PATH) {
|
||
_pwzFileName = new WCHAR[volLen + 1];
|
||
} else {
|
||
_pwzFileName = _FileNameBuffer;
|
||
}
|
||
|
||
if (_pwzFileName == NULL)
|
||
return( ERROR_OUTOFMEMORY );
|
||
|
||
wcscpy(_pwzFileName, pwszVolObjName);
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "Creating Object%ws\n", pwszVolObjName));
|
||
|
||
//
|
||
// Create the storage object.
|
||
//
|
||
dwErr = DfsmCreateStorage(
|
||
pwszVolObjName,
|
||
&_pStorage);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR,
|
||
"Unable to create directory storage object %08lx %ws\n",
|
||
dwErr, pwszVolObjName));
|
||
return(dwErr);
|
||
}
|
||
|
||
//
|
||
// First thing we do now is to setup the Class.
|
||
//
|
||
dwErr = _pStorage->SetClass(CLSID_CDfsVolume);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR,
|
||
"Unable to set Class on this %ws\n", pwszVolObjName));
|
||
return(dwErr);
|
||
}
|
||
|
||
//
|
||
// This is where we need to init and create the dummy property sets
|
||
// so that next time around we can set them and dont need to create them.
|
||
//
|
||
|
||
dwErr = SetVersion( TRUE );
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR,
|
||
"Unable to create version propset for %ws Error: %08lx\n",
|
||
pwszVolObjName, dwErr));
|
||
return(dwErr);
|
||
}
|
||
|
||
GUID Uid;
|
||
|
||
if (pUid == NULL) {
|
||
dwErr = UuidCreate(&Uid);
|
||
_peid.Uid = Uid;
|
||
} else {
|
||
_peid.Uid = *pUid;
|
||
}
|
||
|
||
_EntryType = ulVolType;
|
||
|
||
ULONG epLen = wcslen(pwszPrefix);
|
||
if (epLen > MAX_PATH) {
|
||
_peid.Prefix.Buffer = new WCHAR[epLen + 1];
|
||
_peid.Prefix.MaximumLength = (USHORT) ((epLen + 1)*sizeof(WCHAR));
|
||
} else {
|
||
_peid.Prefix.MaximumLength = sizeof(_EntryPathBuffer);
|
||
_peid.Prefix.Buffer = _EntryPathBuffer;
|
||
}
|
||
|
||
if (_peid.Prefix.Buffer == NULL)
|
||
return( ERROR_OUTOFMEMORY );
|
||
|
||
_peid.Prefix.Length = (USHORT) epLen*sizeof(WCHAR);
|
||
wcscpy(_peid.Prefix.Buffer, pwszPrefix);
|
||
|
||
//
|
||
// We don't yet know the short name of this volume, so simply allocate
|
||
// enough room and fill it with the full prefix. When an exit point
|
||
// corresponding to this volume is created, the short prefix might be
|
||
// modified.
|
||
//
|
||
// Note that it is tempting to think that the short prefix is <= the full
|
||
// prefix in size. This, however, is not a valid assumption, because
|
||
// names like A.BCDE qualify as LFNs, and their 8.3 equivalents look like
|
||
// A12345~1.BCD!
|
||
//
|
||
|
||
ULONG i, sepLen;
|
||
|
||
for (i = 0, sepLen = 0; i < epLen; i++) {
|
||
if (pwszPrefix[i] == UNICODE_PATH_SEP)
|
||
sepLen ++;
|
||
}
|
||
|
||
sepLen *= (1+8+1+3); // For \8.3
|
||
|
||
if (sepLen < epLen)
|
||
sepLen = epLen;
|
||
|
||
if (sepLen > MAX_PATH) {
|
||
_peid.ShortPrefix.Buffer = new WCHAR[sepLen + 1];
|
||
_peid.ShortPrefix.MaximumLength = (USHORT) ((sepLen + 1)*sizeof(WCHAR));
|
||
} else {
|
||
_peid.ShortPrefix.Buffer = _ShortPathBuffer;
|
||
_peid.ShortPrefix.MaximumLength = sizeof(_ShortPathBuffer);
|
||
}
|
||
|
||
if (_peid.ShortPrefix.Buffer == NULL)
|
||
return( ERROR_OUTOFMEMORY );
|
||
|
||
_peid.ShortPrefix.Length = (USHORT) epLen*sizeof(WCHAR);
|
||
wcscpy(_peid.ShortPrefix.Buffer, pwszPrefix);
|
||
|
||
//
|
||
// We need to deal with a NULL comment as well.
|
||
//
|
||
if (pwszComment != NULL) {
|
||
_pwszComment = new WCHAR[wcslen(pwszComment) + 1];
|
||
if (_pwszComment != NULL) {
|
||
wcscpy(_pwszComment, pwszComment);
|
||
}
|
||
} else {
|
||
_pwszComment = new WCHAR[1];
|
||
if (_pwszComment != NULL) {
|
||
*_pwszComment = UNICODE_NULL;
|
||
}
|
||
}
|
||
if (_pwszComment == NULL) {
|
||
return( ERROR_OUTOFMEMORY );
|
||
}
|
||
|
||
GetSystemTime( &st );
|
||
SystemTimeToFileTime( &st, &_ftEntryPath );
|
||
_ftComment = _ftState = _ftEntryPath;
|
||
|
||
dwErr = SetIdProps(
|
||
ulVolType,
|
||
_State,
|
||
pwszPrefix,
|
||
pwszPrefix,
|
||
_peid.Uid,
|
||
_pwszComment,
|
||
_Timeout,
|
||
_ftEntryPath,
|
||
_ftState,
|
||
_ftComment,
|
||
TRUE);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
return(dwErr);
|
||
|
||
_Recover.Initialize(_pStorage);
|
||
_Recover.SetDefaultProps();
|
||
|
||
//
|
||
// Now let us set a NULL service List property. This method will create
|
||
// the stream as well. We dont need to bother.
|
||
//
|
||
dwErr = _DfsSvcList.SetNullSvcList(_pStorage);
|
||
|
||
if (dwErr != ERROR_SUCCESS)
|
||
return(dwErr);
|
||
|
||
_Deleted = FALSE;
|
||
|
||
//
|
||
// Everything is setup now. We can set the appropriate service etc.
|
||
//
|
||
if (pReplicaInfo != NULL) {
|
||
pService = new CDfsService(pReplicaInfo, FALSE, &dwErr);
|
||
if (pService == NULL) {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
}
|
||
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
dwErr = _DfsSvcList.SetNewService(pService);
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
delete pService;
|
||
}
|
||
}
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateVolObject() exit\n"));
|
||
|
||
return(dwErr);
|
||
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Member: CDfsVolume::GetDfsVolumeFromStg, private
|
||
//
|
||
// Synopsis: This method takes a STATDIR structure and returns a CDfsVol
|
||
// pointer to the object corresponding to that.
|
||
//
|
||
// Arguments: [rgelt] -- Pointer to the DFSMSTATDIR structure.
|
||
// [ppDfsVol] -- This is where the DfsVol is returned.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- If successfully set the parent's path.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- If unable to allocate memory for parent's
|
||
// path.
|
||
//
|
||
// Error from loading the volume object
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
DWORD
|
||
CDfsVolume::GetDfsVolumeFromStg(
|
||
DFSMSTATDIR *rgelt,
|
||
CDfsVolume **ppDfsVol)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
PWCHAR pwszFullName;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetDfsVolumeFromStg()\n"));
|
||
|
||
//
|
||
// Allocate a new CDfsVolume and initialize with appropriate name.
|
||
//
|
||
*ppDfsVol = new CDfsVolume();
|
||
if (*ppDfsVol == NULL)
|
||
return( ERROR_OUTOFMEMORY );
|
||
|
||
pwszFullName = new WCHAR[wcslen(_pwzFileName) + wcslen(rgelt->pwcsName) + 2];
|
||
|
||
if (pwszFullName != NULL) {
|
||
|
||
wcscpy(pwszFullName, _pwzFileName);
|
||
wcscat(pwszFullName, L"\\");
|
||
wcscat(pwszFullName, rgelt->pwcsName);
|
||
|
||
dwErr = (*ppDfsVol)->LoadNoRegister(pwszFullName, 0);
|
||
|
||
delete [] pwszFullName;
|
||
|
||
} else {
|
||
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
(*ppDfsVol)->Release();
|
||
*ppDfsVol = NULL;
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetDfsVolumeFromStg() exit\n"));
|
||
|
||
return(dwErr);
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Member: CDfsVolume::SetParentPath, private
|
||
//
|
||
// Synopsis: This method figures out the name of the parent object and
|
||
// sets it up in the private section of this instance.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- If successfully set the parent's path.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- If unable to allocate memory for parent's
|
||
// path.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
DWORD
|
||
CDfsVolume::SetParentPath(void)
|
||
{
|
||
|
||
PWCHAR pwszLastComponent;
|
||
ULONG parentLen;
|
||
|
||
pwszLastComponent = wcsrchr(_pwzFileName, L'\\');
|
||
|
||
if(pwszLastComponent == NULL) {
|
||
return ERROR_INVALID_DATA;
|
||
}
|
||
|
||
ASSERT(*(pwszLastComponent + 1) != UNICODE_NULL);
|
||
|
||
//
|
||
// Let us now figure out the length of the parent Name and copy over
|
||
// appropriate number of characters.
|
||
//
|
||
|
||
if (_pwszParentName != _ParentNameBuffer)
|
||
delete [] _pwszParentName;
|
||
|
||
parentLen = wcslen(_pwzFileName) - wcslen(pwszLastComponent);
|
||
|
||
if (parentLen > MAX_PATH) {
|
||
|
||
_pwszParentName = new WCHAR[parentLen + 1];
|
||
|
||
if (_pwszParentName == NULL)
|
||
return( ERROR_OUTOFMEMORY );
|
||
|
||
} else {
|
||
|
||
_pwszParentName = _ParentNameBuffer;
|
||
|
||
}
|
||
|
||
wcsncpy(_pwszParentName, _pwzFileName, parentLen);
|
||
|
||
_pwszParentName[parentLen] = UNICODE_NULL;
|
||
|
||
return(ERROR_SUCCESS);
|
||
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Member: CDfsVolume::GetParent, private
|
||
//
|
||
// Synopsis: This function returns a pointer to IDfsVolume to the parent
|
||
// of the present object. The release function on this
|
||
// should be called by the caller of this function. We use
|
||
// Ths IStorage interface to get to the parent.
|
||
//
|
||
// Arguments: [pIDfsParent] -- This is where the IDfsVolume for parent is
|
||
// returned.
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- If everything went well.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Unable to create parent instance.
|
||
//
|
||
// History: 14-Sep-92 SudK Created
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::GetParent(
|
||
CDfsVolume **parent)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
CDfsVolume *pDfsVol;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetParent()\n"));
|
||
|
||
//
|
||
// First we get the parent's pathname and then we can do the appropriate.
|
||
//
|
||
|
||
dwErr = SetParentPath();
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR, "Unable to get parentPath %ws %08lx\n",
|
||
_pwzFileName, dwErr));
|
||
return(dwErr);
|
||
}
|
||
|
||
//
|
||
// Now we instantiate a CDfsVolume structure and then initialise it.
|
||
//
|
||
|
||
pDfsVol = new CDfsVolume();
|
||
|
||
if (pDfsVol == NULL)
|
||
return( ERROR_OUTOFMEMORY );
|
||
|
||
dwErr = pDfsVol->LoadNoRegister(_pwszParentName, 0);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
pDfsVol->Release();
|
||
|
||
*parent = NULL;
|
||
|
||
return(dwErr);
|
||
|
||
}
|
||
|
||
*parent = pDfsVol;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetParent() exit\n"));
|
||
|
||
return(dwErr);
|
||
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::DeleteObject, private
|
||
//
|
||
// Synopsis: Support method to merely delete a volume object from
|
||
// persistent store.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: [ERROR_SUCCESS] -- If successfully deleted object.
|
||
//
|
||
// [ERROR_OUTOFMEMORY] -- Unable to get parent instance.
|
||
//
|
||
// History: 16-Sep-1992 SudK Created
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::DeleteObject()
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
CStorage *parentStg;
|
||
PWCHAR pwszLastComponent;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::DeleteObject()\n"));
|
||
|
||
//
|
||
// We are going to delete this object so let us release all our pointers.
|
||
//
|
||
|
||
ASSERT ((_pStorage != NULL));
|
||
|
||
_pStorage->Release();
|
||
|
||
_pStorage = NULL;
|
||
|
||
//
|
||
// Let us now release all the IStorage's which are with CRecover & SvcList
|
||
//
|
||
if (_Recover._pPSStg != NULL) {
|
||
|
||
_Recover._pPSStg->Release();
|
||
|
||
_Recover._pPSStg = NULL;
|
||
|
||
}
|
||
|
||
if (_DfsSvcList._pPSStg != NULL) {
|
||
|
||
_DfsSvcList._pPSStg->Release();
|
||
|
||
_DfsSvcList._pPSStg = NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// First we get the parent's pathname and then we can do the appropriate.
|
||
//
|
||
|
||
dwErr = SetParentPath();
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR, "Failed to get parent path for %ws\n", _pwzFileName));
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
dwErr = DfsmOpenStorage( _pwszParentName, &parentStg);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR, "Unable to open [%ws] %08lx\n", _pwszParentName, dwErr));
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
//
|
||
// Now we have to delete ourselves using our parent's IStorage.
|
||
// So we extract the last component name from the file name.
|
||
//
|
||
|
||
pwszLastComponent = _pwzFileName + wcslen(_pwszParentName) + 1;
|
||
|
||
dwErr = parentStg->DestroyElement(pwszLastComponent);
|
||
|
||
parentStg->Release();
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR, "Unable to delete [%ws] %08lx\n", _pwzFileName, dwErr));
|
||
|
||
return( dwErr );
|
||
|
||
} else {
|
||
|
||
//
|
||
// The storage object has really been deleted, so delete the mapping
|
||
// of this prefix from the storage directory.
|
||
//
|
||
|
||
dwErr = pDfsmStorageDirectory->_Delete( _peid.Prefix.Buffer );
|
||
|
||
ASSERT( dwErr == ERROR_SUCCESS );
|
||
|
||
}
|
||
|
||
_Deleted = TRUE;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::DeleteObject() exit\n"));
|
||
|
||
return( ERROR_SUCCESS );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CDfsVolume::GetVersion, private
|
||
//
|
||
// Synopsis: Retrieves the version of the volume object from the property
|
||
// stamped on it.
|
||
//
|
||
// Arguments: [pVersion] -- The version is returned here.
|
||
//
|
||
// Returns: Result of reading the version property.
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::GetVersion(
|
||
ULONG * pVersion)
|
||
{
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetVersion()\n"));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
dwErr = _pStorage->GetVersionProps(pVersion);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR,
|
||
"Unable to read Version Properties %08lx\n",
|
||
dwErr));
|
||
return(dwErr);
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetVersion() exit\n"));
|
||
|
||
return( dwErr );
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: SetVersion
|
||
//
|
||
// Synopsis: Sets the version property on the volume object to
|
||
// VOL_OBJ_VERSION_NUMBER
|
||
//
|
||
// Arguments: [bCreate] -- TRUE if the property set should be created,
|
||
// FALSE if the property set should be assumed to
|
||
// exist
|
||
//
|
||
// Returns: Result of setting the property
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::SetVersion(
|
||
BOOL bCreate)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVersion()\n"));
|
||
|
||
dwErr = _pStorage->SetVersionProps( VOL_OBJ_VERSION_NUMBER );
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut(( DEB_ERROR,
|
||
"Unable to set Version Properties %08lx\n",
|
||
dwErr));
|
||
return(dwErr);
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVersion() exit\n"));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::GetIdProps, private
|
||
//
|
||
// Synopsis: Gets the ID Properties from a volume object.
|
||
// Memory for the string values is allocated using new. The
|
||
// caller is responsible for freeing it.
|
||
//
|
||
// Arguments: [pdwType] -- The Volume Type property is returned here.
|
||
// [ppwszEntryPath] -- EntryPath is returned here.
|
||
// [ppwszShortPath] -- The 8.3 form of EntryPath is returned here
|
||
// [ppwszComment] -- Comment is returned here.
|
||
// [pGuid] -- The Guid (VolumeID) is returned here.
|
||
// [pdwVolumeState] -- The volume state is returned here.
|
||
// [pftPathTime] -- Time that EntryPath was last modified.
|
||
// [pftStateTime] -- Time that Volume State was last modified.
|
||
// [pftCommentTime] -- Time that Comment was last modified.
|
||
//
|
||
// Returns:
|
||
//
|
||
// History: 16-Sep-1992 SudK Imported from PART.CXX
|
||
// 01-Jan-1996 Milans Ported to NT/SUR
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::GetIdProps(
|
||
ULONG *pdwType,
|
||
PWCHAR *ppwszEntryPath,
|
||
PWCHAR *ppwszShortPath,
|
||
PWCHAR *ppwszComment,
|
||
GUID *pGuid,
|
||
ULONG *pdwVolumeState,
|
||
ULONG *pdwTimeout,
|
||
FILETIME *pftPathTime,
|
||
FILETIME *pftStateTime,
|
||
FILETIME *pftCommentTime
|
||
)
|
||
{
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetIdProps()\n"));
|
||
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
|
||
dwErr = _pStorage->GetIdProps(
|
||
pdwType,
|
||
pdwVolumeState,
|
||
ppwszEntryPath,
|
||
ppwszShortPath,
|
||
pGuid,
|
||
ppwszComment,
|
||
pdwTimeout,
|
||
pftPathTime,
|
||
pftStateTime,
|
||
pftCommentTime);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((
|
||
DEB_ERROR, "Unable to read Id Props %08lx\n", dwErr));
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetIdProps() exit\n"));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::SetIdProps, private
|
||
//
|
||
// Synopsis: Exact opposite of GetIdProps function. A wrapper around the
|
||
// property interface to set the appropriate properties that
|
||
// identify a volume.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Returns:
|
||
//
|
||
// History: 16-Sep-1992 SudK Imported from PART.CXX
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::SetIdProps(
|
||
ULONG Type,
|
||
ULONG State,
|
||
PWCHAR pwszPrefix,
|
||
PWCHAR pwszShortPath,
|
||
GUID & Guid,
|
||
PWSTR pwszComment,
|
||
ULONG Timeout,
|
||
FILETIME ftPrefix,
|
||
FILETIME ftState,
|
||
FILETIME ftComment,
|
||
BOOLEAN bCreate
|
||
)
|
||
{
|
||
DWORD dwErr;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetIdProps()\n"));
|
||
|
||
dwErr = _pStorage->SetIdProps(
|
||
Type,
|
||
State,
|
||
pwszPrefix,
|
||
pwszShortPath,
|
||
Guid,
|
||
pwszComment,
|
||
Timeout,
|
||
ftPrefix,
|
||
ftState,
|
||
ftComment);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut(( DEB_ERROR,
|
||
"Unable to Set IDProperties %08lx\n",
|
||
dwErr));
|
||
return(dwErr);
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetIdProps() exit\n"));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CDfsVolume::SaveShortName
|
||
//
|
||
// Synopsis: Updates the short name for the volume entry path and saves it
|
||
// to the registry.
|
||
//
|
||
// Arguments: None - the short name is picked up from the _peid private
|
||
// member.
|
||
//
|
||
// Returns:
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::SaveShortName()
|
||
{
|
||
DWORD dwErr;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetShortName()\n"));
|
||
|
||
dwErr = SetIdProps(
|
||
_EntryType,
|
||
_State,
|
||
_peid.Prefix.Buffer,
|
||
_peid.ShortPrefix.Buffer,
|
||
_peid.Uid,
|
||
_pwszComment,
|
||
_Timeout,
|
||
_ftEntryPath,
|
||
_ftState,
|
||
_ftComment,
|
||
FALSE);
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetShortName() exit\n"));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::DeletePktEntry, private
|
||
//
|
||
// Synopsis: This method deletes an entry from the PKT. Given an ID to
|
||
// identify the entry this method deletes the entry.
|
||
//
|
||
// Arguments: victim - The entryID that identifies the PKT entry to go.
|
||
//
|
||
// Returns:
|
||
//
|
||
// History: 24-Nov-1992 SudK Created.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume :: DeletePktEntry(
|
||
PDFS_PKT_ENTRY_ID victim
|
||
)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
HANDLE pktHandle = NULL;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::DeletePktEntry()\n"));
|
||
|
||
//
|
||
// Open the local PKT...
|
||
//
|
||
|
||
status = PktOpen(&pktHandle, 0, 0, NULL);
|
||
|
||
if(NT_SUCCESS(status)) {
|
||
status = PktDestroyEntry(
|
||
pktHandle,
|
||
*victim
|
||
);
|
||
|
||
PktClose(pktHandle);
|
||
|
||
if (status == DFS_STATUS_NO_SUCH_ENTRY) {
|
||
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
} else if (!NT_SUCCESS(status)) {
|
||
|
||
dwErr = RtlNtStatusToDosError(status);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
dwErr = RtlNtStatusToDosError(status);
|
||
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::DeletePktEntry() exit\n"));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::CreateSubordinatePktEntry, private
|
||
//
|
||
// Synopsis: This method is basically an interface into the driver to be
|
||
// able to manipulate the PKT. This creates an entry for the
|
||
// current volume object and at the same time links it with its
|
||
// superior volume object's PKT entry. This method makes one
|
||
// assumption that no services are associated with the service.
|
||
// It adds a NULL serviceList infact if the Boolean bWithService
|
||
// is FALSE else it puts in the servicelist also.
|
||
//
|
||
// Arguments: [pSuperior] -- The Superior's EntryID info is passed here to
|
||
// identify the superior in the PKT.
|
||
// [bWithService] -- Whether to include the serviceinfo in EINFO.
|
||
//
|
||
// Returns:
|
||
//
|
||
// History: 22-Nov-1992 SudK Created
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::CreateSubordinatePktEntry(
|
||
HANDLE pktHandle,
|
||
PDFS_PKT_ENTRY_ID pSuperior,
|
||
BOOLEAN bWithService)
|
||
{
|
||
ULONG etype = 0;
|
||
DFS_PKT_ENTRY_INFO einfo;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
CDfsService *pDfsSvc = NULL;
|
||
DFS_SERVICE *pService;
|
||
ULONG count = 0;
|
||
UNICODE_STRING ustrShortName;
|
||
WCHAR ShortPrefix[MAX_PATH+1];
|
||
BOOLEAN CloseHandle = FALSE;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::CreateSubordinatePktEntry()\n"));
|
||
|
||
//
|
||
// We setup the servicelist based on the CreateDisposition.
|
||
//
|
||
if (!bWithService) {
|
||
memset(&einfo, 0, sizeof(DFS_PKT_ENTRY_INFO));
|
||
einfo.ServiceList = NULL;
|
||
einfo.Timeout = _Timeout;
|
||
} else {
|
||
einfo.Timeout = _Timeout;
|
||
count = _DfsSvcList.GetServiceCount();
|
||
einfo.ServiceCount = count;
|
||
einfo.ServiceList = new DFS_SERVICE[count];
|
||
//447491, dont use null pointer.
|
||
if (einfo.ServiceList == NULL) {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
return dwErr;
|
||
}
|
||
memset(einfo.ServiceList, 0, sizeof(DFS_SERVICE)*count);
|
||
|
||
pDfsSvc = _DfsSvcList.GetFirstService();
|
||
pService = einfo.ServiceList;
|
||
for (ULONG i=0; i<count; i++) {
|
||
*pService = *(pDfsSvc->GetDfsService());
|
||
pService++;
|
||
pDfsmSites->LookupSiteInfo((pDfsSvc->GetReplicaInfo())->pwszServerName);
|
||
pDfsSvc = _DfsSvcList.GetNextService(pDfsSvc);
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Note: We depend upon the correspondence of certain bits between the DFS
|
||
// volume types and PKT entry types here.
|
||
//
|
||
#if (DFS_VOL_TYPE_ALL & (PKT_ENTRY_TYPE_LOCAL|PKT_ENTRY_TYPE_PERMANENT|PKT_ENTRY_TYPE_INUSE|PKT_ENTRY_TYPE_REFERRAL_SVC|PKT_ENTRY_TYPE_LOCAL_XPOINT))
|
||
#error (DFS_VOL_TYPE_ALL & (PKT_ENTRY_TYPE_LOCAL|PKT_ENTRY_TYPE_PERMANENT|PKT_ENTRY_TYPE_INUSE|PKT_ENTRY_TYPE_REFERRAL_SVC|PKT_ENTRY_TYPE_LOCAL_XPOINT))
|
||
#endif
|
||
|
||
etype = _EntryType | PKT_ENTRY_TYPE_PERMANENT;
|
||
|
||
//
|
||
// If the handle supplied is NULL, open the local pkt
|
||
//
|
||
|
||
if (pktHandle == NULL) {
|
||
|
||
status = PktOpen(&pktHandle, 0, 0, NULL);
|
||
|
||
if (NT_SUCCESS(status))
|
||
CloseHandle = TRUE;
|
||
}
|
||
|
||
if(NT_SUCCESS(status)) {
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose & 0x80000000) {
|
||
WCHAR wszGuid[sizeof(GUID)*2+1];
|
||
|
||
GuidToString(&_peid.Uid, wszGuid);
|
||
DbgPrint("CDfsVolume::CreateSubordinatePktEntry:\n"
|
||
"\tSupName=%ws\n"
|
||
"\tPrefix=%ws\n"
|
||
"\tShortPrefix=%ws\n"
|
||
"\tType=0x%x\n"
|
||
"\tCount=%d\n"
|
||
"\tGUID=%ws\n",
|
||
pSuperior->Prefix.Buffer,
|
||
_peid.Prefix.Buffer,
|
||
_peid.ShortPrefix.Buffer,
|
||
_EntryType,
|
||
einfo.ServiceCount,
|
||
wszGuid);
|
||
}
|
||
#endif
|
||
|
||
DfspCreateExitPoint(
|
||
pktHandle,
|
||
&_peid.Uid,
|
||
_peid.Prefix.Buffer,
|
||
_EntryType,
|
||
sizeof(ShortPrefix),
|
||
ShortPrefix);
|
||
|
||
status = PktCreateSubordinateEntry(
|
||
pktHandle,
|
||
pSuperior,
|
||
etype,
|
||
&_peid,
|
||
&einfo,
|
||
PKT_ENTRY_SUPERSEDE);
|
||
|
||
//
|
||
// If we opened the handle, close it
|
||
//
|
||
|
||
if (CloseHandle == TRUE) {
|
||
PktClose(pktHandle);
|
||
pktHandle = NULL;
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
dwErr = RtlNtStatusToDosError(status);
|
||
}
|
||
|
||
//
|
||
// Now before we leave we may have to delete the service list if we
|
||
// allocated it.
|
||
//
|
||
delete [] einfo.ServiceList;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::CreateSubordinatePktEntry() exit\n"));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
//+------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::UpdatePktEntry, public
|
||
//
|
||
// Synopsis: This method updates the PKT with all the info regarding this
|
||
// volume. It however, does not bother about any kind of
|
||
// Relational Info at all.
|
||
//
|
||
// Arguments: None
|
||
//
|
||
// Returns: ERROR_SUCCESS -- If all went well.
|
||
//
|
||
// Notes:
|
||
//
|
||
// History: 03-Feb-93 SudK Created.
|
||
//
|
||
//-------------------------------------------------------------------------
|
||
DWORD
|
||
CDfsVolume::UpdatePktEntry(
|
||
HANDLE pktHandle)
|
||
{
|
||
DFS_PKT_ENTRY_INFO einfo;
|
||
PDFS_SERVICE pService;
|
||
CDfsService *pDfsSvc;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG EntryType, count;
|
||
UNICODE_STRING ustrShortName;
|
||
BOOLEAN CloseHandle = FALSE;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::UpdatePktEntry()\n"));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CDfsVolume::UpdatePktEntry()\n");
|
||
#endif
|
||
|
||
memset(&einfo, 0, sizeof(DFS_PKT_ENTRY_INFO));
|
||
EntryType = _EntryType | PKT_ENTRY_TYPE_PERMANENT;
|
||
|
||
//
|
||
// Let us collect the service info now. Some memory allocation out here.
|
||
//
|
||
count = _DfsSvcList.GetServiceCount();
|
||
einfo.Timeout = _Timeout;
|
||
einfo.ServiceCount = count;
|
||
einfo.ServiceList = new DFS_SERVICE[count];
|
||
|
||
//447492, dont use null pointer.
|
||
if (einfo.ServiceList == NULL) {
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
return dwErr;
|
||
}
|
||
|
||
memset(einfo.ServiceList, 0, sizeof(DFS_SERVICE)*count);
|
||
|
||
pService = einfo.ServiceList;
|
||
pDfsSvc = _DfsSvcList.GetFirstService();
|
||
|
||
//
|
||
// In this loop we merely do an assignment of all the services. The
|
||
// conversion operator returns the DFS_SERVICE struct embedded in class.
|
||
//
|
||
for (ULONG i=0;i<count;i++) {
|
||
*pService = *(pDfsSvc->GetDfsService());
|
||
pService++;
|
||
pDfsmSites->LookupSiteInfo((pDfsSvc->GetReplicaInfo())->pwszServerName);
|
||
pDfsSvc = _DfsSvcList.GetNextService(pDfsSvc);
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose) {
|
||
WCHAR wszGuid[sizeof(GUID)*2+1];
|
||
|
||
GuidToString(&_peid.Uid, wszGuid);
|
||
DbgPrint("CDfsVolume::UpdatePktEntry\n"
|
||
"\tPrefix=%ws\n"
|
||
"\tShortPrefix=%ws\n"
|
||
"\tType=0x%x\n"
|
||
"\tCount=%d\n"
|
||
"\tGUID=%ws\n",
|
||
_peid.Prefix.Buffer,
|
||
_peid.ShortPrefix.Buffer,
|
||
_EntryType,
|
||
einfo.ServiceCount,
|
||
wszGuid);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// If we weren't given a handle, create one
|
||
//
|
||
|
||
if (pktHandle == NULL) {
|
||
status = PktOpen(&pktHandle, 0, 0, NULL);
|
||
if (NT_SUCCESS(status))
|
||
CloseHandle = TRUE;
|
||
}
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
status = PktCreateEntry(
|
||
pktHandle,
|
||
EntryType,
|
||
&_peid,
|
||
&einfo,
|
||
PKT_ENTRY_SUPERSEDE);
|
||
|
||
if (CloseHandle == TRUE) {
|
||
PktClose(pktHandle);
|
||
pktHandle = NULL;
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("PktCreateEntry returned 0x%x\n", status);
|
||
#endif
|
||
dwErr = RtlNtStatusToDosError(status);
|
||
}
|
||
|
||
delete [] einfo.ServiceList;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::UpdatePktEntry() exit %d\n", dwErr));
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose)
|
||
DbgPrint("CDfsVolume::UpdatePktEntry() exit %d\n", dwErr);
|
||
#endif
|
||
|
||
//
|
||
// Cant blindly return this error. This needs to be processed.
|
||
//
|
||
|
||
return(dwErr);
|
||
|
||
}
|
||
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: GuidToString
|
||
//
|
||
// Synopsis: Converts a GUID to a 32 char wchar null terminated string.
|
||
//
|
||
// Arguments: [pGuid] -- Pointer to Guid structure.
|
||
// [pwszGuid] -- wchar buffer into which to put the string
|
||
// representation of the GUID. Must be atleast
|
||
// 2 * sizeof(GUID) + 1 long.
|
||
//
|
||
// Returns: Nothing
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
const WCHAR rgwchHexDigits[] = L"0123456789ABCDEF";
|
||
|
||
VOID GuidToString(
|
||
IN GUID *pGuid,
|
||
OUT PWSTR pwszGuid)
|
||
{
|
||
PBYTE pbBuffer = (PBYTE) pGuid;
|
||
USHORT i;
|
||
|
||
for(i = 0; i < sizeof(GUID); i++) {
|
||
pwszGuid[2 * i] = rgwchHexDigits[(pbBuffer[i] >> 4) & 0xF];
|
||
pwszGuid[2 * i + 1] = rgwchHexDigits[pbBuffer[i] & 0xF];
|
||
}
|
||
pwszGuid[2 * i] = UNICODE_NULL;
|
||
}
|
||
|
||
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::CreateChildPartition, private
|
||
//
|
||
// Synopsis: This is somewhat of a wrapper around the IStorage interface.
|
||
// It merely creates a new volume object and associates the
|
||
// properties passed in with the Volume Object. We use the
|
||
// IStorage interface for this purpose.
|
||
// This method generates a GUID and uses that. It also sets
|
||
// a NULL service list and Initial State on the volume object.
|
||
//
|
||
// Arguments: [Name] -- Child Volume Object's name.
|
||
// [Type] -- Type of this volume object.
|
||
// [EntryPath] -- Dfs prefix of child volume.
|
||
// [pwszComment] -- Comment associated with this new volume
|
||
// [pUid] -- Optional guid of child volume
|
||
// [pReplInfo] -- Info regarding the server\share supporting volume
|
||
// [NewIDfsVol] -- On successful return, pointer to new child
|
||
// volume object is returned here.
|
||
//
|
||
// Returns:
|
||
//
|
||
// Notes: This Method creates a GUID and uses it. It also sets a default
|
||
// state on the volume object and associates a NULL serviceList.
|
||
//
|
||
// History: 16-Sep-1992 SudK Imported from PART.CXX
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
CDfsVolume::CreateChildPartition(
|
||
PWCHAR Name,
|
||
ULONG Type,
|
||
PWCHAR EntryPath,
|
||
PWCHAR pwszComment,
|
||
GUID *pUid,
|
||
PDFS_REPLICA_INFO pReplInfo,
|
||
CDfsVolume **NewIDfsVol
|
||
)
|
||
{
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
CDfsVolume *pDfsVol;
|
||
PWSTR pwszChildName;
|
||
CDfsService *pService;
|
||
WCHAR wszChildElement[sizeof(GUID)*2+1];
|
||
GUID Uid, *pVolId;
|
||
PWCHAR pwszChild;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildPartition(%ws)\n", Name));
|
||
|
||
if (Name == NULL) {
|
||
//
|
||
// Get a guid first.
|
||
//
|
||
dwErr = UuidCreate(&Uid);
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR, "UuidCreate failed %08lx\n", dwErr));
|
||
return(dwErr);
|
||
}
|
||
|
||
//
|
||
// Now figure out the last element of the child name from the GUID.
|
||
//
|
||
GuidToString(&Uid, wszChildElement);
|
||
pwszChild = wszChildElement;
|
||
pVolId = pUid == NULL ? &Uid : pUid;
|
||
} else {
|
||
pwszChild = Name;
|
||
pVolId = pUid;
|
||
}
|
||
|
||
//
|
||
// Now compose the full name of the child object.
|
||
//
|
||
pwszChildName = new WCHAR[wcslen(_pwzFileName)+wcslen(pwszChild)+2];
|
||
|
||
if (pwszChildName == NULL) {
|
||
|
||
*NewIDfsVol = NULL;
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
return dwErr;
|
||
|
||
}
|
||
|
||
wcscpy(pwszChildName, _pwzFileName);
|
||
wcscat(pwszChildName, L"\\");
|
||
wcscat(pwszChildName, pwszChild);
|
||
|
||
//
|
||
// Let us now instantiate a new instance of CDfsVolume and then we will
|
||
// initialise it with the appropriate Name.
|
||
//
|
||
pDfsVol = new CDfsVolume();
|
||
|
||
if (pDfsVol != NULL) {
|
||
|
||
dwErr = pDfsVol->CreateObject( pwszChildName,
|
||
EntryPath,
|
||
Type,
|
||
pReplInfo,
|
||
pwszComment,
|
||
pVolId);
|
||
|
||
//
|
||
// We set up recovery properties of creation here though this is also used
|
||
// by Move operation. This is OK however.
|
||
//
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
dwErr = pDfsVol->_Recover.SetOperationStart( DFS_RECOVERY_STATE_CREATING, NULL);
|
||
if (dwErr == ERROR_SUCCESS) {
|
||
*NewIDfsVol = pDfsVol;
|
||
//
|
||
// Create object merely creates the object. We now need to call
|
||
// initPktSvc on the service inside the serviceList.
|
||
//
|
||
pService = pDfsVol->_DfsSvcList.GetFirstService();
|
||
ASSERT(((pService==NULL) && (pReplInfo==NULL)) ||
|
||
((pService!=NULL) && (pReplInfo!=NULL)));
|
||
if (pService != NULL)
|
||
pService->InitializePktSvc();
|
||
}
|
||
else {
|
||
pDfsVol->Release();
|
||
*NewIDfsVol = NULL;
|
||
}
|
||
} else {
|
||
pDfsVol->Release();
|
||
*NewIDfsVol = NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
*NewIDfsVol = NULL;
|
||
dwErr = ERROR_OUTOFMEMORY;
|
||
|
||
}
|
||
|
||
delete [] pwszChildName;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildPartition() exit\n"));
|
||
|
||
return(dwErr);
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CDfsVolume::IsValidChildName,private
|
||
//
|
||
// Synopsis: Determines whether a prefix is a valid child prefix for this
|
||
// volume (ie, is hierarchically subordinate and there is no
|
||
// conflicting child.
|
||
//
|
||
// Arguments: [pwszChildPrefix] -- The prefix to test.
|
||
// [pidChild] -- The volume id of the proposed child volume.
|
||
//
|
||
// Returns: TRUE if the child prefix is legal, FALSE otherwise
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
BOOL CDfsVolume::IsValidChildName(
|
||
PWCHAR pwszChildPrefix,
|
||
GUID *pidChild)
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
Status = PktIsChildnameLegal(
|
||
_peid.Prefix.Buffer,
|
||
pwszChildPrefix,
|
||
pidChild);
|
||
|
||
return( (BOOL) (Status == STATUS_SUCCESS) );
|
||
|
||
}
|
||
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: CDfsVolume::NotLeafVolume, private
|
||
//
|
||
// Synopsis: Uses IStorage to find if child exists.
|
||
//
|
||
// Arguments:None
|
||
//
|
||
// Returns: TRUE if NotLeafVolume else FALSE.
|
||
//
|
||
// History: 18-May-1993 SudK Created.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
BOOL
|
||
CDfsVolume::NotLeafVolume(void)
|
||
{
|
||
ULONG fetched = 0;
|
||
CEnumDirectory *pdir;
|
||
DFSMSTATDIR rgelt;
|
||
DWORD dwErr;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::NotLeafVolume()\n"));
|
||
|
||
ASSERT(!(VolumeDeleted()));
|
||
|
||
memset(&rgelt, 0, sizeof(DFSMSTATDIR));
|
||
|
||
//
|
||
// First, we get a hold of the IDirectory interface to our own volume
|
||
// object.
|
||
//
|
||
|
||
dwErr = _pStorage->GetEnumDirectory(&pdir);
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR, "Failed to get IDirectory %08lx\n", dwErr));
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// While there are children still to be handled we continue on.
|
||
//
|
||
|
||
while (TRUE) {
|
||
|
||
if (rgelt.pwcsName != NULL) {
|
||
delete [] rgelt.pwcsName;
|
||
rgelt.pwcsName = NULL;
|
||
}
|
||
|
||
dwErr = pdir->Next(&rgelt, &fetched);
|
||
|
||
//
|
||
// Will we get an error if there are no more children.
|
||
//
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumeraate %08lx\n",dwErr));
|
||
pdir->Release();
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// If we did not get back any children we are done.
|
||
//
|
||
if (fetched == 0) {
|
||
IDfsVolInlineDebOut((DEB_TRACE, "No Children Found\n",0));
|
||
pdir->Release();
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// If the child is . or .. we look for next child.
|
||
//
|
||
ULONG cbLen = wcslen(rgelt.pwcsName);
|
||
|
||
if (cbLen < sizeof(L"..")/sizeof(WCHAR))
|
||
continue;
|
||
|
||
//
|
||
// If we got here it means that we came across a volume object
|
||
// and we have to return TRUE now.
|
||
//
|
||
IDfsVolInlineDebOut((DEB_ERROR, "Child Found - NotLeafVolume %ws\n",
|
||
rgelt.pwcsName));
|
||
pdir->Release();
|
||
delete [] rgelt.pwcsName;
|
||
return(TRUE);
|
||
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::NotLeafVolume() exit\n"));
|
||
|
||
}
|
||
|
||
|
||
//+----------------------------------------------------------------------------
|
||
//
|
||
// Function: CDfsVolume::IsValidService
|
||
//
|
||
// Synopsis: Given a server name, indicates whether the server is a valid
|
||
// server for this volume.
|
||
//
|
||
// Arguments: [pwszServer] -- Name of server to verify.
|
||
//
|
||
// Returns: TRUE if server is a valid server for this volume, FALSE
|
||
// otherwise
|
||
//
|
||
//-----------------------------------------------------------------------------
|
||
|
||
BOOLEAN
|
||
CDfsVolume::IsValidService(
|
||
IN LPWSTR pwszServer)
|
||
{
|
||
DWORD dwErr;
|
||
CDfsService *pSvc;
|
||
|
||
dwErr = _DfsSvcList.GetServiceFromPrincipalName( pwszServer, &pSvc );
|
||
|
||
return( dwErr == ERROR_SUCCESS );
|
||
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: DeallocateCacheRelationInfo, private
|
||
//
|
||
// Synopsis: This function is used to deallocate relationInfo structures
|
||
// that were allocated by GetPktCacheRelationInfo.
|
||
//
|
||
// Arguments: RelationInfo - The relationInfo struct to deallocate.
|
||
//
|
||
// Returns:
|
||
//
|
||
// History: 24-Nov-1992 SudK Created.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
VOID
|
||
DeallocateCacheRelationInfo(
|
||
DFS_PKT_RELATION_INFO & RelationInfo
|
||
)
|
||
{
|
||
PDFS_PKT_ENTRY_ID peid = &RelationInfo.EntryId;
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "Dfsm::DeallocateCacheRelationInfo()\n"));
|
||
|
||
MarshalBufferFree(peid->Prefix.Buffer);
|
||
peid->Prefix.Buffer = NULL;
|
||
|
||
if (peid->ShortPrefix.Buffer) {
|
||
MarshalBufferFree(peid->ShortPrefix.Buffer);
|
||
peid->ShortPrefix.Buffer = NULL;
|
||
}
|
||
|
||
if(peid = RelationInfo.SubordinateIdList)
|
||
{
|
||
for(ULONG i = 0; i < RelationInfo.SubordinateIdCount; i++)
|
||
{
|
||
MarshalBufferFree(peid[i].Prefix.Buffer);
|
||
peid[i].Prefix.Buffer = NULL;
|
||
if (peid[i].ShortPrefix.Buffer != NULL) {
|
||
MarshalBufferFree(peid[i].ShortPrefix.Buffer);
|
||
peid[i].ShortPrefix.Buffer = NULL;
|
||
}
|
||
}
|
||
MarshalBufferFree(RelationInfo.SubordinateIdList);
|
||
RelationInfo.SubordinateIdList = NULL;
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "Dfsm::DeallocateCacheRelationInfo() exit\n"));
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Method: GetPktCacheRelationInfo, private
|
||
//
|
||
// Synopsis: This method retrieves the relational information regarding
|
||
// a particular volume (identified by the ENTRY_ID props)
|
||
// passed in to it.
|
||
//
|
||
// Arguments: [RelationInfo] -- The relational info is returned here.
|
||
// [peid] -- The EntryID is passed in here.
|
||
//
|
||
// Returns:
|
||
//
|
||
// History: 24-Nov-1992 SudK Created.
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
GetPktCacheRelationInfo(
|
||
PDFS_PKT_ENTRY_ID peid,
|
||
PDFS_PKT_RELATION_INFO RelationInfo
|
||
)
|
||
{
|
||
//
|
||
// Initialize all return values to be NULL...
|
||
//
|
||
|
||
HANDLE pktHandle;
|
||
DWORD dwErr = ERROR_SUCCESS;
|
||
NTSTATUS status;
|
||
memset(RelationInfo, 0, sizeof(DFS_PKT_RELATION_INFO));
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::GetPktCacheRelationInfo()\n"));
|
||
|
||
status = PktOpen(&pktHandle, 0, 0, NULL);
|
||
if (NT_SUCCESS(status))
|
||
{
|
||
|
||
//
|
||
// Create/Update the Entry...
|
||
//
|
||
|
||
status = PktGetRelationInfo(
|
||
pktHandle,
|
||
peid,
|
||
RelationInfo
|
||
);
|
||
|
||
PktClose(pktHandle);
|
||
pktHandle = NULL;
|
||
};
|
||
|
||
if (!NT_SUCCESS(status))
|
||
dwErr = RtlNtStatusToDosError(status);
|
||
else
|
||
dwErr = ERROR_SUCCESS;
|
||
|
||
if (dwErr != ERROR_SUCCESS) {
|
||
IDfsVolInlineDebOut((DEB_ERROR, "Failed GetRelationInfo %08lx\n",dwErr));
|
||
}
|
||
|
||
IDfsVolInlineDebOut((DEB_TRACE, "IDfsVol::GetPktCacheRelationInfo() exit\n"));
|
||
|
||
return( dwErr );
|
||
}
|
||
|
||
NTSTATUS
|
||
DfspCreateExitPoint (
|
||
IN HANDLE DriverHandle,
|
||
IN LPGUID Uid,
|
||
IN LPWSTR Prefix,
|
||
IN ULONG Type,
|
||
IN ULONG Len,
|
||
OUT LPWSTR ShortPrefix)
|
||
{
|
||
NTSTATUS NtStatus;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
PDFS_CREATE_EXIT_POINT_ARG CreateArg;
|
||
ULONG Size = sizeof(*CreateArg);
|
||
PCHAR pWc;
|
||
|
||
if (Uid == NULL || Prefix == NULL) {
|
||
NtStatus = STATUS_INVALID_PARAMETER;
|
||
DFSM_TRACE_HIGH(ERROR, DfspCreateExitPoint_Error1,
|
||
LOGSTATUS(NtStatus)
|
||
LOGWSTR(Prefix));
|
||
goto ExitWithStatus;
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose & 0x80000000) {
|
||
WCHAR wszGuid[sizeof(GUID)*2+1];
|
||
|
||
GuidToString(Uid, wszGuid);
|
||
DbgPrint("DfspCreateExitPoint(%ws,%ws,0x%x)\n",
|
||
wszGuid,
|
||
Prefix,
|
||
Type);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Pack the args into a single buffer that can be sent to
|
||
// the dfs driver:
|
||
//
|
||
|
||
//
|
||
// First find the size...
|
||
//
|
||
|
||
if (Prefix != NULL) {
|
||
|
||
Size += (wcslen(Prefix) + 1) * sizeof(WCHAR);
|
||
|
||
}
|
||
|
||
//
|
||
// Now allocate the memory
|
||
//
|
||
|
||
CreateArg = (PDFS_CREATE_EXIT_POINT_ARG)malloc(Size);
|
||
|
||
if (CreateArg == NULL) {
|
||
|
||
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
DFSM_TRACE_HIGH(ERROR, DfspCreateExitPoint_Error2,
|
||
LOGSTATUS(NtStatus)
|
||
LOGWSTR(Prefix));
|
||
goto ExitWithStatus;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(CreateArg, Size);
|
||
|
||
//
|
||
// Put the fixed parameters into the buffer
|
||
//
|
||
CreateArg->Uid = *Uid;
|
||
CreateArg->Type = Type;
|
||
|
||
//
|
||
// Put the variable data in the buffer
|
||
//
|
||
pWc = (PCHAR)(CreateArg + 1);
|
||
|
||
CreateArg->Prefix = (LPWSTR)pWc;
|
||
RtlCopyMemory(CreateArg->Prefix, Prefix, wcslen(Prefix)*sizeof(WCHAR));
|
||
LPWSTR_TO_OFFSET(CreateArg->Prefix, CreateArg);
|
||
|
||
//
|
||
// Tell the driver!!
|
||
//
|
||
|
||
NtStatus = NtFsControlFile(
|
||
DriverHandle,
|
||
NULL, // Event,
|
||
NULL, // ApcRoutine,
|
||
NULL, // ApcContext,
|
||
&IoStatusBlock,
|
||
FSCTL_DFS_CREATE_EXIT_POINT,
|
||
CreateArg,
|
||
Size,
|
||
ShortPrefix,
|
||
Len);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(NtStatus, ALL_ERROR, DfspCreateExitPoint_Error_NtFsControlFile,
|
||
LOGSTATUS(NtStatus)
|
||
LOGWSTR(Prefix));
|
||
free(CreateArg);
|
||
|
||
ExitWithStatus:
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose & 0x80000000)
|
||
DbgPrint("DfspCreateExitPoint exit 0x%x\n", NtStatus);
|
||
#endif
|
||
|
||
return NtStatus;
|
||
}
|
||
|
||
NTSTATUS
|
||
DfspDeleteExitPoint (
|
||
IN HANDLE DriverHandle,
|
||
IN LPGUID Uid,
|
||
IN LPWSTR Prefix,
|
||
IN ULONG Type)
|
||
{
|
||
NTSTATUS NtStatus;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
PDFS_DELETE_EXIT_POINT_ARG DeleteArg;
|
||
ULONG Size = sizeof(*DeleteArg);
|
||
PCHAR pWc;
|
||
|
||
if (Uid == NULL || Prefix == NULL) {
|
||
NtStatus = STATUS_INVALID_PARAMETER;
|
||
DFSM_TRACE_HIGH(ERROR, DfspDeleteExitPoint_Error1,
|
||
LOGSTATUS(NtStatus)
|
||
LOGWSTR(Prefix));
|
||
goto ExitWithStatus;
|
||
}
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose & 0x80000000) {
|
||
WCHAR wszGuid[sizeof(GUID)*2+1];
|
||
|
||
GuidToString(Uid, wszGuid);
|
||
DbgPrint("DfspDeleteExitPoint(%ws,%ws,0x%x)\n",
|
||
wszGuid,
|
||
Prefix,
|
||
Type);
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Pack the args into a single buffer that can be sent to
|
||
// the dfs driver:
|
||
//
|
||
|
||
//
|
||
// First find the size...
|
||
//
|
||
|
||
if (Prefix != NULL) {
|
||
|
||
Size += (wcslen(Prefix) + 1) * sizeof(WCHAR);
|
||
|
||
}
|
||
|
||
//
|
||
// Now allocate the memory
|
||
//
|
||
|
||
DeleteArg = (PDFS_DELETE_EXIT_POINT_ARG)malloc(Size);
|
||
|
||
if (DeleteArg == NULL) {
|
||
|
||
NtStatus = STATUS_INSUFFICIENT_RESOURCES;
|
||
DFSM_TRACE_HIGH(ERROR, DfspDeleteExitPoint_Error2,
|
||
LOGSTATUS(NtStatus)
|
||
LOGWSTR(Prefix));
|
||
goto ExitWithStatus;
|
||
|
||
}
|
||
|
||
RtlZeroMemory(DeleteArg, Size);
|
||
|
||
//
|
||
// Put the fixed parameters into the buffer
|
||
//
|
||
DeleteArg->Uid = *Uid;
|
||
DeleteArg->Type = Type;
|
||
|
||
//
|
||
// Put the variable data in the buffer
|
||
//
|
||
pWc = (PCHAR)(DeleteArg + 1);
|
||
|
||
DeleteArg->Prefix = (LPWSTR)pWc;
|
||
RtlCopyMemory(DeleteArg->Prefix, Prefix, wcslen(Prefix)*sizeof(WCHAR));
|
||
LPWSTR_TO_OFFSET(DeleteArg->Prefix, DeleteArg);
|
||
|
||
//
|
||
// Tell the driver!!
|
||
//
|
||
|
||
NtStatus = NtFsControlFile(
|
||
DriverHandle,
|
||
NULL, // Event,
|
||
NULL, // ApcRoutine,
|
||
NULL, // ApcContext,
|
||
&IoStatusBlock,
|
||
FSCTL_DFS_DELETE_EXIT_POINT,
|
||
DeleteArg,
|
||
Size,
|
||
NULL,
|
||
0);
|
||
|
||
DFSM_TRACE_ERROR_HIGH(NtStatus, ALL_ERROR, DfspDeleteExitPoint_Error_NtFsControlFile,
|
||
LOGSTATUS(NtStatus)
|
||
LOGWSTR(Prefix));
|
||
free(DeleteArg);
|
||
|
||
ExitWithStatus:
|
||
|
||
#if DBG
|
||
if (DfsSvcVerbose & 0x80000000)
|
||
DbgPrint("DfspDeleteExitPoint exit 0x%x\n", NtStatus);
|
||
#endif
|
||
|
||
return NtStatus;
|
||
}
|