Leaked source code of windows server 2003
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.

2884 lines
89 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsStore.cxx
  6. //
  7. // Contents: the base DFS Store class, this contains the common
  8. // store functionality.
  9. //
  10. // Classes: DfsStore.
  11. //
  12. // History: Dec. 8 2000, Author: udayh
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include "DfsStore.hxx"
  16. #include "DfsServerLibrary.hxx"
  17. #include <dfsmisc.h>
  18. //
  19. // logging stuff
  20. //
  21. #include "dfsstore.tmh"
  22. extern "C" {
  23. DWORD
  24. I_NetDfsIsThisADomainName(
  25. IN LPWSTR wszName);
  26. }
  27. // Initialize the common marshalling info for Registry and ADLegacy stores.
  28. //
  29. INIT_FILE_TIME_INFO();
  30. INIT_DFS_REPLICA_INFO_MARSHAL_INFO();
  31. //+-------------------------------------------------------------------------
  32. //
  33. // Function: PackGetInfo - unpacks information based on MARSHAL_INFO struct
  34. //
  35. // Arguments: pInfo - pointer to the info to fill.
  36. // ppBuffer - pointer to buffer that holds the binary stream.
  37. // pSizeRemaining - pointer to size of above buffer
  38. // pMarshalInfo - pointer to information that describes how to
  39. // interpret the binary stream.
  40. //
  41. // Returns: Status
  42. // ERROR_SUCCESS if we could unpack the name info
  43. // error status otherwise.
  44. //
  45. //
  46. // Description: This routine expects the binary stream to hold all the
  47. // information that is necessary to return the information
  48. // described by the MARSHAL_INFO structure.
  49. //--------------------------------------------------------------------------
  50. DFSSTATUS
  51. DfsStore::PackGetInformation(
  52. ULONG_PTR Info,
  53. PVOID *ppBuffer,
  54. PULONG pSizeRemaining,
  55. PMARSHAL_INFO pMarshalInfo )
  56. {
  57. PMARSHAL_TYPE_INFO typeInfo;
  58. DFSSTATUS Status = ERROR_INVALID_DATA;
  59. for ( typeInfo = &pMarshalInfo->_typeInfo[0];
  60. typeInfo < &pMarshalInfo->_typeInfo[pMarshalInfo->_typecnt];
  61. typeInfo++ )
  62. {
  63. switch ( typeInfo->_type & MTYPE_BASE_TYPE )
  64. {
  65. case MTYPE_COMPOUND:
  66. Status = PackGetInformation(Info + typeInfo->_off,
  67. ppBuffer,
  68. pSizeRemaining,
  69. typeInfo->_subinfo);
  70. break;
  71. case MTYPE_ULONG:
  72. Status = PackGetULong( (PULONG)(Info + typeInfo->_off),
  73. ppBuffer,
  74. pSizeRemaining );
  75. break;
  76. case MTYPE_PWSTR:
  77. Status = PackGetString( (PUNICODE_STRING)(Info + typeInfo->_off),
  78. ppBuffer,
  79. pSizeRemaining );
  80. break;
  81. case MTYPE_GUID:
  82. Status = PackGetGuid( (GUID *)(Info + typeInfo->_off),
  83. ppBuffer,
  84. pSizeRemaining );
  85. break;
  86. default:
  87. break;
  88. }
  89. }
  90. return Status;
  91. }
  92. //+-------------------------------------------------------------------------
  93. //
  94. // Function: PackSetInformation - packs information based on MARSHAL_INFO struct
  95. //
  96. // Arguments: pInfo - pointer to the info buffer to pack
  97. // ppBuffer - pointer to buffer that holds the binary stream.
  98. // pSizeRemaining - pointer to size of above buffer
  99. // pMarshalInfo - pointer to information that describes how to
  100. // pack the info into the binary stream.
  101. //
  102. // Returns: Status
  103. // ERROR_SUCCESS if we could pack the info
  104. // error status otherwise.
  105. //
  106. //
  107. // Description: This routine expects the binary stream can hold all the
  108. // information that is necessary to pack the information
  109. // described by the MARSHAL_INFO structure.
  110. //--------------------------------------------------------------------------
  111. DFSSTATUS
  112. DfsStore::PackSetInformation(
  113. ULONG_PTR Info,
  114. PVOID *ppBuffer,
  115. PULONG pSizeRemaining,
  116. PMARSHAL_INFO pMarshalInfo )
  117. {
  118. PMARSHAL_TYPE_INFO typeInfo;
  119. DFSSTATUS Status = ERROR_INVALID_DATA;
  120. for ( typeInfo = &pMarshalInfo->_typeInfo[0];
  121. typeInfo < &pMarshalInfo->_typeInfo[pMarshalInfo->_typecnt];
  122. typeInfo++ )
  123. {
  124. switch ( typeInfo->_type & MTYPE_BASE_TYPE )
  125. {
  126. case MTYPE_COMPOUND:
  127. Status = PackSetInformation( Info + typeInfo->_off,
  128. ppBuffer,
  129. pSizeRemaining,
  130. typeInfo->_subinfo);
  131. break;
  132. case MTYPE_ULONG:
  133. Status = PackSetULong( *(PULONG)(Info + typeInfo->_off),
  134. ppBuffer,
  135. pSizeRemaining );
  136. break;
  137. case MTYPE_PWSTR:
  138. Status = PackSetString( (PUNICODE_STRING)(Info + typeInfo->_off),
  139. ppBuffer,
  140. pSizeRemaining );
  141. break;
  142. case MTYPE_GUID:
  143. Status = PackSetGuid( (GUID *)(Info + typeInfo->_off),
  144. ppBuffer,
  145. pSizeRemaining );
  146. break;
  147. default:
  148. break;
  149. }
  150. }
  151. return Status;
  152. }
  153. //+-------------------------------------------------------------------------
  154. //
  155. // Function: PackSizeInformation - packs information based on MARSHAL_INFO struct
  156. //
  157. // Arguments: pInfo - pointer to the info buffer to pack
  158. // ppBuffer - pointer to buffer that holds the binary stream.
  159. // pSizeRemaining - pointer to size of above buffer
  160. // pMarshalInfo - pointer to information that describes how to
  161. // pack the info into the binary stream.
  162. //
  163. // Returns: Status
  164. // ERROR_SUCCESS if we could pack the info
  165. // error status otherwise.
  166. //
  167. //
  168. // Description: This routine expects the binary stream can hold all the
  169. // information that is necessary to pack the information
  170. // described by the MARSHAL_INFO structure.
  171. //--------------------------------------------------------------------------
  172. ULONG
  173. DfsStore::PackSizeInformation(
  174. ULONG_PTR Info,
  175. PMARSHAL_INFO pMarshalInfo )
  176. {
  177. PMARSHAL_TYPE_INFO typeInfo;
  178. ULONG Size = 0;
  179. for ( typeInfo = &pMarshalInfo->_typeInfo[0];
  180. typeInfo < &pMarshalInfo->_typeInfo[pMarshalInfo->_typecnt];
  181. typeInfo++ )
  182. {
  183. switch ( typeInfo->_type & MTYPE_BASE_TYPE )
  184. {
  185. case MTYPE_COMPOUND:
  186. Size += PackSizeInformation( Info + typeInfo->_off,
  187. typeInfo->_subinfo);
  188. break;
  189. case MTYPE_ULONG:
  190. Size += PackSizeULong();
  191. break;
  192. case MTYPE_PWSTR:
  193. Size += PackSizeString( (PUNICODE_STRING)(Info + typeInfo->_off) );
  194. break;
  195. case MTYPE_GUID:
  196. Size += PackSizeGuid();
  197. break;
  198. default:
  199. break;
  200. }
  201. }
  202. return Size;
  203. }
  204. //+-------------------------------------------------------------------------
  205. //
  206. // Function: PackGetReplicaInformation - Unpacks the replica info
  207. //
  208. // Arguments: pDfsReplicaInfo - pointer to the info to fill.
  209. // ppBuffer - pointer to buffer that holds the binary stream.
  210. // pSizeRemaining - pointer to size of above buffer
  211. //
  212. // Returns: Status
  213. // ERROR_SUCCESS if we could unpack the name info
  214. // error status otherwise.
  215. //
  216. //
  217. // Description: This routine expects the binary stream to hold all the
  218. // information that is necessary to return a complete replica
  219. // info structure (as defined by MiDfsReplicaInfo). If the stream
  220. // does not have the sufficient info, ERROR_INVALID_DATA is
  221. // returned back.
  222. // This routine expects to find "replicaCount" number of individual
  223. // binary streams in passed in buffer. Each stream starts with
  224. // the size of the stream, followed by that size of data.
  225. //
  226. //--------------------------------------------------------------------------
  227. DFSSTATUS
  228. DfsStore::PackGetReplicaInformation(
  229. PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo,
  230. PVOID *ppBuffer,
  231. PULONG pSizeRemaining)
  232. {
  233. ULONG Count;
  234. ULONG ReplicaSizeRemaining;
  235. PVOID nextStream;
  236. DFSSTATUS Status = ERROR_SUCCESS;
  237. for ( Count = 0; Count < pReplicaListInfo->ReplicaCount; Count++ )
  238. {
  239. PDFS_REPLICA_INFORMATION pReplicaInfo;
  240. pReplicaInfo = &pReplicaListInfo->pReplicas[Count];
  241. //
  242. // We now have a binary stream in ppBuffer, the first word of which
  243. // indicates the size of this stream.
  244. //
  245. Status = PackGetULong( &pReplicaInfo->DataSize,
  246. ppBuffer,
  247. pSizeRemaining );
  248. //
  249. // ppBuffer is now pointing past the size (to the binary stream)
  250. // because UnpackUlong added size of ulong to it.
  251. // Unravel that stream into the next array element.
  252. // Note that when this unpack returns, the ppBuffer is not necessarily
  253. // pointing to the next binary stream within this blob.
  254. //
  255. if(pReplicaInfo->DataSize > *pSizeRemaining)
  256. {
  257. Status = ERROR_INVALID_DATA;
  258. }
  259. if ( Status == ERROR_SUCCESS )
  260. {
  261. nextStream = *ppBuffer;
  262. ReplicaSizeRemaining = pReplicaInfo->DataSize;
  263. Status = PackGetInformation( (ULONG_PTR)pReplicaInfo,
  264. ppBuffer,
  265. &ReplicaSizeRemaining,
  266. &MiDfsReplicaInfo );
  267. if(Status == ERROR_SUCCESS)
  268. {
  269. //
  270. // We now point the buffer to the next sub-stream, which is the previous
  271. // stream + the size of the stream. We also set the remaining size
  272. // appropriately.
  273. //
  274. *ppBuffer = (PVOID)((ULONG_PTR)nextStream + pReplicaInfo->DataSize);
  275. *pSizeRemaining -= pReplicaInfo->DataSize;
  276. }
  277. }
  278. if ( Status != ERROR_SUCCESS )
  279. {
  280. break;
  281. }
  282. }
  283. return Status;
  284. }
  285. //+-------------------------------------------------------------------------
  286. //
  287. // Function: PackSetReplicaInformation - packs the replica info
  288. //
  289. // Arguments: pDfsReplicaInfo - pointer to the info to pack
  290. // ppBuffer - pointer to buffer that holds the binary stream.
  291. // pSizeRemaining - pointer to size of above buffer
  292. //
  293. // Returns: Status
  294. // ERROR_SUCCESS if we could pack the replica info
  295. // error status otherwise.
  296. //
  297. //
  298. // Description: This routine expects the binary stream to be able to
  299. // hold the information that will be copied from the
  300. // info structure (as defined by MiDfsReplicaInfo). If the stream
  301. // does not have the sufficient info, ERROR_INVALID_DATA is
  302. // returned back.
  303. // This routine stores a "replicaCount" number of individual
  304. // binary streams as the first ulong, and then it packs each
  305. // stream.
  306. //
  307. //--------------------------------------------------------------------------
  308. DFSSTATUS
  309. DfsStore::PackSetReplicaInformation(
  310. PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo,
  311. PVOID *ppBuffer,
  312. PULONG pSizeRemaining)
  313. {
  314. ULONG Count;
  315. ULONG ReplicaSizeRemaining;
  316. PVOID nextStream;
  317. DFSSTATUS Status = ERROR_SUCCESS;
  318. for ( Count = 0; Count < pReplicaListInfo->ReplicaCount; Count++ )
  319. {
  320. PDFS_REPLICA_INFORMATION pReplicaInfo;
  321. pReplicaInfo = &pReplicaListInfo->pReplicas[Count];
  322. //
  323. // We now have a binary stream in ppBuffer, the first word of which
  324. // indicates the size of this stream.
  325. //
  326. Status = PackSetULong( pReplicaInfo->DataSize,
  327. ppBuffer,
  328. pSizeRemaining );
  329. //
  330. // ppBuffer is now pointing past the size (to the binary stream)
  331. // because packUlong added size of ulong to it.
  332. // Unravel that stream into the next array element.
  333. // Note that when this returns, the ppBuffer is not necessarily
  334. // pointing to the next binary stream within this blob.
  335. //
  336. if ( Status == ERROR_SUCCESS )
  337. {
  338. nextStream = *ppBuffer;
  339. ReplicaSizeRemaining = pReplicaInfo->DataSize;
  340. Status = PackSetInformation( (ULONG_PTR)pReplicaInfo,
  341. ppBuffer,
  342. &ReplicaSizeRemaining,
  343. &MiDfsReplicaInfo );
  344. //
  345. // We now point the buffer to the next sub-stream, which is the previos
  346. // stream + the size of the stream. We also set the remaining size
  347. // appropriately.
  348. //
  349. *ppBuffer = (PVOID)((ULONG_PTR)nextStream + pReplicaInfo->DataSize);
  350. *pSizeRemaining -= pReplicaInfo->DataSize;
  351. }
  352. if ( Status != ERROR_SUCCESS )
  353. {
  354. break;
  355. }
  356. }
  357. return Status;
  358. }
  359. //+-------------------------------------------------------------------------
  360. //
  361. // Function: PackSizeReplicaInformation - packs the replica info
  362. //
  363. // Arguments: pDfsReplicaInfo - pointer to the info to pack
  364. // ppBuffer - pointer to buffer that holds the binary stream.
  365. // pSizeRemaining - pointer to size of above buffer
  366. //
  367. // Returns: Status
  368. // ERROR_SUCCESS if we could pack the replica info
  369. // error status otherwise.
  370. //
  371. //
  372. // Description: This routine expects the binary stream to be able to
  373. // hold the information that will be copied from the
  374. // info structure (as defined by MiDfsReplicaInfo). If the stream
  375. // does not have the sufficient info, ERROR_INVALID_DATA is
  376. // returned back.
  377. // This routine stores a "replicaCount" number of individual
  378. // binary streams as the first ulong, and then it packs each
  379. // stream.
  380. //
  381. //--------------------------------------------------------------------------
  382. ULONG
  383. DfsStore::PackSizeReplicaInformation(
  384. PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo )
  385. {
  386. ULONG Count;
  387. ULONG Size = 0;
  388. for ( Count = 0; Count < pReplicaListInfo->ReplicaCount; Count++ )
  389. {
  390. PDFS_REPLICA_INFORMATION pReplicaInfo;
  391. pReplicaInfo = &pReplicaListInfo->pReplicas[Count];
  392. Size += PackSizeULong();
  393. pReplicaInfo->DataSize = PackSizeInformation( (ULONG_PTR)pReplicaInfo,
  394. &MiDfsReplicaInfo );
  395. Size += pReplicaInfo->DataSize;
  396. }
  397. return Size;
  398. }
  399. //+-------------------------------------------------------------------------
  400. //
  401. // Function: LookupRoot - Find a root
  402. //
  403. // Arguments: pContextName - the Dfs Name Context
  404. // pLogicalShare - the Logical Share
  405. // ppRoot - the DfsRootFolder that was found
  406. //
  407. // Returns: Status
  408. // ERROR_SUCCESS if we found a matching root
  409. // error status otherwise.
  410. //
  411. //
  412. // Description: This routine takes a Dfs name context and logical share,
  413. // and returns a Root that matches the passed in name
  414. // context and logical share, if one exists.
  415. // Note that the same DFS NC and logical share may exist
  416. // in more than one store (though very unlikely). In this
  417. // case, the first registered store wins.
  418. // IF found, the reference root folder will be returned.
  419. // It is the callers responsibility to release this referencce
  420. // when the caller is done with this root.
  421. //
  422. //--------------------------------------------------------------------------
  423. DFSSTATUS
  424. DfsStore::LookupRoot(
  425. PUNICODE_STRING pContextName,
  426. PUNICODE_STRING pLogicalShare,
  427. DfsRootFolder **ppRootFolder )
  428. {
  429. DFSSTATUS Status;
  430. DfsRootFolder *pRoot;
  431. UNICODE_STRING DfsNetbiosNameContext;
  432. DFS_TRACE_LOW( REFERRAL_SERVER, "Lookup root %wZ %wZ\n", pContextName, pLogicalShare);
  433. //
  434. // First, convert the context name to a netbios context name.
  435. //
  436. DfsGetNetbiosName( pContextName, &DfsNetbiosNameContext, NULL );
  437. //
  438. // Lock the store, so that we dont have new roots coming in while
  439. // we are taking a look.
  440. //
  441. Status = AcquireReadLock();
  442. if ( Status != ERROR_SUCCESS )
  443. {
  444. return Status;
  445. }
  446. //
  447. // The default return status is ERROR_NOT_FOUND;
  448. //
  449. Status = ERROR_NOT_FOUND;
  450. //
  451. // Run through our list of DFS roots, and see if any of them match
  452. // the passed in name context and logical share.
  453. //
  454. pRoot = _DfsRootList;
  455. if (pRoot != NULL)
  456. {
  457. do
  458. {
  459. DFS_TRACE_LOW( REFERRAL_SERVER, "Lookup root, checking root %wZ \n", pRoot->GetLogicalShare());
  460. //
  461. // If the Root indicates that the name context needs to be
  462. // ignored, just check for logical share name match (aliasing
  463. // support).
  464. // Otherwise, compare the namecontext in the cases where
  465. // the passed in name context is not empty.
  466. //
  467. if ( (pRoot->IsIgnoreNameContext() == TRUE) ||
  468. (DfsNetbiosNameContext.Length != 0 &&
  469. (RtlCompareUnicodeString(&DfsNetbiosNameContext,
  470. pRoot->GetNetbiosNameContext(),
  471. TRUE) == 0 )) )
  472. {
  473. if ( RtlCompareUnicodeString( pLogicalShare,
  474. pRoot->GetLogicalShare(),
  475. TRUE) == 0 )
  476. {
  477. Status = ERROR_SUCCESS;
  478. break;
  479. }
  480. }
  481. pRoot = pRoot->pNextRoot;
  482. } while ( pRoot != _DfsRootList );
  483. }
  484. //
  485. // IF we found a matching root, bump up its reference count, and
  486. // return the pointer to the root.
  487. //
  488. if ( Status == ERROR_SUCCESS )
  489. {
  490. pRoot->AcquireReference();
  491. *ppRootFolder = pRoot;
  492. }
  493. ReleaseLock();
  494. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Done Lookup root for %wZ, root %p status %x\n",
  495. pLogicalShare, pRoot, Status);
  496. return Status;
  497. }
  498. DFSSTATUS
  499. DfsStore::GetRootPhysicalShare(
  500. HKEY RootKey,
  501. PUNICODE_STRING pRootPhysicalShare )
  502. {
  503. DFSSTATUS Status = ERROR_SUCCESS;
  504. Status = DfsGetRegValueString( RootKey,
  505. DfsRootShareValueName,
  506. pRootPhysicalShare );
  507. return Status;
  508. }
  509. VOID
  510. DfsStore::ReleaseRootPhysicalShare(
  511. PUNICODE_STRING pRootPhysicalShare )
  512. {
  513. DfsReleaseRegValueString( pRootPhysicalShare );
  514. }
  515. DFSSTATUS
  516. DfsStore::GetRootLogicalShare(
  517. HKEY RootKey,
  518. PUNICODE_STRING pRootLogicalShare )
  519. {
  520. DFSSTATUS Status;
  521. Status = DfsGetRegValueString( RootKey,
  522. DfsLogicalShareValueName,
  523. pRootLogicalShare );
  524. return Status;
  525. }
  526. VOID
  527. DfsStore::ReleaseRootLogicalShare(
  528. PUNICODE_STRING pRootLogicalShare )
  529. {
  530. DfsReleaseRegValueString( pRootLogicalShare );
  531. }
  532. //+-------------------------------------------------------------------------
  533. //
  534. // Function: StoreRecognizeNewDfs - the recognizer for new style dfs
  535. //
  536. // Arguments: Name - the namespace of interest.
  537. // DfsKey - the key for the DFS registry space.
  538. //
  539. // Returns: Status
  540. // ERROR_SUCCESS on success
  541. // ERROR status code otherwise
  542. //
  543. //
  544. // Description: This routine looks up all the standalone roots
  545. // hosted on this machine, and looks up the metadata for
  546. // the roots and either creates new roots or updates existing
  547. // ones to reflect the current children of the root.
  548. //
  549. //--------------------------------------------------------------------------
  550. DFSSTATUS
  551. DfsStore::StoreRecognizeNewDfs(
  552. LPWSTR MachineName,
  553. HKEY DfsKey )
  554. {
  555. DfsRootFolder *pRootFolder = NULL;
  556. HKEY DfsRootKey = NULL;
  557. DFSSTATUS Status = ERROR_SUCCESS;
  558. ULONG ChildNum = 0;
  559. DWORD CchMaxName = 0;
  560. DWORD CchChildName = 0;
  561. LPWSTR ChildName = NULL;
  562. DFSSTATUS RetStatus = ERROR_SUCCESS;
  563. DFS_TRACE_LOW(REFERRAL_SERVER, "Attempting to recognize new DFS\n");
  564. //
  565. // First find the length of the longest subkey
  566. // and allocate a buffer big enough for it.
  567. //
  568. Status = RegQueryInfoKey( DfsKey, // Key
  569. NULL, // Class string
  570. NULL, // Size of class string
  571. NULL, // Reserved
  572. NULL, // # of subkeys
  573. &CchMaxName, // max size of subkey name in TCHARs
  574. NULL, // max size of class name
  575. NULL, // # of values
  576. NULL, // max size of value name
  577. NULL, // max size of value data,
  578. NULL, // security descriptor
  579. NULL ); // Last write time
  580. if (Status == ERROR_SUCCESS)
  581. {
  582. CchMaxName++; // Space for the NULL terminator.
  583. ChildName = (LPWSTR) new WCHAR [CchMaxName];
  584. if (ChildName == NULL)
  585. {
  586. Status = ERROR_NOT_ENOUGH_MEMORY;
  587. }
  588. }
  589. if (Status == ERROR_SUCCESS)
  590. {
  591. //
  592. // For each child, get the child name.
  593. //
  594. do
  595. {
  596. CchChildName = CchMaxName;
  597. //
  598. // Now enumerate the children, starting from the first child.
  599. //
  600. Status = RegEnumKeyEx( DfsKey,
  601. ChildNum,
  602. ChildName,
  603. &CchChildName,
  604. NULL,
  605. NULL,
  606. NULL,
  607. NULL );
  608. ChildNum++;
  609. if (Status == ERROR_SUCCESS)
  610. {
  611. DFS_TRACE_LOW(REFERRAL_SERVER, "Recognize New Dfs, found root (#%d) with metaname %ws\n", ChildNum, ChildName );
  612. //
  613. // We have the name of a child, so open the key to
  614. // that root.
  615. //
  616. Status = RegOpenKeyEx( DfsKey,
  617. ChildName,
  618. 0,
  619. KEY_READ,
  620. &DfsRootKey );
  621. if (Status == ERROR_SUCCESS)
  622. {
  623. DFSSTATUS RootStatus = ERROR_SUCCESS;
  624. //
  625. // Now get either an existing root by this name,
  626. // or create a new one. The error we get here is
  627. // not the original error generated by AD (or the Registry).
  628. // xxx We should try to propagate that error in future.
  629. //
  630. RootStatus = GetRootFolder( MachineName,
  631. ChildName,
  632. DfsRootKey,
  633. &pRootFolder );
  634. if (RootStatus == ERROR_SUCCESS)
  635. {
  636. //
  637. // Call the synchronize method on the root to
  638. // update it with the latest children.
  639. // Again, ignore the error since we need to move
  640. // on to the next root.
  641. // dfsdev: need eventlog to signal this.
  642. //
  643. RootStatus = pRootFolder->Synchronize();
  644. //
  645. // If the Synchronize above had succeeded, then it would've created
  646. // all the reparse points that the root needs. Now we need to add
  647. // this volume as one that has DFS reparse points so that we know
  648. // to perform garbage collection on this volume later on.
  649. //
  650. (VOID)pRootFolder->AddReparseVolumeToList();
  651. // Release our reference on the root folder.
  652. pRootFolder->ReleaseReference();
  653. }
  654. if (RootStatus != ERROR_SUCCESS)
  655. {
  656. if (!DfsStartupProcessingDone())
  657. {
  658. const TCHAR * apszSubStrings[4];
  659. apszSubStrings[0] = ChildName;
  660. DfsLogDfsEvent( DFS_ERROR_ON_ROOT,
  661. 1,
  662. apszSubStrings,
  663. RootStatus);
  664. }
  665. // Return the bad news.
  666. RetStatus = RootStatus;
  667. }
  668. DFS_TRACE_ERROR_LOW(RootStatus, REFERRAL_SERVER, "Recognize DFS: Root folder for %ws, Synchronize status %x\n",
  669. ChildName, RootStatus );
  670. //
  671. // Close the root key, we are done with it.
  672. //
  673. RegCloseKey( DfsRootKey );
  674. }
  675. }
  676. } while (Status == ERROR_SUCCESS);
  677. delete [] ChildName;
  678. }
  679. //
  680. // If we ran out of children, then return success code.
  681. //
  682. if (Status == ERROR_NO_MORE_ITEMS)
  683. {
  684. Status = ERROR_SUCCESS;
  685. }
  686. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Done with recognize new dfs, Status 0x%x, RetStatus 0x%x\n", Status, RetStatus);
  687. // If any of the roots failed to load, convey that to the caller.
  688. if (Status == ERROR_SUCCESS && RetStatus != ERROR_SUCCESS)
  689. {
  690. Status = RetStatus;
  691. }
  692. return Status;
  693. }
  694. //+-------------------------------------------------------------------------
  695. //
  696. // Function: StoreRecognizeNewDfs - the recognizer for new style dfs
  697. //
  698. // Arguments: Name - the namespace of interest.
  699. // LogicalShare
  700. //
  701. // Returns: Status
  702. // ERROR_SUCCESS on success
  703. // ERROR status code otherwise
  704. //
  705. //
  706. // Description: This routine looks up all the domain roots
  707. // hosted on this machine, and looks up the metadata for
  708. // the roots and either creates new roots or updates existing
  709. // ones to reflect the current children of the root.
  710. //
  711. //--------------------------------------------------------------------------
  712. DFSSTATUS
  713. DfsStore::StoreRecognizeNewDfs (
  714. LPWSTR DfsNameContext,
  715. PUNICODE_STRING pLogicalShare )
  716. {
  717. DfsRootFolder *pRootFolder = NULL;
  718. DFSSTATUS Status = ERROR_SUCCESS;
  719. DFS_TRACE_LOW(REFERRAL_SERVER, "Attempting to recognize new remote DFS\n");
  720. //
  721. // Now get either an existing root by this name,
  722. // or create a new one.
  723. //
  724. Status = GetRootFolder( DfsNameContext,
  725. pLogicalShare,
  726. &pRootFolder );
  727. if (Status == ERROR_SUCCESS)
  728. {
  729. //
  730. // Call the synchronize method on the root to
  731. // update it with the latest children.
  732. //
  733. Status = pRootFolder->Synchronize();
  734. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER,
  735. "Recognize DFS: Root folder for %wZ, Synchronize status %x\n",
  736. pLogicalShare, Status );
  737. // Release our reference on the root folder.
  738. pRootFolder->ReleaseReference();
  739. }
  740. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Done with recognize new remote dfs, Status %x\n", Status);
  741. return Status;
  742. }
  743. //+-------------------------------------------------------------------------
  744. //
  745. // Function: DfsGetRootFolder - Get a root folder if the machine
  746. // hosts a registry based DFS.
  747. //
  748. // Arguments: Name - the namespace of interest.
  749. // Key - the root key
  750. // ppRootFolder - the created folder.
  751. //
  752. // Returns: Status
  753. // ERROR_SUCCESS on success
  754. // ERROR status code otherwise
  755. //
  756. //
  757. // Description: This routine reads in the information
  758. // about the root and creates and adds it to our
  759. // list of known roots, if this one does not already
  760. // exist in our list.
  761. //
  762. //--------------------------------------------------------------------------
  763. DFSSTATUS
  764. DfsStore::GetRootFolder (
  765. LPWSTR DfsNameContextString,
  766. LPWSTR RootRegKeyName,
  767. HKEY DfsRootKey,
  768. DfsRootFolder **ppRootFolder )
  769. {
  770. DFSSTATUS Status = ERROR_SUCCESS;
  771. UNICODE_STRING LogicalShare;
  772. UNICODE_STRING PhysicalShare;
  773. //
  774. // Get the logical name information of this root.
  775. //
  776. Status = GetRootLogicalShare( DfsRootKey,
  777. &LogicalShare );
  778. //
  779. // we successfully got the logical share, now get the physical share
  780. //
  781. if ( Status == ERROR_SUCCESS )
  782. {
  783. Status = GetRootPhysicalShare( DfsRootKey,
  784. &PhysicalShare );
  785. if (Status == ERROR_SUCCESS)
  786. {
  787. Status = GetRootFolder ( DfsNameContextString,
  788. RootRegKeyName,
  789. &LogicalShare,
  790. &PhysicalShare,
  791. ppRootFolder );
  792. ReleaseRootPhysicalShare( &PhysicalShare );
  793. }
  794. ReleaseRootLogicalShare( &LogicalShare );
  795. }
  796. return Status;
  797. }
  798. DFSSTATUS
  799. DfsStore::GetRootFolder (
  800. LPWSTR DfsNameContextString,
  801. LPWSTR RootRegKeyName,
  802. PUNICODE_STRING pLogicalShare,
  803. PUNICODE_STRING pPhysicalShare,
  804. DfsRootFolder **ppRootFolder )
  805. {
  806. DFSSTATUS Status = ERROR_SUCCESS;
  807. UNICODE_STRING DfsNameContext;
  808. DFS_TRACE_LOW(REFERRAL_SERVER, "Get Root Folder for %wZ\n", pLogicalShare);
  809. //
  810. // we have both the logical DFS share name, as well as the local machine
  811. // physical share that is backing the DFS logical share.
  812. // now get a root folder for this dfs root.
  813. //
  814. Status = DfsRtlInitUnicodeStringEx( &DfsNameContext, DfsNameContextString );
  815. if(Status != ERROR_SUCCESS)
  816. {
  817. return Status;
  818. }
  819. //
  820. // Check if we already know about this root. If we do, this
  821. // routine gives us a referenced root folder which we can return.
  822. // If not, we create a brand new root folder.
  823. //
  824. Status = LookupRoot( &DfsNameContext,
  825. pLogicalShare,
  826. ppRootFolder );
  827. if (Status != STATUS_SUCCESS )
  828. {
  829. //
  830. // We check if we can proceed here.
  831. //
  832. DFSSTATUS RootStatus;
  833. RootStatus = DfsCheckServerRootHandlingCapability();
  834. if (RootStatus == ERROR_NOT_SUPPORTED)
  835. {
  836. DfsLogDfsEvent(DFS_ERROR_MUTLIPLE_ROOTS_NOT_SUPPORTED, 0, NULL, RootStatus);
  837. return RootStatus;
  838. }
  839. if (RootStatus != ERROR_SUCCESS)
  840. {
  841. return RootStatus;
  842. }
  843. }
  844. //
  845. // we did not find a root, so create a new one.
  846. //
  847. if ( Status != STATUS_SUCCESS )
  848. {
  849. Status = CreateNewRootFolder( DfsNameContextString,
  850. RootRegKeyName,
  851. pLogicalShare,
  852. pPhysicalShare,
  853. ppRootFolder );
  854. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Created New Dfs Root %p, Share %wZ, Status %x\n",
  855. *ppRootFolder, pPhysicalShare, Status);
  856. }
  857. else
  858. {
  859. //
  860. // There is an existing root with this name.
  861. // Validate that the root we looked up matches the
  862. // metadata we are currently processing. If not, we
  863. // have 2 roots with the same logical share name in the
  864. // registry which is bogus.
  865. //
  866. // Dfs dev: rip out the following code.
  867. // just check for equality of the 2 roots.
  868. // they will not be null strings
  869. //
  870. if (RootRegKeyName != NULL)
  871. {
  872. if (_wcsicmp(RootRegKeyName,
  873. (*ppRootFolder)->GetRootRegKeyNameString()) != 0)
  874. {
  875. (*ppRootFolder)->ReleaseReference();
  876. *ppRootFolder = NULL;
  877. Status = ERROR_DUP_NAME;
  878. }
  879. }
  880. else
  881. {
  882. if (IsEmptyString((*ppRootFolder)->GetRootRegKeyNameString()) == FALSE)
  883. {
  884. (*ppRootFolder)->ReleaseReference();
  885. *ppRootFolder = NULL;
  886. Status = ERROR_DUP_NAME;
  887. }
  888. }
  889. //
  890. // If the above comparison matched, we found a root for the
  891. // logical volume, make sure that the physical share names
  892. // that is exported on the local machine to back the logical share
  893. // matches.
  894. //
  895. if (Status == ERROR_SUCCESS)
  896. {
  897. if (RtlCompareUnicodeString( pPhysicalShare,
  898. (*ppRootFolder)->GetRootPhysicalShareName(),
  899. TRUE ) != 0)
  900. {
  901. //
  902. // dfsdev: use appropriate status code.
  903. //
  904. (*ppRootFolder)->ReleaseReference();
  905. *ppRootFolder = NULL;
  906. Status = ERROR_INVALID_PARAMETER;
  907. }
  908. }
  909. }
  910. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "GetRootFolder: Root %p, Status %x\n",
  911. *ppRootFolder, Status);
  912. return Status;
  913. }
  914. //+-------------------------------------------------------------------------
  915. //
  916. // Function: DfsGetRootFolder - Get a root folder given a remote
  917. // <DfsName,LogicalShare>.
  918. //
  919. //
  920. // Arguments: Name - the namespace of interest.
  921. // LogicalShare
  922. // ppRootFolder - the created folder.
  923. //
  924. // Returns: Status
  925. // ERROR_SUCCESS on success
  926. // ERROR status code otherwise
  927. //
  928. //
  929. // Description: This routine creates and adds a root folder to our
  930. // list of known roots, if this one does not already
  931. // exist in our list. This doesn't care to read any of the information
  932. // about its physical share, etc. The caller (a 'referral server')
  933. // is remote.
  934. //
  935. //--------------------------------------------------------------------------
  936. DFSSTATUS
  937. DfsStore::GetRootFolder (
  938. LPWSTR DfsNameContextString,
  939. PUNICODE_STRING pLogicalShare,
  940. DfsRootFolder **ppRootFolder )
  941. {
  942. DFSSTATUS Status = ERROR_SUCCESS;
  943. UNICODE_STRING DfsNameContext;
  944. UNICODE_STRING DfsShare;
  945. DFS_TRACE_LOW(REFERRAL_SERVER, "Get Root Folder (direct) for %wZ\n", pLogicalShare);
  946. Status = DfsRtlInitUnicodeStringEx( &DfsNameContext, DfsNameContextString );
  947. if(Status != ERROR_SUCCESS)
  948. {
  949. return Status;
  950. }
  951. //
  952. // Check if we already know about this root. If we do, this
  953. // routine gives us a referenced root folder which we can return.
  954. // If not, we create a brand new root folder.
  955. //
  956. Status = DfsCreateUnicodeString( &DfsShare, pLogicalShare);
  957. if (Status != ERROR_SUCCESS) {
  958. return Status;
  959. }
  960. Status = LookupRoot( &DfsNameContext,
  961. pLogicalShare,
  962. ppRootFolder );
  963. //
  964. // we did not find a root, so create a new one.
  965. //
  966. if ( Status != STATUS_SUCCESS )
  967. {
  968. Status = CreateNewRootFolder( DfsNameContextString,
  969. DfsShare.Buffer,
  970. pLogicalShare,
  971. pLogicalShare,
  972. ppRootFolder );
  973. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Created New Dfs Root %p, Share %wZ, Status %x\n",
  974. *ppRootFolder, pLogicalShare, Status);
  975. }
  976. else
  977. {
  978. //
  979. // There's precious little to check at this point to weed out duplicates.
  980. // We don't know what the physical share should be because we didn't
  981. // read that information from the (remote) registry.
  982. //
  983. NOTHING;
  984. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "LookupRoot succeeded on folder %p, Share %wZ, Status %x\n",
  985. *ppRootFolder, pLogicalShare, Status);
  986. }
  987. DfsFreeUnicodeString( &DfsShare);
  988. return Status;
  989. }
  990. DFSSTATUS
  991. DfsStore::PackageEnumerationInfo(
  992. DWORD Level,
  993. DWORD EntryCount,
  994. LPBYTE pLinkBuffer,
  995. LPBYTE pBuffer,
  996. LPBYTE *ppCurrentBuffer,
  997. PLONG pSizeRemaining )
  998. {
  999. PDFS_API_INFO pInfo = NULL;
  1000. PDFS_API_INFO pCurrent = (PDFS_API_INFO)pLinkBuffer;
  1001. LONG HeaderSize = 0;
  1002. ULONG_PTR NextFreeMemory = NULL;
  1003. PDFS_STORAGE_INFO pNewStorage = NULL;
  1004. PDFS_STORAGE_INFO pOldStorage = NULL;
  1005. LONG TotalStores = 0;
  1006. LONG i = 0;
  1007. DFSSTATUS Status = ERROR_SUCCESS;
  1008. LONG NeedLen = 0;
  1009. Status = DfsApiSizeLevelHeader( Level, &HeaderSize );
  1010. if (Status != ERROR_SUCCESS)
  1011. {
  1012. return Status;
  1013. }
  1014. NextFreeMemory = (ULONG_PTR)*ppCurrentBuffer;
  1015. pInfo = (PDFS_API_INFO)((ULONG_PTR)pBuffer + HeaderSize * EntryCount);
  1016. RtlCopyMemory( pInfo, pLinkBuffer, HeaderSize );
  1017. pNewStorage = NULL;
  1018. switch (Level)
  1019. {
  1020. case 4:
  1021. if (pNewStorage == NULL)
  1022. {
  1023. pNewStorage = pInfo->Info4.Storage = (PDFS_STORAGE_INFO)NextFreeMemory;
  1024. pOldStorage = pCurrent->Info4.Storage;
  1025. TotalStores = pInfo->Info4.NumberOfStorages;
  1026. }
  1027. case 3:
  1028. if (pNewStorage == NULL)
  1029. {
  1030. pNewStorage = pInfo->Info3.Storage = (PDFS_STORAGE_INFO)NextFreeMemory;
  1031. pOldStorage = pCurrent->Info3.Storage;
  1032. TotalStores = pInfo->Info3.NumberOfStorages;
  1033. }
  1034. NeedLen = sizeof(DFS_STORAGE_INFO) * TotalStores;
  1035. if (*pSizeRemaining >= NeedLen) {
  1036. *pSizeRemaining -= NeedLen;
  1037. NextFreeMemory += NeedLen;
  1038. }
  1039. else{
  1040. return ERROR_BUFFER_OVERFLOW;
  1041. }
  1042. for (i = 0; i < TotalStores; i++)
  1043. {
  1044. pNewStorage[i] = pOldStorage[i];
  1045. pNewStorage[i].ServerName = (LPWSTR)NextFreeMemory;
  1046. NeedLen = (wcslen(pOldStorage[i].ServerName) + 1) * sizeof(WCHAR);
  1047. if (*pSizeRemaining >= NeedLen)
  1048. {
  1049. *pSizeRemaining -= NeedLen;
  1050. wcscpy(pNewStorage[i].ServerName,
  1051. pOldStorage[i].ServerName);
  1052. NextFreeMemory += NeedLen;
  1053. }
  1054. else {
  1055. return ERROR_BUFFER_OVERFLOW;
  1056. }
  1057. pNewStorage[i].ShareName = (LPWSTR)NextFreeMemory;
  1058. NeedLen = (wcslen(pOldStorage[i].ShareName) + 1) * sizeof(WCHAR);
  1059. if (*pSizeRemaining >= NeedLen)
  1060. {
  1061. *pSizeRemaining -= NeedLen;
  1062. wcscpy(pNewStorage[i].ShareName, pOldStorage[i].ShareName);
  1063. NextFreeMemory += NeedLen;
  1064. }
  1065. else {
  1066. return ERROR_BUFFER_OVERFLOW;
  1067. }
  1068. }
  1069. case 2:
  1070. pInfo->Info2.Comment = (LPWSTR)NextFreeMemory;
  1071. NeedLen = (wcslen(pCurrent->Info2.Comment) + 1) * sizeof(WCHAR);
  1072. if (*pSizeRemaining >= NeedLen)
  1073. {
  1074. *pSizeRemaining -= NeedLen;
  1075. wcscpy(pInfo->Info2.Comment, pCurrent->Info2.Comment);
  1076. NextFreeMemory += NeedLen;
  1077. }
  1078. else {
  1079. return ERROR_BUFFER_OVERFLOW;
  1080. }
  1081. case 1:
  1082. pInfo->Info1.EntryPath = (LPWSTR)NextFreeMemory;
  1083. NeedLen = (wcslen(pCurrent->Info1.EntryPath) + 1) * sizeof(WCHAR);
  1084. if (*pSizeRemaining >= NeedLen)
  1085. {
  1086. *pSizeRemaining -= NeedLen;
  1087. wcscpy(pInfo->Info1.EntryPath, pCurrent->Info1.EntryPath);
  1088. NextFreeMemory += NeedLen;
  1089. }
  1090. else {
  1091. return ERROR_BUFFER_OVERFLOW;
  1092. }
  1093. *ppCurrentBuffer = (LPBYTE)NextFreeMemory;
  1094. break;
  1095. default:
  1096. Status = ERROR_INVALID_PARAMETER;
  1097. }
  1098. return Status;
  1099. }
  1100. DFSSTATUS
  1101. DfsStore::EnumerateRoots(
  1102. BOOLEAN DomainRoots,
  1103. PULONG_PTR pBuffer,
  1104. PULONG pBufferSize,
  1105. PULONG pEntriesRead,
  1106. ULONG MaxEntriesToRead,
  1107. PULONG pCurrentNumRoots,
  1108. LPDWORD pResumeHandle,
  1109. PULONG pSizeRequired )
  1110. {
  1111. ULONG RootCount = 0;
  1112. DFSSTATUS Status = ERROR_SUCCESS;
  1113. DfsRootFolder *pRoot = NULL;
  1114. PULONG pDfsInfo;
  1115. ULONG TotalSize, EntriesRead;
  1116. BOOLEAN OverFlow = FALSE;
  1117. ULONG ResumeRoot;
  1118. //
  1119. // We start with total size and entries read with the passed in
  1120. // values, since we expect them to be initialized correctly, and
  1121. // possibly hold values from enumerations of other dfs flavors.
  1122. //
  1123. TotalSize = *pSizeRequired;
  1124. EntriesRead = *pEntriesRead;
  1125. //
  1126. // point the dfsinfo300 structure to the start of buffer passed in
  1127. // we will use this as an array of info200 buffers.
  1128. //
  1129. pDfsInfo = (PULONG)*pBuffer;
  1130. //
  1131. // We might not have to start at the beginning
  1132. //
  1133. ResumeRoot = 0;
  1134. if (pResumeHandle && *pResumeHandle > 0)
  1135. {
  1136. ResumeRoot = *pResumeHandle;
  1137. }
  1138. //
  1139. // now enumerate each child, and read its logical share name.
  1140. // update the total size required: if we have sufficient space
  1141. // in the passed in buffer, copy the information into the buffer.
  1142. //
  1143. RootCount = 0;
  1144. while (Status == ERROR_SUCCESS)
  1145. {
  1146. //
  1147. // Cap the total number of roots we can read.
  1148. //
  1149. if (EntriesRead >= MaxEntriesToRead)
  1150. {
  1151. break;
  1152. }
  1153. Status = FindNextRoot(RootCount, &pRoot);
  1154. if (Status == ERROR_SUCCESS)
  1155. {
  1156. RootCount++;
  1157. //
  1158. // We need to skip entries unless we get to the root we
  1159. // plan on resuming with.
  1160. //
  1161. if ((RootCount + *pCurrentNumRoots) > ResumeRoot)
  1162. {
  1163. PUNICODE_STRING pRootName;
  1164. pRootName = pRoot->GetLogicalShare();
  1165. if (DomainRoots == TRUE)
  1166. {
  1167. Status = AddRootEnumerationInfo200( pRootName,
  1168. (PDFS_INFO_200 *)(&pDfsInfo),
  1169. pBufferSize,
  1170. &EntriesRead,
  1171. &TotalSize );
  1172. }
  1173. else
  1174. {
  1175. UNICODE_STRING Context;
  1176. Status = pRoot->GetVisibleContext(&Context);
  1177. if (Status == ERROR_SUCCESS)
  1178. {
  1179. Status = AddRootEnumerationInfo( &Context,
  1180. pRootName,
  1181. pRoot->GetRootFlavor(),
  1182. (PDFS_INFO_300 *)(&pDfsInfo),
  1183. pBufferSize,
  1184. &EntriesRead,
  1185. &TotalSize );
  1186. pRoot->ReleaseVisibleContext(&Context);
  1187. }
  1188. }
  1189. //
  1190. // Continue on even if we get a buffer overflow.
  1191. // We need to calculate the SizeRequired anyway.
  1192. //
  1193. if (Status == ERROR_BUFFER_OVERFLOW)
  1194. {
  1195. OverFlow = TRUE;
  1196. Status = ERROR_SUCCESS;
  1197. }
  1198. DFS_TRACE_HIGH(API, "enumeratin child %wZ, Status %x\n", pRootName, Status);
  1199. }
  1200. pRoot->ReleaseReference();
  1201. }
  1202. }
  1203. //
  1204. // if we broked out of the loop due to lack of children,
  1205. // update the return pointers correctly.
  1206. // if we had detected an overflow condition above, return overflow
  1207. // otherwise return success.
  1208. //
  1209. *pSizeRequired = TotalSize;
  1210. *pEntriesRead = EntriesRead;
  1211. if (Status == ERROR_NOT_FOUND)
  1212. {
  1213. if (OverFlow)
  1214. {
  1215. Status = ERROR_BUFFER_OVERFLOW;
  1216. }
  1217. else
  1218. {
  1219. //
  1220. // Don't return NO_MORE_ITEMS here because
  1221. // the caller considers anything other than buffer overflow to be an error.
  1222. // Before we return the final values, we'll adjust that
  1223. // final status depending on the *total* number of
  1224. // entries returned (which includes those returned from other stores).
  1225. //
  1226. Status = ERROR_SUCCESS;
  1227. }
  1228. }
  1229. else if (OverFlow)
  1230. {
  1231. Status = ERROR_BUFFER_OVERFLOW;
  1232. }
  1233. //
  1234. // We update resume handle only if we are returning success.
  1235. //
  1236. if (Status == ERROR_SUCCESS)
  1237. {
  1238. //
  1239. // the buffer is now pointing to the next unused pDfsInfo array
  1240. // entry: this lets the next enumerated flavor continue where
  1241. // we left off.
  1242. //
  1243. *pBuffer = (ULONG_PTR)pDfsInfo;
  1244. (*pCurrentNumRoots) += RootCount;
  1245. }
  1246. DFS_TRACE_NORM(REFERRAL_SERVER, "done with flavor read %x, Status %x\n",
  1247. *pEntriesRead, Status);
  1248. return Status;
  1249. }
  1250. DFSSTATUS
  1251. DfsStore::AddRootEnumerationInfo200(
  1252. PUNICODE_STRING pRootName,
  1253. PDFS_INFO_200 *ppDfsInfo200,
  1254. PULONG pBufferSize,
  1255. PULONG pEntriesRead,
  1256. PULONG pTotalSize )
  1257. {
  1258. ULONG NeedSize;
  1259. DFSSTATUS Status = ERROR_SUCCESS;
  1260. DFS_TRACE_NORM(REFERRAL_SERVER, "add root enum: Read %d\n", *pEntriesRead);
  1261. //
  1262. // calculate amount of buffer space requirewd.
  1263. //
  1264. NeedSize = sizeof(DFS_INFO_200) + pRootName->MaximumLength;
  1265. //
  1266. // if it fits in the amount of space we have, we
  1267. // can copy the info into the passed in buffer.
  1268. //
  1269. if (NeedSize <= *pBufferSize)
  1270. {
  1271. ULONG_PTR pStringBuffer;
  1272. //
  1273. // position the string buffer to the end of the buffer,
  1274. // leaving enough space to copy the string.
  1275. // This strategy allows us to treat the pDfsInfo200
  1276. // as an array, marching forward from the beginning
  1277. // of the buffer, while the strings are allocated
  1278. // starting from the end of the buffer, since we
  1279. // dont know how many pDfsInfo200 buffers we will
  1280. // be using.
  1281. //
  1282. pStringBuffer = (ULONG_PTR)(*ppDfsInfo200) + *pBufferSize - pRootName->MaximumLength;
  1283. wcscpy( (LPWSTR)pStringBuffer, pRootName->Buffer);
  1284. (*ppDfsInfo200)->FtDfsName = (LPWSTR)pStringBuffer;
  1285. *pBufferSize -= NeedSize;
  1286. (*pEntriesRead)++;
  1287. (*ppDfsInfo200)++;
  1288. }
  1289. else
  1290. {
  1291. //
  1292. // if the size does not fit, we have overflowed.
  1293. //
  1294. Status = ERROR_BUFFER_OVERFLOW;
  1295. }
  1296. //
  1297. // set the total size under all circumstances.
  1298. //
  1299. *pTotalSize += NeedSize;
  1300. DFS_TRACE_NORM(REFERRAL_SERVER, "add root enum: Read %d, Status %x\n", *pEntriesRead, Status);
  1301. return Status;
  1302. }
  1303. DFSSTATUS
  1304. DfsStore::AddRootEnumerationInfo(
  1305. PUNICODE_STRING pVisibleName,
  1306. PUNICODE_STRING pRootName,
  1307. DWORD Flavor,
  1308. PDFS_INFO_300 *ppDfsInfo300,
  1309. PULONG pBufferSize,
  1310. PULONG pEntriesRead,
  1311. PULONG pTotalSize )
  1312. {
  1313. ULONG NeedSize;
  1314. DFSSTATUS Status = ERROR_SUCCESS;
  1315. ULONG StringLen;
  1316. DFS_TRACE_NORM(REFERRAL_SERVER, "add root enum: Read %d\n", *pEntriesRead);
  1317. //
  1318. // calculate amount of buffer space required.
  1319. //
  1320. StringLen = sizeof(WCHAR) +
  1321. pVisibleName->Length +
  1322. sizeof(WCHAR) +
  1323. pRootName->Length +
  1324. sizeof(WCHAR);
  1325. NeedSize = sizeof(DFS_INFO_300) + StringLen;
  1326. //
  1327. // if it fits in the amount of space we have, we
  1328. // can copy the info into the passed in buffer.
  1329. //
  1330. if (NeedSize <= *pBufferSize)
  1331. {
  1332. LPWSTR pStringBuffer;
  1333. //
  1334. // position the string buffer to the end of the buffer,
  1335. // leaving enough space to copy the string.
  1336. // This strategy allows us to treat the pDfsInfo300
  1337. // as an array, marching forward from the beginning
  1338. // of the buffer, while the strings are allocated
  1339. // starting from the end of the buffer, since we
  1340. // dont know how many pDfsInfo300 buffers we will
  1341. // be using.
  1342. //
  1343. pStringBuffer = (LPWSTR)((ULONG_PTR)(*ppDfsInfo300) + *pBufferSize - StringLen);
  1344. RtlZeroMemory(pStringBuffer, StringLen);
  1345. pStringBuffer[wcslen(pStringBuffer)] = UNICODE_PATH_SEP;
  1346. RtlCopyMemory( &pStringBuffer[wcslen(pStringBuffer)],
  1347. pVisibleName->Buffer,
  1348. pVisibleName->Length);
  1349. pStringBuffer[wcslen(pStringBuffer)] = UNICODE_PATH_SEP;
  1350. RtlCopyMemory( &pStringBuffer[wcslen(pStringBuffer)],
  1351. pRootName->Buffer,
  1352. pRootName->Length);
  1353. pStringBuffer[wcslen(pStringBuffer)] = UNICODE_NULL;
  1354. (*ppDfsInfo300)->DfsName = (LPWSTR)pStringBuffer;
  1355. (*ppDfsInfo300)->Flags = Flavor;
  1356. *pBufferSize -= NeedSize;
  1357. (*pEntriesRead)++;
  1358. (*ppDfsInfo300)++;
  1359. }
  1360. else
  1361. {
  1362. //
  1363. // if the size does not fit, we have overflowed.
  1364. //
  1365. Status = ERROR_BUFFER_OVERFLOW;
  1366. }
  1367. //
  1368. // set the total size under all circumstances.
  1369. //
  1370. *pTotalSize += NeedSize;
  1371. DFS_TRACE_NORM(REFERRAL_SERVER, "add root enum: Read %d, Status %x\n", *pEntriesRead, Status);
  1372. return Status;
  1373. }
  1374. DFSSTATUS
  1375. DfsStore::SetupADBlobRootKeyInformation(
  1376. HKEY DfsKey,
  1377. LPWSTR DfsLogicalShare,
  1378. LPWSTR DfsPhysicalShare )
  1379. {
  1380. DWORD Status = ERROR_SUCCESS;
  1381. HKEY FtDfsShareKey = NULL;
  1382. size_t PhysicalShareCchLength = 0;
  1383. size_t LogicalShareCchLength = 0;
  1384. Status = RegCreateKeyEx( DfsKey,
  1385. DfsLogicalShare,
  1386. 0,
  1387. L"",
  1388. REG_OPTION_NON_VOLATILE,
  1389. KEY_READ | KEY_WRITE,
  1390. NULL,
  1391. &FtDfsShareKey,
  1392. NULL );
  1393. //
  1394. // Now set the values for this root key, so that we know
  1395. // the DN for the root, and the physical share on the machine
  1396. // for the root, etc.
  1397. //
  1398. if (Status == ERROR_SUCCESS) {
  1399. Status = DfsStringCchLength( DfsPhysicalShare,
  1400. MAXUSHORT,
  1401. &PhysicalShareCchLength );
  1402. if (Status == ERROR_SUCCESS)
  1403. {
  1404. PhysicalShareCchLength++; // NULL Terminator
  1405. Status = RegSetValueEx( FtDfsShareKey,
  1406. DfsRootShareValueName,
  1407. 0,
  1408. REG_SZ,
  1409. (PBYTE)DfsPhysicalShare,
  1410. PhysicalShareCchLength * sizeof(WCHAR) );
  1411. }
  1412. if (Status == ERROR_SUCCESS) {
  1413. Status = DfsStringCchLength( DfsLogicalShare,
  1414. MAXUSHORT,
  1415. &LogicalShareCchLength );
  1416. if (Status == ERROR_SUCCESS)
  1417. {
  1418. LogicalShareCchLength++; // NULL Terminator
  1419. Status = RegSetValueEx( FtDfsShareKey,
  1420. DfsLogicalShareValueName,
  1421. 0,
  1422. REG_SZ,
  1423. (PBYTE)DfsLogicalShare,
  1424. LogicalShareCchLength * sizeof(WCHAR) );
  1425. }
  1426. }
  1427. RegCloseKey( FtDfsShareKey );
  1428. }
  1429. return Status;
  1430. }
  1431. DFSSTATUS
  1432. DfsStore::GetMetadataNameInformation(
  1433. IN DFS_METADATA_HANDLE RootHandle,
  1434. IN LPWSTR MetadataName,
  1435. OUT PDFS_NAME_INFORMATION *ppInfo )
  1436. {
  1437. PVOID pBlob = NULL;
  1438. PVOID pUseBlob = NULL;
  1439. ULONG BlobSize = 0;
  1440. ULONG UseBlobSize = 0;
  1441. PDFS_NAME_INFORMATION pNewInfo = NULL;
  1442. DFSSTATUS Status = ERROR_SUCCESS;
  1443. FILETIME BlobModifiedTime;
  1444. Status = GetMetadataNameBlob( RootHandle,
  1445. MetadataName,
  1446. &pBlob,
  1447. &BlobSize,
  1448. &BlobModifiedTime );
  1449. if (Status == ERROR_SUCCESS)
  1450. {
  1451. pNewInfo = new DFS_NAME_INFORMATION;
  1452. if (pNewInfo != NULL)
  1453. {
  1454. RtlZeroMemory (pNewInfo, sizeof(DFS_NAME_INFORMATION));
  1455. pUseBlob = pBlob;
  1456. UseBlobSize = BlobSize;
  1457. Status = PackGetNameInformation( pNewInfo,
  1458. &pUseBlob,
  1459. &UseBlobSize );
  1460. }
  1461. else
  1462. {
  1463. Status = ERROR_NOT_ENOUGH_MEMORY;
  1464. }
  1465. if (Status != ERROR_SUCCESS)
  1466. {
  1467. ReleaseMetadataNameBlob( pBlob, BlobSize );
  1468. }
  1469. }
  1470. if (Status == ERROR_SUCCESS)
  1471. {
  1472. pNewInfo->pData = pBlob;
  1473. pNewInfo->DataSize = BlobSize;
  1474. *ppInfo = pNewInfo;
  1475. }
  1476. return Status;
  1477. }
  1478. VOID
  1479. DfsStore::ReleaseMetadataNameInformation(
  1480. IN DFS_METADATA_HANDLE DfsHandle,
  1481. IN PDFS_NAME_INFORMATION pNameInfo )
  1482. {
  1483. UNREFERENCED_PARAMETER(DfsHandle);
  1484. ReleaseMetadataNameBlob( pNameInfo->pData,
  1485. pNameInfo->DataSize );
  1486. delete [] pNameInfo;
  1487. }
  1488. DFSSTATUS
  1489. DfsStore::SetMetadataNameInformation(
  1490. IN DFS_METADATA_HANDLE RootHandle,
  1491. IN LPWSTR MetadataName,
  1492. IN PDFS_NAME_INFORMATION pNameInfo )
  1493. {
  1494. PVOID pBlob = NULL;
  1495. ULONG BlobSize = 0;
  1496. DFSSTATUS Status = ERROR_SUCCESS;
  1497. SYSTEMTIME CurrentTime;
  1498. FILETIME ModifiedTime;
  1499. GetSystemTime( &CurrentTime);
  1500. if (SystemTimeToFileTime( &CurrentTime, &ModifiedTime ))
  1501. {
  1502. pNameInfo->LastModifiedTime = ModifiedTime;
  1503. }
  1504. Status = CreateNameInformationBlob( pNameInfo,
  1505. &pBlob,
  1506. &BlobSize );
  1507. if (Status == ERROR_SUCCESS)
  1508. {
  1509. Status = SetMetadataNameBlob( RootHandle,
  1510. MetadataName,
  1511. pBlob,
  1512. BlobSize );
  1513. ReleaseMetadataNameBlob( pBlob, BlobSize );
  1514. }
  1515. return Status;
  1516. }
  1517. DFSSTATUS
  1518. DfsStore::GetMetadataReplicaInformation(
  1519. IN DFS_METADATA_HANDLE RootHandle,
  1520. IN LPWSTR MetadataName,
  1521. OUT PDFS_REPLICA_LIST_INFORMATION *ppInfo )
  1522. {
  1523. PVOID pBlob = NULL;
  1524. PVOID pUseBlob = NULL;
  1525. ULONG BlobSize =0;
  1526. ULONG UseBlobSize = 0;
  1527. PDFS_REPLICA_LIST_INFORMATION pNewInfo = NULL;
  1528. DFSSTATUS Status = ERROR_SUCCESS;
  1529. Status = GetMetadataReplicaBlob( RootHandle,
  1530. MetadataName,
  1531. &pBlob,
  1532. &BlobSize,
  1533. NULL );
  1534. if (Status == ERROR_SUCCESS)
  1535. {
  1536. pNewInfo = new DFS_REPLICA_LIST_INFORMATION;
  1537. if (pNewInfo != NULL)
  1538. {
  1539. RtlZeroMemory (pNewInfo, sizeof(DFS_REPLICA_LIST_INFORMATION));
  1540. pUseBlob = pBlob;
  1541. UseBlobSize = BlobSize;
  1542. Status = PackGetULong( &pNewInfo->ReplicaCount,
  1543. &pUseBlob,
  1544. &UseBlobSize );
  1545. if (Status == ERROR_SUCCESS)
  1546. {
  1547. pNewInfo->pReplicas = new DFS_REPLICA_INFORMATION[ pNewInfo->ReplicaCount];
  1548. if ( pNewInfo->pReplicas != NULL )
  1549. {
  1550. Status = PackGetReplicaInformation(pNewInfo,
  1551. &pUseBlob,
  1552. &UseBlobSize );
  1553. }
  1554. else
  1555. {
  1556. Status = ERROR_NOT_ENOUGH_MEMORY;
  1557. }
  1558. }
  1559. if (Status != ERROR_SUCCESS)
  1560. {
  1561. if(pNewInfo->pReplicas != NULL)
  1562. {
  1563. delete [] pNewInfo->pReplicas;
  1564. }
  1565. delete pNewInfo;
  1566. }
  1567. }
  1568. else
  1569. {
  1570. Status = ERROR_NOT_ENOUGH_MEMORY;
  1571. }
  1572. if (Status != ERROR_SUCCESS)
  1573. {
  1574. ReleaseMetadataReplicaBlob( pBlob, BlobSize );
  1575. }
  1576. }
  1577. if (Status == ERROR_SUCCESS)
  1578. {
  1579. pNewInfo->pData = pBlob;
  1580. pNewInfo->DataSize = BlobSize;
  1581. *ppInfo = pNewInfo;
  1582. }
  1583. return Status;
  1584. }
  1585. VOID
  1586. DfsStore::ReleaseMetadataReplicaInformation(
  1587. IN DFS_METADATA_HANDLE DfsHandle,
  1588. IN PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo )
  1589. {
  1590. UNREFERENCED_PARAMETER(DfsHandle);
  1591. ReleaseMetadataReplicaBlob( pReplicaListInfo->pData,
  1592. pReplicaListInfo->DataSize );
  1593. delete [] pReplicaListInfo->pReplicas;
  1594. delete [] pReplicaListInfo;
  1595. }
  1596. DFSSTATUS
  1597. DfsStore::SetMetadataReplicaInformation(
  1598. IN DFS_METADATA_HANDLE RootHandle,
  1599. IN LPWSTR MetadataName,
  1600. IN PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo )
  1601. {
  1602. PVOID pBlob = NULL;
  1603. ULONG BlobSize = 0;
  1604. DFSSTATUS Status = ERROR_SUCCESS;
  1605. Status = CreateReplicaListInformationBlob( pReplicaListInfo,
  1606. &pBlob,
  1607. &BlobSize );
  1608. if (Status == ERROR_SUCCESS)
  1609. {
  1610. Status = SetMetadataReplicaBlob( RootHandle,
  1611. MetadataName,
  1612. pBlob,
  1613. BlobSize );
  1614. ReleaseMetadataReplicaBlob( pBlob, BlobSize );
  1615. }
  1616. return Status;
  1617. }
  1618. DFSSTATUS
  1619. DfsStore::CreateNameInformationBlob(
  1620. IN PDFS_NAME_INFORMATION pDfsNameInfo,
  1621. OUT PVOID *ppBlob,
  1622. OUT PULONG pDataSize )
  1623. {
  1624. PVOID pBlob = NULL;
  1625. PVOID pUseBlob = NULL;
  1626. ULONG BlobSize = 0;
  1627. ULONG UseBlobSize = 0;
  1628. DFSSTATUS Status = ERROR_SUCCESS;
  1629. BlobSize = PackSizeNameInformation( pDfsNameInfo );
  1630. Status = AllocateMetadataNameBlob( &pBlob,
  1631. BlobSize );
  1632. if ( Status == ERROR_SUCCESS )
  1633. {
  1634. pUseBlob = pBlob;
  1635. UseBlobSize = BlobSize;
  1636. // Pack the name information into the binary stream allocated.
  1637. //
  1638. Status = PackSetNameInformation( pDfsNameInfo,
  1639. &pUseBlob,
  1640. &UseBlobSize );
  1641. if (Status != ERROR_SUCCESS)
  1642. {
  1643. ReleaseMetadataNameBlob( pBlob, BlobSize );
  1644. }
  1645. }
  1646. if (Status == ERROR_SUCCESS)
  1647. {
  1648. *ppBlob = pBlob;
  1649. *pDataSize = BlobSize - UseBlobSize;
  1650. }
  1651. return Status;
  1652. }
  1653. DFSSTATUS
  1654. DfsStore::CreateReplicaListInformationBlob(
  1655. IN PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo,
  1656. OUT PVOID *ppBlob,
  1657. OUT PULONG pDataSize )
  1658. {
  1659. PVOID pBlob = NULL;
  1660. PVOID pUseBlob = NULL;
  1661. ULONG BlobSize = 0;
  1662. ULONG UseBlobSize = 0;
  1663. DFSSTATUS Status = ERROR_SUCCESS;
  1664. BlobSize = PackSizeULong();
  1665. BlobSize += PackSizeReplicaInformation( pReplicaListInfo );
  1666. BlobSize += PackSizeULong();
  1667. Status = AllocateMetadataReplicaBlob( &pBlob,
  1668. BlobSize );
  1669. if ( Status == ERROR_SUCCESS )
  1670. {
  1671. pUseBlob = pBlob;
  1672. UseBlobSize = BlobSize;
  1673. //
  1674. // The first item in the stream is the number of replicas
  1675. //
  1676. Status = PackSetULong(pReplicaListInfo->ReplicaCount,
  1677. &pUseBlob,
  1678. &UseBlobSize );
  1679. if (Status == ERROR_SUCCESS)
  1680. {
  1681. //
  1682. // We than pack the array of replicas into the binary stream
  1683. //
  1684. Status = PackSetReplicaInformation( pReplicaListInfo,
  1685. &pUseBlob,
  1686. &UseBlobSize );
  1687. }
  1688. if (Status == ERROR_SUCCESS)
  1689. {
  1690. //
  1691. // We than pack the last word with a 0 so that all the
  1692. // old crap still works.
  1693. //
  1694. Status = PackSetULong( 0,
  1695. &pUseBlob,
  1696. &UseBlobSize );
  1697. }
  1698. if (Status != ERROR_SUCCESS)
  1699. {
  1700. ReleaseMetadataReplicaBlob( pBlob, BlobSize );
  1701. }
  1702. }
  1703. if (Status == ERROR_SUCCESS)
  1704. {
  1705. *ppBlob = pBlob;
  1706. *pDataSize = BlobSize - UseBlobSize;
  1707. }
  1708. return Status;
  1709. }
  1710. DFSSTATUS
  1711. DfsStore::AddChildReplica (
  1712. IN DFS_METADATA_HANDLE DfsHandle,
  1713. LPWSTR LinkMetadataName,
  1714. LPWSTR ServerName,
  1715. LPWSTR SharePath )
  1716. {
  1717. PDFS_REPLICA_LIST_INFORMATION pReplicaList = NULL;
  1718. PDFS_REPLICA_INFORMATION pReplicaInfo = NULL;
  1719. ULONG ReplicaIndex = 0;
  1720. DFSSTATUS Status = ERROR_SUCCESS;
  1721. WCHAR * NameToCheck = NULL;
  1722. DFS_REPLICA_LIST_INFORMATION NewList;
  1723. UNICODE_STRING DfsSharePath;
  1724. UNICODE_STRING DfsServerName;
  1725. DFS_TRACE_HIGH(API, "AddChildReplica for path %ws, Server=%ws Share=%ws \n", LinkMetadataName, ServerName, SharePath);
  1726. if ( (ServerName == NULL) || (SharePath == NULL) )
  1727. {
  1728. return ERROR_INVALID_PARAMETER;
  1729. }
  1730. Status = DfsRtlInitUnicodeStringEx( &DfsSharePath, SharePath );
  1731. if(Status != ERROR_SUCCESS)
  1732. {
  1733. return Status;
  1734. }
  1735. Status = DfsRtlInitUnicodeStringEx( &DfsServerName, ServerName );
  1736. if(Status != ERROR_SUCCESS)
  1737. {
  1738. return Status;
  1739. }
  1740. Status = GetMetadataReplicaInformation( DfsHandle,
  1741. LinkMetadataName,
  1742. &pReplicaList );
  1743. if (Status == ERROR_SUCCESS)
  1744. {
  1745. ReplicaIndex = FindReplicaInReplicaList( pReplicaList,
  1746. ServerName,
  1747. SharePath );
  1748. if (ReplicaIndex < pReplicaList->ReplicaCount)
  1749. {
  1750. Status = ERROR_FILE_EXISTS;
  1751. }
  1752. else if(pReplicaList->ReplicaCount == 1)
  1753. {
  1754. pReplicaInfo = &pReplicaList->pReplicas[0];
  1755. NameToCheck = new WCHAR[pReplicaInfo->ServerName.Length/sizeof(WCHAR) + 1];
  1756. if(NameToCheck != NULL)
  1757. {
  1758. RtlCopyMemory(NameToCheck, pReplicaInfo->ServerName.Buffer, pReplicaInfo->ServerName.Length);
  1759. NameToCheck[pReplicaInfo->ServerName.Length / sizeof(WCHAR)] = UNICODE_NULL;
  1760. //if this is a domain name, fail the request with not supported.
  1761. //else continue on.
  1762. Status = I_NetDfsIsThisADomainName(NameToCheck);
  1763. if(Status == ERROR_SUCCESS)
  1764. {
  1765. Status = ERROR_NOT_SUPPORTED;
  1766. }
  1767. else
  1768. {
  1769. Status = ERROR_SUCCESS;
  1770. }
  1771. delete [] NameToCheck;
  1772. }
  1773. else
  1774. {
  1775. Status = ERROR_NOT_ENOUGH_MEMORY;
  1776. }
  1777. }
  1778. if (Status == ERROR_SUCCESS)
  1779. {
  1780. RtlZeroMemory( &NewList, sizeof(DFS_REPLICA_LIST_INFORMATION));
  1781. NewList.ReplicaCount = pReplicaList->ReplicaCount + 1;
  1782. NewList.pReplicas = new DFS_REPLICA_INFORMATION [ NewList.ReplicaCount ];
  1783. if (NewList.pReplicas == NULL)
  1784. {
  1785. Status = ERROR_NOT_ENOUGH_MEMORY;
  1786. }
  1787. else
  1788. {
  1789. if (pReplicaList->ReplicaCount)
  1790. {
  1791. RtlCopyMemory( &NewList.pReplicas[0],
  1792. &pReplicaList->pReplicas[0],
  1793. pReplicaList->ReplicaCount * sizeof(DFS_REPLICA_INFORMATION) );
  1794. }
  1795. pReplicaInfo = &NewList.pReplicas[pReplicaList->ReplicaCount];
  1796. RtlZeroMemory( pReplicaInfo,
  1797. sizeof(DFS_REPLICA_INFORMATION) );
  1798. DfsRtlInitUnicodeStringEx(&pReplicaInfo->ServerName, DfsServerName.Buffer);
  1799. DfsRtlInitUnicodeStringEx(&pReplicaInfo->ShareName, DfsSharePath.Buffer);
  1800. pReplicaInfo->ReplicaState = DFS_STORAGE_STATE_ONLINE;
  1801. pReplicaInfo->ReplicaType = 2; // hack fro backwards compat.
  1802. Status = SetMetadataReplicaInformation( DfsHandle,
  1803. LinkMetadataName,
  1804. &NewList );
  1805. delete [] NewList.pReplicas;
  1806. }
  1807. }
  1808. ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
  1809. }
  1810. DFS_TRACE_HIGH(API, "AddChildReplica for path %ws, Server=%ws Share=%ws, Status=%d\n", LinkMetadataName,
  1811. ServerName, SharePath, Status);
  1812. return Status;
  1813. }
  1814. DFSSTATUS
  1815. DfsStore::RemoveChildReplica (
  1816. IN DFS_METADATA_HANDLE DfsHandle,
  1817. LPWSTR LinkMetadataName,
  1818. LPWSTR ServerName,
  1819. LPWSTR SharePath,
  1820. PBOOLEAN pLastReplica,
  1821. BOOLEAN Force)
  1822. {
  1823. PDFS_REPLICA_LIST_INFORMATION pReplicaList = NULL;
  1824. ULONG DeleteIndex = 0;
  1825. ULONG NextIndex = 0;
  1826. DFSSTATUS Status = ERROR_SUCCESS;
  1827. DFS_REPLICA_LIST_INFORMATION NewList;
  1828. DFS_TRACE_HIGH(API, "RemoveChildReplica for path %ws, Server=%ws Share=%ws \n", LinkMetadataName, ServerName, SharePath);
  1829. *pLastReplica = FALSE;
  1830. RtlZeroMemory( &NewList,
  1831. sizeof(DFS_REPLICA_LIST_INFORMATION));
  1832. if ( (ServerName == NULL) || (SharePath == NULL) )
  1833. {
  1834. return ERROR_INVALID_PARAMETER;
  1835. }
  1836. Status = GetMetadataReplicaInformation( DfsHandle,
  1837. LinkMetadataName,
  1838. &pReplicaList );
  1839. if (Status == ERROR_SUCCESS)
  1840. {
  1841. DeleteIndex = FindReplicaInReplicaList( pReplicaList,
  1842. ServerName,
  1843. SharePath );
  1844. DFS_TRACE_HIGH(API, "DfsRemove for path %ws, Server=%ws Share=%ws, DeleteIndex=%d,pReplicaList->ReplicaCount=%d \n", LinkMetadataName,
  1845. ServerName, SharePath, DeleteIndex, pReplicaList->ReplicaCount);
  1846. if (DeleteIndex < pReplicaList->ReplicaCount)
  1847. {
  1848. NewList.ReplicaCount = pReplicaList->ReplicaCount - 1;
  1849. if (NewList.ReplicaCount)
  1850. {
  1851. NewList.pReplicas = new DFS_REPLICA_INFORMATION [NewList.ReplicaCount];
  1852. if (NewList.pReplicas != NULL)
  1853. {
  1854. if (DeleteIndex)
  1855. {
  1856. RtlCopyMemory( &NewList.pReplicas[0],
  1857. &pReplicaList->pReplicas[0],
  1858. DeleteIndex * sizeof(DFS_REPLICA_INFORMATION) );
  1859. }
  1860. NextIndex = DeleteIndex + 1;
  1861. if ( NextIndex < pReplicaList->ReplicaCount)
  1862. {
  1863. RtlCopyMemory( &NewList.pReplicas[DeleteIndex],
  1864. &pReplicaList->pReplicas[NextIndex],
  1865. (pReplicaList->ReplicaCount - NextIndex) * sizeof(DFS_REPLICA_INFORMATION) );
  1866. }
  1867. }
  1868. else {
  1869. Status = ERROR_NOT_ENOUGH_MEMORY;
  1870. }
  1871. }
  1872. //if this is the last target, do not remove it. Return ERROR_LAST_ADMIN
  1873. //to the upper code, so that he can remove the last target and link in one
  1874. //atomic operation.
  1875. if (Status == ERROR_SUCCESS)
  1876. {
  1877. if(NewList.ReplicaCount == 0)
  1878. {
  1879. *pLastReplica = TRUE;
  1880. }
  1881. if( (Force == FALSE) && (NewList.ReplicaCount == 0))
  1882. {
  1883. Status = ERROR_LAST_ADMIN;
  1884. }
  1885. else
  1886. {
  1887. Status = SetMetadataReplicaInformation( DfsHandle,
  1888. LinkMetadataName,
  1889. &NewList );
  1890. }
  1891. }
  1892. if (NewList.pReplicas != NULL)
  1893. {
  1894. delete [] NewList.pReplicas;
  1895. }
  1896. }
  1897. else {
  1898. Status = ERROR_FILE_NOT_FOUND;
  1899. }
  1900. ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
  1901. }
  1902. DFS_TRACE_HIGH(API, "DfsRemove for path %ws, Server=%ws Share=%ws, LastReplica=%d, Status=%d\n", LinkMetadataName,
  1903. ServerName, SharePath, *pLastReplica, Status);
  1904. return Status;
  1905. }
  1906. DFSSTATUS
  1907. DfsStore::GetStoreApiInformation(
  1908. IN DFS_METADATA_HANDLE DfsHandle,
  1909. PUNICODE_STRING pRootName,
  1910. LPWSTR LinkMetadataName,
  1911. DWORD Level,
  1912. LPBYTE pBuffer,
  1913. LONG BufferSize,
  1914. PLONG pSizeRequired )
  1915. {
  1916. DFSSTATUS Status = ERROR_SUCCESS;
  1917. PDFS_NAME_INFORMATION pNameInformation = NULL;
  1918. PDFS_REPLICA_LIST_INFORMATION pReplicaList = NULL;
  1919. PDFS_REPLICA_INFORMATION pReplica = NULL;
  1920. PDFS_API_INFO pInfo = (PDFS_API_INFO)pBuffer;
  1921. PDFS_STORAGE_INFO pStorage = NULL;
  1922. LONG HeaderSize = 0;
  1923. LONG AdditionalSize = 0;
  1924. ULONG_PTR NextFreeMemory = NULL;
  1925. ULONG i = 0;
  1926. UNICODE_STRING UsePrefixName;
  1927. DFS_API_INFO LocalInfo;
  1928. RtlZeroMemory(&LocalInfo, sizeof(DFS_API_INFO));
  1929. Status = GetMetadataNameInformation( DfsHandle,
  1930. LinkMetadataName,
  1931. &pNameInformation );
  1932. if (Status == ERROR_SUCCESS)
  1933. {
  1934. Status = GenerateApiLogicalPath( pRootName,
  1935. &pNameInformation->Prefix,
  1936. &UsePrefixName );
  1937. if (Status != ERROR_SUCCESS)
  1938. {
  1939. ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
  1940. }
  1941. }
  1942. if (Status == ERROR_SUCCESS)
  1943. {
  1944. Status = GetMetadataReplicaInformation( DfsHandle,
  1945. LinkMetadataName,
  1946. &pReplicaList );
  1947. if (Status == ERROR_SUCCESS)
  1948. {
  1949. switch (Level)
  1950. {
  1951. case 100:
  1952. if (HeaderSize == 0)
  1953. {
  1954. HeaderSize = sizeof(DFS_INFO_100);
  1955. NextFreeMemory = (ULONG_PTR)(&pInfo->Info100 + 1);
  1956. }
  1957. AdditionalSize += pNameInformation->Comment.Length + sizeof(WCHAR);
  1958. break;
  1959. case 4:
  1960. if (HeaderSize == 0)
  1961. {
  1962. HeaderSize = sizeof(DFS_INFO_4);
  1963. LocalInfo.Info4.Timeout = pNameInformation->Timeout;
  1964. LocalInfo.Info4.State = pNameInformation->State;
  1965. LocalInfo.Info4.NumberOfStorages = pReplicaList->ReplicaCount;
  1966. pStorage = LocalInfo.Info4.Storage = (PDFS_STORAGE_INFO)(&pInfo->Info4 + 1);
  1967. NextFreeMemory = (ULONG_PTR)(LocalInfo.Info4.Storage + LocalInfo.Info4.NumberOfStorages);
  1968. }
  1969. case 3:
  1970. if (HeaderSize == 0)
  1971. {
  1972. HeaderSize = sizeof(DFS_INFO_3);
  1973. LocalInfo.Info3.State = pNameInformation->State;
  1974. LocalInfo.Info3.NumberOfStorages = pReplicaList->ReplicaCount;
  1975. pStorage = LocalInfo.Info3.Storage = (PDFS_STORAGE_INFO)(&pInfo->Info3 + 1);
  1976. NextFreeMemory = (ULONG_PTR)(LocalInfo.Info3.Storage + LocalInfo.Info3.NumberOfStorages);
  1977. }
  1978. for (i = 0; i < pReplicaList->ReplicaCount; i++)
  1979. {
  1980. UNICODE_STRING ServerName = pReplicaList->pReplicas[i].ServerName;
  1981. if (IsLocalName(&ServerName))
  1982. {
  1983. ServerName = *pRootName;
  1984. }
  1985. AdditionalSize += ( sizeof(DFS_STORAGE_INFO) +
  1986. ServerName.Length + sizeof(WCHAR) +
  1987. pReplicaList->pReplicas[i].ShareName.Length + sizeof(WCHAR) );
  1988. }
  1989. case 2:
  1990. if (HeaderSize == 0)
  1991. {
  1992. HeaderSize = sizeof(DFS_INFO_2);
  1993. LocalInfo.Info2.State = pNameInformation->State;
  1994. LocalInfo.Info2.NumberOfStorages = pReplicaList->ReplicaCount;
  1995. NextFreeMemory = (ULONG_PTR)(&pInfo->Info2 + 1);
  1996. }
  1997. AdditionalSize += pNameInformation->Comment.Length + sizeof(WCHAR);
  1998. case 1:
  1999. if (HeaderSize == 0)
  2000. {
  2001. HeaderSize = sizeof(DFS_INFO_1);
  2002. NextFreeMemory = (ULONG_PTR)(&pInfo->Info1 + 1);
  2003. }
  2004. AdditionalSize += UsePrefixName.Length + sizeof(WCHAR);
  2005. break;
  2006. default:
  2007. Status = ERROR_INVALID_PARAMETER;
  2008. break;
  2009. }
  2010. *pSizeRequired = HeaderSize + AdditionalSize;
  2011. if (*pSizeRequired > BufferSize)
  2012. {
  2013. Status = ERROR_BUFFER_OVERFLOW;
  2014. }
  2015. if (Status == ERROR_SUCCESS)
  2016. {
  2017. RtlZeroMemory( pBuffer, *pSizeRequired);
  2018. RtlCopyMemory( &pInfo->Info4, &LocalInfo.Info4, HeaderSize );
  2019. switch (Level)
  2020. {
  2021. //
  2022. // Extract just the comment for this root/link.
  2023. //
  2024. case 100:
  2025. pInfo->Info100.Comment = (LPWSTR)NextFreeMemory;
  2026. NextFreeMemory += pNameInformation->Comment.Length + sizeof(WCHAR);
  2027. RtlCopyMemory( pInfo->Info100.Comment,
  2028. pNameInformation->Comment.Buffer,
  2029. pNameInformation->Comment.Length );
  2030. break;
  2031. case 4:
  2032. case 3:
  2033. for (i = 0; i < pReplicaList->ReplicaCount; i++)
  2034. {
  2035. UNICODE_STRING ServerName = pReplicaList->pReplicas[i].ServerName;
  2036. if (IsLocalName(&ServerName))
  2037. {
  2038. ServerName = *pRootName;
  2039. }
  2040. pReplica = &pReplicaList->pReplicas[i];
  2041. pStorage[i].State = pReplica->ReplicaState;
  2042. pStorage[i].ServerName = (LPWSTR)NextFreeMemory;
  2043. NextFreeMemory += ServerName.Length + sizeof(WCHAR);
  2044. pStorage[i].ShareName = (LPWSTR)NextFreeMemory;
  2045. NextFreeMemory += pReplica->ShareName.Length + sizeof(WCHAR);
  2046. RtlCopyMemory( pStorage[i].ServerName,
  2047. ServerName.Buffer,
  2048. ServerName.Length );
  2049. RtlCopyMemory( pStorage[i].ShareName,
  2050. pReplica->ShareName.Buffer,
  2051. pReplica->ShareName.Length );
  2052. }
  2053. case 2:
  2054. pInfo->Info2.Comment = (LPWSTR)NextFreeMemory;
  2055. NextFreeMemory += pNameInformation->Comment.Length + sizeof(WCHAR);
  2056. RtlCopyMemory( pInfo->Info2.Comment,
  2057. pNameInformation->Comment.Buffer,
  2058. pNameInformation->Comment.Length );
  2059. case 1:
  2060. pInfo->Info1.EntryPath = (LPWSTR)NextFreeMemory;
  2061. RtlCopyMemory( pInfo->Info1.EntryPath,
  2062. UsePrefixName.Buffer,
  2063. UsePrefixName.Length );
  2064. pInfo->Info1.EntryPath[UsePrefixName.Length/sizeof(WCHAR)] = UNICODE_NULL;
  2065. break;
  2066. }
  2067. }
  2068. ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
  2069. }
  2070. ReleaseApiLogicalPath( &UsePrefixName );
  2071. ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
  2072. }
  2073. return Status;
  2074. }
  2075. DFSSTATUS
  2076. DfsStore::GetExtendedAttributes(
  2077. IN DFS_METADATA_HANDLE DfsHandle,
  2078. LPWSTR LinkMetadataName,
  2079. PULONG pAttr)
  2080. {
  2081. DFSSTATUS Status = ERROR_SUCCESS;
  2082. PDFS_NAME_INFORMATION pNameInformation = NULL;
  2083. Status = GetMetadataNameInformation( DfsHandle,
  2084. LinkMetadataName,
  2085. &pNameInformation );
  2086. if (Status != ERROR_SUCCESS)
  2087. {
  2088. return Status;
  2089. }
  2090. *pAttr = (pNameInformation->Type & PKT_ENTRY_TYPE_EXTENDED_ATTRIBUTES);
  2091. ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
  2092. return Status;
  2093. }
  2094. DFSSTATUS
  2095. DfsStore::SetExtendedAttributes(
  2096. IN DFS_METADATA_HANDLE DfsHandle,
  2097. LPWSTR LinkMetadataName,
  2098. ULONG Attr)
  2099. {
  2100. DFSSTATUS Status = ERROR_SUCCESS;
  2101. PDFS_NAME_INFORMATION pNameInformation = NULL;
  2102. ULONG UseAttr;
  2103. UseAttr = Attr & PKT_ENTRY_TYPE_EXTENDED_ATTRIBUTES;
  2104. if (UseAttr != Attr)
  2105. {
  2106. return ERROR_INVALID_PARAMETER;
  2107. }
  2108. Status = GetMetadataNameInformation( DfsHandle,
  2109. LinkMetadataName,
  2110. &pNameInformation );
  2111. if (Status != ERROR_SUCCESS)
  2112. {
  2113. return Status;
  2114. }
  2115. pNameInformation->Type &= ~PKT_ENTRY_TYPE_EXTENDED_ATTRIBUTES;
  2116. pNameInformation->Type |= UseAttr;
  2117. Status = SetMetadataNameInformation( DfsHandle,
  2118. LinkMetadataName,
  2119. pNameInformation );
  2120. ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
  2121. return Status;
  2122. }
  2123. DFSSTATUS
  2124. DfsStore::SetStoreApiInformation(
  2125. IN DFS_METADATA_HANDLE DfsHandle,
  2126. LPWSTR LinkMetadataName,
  2127. LPWSTR ServerName,
  2128. LPWSTR SharePath,
  2129. DWORD Level,
  2130. LPBYTE pBuffer )
  2131. {
  2132. DFSSTATUS Status = ERROR_SUCCESS;
  2133. PDFS_NAME_INFORMATION pNameInformation = NULL;
  2134. BOOLEAN TypeInfoSet = FALSE;
  2135. //
  2136. // The set is a little strange: the pBuffer is pointing to a pointer
  2137. // that we are interested in. Grab it directly.
  2138. // dfsdev: this is confusing, fix it or document in detail.
  2139. //
  2140. PDFS_API_INFO pApiInfo = (PDFS_API_INFO)(*(PULONG_PTR)pBuffer);
  2141. if(pApiInfo == NULL)
  2142. {
  2143. return ERROR_INVALID_PARAMETER;
  2144. }
  2145. //
  2146. // dfsdev: need to do some api work before enabling code
  2147. // below.
  2148. //
  2149. #if 0
  2150. if ( (ServerName != NULL) || (SharePath != NULL) )
  2151. {
  2152. if (Level != 101)
  2153. {
  2154. return ERROR_INVALID_PARAMETER;
  2155. }
  2156. }
  2157. #endif
  2158. Status = GetMetadataNameInformation( DfsHandle,
  2159. LinkMetadataName,
  2160. &pNameInformation );
  2161. if (Status != ERROR_SUCCESS)
  2162. {
  2163. return Status;
  2164. }
  2165. switch (Level)
  2166. {
  2167. case 100:
  2168. Status = DfsRtlInitUnicodeStringEx( &pNameInformation->Comment,
  2169. pApiInfo->Info100.Comment );
  2170. if(Status == ERROR_SUCCESS)
  2171. {
  2172. Status = SetMetadataNameInformation( DfsHandle,
  2173. LinkMetadataName,
  2174. pNameInformation );
  2175. }
  2176. break;
  2177. case 102:
  2178. pNameInformation->Timeout = pApiInfo->Info102.Timeout;
  2179. Status = SetMetadataNameInformation( DfsHandle,
  2180. LinkMetadataName,
  2181. pNameInformation );
  2182. break;
  2183. case 101:
  2184. if ((ServerName == NULL) && (SharePath == NULL))
  2185. {
  2186. pNameInformation->State = pApiInfo->Info101.State;
  2187. Status = SetMetadataNameInformation( DfsHandle,
  2188. LinkMetadataName,
  2189. pNameInformation );
  2190. }
  2191. else {
  2192. PDFS_REPLICA_LIST_INFORMATION pReplicaList;
  2193. ULONG ReplicaIndex;
  2194. Status = GetMetadataReplicaInformation (DfsHandle,
  2195. LinkMetadataName,
  2196. &pReplicaList );
  2197. if (Status == ERROR_SUCCESS)
  2198. {
  2199. ReplicaIndex = FindReplicaInReplicaList( pReplicaList,
  2200. ServerName,
  2201. SharePath );
  2202. if (ReplicaIndex >= pReplicaList->ReplicaCount)
  2203. {
  2204. Status = ERROR_NOT_FOUND;
  2205. }
  2206. else {
  2207. DFS_REPLICA_LIST_INFORMATION NewList;
  2208. RtlZeroMemory( &NewList, sizeof( DFS_REPLICA_LIST_INFORMATION) );
  2209. NewList.ReplicaCount = pReplicaList->ReplicaCount;
  2210. NewList.pReplicas = new DFS_REPLICA_INFORMATION [ NewList.ReplicaCount ];
  2211. if (NewList.pReplicas != NULL)
  2212. {
  2213. RtlCopyMemory( &NewList.pReplicas[0],
  2214. &pReplicaList->pReplicas[0],
  2215. NewList.ReplicaCount * sizeof(DFS_REPLICA_INFORMATION) );
  2216. NewList.pReplicas[ReplicaIndex].ReplicaState = pApiInfo->Info101.State;
  2217. NewList.pReplicas[ReplicaIndex].ReplicaType = 2; // hack fro backwards compat.
  2218. Status = SetMetadataReplicaInformation (DfsHandle,
  2219. LinkMetadataName,
  2220. &NewList );
  2221. delete [] NewList.pReplicas;
  2222. }
  2223. else {
  2224. Status = ERROR_NOT_ENOUGH_MEMORY;
  2225. }
  2226. }
  2227. ReleaseMetadataReplicaInformation( DfsHandle, pReplicaList );
  2228. }
  2229. }
  2230. break;
  2231. default:
  2232. Status = ERROR_INVALID_PARAMETER;
  2233. break;
  2234. }
  2235. ReleaseMetadataNameInformation( DfsHandle, pNameInformation );
  2236. return Status;
  2237. }
  2238. DFSSTATUS
  2239. DfsStore::GetStoreApiInformationBuffer(
  2240. IN DFS_METADATA_HANDLE DfsHandle,
  2241. PUNICODE_STRING pRootName,
  2242. LPWSTR LinkMetadataName,
  2243. DWORD Level,
  2244. LPBYTE *ppBuffer,
  2245. PLONG pBufferSize )
  2246. {
  2247. DFSSTATUS Status = ERROR_SUCCESS;
  2248. LONG RequiredSize = 0;
  2249. LONG BufferSize = 4096;
  2250. LPBYTE pBuffer = new BYTE [ BufferSize ];
  2251. if (pBuffer == NULL)
  2252. {
  2253. return ERROR_NOT_ENOUGH_MEMORY;
  2254. }
  2255. Status = GetStoreApiInformation( DfsHandle,
  2256. pRootName,
  2257. LinkMetadataName,
  2258. Level,
  2259. pBuffer,
  2260. BufferSize,
  2261. &RequiredSize );
  2262. if (Status == ERROR_BUFFER_OVERFLOW)
  2263. {
  2264. delete [] pBuffer;
  2265. BufferSize = RequiredSize;
  2266. pBuffer = new BYTE[ BufferSize ];
  2267. if (pBuffer == NULL)
  2268. {
  2269. Status = ERROR_NOT_ENOUGH_MEMORY;
  2270. }
  2271. else {
  2272. Status = GetStoreApiInformation( DfsHandle,
  2273. pRootName,
  2274. LinkMetadataName,
  2275. Level,
  2276. pBuffer,
  2277. BufferSize,
  2278. &RequiredSize );
  2279. }
  2280. }
  2281. if (Status == ERROR_SUCCESS)
  2282. {
  2283. *ppBuffer = pBuffer;
  2284. *pBufferSize = RequiredSize;
  2285. }
  2286. else
  2287. {
  2288. if(pBuffer != NULL)
  2289. {
  2290. delete [] pBuffer;
  2291. }
  2292. }
  2293. return Status;
  2294. }
  2295. DFSSTATUS
  2296. DfsStore::FindNextRoot(
  2297. ULONG RootNum,
  2298. DfsRootFolder **ppRootFolder )
  2299. {
  2300. DFSSTATUS Status = ERROR_SUCCESS;
  2301. DfsRootFolder *pRoot = NULL;
  2302. ULONG Start = 0;
  2303. DFS_TRACE_LOW( REFERRAL_SERVER, "Store %p, Find next root %d\n",
  2304. this, RootNum );
  2305. //
  2306. // Lock the store, so that we dont have new roots coming in while
  2307. // we are taking a look.
  2308. //
  2309. Status = AcquireReadLock();
  2310. if ( Status != ERROR_SUCCESS )
  2311. {
  2312. return Status;
  2313. }
  2314. //
  2315. // The default return status is ERROR_NOT_FOUND;
  2316. //
  2317. Status = ERROR_NOT_FOUND;
  2318. //
  2319. // Run through our list of DFS roots, and see if any of them match
  2320. // the passed in name context and logical share.
  2321. //
  2322. pRoot = _DfsRootList;
  2323. Start = 0;
  2324. if (pRoot != NULL)
  2325. {
  2326. do
  2327. {
  2328. if (Start++ == RootNum)
  2329. {
  2330. Status = ERROR_SUCCESS;
  2331. break;
  2332. }
  2333. pRoot = pRoot->pNextRoot;
  2334. } while ( pRoot != _DfsRootList );
  2335. }
  2336. //
  2337. // IF we found a matching root, bump up its reference count, and
  2338. // return the pointer to the root.
  2339. //
  2340. if ( Status == ERROR_SUCCESS )
  2341. {
  2342. pRoot->AcquireReference();
  2343. *ppRootFolder = pRoot;
  2344. }
  2345. ReleaseLock();
  2346. DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "Done find next %d, root %p status %x\n",
  2347. RootNum, pRoot, Status);
  2348. return Status;
  2349. }
  2350. //
  2351. // the store syncrhonizer: syncrhonizes roots that we already know of.
  2352. // Note that we could be racing with a delete: in the worst case we will
  2353. // resync the same root more than once.
  2354. //
  2355. VOID
  2356. DfsStore::StoreSynchronizer()
  2357. {
  2358. ULONG RootNum = 0;
  2359. DFSSTATUS Status = ERROR_SUCCESS;
  2360. DfsRootFolder *pRoot = NULL;
  2361. while (Status != ERROR_NOT_FOUND)
  2362. {
  2363. Status = FindNextRoot(RootNum++, &pRoot);
  2364. if (Status == ERROR_SUCCESS)
  2365. {
  2366. Status = pRoot->Synchronize();
  2367. DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "Root %p Synchronize Status %x\n", this, Status);
  2368. pRoot->ReleaseReference();
  2369. }
  2370. }
  2371. return NOTHING;
  2372. }
  2373. DFSSTATUS
  2374. DfsStore::LoadServerSiteDataPerRoot(void)
  2375. {
  2376. DFSSTATUS Status = ERROR_SUCCESS;
  2377. DfsRootFolder *pRoot = NULL;
  2378. Status = AcquireReadLock();
  2379. if ( Status != ERROR_SUCCESS )
  2380. {
  2381. return Status;
  2382. }
  2383. pRoot = _DfsRootList;
  2384. if(pRoot != NULL)
  2385. {
  2386. do
  2387. {
  2388. pRoot->PreloadServerSiteData();
  2389. pRoot = pRoot->pNextRoot;
  2390. } while ( pRoot != _DfsRootList );
  2391. }
  2392. ReleaseLock();
  2393. return Status;
  2394. }