|
|
//+-------------------------------------------------------------------------
//
// File: idfsvol.cxx
//
// Contents: Implementation of IDfsVolume interface. This interface
// supports the administrative functions on DFS.
//
//--------------------------------------------------------------------------
//#include <ntos.h>
//#include <ntrtl.h>
//#include <nturtl.h>
//#include <dfsfsctl.h>
//#include <windows.h>
#include "headers.hxx"
#pragma hdrstop
#include "dfsmsrv.h"
#include "dfsm.hxx"
#include "cdfsvol.hxx"
#include "jnpt.hxx"
#include "dfsmwml.h"
VOID ComputeNewEntryPath( PWCHAR oldPath, PWCHAR newPath, PWCHAR childPath, PWCHAR *childNewPath );
NTSTATUS MoveFileOrJP( IN PCWSTR pwszSrcName, IN PCWSTR pwszTgtName );
//+-------------------------------------------------------------------------
//
// Method: AddReplicaToObj, private
//
// Synopsis: This method adds a replica info structure to the volume
// object and returns after that.
//
// Arguments: [pReplicaInfo] -- The ReplicaInfo structure.
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::AddReplicaToObj( PDFS_REPLICA_INFO pReplicaInfo ) { DWORD dwErr = ERROR_SUCCESS; CDfsService *pService = NULL;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplicaToObj()\n"));
//
// First before we even set recoveryProperties we want to make sure
// that this service does not already exist in the ServiceList.
//
if ((dwErr == ERROR_SUCCESS) && (_DfsSvcList.GetService(pReplicaInfo, &pService) == ERROR_SUCCESS)) { dwErr = NERR_DfsDuplicateService; }
if (dwErr == ERROR_SUCCESS) { //
// Argument validation also takes place right in this constructor.
// Also the ServiceName etc. gets converted to an ORG based name in
// the constructor. So we dont need to worry about that at all.
//
pService = new CDfsService(pReplicaInfo, TRUE, &dwErr);
if (pService == NULL) dwErr = ERROR_OUTOFMEMORY;
}
if (dwErr == ERROR_SUCCESS) {
//
// Set the new service properties on the volume object. This method
// will return an error code if the service already exists on the
// volume object. No explicit checking need be done here.
//
if (dwErr == ERROR_SUCCESS) {
pService->SetCreateTime();
dwErr = _DfsSvcList.SetNewService(pService);
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_ERROR, "Failed to Set new replica %08lx\n",dwErr)); }
}
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplicaToObj() exit\n"));
return(dwErr); }
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::AddReplica, public
//
// Synopsis: This function associates a new service with an existing
// Volume Object. A new service is defined by the ServiceName,
// StorageId, Type of Service, and sometimes an AddressQualifier.
// For this operation to succeed the service being added should
// be available. Unavailability of the service will result in
// failure of this method. This operation will be atomic as far
// as all information on the DC is concerned. Either the operation
// will succeed or no irrelevant information will be left on the
// DC. However, there are no guarantees made regarding the state
// of the service involved in the face of Network Failures and
// remote service crashes etc. If you attempt to add the same
// service name again it will return an error.
//
// Arguments: [pReplicaInfo] -- The ServiceInfo here. Look at docs for details
//
// Returns: ERROR_SUCCESS -- If the operation succeeded.
//
// ERROR_OUTOFMEMORY -- Unable to allocate memory for operation.
//
// NERR_DfsVolumeIsOffline -- The volume is offline, can't do
// AddReplica operation on it.
//
// NERR_DfsDuplicateService --
// If the service already exists on this volume.
//
// NERR_DfsVolumeDataCorrupt --
// If the volume object to which this
// service is being added is corrupt.
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::AddReplica( PDFS_REPLICA_INFO pReplicaInfo, ULONG fCreateOptions ) { DWORD dwErr = ERROR_SUCCESS; PWCHAR ErrorStrs[3]; CDfsService *pService = NULL;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplica()\n"));
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::AddReplica(%ws,%ws,0x%x)\n", pReplicaInfo->pwszServerName, pReplicaInfo->pwszShareName); #endif
if (_State == DFS_VOLUME_STATE_OFFLINE) {
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::AddReplica exit NERR_DfsVolumeIsOffline\n"); #endif
return( NERR_DfsVolumeIsOffline ); }
//
// First before we even set recoveryProperties we want to make sure
// that this service does not already exist in the ServiceList.
//
if (_DfsSvcList.GetService(pReplicaInfo, &pService) == ERROR_SUCCESS) { #if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::AddReplica: returning NERR_DfsDuplicateService\n"); #endif
pService = NULL; // So we don't try to delete
dwErr = NERR_DfsDuplicateService; // it later...
}
if (dwErr == ERROR_SUCCESS) { //
// Argument validation also takes place right in this constructor.
// Also the ServiceName etc. gets converted to an ORG based name in
// the constructor. So we dont need to worry about that at all.
//
pService = new CDfsService(pReplicaInfo, TRUE, &dwErr);
if (pService == NULL) dwErr = ERROR_OUTOFMEMORY;
}
if (dwErr == ERROR_SUCCESS) {
pService->SetCreateTime();
RECOVERY_TEST_POINT(L"AddReplica", 1);
//
// This is where we want to do some STATE changes. Register the
// intent of doing an AddReplicaoperation and mention the service
// name and record that we are in the Start State. RECOVERY
// If we cant set recovery props then something is really wrong.
// The following constructor will throw an exception and we will
// deal with it appropriately.
//
dwErr = _Recover.SetOperationStart( DFS_RECOVERY_STATE_ADD_SERVICE, pService);
RECOVERY_TEST_POINT(L"AddReplica", 2);
//
// Set the new service properties on the volume object. This method
// will return an error code if the service already exists on the
// volume object. No explicit checking need be done here.
//
if (dwErr == ERROR_SUCCESS) { dwErr = _DfsSvcList.SetNewService(pService); }
if (dwErr != ERROR_SUCCESS) { //
// 433532, SetNewService already deletes pservice in case of
// failure. Dont use pservice, and set it to NULL so it does
// not get freed twice!
pService = NULL;
//LogMessage( DEB_TRACE,
// &(pService->GetServiceName()),
// 1,
// DFS_CANNOT_SET_SERVICE_PROPERTY_MSG);
}
}
if (dwErr == ERROR_SUCCESS) { //
// Now we need to change the state to UpdatedSvcList RECOVERY
//
RECOVERY_TEST_POINT(L"AddReplica", 3);
_Recover.SetOperStage(DFS_OPER_STAGE_SVCLIST_UPDATED);
RECOVERY_TEST_POINT(L"AddReplica", 4);
//
// Let us now ask the remote machine to create a local volume.
// If we fail to do this for ANY reason, we fail the operation.
//
dwErr = pService->CreateLocalVolume(&_peid, _EntryType);
//
// If we failed, it might be because the server's state is not
// consistent with our state. See if this is the case, and
//
//
// If we failed we need to delete the entry from the serviceList.
// We have to use the servicename from the DfsSvc class since that
// is the ORG based name. If we get an error here as well then
// we will return that error (dwErr2) since it becomes more relevant
// suddenly. Else we will return the error we got above from
// CreateLocalVolume which will be returning a proper error to us.
//
if (dwErr != ERROR_SUCCESS) {
DWORD dwErr2 = _DfsSvcList.DeleteService(pService, FALSE); PWCHAR ErrorStrs[1];
ErrorStrs[0] = (pService->GetServiceName()); if (dwErr2 != ERROR_SUCCESS) { LogMessage( DEB_ERROR, ErrorStrs, 1, DFS_CANNOT_DELETE_SERVICE_PROPERTY_MSG);
dwErr = NERR_DfsVolumeDataCorrupt;
} else {
//
// DeleteService() deleted this instance for us, so set the
// pointer to NULL
//
pService = NULL;
} } } //CreateLocalVolumeDone OR FAILED.
//
// Now we set state to DONE on vol object. It is of no concern whether
// the operation succeeded or failed.
//
RECOVERY_TEST_POINT(L"AddReplica", 5);
_Recover.SetOperationDone();
if (dwErr == ERROR_SUCCESS) { //
// Now we update the PKT with the new service. We get an
// appropriate Error Code from UpdatePktEntry.
//
dwErr = UpdatePktEntry(NULL); if (dwErr != ERROR_SUCCESS) { //
// Why should this fail at all.
// An EVENT here too maybe.
//
LogMessage( DEB_ERROR, &(_peid.Prefix.Buffer), 1, DFS_FAILED_UPDATE_PKT_MSG); IDfsVolInlineDebOut((DEB_ERROR, "UpdPktEntFailed %08lx\n", dwErr)); ASSERT(L"UpdatePktEntry Failed in AddService - WHY?"); }
} //UpdatePktEntry Block.
if (dwErr != ERROR_SUCCESS) { _Recover.SetOperationDone(); if (pService != NULL) delete pService; }
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplica() exit\n"));
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::AddReplica exit %d\n", dwErr); #endif
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Member: CDfsVolume::RemoveReplicaFromObj, public
//
// Synopsis: This operation removes a replica from a volume object and
// returns after that.
//
// Arguments: [pwszServiceName] -- Name of server to remove
//
// Returns:
//
//-----------------------------------------------------------------------------
DWORD CDfsVolume::RemoveReplicaFromObj( IN LPWSTR pwszServiceName) { DWORD dwErr; CDfsService *pSvc;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplicaFromObj(%ws)\n", pwszServiceName));
dwErr = _DfsSvcList.GetServiceFromPrincipalName( pwszServiceName, &pSvc );
if (dwErr == ERROR_SUCCESS) {
//
// See if this is the last service. In that case, we cannot
// permit anyone to delete it.
//
if (_DfsSvcList.GetServiceCount() == 1) { dwErr = NERR_DfsCantRemoveLastServerShare; }
//
// Now delete the service from the service list
//
dwErr = _DfsSvcList.DeleteService(pSvc);
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplicaFromObj() exit\n"));
return( dwErr );
}
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::RemoveReplica, public
//
// Synopsis: This operation dissociates a service from a volume in the DFS
// namespace. On the DC this merely involves modifying the service
// List on the Volume object. At the same time the service involved
// has to be notified of this change. This operation will fail if
// for some reason the service refuses to delete its knowledge
// regarding this volume or if there are network failures
// during this operation. Of course if we fail the operation due
// to Network failures note the fact that the operation at the
// remote service might have succeeded and network failed after
// that - in which case we may have an INCONSISTENCY (very easy to
// detect this one).
//
// Arguments: [pwszServiceName] -- The name of the service to be deleted
// from the volume object.
//
// Returns: DFS_S_SUCCESS -- If the operation succeeded.
//
// NERR_DfsNoSuchShare -- If the specified server\share is not
// a service for this volume.
//
// NERR_DfsCantRemoveLastServerShare -- If the specified
// server\share is the only service for this volume.
//
// NERR_DfsVolumeDataCorrupt -- If the volume object could not
// be read.
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::RemoveReplica( PDFS_REPLICA_INFO pReplicaInfo, ULONG fDeleteOptions ) { DWORD dwErr = ERROR_SUCCESS; DWORD dwErr2 = ERROR_SUCCESS; PWCHAR orgServiceName = NULL; CDfsService *pDfsSvc; PWCHAR ErrorStrs[3];
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplica()\n"));
dwErr = _DfsSvcList.GetService(pReplicaInfo, &pDfsSvc);
if (dwErr != ERROR_SUCCESS) {
LogMessage( DEB_TRACE, nullPtr, 0, DFS_SERVICE_DOES_NOT_EXIST_MSG); }
if (dwErr == ERROR_SUCCESS && _EntryType & DFS_VOL_TYPE_REFERRAL_SVC && !(_EntryType & DFS_VOL_TYPE_INTER_DFS)) { dwErr = NERR_DfsCantRemoveDfsRoot; }
if (dwErr == ERROR_SUCCESS) {
//
// See if this is the last service. In that case, we cannot
// permit anyone to delete it.
//
if (_DfsSvcList.GetServiceCount() == 1) { dwErr = NERR_DfsCantRemoveLastServerShare; }
}
if (dwErr != ERROR_SUCCESS) {
return(dwErr); }
if (dwErr == ERROR_SUCCESS) {
//
// Next we register the intent to delete a specific service by
// marking the ServiceName on the object. RECOVERY.
//
RECOVERY_TEST_POINT(L"RemoveReplica", 1);
dwErr = _Recover.SetOperationStart(DFS_RECOVERY_STATE_REMOVE_SERVICE, pDfsSvc);
RECOVERY_TEST_POINT(L"RemoveReplica", 2);
//
// Now that we know that such a service is actually registered.
// Let us request the remote service to delete LVOL knowledge.
//
if (dwErr == ERROR_SUCCESS) { dwErr = pDfsSvc->DeleteLocalVolume(&_peid); }
if (dwErr != ERROR_SUCCESS) { //
// We assume that if we got an error here we are in big trouble
// and we back out the operation infact. The DeleteLocalVolume
// method would have already taken care of filtering out the
// relevant errors for us.
//
LogMessage( DEB_TRACE, &(_peid.Prefix.Buffer), 1, DFS_DELETE_VOLUME_FAILED_MSG);
//
// Since we got this error we assume that we could not find
// the service. However, that need not be the reason at all.
// Raid: 455283. Need to resolve this later on.
//
dwErr = NERR_DfsNoSuchShare; } }
if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
//
// Now we write out RecoveryState to DFS_OPER_STAGE_INFORMED_SERVICE
//
RECOVERY_TEST_POINT(L"RemoveReplica", 3);
_Recover.SetOperStage(DFS_OPER_STAGE_INFORMED_SERVICE);
RECOVERY_TEST_POINT(L"RemoveReplica", 4);
//
// Now write out the new service list
//
dwErr2 = _DfsSvcList.DeleteService(pDfsSvc);
if (dwErr2 != ERROR_SUCCESS) { //
// This should never happen. We probably had some security
// problems. Do we now go and back out the Previous Step. Raid 455283
//
ErrorStrs[1] = pDfsSvc->GetServiceName(); ErrorStrs[0] = _peid.Prefix.Buffer; LogMessage( DEB_ERROR, ErrorStrs, 2, DFS_CANNOT_DELETE_SERVICE_PROPERTY_MSG); ASSERT(L"Deleting and existing service FAILED in RemRepl"); } }
//
// Done. The operation is committed if the last stage of deleting
// service succeeded, else we dont want to remove the recovery property.
// If we never got to the last stage of DeleteService dwErr2 will be
// ERROR_SUCCESS.
//
RECOVERY_TEST_POINT(L"RemoveReplica", 5);
if (dwErr2 == ERROR_SUCCESS) _Recover.SetOperationDone();
if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) { //
// Now update the PKT as well.
//
dwErr = UpdatePktEntry(NULL); if (dwErr != ERROR_SUCCESS) { //
// Something is really messed up if we got here.
//
LogMessage(DEB_ERROR, nullPtr, 0, DFS_FAILED_UPDATE_PKT_MSG); IDfsVolInlineDebOut((DEB_ERROR, "UpdPktEntry in RemRepl failed %08lx\n", dwErr)); ASSERT(L"UpdatePktEntry in RemoveRepl failed\n"); } }
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplica() exit\n"));
return(dwErr); }
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::Delete, public
//
// Synopsis: This method deletes the volume object and deletes all knowledge
// of this volume at all the services that were supporting this
// volume in the namespace. At the same time the exit point at the
// parent volume is deleted. All of the services that support this
// volume are also advised to delete all information regarding this
// volume. There is an additional restriction that there should
// be only one service associated with a volume to be able to call
// method. This operation has problems due to its distributed
// nature. The moment the service supporting this volume has been
// informed to delete its local volume knowledge this operation is
// committed. In the case of Network failures while talking to one
// of the services involved, this operation continues to go on. If
// any such errors are encountered they are reported to the caller
// though the operation is declared to be a success. Note that this
// operation does not delete the storage and has nothing to do with
// that aspect. By not confirming the deletion of all ExitPoint
// info anywhere this operation can directly introduce an
// inconsistency of TOO MANY EXIT Points. This inconsistency is
// well understood and easy to deal with.
//
// Arguments: None
//
// Returns: DFS_S_SUCCESS -- If all went well.
//
// NERR_DfsNotALeafVolume --
// An attempt was made to delete a volume which
// has child volumes and hence the operation failed
//
// NERR_DfsVolumeDataCorrupt --
// The volume object seems to be corrupt due to
// which this operation cannot proceed at all.
//
// NERR_DfsVolumeHasMultipleServers --
// This operation will not succeed if there is
// more than one service assoicated with the vol.
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::Delete( ULONG fDeleteOptions) { DWORD dwErr = ERROR_SUCCESS; CDfsVolume *parent = NULL; BOOLEAN InconsistencyPossible = FALSE; BOOLEAN ParentInconsistency = FALSE; CDfsService *pDfsSvc; ULONG rState = 0; ULONG count = 0; PWCHAR ErrorStrs[3];
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Delete()\n"));
if (NotLeafVolume()) dwErr = NERR_DfsNotALeafVolume;
//
// We want to make sure that this is not the root volume
//
if (dwErr == ERROR_SUCCESS && _EntryType & DFS_VOL_TYPE_REFERRAL_SVC && !(_EntryType & DFS_VOL_TYPE_INTER_DFS)) { dwErr = NERR_DfsCantRemoveDfsRoot; }
//
// We next want to make sure that there is only one service associated
// with this volume else we will fail this operation right now.
//
if (dwErr == ERROR_SUCCESS) if (_DfsSvcList.GetServiceCount()>1) dwErr = NERR_DfsVolumeHasMultipleServers;
if (dwErr != ERROR_SUCCESS) {
return(dwErr); }
if(dwErr == ERROR_SUCCESS) {
//
// we are going to need to talk with the parent once the
// child is gone, so we get a handle to it now.
// If we fail to bind to parent. Then it probably means that
// this is a top level volume object and hence cannot be deleted.
// We return the error to the caller.
//
dwErr = GetParent(&parent);
if (dwErr != ERROR_SUCCESS) { LogMessage(DEB_TRACE, nullPtr, 0, DFS_CANT_GET_PARENT_MSG); dwErr = NERR_DfsVolumeDataCorrupt; } }
if (dwErr != ERROR_SUCCESS) {
return(dwErr); }
if (dwErr == ERROR_SUCCESS) {
//
// Before we take off on our operation. We should setup the
// State variable on the Volume object indicating that we are
// deleting this volume from the namespace.
//
RECOVERY_TEST_POINT(L"DeleteVolume", 1);
dwErr = _Recover.SetOperationStart(DFS_RECOVERY_STATE_DELETE, NULL);
RECOVERY_TEST_POINT(L"DeleteVolume", 2);
//
// Now we inform the service to delete its LocalVolume knowledge.
//
if (dwErr == ERROR_SUCCESS) { pDfsSvc = _DfsSvcList.GetFirstService();
if (pDfsSvc != NULL) { dwErr = pDfsSvc->DeleteLocalVolume(&_peid); //
// If we got an error here, we dont really want to go on??
//
// When we move to DWORDs we might want to return exactly
// which service did not get updated etc.
//
} } }
if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
//
// Now we set Recovery State to new value if we have informed
// all related services.
//
RECOVERY_TEST_POINT(L"DeleteVolume", 3);
_Recover.SetOperStage(DFS_OPER_STAGE_INFORMED_SERVICE);
RECOVERY_TEST_POINT(L"DeleteVolume", 4);
//
// We need to tell each service of the parent volume to delete the
// exit point. I think at this point we have to force the operation
// through. Even if we are not able to delete some exit points it
// is OK. We will return a success error code but will indicate
// that there could potentially be a possible inconsistency in the
// parent volume's knowledge.
//
pDfsSvc = parent->_DfsSvcList.GetFirstService(); while (pDfsSvc != NULL) {
//
// Ignore error codes from this. We dont care if we cant
// make some machine to delete the exit point.
// The possible things that could happen here are that the
// remote machine will say that it cannot delete the exit
// point since the GUIDs dont match OR the exit point does
// not exist (It got deleted due to reconciliation) or
// Network failures themselves. In all cases we dont care.
// We will return a status code which indicates that one
// of the parent services misbehaved and admin needs to
// make sure that nothing is wrong.
//
dwErr = pDfsSvc->DeleteExitPoint(&_peid, _EntryType);
if (dwErr != ERROR_SUCCESS) { PWCHAR ErrorStrs[1]; ParentInconsistency = TRUE; ErrorStrs[0] = pDfsSvc->GetServiceName(); LogMessage(DEB_ERROR, ErrorStrs, 1, DFS_CANT_DELETE_EXIT_POINT_MSG); IDfsVolInlineDebOut((DEB_ERROR, "ErrorCode from DeleteExitPoint %08lx\n", dwErr)); } dwErr = ERROR_SUCCESS; pDfsSvc = parent->_DfsSvcList.GetNextService(pDfsSvc);
}
}
//
// We want to get rid of the parent pointer if we no longer need it.
//
if (parent != NULL) { parent->Release(); parent = NULL; }
//
// If the operation failed we want to set the properties to done else
// we are anyway going to go in and delete this object itself.
//
RECOVERY_TEST_POINT(L"DeleteVolume", 5);
if (dwErr != ERROR_SUCCESS) { _Recover.SetOperationDone(); }
//
// If we successfully managed to do the deletion then we go ahead
// and delete the volume object from disk. Note that even if
// Network failures occur while talking to each of the services
// above we will go on. Once this deletion happens the operation is
// commited. Updating the PKT is not a part of the commit point.
//
if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) { DeleteObject(); //
// We need to make this instance of the VolumeObject invalid or
// so that no one can do any more operations on this volume.
//
_Deleted = TRUE; }
//
// Now we go and update the PKT with the deletion information.
// Once again we ignore errors here except to return an
// INCONSISTENCY status code.
//
if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
dwErr = DeletePktEntry(&_peid);
if (dwErr != ERROR_SUCCESS) {
LogMessage( DEB_ERROR, &(_peid.Prefix.Buffer), 1, DFS_CANT_DELETE_ENTRY_MSG);
IDfsVolInlineDebOut(( DEB_ERROR, "DelPktEnt Failed%08lx\n", dwErr));
ASSERT(L"DeletePktEntry Failed in Deletion of Volume");
dwErr = ERROR_SUCCESS;
}
}
if (parent != NULL) parent->Release();
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Delete() exit\n"));
return( dwErr ); }
//+-------------------------------------------------------------------------
//
// Method: CDfsVolume::CreateChildX, public
//
// Synopsis: This is one way of creating new volume objects.
// This operation involves the creation of the volume object,
// Updating the parent's knowledge regarding the new exit point
// and creating the exit point. The parent volume could have
// multiple replicas. In this case all the replicas are informed
// of the changes and are advised to create the relevant knowledge.
// This operation will roll back in the event of a failure during
// the operation before it is complete. If all of the parent's
// cannot create the exit point information then this operation
// will not proceed. Every attempt will be made to delete all
// information that was created on other replicas but no guarantees
// are made about this. However, all local knowledge will be
// deleted and knowledge synchronisation is supposed to eliminate
// any problems that might have arised because of inconsistencies
// created by this operation.
//
// Arguments: [pwszChildName] -- The last component of child Vol object Name.
//
// [pwszEntryPath] -- The entry path for the new volume in the namespace
//
// [ulVolType] -- The type of the volume.
// Values in the IDL file for this interface.
//
// [pChild] -- This is where the IDfsVolume reference is
// returned to caller.
//
// [pComment] -- Comment for this volume.
//
// Returns: ERROR_SUCCESS -- If the operation succeeded with NO problems.
//
// ERROR_INVALID_PARAMETER -- The child volume's prefix is not
// hierarchically subordinate to this volume's prefix.
//
// NERR_DfsVolumeIsInterDfs -- The volume is an inter-dfs one;
// can't create a child volume.
//
// NERR_DfsNotSupportedInServerDfs -- Can't have more than one
// level of hierarchy in Server Dfs.
//
// NERR_DfsLeafVolume -- This is a downlevel or leaf volume,
// can't create a child here.
//
// NERR_DfsCantCreateJunctionPoint -- Unable to create a
// junction point on any of the server-shares
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::CreateChildX( WCHAR * childName, WCHAR * pwszPrefix, ULONG ulVolType, LPWSTR pwszComment, CDfsVolume **ppChild) { DWORD dwErr = ERROR_SUCCESS; CDfsVolume *pChild = NULL; CDfsService *pDfsSvc = NULL; BOOLEAN CreatedExitPt = FALSE; BOOLEAN InconsistencyPossible = FALSE; PWCHAR pwszSuffix = NULL; PWCHAR ErrorStrs[3]; ULONG ulen = 0; LPWSTR wszChildShortName; BOOLEAN GotShortName = FALSE;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildX(%ws,%ws,0x%x,%s)\n", childName, pwszPrefix, ulVolType, pwszComment));
#if DBG
if (DfsSvcVerbose) DbgPrint("DfsVolume::CreateChildX(%ws,%ws,0x%x,%ws)\n", childName, pwszPrefix, ulVolType, pwszComment); #endif
//
// Check for validity of Type field and for LEAF volume etc. Only the
// allowed TypeBits should be set and also one of the Three required Types
// bits should be set.
//
//
// We check to make sure that the prefix of the child volume meets
// our heirarchy requirements. It must be strictly a child of this
// volume's prefix, and must not cross inter-dfs boundaries.
//
if (dwErr == ERROR_SUCCESS) {
if (_EntryType & DFS_VOL_TYPE_INTER_DFS) {
dwErr = NERR_DfsVolumeIsInterDfs;
} else if (ulDfsManagerType == DFS_MANAGER_SERVER && ((_EntryType & DFS_VOL_TYPE_REFERRAL_SVC) == 0)) {
dwErr = NERR_DfsVolumeAlreadyExists; #if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::CreateChildX: dwErr = NERR_DfsVolumeAlreadyExists\n"); #endif
} else if (_wcsnicmp(_peid.Prefix.Buffer, pwszPrefix, wcslen(_peid.Prefix.Buffer)) != 0) {
dwErr = ERROR_INVALID_PARAMETER; #if DBG
if (DfsSvcVerbose) { DbgPrint("CDfsVolume::CreateChildX(1): [%ws]!=[%ws] (1st %d chars)\n", _peid.Prefix.Buffer, pwszPrefix, wcslen(_peid.Prefix.Buffer)); DbgPrint("CDfsVolume::CreateChildX(1): dwErr = ERROR_INVALID_PARAMETER\n"); } #endif
} else {
//
// In this case we want to make sure that the new EntryPath
// is also greater than the entrypath for this volume, and that
// it is a valid Win32 Path name
//
LPWSTR wszExitPath = &pwszPrefix[_peid.Prefix.Length/sizeof(WCHAR)];
if (wcslen(pwszPrefix) <= wcslen(_peid.Prefix.Buffer)) {
if (_wcsicmp(pwszPrefix,_peid.Prefix.Buffer) == 0) { dwErr = NERR_DfsVolumeAlreadyExists; } else { dwErr = ERROR_INVALID_PARAMETER; } #if DBG
if (DfsSvcVerbose) { DbgPrint("CDfsVolume::CreateChildX(2): dwErr = %d\n"); DbgPrint(" pwszPrefix=[%ws],_peid.Prefix.Buffer=[%ws]\n", pwszPrefix, _peid.Prefix.Buffer); } #endif
} else if (!IsValidWin32Path( wszExitPath )) {
dwErr = ERROR_BAD_PATHNAME; #if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::CreateChildX: dwErr = ERROR_BAD_PATHNAME\n"); #endif
}
}
}
if (dwErr == ERROR_SUCCESS) {
//
// We first try to create the volume object. So that we can use
// it to go about our state management stuff for recovery purposes.
// It automatically sets recoveryState to being OPER_START etc.
// It will also set a NULL service list for now. This method will
// also pick a GUID for us. We dont need to pass it one.
//
dwErr = CreateChildPartition( childName, ulVolType, pwszPrefix, pwszComment, NULL, NULL, &pChild);
if (dwErr != ERROR_SUCCESS) {
IDfsVolInlineDebOut(( DEB_ERROR, "Unable to create child %ws\n under : %ws\n", pwszPrefix, _peid.Prefix.Buffer));
}
}
if (dwErr == ERROR_SUCCESS) {
RECOVERY_TEST_POINT(L"CreateChildX", 1);
//
// We next try to create exit points on each of the services for
// the parent volume. However, we need to create an exit point on
// only one of the services for the parent volume. We rely on
// Replication to reconcile everything to other machines.
//
pDfsSvc = _DfsSvcList.GetFirstService();
while (pDfsSvc!=NULL) {
dwErr = pDfsSvc->CreateExitPoint( &(pChild->_peid), ulVolType);
if (dwErr == ERROR_SUCCESS) {
//
// This would have updated the short name. Save it...
//
CreatedExitPt = TRUE;
if (!GotShortName) {
DWORD dwErrUpdatedShortName;
dwErrUpdatedShortName = pChild->SaveShortName();
if (dwErrUpdatedShortName == ERROR_SUCCESS) {
GotShortName = TRUE;
IDfsVolInlineDebOut(( DEB_TRACE, "Setting short name to: %ws\n", pChild->_peid.ShortPrefix.Buffer));
} else {
IDfsVolInlineDebOut(( DEB_ERROR, "Error %08lx setting short name\n", dwErrUpdatedShortName)); }
}
} else {
InconsistencyPossible = TRUE;
IDfsVolInlineDebOut(( DEB_ERROR, "Failed to CreateExPt %08lx %ws\n", dwErr, pChild->_peid.Prefix.Buffer));
}
dwErr = ERROR_SUCCESS;
pDfsSvc = _DfsSvcList.GetNextService(pDfsSvc);
}
//
// If we did create an exit point on atleast one machine we can go on.
// Also we can set the state to DONE!!
//
if (CreatedExitPt == TRUE) {
//
// We need to ClearUp Recovery Properties here!!
//
RECOVERY_TEST_POINT(L"CreateChildX", 2);
pChild->_Recover.SetOperationDone();
} else {
//
// We have to delete the object that we created. dwErr already
// has an error code in it. Let that go by us. Remember however,
// the exit point itself never got created as far as the DC is
// concerned and hence makes no sense to try to undo that stuff.
//
LogMessage( DEB_ERROR,nullPtr,0,DFS_CANT_CREATE_ANY_EXIT_POINT_MSG);
pChild->DeleteObject();
dwErr = NERR_DfsCantCreateJunctionPoint;
}
}
//
// Now we merely need to update the PKT with the relevant information.
//
if (dwErr == ERROR_SUCCESS) {
dwErr = pChild->CreateSubordinatePktEntry(NULL, &_peid, FALSE);
if (dwErr != ERROR_SUCCESS) { LogMessage( DEB_ERROR, &_peid.Prefix.Buffer, 1, DFS_CANT_CREATE_SUBORDINATE_ENTRY_MSG);
IDfsVolInlineDebOut(( DEB_ERROR, "Failed CreateSubordPktEntry %08lx\n", dwErr));
ASSERT(L"CreateSubordinateEntry Failed in CreateChild");
}
}
if (dwErr != ERROR_SUCCESS) {
if (pChild != NULL) pChild->Release();
*ppChild = NULL;
} else {
*ppChild = pChild;
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildX() exit %d\n", dwErr));
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::CreateChildX exit %d\n", dwErr); #endif
return((dwErr));
}
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::CreateChild, public
//
// Synopsis: This is one way of creating new volume objects.
// This operation involves the creation of the volume object,
// Updating the parent's knowledge regarding the new exit point
// and creating the exit point. The parent volume could have
// multiple replicas. In this case all the replicas are informed
// of the changes and are advised to create the relevant knowledge.
// This operation will roll back in the event of a failure during
// the operation before it is complete. Every attempt will be made
// to delete all information that was created on other replicas
// but no guarantees are made about this. However, all local
// knowledge will be deleted and knowledge synchronisation is
// supposed to eliminate any problems that might have arised
// because of inconsistencies created by this operation. This
// operation also associates a SERVICE with the volume that it
// creates (unlike the CreateChild/CreateInActiveVolume) operation.
// Hence it also needs to communicate with the relevant service.
//
// Arguments: [pwszEntryPath] -- The entry path for the new volume in the namespace
// This entry path is relative to the parent's entrypath.
//
// [ulVolType] -- The type of the volume. Look in dfsh.idl
//
// [pReplInfo] -- The ServiceInfo for the first replica.
//
// [pChild] -- This is where the IDfsVolume reference is
// returned to caller.
//
// [pwszComment] -- Comment for this volume.
//
// Returns: Error code from CreateChildX() or AddReplica().
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::CreateChild( LPWSTR pwszPrefix, ULONG ulVolType, PDFS_REPLICA_INFO pReplicaInfo, PWCHAR pwszComment, ULONG fCreateOptions) { CDfsVolume *pChild;
DWORD dwErr = ERROR_SUCCESS;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChild(%ws,0x%x,%ws,0x%x)\n", pwszPrefix, ulVolType, pwszComment, fCreateOptions));
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::CreateChild(%ws,0x%x,%ws,%ws,%ws,0x%x)\n", pwszPrefix, ulVolType, pReplicaInfo->pwszServerName, pReplicaInfo->pwszShareName, pwszComment, fCreateOptions); #endif
if (VolumeOffLine()) {
return( NERR_DfsVolumeIsOffline ); }
//
// I will cheat for now but will come back and fix this later on. Raid 455283
// At this place I basically need to have a recovery mechanism to recover
// in between the operations etc. The entire operation should be done or
// undone. In the present scheme only the two suboperations below will
// be in some sense "atomic" but not this entire operation itself.
//
dwErr = CreateChildX( NULL, // Dont give any child name.
pwszPrefix, ulVolType, pwszComment, &pChild);
if (dwErr != ERROR_SUCCESS) {
return((dwErr)); }
//
// Now let us go ahead and associate a service with the volume object that
// we just created.
//
dwErr = pChild->AddReplica(pReplicaInfo, fCreateOptions);
//
// If AddServic failed then we have to delete the object itself and
// backout the entire operation.
//
if (dwErr != ERROR_SUCCESS) pChild->Delete(DFS_OVERRIDE_FORCE);
pChild->Release();
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChild() exit\n"));
#if DBG
if (DfsSvcVerbose) DbgPrint("CDfsVolume::CreateChild exit %d\n", dwErr); #endif
return((dwErr)); }
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::Move, public
//
// Synopsis: This operation moves a volume from one place in the namespace
// to another point in the namespace. Here we need the
// volume Name and the new entry Path. The old entryPath is
// already available to us since we can get it from the properties
// on the volume object. The volume to be moved should be a leaf
// volume (should have no children) else this operation will
// return an Error Code.
//
// Arguments: [pwszNewPrefix] -- The new EntryPath for this volume. This
// should be absolute path.
//
// Returns: ERROR_SUCCESS -- The operation succeeded.
//
// ERROR_INVALID_PARAMETER -- If pwszNewPrefix is a
// hierarchically below the current prefix!
//
// NERR_DfsVolumeAlreadyExists -- A Dfs volume with the same
// prefix as pwszNewPrefix already exists
//
// Error from various IDfsvol methods.
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::Move( LPWSTR pwszNewPrefix ) { DWORD dwErr = ERROR_SUCCESS;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Move(%ws)\n", pwszNewPrefix));
CDfsVolume *pNewParentVol = NULL; CDfsVolume *pChildVol = NULL; CDfsVolume *pOldParentVol = NULL;
BOOLEAN CreatedExitPt = FALSE; CDfsService *pService; CDfsService *pNextService; DFS_PKT_ENTRY_ID NewId;
LPWSTR pwszChildName = NULL; LPWSTR pwszNewParentPrefix = NULL; LPWSTR pwszNewParentObject = NULL; ULONG volPrefixLen, prefixLen;
if (VolumeOffLine()) { return(NERR_DfsVolumeIsOffline); }
if (NotLeafVolume()) { return(NERR_DfsNotALeafVolume); }
//
// Get a hold of the new parent, and check the validity of pwszNewPrefix
// in the process
//
prefixLen = wcslen( pwszNewPrefix ); pwszNewParentPrefix = new WCHAR[prefixLen + 1]; prefixLen *= sizeof(WCHAR);
if (pwszNewParentPrefix == NULL) {
dwErr = ERROR_OUTOFMEMORY;
} else {
wcscpy( pwszNewParentPrefix, pwszNewPrefix );
dwErr = pDfsmStorageDirectory->GetObjectForPrefix( pwszNewParentPrefix, FALSE, &pwszNewParentObject, &volPrefixLen);
if (dwErr == ERROR_SUCCESS) {
pwszNewParentPrefix[ volPrefixLen/sizeof(WCHAR) ] = UNICODE_NULL; if (prefixLen == volPrefixLen) { dwErr = NERR_DfsVolumeAlreadyExists; } else { if (!_wcsnicmp(pwszNewParentPrefix, _peid.Prefix.Buffer, _peid.Prefix.Length/sizeof(WCHAR))) { //
// This means that we are trying to move somewhere
// below where we already are in the namespace. This
// is total nonsense. Return right now.
//
dwErr = ERROR_INVALID_PARAMETER;
} }
} else { IDfsVolInlineDebOut(( DEB_ERROR, "Failed to FindVolPrefix %08lx %ws\n", dwErr, pwszNewParentPrefix)); } }
//
// Instantiate the parent and cleanup strings used to get parent...
//
if (dwErr == ERROR_SUCCESS) {
pNewParentVol = new CDfsVolume();
if (pNewParentVol != NULL) {
dwErr = pNewParentVol->LoadNoRegister( pwszNewParentObject, 0);
} else {
dwErr = ERROR_OUTOFMEMORY;
}
}
delete [] pwszNewParentPrefix;
if (pwszNewParentObject != NULL) { delete [] pwszNewParentObject; }
if (dwErr == ERROR_SUCCESS) {
//
// Now that we have a handle on the appropriate volume object we
// can go ahead and perform the move.
//
dwErr = pNewParentVol->CreateChildPartition( NULL, _EntryType, pwszNewPrefix, _pwszComment, &_peid.Uid, NULL, &pChildVol);
delete [] pwszChildName;
RECOVERY_TEST_POINT(L"Move", 1);
}
//
// If we succeeded in creating the object then we need to go and
// set the service List appropriately. Note that we will not
// set any recovery properties for now. We will exploit the recovery
// props setup by CreateChildPartition.
//
if (dwErr == ERROR_SUCCESS) {
pService = _DfsSvcList.GetFirstService(); while (pService != NULL) { pNextService = _DfsSvcList.GetNextService(pService); _DfsSvcList.RemoveService(pService); dwErr = pChildVol->_DfsSvcList.SetNewService(pService); if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut((DEB_ERROR, "Failed to Set SvcProp %08lx\n",dwErr)); break; } pService = pNextService; }
//
// Now we need to carefully remove the services from inmemory
// instantiation of the new pChildVol
//
pService = pChildVol->_DfsSvcList.GetFirstService(); while (pService != NULL) { pNextService = pChildVol->_DfsSvcList.GetNextService(pService); pChildVol->_DfsSvcList.RemoveService(pService); _DfsSvcList.InsertNewService(pService); pService = pNextService; }
//
// If we failed to set service list we delete the object and we
// get out.
//
if (dwErr != ERROR_SUCCESS) { pChildVol->DeleteObject(); }
}
//
// If we succeeded in creating the new object we go on to create the
// New ExitPoint
//
if (dwErr == ERROR_SUCCESS) {
//
// Let us switch to new EntryPath. We want to avoid mem allocations
// here itself.
//
NewId = _peid; NewId.Prefix.Length = wcslen(pwszNewPrefix)*sizeof(WCHAR); NewId.Prefix.MaximumLength = NewId.Prefix.Length + sizeof(WCHAR); NewId.Prefix.Buffer = pwszNewPrefix;
//
// Now we can create the exit point at the appropriate place.
//
pService = pNewParentVol->_DfsSvcList.GetFirstService(); ASSERT(pService != NULL);
while (pService != NULL) { dwErr = pService->CreateExitPoint(&NewId, _EntryType); if (dwErr == ERROR_SUCCESS) { CreatedExitPt = TRUE; } pService = pNewParentVol->_DfsSvcList.GetNextService(pService); }
if (CreatedExitPt == TRUE) { //
// This operation is committed now and we can set the
// Recovery Properties on the new object to DONE.
//
//
// Now before we set the recovery Properties to be done on the
// new object. We have to set the appropriate recovery props
// on the current object so that we can force this operation
// forward.
//
dwErr = _Recover.SetOperationStart(DFS_RECOVERY_STATE_MOVE, NULL);
//
// Now we set the recovery properties on the new object to
// DONE since there is nothing that needs to be done over there
// if we fail now. The only recovery (or roll forward) code will
// be triggered off this volume object itself.
//
RECOVERY_TEST_POINT(L"Move", 2);
if (dwErr == ERROR_SUCCESS) { pChildVol->_Recover.SetOperationDone(); } } else { //
// Cant go on with this operation so let us get rid of the
// object that we created.
//
IDfsVolInlineDebOut((DEB_TRACE, "Unable to create Exit Pt %ws for Move\n", pwszNewPrefix)); pChildVol->DeleteObject(); dwErr = NERR_DfsCantCreateJunctionPoint; }
}
//
// Now if we passed the last stage then there is no stopping in this
// operation anymore.
//
if (dwErr == ERROR_SUCCESS) { //
// Let us get to the old parent and delete the exit point first.
//
dwErr = GetParent(&pOldParentVol);
if (dwErr == ERROR_SUCCESS) { pService = pOldParentVol->_DfsSvcList.GetFirstService(); ASSERT(pService != NULL); //
// We ignore all errors here.
//
while(pService != NULL) { dwErr = pService->DeleteExitPoint(&_peid, _EntryType); pService = pOldParentVol->_DfsSvcList.GetNextService(pService); } dwErr = ERROR_SUCCESS; } else { IDfsVolInlineDebOut((DEB_ERROR, "Unable to get to the parent vol for %ws\n", _pwzFileName)); } RECOVERY_TEST_POINT(L"Move", 3); //
// Now we merely need to do a modify Prefix operation on the current
// volume's services.
//
pService = _DfsSvcList.GetFirstService(); ASSERT(pService != NULL); while (pService != NULL) { dwErr = pService->ModifyPrefix(&NewId); if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut((DEB_ERROR, "Unable to Modify prefix to %ws %08lx\n", NewId.Prefix.Buffer, dwErr)); } pService = _DfsSvcList.GetNextService(pService); } dwErr = ERROR_SUCCESS;
//
// We can now delete this object itself.
//
DeleteObject(); _Deleted = FALSE;
//
// We now need to change the _pwzFileName of this idfsvol to match
// the new child that we have created. Also need to change E.P.
//
ULONG uLen = wcslen(pChildVol->_pwzFileName);
if ((uLen > wcslen(_pwzFileName)) && (uLen > MAX_PATH)) { if (_pwzFileName != _FileNameBuffer) delete [] _pwzFileName; _pwzFileName = new WCHAR[uLen + 1]; } wcscpy(_pwzFileName, pChildVol->_pwzFileName);
//
// Now the entrypath prefix.
//
uLen = NewId.Prefix.Length; if (uLen > _peid.Prefix.Length) { if (_peid.Prefix.Buffer != _EntryPathBuffer) delete [] _peid.Prefix.Buffer;
if (uLen >= MAX_PATH) _peid.Prefix.Buffer = new WCHAR[(uLen+1)]; else _peid.Prefix.Buffer = _EntryPathBuffer; } _peid.Prefix.Length = (USHORT)uLen; _peid.Prefix.MaximumLength = _peid.Prefix.Length + sizeof(WCHAR); wcscpy(_peid.Prefix.Buffer, NewId.Prefix.Buffer);
//
// Now we get the IStorage's etc. over to this idfsvol. We steal.
//
ASSERT((_pStorage == NULL) && (_Recover._pPSStg == NULL) && (_DfsSvcList._pPSStg == NULL));
_pStorage = pChildVol->_pStorage; pChildVol->_pStorage = NULL; _Recover._pPSStg = pChildVol->_Recover._pPSStg; _DfsSvcList._pPSStg = pChildVol->_DfsSvcList._pPSStg; pChildVol->_Recover._pPSStg = NULL; pChildVol->_DfsSvcList._pPSStg = NULL;
//
// Copy over the child's registration id, so we can revoke that
// as well. We need to revoke it because it has been registered
// with the child's CDfsVol address.
//
_dwRotRegistration = pChildVol->_dwRotRegistration; pChildVol->_dwRotRegistration = NULL;
//
// Now we have to update the DC's PKT entry itself.
//
dwErr = UpdatePktEntry(NULL); if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut((DEB_ERROR, "Unable to updatePkt entry %08lx for %ws\n", dwErr, pChildVol->_peid.Prefix.Buffer)); }
}
if (pNewParentVol != NULL) { pNewParentVol->Release(); }
if (pChildVol != NULL) { pChildVol->Release(); }
if (pOldParentVol != NULL) { pOldParentVol->Release(); }
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Move() exit\n"));
return((dwErr)); }
//+------------------------------------------------------------------------
//
// Method: CDfsVolume::InitializePkt, public
//
// Synopsis: This method initilaizes the PKT with info regarding this
// volume and also sets up the relational info for itself. It
// also continues to recursively call all the child volume
// objects' InitializePkt method.
//
// Arguments: None
//
// Notes: This is a recursive method. By calling this we can initialise
// the PKT with info regarding this volume and all its children
// since it is a recursive routine. This is a DEPTH-FIRST Traversal
//
// History: 09-Feb-93 SudK Created.
//
//-------------------------------------------------------------------------
DWORD CDfsVolume::InitializePkt( HANDLE PktHandle) {
DWORD dwErr = ERROR_SUCCESS; CEnumDirectory *pDir = NULL; DFSMSTATDIR rgelt; ULONG fetched = 0; CDfsVolume *child = NULL;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::InitializePkt()\n"));
#if DBG
if (DfsSvcVerbose & 0x80000000) DbgPrint("CDfsVolume::InitializePkt()\n"); #endif
memset(&rgelt, 0, sizeof(DFSMSTATDIR));
//
// First, we get a hold of the CRegEnumDirectory 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(dwErr); }
//
// 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);
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumerate %08lx\n", dwErr)); break; } //
// If we did not get back any children we are done.
//
if (fetched == 0) break;
IDfsVolInlineDebOut(( DEB_TRACE, "CDfsVolume::InitializePkt Name=%ws\n", rgelt.pwcsName));
//
// If the child name is . or .. we ignore it
//
if ((!wcscmp(rgelt.pwcsName, L".")) || (!wcscmp(rgelt.pwcsName, L".."))) continue;
dwErr = GetDfsVolumeFromStg(&rgelt, &child);
if (dwErr != ERROR_SUCCESS) { //
// Log an EVENT here saying that volume object is corrupt and
// continue on. We dont want to stop just because we cant handle
// one particular object.
//
LogMessage( DEB_ERROR, &(_peid.Prefix.Buffer), 1, DFS_CANT_GET_TO_CHILD_IDFSVOL_MSG); IDfsVolInlineDebOut((DEB_ERROR, "Bad Object: %ws\n", rgelt.pwcsName)); //
// We dont want to give up as yet. So let us go on to the next
// object.
//
fetched = 0; //Do I need to do this??
continue; }
if (DFS_GET_RECOVERY_STATE(child->_RecoveryState) != DFS_RECOVERY_STATE_NONE) { //
// Now we need to call the recovery method to handle this stuff.
// What do I do with the error code that I get back out here.
//
LogMessage(DEB_ERROR, &(child->_peid.Prefix.Buffer), 1, DFS_RECOVERY_NECESSARY_MSG); IDfsVolInlineDebOut((DEB_ERROR, "Object To Recover From: %ws\n", rgelt.pwcsName)); dwErr = child->RecoverFromFailure(); //
// We failed to recover from failure. The required messages would
// have already been logged so we dont need to bother about that
// here at all. But a failure in this process means we really cant
// go on here. We would get a failure from the above only if there
// was some drastic problem.
//
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut((DEB_ERROR, "Fatal RecoveryError \n")); }
if (child->_Deleted == TRUE) { //
// Due to above recovery the volume got deleted. No point
// going on along this path. Move on to next sibling.
//
child->Release(); fetched = 0; continue; } }
if (dwErr == ERROR_SUCCESS) {
//
// Create the subordinate PKT entry for the child. This way we
// get to setup the links as well.
//
dwErr = child->CreateSubordinatePktEntry(PktHandle, &_peid, TRUE); if (dwErr != ERROR_SUCCESS) { //
// This is a chance to write out an EVENT and then continue
// to the Initialization of further children. We need to
// continue on even though we could not get to finish this
// volume.
//
LogMessage(DEB_ERROR, &(child->_peid.Prefix.Buffer), 1, DFS_UNABLE_TO_CREATE_SUBORDINATE_ENTRY_MSG); IDfsVolInlineDebOut((DEB_ERROR, "Object For Above Error: %ws\n", rgelt.pwcsName)); } }
//
// Now that the subordinate entry has been created we can go ahead
// and call InitialisePkt on child. This makes a DepthFirst traversal.
// Even if we could not create the subordinate entry for some reason,
// we need to go on and attempt to initialize the rest. But we really
// cant do that here. Riad: 455283. We need a different approach here.
//
if (dwErr == ERROR_SUCCESS) { dwErr = child->InitializePkt(PktHandle); if (dwErr != ERROR_SUCCESS) { //
// We ignore this error and also dont bother to write out an
// event since this should have been handled by some lower method.
// We maybe sitting many levels high up and this error came all
// the way back up.
//
IDfsVolInlineDebOut((DEB_ERROR, "InitPkt failed %08lx\n", dwErr)); } }
child->Release(); //
// Let us now attempt to enumerate the next child.
//
fetched = 0;
} //While fetched!=0
//
// If this volume's state is offline, set the local DC's pkt to reflect
// that case
//
if (_State == DFS_VOLUME_STATE_OFFLINE) {
NTSTATUS Status; CDfsService *psvc;
for (psvc = _DfsSvcList.GetFirstService(); psvc != NULL; psvc = _DfsSvcList.GetNextService(psvc)) {
LPWSTR wszService;
wszService = psvc->GetServiceName();
Status = DfsSetServiceState( &_peid, wszService, DFS_SERVICE_TYPE_OFFLINE);
}
Status = DfsDCSetVolumeState( &_peid, PKT_ENTRY_TYPE_OFFLINE);
}
if (rgelt.pwcsName != NULL) delete [] rgelt.pwcsName;
if (pDir != NULL) pDir->Release();
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::InitializePkt() exit\n"));
#if DBG
if (DfsSvcVerbose & 0x80000000) DbgPrint("CDfsVolume::InitializePkt exit %d\n", dwErr); #endif
return(dwErr); }
//+----------------------------------------------------------------------------
//
// Function: GetNetInfo
//
// Synopsis: Gets information about the volume.
//
// Arguments: [Level] -- Level of Information desired.
//
// [pInfo] -- Pointer to info struct to be filled. Pointer
// members will be allocated using MIDL_user_allocate.
// The type of this variable is LPDFS_INFO_3, but one
// can pass in pointers to lower levels, and only the
// fields appropriate for the level will be touched.
//
// [pcbInfo] -- On successful return, contains the size in
// bytes of the returned info. The returned size does
// not include the size of the DFS_INFO_3 struct itself.
//
// Returns: ERROR_SUCCESS -- Successfully returning info
//
// ERROR_OUTOFMEMORY -- Out of memory
//
//-----------------------------------------------------------------------------
DWORD CDfsVolume::GetNetInfo( DWORD Level, LPDFS_INFO_3 pInfo, LPDWORD pcbInfo) { DWORD dwErr = ERROR_SUCCESS; DWORD cbInfo = 0, cbItem;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetNetInfo(l=%d)\n", Level));
#if DBG
if (DfsSvcVerbose) DbgPrint(" CDfsVolume::GetNetInfo(l=%d)\n", Level); #endif
//
// See if this is a Level 100 or 101. If so, we handle them right away
// and return
if (Level == 100) {
LPDFS_INFO_100 pInfo100 = (LPDFS_INFO_100) pInfo;
cbItem = (wcslen(_pwszComment) + 1) * sizeof(WCHAR);
pInfo100->Comment = (LPWSTR) MIDL_user_allocate(cbItem);
if (pInfo100->Comment != NULL) {
wcscpy(pInfo100->Comment, _pwszComment);
*pcbInfo = cbItem;
return( ERROR_SUCCESS );
} else {
return( ERROR_OUTOFMEMORY );
}
}
if (Level == 101) {
LPDFS_INFO_101 pInfo101 = (LPDFS_INFO_101) pInfo;
pInfo->State = _State;
return( ERROR_SUCCESS );
}
//
// level 4 isn't just an extension of 3, so handle it seperately
//
if (Level == 4) {
LPDFS_INFO_4 pInfo4 = (LPDFS_INFO_4) pInfo;
cbItem = sizeof(UNICODE_PATH_SEP) + _peid.Prefix.Length + sizeof(WCHAR);
pInfo4->EntryPath = (LPWSTR) MIDL_user_allocate(cbItem);
if (pInfo4->EntryPath != NULL) {
pInfo4->EntryPath[0] = UNICODE_PATH_SEP;
wcscpy(&pInfo4->EntryPath[1], _peid.Prefix.Buffer);
cbInfo += cbItem;
} else {
dwErr = ERROR_OUTOFMEMORY;
}
if (dwErr == ERROR_SUCCESS) {
cbItem = (wcslen(_pwszComment)+1) * sizeof(WCHAR); pInfo4->Comment = (LPWSTR) MIDL_user_allocate(cbItem);
if (pInfo4->Comment != NULL) {
wcscpy( pInfo4->Comment, _pwszComment );
cbInfo += cbItem;
} else {
dwErr = ERROR_OUTOFMEMORY;
}
}
if (dwErr == ERROR_SUCCESS) {
pInfo4->State = _State;
pInfo4->Timeout = _Timeout;
pInfo4->Guid = _peid.Uid;
pInfo4->NumberOfStorages = _DfsSvcList.GetServiceCount();
cbItem = pInfo4->NumberOfStorages * sizeof(DFS_STORAGE_INFO); pInfo4->Storage = (LPDFS_STORAGE_INFO) MIDL_user_allocate(cbItem);
if (pInfo4->Storage != NULL) {
ULONG i; CDfsService *pSvc;
RtlZeroMemory(pInfo4->Storage, cbItem);
cbInfo += cbItem;
pSvc = _DfsSvcList.GetFirstService();
i = 0;
while (pSvc != NULL && dwErr == ERROR_SUCCESS) {
dwErr = pSvc->GetNetStorageInfo(&pInfo4->Storage[i], &cbItem);
cbInfo += cbItem;
i++;
pSvc = _DfsSvcList.GetNextService( pSvc );
}
if (dwErr != ERROR_SUCCESS) {
for (; i > 0; i--) {
MIDL_user_free(pInfo4->Storage[i-1].ServerName); MIDL_user_free(pInfo4->Storage[i-1].ShareName);
}
}
} else {
dwErr = ERROR_OUTOFMEMORY;
}
}
//
// See if we need to clean up...
//
if (dwErr != ERROR_SUCCESS) {
if (pInfo4->EntryPath != NULL) {
MIDL_user_free(pInfo4->EntryPath);
}
if (pInfo4->Storage != NULL) {
MIDL_user_free(pInfo4->Storage);
}
}
*pcbInfo = cbInfo;
return(dwErr);
}
//
// Level is 1,2 or 3
//
//
// Fill in the Level 1 stuff
//
cbItem = sizeof(UNICODE_PATH_SEP) + _peid.Prefix.Length + sizeof(WCHAR);
pInfo->EntryPath = (LPWSTR) MIDL_user_allocate(cbItem);
if (pInfo->EntryPath != NULL) {
pInfo->EntryPath[0] = UNICODE_PATH_SEP;
wcscpy(&pInfo->EntryPath[1], _peid.Prefix.Buffer);
cbInfo += cbItem;
} else {
dwErr = ERROR_OUTOFMEMORY;
}
//
// Fill in the Level 2 stuff if needed
//
if (dwErr == ERROR_SUCCESS && Level > 1) {
cbItem = (wcslen(_pwszComment)+1) * sizeof(WCHAR); pInfo->Comment = (LPWSTR) MIDL_user_allocate(cbItem);
if (pInfo->Comment != NULL) {
wcscpy( pInfo->Comment, _pwszComment );
cbInfo += cbItem;
} else {
dwErr = ERROR_OUTOFMEMORY;
}
}
if (dwErr == ERROR_SUCCESS && Level > 1) {
pInfo->State = _State;
pInfo->NumberOfStorages = _DfsSvcList.GetServiceCount();
}
//
// Fill in the Level 3 stuff if needed
//
if (dwErr == ERROR_SUCCESS && Level > 2) {
cbItem = pInfo->NumberOfStorages * sizeof(DFS_STORAGE_INFO); pInfo->Storage = (LPDFS_STORAGE_INFO) MIDL_user_allocate(cbItem);
if (pInfo->Storage != NULL) {
ULONG i; CDfsService *pSvc;
RtlZeroMemory(pInfo->Storage, cbItem);
cbInfo += cbItem;
pSvc = _DfsSvcList.GetFirstService();
i = 0;
while (pSvc != NULL && dwErr == ERROR_SUCCESS) {
dwErr = pSvc->GetNetStorageInfo(&pInfo->Storage[i], &cbItem);
cbInfo += cbItem;
i++;
pSvc = _DfsSvcList.GetNextService( pSvc );
}
if (dwErr != ERROR_SUCCESS) {
for (; i > 0; i--) {
MIDL_user_free(pInfo->Storage[i-1].ServerName); MIDL_user_free(pInfo->Storage[i-1].ShareName);
}
}
} else {
dwErr = ERROR_OUTOFMEMORY;
}
}
//
// See if we need to clean up...
//
if (dwErr != ERROR_SUCCESS) {
if (Level > 1) {
if (pInfo->EntryPath != NULL) {
MIDL_user_free(pInfo->EntryPath);
}
}
if (Level > 2) {
if (pInfo->Storage != NULL) {
MIDL_user_free(pInfo->Storage);
} } }
//
// Finally, we are done
//
*pcbInfo = cbInfo;
return(dwErr);
}
//+-----------------------------------------------------------------------
//
// Member: CDfsVolume::SetComment, public
//
// Synopsis: Sets a comment on the volume object.
//
// Arguments: [pwszComment] -- The comment
//
// Returns:
//
// History: 05/10/93 SudK Created.
//
//------------------------------------------------------------------------
DWORD CDfsVolume::SetComment( PWCHAR pwszComment ) { DWORD dwErr = ERROR_SUCCESS; SYSTEMTIME st; FILETIME ftOld; LPWSTR pwszOldComment; ULONG ulen = wcslen(pwszComment);
IDfsVolInlineDebOut((DEB_TRACE, "SetComment: %ws\n", pwszComment));
ftOld = _ftComment; pwszOldComment = _pwszComment; _pwszComment = new WCHAR[ulen+1];
if (_pwszComment == NULL) dwErr = ERROR_OUTOFMEMORY; else { wcscpy(_pwszComment, pwszComment);
GetSystemTime( &st ); SystemTimeToFileTime( &st, &_ftComment );
dwErr = SetIdProps( _EntryType, _State, _peid.Prefix.Buffer, _peid.ShortPrefix.Buffer, _peid.Uid, pwszComment, _Timeout, _ftEntryPath, _ftState, _ftComment, FALSE); }
if (dwErr != ERROR_SUCCESS) { if (_pwszComment) { delete [] _pwszComment; } _ftComment = ftOld; _pwszComment = pwszOldComment; }
return(dwErr); }
//+-------------------------------------------------------------------------
//
// Member: CDfsVolume::FixServiceKnowledge
//
// Synopsis: This method is called for fixing knowledge inconsistencies.
// It checks to make sure that the given service does support
// this volume and then goes on to do a CreateLocalVol call on
// that service.
//
// Arguments: [pwszServiceName] -- The principal name of service to be
// fixed.
//
// History: 06-April-1993 SudK Created
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::FixServiceKnowledge( PWCHAR pwszServiceName ) {
DWORD dwErr = ERROR_SUCCESS; CDfsService *pService; PWCHAR ErrorStrs[3];
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::FixServiceKnowledge(%s)\n", pwszServiceName));
dwErr = _DfsSvcList.GetServiceFromPrincipalName(pwszServiceName, &pService);
if (dwErr == ERROR_SUCCESS) {
//
// We really dont care about errors since this is all heuristic. We
// will merely log an error that's all.
//
dwErr = pService->FixLocalVolume(&_peid, _EntryType);
if (dwErr != ERROR_SUCCESS) {
//
// Log the error and try to take the service off-line
//
DWORD dwErrOffLine;
ErrorStrs[0] = _peid.Prefix.Buffer; ErrorStrs[1] = pwszServiceName;
LogMessage( DEB_ERROR, ErrorStrs, 2, DFS_CANNOT_SET_SERVICE_PROPERTY_MSG);
dwErrOffLine = pService->SetVolumeState( &_peid, DFS_SERVICE_TYPE_OFFLINE, FALSE);
if (dwErrOffLine == ERROR_SUCCESS) {
dwErrOffLine = _DfsSvcList.SerializeSvcList(); }
if (dwErrOffLine == ERROR_SUCCESS) {
_DfsSvcList.SetServiceListProperty( FALSE );
}
}
} else {
IDfsVolInlineDebOut(( DEB_ERROR, "Could not find Service %ws on Volume: %ws\n", pwszServiceName, _peid.Prefix.Buffer));
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::FixServiceKnowledge() exit\n"));
return((dwErr));
}
//+---------------------------------------------------------------------
//
// Member: CDfsVolume::Rename, public
//
// Synopsis: This method should be called if an object/file/directory
// on this volume is to be renamed, and the name falls along an
// exit point off this volume. This method will perform the
// rename on the filesystem and then go on to call ModifyPrefix
// on all the child volume objects which are affected by the
// rename operation.
//
// Arguments: [oldPrefix] -- The oldPrefix that needs to be modified. Prefix
// [newPrefix] -- This should be ORG relative prefix.
//
// Returns: ERROR_SUCCESS -- If all went well.
//
// Notes: The old and newPaths should follow all requirements of a File
// System Rename operation. Should vary only in last component etc.
//
// History: 31 April 1993 SudK Created.
// 26 April 1993 SudK Fixed to work properly.
//
//----------------------------------------------------------------------
DWORD CDfsVolume::Rename( PWSTR oldPrefix, PWSTR newPrefix ) {
DWORD dwErr = ERROR_SUCCESS; CDfsVolume *child = NULL; CEnumDirectory *pdir = NULL; DFSMSTATDIR rgelt; ULONG fetched = 0; WCHAR wszOldPath[MAX_PATH], wszNewPath[MAX_PATH]; PWSTR pwszOldPath = wszOldPath; PWSTR pwszNewPath = wszNewPath; ULONG len = MAX_PATH;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Rename(%ws,%ws)\n", oldPrefix, newPrefix));
//
// Need to check if this is the right idfsvol to call rename on.
//
ULONG ulen = _peid.Prefix.Length/sizeof(WCHAR);
if ((wcslen(oldPrefix) <= ulen) || (wcslen(newPrefix) <= ulen)) { //
// Both old and new prefixes should be longer than the prefix of
// this volume. If they are not then we can return error right away.
//
dwErr = NERR_DfsBadRenamePath; } else if ((_wcsnicmp(_peid.Prefix.Buffer, oldPrefix, ulen) != 0) || (_wcsnicmp(_peid.Prefix.Buffer, newPrefix, ulen) != 0)) {
//
// Now we need to check to make sure that this volume's prefix is a
// proper prefix of path being renamed.
//
dwErr = NERR_DfsBadRenamePath;
} else if (_wcsicmp(oldPrefix, newPrefix) == 0) { //
// Someone has given identical rename path. Return right away.
//
dwErr = NERR_DfsBadRenamePath; }
if (dwErr == ERROR_SUCCESS) {
len = wcslen(oldPrefix);
if (len > (MAX_PATH - 2)) { pwszOldPath = new WCHAR[ len + 2 ]; if (pwszOldPath == NULL) { dwErr = ERROR_OUTOFMEMORY; } }
if (dwErr == ERROR_SUCCESS) { wcscpy( pwszOldPath, UNICODE_PATH_SEP_STR ); wcscat( pwszOldPath, oldPrefix ); }
}
if (dwErr == ERROR_SUCCESS) {
len = wcslen(newPrefix);
if (len > (MAX_PATH - 2)) { pwszNewPath = new WCHAR[ len + 2 ]; if (pwszNewPath == NULL) { dwErr = ERROR_OUTOFMEMORY; } }
if (dwErr == ERROR_SUCCESS) { wcscpy( pwszNewPath, UNICODE_PATH_SEP_STR ); wcscat( pwszNewPath, newPrefix ); }
}
if (dwErr == ERROR_SUCCESS) { //
// Now do the Rename operation
//
NTSTATUS Status;
Status = MoveFileOrJP(pwszOldPath, pwszNewPath);
if (!NT_SUCCESS(Status)) { dwErr = RtlNtStatusToDosError(Status); } if (pwszOldPath != wszOldPath) { delete [] pwszOldPath; } if (pwszNewPath != wszNewPath) { delete [] pwszNewPath; } }
if (dwErr == ERROR_SUCCESS) {
dwErr = _pStorage->GetEnumDirectory(&pdir); if (dwErr != ERROR_SUCCESS) { return(dwErr); }
//
// While there are children still to be handled we continue on.
//
rgelt.pwcsName = NULL;
while (TRUE) {
if (rgelt.pwcsName != NULL) { delete [] rgelt.pwcsName; rgelt.pwcsName = NULL; }
dwErr = pdir->Next(&rgelt, &fetched);
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumeraate\n", 0)); break; } //
// If we did not get back any children we are done.
//
if (fetched == 0) break;
//
// If the child name is . or .. we ignore it
//
if ((!wcscmp(rgelt.pwcsName, L".")) || (!wcscmp(rgelt.pwcsName, L".."))) continue;
dwErr = GetDfsVolumeFromStg(&rgelt, &child);
if (dwErr != ERROR_SUCCESS) { //
// Log an EVENT here saying that volume object is corrupt and
// continue on. We dont want to stop just because we cant handle
// one particular object.
//
LogMessage( DEB_ERROR, &(_peid.Prefix.Buffer), 1, DFS_CANT_GET_TO_CHILD_IDFSVOL_MSG); //
// We dont want to give up as yet. So let us go on to the next
// object.
//
fetched = 0; continue; }
dwErr = child->ModifyEntryPath(oldPrefix, newPrefix); if (dwErr != ERROR_SUCCESS) { //
// We ignore this err since it would be logged further down.
//
}
child->Release();
//
// Let us now attempt to enumerate the next child.
//
fetched = 0;
} //While TRUE
if (pdir != NULL) pdir->Release();
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Rename() exit\n"));
return(dwErr);
}
//+----------------------------------------------------------------------------
//
// Method: CDfsVolume::ModifyLocalEntryPath,private
//
// Synopsis: This method modifies the entry path on the volume object,
// and modifies the local PKT to reflect the change.
//
// Arguments:
//
// Returns:
//
//-----------------------------------------------------------------------------
DWORD CDfsVolume::ModifyLocalEntryPath( PWCHAR newEntryPath, FILETIME ftEntryPath, BOOL fUpdatePkt) { DWORD dwErr = ERROR_SUCCESS; CUnicodeString oldString, newString;
dwErr = SetIdProps( _EntryType, _State, newEntryPath, _peid.ShortPrefix.Buffer, _peid.Uid, _pwszComment, _Timeout, ftEntryPath, _ftState, _ftComment, FALSE);
if (dwErr != ERROR_SUCCESS) { //
// We want to return right away. Can we hope that the private section
// variable will get deleted and return or should we fix the private
// _peid since this operation never succeeded.
//
IDfsVolInlineDebOut(( DEB_ERROR, "Unable To modify Prefix to [%ws]\n", newEntryPath));
return(dwErr); //Raid: 455283 cant return this error here.
}
//
// Now that the object has changed let us modify the Private variables.
//
oldString.Copy(_peid.Prefix.Buffer);
newString.Copy(newEntryPath); if (_peid.Prefix.Buffer != _EntryPathBuffer) delete [] _peid.Prefix.Buffer; newString.Transfer(&(_peid.Prefix));
if (fUpdatePkt) { dwErr = UpdatePktEntry(NULL); }
if (dwErr != ERROR_SUCCESS) {
DWORD dwErr2; delete [] _peid.Prefix.Buffer; oldString.Transfer(&(_peid.Prefix)); dwErr2 = SetIdProps(_EntryType, _State, _peid.Prefix.Buffer, _peid.ShortPrefix.Buffer, _peid.Uid, _pwszComment, _Timeout, _ftEntryPath, _ftState, _ftComment, FALSE);
if (dwErr2 != ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_ERROR, "Error restoring id props in failed rename operation %08lx\n", dwErr2)); }
} else {
_ftEntryPath = ftEntryPath;
}
return(dwErr);
}
//+---------------------------------------------------------------------
//
// Method: CDfsVolume::ModifyEntryPath,public
//
// Synopsis: This method modifies the entry path on this volume object
// and at the same time modifies the entry paths on all the
// services by issuing FSCTRLs. It then turns around and calls
// the same API on all the children since their entrypaths are
// also affected by this change.
//
// Arguments: [oldPrefix] -- The old Prefix on the Parent volume object.
// [newPrefix] -- The new Prefix on the Parent volume object.
//
// Returns: ERROR_SUCCESS -- If all went well.
//
// Notes: This method does not bother to check for the validity of
// the new entryPath etc. THat should have happened way before
// we got here.
//
// History: 31 April 1993 SudK Created.
//
//----------------------------------------------------------------------
DWORD CDfsVolume::ModifyEntryPath( LPWSTR oldPrefix, LPWSTR newPrefix) {
DWORD dwErr = ERROR_SUCCESS; CDfsService *pService; PWCHAR ErrorStrs[2]; PWCHAR childNewPrefix; CEnumDirectory *pdir; DFSMSTATDIR rgelt; ULONG fetched = 0; CDfsVolume *child = NULL; PWCHAR newEntryPath; SYSTEMTIME st; FILETIME ftEntryPath;
IDfsVolInlineDebOut((DEB_TRACE, "ModifyEntryPath(%s,%s)\n", oldPrefix, newPrefix));
//
// First, see if we need to modify anything at all. If the oldPrefix
// is *not* a prefix of our name, then our name is *not* changing, and
// we just return.
//
if (_wcsnicmp(_peid.Prefix.Buffer, oldPrefix, wcslen(oldPrefix)) != 0) { IDfsVolInlineDebOut((DEB_TRACE, "ModifyEntryPath() exit\n")); return( ERROR_SUCCESS ); }
//
// Next, compute the new entry path
//
ComputeNewEntryPath( oldPrefix, newPrefix, _peid.Prefix.Buffer, &newEntryPath );
if (newEntryPath == NULL) { return( ERROR_OUTOFMEMORY ); }
//
// Let us first modify the prefix locally on the object. We trust the
// arguments since they could have been passed by our own code. So we
// will not bother with a TRY/CATCH etc. out here.
//
GetSystemTime( &st ); SystemTimeToFileTime( &st, &ftEntryPath ); dwErr = ModifyLocalEntryPath( newEntryPath, ftEntryPath, TRUE );
if (dwErr != ERROR_SUCCESS) {
delete [] newEntryPath;
return(dwErr);
}
//
// Now that the prefix has been modified locally we need to update all the
// services.
//
pService = _DfsSvcList.GetFirstService();
while (pService != NULL) {
dwErr = pService->ModifyPrefix(&_peid);
//
// If we fail to modify the prefix we really dont want to stop. We go
// on and update the other services and volumes.
//
if (dwErr != ERROR_SUCCESS) { ErrorStrs[0] = _peid.Prefix.Buffer; ErrorStrs[1] = pService->GetServiceName(); LogMessage(DEB_ERROR, ErrorStrs, 2, DFS_MODIFY_PREFIX_FAILED_MSG);
} dwErr = ERROR_SUCCESS; pService = _DfsSvcList.GetNextService(pService);
}
//
// Now we have updated all the services of this volume. Let us now get to
// all our children and call this method on them again.
//
dwErr = _pStorage->GetEnumDirectory(&pdir); if (dwErr != ERROR_SUCCESS) { delete [] newEntryPath; return(dwErr); }
//
// While there are children still to be handled we continue on.
//
rgelt.pwcsName = NULL;
while (TRUE) {
if (rgelt.pwcsName != NULL) { delete [] rgelt.pwcsName; rgelt.pwcsName = NULL; }
dwErr = pdir->Next(&rgelt, &fetched);
if (dwErr != ERROR_SUCCESS) { IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumeraate\n", 0)); break; }
//
// If we did not get back any children we are done.
//
if (fetched == 0) break;
//
// If the child name is . or .. we ignore it
//
if ((!wcscmp(rgelt.pwcsName, L".")) || (!wcscmp(rgelt.pwcsName, L".."))) continue;
dwErr = GetDfsVolumeFromStg(&rgelt, &child);
if (dwErr != ERROR_SUCCESS) { //
// Log an EVENT here saying that volume object is corrupt and
// continue on. We dont want to stop just because we cant handle
// one particular object.
//
LogMessage( DEB_ERROR, &(_peid.Prefix.Buffer), 1, DFS_CANT_GET_TO_CHILD_IDFSVOL_MSG); //
// We dont want to give up as yet. So let us go on to the next
// object.
//
fetched = 0; continue; }
dwErr = child->ModifyEntryPath(oldPrefix, newPrefix); if (dwErr != ERROR_SUCCESS) { //
// We ignore this error and also dont bother to write out an
// event since this should have been handled by some lower method.
// We maybe sitting many levels high up and this error came all
// the way back up.
}
child->Release(); //
// Let us now attempt to enumerate the next child.
//
fetched = 0;
} //While TRUE
if (pdir != NULL) pdir->Release();
delete [] newEntryPath;
IDfsVolInlineDebOut((DEB_TRACE, "ModifyEntryPath() exit\n"));
return(dwErr); }
//+-----------------------------------------------------------------------
//
// Member: CDfsVolume::GetReplicaSetID, public
//
// Synopsis: This method returns the replica set ID (if any) stored with
// this volume object.
//
// Arguments: [pguidRsid] -- This is where the replica set ID is returned.
//
// Returns: If there is no replica set ID then caller gets NullGuid.
//
// History: 16 Aug 1993 Alanw Created
// 19 Oct 1993 SudK Implemented
//
//------------------------------------------------------------------------
DWORD CDfsVolume::GetReplicaSetID( GUID *pguidRsid ) { IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetReplicaSetID()\n"));
(*pguidRsid) = _DfsSvcList._ReplicaSetID;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetReplicaSetID() exit\n"));
return(ERROR_SUCCESS); }
//+-----------------------------------------------------------------------
//
// Member: CDfsVolume::SetReplicaSetID, public
//
// Synopsis: This method sets the replica set ID associated with
// this volume object.
//
// Arguments: [pguidRsid] -- A pointer to the replica set ID.
//
// Returns:
//
// History: 16 Aug 1993 Alanw Created
// 19 Oct 1993 SudK Implemented
//
//------------------------------------------------------------------------
DWORD CDfsVolume::SetReplicaSetID( GUID *pguidRsid ) { DWORD dwErr = ERROR_SUCCESS;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaSetID()\n"));
_DfsSvcList._ReplicaSetID = *pguidRsid; //
// I am assuming here that the service List is always setup if someone
// called this method. For now this is correct.
//
dwErr = _DfsSvcList.SetServiceListProperty(FALSE);
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaSetID() exit\n"));
return(dwErr);
}
//+-----------------------------------------------------------------------
//
// Method: CDfsVolume::ChangeStorageID
//
// Synopsis: Modify the storage ID on the replica mentioned.
//
// Arguments: [pwszMachineName] -- The replica whose state needs to be
// changed.
// [pwszStorageId] -- The new storageId on the above replica
//
// Returns:
//
// History: 7/21/94 SudK Created
//
//------------------------------------------------------------------------
DWORD CDfsVolume::ChangeStorageID( LPWSTR pwszMachineName, LPWSTR pwszNetStorageId ) { return(ERROR_SUCCESS); }
//+-----------------------------------------------------------------------
//
// Member: CDfsVolume::SetReplicaState, public
//
// Synopsis: Change the state of the replica indicated.
//
// Arguments: [pwszMachineName] -- The server whose state needs to be
// changed.
// [pwszShareName] -- The share on server whose state needs to
// be changed.
// [fState] -- The State to set on this.
//
// Returns:
//
// History: 7/21/94 SudK Created
//
//------------------------------------------------------------------------
DWORD CDfsVolume::SetReplicaState( LPWSTR pwszMachineName, LPWSTR pwszShareName, ULONG fState ) { DWORD dwErr = ERROR_SUCCESS; CDfsService *psvc; ULONG svcState; PWCHAR pMachineName; PWCHAR pShareName;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaState(%ws,%ws)\n", pwszMachineName, pwszShareName));
switch (fState) { case DFS_STORAGE_STATE_OFFLINE: svcState = DFS_SERVICE_TYPE_OFFLINE; break;
case DFS_STORAGE_STATE_ONLINE: svcState = 0; break;
default: return( ERROR_INVALID_PARAMETER ); break;
}
for (psvc = _DfsSvcList.GetFirstService(); psvc != NULL; psvc = _DfsSvcList.GetNextService(psvc)) {
pMachineName = psvc->GetServiceName(); pShareName = psvc->GetShareName();
if (pMachineName != NULL && _wcsicmp(pwszMachineName, pMachineName) == 0 && pShareName != NULL && _wcsicmp(pwszShareName, pShareName) == 0) {
dwErr = psvc->SetVolumeState( &_peid, svcState, TRUE );
if (dwErr == ERROR_SUCCESS) {
//
// Store the udpated svclist to the volume object. We don't
// revert if we fail to save to disk. Instead, we return the
// error, and let the admin try again if she wishes.
//
dwErr = _DfsSvcList.SerializeSvcList();
if (dwErr == ERROR_SUCCESS) {
dwErr = _DfsSvcList.SetServiceListProperty( FALSE );
}
}
}
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaState() exit\n"));
return(dwErr);
}
//+-----------------------------------------------------------------------
//
// Member: CDfsVolume::SetVolumeState, public
//
// Synopsis: Change the state of the volume indicated.
//
// Arguments: [fState] -- The State to set on this.
//
// Returns:
//
// History: 7/21/94 SudK Created
//
//------------------------------------------------------------------------
DWORD CDfsVolume::SetVolumeState( ULONG fState ) { DWORD dwErr; NTSTATUS status; CDfsService *psvc; ULONG svcState, volState;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeState(0x%x)\n", fState));
switch (fState) { case DFS_VOLUME_STATE_OFFLINE: svcState = DFS_SERVICE_TYPE_OFFLINE; volState = PKT_ENTRY_TYPE_OFFLINE; break;
case DFS_VOLUME_STATE_ONLINE: svcState = 0; volState = 0; break;
default: return( ERROR_INVALID_PARAMETER ); break;
}
status = DfsDCSetVolumeState( &_peid, volState );
if (NT_SUCCESS(status)) {
SYSTEMTIME st;
_State = fState;
GetSystemTime( &st ); SystemTimeToFileTime( &st, &_ftState );
dwErr = SetIdProps(_EntryType, _State, _peid.Prefix.Buffer, _peid.ShortPrefix.Buffer, _peid.Uid, _pwszComment, _Timeout, _ftEntryPath, _ftState, _ftComment, FALSE);
} else {
dwErr = RtlNtStatusToDosError(status);
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeState()\n"));
return(dwErr);
}
//+-----------------------------------------------------------------------
//
// Member: CDfsVolume::SetVolumeTimeout, public
//
// Synopsis: Change the timeout of the volume
//
// Arguments: [Timeout] -- The new timeout to set on this.
//
// Returns:
//
//------------------------------------------------------------------------
DWORD CDfsVolume::SetVolumeTimeout( ULONG Timeout ) { DWORD dwErr = 0; NTSTATUS status;
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeTimeout(0x%x)\n", Timeout));
status = DfsSetVolumeTimeout( &_peid, Timeout );
if (NT_SUCCESS(status)) {
_Timeout = Timeout;
dwErr = SetIdProps(_EntryType, _State, _peid.Prefix.Buffer, _peid.ShortPrefix.Buffer, _peid.Uid, _pwszComment, _Timeout, _ftEntryPath, _ftState, _ftComment, FALSE);
} else {
dwErr = RtlNtStatusToDosError(status);
}
IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeTimeout()\n"));
return(dwErr); }
//+-------------------------------------------------------------------------
//
// Function: CDfsVolume::GetObjectID
//
// Synopsis: Return the volume object guid
//
//--------------------------------------------------------------------------
DWORD CDfsVolume::GetObjectID(LPGUID guidVolume) { *guidVolume = _peid.Uid;
return(ERROR_SUCCESS); }
//+---------------------------------------------------------------------
//
// Function: ComputeNewEntryPath, private
//
// Synopsis: This function is a helper function for the following functions
// to be able to compute the entry paths for a child volume given
// the change in their entrypath's and the child's current path.
//
// Arguments: [oldPath] -- OldPath of currentVolume. Prefix
// [newPath] -- NewPath of currentVOlume. Prefix
// [childPath] -- CurrentPath of child. Prefix
// [childNewPath] -- NewPath of child. Prefix
//
// Returns: NOTHING.
//
// History: 05-01-93 SudK Created.
//
//----------------------------------------------------------------------
VOID ComputeNewEntryPath( PWCHAR oldPath, PWCHAR newPath, PWCHAR childPath, PWCHAR *childNewPath ) {
ULONG newLen, oldLen; PWCHAR childComponent;
oldLen = wcslen(oldPath); newLen = wcslen(newPath); newLen += wcslen(childPath) - oldLen;
*childNewPath = new WCHAR[newLen + sizeof(WCHAR)];
if (*childNewPath != NULL) {
wcscpy(*childNewPath, newPath);
childComponent = childPath + oldLen;
wcscat(*childNewPath, childComponent);
}
return; }
//+----------------------------------------------------------------------------
//
// Function: MoveFileOrJP, private
//
// Synopsis: Similar to Win32 MoveFile, except if the named src is a JP,
// then the JP will get renamed.
//
// Arguments: [pwszSrcName] -- Name of the Src object.
// [pwszTgtName] -- New name of the object.
//
// Returns: [STATUS_SUCCESS] -- Rename succeeded.
//
//-----------------------------------------------------------------------------
NTSTATUS MoveFileOrJP( IN PCWSTR pwszSrcName, IN PCWSTR pwszTgtName) { UNICODE_STRING ustrSrc = {0}, ustrTgt = {0}; NTSTATUS Status = STATUS_SUCCESS;
if (!RtlDosPathNameToNtPathName_U( pwszSrcName, &ustrSrc, NULL, NULL)) {
Status = STATUS_INSUFFICIENT_RESOURCES; DFSM_TRACE_HIGH(ERROR, MoveFileOrJP_Error1, LOGSTATUS(Status));
} else if (!RtlDosPathNameToNtPathName_U( pwszTgtName, &ustrTgt, NULL, NULL)) {
Status = STATUS_INSUFFICIENT_RESOURCES;
DFSM_TRACE_HIGH(ERROR, MoveFileOrJP_Error2, LOGSTATUS(Status)); }
if (NT_SUCCESS(Status)) { OBJECT_ATTRIBUTES oaSrc; HANDLE hSrc; IO_STATUS_BLOCK iosb;
InitializeObjectAttributes( &oaSrc, &ustrSrc, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = NtCreateFile( &hSrc, FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE, &oaSrc, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, pOpenIfJPEa, cbOpenIfJPEa);
DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, MoveFileOrJP_Error_NtCreateFile, LOGSTATUS(Status));
if (Status == STATUS_DFS_EXIT_PATH_FOUND) {
Status = NtCreateFile( &hSrc, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE, &oaSrc, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, pOpenIfJPEa, cbOpenIfJPEa);
DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, MoveFileOrJP_Error_NtCreateFile2, LOGSTATUS(Status)); }
if (NT_SUCCESS(Status)) {
Status = iosb.Status;
}
if (NT_SUCCESS(Status)) { PFILE_RENAME_INFORMATION pRenameInfo; ULONG cbRenameInfo;
cbRenameInfo = sizeof(FILE_RENAME_INFORMATION) + ustrTgt.Length;
pRenameInfo = (PFILE_RENAME_INFORMATION) new BYTE [cbRenameInfo];
if (pRenameInfo != NULL) {
pRenameInfo->ReplaceIfExists = FALSE; pRenameInfo->RootDirectory = NULL; pRenameInfo->FileNameLength = ustrTgt.Length; CopyMemory( &pRenameInfo->FileName[0], ustrTgt.Buffer, ustrTgt.Length);
Status = NtSetInformationFile( hSrc, &iosb, pRenameInfo, cbRenameInfo, FileRenameInformation);
DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, MoveFileOrJP_Error_NtSetInformationFile, LOGSTATUS(Status)); delete [] pRenameInfo;
if (NT_SUCCESS(Status)) {
Status = iosb.Status;
}
} else {
Status = STATUS_INSUFFICIENT_RESOURCES; DFSM_TRACE_HIGH(ERROR, MoveFileOrJP_Error3, LOGSTATUS(Status)); }
NtClose( hSrc );
} // end if successfully opened src
} // end if successfull converted dos names to nt names.
if (ustrSrc.Buffer != NULL) {
RtlFreeUnicodeString( &ustrSrc );
}
if (ustrTgt.Buffer != NULL) {
RtlFreeUnicodeString( &ustrTgt );
}
return( Status );
}
|