Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3507 lines
102 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // File: idfsvol.cxx
  4. //
  5. // Contents: Implementation of IDfsVolume interface. This interface
  6. // supports the administrative functions on DFS.
  7. //
  8. //--------------------------------------------------------------------------
  9. //#include <ntos.h>
  10. //#include <ntrtl.h>
  11. //#include <nturtl.h>
  12. //#include <dfsfsctl.h>
  13. //#include <windows.h>
  14. #include "headers.hxx"
  15. #pragma hdrstop
  16. #include "dfsmsrv.h"
  17. #include "dfsm.hxx"
  18. #include "cdfsvol.hxx"
  19. #include "jnpt.hxx"
  20. #include "dfsmwml.h"
  21. VOID
  22. ComputeNewEntryPath(
  23. PWCHAR oldPath,
  24. PWCHAR newPath,
  25. PWCHAR childPath,
  26. PWCHAR *childNewPath
  27. );
  28. NTSTATUS
  29. MoveFileOrJP(
  30. IN PCWSTR pwszSrcName,
  31. IN PCWSTR pwszTgtName
  32. );
  33. //+-------------------------------------------------------------------------
  34. //
  35. // Method: AddReplicaToObj, private
  36. //
  37. // Synopsis: This method adds a replica info structure to the volume
  38. // object and returns after that.
  39. //
  40. // Arguments: [pReplicaInfo] -- The ReplicaInfo structure.
  41. //
  42. //--------------------------------------------------------------------------
  43. DWORD
  44. CDfsVolume::AddReplicaToObj(
  45. PDFS_REPLICA_INFO pReplicaInfo
  46. )
  47. {
  48. DWORD dwErr = ERROR_SUCCESS;
  49. CDfsService *pService = NULL;
  50. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplicaToObj()\n"));
  51. //
  52. // First before we even set recoveryProperties we want to make sure
  53. // that this service does not already exist in the ServiceList.
  54. //
  55. if ((dwErr == ERROR_SUCCESS) &&
  56. (_DfsSvcList.GetService(pReplicaInfo, &pService) == ERROR_SUCCESS)) {
  57. dwErr = NERR_DfsDuplicateService;
  58. }
  59. if (dwErr == ERROR_SUCCESS) {
  60. //
  61. // Argument validation also takes place right in this constructor.
  62. // Also the ServiceName etc. gets converted to an ORG based name in
  63. // the constructor. So we dont need to worry about that at all.
  64. //
  65. pService = new CDfsService(pReplicaInfo, TRUE, &dwErr);
  66. if (pService == NULL)
  67. dwErr = ERROR_OUTOFMEMORY;
  68. }
  69. if (dwErr == ERROR_SUCCESS) {
  70. //
  71. // Set the new service properties on the volume object. This method
  72. // will return an error code if the service already exists on the
  73. // volume object. No explicit checking need be done here.
  74. //
  75. if (dwErr == ERROR_SUCCESS) {
  76. pService->SetCreateTime();
  77. dwErr = _DfsSvcList.SetNewService(pService);
  78. if (dwErr != ERROR_SUCCESS) {
  79. IDfsVolInlineDebOut((
  80. DEB_ERROR, "Failed to Set new replica %08lx\n",dwErr));
  81. }
  82. }
  83. }
  84. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplicaToObj() exit\n"));
  85. return(dwErr);
  86. }
  87. //+-------------------------------------------------------------------------
  88. //
  89. // Member: CDfsVolume::AddReplica, public
  90. //
  91. // Synopsis: This function associates a new service with an existing
  92. // Volume Object. A new service is defined by the ServiceName,
  93. // StorageId, Type of Service, and sometimes an AddressQualifier.
  94. // For this operation to succeed the service being added should
  95. // be available. Unavailability of the service will result in
  96. // failure of this method. This operation will be atomic as far
  97. // as all information on the DC is concerned. Either the operation
  98. // will succeed or no irrelevant information will be left on the
  99. // DC. However, there are no guarantees made regarding the state
  100. // of the service involved in the face of Network Failures and
  101. // remote service crashes etc. If you attempt to add the same
  102. // service name again it will return an error.
  103. //
  104. // Arguments: [pReplicaInfo] -- The ServiceInfo here. Look at docs for details
  105. //
  106. // Returns: ERROR_SUCCESS -- If the operation succeeded.
  107. //
  108. // ERROR_OUTOFMEMORY -- Unable to allocate memory for operation.
  109. //
  110. // NERR_DfsVolumeIsOffline -- The volume is offline, can't do
  111. // AddReplica operation on it.
  112. //
  113. // NERR_DfsDuplicateService --
  114. // If the service already exists on this volume.
  115. //
  116. // NERR_DfsVolumeDataCorrupt --
  117. // If the volume object to which this
  118. // service is being added is corrupt.
  119. //
  120. //--------------------------------------------------------------------------
  121. DWORD
  122. CDfsVolume::AddReplica(
  123. PDFS_REPLICA_INFO pReplicaInfo,
  124. ULONG fCreateOptions
  125. )
  126. {
  127. DWORD dwErr = ERROR_SUCCESS;
  128. PWCHAR ErrorStrs[3];
  129. CDfsService *pService = NULL;
  130. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplica()\n"));
  131. #if DBG
  132. if (DfsSvcVerbose)
  133. DbgPrint("CDfsVolume::AddReplica(%ws,%ws,0x%x)\n",
  134. pReplicaInfo->pwszServerName,
  135. pReplicaInfo->pwszShareName);
  136. #endif
  137. if (_State == DFS_VOLUME_STATE_OFFLINE) {
  138. #if DBG
  139. if (DfsSvcVerbose)
  140. DbgPrint("CDfsVolume::AddReplica exit NERR_DfsVolumeIsOffline\n");
  141. #endif
  142. return( NERR_DfsVolumeIsOffline );
  143. }
  144. //
  145. // First before we even set recoveryProperties we want to make sure
  146. // that this service does not already exist in the ServiceList.
  147. //
  148. if (_DfsSvcList.GetService(pReplicaInfo, &pService) == ERROR_SUCCESS) {
  149. #if DBG
  150. if (DfsSvcVerbose)
  151. DbgPrint("CDfsVolume::AddReplica: returning NERR_DfsDuplicateService\n");
  152. #endif
  153. pService = NULL; // So we don't try to delete
  154. dwErr = NERR_DfsDuplicateService; // it later...
  155. }
  156. if (dwErr == ERROR_SUCCESS) {
  157. //
  158. // Argument validation also takes place right in this constructor.
  159. // Also the ServiceName etc. gets converted to an ORG based name in
  160. // the constructor. So we dont need to worry about that at all.
  161. //
  162. pService = new CDfsService(pReplicaInfo, TRUE, &dwErr);
  163. if (pService == NULL)
  164. dwErr = ERROR_OUTOFMEMORY;
  165. }
  166. if (dwErr == ERROR_SUCCESS) {
  167. pService->SetCreateTime();
  168. RECOVERY_TEST_POINT(L"AddReplica", 1);
  169. //
  170. // This is where we want to do some STATE changes. Register the
  171. // intent of doing an AddReplicaoperation and mention the service
  172. // name and record that we are in the Start State. RECOVERY
  173. // If we cant set recovery props then something is really wrong.
  174. // The following constructor will throw an exception and we will
  175. // deal with it appropriately.
  176. //
  177. dwErr = _Recover.SetOperationStart(
  178. DFS_RECOVERY_STATE_ADD_SERVICE,
  179. pService);
  180. RECOVERY_TEST_POINT(L"AddReplica", 2);
  181. //
  182. // Set the new service properties on the volume object. This method
  183. // will return an error code if the service already exists on the
  184. // volume object. No explicit checking need be done here.
  185. //
  186. if (dwErr == ERROR_SUCCESS) {
  187. dwErr = _DfsSvcList.SetNewService(pService);
  188. }
  189. if (dwErr != ERROR_SUCCESS) {
  190. //
  191. // 433532, SetNewService already deletes pservice in case of
  192. // failure. Dont use pservice, and set it to NULL so it does
  193. // not get freed twice!
  194. pService = NULL;
  195. //LogMessage( DEB_TRACE,
  196. // &(pService->GetServiceName()),
  197. // 1,
  198. // DFS_CANNOT_SET_SERVICE_PROPERTY_MSG);
  199. }
  200. }
  201. if (dwErr == ERROR_SUCCESS) {
  202. //
  203. // Now we need to change the state to UpdatedSvcList RECOVERY
  204. //
  205. RECOVERY_TEST_POINT(L"AddReplica", 3);
  206. _Recover.SetOperStage(DFS_OPER_STAGE_SVCLIST_UPDATED);
  207. RECOVERY_TEST_POINT(L"AddReplica", 4);
  208. //
  209. // Let us now ask the remote machine to create a local volume.
  210. // If we fail to do this for ANY reason, we fail the operation.
  211. //
  212. dwErr = pService->CreateLocalVolume(&_peid, _EntryType);
  213. //
  214. // If we failed, it might be because the server's state is not
  215. // consistent with our state. See if this is the case, and
  216. //
  217. //
  218. // If we failed we need to delete the entry from the serviceList.
  219. // We have to use the servicename from the DfsSvc class since that
  220. // is the ORG based name. If we get an error here as well then
  221. // we will return that error (dwErr2) since it becomes more relevant
  222. // suddenly. Else we will return the error we got above from
  223. // CreateLocalVolume which will be returning a proper error to us.
  224. //
  225. if (dwErr != ERROR_SUCCESS) {
  226. DWORD dwErr2 = _DfsSvcList.DeleteService(pService, FALSE);
  227. PWCHAR ErrorStrs[1];
  228. ErrorStrs[0] = (pService->GetServiceName());
  229. if (dwErr2 != ERROR_SUCCESS) {
  230. LogMessage( DEB_ERROR,
  231. ErrorStrs,
  232. 1,
  233. DFS_CANNOT_DELETE_SERVICE_PROPERTY_MSG);
  234. dwErr = NERR_DfsVolumeDataCorrupt;
  235. } else {
  236. //
  237. // DeleteService() deleted this instance for us, so set the
  238. // pointer to NULL
  239. //
  240. pService = NULL;
  241. }
  242. }
  243. } //CreateLocalVolumeDone OR FAILED.
  244. //
  245. // Now we set state to DONE on vol object. It is of no concern whether
  246. // the operation succeeded or failed.
  247. //
  248. RECOVERY_TEST_POINT(L"AddReplica", 5);
  249. _Recover.SetOperationDone();
  250. if (dwErr == ERROR_SUCCESS) {
  251. //
  252. // Now we update the PKT with the new service. We get an
  253. // appropriate Error Code from UpdatePktEntry.
  254. //
  255. dwErr = UpdatePktEntry(NULL);
  256. if (dwErr != ERROR_SUCCESS) {
  257. //
  258. // Why should this fail at all.
  259. // An EVENT here too maybe.
  260. //
  261. LogMessage( DEB_ERROR,
  262. &(_peid.Prefix.Buffer),
  263. 1,
  264. DFS_FAILED_UPDATE_PKT_MSG);
  265. IDfsVolInlineDebOut((DEB_ERROR, "UpdPktEntFailed %08lx\n", dwErr));
  266. ASSERT(L"UpdatePktEntry Failed in AddService - WHY?");
  267. }
  268. } //UpdatePktEntry Block.
  269. if (dwErr != ERROR_SUCCESS) {
  270. _Recover.SetOperationDone();
  271. if (pService != NULL)
  272. delete pService;
  273. }
  274. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::AddReplica() exit\n"));
  275. #if DBG
  276. if (DfsSvcVerbose)
  277. DbgPrint("CDfsVolume::AddReplica exit %d\n", dwErr);
  278. #endif
  279. return(dwErr);
  280. }
  281. //+----------------------------------------------------------------------------
  282. //
  283. // Member: CDfsVolume::RemoveReplicaFromObj, public
  284. //
  285. // Synopsis: This operation removes a replica from a volume object and
  286. // returns after that.
  287. //
  288. // Arguments: [pwszServiceName] -- Name of server to remove
  289. //
  290. // Returns:
  291. //
  292. //-----------------------------------------------------------------------------
  293. DWORD
  294. CDfsVolume::RemoveReplicaFromObj(
  295. IN LPWSTR pwszServiceName)
  296. {
  297. DWORD dwErr;
  298. CDfsService *pSvc;
  299. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplicaFromObj(%ws)\n", pwszServiceName));
  300. dwErr = _DfsSvcList.GetServiceFromPrincipalName( pwszServiceName, &pSvc );
  301. if (dwErr == ERROR_SUCCESS) {
  302. //
  303. // See if this is the last service. In that case, we cannot
  304. // permit anyone to delete it.
  305. //
  306. if (_DfsSvcList.GetServiceCount() == 1) {
  307. dwErr = NERR_DfsCantRemoveLastServerShare;
  308. }
  309. //
  310. // Now delete the service from the service list
  311. //
  312. dwErr = _DfsSvcList.DeleteService(pSvc);
  313. }
  314. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplicaFromObj() exit\n"));
  315. return( dwErr );
  316. }
  317. //+-------------------------------------------------------------------------
  318. //
  319. // Member: CDfsVolume::RemoveReplica, public
  320. //
  321. // Synopsis: This operation dissociates a service from a volume in the DFS
  322. // namespace. On the DC this merely involves modifying the service
  323. // List on the Volume object. At the same time the service involved
  324. // has to be notified of this change. This operation will fail if
  325. // for some reason the service refuses to delete its knowledge
  326. // regarding this volume or if there are network failures
  327. // during this operation. Of course if we fail the operation due
  328. // to Network failures note the fact that the operation at the
  329. // remote service might have succeeded and network failed after
  330. // that - in which case we may have an INCONSISTENCY (very easy to
  331. // detect this one).
  332. //
  333. // Arguments: [pwszServiceName] -- The name of the service to be deleted
  334. // from the volume object.
  335. //
  336. // Returns: DFS_S_SUCCESS -- If the operation succeeded.
  337. //
  338. // NERR_DfsNoSuchShare -- If the specified server\share is not
  339. // a service for this volume.
  340. //
  341. // NERR_DfsCantRemoveLastServerShare -- If the specified
  342. // server\share is the only service for this volume.
  343. //
  344. // NERR_DfsVolumeDataCorrupt -- If the volume object could not
  345. // be read.
  346. //
  347. //--------------------------------------------------------------------------
  348. DWORD
  349. CDfsVolume::RemoveReplica(
  350. PDFS_REPLICA_INFO pReplicaInfo,
  351. ULONG fDeleteOptions
  352. )
  353. {
  354. DWORD dwErr = ERROR_SUCCESS;
  355. DWORD dwErr2 = ERROR_SUCCESS;
  356. PWCHAR orgServiceName = NULL;
  357. CDfsService *pDfsSvc;
  358. PWCHAR ErrorStrs[3];
  359. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplica()\n"));
  360. dwErr = _DfsSvcList.GetService(pReplicaInfo, &pDfsSvc);
  361. if (dwErr != ERROR_SUCCESS) {
  362. LogMessage( DEB_TRACE,
  363. nullPtr,
  364. 0,
  365. DFS_SERVICE_DOES_NOT_EXIST_MSG);
  366. }
  367. if (dwErr == ERROR_SUCCESS &&
  368. _EntryType & DFS_VOL_TYPE_REFERRAL_SVC &&
  369. !(_EntryType & DFS_VOL_TYPE_INTER_DFS)) {
  370. dwErr = NERR_DfsCantRemoveDfsRoot;
  371. }
  372. if (dwErr == ERROR_SUCCESS) {
  373. //
  374. // See if this is the last service. In that case, we cannot
  375. // permit anyone to delete it.
  376. //
  377. if (_DfsSvcList.GetServiceCount() == 1) {
  378. dwErr = NERR_DfsCantRemoveLastServerShare;
  379. }
  380. }
  381. if (dwErr != ERROR_SUCCESS) {
  382. return(dwErr);
  383. }
  384. if (dwErr == ERROR_SUCCESS) {
  385. //
  386. // Next we register the intent to delete a specific service by
  387. // marking the ServiceName on the object. RECOVERY.
  388. //
  389. RECOVERY_TEST_POINT(L"RemoveReplica", 1);
  390. dwErr = _Recover.SetOperationStart(DFS_RECOVERY_STATE_REMOVE_SERVICE,
  391. pDfsSvc);
  392. RECOVERY_TEST_POINT(L"RemoveReplica", 2);
  393. //
  394. // Now that we know that such a service is actually registered.
  395. // Let us request the remote service to delete LVOL knowledge.
  396. //
  397. if (dwErr == ERROR_SUCCESS) {
  398. dwErr = pDfsSvc->DeleteLocalVolume(&_peid);
  399. }
  400. if (dwErr != ERROR_SUCCESS) {
  401. //
  402. // We assume that if we got an error here we are in big trouble
  403. // and we back out the operation infact. The DeleteLocalVolume
  404. // method would have already taken care of filtering out the
  405. // relevant errors for us.
  406. //
  407. LogMessage( DEB_TRACE,
  408. &(_peid.Prefix.Buffer),
  409. 1,
  410. DFS_DELETE_VOLUME_FAILED_MSG);
  411. //
  412. // Since we got this error we assume that we could not find
  413. // the service. However, that need not be the reason at all.
  414. // Raid: 455283. Need to resolve this later on.
  415. //
  416. dwErr = NERR_DfsNoSuchShare;
  417. }
  418. }
  419. if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
  420. //
  421. // Now we write out RecoveryState to DFS_OPER_STAGE_INFORMED_SERVICE
  422. //
  423. RECOVERY_TEST_POINT(L"RemoveReplica", 3);
  424. _Recover.SetOperStage(DFS_OPER_STAGE_INFORMED_SERVICE);
  425. RECOVERY_TEST_POINT(L"RemoveReplica", 4);
  426. //
  427. // Now write out the new service list
  428. //
  429. dwErr2 = _DfsSvcList.DeleteService(pDfsSvc);
  430. if (dwErr2 != ERROR_SUCCESS) {
  431. //
  432. // This should never happen. We probably had some security
  433. // problems. Do we now go and back out the Previous Step. Raid 455283
  434. //
  435. ErrorStrs[1] = pDfsSvc->GetServiceName();
  436. ErrorStrs[0] = _peid.Prefix.Buffer;
  437. LogMessage( DEB_ERROR,
  438. ErrorStrs,
  439. 2,
  440. DFS_CANNOT_DELETE_SERVICE_PROPERTY_MSG);
  441. ASSERT(L"Deleting and existing service FAILED in RemRepl");
  442. }
  443. }
  444. //
  445. // Done. The operation is committed if the last stage of deleting
  446. // service succeeded, else we dont want to remove the recovery property.
  447. // If we never got to the last stage of DeleteService dwErr2 will be
  448. // ERROR_SUCCESS.
  449. //
  450. RECOVERY_TEST_POINT(L"RemoveReplica", 5);
  451. if (dwErr2 == ERROR_SUCCESS)
  452. _Recover.SetOperationDone();
  453. if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
  454. //
  455. // Now update the PKT as well.
  456. //
  457. dwErr = UpdatePktEntry(NULL);
  458. if (dwErr != ERROR_SUCCESS) {
  459. //
  460. // Something is really messed up if we got here.
  461. //
  462. LogMessage(DEB_ERROR, nullPtr, 0, DFS_FAILED_UPDATE_PKT_MSG);
  463. IDfsVolInlineDebOut((DEB_ERROR,
  464. "UpdPktEntry in RemRepl failed %08lx\n", dwErr));
  465. ASSERT(L"UpdatePktEntry in RemoveRepl failed\n");
  466. }
  467. }
  468. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::RemoveReplica() exit\n"));
  469. return(dwErr);
  470. }
  471. //+-------------------------------------------------------------------------
  472. //
  473. // Member: CDfsVolume::Delete, public
  474. //
  475. // Synopsis: This method deletes the volume object and deletes all knowledge
  476. // of this volume at all the services that were supporting this
  477. // volume in the namespace. At the same time the exit point at the
  478. // parent volume is deleted. All of the services that support this
  479. // volume are also advised to delete all information regarding this
  480. // volume. There is an additional restriction that there should
  481. // be only one service associated with a volume to be able to call
  482. // method. This operation has problems due to its distributed
  483. // nature. The moment the service supporting this volume has been
  484. // informed to delete its local volume knowledge this operation is
  485. // committed. In the case of Network failures while talking to one
  486. // of the services involved, this operation continues to go on. If
  487. // any such errors are encountered they are reported to the caller
  488. // though the operation is declared to be a success. Note that this
  489. // operation does not delete the storage and has nothing to do with
  490. // that aspect. By not confirming the deletion of all ExitPoint
  491. // info anywhere this operation can directly introduce an
  492. // inconsistency of TOO MANY EXIT Points. This inconsistency is
  493. // well understood and easy to deal with.
  494. //
  495. // Arguments: None
  496. //
  497. // Returns: DFS_S_SUCCESS -- If all went well.
  498. //
  499. // NERR_DfsNotALeafVolume --
  500. // An attempt was made to delete a volume which
  501. // has child volumes and hence the operation failed
  502. //
  503. // NERR_DfsVolumeDataCorrupt --
  504. // The volume object seems to be corrupt due to
  505. // which this operation cannot proceed at all.
  506. //
  507. // NERR_DfsVolumeHasMultipleServers --
  508. // This operation will not succeed if there is
  509. // more than one service assoicated with the vol.
  510. //
  511. //--------------------------------------------------------------------------
  512. DWORD
  513. CDfsVolume::Delete(
  514. ULONG fDeleteOptions)
  515. {
  516. DWORD dwErr = ERROR_SUCCESS;
  517. CDfsVolume *parent = NULL;
  518. BOOLEAN InconsistencyPossible = FALSE;
  519. BOOLEAN ParentInconsistency = FALSE;
  520. CDfsService *pDfsSvc;
  521. ULONG rState = 0;
  522. ULONG count = 0;
  523. PWCHAR ErrorStrs[3];
  524. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Delete()\n"));
  525. if (NotLeafVolume())
  526. dwErr = NERR_DfsNotALeafVolume;
  527. //
  528. // We want to make sure that this is not the root volume
  529. //
  530. if (dwErr == ERROR_SUCCESS &&
  531. _EntryType & DFS_VOL_TYPE_REFERRAL_SVC &&
  532. !(_EntryType & DFS_VOL_TYPE_INTER_DFS)) {
  533. dwErr = NERR_DfsCantRemoveDfsRoot;
  534. }
  535. //
  536. // We next want to make sure that there is only one service associated
  537. // with this volume else we will fail this operation right now.
  538. //
  539. if (dwErr == ERROR_SUCCESS)
  540. if (_DfsSvcList.GetServiceCount()>1)
  541. dwErr = NERR_DfsVolumeHasMultipleServers;
  542. if (dwErr != ERROR_SUCCESS) {
  543. return(dwErr);
  544. }
  545. if(dwErr == ERROR_SUCCESS) {
  546. //
  547. // we are going to need to talk with the parent once the
  548. // child is gone, so we get a handle to it now.
  549. // If we fail to bind to parent. Then it probably means that
  550. // this is a top level volume object and hence cannot be deleted.
  551. // We return the error to the caller.
  552. //
  553. dwErr = GetParent(&parent);
  554. if (dwErr != ERROR_SUCCESS) {
  555. LogMessage(DEB_TRACE, nullPtr, 0, DFS_CANT_GET_PARENT_MSG);
  556. dwErr = NERR_DfsVolumeDataCorrupt;
  557. }
  558. }
  559. if (dwErr != ERROR_SUCCESS) {
  560. return(dwErr);
  561. }
  562. if (dwErr == ERROR_SUCCESS) {
  563. //
  564. // Before we take off on our operation. We should setup the
  565. // State variable on the Volume object indicating that we are
  566. // deleting this volume from the namespace.
  567. //
  568. RECOVERY_TEST_POINT(L"DeleteVolume", 1);
  569. dwErr = _Recover.SetOperationStart(DFS_RECOVERY_STATE_DELETE, NULL);
  570. RECOVERY_TEST_POINT(L"DeleteVolume", 2);
  571. //
  572. // Now we inform the service to delete its LocalVolume knowledge.
  573. //
  574. if (dwErr == ERROR_SUCCESS) {
  575. pDfsSvc = _DfsSvcList.GetFirstService();
  576. if (pDfsSvc != NULL) {
  577. dwErr = pDfsSvc->DeleteLocalVolume(&_peid);
  578. //
  579. // If we got an error here, we dont really want to go on??
  580. //
  581. // When we move to DWORDs we might want to return exactly
  582. // which service did not get updated etc.
  583. //
  584. }
  585. }
  586. }
  587. if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
  588. //
  589. // Now we set Recovery State to new value if we have informed
  590. // all related services.
  591. //
  592. RECOVERY_TEST_POINT(L"DeleteVolume", 3);
  593. _Recover.SetOperStage(DFS_OPER_STAGE_INFORMED_SERVICE);
  594. RECOVERY_TEST_POINT(L"DeleteVolume", 4);
  595. //
  596. // We need to tell each service of the parent volume to delete the
  597. // exit point. I think at this point we have to force the operation
  598. // through. Even if we are not able to delete some exit points it
  599. // is OK. We will return a success error code but will indicate
  600. // that there could potentially be a possible inconsistency in the
  601. // parent volume's knowledge.
  602. //
  603. pDfsSvc = parent->_DfsSvcList.GetFirstService();
  604. while (pDfsSvc != NULL) {
  605. //
  606. // Ignore error codes from this. We dont care if we cant
  607. // make some machine to delete the exit point.
  608. // The possible things that could happen here are that the
  609. // remote machine will say that it cannot delete the exit
  610. // point since the GUIDs dont match OR the exit point does
  611. // not exist (It got deleted due to reconciliation) or
  612. // Network failures themselves. In all cases we dont care.
  613. // We will return a status code which indicates that one
  614. // of the parent services misbehaved and admin needs to
  615. // make sure that nothing is wrong.
  616. //
  617. dwErr = pDfsSvc->DeleteExitPoint(&_peid, _EntryType);
  618. if (dwErr != ERROR_SUCCESS) {
  619. PWCHAR ErrorStrs[1];
  620. ParentInconsistency = TRUE;
  621. ErrorStrs[0] = pDfsSvc->GetServiceName();
  622. LogMessage(DEB_ERROR,
  623. ErrorStrs,
  624. 1,
  625. DFS_CANT_DELETE_EXIT_POINT_MSG);
  626. IDfsVolInlineDebOut((DEB_ERROR,
  627. "ErrorCode from DeleteExitPoint %08lx\n",
  628. dwErr));
  629. }
  630. dwErr = ERROR_SUCCESS;
  631. pDfsSvc = parent->_DfsSvcList.GetNextService(pDfsSvc);
  632. }
  633. }
  634. //
  635. // We want to get rid of the parent pointer if we no longer need it.
  636. //
  637. if (parent != NULL) {
  638. parent->Release();
  639. parent = NULL;
  640. }
  641. //
  642. // If the operation failed we want to set the properties to done else
  643. // we are anyway going to go in and delete this object itself.
  644. //
  645. RECOVERY_TEST_POINT(L"DeleteVolume", 5);
  646. if (dwErr != ERROR_SUCCESS) {
  647. _Recover.SetOperationDone();
  648. }
  649. //
  650. // If we successfully managed to do the deletion then we go ahead
  651. // and delete the volume object from disk. Note that even if
  652. // Network failures occur while talking to each of the services
  653. // above we will go on. Once this deletion happens the operation is
  654. // commited. Updating the PKT is not a part of the commit point.
  655. //
  656. if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
  657. DeleteObject();
  658. //
  659. // We need to make this instance of the VolumeObject invalid or
  660. // so that no one can do any more operations on this volume.
  661. //
  662. _Deleted = TRUE;
  663. }
  664. //
  665. // Now we go and update the PKT with the deletion information.
  666. // Once again we ignore errors here except to return an
  667. // INCONSISTENCY status code.
  668. //
  669. if ((dwErr == ERROR_SUCCESS) || (fDeleteOptions & DFS_OVERRIDE_FORCE)) {
  670. dwErr = DeletePktEntry(&_peid);
  671. if (dwErr != ERROR_SUCCESS) {
  672. LogMessage(
  673. DEB_ERROR, &(_peid.Prefix.Buffer), 1,
  674. DFS_CANT_DELETE_ENTRY_MSG);
  675. IDfsVolInlineDebOut((
  676. DEB_ERROR, "DelPktEnt Failed%08lx\n", dwErr));
  677. ASSERT(L"DeletePktEntry Failed in Deletion of Volume");
  678. dwErr = ERROR_SUCCESS;
  679. }
  680. }
  681. if (parent != NULL)
  682. parent->Release();
  683. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Delete() exit\n"));
  684. return( dwErr );
  685. }
  686. //+-------------------------------------------------------------------------
  687. //
  688. // Method: CDfsVolume::CreateChildX, public
  689. //
  690. // Synopsis: This is one way of creating new volume objects.
  691. // This operation involves the creation of the volume object,
  692. // Updating the parent's knowledge regarding the new exit point
  693. // and creating the exit point. The parent volume could have
  694. // multiple replicas. In this case all the replicas are informed
  695. // of the changes and are advised to create the relevant knowledge.
  696. // This operation will roll back in the event of a failure during
  697. // the operation before it is complete. If all of the parent's
  698. // cannot create the exit point information then this operation
  699. // will not proceed. Every attempt will be made to delete all
  700. // information that was created on other replicas but no guarantees
  701. // are made about this. However, all local knowledge will be
  702. // deleted and knowledge synchronisation is supposed to eliminate
  703. // any problems that might have arised because of inconsistencies
  704. // created by this operation.
  705. //
  706. // Arguments: [pwszChildName] -- The last component of child Vol object Name.
  707. //
  708. // [pwszEntryPath] -- The entry path for the new volume in the namespace
  709. //
  710. // [ulVolType] -- The type of the volume.
  711. // Values in the IDL file for this interface.
  712. //
  713. // [pChild] -- This is where the IDfsVolume reference is
  714. // returned to caller.
  715. //
  716. // [pComment] -- Comment for this volume.
  717. //
  718. // Returns: ERROR_SUCCESS -- If the operation succeeded with NO problems.
  719. //
  720. // ERROR_INVALID_PARAMETER -- The child volume's prefix is not
  721. // hierarchically subordinate to this volume's prefix.
  722. //
  723. // NERR_DfsVolumeIsInterDfs -- The volume is an inter-dfs one;
  724. // can't create a child volume.
  725. //
  726. // NERR_DfsNotSupportedInServerDfs -- Can't have more than one
  727. // level of hierarchy in Server Dfs.
  728. //
  729. // NERR_DfsLeafVolume -- This is a downlevel or leaf volume,
  730. // can't create a child here.
  731. //
  732. // NERR_DfsCantCreateJunctionPoint -- Unable to create a
  733. // junction point on any of the server-shares
  734. //
  735. //--------------------------------------------------------------------------
  736. DWORD
  737. CDfsVolume::CreateChildX(
  738. WCHAR * childName,
  739. WCHAR * pwszPrefix,
  740. ULONG ulVolType,
  741. LPWSTR pwszComment,
  742. CDfsVolume **ppChild)
  743. {
  744. DWORD dwErr = ERROR_SUCCESS;
  745. CDfsVolume *pChild = NULL;
  746. CDfsService *pDfsSvc = NULL;
  747. BOOLEAN CreatedExitPt = FALSE;
  748. BOOLEAN InconsistencyPossible = FALSE;
  749. PWCHAR pwszSuffix = NULL;
  750. PWCHAR ErrorStrs[3];
  751. ULONG ulen = 0;
  752. LPWSTR wszChildShortName;
  753. BOOLEAN GotShortName = FALSE;
  754. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildX(%ws,%ws,0x%x,%s)\n",
  755. childName, pwszPrefix, ulVolType, pwszComment));
  756. #if DBG
  757. if (DfsSvcVerbose)
  758. DbgPrint("DfsVolume::CreateChildX(%ws,%ws,0x%x,%ws)\n",
  759. childName,
  760. pwszPrefix,
  761. ulVolType,
  762. pwszComment);
  763. #endif
  764. //
  765. // Check for validity of Type field and for LEAF volume etc. Only the
  766. // allowed TypeBits should be set and also one of the Three required Types
  767. // bits should be set.
  768. //
  769. //
  770. // We check to make sure that the prefix of the child volume meets
  771. // our heirarchy requirements. It must be strictly a child of this
  772. // volume's prefix, and must not cross inter-dfs boundaries.
  773. //
  774. if (dwErr == ERROR_SUCCESS) {
  775. if (_EntryType & DFS_VOL_TYPE_INTER_DFS) {
  776. dwErr = NERR_DfsVolumeIsInterDfs;
  777. } else if (ulDfsManagerType == DFS_MANAGER_SERVER &&
  778. ((_EntryType & DFS_VOL_TYPE_REFERRAL_SVC) == 0)) {
  779. dwErr = NERR_DfsVolumeAlreadyExists;
  780. #if DBG
  781. if (DfsSvcVerbose)
  782. DbgPrint("CDfsVolume::CreateChildX: dwErr = NERR_DfsVolumeAlreadyExists\n");
  783. #endif
  784. } else if (_wcsnicmp(_peid.Prefix.Buffer, pwszPrefix,
  785. wcslen(_peid.Prefix.Buffer)) != 0) {
  786. dwErr = ERROR_INVALID_PARAMETER;
  787. #if DBG
  788. if (DfsSvcVerbose) {
  789. DbgPrint("CDfsVolume::CreateChildX(1): [%ws]!=[%ws] (1st %d chars)\n",
  790. _peid.Prefix.Buffer,
  791. pwszPrefix,
  792. wcslen(_peid.Prefix.Buffer));
  793. DbgPrint("CDfsVolume::CreateChildX(1): dwErr = ERROR_INVALID_PARAMETER\n");
  794. }
  795. #endif
  796. } else {
  797. //
  798. // In this case we want to make sure that the new EntryPath
  799. // is also greater than the entrypath for this volume, and that
  800. // it is a valid Win32 Path name
  801. //
  802. LPWSTR wszExitPath = &pwszPrefix[_peid.Prefix.Length/sizeof(WCHAR)];
  803. if (wcslen(pwszPrefix) <= wcslen(_peid.Prefix.Buffer)) {
  804. if (_wcsicmp(pwszPrefix,_peid.Prefix.Buffer) == 0) {
  805. dwErr = NERR_DfsVolumeAlreadyExists;
  806. } else {
  807. dwErr = ERROR_INVALID_PARAMETER;
  808. }
  809. #if DBG
  810. if (DfsSvcVerbose) {
  811. DbgPrint("CDfsVolume::CreateChildX(2): dwErr = %d\n");
  812. DbgPrint(" pwszPrefix=[%ws],_peid.Prefix.Buffer=[%ws]\n",
  813. pwszPrefix,
  814. _peid.Prefix.Buffer);
  815. }
  816. #endif
  817. } else if (!IsValidWin32Path( wszExitPath )) {
  818. dwErr = ERROR_BAD_PATHNAME;
  819. #if DBG
  820. if (DfsSvcVerbose)
  821. DbgPrint("CDfsVolume::CreateChildX: dwErr = ERROR_BAD_PATHNAME\n");
  822. #endif
  823. }
  824. }
  825. }
  826. if (dwErr == ERROR_SUCCESS) {
  827. //
  828. // We first try to create the volume object. So that we can use
  829. // it to go about our state management stuff for recovery purposes.
  830. // It automatically sets recoveryState to being OPER_START etc.
  831. // It will also set a NULL service list for now. This method will
  832. // also pick a GUID for us. We dont need to pass it one.
  833. //
  834. dwErr = CreateChildPartition(
  835. childName,
  836. ulVolType,
  837. pwszPrefix,
  838. pwszComment,
  839. NULL,
  840. NULL,
  841. &pChild);
  842. if (dwErr != ERROR_SUCCESS) {
  843. IDfsVolInlineDebOut((
  844. DEB_ERROR, "Unable to create child %ws\n under : %ws\n",
  845. pwszPrefix, _peid.Prefix.Buffer));
  846. }
  847. }
  848. if (dwErr == ERROR_SUCCESS) {
  849. RECOVERY_TEST_POINT(L"CreateChildX", 1);
  850. //
  851. // We next try to create exit points on each of the services for
  852. // the parent volume. However, we need to create an exit point on
  853. // only one of the services for the parent volume. We rely on
  854. // Replication to reconcile everything to other machines.
  855. //
  856. pDfsSvc = _DfsSvcList.GetFirstService();
  857. while (pDfsSvc!=NULL) {
  858. dwErr = pDfsSvc->CreateExitPoint(
  859. &(pChild->_peid),
  860. ulVolType);
  861. if (dwErr == ERROR_SUCCESS) {
  862. //
  863. // This would have updated the short name. Save it...
  864. //
  865. CreatedExitPt = TRUE;
  866. if (!GotShortName) {
  867. DWORD dwErrUpdatedShortName;
  868. dwErrUpdatedShortName = pChild->SaveShortName();
  869. if (dwErrUpdatedShortName == ERROR_SUCCESS) {
  870. GotShortName = TRUE;
  871. IDfsVolInlineDebOut((
  872. DEB_TRACE, "Setting short name to: %ws\n",
  873. pChild->_peid.ShortPrefix.Buffer));
  874. } else {
  875. IDfsVolInlineDebOut((
  876. DEB_ERROR, "Error %08lx setting short name\n",
  877. dwErrUpdatedShortName));
  878. }
  879. }
  880. } else {
  881. InconsistencyPossible = TRUE;
  882. IDfsVolInlineDebOut((
  883. DEB_ERROR, "Failed to CreateExPt %08lx %ws\n",
  884. dwErr, pChild->_peid.Prefix.Buffer));
  885. }
  886. dwErr = ERROR_SUCCESS;
  887. pDfsSvc = _DfsSvcList.GetNextService(pDfsSvc);
  888. }
  889. //
  890. // If we did create an exit point on atleast one machine we can go on.
  891. // Also we can set the state to DONE!!
  892. //
  893. if (CreatedExitPt == TRUE) {
  894. //
  895. // We need to ClearUp Recovery Properties here!!
  896. //
  897. RECOVERY_TEST_POINT(L"CreateChildX", 2);
  898. pChild->_Recover.SetOperationDone();
  899. } else {
  900. //
  901. // We have to delete the object that we created. dwErr already
  902. // has an error code in it. Let that go by us. Remember however,
  903. // the exit point itself never got created as far as the DC is
  904. // concerned and hence makes no sense to try to undo that stuff.
  905. //
  906. LogMessage(
  907. DEB_ERROR,nullPtr,0,DFS_CANT_CREATE_ANY_EXIT_POINT_MSG);
  908. pChild->DeleteObject();
  909. dwErr = NERR_DfsCantCreateJunctionPoint;
  910. }
  911. }
  912. //
  913. // Now we merely need to update the PKT with the relevant information.
  914. //
  915. if (dwErr == ERROR_SUCCESS) {
  916. dwErr = pChild->CreateSubordinatePktEntry(NULL, &_peid, FALSE);
  917. if (dwErr != ERROR_SUCCESS) {
  918. LogMessage(
  919. DEB_ERROR, &_peid.Prefix.Buffer, 1,
  920. DFS_CANT_CREATE_SUBORDINATE_ENTRY_MSG);
  921. IDfsVolInlineDebOut((
  922. DEB_ERROR, "Failed CreateSubordPktEntry %08lx\n", dwErr));
  923. ASSERT(L"CreateSubordinateEntry Failed in CreateChild");
  924. }
  925. }
  926. if (dwErr != ERROR_SUCCESS) {
  927. if (pChild != NULL)
  928. pChild->Release();
  929. *ppChild = NULL;
  930. } else {
  931. *ppChild = pChild;
  932. }
  933. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChildX() exit %d\n", dwErr));
  934. #if DBG
  935. if (DfsSvcVerbose)
  936. DbgPrint("CDfsVolume::CreateChildX exit %d\n", dwErr);
  937. #endif
  938. return((dwErr));
  939. }
  940. //+-------------------------------------------------------------------------
  941. //
  942. // Member: CDfsVolume::CreateChild, public
  943. //
  944. // Synopsis: This is one way of creating new volume objects.
  945. // This operation involves the creation of the volume object,
  946. // Updating the parent's knowledge regarding the new exit point
  947. // and creating the exit point. The parent volume could have
  948. // multiple replicas. In this case all the replicas are informed
  949. // of the changes and are advised to create the relevant knowledge.
  950. // This operation will roll back in the event of a failure during
  951. // the operation before it is complete. Every attempt will be made
  952. // to delete all information that was created on other replicas
  953. // but no guarantees are made about this. However, all local
  954. // knowledge will be deleted and knowledge synchronisation is
  955. // supposed to eliminate any problems that might have arised
  956. // because of inconsistencies created by this operation. This
  957. // operation also associates a SERVICE with the volume that it
  958. // creates (unlike the CreateChild/CreateInActiveVolume) operation.
  959. // Hence it also needs to communicate with the relevant service.
  960. //
  961. // Arguments: [pwszEntryPath] -- The entry path for the new volume in the namespace
  962. // This entry path is relative to the parent's entrypath.
  963. //
  964. // [ulVolType] -- The type of the volume. Look in dfsh.idl
  965. //
  966. // [pReplInfo] -- The ServiceInfo for the first replica.
  967. //
  968. // [pChild] -- This is where the IDfsVolume reference is
  969. // returned to caller.
  970. //
  971. // [pwszComment] -- Comment for this volume.
  972. //
  973. // Returns: Error code from CreateChildX() or AddReplica().
  974. //
  975. //--------------------------------------------------------------------------
  976. DWORD
  977. CDfsVolume::CreateChild(
  978. LPWSTR pwszPrefix,
  979. ULONG ulVolType,
  980. PDFS_REPLICA_INFO pReplicaInfo,
  981. PWCHAR pwszComment,
  982. ULONG fCreateOptions)
  983. {
  984. CDfsVolume *pChild;
  985. DWORD dwErr = ERROR_SUCCESS;
  986. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChild(%ws,0x%x,%ws,0x%x)\n",
  987. pwszPrefix, ulVolType, pwszComment, fCreateOptions));
  988. #if DBG
  989. if (DfsSvcVerbose)
  990. DbgPrint("CDfsVolume::CreateChild(%ws,0x%x,%ws,%ws,%ws,0x%x)\n",
  991. pwszPrefix,
  992. ulVolType,
  993. pReplicaInfo->pwszServerName,
  994. pReplicaInfo->pwszShareName,
  995. pwszComment,
  996. fCreateOptions);
  997. #endif
  998. if (VolumeOffLine()) {
  999. return( NERR_DfsVolumeIsOffline );
  1000. }
  1001. //
  1002. // I will cheat for now but will come back and fix this later on. Raid 455283
  1003. // At this place I basically need to have a recovery mechanism to recover
  1004. // in between the operations etc. The entire operation should be done or
  1005. // undone. In the present scheme only the two suboperations below will
  1006. // be in some sense "atomic" but not this entire operation itself.
  1007. //
  1008. dwErr = CreateChildX(
  1009. NULL, // Dont give any child name.
  1010. pwszPrefix,
  1011. ulVolType,
  1012. pwszComment,
  1013. &pChild);
  1014. if (dwErr != ERROR_SUCCESS) {
  1015. return((dwErr));
  1016. }
  1017. //
  1018. // Now let us go ahead and associate a service with the volume object that
  1019. // we just created.
  1020. //
  1021. dwErr = pChild->AddReplica(pReplicaInfo, fCreateOptions);
  1022. //
  1023. // If AddServic failed then we have to delete the object itself and
  1024. // backout the entire operation.
  1025. //
  1026. if (dwErr != ERROR_SUCCESS)
  1027. pChild->Delete(DFS_OVERRIDE_FORCE);
  1028. pChild->Release();
  1029. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::CreateChild() exit\n"));
  1030. #if DBG
  1031. if (DfsSvcVerbose)
  1032. DbgPrint("CDfsVolume::CreateChild exit %d\n", dwErr);
  1033. #endif
  1034. return((dwErr));
  1035. }
  1036. //+-------------------------------------------------------------------------
  1037. //
  1038. // Member: CDfsVolume::Move, public
  1039. //
  1040. // Synopsis: This operation moves a volume from one place in the namespace
  1041. // to another point in the namespace. Here we need the
  1042. // volume Name and the new entry Path. The old entryPath is
  1043. // already available to us since we can get it from the properties
  1044. // on the volume object. The volume to be moved should be a leaf
  1045. // volume (should have no children) else this operation will
  1046. // return an Error Code.
  1047. //
  1048. // Arguments: [pwszNewPrefix] -- The new EntryPath for this volume. This
  1049. // should be absolute path.
  1050. //
  1051. // Returns: ERROR_SUCCESS -- The operation succeeded.
  1052. //
  1053. // ERROR_INVALID_PARAMETER -- If pwszNewPrefix is a
  1054. // hierarchically below the current prefix!
  1055. //
  1056. // NERR_DfsVolumeAlreadyExists -- A Dfs volume with the same
  1057. // prefix as pwszNewPrefix already exists
  1058. //
  1059. // Error from various IDfsvol methods.
  1060. //
  1061. //--------------------------------------------------------------------------
  1062. DWORD
  1063. CDfsVolume::Move(
  1064. LPWSTR pwszNewPrefix
  1065. )
  1066. {
  1067. DWORD dwErr = ERROR_SUCCESS;
  1068. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Move(%ws)\n", pwszNewPrefix));
  1069. CDfsVolume *pNewParentVol = NULL;
  1070. CDfsVolume *pChildVol = NULL;
  1071. CDfsVolume *pOldParentVol = NULL;
  1072. BOOLEAN CreatedExitPt = FALSE;
  1073. CDfsService *pService;
  1074. CDfsService *pNextService;
  1075. DFS_PKT_ENTRY_ID NewId;
  1076. LPWSTR pwszChildName = NULL;
  1077. LPWSTR pwszNewParentPrefix = NULL;
  1078. LPWSTR pwszNewParentObject = NULL;
  1079. ULONG volPrefixLen, prefixLen;
  1080. if (VolumeOffLine()) {
  1081. return(NERR_DfsVolumeIsOffline);
  1082. }
  1083. if (NotLeafVolume()) {
  1084. return(NERR_DfsNotALeafVolume);
  1085. }
  1086. //
  1087. // Get a hold of the new parent, and check the validity of pwszNewPrefix
  1088. // in the process
  1089. //
  1090. prefixLen = wcslen( pwszNewPrefix );
  1091. pwszNewParentPrefix = new WCHAR[prefixLen + 1];
  1092. prefixLen *= sizeof(WCHAR);
  1093. if (pwszNewParentPrefix == NULL) {
  1094. dwErr = ERROR_OUTOFMEMORY;
  1095. } else {
  1096. wcscpy( pwszNewParentPrefix, pwszNewPrefix );
  1097. dwErr = pDfsmStorageDirectory->GetObjectForPrefix(
  1098. pwszNewParentPrefix,
  1099. FALSE,
  1100. &pwszNewParentObject,
  1101. &volPrefixLen);
  1102. if (dwErr == ERROR_SUCCESS) {
  1103. pwszNewParentPrefix[ volPrefixLen/sizeof(WCHAR) ] =
  1104. UNICODE_NULL;
  1105. if (prefixLen == volPrefixLen) {
  1106. dwErr = NERR_DfsVolumeAlreadyExists;
  1107. } else {
  1108. if (!_wcsnicmp(pwszNewParentPrefix,
  1109. _peid.Prefix.Buffer,
  1110. _peid.Prefix.Length/sizeof(WCHAR)))
  1111. {
  1112. //
  1113. // This means that we are trying to move somewhere
  1114. // below where we already are in the namespace. This
  1115. // is total nonsense. Return right now.
  1116. //
  1117. dwErr = ERROR_INVALID_PARAMETER;
  1118. }
  1119. }
  1120. } else {
  1121. IDfsVolInlineDebOut((
  1122. DEB_ERROR, "Failed to FindVolPrefix %08lx %ws\n",
  1123. dwErr, pwszNewParentPrefix));
  1124. }
  1125. }
  1126. //
  1127. // Instantiate the parent and cleanup strings used to get parent...
  1128. //
  1129. if (dwErr == ERROR_SUCCESS) {
  1130. pNewParentVol = new CDfsVolume();
  1131. if (pNewParentVol != NULL) {
  1132. dwErr = pNewParentVol->LoadNoRegister(
  1133. pwszNewParentObject,
  1134. 0);
  1135. } else {
  1136. dwErr = ERROR_OUTOFMEMORY;
  1137. }
  1138. }
  1139. delete [] pwszNewParentPrefix;
  1140. if (pwszNewParentObject != NULL) {
  1141. delete [] pwszNewParentObject;
  1142. }
  1143. if (dwErr == ERROR_SUCCESS) {
  1144. //
  1145. // Now that we have a handle on the appropriate volume object we
  1146. // can go ahead and perform the move.
  1147. //
  1148. dwErr = pNewParentVol->CreateChildPartition(
  1149. NULL,
  1150. _EntryType,
  1151. pwszNewPrefix,
  1152. _pwszComment,
  1153. &_peid.Uid,
  1154. NULL,
  1155. &pChildVol);
  1156. delete [] pwszChildName;
  1157. RECOVERY_TEST_POINT(L"Move", 1);
  1158. }
  1159. //
  1160. // If we succeeded in creating the object then we need to go and
  1161. // set the service List appropriately. Note that we will not
  1162. // set any recovery properties for now. We will exploit the recovery
  1163. // props setup by CreateChildPartition.
  1164. //
  1165. if (dwErr == ERROR_SUCCESS) {
  1166. pService = _DfsSvcList.GetFirstService();
  1167. while (pService != NULL) {
  1168. pNextService = _DfsSvcList.GetNextService(pService);
  1169. _DfsSvcList.RemoveService(pService);
  1170. dwErr = pChildVol->_DfsSvcList.SetNewService(pService);
  1171. if (dwErr != ERROR_SUCCESS) {
  1172. IDfsVolInlineDebOut((DEB_ERROR, "Failed to Set SvcProp %08lx\n",dwErr));
  1173. break;
  1174. }
  1175. pService = pNextService;
  1176. }
  1177. //
  1178. // Now we need to carefully remove the services from inmemory
  1179. // instantiation of the new pChildVol
  1180. //
  1181. pService = pChildVol->_DfsSvcList.GetFirstService();
  1182. while (pService != NULL) {
  1183. pNextService = pChildVol->_DfsSvcList.GetNextService(pService);
  1184. pChildVol->_DfsSvcList.RemoveService(pService);
  1185. _DfsSvcList.InsertNewService(pService);
  1186. pService = pNextService;
  1187. }
  1188. //
  1189. // If we failed to set service list we delete the object and we
  1190. // get out.
  1191. //
  1192. if (dwErr != ERROR_SUCCESS) {
  1193. pChildVol->DeleteObject();
  1194. }
  1195. }
  1196. //
  1197. // If we succeeded in creating the new object we go on to create the
  1198. // New ExitPoint
  1199. //
  1200. if (dwErr == ERROR_SUCCESS) {
  1201. //
  1202. // Let us switch to new EntryPath. We want to avoid mem allocations
  1203. // here itself.
  1204. //
  1205. NewId = _peid;
  1206. NewId.Prefix.Length = wcslen(pwszNewPrefix)*sizeof(WCHAR);
  1207. NewId.Prefix.MaximumLength = NewId.Prefix.Length + sizeof(WCHAR);
  1208. NewId.Prefix.Buffer = pwszNewPrefix;
  1209. //
  1210. // Now we can create the exit point at the appropriate place.
  1211. //
  1212. pService = pNewParentVol->_DfsSvcList.GetFirstService();
  1213. ASSERT(pService != NULL);
  1214. while (pService != NULL) {
  1215. dwErr = pService->CreateExitPoint(&NewId, _EntryType);
  1216. if (dwErr == ERROR_SUCCESS) {
  1217. CreatedExitPt = TRUE;
  1218. }
  1219. pService = pNewParentVol->_DfsSvcList.GetNextService(pService);
  1220. }
  1221. if (CreatedExitPt == TRUE) {
  1222. //
  1223. // This operation is committed now and we can set the
  1224. // Recovery Properties on the new object to DONE.
  1225. //
  1226. //
  1227. // Now before we set the recovery Properties to be done on the
  1228. // new object. We have to set the appropriate recovery props
  1229. // on the current object so that we can force this operation
  1230. // forward.
  1231. //
  1232. dwErr = _Recover.SetOperationStart(DFS_RECOVERY_STATE_MOVE, NULL);
  1233. //
  1234. // Now we set the recovery properties on the new object to
  1235. // DONE since there is nothing that needs to be done over there
  1236. // if we fail now. The only recovery (or roll forward) code will
  1237. // be triggered off this volume object itself.
  1238. //
  1239. RECOVERY_TEST_POINT(L"Move", 2);
  1240. if (dwErr == ERROR_SUCCESS) {
  1241. pChildVol->_Recover.SetOperationDone();
  1242. }
  1243. }
  1244. else {
  1245. //
  1246. // Cant go on with this operation so let us get rid of the
  1247. // object that we created.
  1248. //
  1249. IDfsVolInlineDebOut((DEB_TRACE,
  1250. "Unable to create Exit Pt %ws for Move\n",
  1251. pwszNewPrefix));
  1252. pChildVol->DeleteObject();
  1253. dwErr = NERR_DfsCantCreateJunctionPoint;
  1254. }
  1255. }
  1256. //
  1257. // Now if we passed the last stage then there is no stopping in this
  1258. // operation anymore.
  1259. //
  1260. if (dwErr == ERROR_SUCCESS) {
  1261. //
  1262. // Let us get to the old parent and delete the exit point first.
  1263. //
  1264. dwErr = GetParent(&pOldParentVol);
  1265. if (dwErr == ERROR_SUCCESS) {
  1266. pService = pOldParentVol->_DfsSvcList.GetFirstService();
  1267. ASSERT(pService != NULL);
  1268. //
  1269. // We ignore all errors here.
  1270. //
  1271. while(pService != NULL) {
  1272. dwErr = pService->DeleteExitPoint(&_peid, _EntryType);
  1273. pService = pOldParentVol->_DfsSvcList.GetNextService(pService);
  1274. }
  1275. dwErr = ERROR_SUCCESS;
  1276. }
  1277. else {
  1278. IDfsVolInlineDebOut((DEB_ERROR,
  1279. "Unable to get to the parent vol for %ws\n",
  1280. _pwzFileName));
  1281. }
  1282. RECOVERY_TEST_POINT(L"Move", 3);
  1283. //
  1284. // Now we merely need to do a modify Prefix operation on the current
  1285. // volume's services.
  1286. //
  1287. pService = _DfsSvcList.GetFirstService();
  1288. ASSERT(pService != NULL);
  1289. while (pService != NULL) {
  1290. dwErr = pService->ModifyPrefix(&NewId);
  1291. if (dwErr != ERROR_SUCCESS) {
  1292. IDfsVolInlineDebOut((DEB_ERROR,
  1293. "Unable to Modify prefix to %ws %08lx\n",
  1294. NewId.Prefix.Buffer, dwErr));
  1295. }
  1296. pService = _DfsSvcList.GetNextService(pService);
  1297. }
  1298. dwErr = ERROR_SUCCESS;
  1299. //
  1300. // We can now delete this object itself.
  1301. //
  1302. DeleteObject();
  1303. _Deleted = FALSE;
  1304. //
  1305. // We now need to change the _pwzFileName of this idfsvol to match
  1306. // the new child that we have created. Also need to change E.P.
  1307. //
  1308. ULONG uLen = wcslen(pChildVol->_pwzFileName);
  1309. if ((uLen > wcslen(_pwzFileName)) && (uLen > MAX_PATH)) {
  1310. if (_pwzFileName != _FileNameBuffer)
  1311. delete [] _pwzFileName;
  1312. _pwzFileName = new WCHAR[uLen + 1];
  1313. }
  1314. wcscpy(_pwzFileName, pChildVol->_pwzFileName);
  1315. //
  1316. // Now the entrypath prefix.
  1317. //
  1318. uLen = NewId.Prefix.Length;
  1319. if (uLen > _peid.Prefix.Length) {
  1320. if (_peid.Prefix.Buffer != _EntryPathBuffer)
  1321. delete [] _peid.Prefix.Buffer;
  1322. if (uLen >= MAX_PATH)
  1323. _peid.Prefix.Buffer = new WCHAR[(uLen+1)];
  1324. else
  1325. _peid.Prefix.Buffer = _EntryPathBuffer;
  1326. }
  1327. _peid.Prefix.Length = (USHORT)uLen;
  1328. _peid.Prefix.MaximumLength = _peid.Prefix.Length + sizeof(WCHAR);
  1329. wcscpy(_peid.Prefix.Buffer, NewId.Prefix.Buffer);
  1330. //
  1331. // Now we get the IStorage's etc. over to this idfsvol. We steal.
  1332. //
  1333. ASSERT((_pStorage == NULL) &&
  1334. (_Recover._pPSStg == NULL) &&
  1335. (_DfsSvcList._pPSStg == NULL));
  1336. _pStorage = pChildVol->_pStorage;
  1337. pChildVol->_pStorage = NULL;
  1338. _Recover._pPSStg = pChildVol->_Recover._pPSStg;
  1339. _DfsSvcList._pPSStg = pChildVol->_DfsSvcList._pPSStg;
  1340. pChildVol->_Recover._pPSStg = NULL;
  1341. pChildVol->_DfsSvcList._pPSStg = NULL;
  1342. //
  1343. // Copy over the child's registration id, so we can revoke that
  1344. // as well. We need to revoke it because it has been registered
  1345. // with the child's CDfsVol address.
  1346. //
  1347. _dwRotRegistration = pChildVol->_dwRotRegistration;
  1348. pChildVol->_dwRotRegistration = NULL;
  1349. //
  1350. // Now we have to update the DC's PKT entry itself.
  1351. //
  1352. dwErr = UpdatePktEntry(NULL);
  1353. if (dwErr != ERROR_SUCCESS) {
  1354. IDfsVolInlineDebOut((DEB_ERROR,
  1355. "Unable to updatePkt entry %08lx for %ws\n",
  1356. dwErr, pChildVol->_peid.Prefix.Buffer));
  1357. }
  1358. }
  1359. if (pNewParentVol != NULL) {
  1360. pNewParentVol->Release();
  1361. }
  1362. if (pChildVol != NULL) {
  1363. pChildVol->Release();
  1364. }
  1365. if (pOldParentVol != NULL) {
  1366. pOldParentVol->Release();
  1367. }
  1368. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Move() exit\n"));
  1369. return((dwErr));
  1370. }
  1371. //+------------------------------------------------------------------------
  1372. //
  1373. // Method: CDfsVolume::InitializePkt, public
  1374. //
  1375. // Synopsis: This method initilaizes the PKT with info regarding this
  1376. // volume and also sets up the relational info for itself. It
  1377. // also continues to recursively call all the child volume
  1378. // objects' InitializePkt method.
  1379. //
  1380. // Arguments: None
  1381. //
  1382. // Notes: This is a recursive method. By calling this we can initialise
  1383. // the PKT with info regarding this volume and all its children
  1384. // since it is a recursive routine. This is a DEPTH-FIRST Traversal
  1385. //
  1386. // History: 09-Feb-93 SudK Created.
  1387. //
  1388. //-------------------------------------------------------------------------
  1389. DWORD
  1390. CDfsVolume::InitializePkt(
  1391. HANDLE PktHandle)
  1392. {
  1393. DWORD dwErr = ERROR_SUCCESS;
  1394. CEnumDirectory *pDir = NULL;
  1395. DFSMSTATDIR rgelt;
  1396. ULONG fetched = 0;
  1397. CDfsVolume *child = NULL;
  1398. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::InitializePkt()\n"));
  1399. #if DBG
  1400. if (DfsSvcVerbose & 0x80000000)
  1401. DbgPrint("CDfsVolume::InitializePkt()\n");
  1402. #endif
  1403. memset(&rgelt, 0, sizeof(DFSMSTATDIR));
  1404. //
  1405. // First, we get a hold of the CRegEnumDirectory interface to our own
  1406. // volume object.
  1407. //
  1408. dwErr = _pStorage->GetEnumDirectory(&pDir);
  1409. if (dwErr != ERROR_SUCCESS) {
  1410. IDfsVolInlineDebOut((DEB_ERROR, "Failed to get IDirectory %08lx\n", dwErr));
  1411. return(dwErr);
  1412. }
  1413. //
  1414. // While there are children still to be handled we continue on.
  1415. //
  1416. while (TRUE) {
  1417. if (rgelt.pwcsName != NULL) {
  1418. delete [] rgelt.pwcsName;
  1419. rgelt.pwcsName = NULL;
  1420. }
  1421. dwErr = pDir->Next(&rgelt, &fetched);
  1422. if (dwErr != ERROR_SUCCESS) {
  1423. IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumerate %08lx\n", dwErr));
  1424. break;
  1425. }
  1426. //
  1427. // If we did not get back any children we are done.
  1428. //
  1429. if (fetched == 0)
  1430. break;
  1431. IDfsVolInlineDebOut((
  1432. DEB_TRACE, "CDfsVolume::InitializePkt Name=%ws\n", rgelt.pwcsName));
  1433. //
  1434. // If the child name is . or .. we ignore it
  1435. //
  1436. if ((!wcscmp(rgelt.pwcsName, L".")) ||
  1437. (!wcscmp(rgelt.pwcsName, L"..")))
  1438. continue;
  1439. dwErr = GetDfsVolumeFromStg(&rgelt, &child);
  1440. if (dwErr != ERROR_SUCCESS) {
  1441. //
  1442. // Log an EVENT here saying that volume object is corrupt and
  1443. // continue on. We dont want to stop just because we cant handle
  1444. // one particular object.
  1445. //
  1446. LogMessage( DEB_ERROR,
  1447. &(_peid.Prefix.Buffer),
  1448. 1,
  1449. DFS_CANT_GET_TO_CHILD_IDFSVOL_MSG);
  1450. IDfsVolInlineDebOut((DEB_ERROR, "Bad Object: %ws\n", rgelt.pwcsName));
  1451. //
  1452. // We dont want to give up as yet. So let us go on to the next
  1453. // object.
  1454. //
  1455. fetched = 0; //Do I need to do this??
  1456. continue;
  1457. }
  1458. if (DFS_GET_RECOVERY_STATE(child->_RecoveryState) != DFS_RECOVERY_STATE_NONE) {
  1459. //
  1460. // Now we need to call the recovery method to handle this stuff.
  1461. // What do I do with the error code that I get back out here.
  1462. //
  1463. LogMessage(DEB_ERROR,
  1464. &(child->_peid.Prefix.Buffer),
  1465. 1,
  1466. DFS_RECOVERY_NECESSARY_MSG);
  1467. IDfsVolInlineDebOut((DEB_ERROR, "Object To Recover From: %ws\n",
  1468. rgelt.pwcsName));
  1469. dwErr = child->RecoverFromFailure();
  1470. //
  1471. // We failed to recover from failure. The required messages would
  1472. // have already been logged so we dont need to bother about that
  1473. // here at all. But a failure in this process means we really cant
  1474. // go on here. We would get a failure from the above only if there
  1475. // was some drastic problem.
  1476. //
  1477. if (dwErr != ERROR_SUCCESS) {
  1478. IDfsVolInlineDebOut((DEB_ERROR, "Fatal RecoveryError \n"));
  1479. }
  1480. if (child->_Deleted == TRUE) {
  1481. //
  1482. // Due to above recovery the volume got deleted. No point
  1483. // going on along this path. Move on to next sibling.
  1484. //
  1485. child->Release();
  1486. fetched = 0;
  1487. continue;
  1488. }
  1489. }
  1490. if (dwErr == ERROR_SUCCESS) {
  1491. //
  1492. // Create the subordinate PKT entry for the child. This way we
  1493. // get to setup the links as well.
  1494. //
  1495. dwErr = child->CreateSubordinatePktEntry(PktHandle, &_peid, TRUE);
  1496. if (dwErr != ERROR_SUCCESS) {
  1497. //
  1498. // This is a chance to write out an EVENT and then continue
  1499. // to the Initialization of further children. We need to
  1500. // continue on even though we could not get to finish this
  1501. // volume.
  1502. //
  1503. LogMessage(DEB_ERROR,
  1504. &(child->_peid.Prefix.Buffer),
  1505. 1,
  1506. DFS_UNABLE_TO_CREATE_SUBORDINATE_ENTRY_MSG);
  1507. IDfsVolInlineDebOut((DEB_ERROR, "Object For Above Error: %ws\n",
  1508. rgelt.pwcsName));
  1509. }
  1510. }
  1511. //
  1512. // Now that the subordinate entry has been created we can go ahead
  1513. // and call InitialisePkt on child. This makes a DepthFirst traversal.
  1514. // Even if we could not create the subordinate entry for some reason,
  1515. // we need to go on and attempt to initialize the rest. But we really
  1516. // cant do that here. Riad: 455283. We need a different approach here.
  1517. //
  1518. if (dwErr == ERROR_SUCCESS) {
  1519. dwErr = child->InitializePkt(PktHandle);
  1520. if (dwErr != ERROR_SUCCESS) {
  1521. //
  1522. // We ignore this error and also dont bother to write out an
  1523. // event since this should have been handled by some lower method.
  1524. // We maybe sitting many levels high up and this error came all
  1525. // the way back up.
  1526. //
  1527. IDfsVolInlineDebOut((DEB_ERROR, "InitPkt failed %08lx\n", dwErr));
  1528. }
  1529. }
  1530. child->Release();
  1531. //
  1532. // Let us now attempt to enumerate the next child.
  1533. //
  1534. fetched = 0;
  1535. } //While fetched!=0
  1536. //
  1537. // If this volume's state is offline, set the local DC's pkt to reflect
  1538. // that case
  1539. //
  1540. if (_State == DFS_VOLUME_STATE_OFFLINE) {
  1541. NTSTATUS Status;
  1542. CDfsService *psvc;
  1543. for (psvc = _DfsSvcList.GetFirstService();
  1544. psvc != NULL;
  1545. psvc = _DfsSvcList.GetNextService(psvc)) {
  1546. LPWSTR wszService;
  1547. wszService = psvc->GetServiceName();
  1548. Status = DfsSetServiceState(
  1549. &_peid,
  1550. wszService,
  1551. DFS_SERVICE_TYPE_OFFLINE);
  1552. }
  1553. Status = DfsDCSetVolumeState(
  1554. &_peid,
  1555. PKT_ENTRY_TYPE_OFFLINE);
  1556. }
  1557. if (rgelt.pwcsName != NULL)
  1558. delete [] rgelt.pwcsName;
  1559. if (pDir != NULL)
  1560. pDir->Release();
  1561. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::InitializePkt() exit\n"));
  1562. #if DBG
  1563. if (DfsSvcVerbose & 0x80000000)
  1564. DbgPrint("CDfsVolume::InitializePkt exit %d\n", dwErr);
  1565. #endif
  1566. return(dwErr);
  1567. }
  1568. //+----------------------------------------------------------------------------
  1569. //
  1570. // Function: GetNetInfo
  1571. //
  1572. // Synopsis: Gets information about the volume.
  1573. //
  1574. // Arguments: [Level] -- Level of Information desired.
  1575. //
  1576. // [pInfo] -- Pointer to info struct to be filled. Pointer
  1577. // members will be allocated using MIDL_user_allocate.
  1578. // The type of this variable is LPDFS_INFO_3, but one
  1579. // can pass in pointers to lower levels, and only the
  1580. // fields appropriate for the level will be touched.
  1581. //
  1582. // [pcbInfo] -- On successful return, contains the size in
  1583. // bytes of the returned info. The returned size does
  1584. // not include the size of the DFS_INFO_3 struct itself.
  1585. //
  1586. // Returns: ERROR_SUCCESS -- Successfully returning info
  1587. //
  1588. // ERROR_OUTOFMEMORY -- Out of memory
  1589. //
  1590. //-----------------------------------------------------------------------------
  1591. DWORD
  1592. CDfsVolume::GetNetInfo(
  1593. DWORD Level,
  1594. LPDFS_INFO_3 pInfo,
  1595. LPDWORD pcbInfo)
  1596. {
  1597. DWORD dwErr = ERROR_SUCCESS;
  1598. DWORD cbInfo = 0, cbItem;
  1599. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetNetInfo(l=%d)\n", Level));
  1600. #if DBG
  1601. if (DfsSvcVerbose)
  1602. DbgPrint(" CDfsVolume::GetNetInfo(l=%d)\n", Level);
  1603. #endif
  1604. //
  1605. // See if this is a Level 100 or 101. If so, we handle them right away
  1606. // and return
  1607. if (Level == 100) {
  1608. LPDFS_INFO_100 pInfo100 = (LPDFS_INFO_100) pInfo;
  1609. cbItem = (wcslen(_pwszComment) + 1) * sizeof(WCHAR);
  1610. pInfo100->Comment = (LPWSTR) MIDL_user_allocate(cbItem);
  1611. if (pInfo100->Comment != NULL) {
  1612. wcscpy(pInfo100->Comment, _pwszComment);
  1613. *pcbInfo = cbItem;
  1614. return( ERROR_SUCCESS );
  1615. } else {
  1616. return( ERROR_OUTOFMEMORY );
  1617. }
  1618. }
  1619. if (Level == 101) {
  1620. LPDFS_INFO_101 pInfo101 = (LPDFS_INFO_101) pInfo;
  1621. pInfo->State = _State;
  1622. return( ERROR_SUCCESS );
  1623. }
  1624. //
  1625. // level 4 isn't just an extension of 3, so handle it seperately
  1626. //
  1627. if (Level == 4) {
  1628. LPDFS_INFO_4 pInfo4 = (LPDFS_INFO_4) pInfo;
  1629. cbItem = sizeof(UNICODE_PATH_SEP) + _peid.Prefix.Length + sizeof(WCHAR);
  1630. pInfo4->EntryPath = (LPWSTR) MIDL_user_allocate(cbItem);
  1631. if (pInfo4->EntryPath != NULL) {
  1632. pInfo4->EntryPath[0] = UNICODE_PATH_SEP;
  1633. wcscpy(&pInfo4->EntryPath[1], _peid.Prefix.Buffer);
  1634. cbInfo += cbItem;
  1635. } else {
  1636. dwErr = ERROR_OUTOFMEMORY;
  1637. }
  1638. if (dwErr == ERROR_SUCCESS) {
  1639. cbItem = (wcslen(_pwszComment)+1) * sizeof(WCHAR);
  1640. pInfo4->Comment = (LPWSTR) MIDL_user_allocate(cbItem);
  1641. if (pInfo4->Comment != NULL) {
  1642. wcscpy( pInfo4->Comment, _pwszComment );
  1643. cbInfo += cbItem;
  1644. } else {
  1645. dwErr = ERROR_OUTOFMEMORY;
  1646. }
  1647. }
  1648. if (dwErr == ERROR_SUCCESS) {
  1649. pInfo4->State = _State;
  1650. pInfo4->Timeout = _Timeout;
  1651. pInfo4->Guid = _peid.Uid;
  1652. pInfo4->NumberOfStorages = _DfsSvcList.GetServiceCount();
  1653. cbItem = pInfo4->NumberOfStorages * sizeof(DFS_STORAGE_INFO);
  1654. pInfo4->Storage = (LPDFS_STORAGE_INFO) MIDL_user_allocate(cbItem);
  1655. if (pInfo4->Storage != NULL) {
  1656. ULONG i;
  1657. CDfsService *pSvc;
  1658. RtlZeroMemory(pInfo4->Storage, cbItem);
  1659. cbInfo += cbItem;
  1660. pSvc = _DfsSvcList.GetFirstService();
  1661. i = 0;
  1662. while (pSvc != NULL && dwErr == ERROR_SUCCESS) {
  1663. dwErr = pSvc->GetNetStorageInfo(&pInfo4->Storage[i], &cbItem);
  1664. cbInfo += cbItem;
  1665. i++;
  1666. pSvc = _DfsSvcList.GetNextService( pSvc );
  1667. }
  1668. if (dwErr != ERROR_SUCCESS) {
  1669. for (; i > 0; i--) {
  1670. MIDL_user_free(pInfo4->Storage[i-1].ServerName);
  1671. MIDL_user_free(pInfo4->Storage[i-1].ShareName);
  1672. }
  1673. }
  1674. } else {
  1675. dwErr = ERROR_OUTOFMEMORY;
  1676. }
  1677. }
  1678. //
  1679. // See if we need to clean up...
  1680. //
  1681. if (dwErr != ERROR_SUCCESS) {
  1682. if (pInfo4->EntryPath != NULL) {
  1683. MIDL_user_free(pInfo4->EntryPath);
  1684. }
  1685. if (pInfo4->Storage != NULL) {
  1686. MIDL_user_free(pInfo4->Storage);
  1687. }
  1688. }
  1689. *pcbInfo = cbInfo;
  1690. return(dwErr);
  1691. }
  1692. //
  1693. // Level is 1,2 or 3
  1694. //
  1695. //
  1696. // Fill in the Level 1 stuff
  1697. //
  1698. cbItem = sizeof(UNICODE_PATH_SEP) + _peid.Prefix.Length + sizeof(WCHAR);
  1699. pInfo->EntryPath = (LPWSTR) MIDL_user_allocate(cbItem);
  1700. if (pInfo->EntryPath != NULL) {
  1701. pInfo->EntryPath[0] = UNICODE_PATH_SEP;
  1702. wcscpy(&pInfo->EntryPath[1], _peid.Prefix.Buffer);
  1703. cbInfo += cbItem;
  1704. } else {
  1705. dwErr = ERROR_OUTOFMEMORY;
  1706. }
  1707. //
  1708. // Fill in the Level 2 stuff if needed
  1709. //
  1710. if (dwErr == ERROR_SUCCESS && Level > 1) {
  1711. cbItem = (wcslen(_pwszComment)+1) * sizeof(WCHAR);
  1712. pInfo->Comment = (LPWSTR) MIDL_user_allocate(cbItem);
  1713. if (pInfo->Comment != NULL) {
  1714. wcscpy( pInfo->Comment, _pwszComment );
  1715. cbInfo += cbItem;
  1716. } else {
  1717. dwErr = ERROR_OUTOFMEMORY;
  1718. }
  1719. }
  1720. if (dwErr == ERROR_SUCCESS && Level > 1) {
  1721. pInfo->State = _State;
  1722. pInfo->NumberOfStorages = _DfsSvcList.GetServiceCount();
  1723. }
  1724. //
  1725. // Fill in the Level 3 stuff if needed
  1726. //
  1727. if (dwErr == ERROR_SUCCESS && Level > 2) {
  1728. cbItem = pInfo->NumberOfStorages * sizeof(DFS_STORAGE_INFO);
  1729. pInfo->Storage = (LPDFS_STORAGE_INFO) MIDL_user_allocate(cbItem);
  1730. if (pInfo->Storage != NULL) {
  1731. ULONG i;
  1732. CDfsService *pSvc;
  1733. RtlZeroMemory(pInfo->Storage, cbItem);
  1734. cbInfo += cbItem;
  1735. pSvc = _DfsSvcList.GetFirstService();
  1736. i = 0;
  1737. while (pSvc != NULL && dwErr == ERROR_SUCCESS) {
  1738. dwErr = pSvc->GetNetStorageInfo(&pInfo->Storage[i], &cbItem);
  1739. cbInfo += cbItem;
  1740. i++;
  1741. pSvc = _DfsSvcList.GetNextService( pSvc );
  1742. }
  1743. if (dwErr != ERROR_SUCCESS) {
  1744. for (; i > 0; i--) {
  1745. MIDL_user_free(pInfo->Storage[i-1].ServerName);
  1746. MIDL_user_free(pInfo->Storage[i-1].ShareName);
  1747. }
  1748. }
  1749. } else {
  1750. dwErr = ERROR_OUTOFMEMORY;
  1751. }
  1752. }
  1753. //
  1754. // See if we need to clean up...
  1755. //
  1756. if (dwErr != ERROR_SUCCESS) {
  1757. if (Level > 1) {
  1758. if (pInfo->EntryPath != NULL) {
  1759. MIDL_user_free(pInfo->EntryPath);
  1760. }
  1761. }
  1762. if (Level > 2) {
  1763. if (pInfo->Storage != NULL) {
  1764. MIDL_user_free(pInfo->Storage);
  1765. }
  1766. }
  1767. }
  1768. //
  1769. // Finally, we are done
  1770. //
  1771. *pcbInfo = cbInfo;
  1772. return(dwErr);
  1773. }
  1774. //+-----------------------------------------------------------------------
  1775. //
  1776. // Member: CDfsVolume::SetComment, public
  1777. //
  1778. // Synopsis: Sets a comment on the volume object.
  1779. //
  1780. // Arguments: [pwszComment] -- The comment
  1781. //
  1782. // Returns:
  1783. //
  1784. // History: 05/10/93 SudK Created.
  1785. //
  1786. //------------------------------------------------------------------------
  1787. DWORD
  1788. CDfsVolume::SetComment(
  1789. PWCHAR pwszComment
  1790. )
  1791. {
  1792. DWORD dwErr = ERROR_SUCCESS;
  1793. SYSTEMTIME st;
  1794. FILETIME ftOld;
  1795. LPWSTR pwszOldComment;
  1796. ULONG ulen = wcslen(pwszComment);
  1797. IDfsVolInlineDebOut((DEB_TRACE, "SetComment: %ws\n", pwszComment));
  1798. ftOld = _ftComment;
  1799. pwszOldComment = _pwszComment;
  1800. _pwszComment = new WCHAR[ulen+1];
  1801. if (_pwszComment == NULL)
  1802. dwErr = ERROR_OUTOFMEMORY;
  1803. else {
  1804. wcscpy(_pwszComment, pwszComment);
  1805. GetSystemTime( &st );
  1806. SystemTimeToFileTime( &st, &_ftComment );
  1807. dwErr = SetIdProps( _EntryType,
  1808. _State,
  1809. _peid.Prefix.Buffer,
  1810. _peid.ShortPrefix.Buffer,
  1811. _peid.Uid,
  1812. pwszComment,
  1813. _Timeout,
  1814. _ftEntryPath,
  1815. _ftState,
  1816. _ftComment,
  1817. FALSE);
  1818. }
  1819. if (dwErr != ERROR_SUCCESS) {
  1820. if (_pwszComment) {
  1821. delete [] _pwszComment;
  1822. }
  1823. _ftComment = ftOld;
  1824. _pwszComment = pwszOldComment;
  1825. }
  1826. return(dwErr);
  1827. }
  1828. //+-------------------------------------------------------------------------
  1829. //
  1830. // Member: CDfsVolume::FixServiceKnowledge
  1831. //
  1832. // Synopsis: This method is called for fixing knowledge inconsistencies.
  1833. // It checks to make sure that the given service does support
  1834. // this volume and then goes on to do a CreateLocalVol call on
  1835. // that service.
  1836. //
  1837. // Arguments: [pwszServiceName] -- The principal name of service to be
  1838. // fixed.
  1839. //
  1840. // History: 06-April-1993 SudK Created
  1841. //
  1842. //--------------------------------------------------------------------------
  1843. DWORD
  1844. CDfsVolume::FixServiceKnowledge(
  1845. PWCHAR pwszServiceName
  1846. )
  1847. {
  1848. DWORD dwErr = ERROR_SUCCESS;
  1849. CDfsService *pService;
  1850. PWCHAR ErrorStrs[3];
  1851. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::FixServiceKnowledge(%s)\n",
  1852. pwszServiceName));
  1853. dwErr = _DfsSvcList.GetServiceFromPrincipalName(pwszServiceName, &pService);
  1854. if (dwErr == ERROR_SUCCESS) {
  1855. //
  1856. // We really dont care about errors since this is all heuristic. We
  1857. // will merely log an error that's all.
  1858. //
  1859. dwErr = pService->FixLocalVolume(&_peid, _EntryType);
  1860. if (dwErr != ERROR_SUCCESS) {
  1861. //
  1862. // Log the error and try to take the service off-line
  1863. //
  1864. DWORD dwErrOffLine;
  1865. ErrorStrs[0] = _peid.Prefix.Buffer;
  1866. ErrorStrs[1] = pwszServiceName;
  1867. LogMessage( DEB_ERROR,
  1868. ErrorStrs,
  1869. 2,
  1870. DFS_CANNOT_SET_SERVICE_PROPERTY_MSG);
  1871. dwErrOffLine = pService->SetVolumeState(
  1872. &_peid,
  1873. DFS_SERVICE_TYPE_OFFLINE,
  1874. FALSE);
  1875. if (dwErrOffLine == ERROR_SUCCESS) {
  1876. dwErrOffLine = _DfsSvcList.SerializeSvcList();
  1877. }
  1878. if (dwErrOffLine == ERROR_SUCCESS) {
  1879. _DfsSvcList.SetServiceListProperty( FALSE );
  1880. }
  1881. }
  1882. } else {
  1883. IDfsVolInlineDebOut((
  1884. DEB_ERROR,
  1885. "Could not find Service %ws on Volume: %ws\n",
  1886. pwszServiceName,
  1887. _peid.Prefix.Buffer));
  1888. }
  1889. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::FixServiceKnowledge() exit\n"));
  1890. return((dwErr));
  1891. }
  1892. //+---------------------------------------------------------------------
  1893. //
  1894. // Member: CDfsVolume::Rename, public
  1895. //
  1896. // Synopsis: This method should be called if an object/file/directory
  1897. // on this volume is to be renamed, and the name falls along an
  1898. // exit point off this volume. This method will perform the
  1899. // rename on the filesystem and then go on to call ModifyPrefix
  1900. // on all the child volume objects which are affected by the
  1901. // rename operation.
  1902. //
  1903. // Arguments: [oldPrefix] -- The oldPrefix that needs to be modified. Prefix
  1904. // [newPrefix] -- This should be ORG relative prefix.
  1905. //
  1906. // Returns: ERROR_SUCCESS -- If all went well.
  1907. //
  1908. // Notes: The old and newPaths should follow all requirements of a File
  1909. // System Rename operation. Should vary only in last component etc.
  1910. //
  1911. // History: 31 April 1993 SudK Created.
  1912. // 26 April 1993 SudK Fixed to work properly.
  1913. //
  1914. //----------------------------------------------------------------------
  1915. DWORD
  1916. CDfsVolume::Rename(
  1917. PWSTR oldPrefix,
  1918. PWSTR newPrefix
  1919. )
  1920. {
  1921. DWORD dwErr = ERROR_SUCCESS;
  1922. CDfsVolume *child = NULL;
  1923. CEnumDirectory *pdir = NULL;
  1924. DFSMSTATDIR rgelt;
  1925. ULONG fetched = 0;
  1926. WCHAR wszOldPath[MAX_PATH], wszNewPath[MAX_PATH];
  1927. PWSTR pwszOldPath = wszOldPath;
  1928. PWSTR pwszNewPath = wszNewPath;
  1929. ULONG len = MAX_PATH;
  1930. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Rename(%ws,%ws)\n", oldPrefix, newPrefix));
  1931. //
  1932. // Need to check if this is the right idfsvol to call rename on.
  1933. //
  1934. ULONG ulen = _peid.Prefix.Length/sizeof(WCHAR);
  1935. if ((wcslen(oldPrefix) <= ulen) ||
  1936. (wcslen(newPrefix) <= ulen)) {
  1937. //
  1938. // Both old and new prefixes should be longer than the prefix of
  1939. // this volume. If they are not then we can return error right away.
  1940. //
  1941. dwErr = NERR_DfsBadRenamePath;
  1942. } else if ((_wcsnicmp(_peid.Prefix.Buffer, oldPrefix, ulen) != 0) ||
  1943. (_wcsnicmp(_peid.Prefix.Buffer, newPrefix, ulen) != 0)) {
  1944. //
  1945. // Now we need to check to make sure that this volume's prefix is a
  1946. // proper prefix of path being renamed.
  1947. //
  1948. dwErr = NERR_DfsBadRenamePath;
  1949. } else if (_wcsicmp(oldPrefix, newPrefix) == 0) {
  1950. //
  1951. // Someone has given identical rename path. Return right away.
  1952. //
  1953. dwErr = NERR_DfsBadRenamePath;
  1954. }
  1955. if (dwErr == ERROR_SUCCESS) {
  1956. len = wcslen(oldPrefix);
  1957. if (len > (MAX_PATH - 2)) {
  1958. pwszOldPath = new WCHAR[ len + 2 ];
  1959. if (pwszOldPath == NULL) {
  1960. dwErr = ERROR_OUTOFMEMORY;
  1961. }
  1962. }
  1963. if (dwErr == ERROR_SUCCESS) {
  1964. wcscpy( pwszOldPath, UNICODE_PATH_SEP_STR );
  1965. wcscat( pwszOldPath, oldPrefix );
  1966. }
  1967. }
  1968. if (dwErr == ERROR_SUCCESS) {
  1969. len = wcslen(newPrefix);
  1970. if (len > (MAX_PATH - 2)) {
  1971. pwszNewPath = new WCHAR[ len + 2 ];
  1972. if (pwszNewPath == NULL) {
  1973. dwErr = ERROR_OUTOFMEMORY;
  1974. }
  1975. }
  1976. if (dwErr == ERROR_SUCCESS) {
  1977. wcscpy( pwszNewPath, UNICODE_PATH_SEP_STR );
  1978. wcscat( pwszNewPath, newPrefix );
  1979. }
  1980. }
  1981. if (dwErr == ERROR_SUCCESS) {
  1982. //
  1983. // Now do the Rename operation
  1984. //
  1985. NTSTATUS Status;
  1986. Status = MoveFileOrJP(pwszOldPath, pwszNewPath);
  1987. if (!NT_SUCCESS(Status)) {
  1988. dwErr = RtlNtStatusToDosError(Status);
  1989. }
  1990. if (pwszOldPath != wszOldPath) {
  1991. delete [] pwszOldPath;
  1992. }
  1993. if (pwszNewPath != wszNewPath) {
  1994. delete [] pwszNewPath;
  1995. }
  1996. }
  1997. if (dwErr == ERROR_SUCCESS) {
  1998. dwErr = _pStorage->GetEnumDirectory(&pdir);
  1999. if (dwErr != ERROR_SUCCESS) {
  2000. return(dwErr);
  2001. }
  2002. //
  2003. // While there are children still to be handled we continue on.
  2004. //
  2005. rgelt.pwcsName = NULL;
  2006. while (TRUE) {
  2007. if (rgelt.pwcsName != NULL) {
  2008. delete [] rgelt.pwcsName;
  2009. rgelt.pwcsName = NULL;
  2010. }
  2011. dwErr = pdir->Next(&rgelt, &fetched);
  2012. if (dwErr != ERROR_SUCCESS) {
  2013. IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumeraate\n", 0));
  2014. break;
  2015. }
  2016. //
  2017. // If we did not get back any children we are done.
  2018. //
  2019. if (fetched == 0)
  2020. break;
  2021. //
  2022. // If the child name is . or .. we ignore it
  2023. //
  2024. if ((!wcscmp(rgelt.pwcsName, L".")) ||
  2025. (!wcscmp(rgelt.pwcsName, L"..")))
  2026. continue;
  2027. dwErr = GetDfsVolumeFromStg(&rgelt, &child);
  2028. if (dwErr != ERROR_SUCCESS) {
  2029. //
  2030. // Log an EVENT here saying that volume object is corrupt and
  2031. // continue on. We dont want to stop just because we cant handle
  2032. // one particular object.
  2033. //
  2034. LogMessage( DEB_ERROR,
  2035. &(_peid.Prefix.Buffer),
  2036. 1,
  2037. DFS_CANT_GET_TO_CHILD_IDFSVOL_MSG);
  2038. //
  2039. // We dont want to give up as yet. So let us go on to the next
  2040. // object.
  2041. //
  2042. fetched = 0;
  2043. continue;
  2044. }
  2045. dwErr = child->ModifyEntryPath(oldPrefix, newPrefix);
  2046. if (dwErr != ERROR_SUCCESS) {
  2047. //
  2048. // We ignore this err since it would be logged further down.
  2049. //
  2050. }
  2051. child->Release();
  2052. //
  2053. // Let us now attempt to enumerate the next child.
  2054. //
  2055. fetched = 0;
  2056. } //While TRUE
  2057. if (pdir != NULL)
  2058. pdir->Release();
  2059. }
  2060. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::Rename() exit\n"));
  2061. return(dwErr);
  2062. }
  2063. //+----------------------------------------------------------------------------
  2064. //
  2065. // Method: CDfsVolume::ModifyLocalEntryPath,private
  2066. //
  2067. // Synopsis: This method modifies the entry path on the volume object,
  2068. // and modifies the local PKT to reflect the change.
  2069. //
  2070. // Arguments:
  2071. //
  2072. // Returns:
  2073. //
  2074. //-----------------------------------------------------------------------------
  2075. DWORD
  2076. CDfsVolume::ModifyLocalEntryPath(
  2077. PWCHAR newEntryPath,
  2078. FILETIME ftEntryPath,
  2079. BOOL fUpdatePkt)
  2080. {
  2081. DWORD dwErr = ERROR_SUCCESS;
  2082. CUnicodeString oldString, newString;
  2083. dwErr = SetIdProps(
  2084. _EntryType,
  2085. _State,
  2086. newEntryPath,
  2087. _peid.ShortPrefix.Buffer,
  2088. _peid.Uid,
  2089. _pwszComment,
  2090. _Timeout,
  2091. ftEntryPath,
  2092. _ftState,
  2093. _ftComment,
  2094. FALSE);
  2095. if (dwErr != ERROR_SUCCESS) {
  2096. //
  2097. // We want to return right away. Can we hope that the private section
  2098. // variable will get deleted and return or should we fix the private
  2099. // _peid since this operation never succeeded.
  2100. //
  2101. IDfsVolInlineDebOut((
  2102. DEB_ERROR, "Unable To modify Prefix to [%ws]\n", newEntryPath));
  2103. return(dwErr); //Raid: 455283 cant return this error here.
  2104. }
  2105. //
  2106. // Now that the object has changed let us modify the Private variables.
  2107. //
  2108. oldString.Copy(_peid.Prefix.Buffer);
  2109. newString.Copy(newEntryPath);
  2110. if (_peid.Prefix.Buffer != _EntryPathBuffer)
  2111. delete [] _peid.Prefix.Buffer;
  2112. newString.Transfer(&(_peid.Prefix));
  2113. if (fUpdatePkt) {
  2114. dwErr = UpdatePktEntry(NULL);
  2115. }
  2116. if (dwErr != ERROR_SUCCESS) {
  2117. DWORD dwErr2;
  2118. delete [] _peid.Prefix.Buffer;
  2119. oldString.Transfer(&(_peid.Prefix));
  2120. dwErr2 = SetIdProps(_EntryType,
  2121. _State,
  2122. _peid.Prefix.Buffer,
  2123. _peid.ShortPrefix.Buffer,
  2124. _peid.Uid,
  2125. _pwszComment,
  2126. _Timeout,
  2127. _ftEntryPath,
  2128. _ftState,
  2129. _ftComment,
  2130. FALSE);
  2131. if (dwErr2 != ERROR_SUCCESS) {
  2132. IDfsVolInlineDebOut((
  2133. DEB_ERROR,
  2134. "Error restoring id props in failed rename operation %08lx\n",
  2135. dwErr2));
  2136. }
  2137. } else {
  2138. _ftEntryPath = ftEntryPath;
  2139. }
  2140. return(dwErr);
  2141. }
  2142. //+---------------------------------------------------------------------
  2143. //
  2144. // Method: CDfsVolume::ModifyEntryPath,public
  2145. //
  2146. // Synopsis: This method modifies the entry path on this volume object
  2147. // and at the same time modifies the entry paths on all the
  2148. // services by issuing FSCTRLs. It then turns around and calls
  2149. // the same API on all the children since their entrypaths are
  2150. // also affected by this change.
  2151. //
  2152. // Arguments: [oldPrefix] -- The old Prefix on the Parent volume object.
  2153. // [newPrefix] -- The new Prefix on the Parent volume object.
  2154. //
  2155. // Returns: ERROR_SUCCESS -- If all went well.
  2156. //
  2157. // Notes: This method does not bother to check for the validity of
  2158. // the new entryPath etc. THat should have happened way before
  2159. // we got here.
  2160. //
  2161. // History: 31 April 1993 SudK Created.
  2162. //
  2163. //----------------------------------------------------------------------
  2164. DWORD
  2165. CDfsVolume::ModifyEntryPath(
  2166. LPWSTR oldPrefix,
  2167. LPWSTR newPrefix)
  2168. {
  2169. DWORD dwErr = ERROR_SUCCESS;
  2170. CDfsService *pService;
  2171. PWCHAR ErrorStrs[2];
  2172. PWCHAR childNewPrefix;
  2173. CEnumDirectory *pdir;
  2174. DFSMSTATDIR rgelt;
  2175. ULONG fetched = 0;
  2176. CDfsVolume *child = NULL;
  2177. PWCHAR newEntryPath;
  2178. SYSTEMTIME st;
  2179. FILETIME ftEntryPath;
  2180. IDfsVolInlineDebOut((DEB_TRACE, "ModifyEntryPath(%s,%s)\n", oldPrefix, newPrefix));
  2181. //
  2182. // First, see if we need to modify anything at all. If the oldPrefix
  2183. // is *not* a prefix of our name, then our name is *not* changing, and
  2184. // we just return.
  2185. //
  2186. if (_wcsnicmp(_peid.Prefix.Buffer, oldPrefix, wcslen(oldPrefix)) != 0) {
  2187. IDfsVolInlineDebOut((DEB_TRACE, "ModifyEntryPath() exit\n"));
  2188. return( ERROR_SUCCESS );
  2189. }
  2190. //
  2191. // Next, compute the new entry path
  2192. //
  2193. ComputeNewEntryPath( oldPrefix, newPrefix, _peid.Prefix.Buffer, &newEntryPath );
  2194. if (newEntryPath == NULL) {
  2195. return( ERROR_OUTOFMEMORY );
  2196. }
  2197. //
  2198. // Let us first modify the prefix locally on the object. We trust the
  2199. // arguments since they could have been passed by our own code. So we
  2200. // will not bother with a TRY/CATCH etc. out here.
  2201. //
  2202. GetSystemTime( &st );
  2203. SystemTimeToFileTime( &st, &ftEntryPath );
  2204. dwErr = ModifyLocalEntryPath( newEntryPath, ftEntryPath, TRUE );
  2205. if (dwErr != ERROR_SUCCESS) {
  2206. delete [] newEntryPath;
  2207. return(dwErr);
  2208. }
  2209. //
  2210. // Now that the prefix has been modified locally we need to update all the
  2211. // services.
  2212. //
  2213. pService = _DfsSvcList.GetFirstService();
  2214. while (pService != NULL) {
  2215. dwErr = pService->ModifyPrefix(&_peid);
  2216. //
  2217. // If we fail to modify the prefix we really dont want to stop. We go
  2218. // on and update the other services and volumes.
  2219. //
  2220. if (dwErr != ERROR_SUCCESS) {
  2221. ErrorStrs[0] = _peid.Prefix.Buffer;
  2222. ErrorStrs[1] = pService->GetServiceName();
  2223. LogMessage(DEB_ERROR,
  2224. ErrorStrs,
  2225. 2,
  2226. DFS_MODIFY_PREFIX_FAILED_MSG);
  2227. }
  2228. dwErr = ERROR_SUCCESS;
  2229. pService = _DfsSvcList.GetNextService(pService);
  2230. }
  2231. //
  2232. // Now we have updated all the services of this volume. Let us now get to
  2233. // all our children and call this method on them again.
  2234. //
  2235. dwErr = _pStorage->GetEnumDirectory(&pdir);
  2236. if (dwErr != ERROR_SUCCESS) {
  2237. delete [] newEntryPath;
  2238. return(dwErr);
  2239. }
  2240. //
  2241. // While there are children still to be handled we continue on.
  2242. //
  2243. rgelt.pwcsName = NULL;
  2244. while (TRUE) {
  2245. if (rgelt.pwcsName != NULL) {
  2246. delete [] rgelt.pwcsName;
  2247. rgelt.pwcsName = NULL;
  2248. }
  2249. dwErr = pdir->Next(&rgelt, &fetched);
  2250. if (dwErr != ERROR_SUCCESS) {
  2251. IDfsVolInlineDebOut((DEB_ERROR, "Failed to Enumeraate\n", 0));
  2252. break;
  2253. }
  2254. //
  2255. // If we did not get back any children we are done.
  2256. //
  2257. if (fetched == 0)
  2258. break;
  2259. //
  2260. // If the child name is . or .. we ignore it
  2261. //
  2262. if ((!wcscmp(rgelt.pwcsName, L".")) ||
  2263. (!wcscmp(rgelt.pwcsName, L"..")))
  2264. continue;
  2265. dwErr = GetDfsVolumeFromStg(&rgelt, &child);
  2266. if (dwErr != ERROR_SUCCESS) {
  2267. //
  2268. // Log an EVENT here saying that volume object is corrupt and
  2269. // continue on. We dont want to stop just because we cant handle
  2270. // one particular object.
  2271. //
  2272. LogMessage( DEB_ERROR,
  2273. &(_peid.Prefix.Buffer),
  2274. 1,
  2275. DFS_CANT_GET_TO_CHILD_IDFSVOL_MSG);
  2276. //
  2277. // We dont want to give up as yet. So let us go on to the next
  2278. // object.
  2279. //
  2280. fetched = 0;
  2281. continue;
  2282. }
  2283. dwErr = child->ModifyEntryPath(oldPrefix, newPrefix);
  2284. if (dwErr != ERROR_SUCCESS) {
  2285. //
  2286. // We ignore this error and also dont bother to write out an
  2287. // event since this should have been handled by some lower method.
  2288. // We maybe sitting many levels high up and this error came all
  2289. // the way back up.
  2290. }
  2291. child->Release();
  2292. //
  2293. // Let us now attempt to enumerate the next child.
  2294. //
  2295. fetched = 0;
  2296. } //While TRUE
  2297. if (pdir != NULL)
  2298. pdir->Release();
  2299. delete [] newEntryPath;
  2300. IDfsVolInlineDebOut((DEB_TRACE, "ModifyEntryPath() exit\n"));
  2301. return(dwErr);
  2302. }
  2303. //+-----------------------------------------------------------------------
  2304. //
  2305. // Member: CDfsVolume::GetReplicaSetID, public
  2306. //
  2307. // Synopsis: This method returns the replica set ID (if any) stored with
  2308. // this volume object.
  2309. //
  2310. // Arguments: [pguidRsid] -- This is where the replica set ID is returned.
  2311. //
  2312. // Returns: If there is no replica set ID then caller gets NullGuid.
  2313. //
  2314. // History: 16 Aug 1993 Alanw Created
  2315. // 19 Oct 1993 SudK Implemented
  2316. //
  2317. //------------------------------------------------------------------------
  2318. DWORD
  2319. CDfsVolume::GetReplicaSetID(
  2320. GUID *pguidRsid
  2321. )
  2322. {
  2323. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetReplicaSetID()\n"));
  2324. (*pguidRsid) = _DfsSvcList._ReplicaSetID;
  2325. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetReplicaSetID() exit\n"));
  2326. return(ERROR_SUCCESS);
  2327. }
  2328. //+-----------------------------------------------------------------------
  2329. //
  2330. // Member: CDfsVolume::SetReplicaSetID, public
  2331. //
  2332. // Synopsis: This method sets the replica set ID associated with
  2333. // this volume object.
  2334. //
  2335. // Arguments: [pguidRsid] -- A pointer to the replica set ID.
  2336. //
  2337. // Returns:
  2338. //
  2339. // History: 16 Aug 1993 Alanw Created
  2340. // 19 Oct 1993 SudK Implemented
  2341. //
  2342. //------------------------------------------------------------------------
  2343. DWORD
  2344. CDfsVolume::SetReplicaSetID(
  2345. GUID *pguidRsid
  2346. )
  2347. {
  2348. DWORD dwErr = ERROR_SUCCESS;
  2349. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaSetID()\n"));
  2350. _DfsSvcList._ReplicaSetID = *pguidRsid;
  2351. //
  2352. // I am assuming here that the service List is always setup if someone
  2353. // called this method. For now this is correct.
  2354. //
  2355. dwErr = _DfsSvcList.SetServiceListProperty(FALSE);
  2356. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaSetID() exit\n"));
  2357. return(dwErr);
  2358. }
  2359. //+-----------------------------------------------------------------------
  2360. //
  2361. // Method: CDfsVolume::ChangeStorageID
  2362. //
  2363. // Synopsis: Modify the storage ID on the replica mentioned.
  2364. //
  2365. // Arguments: [pwszMachineName] -- The replica whose state needs to be
  2366. // changed.
  2367. // [pwszStorageId] -- The new storageId on the above replica
  2368. //
  2369. // Returns:
  2370. //
  2371. // History: 7/21/94 SudK Created
  2372. //
  2373. //------------------------------------------------------------------------
  2374. DWORD
  2375. CDfsVolume::ChangeStorageID(
  2376. LPWSTR pwszMachineName,
  2377. LPWSTR pwszNetStorageId
  2378. )
  2379. {
  2380. return(ERROR_SUCCESS);
  2381. }
  2382. //+-----------------------------------------------------------------------
  2383. //
  2384. // Member: CDfsVolume::SetReplicaState, public
  2385. //
  2386. // Synopsis: Change the state of the replica indicated.
  2387. //
  2388. // Arguments: [pwszMachineName] -- The server whose state needs to be
  2389. // changed.
  2390. // [pwszShareName] -- The share on server whose state needs to
  2391. // be changed.
  2392. // [fState] -- The State to set on this.
  2393. //
  2394. // Returns:
  2395. //
  2396. // History: 7/21/94 SudK Created
  2397. //
  2398. //------------------------------------------------------------------------
  2399. DWORD
  2400. CDfsVolume::SetReplicaState(
  2401. LPWSTR pwszMachineName,
  2402. LPWSTR pwszShareName,
  2403. ULONG fState
  2404. )
  2405. {
  2406. DWORD dwErr = ERROR_SUCCESS;
  2407. CDfsService *psvc;
  2408. ULONG svcState;
  2409. PWCHAR pMachineName;
  2410. PWCHAR pShareName;
  2411. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaState(%ws,%ws)\n",
  2412. pwszMachineName, pwszShareName));
  2413. switch (fState) {
  2414. case DFS_STORAGE_STATE_OFFLINE:
  2415. svcState = DFS_SERVICE_TYPE_OFFLINE;
  2416. break;
  2417. case DFS_STORAGE_STATE_ONLINE:
  2418. svcState = 0;
  2419. break;
  2420. default:
  2421. return( ERROR_INVALID_PARAMETER );
  2422. break;
  2423. }
  2424. for (psvc = _DfsSvcList.GetFirstService();
  2425. psvc != NULL;
  2426. psvc = _DfsSvcList.GetNextService(psvc)) {
  2427. pMachineName = psvc->GetServiceName();
  2428. pShareName = psvc->GetShareName();
  2429. if (pMachineName != NULL && _wcsicmp(pwszMachineName, pMachineName) == 0 &&
  2430. pShareName != NULL && _wcsicmp(pwszShareName, pShareName) == 0) {
  2431. dwErr = psvc->SetVolumeState( &_peid, svcState, TRUE );
  2432. if (dwErr == ERROR_SUCCESS) {
  2433. //
  2434. // Store the udpated svclist to the volume object. We don't
  2435. // revert if we fail to save to disk. Instead, we return the
  2436. // error, and let the admin try again if she wishes.
  2437. //
  2438. dwErr = _DfsSvcList.SerializeSvcList();
  2439. if (dwErr == ERROR_SUCCESS) {
  2440. dwErr = _DfsSvcList.SetServiceListProperty( FALSE );
  2441. }
  2442. }
  2443. }
  2444. }
  2445. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetReplicaState() exit\n"));
  2446. return(dwErr);
  2447. }
  2448. //+-----------------------------------------------------------------------
  2449. //
  2450. // Member: CDfsVolume::SetVolumeState, public
  2451. //
  2452. // Synopsis: Change the state of the volume indicated.
  2453. //
  2454. // Arguments: [fState] -- The State to set on this.
  2455. //
  2456. // Returns:
  2457. //
  2458. // History: 7/21/94 SudK Created
  2459. //
  2460. //------------------------------------------------------------------------
  2461. DWORD
  2462. CDfsVolume::SetVolumeState(
  2463. ULONG fState
  2464. )
  2465. {
  2466. DWORD dwErr;
  2467. NTSTATUS status;
  2468. CDfsService *psvc;
  2469. ULONG svcState, volState;
  2470. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeState(0x%x)\n", fState));
  2471. switch (fState) {
  2472. case DFS_VOLUME_STATE_OFFLINE:
  2473. svcState = DFS_SERVICE_TYPE_OFFLINE;
  2474. volState = PKT_ENTRY_TYPE_OFFLINE;
  2475. break;
  2476. case DFS_VOLUME_STATE_ONLINE:
  2477. svcState = 0;
  2478. volState = 0;
  2479. break;
  2480. default:
  2481. return( ERROR_INVALID_PARAMETER );
  2482. break;
  2483. }
  2484. status = DfsDCSetVolumeState( &_peid, volState );
  2485. if (NT_SUCCESS(status)) {
  2486. SYSTEMTIME st;
  2487. _State = fState;
  2488. GetSystemTime( &st );
  2489. SystemTimeToFileTime( &st, &_ftState );
  2490. dwErr = SetIdProps(_EntryType,
  2491. _State,
  2492. _peid.Prefix.Buffer,
  2493. _peid.ShortPrefix.Buffer,
  2494. _peid.Uid,
  2495. _pwszComment,
  2496. _Timeout,
  2497. _ftEntryPath,
  2498. _ftState,
  2499. _ftComment,
  2500. FALSE);
  2501. } else {
  2502. dwErr = RtlNtStatusToDosError(status);
  2503. }
  2504. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeState()\n"));
  2505. return(dwErr);
  2506. }
  2507. //+-----------------------------------------------------------------------
  2508. //
  2509. // Member: CDfsVolume::SetVolumeTimeout, public
  2510. //
  2511. // Synopsis: Change the timeout of the volume
  2512. //
  2513. // Arguments: [Timeout] -- The new timeout to set on this.
  2514. //
  2515. // Returns:
  2516. //
  2517. //------------------------------------------------------------------------
  2518. DWORD
  2519. CDfsVolume::SetVolumeTimeout(
  2520. ULONG Timeout
  2521. )
  2522. {
  2523. DWORD dwErr = 0;
  2524. NTSTATUS status;
  2525. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeTimeout(0x%x)\n", Timeout));
  2526. status = DfsSetVolumeTimeout( &_peid, Timeout );
  2527. if (NT_SUCCESS(status)) {
  2528. _Timeout = Timeout;
  2529. dwErr = SetIdProps(_EntryType,
  2530. _State,
  2531. _peid.Prefix.Buffer,
  2532. _peid.ShortPrefix.Buffer,
  2533. _peid.Uid,
  2534. _pwszComment,
  2535. _Timeout,
  2536. _ftEntryPath,
  2537. _ftState,
  2538. _ftComment,
  2539. FALSE);
  2540. } else {
  2541. dwErr = RtlNtStatusToDosError(status);
  2542. }
  2543. IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::SetVolumeTimeout()\n"));
  2544. return(dwErr);
  2545. }
  2546. //+-------------------------------------------------------------------------
  2547. //
  2548. // Function: CDfsVolume::GetObjectID
  2549. //
  2550. // Synopsis: Return the volume object guid
  2551. //
  2552. //--------------------------------------------------------------------------
  2553. DWORD
  2554. CDfsVolume::GetObjectID(LPGUID guidVolume)
  2555. {
  2556. *guidVolume = _peid.Uid;
  2557. return(ERROR_SUCCESS);
  2558. }
  2559. //+---------------------------------------------------------------------
  2560. //
  2561. // Function: ComputeNewEntryPath, private
  2562. //
  2563. // Synopsis: This function is a helper function for the following functions
  2564. // to be able to compute the entry paths for a child volume given
  2565. // the change in their entrypath's and the child's current path.
  2566. //
  2567. // Arguments: [oldPath] -- OldPath of currentVolume. Prefix
  2568. // [newPath] -- NewPath of currentVOlume. Prefix
  2569. // [childPath] -- CurrentPath of child. Prefix
  2570. // [childNewPath] -- NewPath of child. Prefix
  2571. //
  2572. // Returns: NOTHING.
  2573. //
  2574. // History: 05-01-93 SudK Created.
  2575. //
  2576. //----------------------------------------------------------------------
  2577. VOID
  2578. ComputeNewEntryPath(
  2579. PWCHAR oldPath,
  2580. PWCHAR newPath,
  2581. PWCHAR childPath,
  2582. PWCHAR *childNewPath
  2583. )
  2584. {
  2585. ULONG newLen, oldLen;
  2586. PWCHAR childComponent;
  2587. oldLen = wcslen(oldPath);
  2588. newLen = wcslen(newPath);
  2589. newLen += wcslen(childPath) - oldLen;
  2590. *childNewPath = new WCHAR[newLen + sizeof(WCHAR)];
  2591. if (*childNewPath != NULL) {
  2592. wcscpy(*childNewPath, newPath);
  2593. childComponent = childPath + oldLen;
  2594. wcscat(*childNewPath, childComponent);
  2595. }
  2596. return;
  2597. }
  2598. //+----------------------------------------------------------------------------
  2599. //
  2600. // Function: MoveFileOrJP, private
  2601. //
  2602. // Synopsis: Similar to Win32 MoveFile, except if the named src is a JP,
  2603. // then the JP will get renamed.
  2604. //
  2605. // Arguments: [pwszSrcName] -- Name of the Src object.
  2606. // [pwszTgtName] -- New name of the object.
  2607. //
  2608. // Returns: [STATUS_SUCCESS] -- Rename succeeded.
  2609. //
  2610. //-----------------------------------------------------------------------------
  2611. NTSTATUS
  2612. MoveFileOrJP(
  2613. IN PCWSTR pwszSrcName,
  2614. IN PCWSTR pwszTgtName)
  2615. {
  2616. UNICODE_STRING ustrSrc = {0}, ustrTgt = {0};
  2617. NTSTATUS Status = STATUS_SUCCESS;
  2618. if (!RtlDosPathNameToNtPathName_U( pwszSrcName, &ustrSrc, NULL, NULL)) {
  2619. Status = STATUS_INSUFFICIENT_RESOURCES;
  2620. DFSM_TRACE_HIGH(ERROR, MoveFileOrJP_Error1, LOGSTATUS(Status));
  2621. } else if (!RtlDosPathNameToNtPathName_U(
  2622. pwszTgtName, &ustrTgt, NULL, NULL)) {
  2623. Status = STATUS_INSUFFICIENT_RESOURCES;
  2624. DFSM_TRACE_HIGH(ERROR, MoveFileOrJP_Error2, LOGSTATUS(Status));
  2625. }
  2626. if (NT_SUCCESS(Status)) {
  2627. OBJECT_ATTRIBUTES oaSrc;
  2628. HANDLE hSrc;
  2629. IO_STATUS_BLOCK iosb;
  2630. InitializeObjectAttributes(
  2631. &oaSrc,
  2632. &ustrSrc,
  2633. OBJ_CASE_INSENSITIVE,
  2634. NULL,
  2635. NULL);
  2636. Status = NtCreateFile(
  2637. &hSrc,
  2638. FILE_WRITE_ATTRIBUTES |
  2639. FILE_READ_ATTRIBUTES |
  2640. DELETE |
  2641. SYNCHRONIZE,
  2642. &oaSrc,
  2643. &iosb,
  2644. NULL,
  2645. FILE_ATTRIBUTE_NORMAL,
  2646. FILE_SHARE_READ,
  2647. FILE_OPEN,
  2648. FILE_DIRECTORY_FILE |
  2649. FILE_SYNCHRONOUS_IO_NONALERT,
  2650. pOpenIfJPEa,
  2651. cbOpenIfJPEa);
  2652. DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, MoveFileOrJP_Error_NtCreateFile, LOGSTATUS(Status));
  2653. if (Status == STATUS_DFS_EXIT_PATH_FOUND) {
  2654. Status = NtCreateFile(
  2655. &hSrc,
  2656. FILE_READ_ATTRIBUTES |
  2657. FILE_WRITE_ATTRIBUTES |
  2658. DELETE |
  2659. SYNCHRONIZE,
  2660. &oaSrc,
  2661. &iosb,
  2662. NULL,
  2663. FILE_ATTRIBUTE_NORMAL,
  2664. FILE_SHARE_READ,
  2665. FILE_OPEN,
  2666. FILE_SYNCHRONOUS_IO_NONALERT,
  2667. pOpenIfJPEa,
  2668. cbOpenIfJPEa);
  2669. DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, MoveFileOrJP_Error_NtCreateFile2, LOGSTATUS(Status));
  2670. }
  2671. if (NT_SUCCESS(Status)) {
  2672. Status = iosb.Status;
  2673. }
  2674. if (NT_SUCCESS(Status)) {
  2675. PFILE_RENAME_INFORMATION pRenameInfo;
  2676. ULONG cbRenameInfo;
  2677. cbRenameInfo = sizeof(FILE_RENAME_INFORMATION) + ustrTgt.Length;
  2678. pRenameInfo = (PFILE_RENAME_INFORMATION) new BYTE [cbRenameInfo];
  2679. if (pRenameInfo != NULL) {
  2680. pRenameInfo->ReplaceIfExists = FALSE;
  2681. pRenameInfo->RootDirectory = NULL;
  2682. pRenameInfo->FileNameLength = ustrTgt.Length;
  2683. CopyMemory(
  2684. &pRenameInfo->FileName[0],
  2685. ustrTgt.Buffer,
  2686. ustrTgt.Length);
  2687. Status = NtSetInformationFile(
  2688. hSrc,
  2689. &iosb,
  2690. pRenameInfo,
  2691. cbRenameInfo,
  2692. FileRenameInformation);
  2693. DFSM_TRACE_ERROR_HIGH(Status, ALL_ERROR, MoveFileOrJP_Error_NtSetInformationFile, LOGSTATUS(Status));
  2694. delete [] pRenameInfo;
  2695. if (NT_SUCCESS(Status)) {
  2696. Status = iosb.Status;
  2697. }
  2698. } else {
  2699. Status = STATUS_INSUFFICIENT_RESOURCES;
  2700. DFSM_TRACE_HIGH(ERROR, MoveFileOrJP_Error3, LOGSTATUS(Status));
  2701. }
  2702. NtClose( hSrc );
  2703. } // end if successfully opened src
  2704. } // end if successfull converted dos names to nt names.
  2705. if (ustrSrc.Buffer != NULL) {
  2706. RtlFreeUnicodeString( &ustrSrc );
  2707. }
  2708. if (ustrTgt.Buffer != NULL) {
  2709. RtlFreeUnicodeString( &ustrTgt );
  2710. }
  2711. return( Status );
  2712. }