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.

3995 lines
122 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 2000, Microsoft Corporation
  4. //
  5. // File: DfsRootFolder.cxx
  6. //
  7. // Contents: implements the base DFS Folder class
  8. //
  9. // Classes: DfsRootFolder.
  10. //
  11. // History: Dec. 8 2000, Author: udayh
  12. //
  13. //-----------------------------------------------------------------------------
  14. #include "DfsRootFolder.hxx"
  15. #include "dfsfilterapi.hxx"
  16. #include "rpc.h"
  17. #include "rpcdce.h"
  18. #include "DfsStore.hxx"
  19. #include "srvfsctl.h" //for calling into srv.sys
  20. #include "dfsfsctl.h"
  21. #include "DfsReparse.hxx"
  22. //
  23. // logging includes.
  24. //
  25. #include "DfsRootFolder.tmh"
  26. #define FILETIMETO64(_f) (*(UINT64 *)(&(_f)))
  27. LPWSTR DFSRENAMEPREFIX = L"DFS.";
  28. ULONG DFSDIRWHACKQOFFSET = 4;
  29. extern "C" {
  30. DWORD
  31. I_NetDfsIsThisADomainName(
  32. IN LPWSTR wszName);
  33. }
  34. NTSTATUS
  35. StripAndReturnLastPathComponent(
  36. PUNICODE_STRING pPath,
  37. PUNICODE_STRING pLeaf) ;
  38. DFSSTATUS
  39. SendShareToSrv(PUNICODE_STRING pShareName,
  40. BOOLEAN fAttach) ;
  41. //+-------------------------------------------------------------------------
  42. //
  43. // Function: DfsRootFolder - Contstruct for the rootFolder class
  44. //
  45. // Arguments: NameContext - the Dfs Name context
  46. // pLogicalShare - the Logical Share name
  47. // ObType - the object type. Set to the derived class type.
  48. // pStatus - status of this call.
  49. //
  50. // Returns: NONE
  51. //
  52. // Description: This routine initializes the class variables of the
  53. // the root folder, and initialize the name context and
  54. // logical share name to the passed in values.
  55. // It also allocated and initializes the lock for the root
  56. // folder, as well as all the locks that will be assigned
  57. // to the child folders.
  58. // We then create a metadata name table and a logical namespace
  59. // prefix table.
  60. //
  61. //--------------------------------------------------------------------------
  62. DfsRootFolder::DfsRootFolder(
  63. IN LPWSTR NameContext,
  64. IN LPWSTR RootRegKeyNameString,
  65. IN PUNICODE_STRING pLogicalShare,
  66. IN PUNICODE_STRING pPhysicalShare,
  67. IN DfsObjectTypeEnumeration ObType,
  68. OUT DFSSTATUS *pStatus ) : DfsFolder (NULL,
  69. NULL,
  70. ObType )
  71. {
  72. ULONG LockNum = 0;
  73. DFSSTATUS Status = ERROR_SUCCESS;
  74. DfsRtlInitUnicodeStringEx( &_DfsNameContext, NULL );
  75. DfsRtlInitUnicodeStringEx( &_LogicalShareName, NULL );
  76. DfsRtlInitUnicodeStringEx( &_RootRegKeyName, NULL );
  77. DfsRtlInitUnicodeStringEx( &_PhysicalShareName, NULL );
  78. DfsRtlInitUnicodeStringEx( &_ShareFilePathName, NULL );
  79. DfsRtlInitUnicodeStringEx( &_DirectoryCreateRootPathName, NULL );
  80. DfsRtlInitUnicodeStringEx( &_DfsVisibleContext, NULL );
  81. _DirectoryCreateError = STATUS_SUCCESS;
  82. _ShareAcquireStatus = STATUS_SUCCESS;
  83. _pMetadataNameTable = NULL;
  84. _pLogicalPrefixTable = NULL;
  85. _IgnoreNameContext = FALSE;
  86. _CreateDirectories = DfsCheckCreateDirectories();
  87. pStatistics = NULL;
  88. _pChildLocks = NULL;
  89. _pRootLock = NULL;
  90. _ChildCount = 0;
  91. _CurrentErrors = 0;
  92. _RootFlags = 0;
  93. _PrefetchNeeded = FALSE;
  94. _LogicalShareAddedToTable = FALSE;
  95. _RootFlavor = 0;
  96. _fRootLockInit = FALSE;
  97. _fpLockInit = FALSE;
  98. _TooManyEventLogErrors = FEWERRORS_ON_ROOT;
  99. ZeroMemory(&_fChildLocksInit, sizeof(_fChildLocksInit));
  100. Status = DfsCreateUnicodeStringFromString( &_DfsNameContext, NameContext );
  101. if ( Status == ERROR_SUCCESS )
  102. {
  103. DfsGetNetbiosName( &_DfsNameContext, &_DfsNetbiosNameContext, NULL );
  104. Status = DfsCreateUnicodeString( &_LogicalShareName, pLogicalShare );
  105. }
  106. if ( Status == ERROR_SUCCESS )
  107. {
  108. Status = DfsCreateUnicodeStringFromString( &_RootRegKeyName,
  109. RootRegKeyNameString );
  110. }
  111. if ( Status == ERROR_SUCCESS )
  112. {
  113. Status = DfsCreateUnicodeString( &_PhysicalShareName,
  114. pPhysicalShare );
  115. }
  116. if ( Status == ERROR_SUCCESS )
  117. {
  118. pStatistics = new DfsStatistics();
  119. if (pStatistics == NULL)
  120. {
  121. Status = ERROR_NOT_ENOUGH_MEMORY;
  122. }
  123. }
  124. if ( Status == ERROR_SUCCESS )
  125. {
  126. _pRootLock = new CRITICAL_SECTION;
  127. if ( _pRootLock == NULL )
  128. {
  129. Status = ERROR_NOT_ENOUGH_MEMORY;
  130. }
  131. }
  132. if ( Status == ERROR_SUCCESS )
  133. {
  134. _fRootLockInit = (BOOLEAN) InitializeCriticalSectionAndSpinCount( _pRootLock, 0);
  135. if(!_fRootLockInit)
  136. {
  137. Status = GetLastError();
  138. }
  139. }
  140. if ( Status == ERROR_SUCCESS )
  141. {
  142. _pLock = new CRITICAL_SECTION;
  143. if ( _pLock == NULL )
  144. {
  145. Status = ERROR_NOT_ENOUGH_MEMORY;
  146. }
  147. }
  148. if ( Status == ERROR_SUCCESS )
  149. {
  150. _fpLockInit = (BOOLEAN) InitializeCriticalSectionAndSpinCount( _pLock, DFS_CRIT_SPIN_COUNT );
  151. if(!_fpLockInit)
  152. {
  153. Status = GetLastError();
  154. }
  155. if(Status == ERROR_SUCCESS)
  156. {
  157. _Flags = DFS_FOLDER_ROOT;
  158. //
  159. // Allocate the child locks, and initiailize them.
  160. //
  161. _pChildLocks = new CRITICAL_SECTION[ NUMBER_OF_SHARED_LINK_LOCKS ];
  162. if ( _pChildLocks != NULL )
  163. {
  164. for ( LockNum = 0; LockNum < NUMBER_OF_SHARED_LINK_LOCKS; LockNum++ )
  165. {
  166. _fChildLocksInit[LockNum] = (BOOLEAN) InitializeCriticalSectionAndSpinCount( &_pChildLocks[LockNum],DFS_CRIT_SPIN_COUNT );
  167. if(!_fChildLocksInit[LockNum])
  168. {
  169. Status = GetLastError();
  170. break;
  171. }
  172. }
  173. } else
  174. {
  175. Status = ERROR_NOT_ENOUGH_MEMORY;
  176. }
  177. }
  178. }
  179. //
  180. // Initialize the prefix and nametable for this root.
  181. //
  182. if ( Status == ERROR_SUCCESS )
  183. {
  184. Status = DfsInitializePrefixTable( &_pLogicalPrefixTable,
  185. FALSE,
  186. NULL );
  187. }
  188. if ( Status == ERROR_SUCCESS )
  189. {
  190. Status = DfsInitializeNameTable( 0, &_pMetadataNameTable );
  191. }
  192. //
  193. // We have not assigned any of the child locks: set the lock index
  194. // to 0. This index provides us a mechanism of allocating locks
  195. // to the child folders in a round robin way.
  196. //
  197. _ChildLockIndex = 0;
  198. _LocalCreate = FALSE;
  199. //
  200. // we start by assuming we have to use the PDC for AD Blobs.
  201. //
  202. _RootScalability = FALSE;
  203. pPrevRoot = pNextRoot = NULL;
  204. *pStatus = Status;
  205. }
  206. //+-------------------------------------------------------------------------
  207. //
  208. // Function: CreateLinkFolder - Create a DfsFolder and initialize it.
  209. //
  210. // Arguments: ChildName - metadata name of the child
  211. // pLinkName - the logical namespace name, relative to root
  212. // ppChildFolder - the returned child folder
  213. //
  214. // Returns: Status: Success or error status
  215. //
  216. // Description: This routine Creates a link folder and adds it to the
  217. // parent Root's table.
  218. //
  219. //--------------------------------------------------------------------------
  220. DFSSTATUS
  221. DfsRootFolder::CreateLinkFolder(
  222. IN LPWSTR ChildName,
  223. IN PUNICODE_STRING pLinkName,
  224. OUT DfsFolder **ppChildFolder,
  225. IN BOOLEAN CalledByApi )
  226. {
  227. DfsFolder *pChildFolder = NULL;
  228. DFSSTATUS Status = ERROR_SUCCESS;
  229. const TCHAR * apszSubStrings[4];
  230. DFS_TRACE_LOW( REFERRAL_SERVER, "Create Link Folder: MetaName %ws, Link %wZ\n",
  231. ChildName, pLinkName );
  232. //
  233. // Create a new child folder. Allocate a lock for this child
  234. // and pass the lock along to the Folder constructor.
  235. //
  236. pChildFolder = new DfsFolder (this,
  237. GetChildLock() );
  238. if ( pChildFolder == NULL )
  239. {
  240. Status = ERROR_NOT_ENOUGH_MEMORY;
  241. } else
  242. {
  243. //
  244. // We successfully created the folder. Now set the metadata
  245. // and logical name of the child folder.
  246. //
  247. Status = pChildFolder->InitializeMetadataName( ChildName );
  248. if ( Status == ERROR_SUCCESS )
  249. {
  250. Status = pChildFolder->InitializeLogicalName( pLinkName );
  251. }
  252. }
  253. if ( Status == ERROR_SUCCESS )
  254. {
  255. //
  256. // We now acquire the child folder's write lock, and insert
  257. // the child into the parent's metadata and logical namespace
  258. // tables.
  259. // When adding/removing the child in one of these tables,
  260. // it is necessary to acquire the child folder lock since
  261. // we are setting state in the folder indicating whether the
  262. // child is in any of these tables.
  263. //
  264. Status = pChildFolder->AcquireWriteLock();
  265. if ( Status == ERROR_SUCCESS )
  266. {
  267. Status = InsertLinkFolderInMetadataTable( pChildFolder );
  268. if ( Status == ERROR_SUCCESS )
  269. {
  270. IncrementChildCount();
  271. Status = InsertLinkFolderInLogicalTable( pChildFolder );
  272. }
  273. pChildFolder->ReleaseLock();
  274. }
  275. }
  276. if (Status == ERROR_SUCCESS)
  277. {
  278. DFSSTATUS DfStatus;
  279. DfStatus = SetupLinkReparsePoint( pChildFolder->GetFolderLogicalNameString() );
  280. if(DfStatus != ERROR_SUCCESS)
  281. {
  282. apszSubStrings[0] = pChildFolder->GetFolderLogicalNameString();
  283. apszSubStrings[1] = GetDirectoryCreatePathName()->Buffer;
  284. GenerateEventLog(DFS_ERROR_CREATE_REPARSEPOINT_FAILURE,
  285. 2,
  286. apszSubStrings,
  287. DfStatus);
  288. }
  289. if(CalledByApi)
  290. {
  291. Status = DfStatus;
  292. }
  293. DFS_TRACE_ERROR_LOW(DfStatus, REFERRAL_SERVER, "[%!FUNC!]Setup link reparse point child %p, link %wZ, Status %x\n",
  294. pChildFolder, pLinkName, Status);
  295. }
  296. //
  297. // If we are successful, return the newly created child folder.
  298. // We currently have a reference on the folder (the reference on
  299. // the folder when the folder was created)
  300. //
  301. // If we encountered an error, and the childFolder has been created,
  302. // get rid of out reference on this folder. This will usually
  303. // destroy the childFolder.
  304. //
  305. //
  306. if ( Status == ERROR_SUCCESS )
  307. {
  308. *ppChildFolder = pChildFolder;
  309. pStatistics->UpdateLinkAdded();
  310. LoadServerSiteData(pChildFolder);
  311. } else
  312. {
  313. if ( pChildFolder != NULL )
  314. {
  315. pChildFolder->ReleaseReference();
  316. }
  317. }
  318. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Create Link Folder: MetaName %ws, Child %p Status %x\n",
  319. ChildName, pChildFolder, Status );
  320. return Status;
  321. }
  322. //+-------------------------------------------------------------------------
  323. //
  324. // Function: UpdateLinkFolder - Update a DfsFolder.
  325. //
  326. // Arguments: ChildName - metadata name of the child
  327. // pLinkName - the logical namespace name, relative to root
  328. // pChildFolder - the child folder
  329. //
  330. // Returns: Status: Success or error status
  331. //
  332. // Description: This routine TBD
  333. //
  334. //--------------------------------------------------------------------------
  335. DFSSTATUS
  336. DfsRootFolder::UpdateLinkFolder(
  337. IN LPWSTR ChildName,
  338. IN PUNICODE_STRING pLinkName,
  339. IN DfsFolder *pChildFolder )
  340. {
  341. BOOLEAN Removed = FALSE;
  342. UNREFERENCED_PARAMETER(ChildName);
  343. UNREFERENCED_PARAMETER(pLinkName);
  344. pChildFolder->RemoveReferralData( NULL, &Removed );
  345. pStatistics->UpdateLinkModified();
  346. if (Removed == TRUE)
  347. {
  348. pStatistics->UpdateForcedCacheFlush();
  349. }
  350. LoadServerSiteData(pChildFolder);
  351. //
  352. // Create directories too. Delete old directories.
  353. //
  354. return ERROR_SUCCESS;
  355. }
  356. //+-------------------------------------------------------------------------
  357. //
  358. // Function: RemoveAllLinkFolders - Remove all folders of this root
  359. //
  360. // Arguments: None
  361. //
  362. // Returns: Status: Success or error status
  363. //
  364. // Description: This routine TBD
  365. //
  366. //--------------------------------------------------------------------------
  367. DFSSTATUS
  368. DfsRootFolder::RemoveAllLinkFolders(
  369. BOOLEAN IsPermanent)
  370. {
  371. DFSSTATUS Status = ERROR_SUCCESS;
  372. DfsFolder *pChildFolder;
  373. ULONG Count = 0;
  374. while (Status == ERROR_SUCCESS)
  375. {
  376. Status = LookupFolder(&pChildFolder);
  377. if (Status == ERROR_SUCCESS)
  378. {
  379. Status = RemoveLinkFolder(pChildFolder,
  380. IsPermanent);
  381. pChildFolder->ReleaseReference();
  382. Count++;
  383. }
  384. }
  385. DFS_TRACE_ERROR_HIGH( Status, REFERRAL_SERVER, "Remove all link folders Count %d Status %x\n",
  386. Count,
  387. Status);
  388. return Status;
  389. }
  390. //+-------------------------------------------------------------------------
  391. //
  392. // Function: RemoveLinkFolder - Update a DfsFolder.
  393. //
  394. // Arguments: ChildName - metadata name of the child
  395. // pLinkName - the logical namespace name, relative to root
  396. // pChildFolder - the child folder
  397. //
  398. // Returns: Status: Success or error status
  399. //
  400. // Description: This routine TBD
  401. //
  402. //--------------------------------------------------------------------------
  403. DFSSTATUS
  404. DfsRootFolder::RemoveLinkFolder(
  405. IN DfsFolder *pChildFolder,
  406. BOOLEAN IsPermanent )
  407. {
  408. DFSSTATUS Status = ERROR_SUCCESS;
  409. if (IsPermanent == TRUE)
  410. {
  411. //
  412. // try to tear down the link reparse point: return status ignored.
  413. //
  414. Status = TeardownLinkReparsePoint( pChildFolder->GetFolderLogicalNameString() );
  415. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!] Tear down reparse for %p, status %x \n", pChildFolder, Status );
  416. }
  417. Status = pChildFolder->AcquireWriteLock();
  418. if ( Status == ERROR_SUCCESS )
  419. {
  420. Status = RemoveLinkFolderFromMetadataTable( pChildFolder );
  421. if ( Status == ERROR_SUCCESS )
  422. {
  423. DFSSTATUS LinkRemoveStatus;
  424. pChildFolder->SetFlag( DFS_FOLDER_DELETE_IN_PROGRESS );
  425. DecrementChildCount();
  426. LinkRemoveStatus = RemoveLinkFolderFromLogicalTable( pChildFolder );
  427. DFS_TRACE_ERROR_LOW(LinkRemoveStatus, REFERRAL_SERVER, "Remove Link From logical %p, status %x \n", pChildFolder, LinkRemoveStatus );
  428. }
  429. pChildFolder->ReleaseLock();
  430. }
  431. if (Status == ERROR_SUCCESS)
  432. {
  433. pStatistics->UpdateLinkDeleted();
  434. }
  435. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Remove Link Folder %p, status %x \n", pChildFolder, Status );
  436. return Status;
  437. }
  438. //+-------------------------------------------------------------------------
  439. //
  440. // Function: SetDfsReparsePoint
  441. //
  442. // Arguments: DirHandle - handle on open directory
  443. //
  444. // Returns: SUCCESS or error
  445. //
  446. // Description: This routine takes a handle to an open directory and
  447. // makes that directory a reparse point with the DFS tag
  448. //
  449. //--------------------------------------------------------------------------
  450. NTSTATUS
  451. DfsRootFolder::SetDfsReparsePoint(
  452. IN HANDLE DirHandle )
  453. {
  454. NTSTATUS NtStatus;
  455. REPARSE_DATA_BUFFER ReparseDataBuffer;
  456. IO_STATUS_BLOCK IoStatusBlock;
  457. //
  458. // Attempt to set a reparse point on the directory
  459. //
  460. RtlZeroMemory( &ReparseDataBuffer, sizeof(ReparseDataBuffer) );
  461. ReparseDataBuffer.ReparseTag = IO_REPARSE_TAG_DFS;
  462. ReparseDataBuffer.ReparseDataLength = 0;
  463. NtStatus = NtFsControlFile( DirHandle,
  464. NULL,
  465. NULL,
  466. NULL,
  467. &IoStatusBlock,
  468. FSCTL_SET_REPARSE_POINT,
  469. &ReparseDataBuffer,
  470. REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataBuffer.ReparseDataLength,
  471. NULL,
  472. 0 );
  473. return NtStatus;
  474. }
  475. //+-------------------------------------------------------------------------
  476. //
  477. // Function: MorphLinkCollision
  478. //
  479. // Arguments: DirectoryName - Name of directory to morph.
  480. //
  481. // Returns: SUCCESS or error
  482. //
  483. // Description: This routine takes a NT pathname to a directory. It
  484. // renames that directory with a morphed name.
  485. //
  486. //--------------------------------------------------------------------------
  487. DFSSTATUS
  488. DfsRootFolder::MorphLinkCollision(
  489. PUNICODE_STRING ParentDirectory,
  490. PUNICODE_STRING DirectoryToRename )
  491. {
  492. DFSSTATUS Status = ERROR_SUCCESS;
  493. Status = RenamePath(ParentDirectory,
  494. DirectoryToRename);
  495. return Status;
  496. }
  497. DFSSTATUS
  498. DfsRootFolder::TeardownLinkReparsePoint(
  499. LPWSTR LinkNameString )
  500. {
  501. NTSTATUS NtStatus = STATUS_SUCCESS;
  502. DFSSTATUS Status = ERROR_SUCCESS;
  503. HANDLE DirectoryHandle = NULL;
  504. UNICODE_STRING LinkName;
  505. Status = DfsRtlInitUnicodeStringEx( &LinkName, LinkNameString);
  506. if ((IsRootFolderShareAcquired() == TRUE) &&
  507. (Status == ERROR_SUCCESS))
  508. {
  509. NtStatus = DfsOpenDirectory ( GetDirectoryCreatePathName(),
  510. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  511. NULL,
  512. &DirectoryHandle,
  513. NULL );
  514. if (NtStatus == STATUS_SUCCESS)
  515. {
  516. //
  517. // Delete empty parent directories as well.
  518. //
  519. NtStatus = DfsDeleteLinkReparsePointAndParents( &LinkName, DirectoryHandle );
  520. DfsCloseDirectory( DirectoryHandle );
  521. }
  522. Status = RtlNtStatusToDosError(NtStatus);
  523. }
  524. return Status;
  525. }
  526. DFSSTATUS
  527. DfsRootFolder::SetupLinkReparsePoint(
  528. LPWSTR LinkNameString )
  529. {
  530. NTSTATUS NtStatus = STATUS_SUCCESS;
  531. DFSSTATUS Status = ERROR_SUCCESS;
  532. HANDLE DirectoryHandle = NULL;
  533. UNICODE_STRING LinkName;
  534. //
  535. // We don't want to create any reparse points
  536. // if we're not supposed to.
  537. //
  538. if (IsRootCreateDirectories() == FALSE)
  539. return ERROR_SUCCESS;
  540. Status = GetRootShareAcquireStatus();
  541. if(Status == ERROR_SUCCESS)
  542. {
  543. Status = DfsRtlInitUnicodeStringEx( &LinkName, LinkNameString);
  544. if (Status == ERROR_SUCCESS)
  545. {
  546. NtStatus = DfsOpenDirectory ( GetDirectoryCreatePathName(),
  547. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  548. NULL,
  549. &DirectoryHandle,
  550. NULL );
  551. if (NtStatus == STATUS_SUCCESS)
  552. {
  553. Status = CreateLinkReparsePoint( &LinkName,
  554. DirectoryHandle );
  555. DfsCloseDirectory( DirectoryHandle );
  556. }
  557. else
  558. {
  559. Status = RtlNtStatusToDosError(NtStatus);
  560. }
  561. }
  562. }
  563. if (Status != ERROR_SUCCESS)
  564. {
  565. SetLastCreateDirectoryError(Status);
  566. }
  567. return Status;
  568. }
  569. DFSSTATUS
  570. DfsRootFolder::CreateLinkReparsePoint(
  571. PUNICODE_STRING pLinkName,
  572. HANDLE RelativeHandle )
  573. {
  574. NTSTATUS NtStatus = STATUS_SUCCESS;
  575. DFSSTATUS MorphStatus = ERROR_SUCCESS;
  576. DFSSTATUS DosStatus = ERROR_SUCCESS;
  577. ULONG ShareMode = 0;
  578. ULONG RetryCount = 0;
  579. HANDLE DirectoryHandle = INVALID_HANDLE_VALUE;
  580. BOOLEAN IsNewlyCreated = FALSE;
  581. UNICODE_STRING LastComp;
  582. Retry:
  583. DfsRtlInitUnicodeStringEx(&LastComp, NULL);
  584. NtStatus = CreateLinkDirectories( pLinkName,
  585. RelativeHandle,
  586. &DirectoryHandle,
  587. &IsNewlyCreated,
  588. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE );
  589. if (NtStatus == STATUS_SUCCESS)
  590. {
  591. NtStatus = SetDfsReparsePoint( DirectoryHandle);
  592. NtClose( DirectoryHandle);
  593. if((RetryCount == 0) && (NtStatus == STATUS_DIRECTORY_NOT_EMPTY))
  594. {
  595. StripAndReturnLastPathComponent(pLinkName, &LastComp);
  596. MorphStatus = MorphLinkCollision(pLinkName, &LastComp);
  597. AddNextPathComponent(pLinkName);
  598. if(MorphStatus == ERROR_SUCCESS)
  599. {
  600. RetryCount++;
  601. goto Retry;
  602. }
  603. }
  604. }
  605. DosStatus = RtlNtStatusToDosError(NtStatus);
  606. DFS_TRACE_ERROR_HIGH(DosStatus, REFERRAL_SERVER, "[%!FUNC!] DirectoryName of interest %wZ: Create Reparse point Status %x\n",
  607. pLinkName,
  608. DosStatus);
  609. return DosStatus;
  610. }
  611. NTSTATUS
  612. DfsRootFolder::CreateLinkDirectories(
  613. PUNICODE_STRING pLinkName,
  614. HANDLE RelativeHandle,
  615. PHANDLE pDirectoryHandle,
  616. PBOOLEAN pIsNewlyCreated,
  617. ULONG ShareMode )
  618. {
  619. NTSTATUS NtStatus = STATUS_SUCCESS;
  620. DFSSTATUS Status = ERROR_SUCCESS;
  621. HANDLE CurrentDirectory = INVALID_HANDLE_VALUE;
  622. HANDLE LocalRelativeHandle = INVALID_HANDLE_VALUE;
  623. BOOLEAN DfsMountPoint = FALSE;
  624. BOOLEAN NewlyCreated = FALSE;
  625. UNICODE_STRING RemainingName;
  626. UNICODE_STRING TempString;
  627. UNICODE_STRING DirectoryToCreate;
  628. UNICODE_STRING TrackDirectory;
  629. TrackDirectory = *pLinkName;
  630. TrackDirectory.Length = 0;
  631. LocalRelativeHandle = RelativeHandle;
  632. NtStatus = DfsGetFirstComponent(pLinkName,
  633. &DirectoryToCreate,
  634. &RemainingName);
  635. while ( NtStatus == STATUS_SUCCESS)
  636. {
  637. NtStatus = DfsOpenDirectory( &DirectoryToCreate,
  638. ShareMode,
  639. LocalRelativeHandle,
  640. &CurrentDirectory,
  641. &NewlyCreated );
  642. if (NtStatus == STATUS_SUCCESS)
  643. {
  644. AddNextPathComponent(&TrackDirectory);
  645. if(LocalRelativeHandle != RelativeHandle)
  646. {
  647. DfsCloseDirectory( LocalRelativeHandle );
  648. }
  649. LocalRelativeHandle = CurrentDirectory;
  650. CurrentDirectory = INVALID_HANDLE_VALUE;
  651. if(RemainingName.Length == 0)
  652. {
  653. break;
  654. }
  655. NtStatus = DfsGetNextComponent(&RemainingName,
  656. &DirectoryToCreate,
  657. &TempString);
  658. RemainingName = TempString;
  659. }
  660. else if(NtStatus == STATUS_NOT_A_DIRECTORY)
  661. {
  662. Status = MorphLinkCollision(&TrackDirectory,
  663. &DirectoryToCreate);
  664. if(Status == ERROR_SUCCESS)
  665. {
  666. NtStatus = STATUS_SUCCESS;
  667. }
  668. }
  669. }
  670. if (NtStatus == STATUS_SUCCESS)
  671. {
  672. IsDirectoryMountPoint(LocalRelativeHandle,
  673. &DfsMountPoint);
  674. if(DfsMountPoint)
  675. {
  676. NtStatus = STATUS_DIRECTORY_IS_A_REPARSE_POINT;
  677. if(LocalRelativeHandle != INVALID_HANDLE_VALUE)
  678. {
  679. DfsCloseDirectory( LocalRelativeHandle );
  680. LocalRelativeHandle = INVALID_HANDLE_VALUE;
  681. }
  682. }
  683. else
  684. {
  685. if(pDirectoryHandle)
  686. {
  687. *pDirectoryHandle = LocalRelativeHandle;
  688. }
  689. else
  690. {
  691. DfsCloseDirectory( LocalRelativeHandle );
  692. }
  693. if(pIsNewlyCreated)
  694. {
  695. *pIsNewlyCreated = NewlyCreated;
  696. }
  697. }
  698. }
  699. else
  700. {
  701. if(LocalRelativeHandle != RelativeHandle)
  702. {
  703. if(LocalRelativeHandle != INVALID_HANDLE_VALUE)
  704. {
  705. DfsCloseDirectory( LocalRelativeHandle );
  706. LocalRelativeHandle = INVALID_HANDLE_VALUE;
  707. }
  708. }
  709. }
  710. DFS_TRACE_ERROR_LOW(NtStatus, REFERRAL_SERVER, "CreateLinkDirectory: %wZ: Status %x\n",
  711. pLinkName, NtStatus );
  712. return NtStatus;
  713. }
  714. #define WHACKWHACKDOTWHACKDIROFFSET 14
  715. //the code below attempt to see if the directory, pointed to by pDirectory
  716. //name is a mount point. The name comes in looking like \\??\\c:\directoryname.
  717. //To see if this name is a mount point, we have to open up the parent directory,
  718. //and then try to create the subdirectory. In the name above, \\??\\c:\ is the
  719. //parent directory and directoryname is the subdirectory.WHACKWHACKDOTWHACKDIROFFSET
  720. //is the length of \\??\\c:\. This is the RootDir in the below code. The remaining
  721. //name is the rest of the string
  722. NTSTATUS
  723. DfsRootFolder::IsRootShareMountPoint(PUNICODE_STRING pDirectoryName)
  724. {
  725. NTSTATUS NtStatus = STATUS_SUCCESS;
  726. HANDLE DirHandle = NULL;
  727. OBJECT_ATTRIBUTES ObjectAttributes;
  728. IO_STATUS_BLOCK IoStatusBlock;
  729. UNICODE_STRING RemainingName;
  730. UNICODE_STRING RootDir;
  731. RootDir = RemainingName = * pDirectoryName;
  732. //setup the root directory length (i.e \\??\\c:\)
  733. RootDir.Length = (USHORT) WHACKWHACKDOTWHACKDIROFFSET;
  734. //next, setup the renmaining piece of the directory
  735. RemainingName.Length -= (USHORT) WHACKWHACKDOTWHACKDIROFFSET;
  736. RemainingName.MaximumLength -= (USHORT)WHACKWHACKDOTWHACKDIROFFSET;
  737. RemainingName.Buffer = &RemainingName.Buffer[WHACKWHACKDOTWHACKDIROFFSET/sizeof(WCHAR)];
  738. //open the root directory
  739. InitializeObjectAttributes ( &ObjectAttributes,
  740. &RootDir,
  741. OBJ_CASE_INSENSITIVE, //Attributes
  742. NULL, //Root handle
  743. NULL ); //Security descriptor.
  744. NtStatus = NtOpenFile( &DirHandle,
  745. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  746. &ObjectAttributes,
  747. &IoStatusBlock,
  748. FILE_SHARE_READ | FILE_SHARE_WRITE,
  749. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT );
  750. if(NtStatus == STATUS_SUCCESS)
  751. {
  752. //now, if there is still a path left, try to create this directory.
  753. if(RemainingName.Length != 0)
  754. {
  755. NtStatus = CreateLinkDirectories(&RemainingName,
  756. DirHandle,
  757. NULL,
  758. NULL,
  759. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE);
  760. }
  761. CloseHandle(DirHandle);
  762. }
  763. return NtStatus;
  764. }
  765. //+-------------------------------------------------------------------------
  766. //
  767. // Function: AcquireRootShareDirectory
  768. //
  769. // Arguments: none
  770. //
  771. // Returns: Status: success if we passed all checks.
  772. //
  773. // Description: This routine checks to see if the share backing the
  774. // the dfs root actually exists. If it does, it confirms
  775. // that the filesystem hosting this directory supports
  776. // reparse points. Finally, it tells the driver to attach
  777. // to this directory.
  778. // If all of this works, we have acquired the root share.
  779. //
  780. //--------------------------------------------------------------------------
  781. DFSSTATUS
  782. DfsRootFolder::AcquireRootShareDirectory(void)
  783. {
  784. NTSTATUS NtStatus = STATUS_SUCCESS;
  785. DFSSTATUS Status = ERROR_SUCCESS;
  786. HANDLE DirHandle = NULL;
  787. PUNICODE_STRING pDirectoryName = NULL;
  788. PUNICODE_STRING pUseShare = NULL;
  789. PUNICODE_STRING pLogicalShare = NULL;
  790. BOOLEAN SubStringMatch = FALSE;
  791. BOOLEAN Inserted = FALSE;
  792. BOOLEAN PhysicalShareInDFS = FALSE;
  793. BOOLEAN DfsMountPoint = FALSE;
  794. OBJECT_ATTRIBUTES ObjectAttributes;
  795. IO_STATUS_BLOCK IoStatusBlock;
  796. ULONG pAttribInfoSize;
  797. PFILE_FS_ATTRIBUTE_INFORMATION pAttribInfo = NULL;
  798. UNICODE_STRING LogicalVol;
  799. const TCHAR * apszSubStrings[4];
  800. ZeroMemory (&LogicalVol, sizeof(LogicalVol));
  801. pUseShare = GetRootPhysicalShareName();
  802. pLogicalShare = GetLogicalShare();
  803. DFS_TRACE_LOW(REFERRAL_SERVER, "[%!FUNC!] AcquireRoot Share called for root %p, name %wZ\n", this, pUseShare);
  804. //
  805. // if either the root share is already acquired, or the library
  806. // was told that we are not interested in creating directories, we
  807. // are done.
  808. //
  809. if ( (IsRootFolderShareAcquired() == TRUE) ||
  810. (IsRootCreateDirectories() == FALSE) )
  811. {
  812. DFS_TRACE_LOW(REFERRAL_SERVER, "Root %p, Share Already acquired\n", this);
  813. return ERROR_SUCCESS;
  814. }
  815. //
  816. // first we get the logical share
  817. // Then we call into initialize directory information to setup the
  818. // physical share path etc.
  819. //
  820. Status = InitializeDirectoryCreateInformation();
  821. //
  822. // If the directory create path is invalid, we are done.
  823. //
  824. if (Status == ERROR_SUCCESS)
  825. {
  826. pDirectoryName = GetDirectoryCreatePathName();
  827. if ( (pDirectoryName == NULL) ||
  828. (pDirectoryName->Buffer == NULL) ||
  829. (pDirectoryName->Length == 0) )
  830. {
  831. Status = ERROR_INVALID_PARAMETER;
  832. }
  833. }
  834. if (Status == ERROR_SUCCESS)
  835. {
  836. //
  837. // Now allocate space to fill the attribute information we
  838. // will query.
  839. // dfsdev: document why we allocate an additional max_path.
  840. //
  841. pAttribInfoSize = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH;
  842. pAttribInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)new BYTE [pAttribInfoSize];
  843. if (pAttribInfo != NULL)
  844. {
  845. InitializeObjectAttributes ( &ObjectAttributes,
  846. pDirectoryName,
  847. OBJ_CASE_INSENSITIVE, //Attributes
  848. NULL, //Root handle
  849. NULL ); //Security descriptor.
  850. NtStatus = NtOpenFile( &DirHandle,
  851. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  852. &ObjectAttributes,
  853. &IoStatusBlock,
  854. FILE_SHARE_READ | FILE_SHARE_WRITE,
  855. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT );
  856. if (NtStatus == STATUS_SUCCESS)
  857. {
  858. //
  859. // Query for the basic information, which has the attributes.
  860. //
  861. NtStatus = NtQueryVolumeInformationFile( DirHandle,
  862. &IoStatusBlock,
  863. pAttribInfo,
  864. pAttribInfoSize,
  865. FileFsAttributeInformation );
  866. if (NtStatus == STATUS_SUCCESS)
  867. {
  868. //
  869. // If the attributes indicate reparse point, we have a reparse
  870. // point directory on our hands.
  871. //
  872. if ( (pAttribInfo->FileSystemAttributes & FILE_SUPPORTS_REPARSE_POINTS) == 0)
  873. {
  874. NtStatus = STATUS_NOT_SUPPORTED;
  875. apszSubStrings[0] = pUseShare->Buffer;
  876. apszSubStrings[1] = pDirectoryName->Buffer;
  877. GenerateEventLog(DFS_ERROR_UNSUPPORTED_FILESYSTEM,
  878. 2,
  879. apszSubStrings,
  880. 0);
  881. }
  882. }
  883. CloseHandle (DirHandle);
  884. }
  885. else
  886. {
  887. Status = RtlNtStatusToDosError(NtStatus);
  888. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!] - NTOPEN failed share for root %p, (%wZ) (%wZ) status %x NtStatus %x\n",
  889. this, pUseShare, pDirectoryName, Status, NtStatus);
  890. }
  891. if (NtStatus == STATUS_SUCCESS)
  892. {
  893. NtStatus = IsRootShareMountPoint(pDirectoryName);
  894. }
  895. if( NtStatus != STATUS_SUCCESS)
  896. {
  897. Status = RtlNtStatusToDosError(NtStatus);
  898. }
  899. delete [] pAttribInfo;
  900. pAttribInfo = NULL;
  901. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "AcquireRoot - IsRootShareMountPoint failed share for root %p, (%wZ) (%wZ) status %x NtStatus %x\n",
  902. this, pUseShare, pDirectoryName, Status, NtStatus);
  903. }
  904. else {
  905. Status = ERROR_NOT_ENOUGH_MEMORY;
  906. }
  907. }
  908. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!] Root %p, Share check status %x\n", this, Status);
  909. //
  910. // Now check if we already know about parts of this path.
  911. // if there is overlap with other paths that we already know about,
  912. // we cannot handle this root, so reject it.
  913. //
  914. if (Status == ERROR_SUCCESS)
  915. {
  916. Status = DfsAddKnownDirectoryPath( pDirectoryName,
  917. pUseShare );
  918. if (Status == ERROR_SUCCESS)
  919. {
  920. Inserted = TRUE;
  921. }
  922. else
  923. {
  924. Status = ERROR_BAD_PATHNAME;
  925. apszSubStrings[0] = pUseShare->Buffer;
  926. apszSubStrings[1] = pDirectoryName->Buffer;
  927. GenerateEventLog(DFS_ERROR_OVERLAPPING_DIRECTORIES,
  928. 2,
  929. apszSubStrings,
  930. 0);
  931. }
  932. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "Root %p, Share add known directory status %x\n", this, Status);
  933. }
  934. //
  935. // if we are here: we know this is a reparse point, and we have
  936. // inserted in the user mode database.
  937. // now call into the driver so it may attach to this filesystem.
  938. //
  939. if (Status == ERROR_SUCCESS)
  940. {
  941. Status = DfsUserModeAttachToFilesystem( pDirectoryName,
  942. pUseShare);
  943. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]Root %p, user mode attach status %x\n", this, Status);
  944. if(Status == ERROR_SUCCESS)
  945. {
  946. PhysicalShareInDFS = TRUE;
  947. if (RtlCompareUnicodeString(pUseShare, pLogicalShare, TRUE ))
  948. {
  949. Status = DfsUserModeAttachToFilesystem( &LogicalVol,
  950. pLogicalShare);
  951. if(Status == ERROR_SUCCESS)
  952. {
  953. _LogicalShareAddedToTable = TRUE;
  954. }
  955. }
  956. }
  957. }
  958. if(Status == ERROR_SUCCESS)
  959. {
  960. Status = SendShareToSrv(pUseShare, TRUE);
  961. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]Root %p, user mode SendShareToSrv status %x\n", this, Status);
  962. }
  963. //
  964. // if we are successful, we acquired the root share, now mark
  965. // our state accordingly.
  966. //
  967. if (Status == ERROR_SUCCESS)
  968. {
  969. SetRootFolderShareAcquired();
  970. SetRootShareAcquireStatus(Status);
  971. }
  972. else
  973. {
  974. //
  975. // otherwise, clear up some of the work we just did.
  976. //
  977. ClearRootFolderShareAcquired();
  978. SetRootShareAcquireStatus(Status);
  979. if (Inserted == TRUE)
  980. {
  981. DfsRemoveKnownDirectoryPath( pDirectoryName,
  982. pUseShare);
  983. }
  984. if(PhysicalShareInDFS == TRUE)
  985. { DFSSTATUS LocalStatus = ERROR_SUCCESS;
  986. LocalStatus = DfsUserModeDetachFromFilesystem( pDirectoryName,
  987. pUseShare);
  988. }
  989. if(_LogicalShareAddedToTable == TRUE)
  990. { DFSSTATUS LocalStatus = ERROR_SUCCESS;
  991. LocalStatus = DfsUserModeDetachFromFilesystem( &LogicalVol,
  992. pUseShare);
  993. }
  994. }
  995. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]AcquireRoot share for root %p, (%wZ) status %x\n",
  996. this, pUseShare, Status);
  997. return Status;
  998. }
  999. //+-------------------------------------------------------------------------
  1000. //
  1001. // Function: ReleaseRootShareDirectory
  1002. //
  1003. // Arguments: none
  1004. //
  1005. // Returns: Status: success if we are successful
  1006. //
  1007. // Description: This routine checks to see if the share backing the
  1008. // the dfs root was acquired by us earlier. If so, we
  1009. // tell the driver to releast its reference on this
  1010. // share, and remove this information from our tables,
  1011. //
  1012. //--------------------------------------------------------------------------
  1013. DFSSTATUS
  1014. DfsRootFolder::ReleaseRootShareDirectory(void)
  1015. {
  1016. NTSTATUS NtStatus = STATUS_SUCCESS;
  1017. DFSSTATUS Status = ERROR_SUCCESS;
  1018. PUNICODE_STRING pDirectoryName = NULL;
  1019. PUNICODE_STRING pUseShare = NULL;
  1020. PUNICODE_STRING pLogicalShare = NULL;
  1021. PVOID pData = NULL;
  1022. BOOLEAN SubStringMatch = FALSE;
  1023. UNICODE_STRING LogicalVol;
  1024. DFS_TRACE_LOW(REFERRAL_SERVER, "[%!FUNC!]ReleaseRoot share for root %p\n", this);
  1025. if (IsRootFolderShareAcquired() == TRUE)
  1026. {
  1027. //
  1028. // get the logical share, and the physical directory backing the
  1029. // share.
  1030. //
  1031. ZeroMemory (&LogicalVol, sizeof(LogicalVol));
  1032. pUseShare = GetRootPhysicalShareName();
  1033. pLogicalShare = GetLogicalShare();
  1034. pDirectoryName = GetDirectoryCreatePathName();
  1035. if ( (pDirectoryName == NULL) ||
  1036. (pDirectoryName->Buffer == NULL) ||
  1037. (pDirectoryName->Length == 0) )
  1038. {
  1039. Status = ERROR_INVALID_PARAMETER;
  1040. }
  1041. if(Status == ERROR_SUCCESS)
  1042. {
  1043. Status = SendShareToSrv(pUseShare, FALSE);
  1044. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]SendShareToSrv path %wZ, %wZ: Status %x\n",
  1045. pDirectoryName, pUseShare, Status );
  1046. }
  1047. //
  1048. // now, signal the driver to detach itself from this share.
  1049. //dfsdev: if this fails, we are in an inconsistent state, since
  1050. // we just removed it from our table above!
  1051. //
  1052. if (Status == ERROR_SUCCESS)
  1053. {
  1054. Status = DfsUserModeDetachFromFilesystem( pDirectoryName,
  1055. pUseShare);
  1056. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]user mode detach path %wZ, %wZ: Status %x\n",
  1057. pDirectoryName, pUseShare, Status );
  1058. }
  1059. if (Status == ERROR_SUCCESS)
  1060. {
  1061. if(_LogicalShareAddedToTable == TRUE)
  1062. { DFSSTATUS LocalStatus = ERROR_SUCCESS;
  1063. LocalStatus = DfsUserModeDetachFromFilesystem( &LogicalVol,
  1064. pUseShare);
  1065. }
  1066. }
  1067. //
  1068. // now, find the information in our database. if we did not find an
  1069. // exact match, something went wrong and signal that.
  1070. //
  1071. if (Status == ERROR_SUCCESS)
  1072. {
  1073. DFSSTATUS RemoveStatus;
  1074. RemoveStatus = DfsRemoveKnownDirectoryPath( pDirectoryName,
  1075. pUseShare );
  1076. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]RemoveKnownDirectory path %wZ, %wZ: Status %x\n",
  1077. pDirectoryName, pUseShare, RemoveStatus );
  1078. }
  1079. if (Status == ERROR_SUCCESS)
  1080. {
  1081. ClearRootFolderShareAcquired();
  1082. }
  1083. }
  1084. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]Release root share %p, Status %x\n",
  1085. this, Status );
  1086. return Status;
  1087. }
  1088. //+-------------------------------------------------------------------------
  1089. //
  1090. // Function: AddMetadataLink
  1091. //
  1092. // Arguments:
  1093. // pLogicalName: the complete logical unc name of this link.
  1094. // ReplicaServer: the target server for this link.
  1095. // ReplicaPath: the target path on the server.
  1096. // Comment : comment to be associated with this link.
  1097. //
  1098. // Returns: SUCCESS or error
  1099. //
  1100. // Description: This routine Adds a link to the metadata.
  1101. // In future, ReplicaServer and ReplicaPath's
  1102. // can be null, since we will allow links with
  1103. // no targets.
  1104. // dfsdev: make sure we do the right thing for
  1105. // compat.
  1106. //
  1107. // Assumptions: the caller is responsible for mutual exclusion.
  1108. // The caller is also responsible for ensuring
  1109. // this link does not already exist in the
  1110. // the metadata.
  1111. // The caller is also responsible to make sure that this
  1112. // name does not overlap an existing link.
  1113. // (for example if link a/b exisits, link a or a/b/c are
  1114. // overlapping links and should be disallowed.)
  1115. //--------------------------------------------------------------------------
  1116. DFSSTATUS
  1117. DfsRootFolder::AddMetadataLink(
  1118. PUNICODE_STRING pLogicalName,
  1119. LPWSTR ReplicaServer,
  1120. LPWSTR ReplicaPath,
  1121. LPWSTR Comment )
  1122. {
  1123. DFS_METADATA_HANDLE RootHandle = NULL;
  1124. DFSSTATUS Status = ERROR_SUCCESS;
  1125. BOOLEAN IsDomainDfs = FALSE;
  1126. UNICODE_STRING LinkMetadataName;
  1127. UNICODE_STRING VisibleNameContext, UseName;
  1128. DFS_NAME_INFORMATION NameInfo;
  1129. DFS_REPLICA_LIST_INFORMATION ReplicaListInfo;
  1130. DFS_REPLICA_INFORMATION ReplicaInfo;
  1131. UUID NewUid;
  1132. Status = AcquireRootLock();
  1133. if (Status != ERROR_SUCCESS)
  1134. {
  1135. return Status;
  1136. }
  1137. Status = UuidCreate(&NewUid);
  1138. if (Status == ERROR_SUCCESS)
  1139. {
  1140. Status = GetMetadataStore()->GenerateLinkMetadataName( &NewUid,
  1141. &LinkMetadataName);
  1142. }
  1143. if (Status == ERROR_SUCCESS)
  1144. {
  1145. //
  1146. // First get a handle to the
  1147. // metadata. The handle has different meaning to different
  1148. // underlying stores: for example the registry store may
  1149. // use the handle as a key, while the ad store may use the
  1150. // handle as a pointer in some cache.
  1151. //
  1152. Status = GetMetadataHandle( &RootHandle );
  1153. if (Status == ERROR_SUCCESS)
  1154. {
  1155. GetVisibleNameContextLocked( NULL, &VisibleNameContext );
  1156. Status = GetMetadataStore()->GenerateMetadataLogicalName( &VisibleNameContext,
  1157. pLogicalName,
  1158. &UseName );
  1159. if (Status == ERROR_SUCCESS)
  1160. {
  1161. GetMetadataStore()->StoreInitializeNameInformation( &NameInfo,
  1162. &UseName,
  1163. &NewUid,
  1164. Comment );
  1165. if (DfsIsThisARealDfsName(ReplicaServer, ReplicaPath, &IsDomainDfs) == ERROR_SUCCESS)
  1166. {
  1167. NameInfo.Type |= (PKT_ENTRY_TYPE_OUTSIDE_MY_DOM);
  1168. }
  1169. GetMetadataStore()->StoreInitializeReplicaInformation( &ReplicaListInfo,
  1170. &ReplicaInfo,
  1171. ReplicaServer,
  1172. ReplicaPath );
  1173. Status = GetMetadataStore()->AddChild( RootHandle,
  1174. &NameInfo,
  1175. &ReplicaListInfo,
  1176. &LinkMetadataName );
  1177. //
  1178. // if we failed add child, we need to reset the
  1179. // internal state to wipe out any work we did when
  1180. // we were adding the child.
  1181. //
  1182. if (Status != ERROR_SUCCESS)
  1183. {
  1184. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::AddMetadataLink path %wZ, %ws, %ws: Status %x\n",
  1185. pLogicalName, ReplicaServer, ReplicaPath, Status );
  1186. ReSynchronize(TRUE);
  1187. }
  1188. GetMetadataStore()->ReleaseMetadataLogicalName(&UseName );
  1189. //
  1190. // if we successfully added the link, update the link information
  1191. // so that we can pass this out in referrals, and create the appropriate
  1192. // directories.
  1193. //
  1194. if (Status == ERROR_SUCCESS)
  1195. {
  1196. Status = UpdateLinkInformation( RootHandle,
  1197. LinkMetadataName.Buffer,
  1198. TRUE );
  1199. if(Status != ERROR_SUCCESS)
  1200. {
  1201. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::AddMetadataLink (2) path %wZ, %ws, %ws: Status %x\n",
  1202. pLogicalName, ReplicaServer, ReplicaPath, Status );
  1203. }
  1204. }
  1205. }
  1206. //
  1207. // Finally, release the root handle we acquired earlier.
  1208. //
  1209. ReleaseMetadataHandle( RootHandle );
  1210. }
  1211. GetMetadataStore()->ReleaseLinkMetadataName( &LinkMetadataName );
  1212. }
  1213. ReleaseRootLock();
  1214. return Status;
  1215. }
  1216. //+-------------------------------------------------------------------------
  1217. //
  1218. // Function: RemoveMetadataLink
  1219. //
  1220. // Arguments:
  1221. // pLogicalName: the link name relative to root share
  1222. //
  1223. // Returns: SUCCESS or error
  1224. //
  1225. // Description: This routine removes a link from the the metadata.
  1226. //
  1227. // Assumptions: the caller is responsible for mutual exclusion.
  1228. //
  1229. //--------------------------------------------------------------------------
  1230. DFSSTATUS
  1231. DfsRootFolder::RemoveMetadataLink(
  1232. PUNICODE_STRING pLinkName )
  1233. {
  1234. DFSSTATUS Status = ERROR_SUCCESS;
  1235. LPWSTR LinkMetadataName = NULL;
  1236. DfsFolder *pFolder = NULL;
  1237. DFS_METADATA_HANDLE RootHandle;
  1238. UNICODE_STRING Remaining;
  1239. Status = AcquireRootLock();
  1240. if (Status != ERROR_SUCCESS)
  1241. {
  1242. return Status;
  1243. }
  1244. //
  1245. // First, look this link up in our local data structures.
  1246. //
  1247. Status = LookupFolderByLogicalName( pLinkName,
  1248. &Remaining,
  1249. &pFolder );
  1250. //
  1251. // if an EXACT match was not found, we are done.
  1252. //
  1253. if ( (Status == ERROR_SUCCESS) && (Remaining.Length != 0) )
  1254. {
  1255. pFolder->ReleaseReference();
  1256. Status = ERROR_NOT_FOUND;
  1257. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::RemoveMetadataLink (1) path %wZ: Status %x\n",
  1258. pLinkName, Status );
  1259. }
  1260. //
  1261. // we found the child folder. Now work on removing the metadata
  1262. // and our local structures associated with this link.
  1263. //
  1264. if (Status == ERROR_SUCCESS)
  1265. {
  1266. //
  1267. // Get a handle to our metadata.
  1268. //
  1269. Status = GetMetadataHandle( &RootHandle );
  1270. //
  1271. //Now, look up the metadata name and remove it from the store.
  1272. //
  1273. if (Status == ERROR_SUCCESS)
  1274. {
  1275. LinkMetadataName = pFolder->GetFolderMetadataNameString();
  1276. Status = GetMetadataStore()->RemoveChild( RootHandle,
  1277. LinkMetadataName );
  1278. if (Status != ERROR_SUCCESS)
  1279. {
  1280. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::RemoveMetadataLink path %wZ: Status %x\n",
  1281. pLinkName, Status );
  1282. ReSynchronize(TRUE);
  1283. }
  1284. ReleaseMetadataHandle( RootHandle );
  1285. //
  1286. // If we successfully removed the child from the metadata,
  1287. // remove the link folder associated with this child. This will
  1288. // get rid of our data structure and related directory for that child.
  1289. //
  1290. if (Status == ERROR_SUCCESS)
  1291. {
  1292. DFSSTATUS RemoveStatus;
  1293. RemoveStatus = RemoveLinkFolder( pFolder,
  1294. TRUE ); // permanent removal
  1295. }
  1296. }
  1297. pFolder->ReleaseReference();
  1298. }
  1299. ReleaseRootLock();
  1300. return Status;
  1301. }
  1302. //+-------------------------------------------------------------------------
  1303. //
  1304. // Function: AddMetadataLinkReplica
  1305. //
  1306. // Arguments:
  1307. // pLinkName: the link name relative to root share
  1308. // ReplicaServer : the target server to add
  1309. // ReplicaPath : the target path on the server.
  1310. //
  1311. // Returns: SUCCESS or error
  1312. //
  1313. // Description: This routine adds a target to an existing link.
  1314. //
  1315. // Assumptions: the caller is responsible for mutual exclusion.
  1316. //
  1317. //--------------------------------------------------------------------------
  1318. DFSSTATUS
  1319. DfsRootFolder::AddMetadataLinkReplica(
  1320. PUNICODE_STRING pLinkName,
  1321. LPWSTR ReplicaServer,
  1322. LPWSTR ReplicaPath )
  1323. {
  1324. DFS_METADATA_HANDLE RootHandle;
  1325. DFSSTATUS Status = ERROR_SUCCESS;
  1326. DfsFolder *pFolder = NULL;
  1327. BOOLEAN IsDomainDfs = FALSE;
  1328. LPWSTR LinkMetadataName = NULL;
  1329. UNICODE_STRING Remaining;
  1330. //
  1331. // If either the target server or the path is null, reject the request.
  1332. //
  1333. if ((ReplicaServer == NULL) || (ReplicaPath == NULL))
  1334. {
  1335. return ERROR_INVALID_PARAMETER;
  1336. }
  1337. Status = AcquireRootLock();
  1338. if (Status != ERROR_SUCCESS)
  1339. {
  1340. return Status;
  1341. }
  1342. //
  1343. // Find the link folder associated with this logical name.
  1344. //
  1345. Status = LookupFolderByLogicalName( pLinkName,
  1346. &Remaining,
  1347. &pFolder );
  1348. //
  1349. // If we did not find an EXACT match on the logical name, we are done.
  1350. //
  1351. if ( (Status == ERROR_SUCCESS) && (Remaining.Length != 0) )
  1352. {
  1353. pFolder->ReleaseReference();
  1354. Status = ERROR_NOT_FOUND;
  1355. }
  1356. if ( (Status == ERROR_SUCCESS) &&
  1357. (I_NetDfsIsThisADomainName(ReplicaServer) == ERROR_SUCCESS))
  1358. {
  1359. //
  1360. //dfsdev: include in this check nameinfo->type == OUTSIDE_MY_DOM.
  1361. //
  1362. pFolder->ReleaseReference();
  1363. Status = ERROR_NOT_SUPPORTED;
  1364. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::AddMetadataLinkReplica (1) path %wZ, %ws, %ws: Status %x\n",
  1365. pLinkName, ReplicaServer, ReplicaPath, Status );
  1366. }
  1367. //
  1368. // if we are successful so far, call the store with a handle to
  1369. // the metadata to add this target.
  1370. //
  1371. if (Status == ERROR_SUCCESS)
  1372. {
  1373. //
  1374. // get the metadata name for this link from the root folder.
  1375. //
  1376. LinkMetadataName = pFolder->GetFolderMetadataNameString();
  1377. //
  1378. // Get a handle to the root metadata this root folder.
  1379. //
  1380. Status = GetMetadataHandle( &RootHandle );
  1381. if (Status == ERROR_SUCCESS)
  1382. {
  1383. Status = GetMetadataStore()->AddChildReplica( RootHandle,
  1384. LinkMetadataName,
  1385. ReplicaServer,
  1386. ReplicaPath );
  1387. if (Status != ERROR_SUCCESS)
  1388. {
  1389. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::AddMetadataLinkReplica path %wZ, %ws, %ws: Status %x\n",
  1390. pLinkName, ReplicaServer, ReplicaPath, Status );
  1391. ReSynchronize(TRUE);
  1392. }
  1393. //
  1394. // Release the metadata handle we acquired earlier.
  1395. //
  1396. ReleaseMetadataHandle( RootHandle );
  1397. }
  1398. //
  1399. // If we successfully added the target in the metadata, update the
  1400. // link folder so that the next referral request will pick up the
  1401. // new target.
  1402. //
  1403. if (Status == ERROR_SUCCESS)
  1404. {
  1405. DFSSTATUS UpdateStatus;
  1406. UpdateStatus = UpdateLinkFolder( LinkMetadataName,
  1407. pLinkName,
  1408. pFolder );
  1409. //
  1410. // dfsdev: log the update state.
  1411. //
  1412. }
  1413. //
  1414. // we are done with this link folder: release thre reference we got
  1415. // when we looked it up.
  1416. //
  1417. pFolder->ReleaseReference();
  1418. }
  1419. ReleaseRootLock();
  1420. return Status;
  1421. }
  1422. //+-------------------------------------------------------------------------
  1423. //
  1424. // Function: RemoveMetadataLinkReplica
  1425. //
  1426. // Arguments:
  1427. // pLinkName: the link name relative to root share
  1428. // ReplicaServer : the target server to remove
  1429. // ReplicaPath : the target path on the server.
  1430. // pLastReplica: pointer to boolean, returns true if the last
  1431. // target on this link is being deleted.
  1432. //
  1433. // Returns: SUCCESS or error
  1434. //
  1435. // Description: This routine removes the target of an existing link.
  1436. //
  1437. // Assumptions: the caller is responsible for mutual exclusion.
  1438. //
  1439. //--------------------------------------------------------------------------
  1440. DFSSTATUS
  1441. DfsRootFolder::RemoveMetadataLinkReplica(
  1442. PUNICODE_STRING pLinkName,
  1443. LPWSTR ReplicaServer,
  1444. LPWSTR ReplicaPath,
  1445. PBOOLEAN pLastReplica )
  1446. {
  1447. DFSSTATUS Status = ERROR_SUCCESS;
  1448. LPWSTR LinkMetadataName = NULL;
  1449. DfsFolder *pFolder = NULL;
  1450. DFS_METADATA_HANDLE RootHandle;
  1451. UNICODE_STRING Remaining;
  1452. //
  1453. // if either the target server or target path is empty, return error.
  1454. //
  1455. if ((ReplicaServer == NULL) || (ReplicaPath == NULL))
  1456. {
  1457. return ERROR_INVALID_PARAMETER;
  1458. }
  1459. Status = AcquireRootLock();
  1460. if (Status != ERROR_SUCCESS)
  1461. {
  1462. return Status;
  1463. }
  1464. //
  1465. //find the link folder associated with this logical name.
  1466. //
  1467. Status = LookupFolderByLogicalName( pLinkName,
  1468. &Remaining,
  1469. &pFolder );
  1470. //
  1471. // if we did not find an EXACT match on the logical name, we are done.
  1472. //
  1473. if ( (Status == ERROR_SUCCESS) && (Remaining.Length != 0) )
  1474. {
  1475. pFolder->ReleaseReference();
  1476. Status = ERROR_NOT_FOUND;
  1477. }
  1478. //
  1479. // Call the store to remove the target from this child.
  1480. //
  1481. if (Status == ERROR_SUCCESS)
  1482. {
  1483. //
  1484. // Get the link metadata name from the folder.
  1485. //
  1486. LinkMetadataName = pFolder->GetFolderMetadataNameString();
  1487. //
  1488. // Get the handle to the root metadata for this root folder.
  1489. //
  1490. Status = GetMetadataHandle( &RootHandle );
  1491. if (Status == ERROR_SUCCESS)
  1492. {
  1493. Status = GetMetadataStore()->RemoveChildReplica( RootHandle,
  1494. LinkMetadataName,
  1495. ReplicaServer,
  1496. ReplicaPath,
  1497. pLastReplica );
  1498. if( (Status != ERROR_SUCCESS) && (Status != ERROR_LAST_ADMIN))
  1499. {
  1500. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::RemoveMetadataLinkReplica path %wZ, %ws, %ws: Status %x\n",
  1501. pLinkName, ReplicaServer, ReplicaPath, Status );
  1502. ReSynchronize(TRUE);
  1503. }
  1504. //
  1505. // release the metadata handle we acquired a little bit earlier.
  1506. //
  1507. ReleaseMetadataHandle( RootHandle );
  1508. }
  1509. //
  1510. // if we are successful in removing the target, update the link
  1511. // folder so that future referrals will no longer see the target
  1512. // we just deleted.
  1513. //
  1514. if (Status == ERROR_SUCCESS)
  1515. {
  1516. DFSSTATUS UpdateStatus;
  1517. UpdateStatus = UpdateLinkFolder( LinkMetadataName,
  1518. pLinkName,
  1519. pFolder );
  1520. }
  1521. pFolder->ReleaseReference();
  1522. }
  1523. ReleaseRootLock();
  1524. return Status;
  1525. }
  1526. //+-------------------------------------------------------------------------
  1527. //
  1528. // Function: EnumerateApiLinks
  1529. //
  1530. // Arguments:
  1531. // LPWSTR DfsPathName : the dfs root to enumerate.
  1532. // DWORD Level : the enumeration level
  1533. // LPBYTE pBuffer : buffer to hold results.
  1534. // LONG BufferSize, : buffer size
  1535. // LPDWORD pEntriesRead : number of entries to read.
  1536. // LPDWORD pResumeHandle : the starting child to read.
  1537. // PLONG pNextSizeRequired : return value to hold size required in case of overflow.
  1538. //
  1539. // Returns: SUCCESS or error
  1540. //
  1541. // Description: This routine enumerates the dfs metadata information.
  1542. //
  1543. // Assumptions: the caller is responsible for mutual exclusion.
  1544. //
  1545. //--------------------------------------------------------------------------
  1546. DFSSTATUS
  1547. DfsRootFolder::EnumerateApiLinks(
  1548. LPWSTR DfsPathName,
  1549. DWORD Level,
  1550. LPBYTE pBuffer,
  1551. LONG BufferSize,
  1552. LPDWORD pEntriesRead,
  1553. LPDWORD pResumeHandle,
  1554. PLONG pNextSizeRequired )
  1555. {
  1556. DFSSTATUS Status = ERROR_SUCCESS;
  1557. DFS_METADATA_HANDLE RootHandle = NULL;
  1558. UNICODE_STRING VisibleNameContext;
  1559. UNICODE_STRING DfsPath;
  1560. Status = AcquireRootLock();
  1561. if (Status != ERROR_SUCCESS)
  1562. {
  1563. return Status;
  1564. }
  1565. Status = DfsRtlInitUnicodeStringEx( &DfsPath,
  1566. DfsPathName );
  1567. if(Status == ERROR_SUCCESS)
  1568. {
  1569. //
  1570. // Get the name context for this call.
  1571. // do not use the user passed in name context within the path
  1572. // for this call: if the user comes in with an ip address, we want
  1573. // to return back the correct server/domain info to the caller
  1574. // so the dfsapi results will not show the ip address etc.
  1575. //
  1576. GetVisibleNameContextLocked( NULL,
  1577. &VisibleNameContext );
  1578. //
  1579. // Get the handle to the metadata for this root folder, and call
  1580. // the store to enumerate the links.
  1581. //
  1582. Status = GetMetadataHandle( &RootHandle );
  1583. if (Status == ERROR_SUCCESS)
  1584. {
  1585. Status = GetMetadataStore()->EnumerateApiLinks( RootHandle,
  1586. &VisibleNameContext,
  1587. Level,
  1588. pBuffer,
  1589. BufferSize,
  1590. pEntriesRead,
  1591. pResumeHandle,
  1592. pNextSizeRequired);
  1593. //
  1594. // Release the metadata handle.
  1595. //
  1596. ReleaseMetadataHandle( RootHandle );
  1597. }
  1598. }
  1599. ReleaseRootLock();
  1600. return Status;
  1601. }
  1602. //+-------------------------------------------------------------------------
  1603. //
  1604. // Function: GetApiInformation
  1605. //
  1606. // Arguments:
  1607. // PUNICODE DfsPathName : the dfs root name
  1608. // PUNICODE pLinkName : the link within the root.
  1609. // DWORD Level : the info level.
  1610. // LPBYTE pBuffer : buffer to hold results.
  1611. // LONG BufferSize, : buffer size
  1612. // PLONG pSizeRequired : return value to hold size required in case of overflow.
  1613. //
  1614. // Returns: SUCCESS or error
  1615. //
  1616. // Description: This routine gets the required information for a given root or link
  1617. //
  1618. // Assumptions: the caller is responsible for mutual exclusion.
  1619. //
  1620. //--------------------------------------------------------------------------
  1621. DFSSTATUS
  1622. DfsRootFolder::GetApiInformation(
  1623. PUNICODE_STRING pDfsName,
  1624. PUNICODE_STRING pLinkName,
  1625. DWORD Level,
  1626. LPBYTE pBuffer,
  1627. LONG BufferSize,
  1628. PLONG pSizeRequired )
  1629. {
  1630. UNREFERENCED_PARAMETER(pDfsName);
  1631. DFSSTATUS Status;
  1632. DFS_METADATA_HANDLE RootHandle;
  1633. LPWSTR MetadataName;
  1634. DfsFolder *pFolder;
  1635. UNICODE_STRING VisibleNameContext;
  1636. UNICODE_STRING Remaining;
  1637. Status = AcquireRootLock();
  1638. if (Status != ERROR_SUCCESS)
  1639. {
  1640. return Status;
  1641. }
  1642. //
  1643. //
  1644. // Do not base the context to use on the passed in dfsname:
  1645. // it is important to pass back our correct information
  1646. // in the api call.
  1647. //
  1648. //
  1649. GetVisibleNameContextLocked( NULL,
  1650. &VisibleNameContext );
  1651. //
  1652. // If the link name is empty, we are dealing with the root.
  1653. // so set the metadata name to null.
  1654. //
  1655. if (pLinkName->Length == 0)
  1656. {
  1657. MetadataName = NULL;
  1658. Status = ERROR_SUCCESS;
  1659. }
  1660. //
  1661. // otherwise, lookup the link folder and get the metadataname for that link.
  1662. //
  1663. else {
  1664. Status = LookupFolderByLogicalName( pLinkName,
  1665. &Remaining,
  1666. &pFolder );
  1667. //
  1668. // if we did not find an EXACT match on the logical name, we are done.
  1669. //
  1670. if ( (Status == ERROR_SUCCESS) && (Remaining.Length != 0) )
  1671. {
  1672. pFolder->ReleaseReference();
  1673. Status = ERROR_NOT_FOUND;
  1674. }
  1675. //
  1676. // we had an exact match, so lookup the metadata name and release the
  1677. // the reference on the folder.
  1678. //
  1679. if (Status == ERROR_SUCCESS)
  1680. {
  1681. MetadataName = pFolder->GetFolderMetadataNameString();
  1682. pFolder->ReleaseReference();
  1683. }
  1684. }
  1685. //
  1686. // we got the metadata name: now call into the store to get the
  1687. // required information for the metadata name.
  1688. //
  1689. if (Status == ERROR_SUCCESS)
  1690. {
  1691. //
  1692. // Get the handle to the metadata for this root folder.
  1693. //
  1694. Status = GetMetadataHandle( &RootHandle );
  1695. if (Status == ERROR_SUCCESS)
  1696. {
  1697. Status = GetMetadataStore()->GetStoreApiInformation( RootHandle,
  1698. &VisibleNameContext,
  1699. MetadataName,
  1700. Level,
  1701. pBuffer,
  1702. BufferSize,
  1703. pSizeRequired);
  1704. ReleaseMetadataHandle( RootHandle );
  1705. }
  1706. }
  1707. ReleaseRootLock();
  1708. return Status;
  1709. }
  1710. DFSSTATUS
  1711. DfsRootFolder::ExtendedRootAttributes(
  1712. PULONG pAttr,
  1713. PUNICODE_STRING pRemainingName,
  1714. BOOLEAN Set)
  1715. {
  1716. DFSSTATUS Status;
  1717. DFS_METADATA_HANDLE RootHandle;
  1718. LPWSTR MetadataName = NULL;
  1719. /*
  1720. we get RESETs too (Set == TRUE). INSITE_ONLY flag
  1721. is masked out in those. So there's no way to easily
  1722. do this check. BUG 603118
  1723. if (Set &&
  1724. !IsEmptyUnicodeString(pRemainingName) &&
  1725. (*pAttr != PKT_ENTRY_TYPE_INSITE_ONLY))
  1726. {
  1727. return ERROR_INVALID_PARAMETER;
  1728. }
  1729. */
  1730. Status = AcquireRootLock();
  1731. if (Status != ERROR_SUCCESS)
  1732. {
  1733. return Status;
  1734. }
  1735. Status = GetMetadataHandle( &RootHandle );
  1736. if (Status == ERROR_SUCCESS)
  1737. {
  1738. if (!IsEmptyUnicodeString(pRemainingName))
  1739. {
  1740. PUNICODE_STRING pLinkName = pRemainingName;
  1741. UNICODE_STRING Remaining;
  1742. DfsFolder *pFolder = NULL;
  1743. Status = LookupFolderByLogicalName( pLinkName,
  1744. &Remaining,
  1745. &pFolder );
  1746. //
  1747. // if we did not find an EXACT match on the logical name, we are done.
  1748. //
  1749. if ( (Status == ERROR_SUCCESS) && (Remaining.Length != 0) )
  1750. {
  1751. pFolder->ReleaseReference();
  1752. Status = ERROR_NOT_FOUND;
  1753. }
  1754. if (Status == ERROR_SUCCESS)
  1755. {
  1756. MetadataName = pFolder->GetFolderMetadataNameString();
  1757. //
  1758. // if we got the metadataname, call the store with the
  1759. // details so that it can associate the information
  1760. // with this root or link.
  1761. //
  1762. }
  1763. }
  1764. }
  1765. if (Status == ERROR_SUCCESS)
  1766. {
  1767. if (Set)
  1768. {
  1769. Status = GetMetadataStore()->SetExtendedAttributes( RootHandle,
  1770. MetadataName,
  1771. *pAttr);
  1772. }
  1773. else
  1774. {
  1775. Status = GetMetadataStore()->GetExtendedAttributes( RootHandle,
  1776. MetadataName,
  1777. pAttr);
  1778. }
  1779. }
  1780. ReleaseRootLock();
  1781. return Status;
  1782. }
  1783. //+-------------------------------------------------------------------------
  1784. //
  1785. // Function: SetApiInformation
  1786. //
  1787. // Arguments:
  1788. // PUNICODE pLinkName : the name of link relative to root share
  1789. // LPWSTR Server, : the target server.
  1790. // LPWSTR Share, : the target path within the server.
  1791. // DWORD Level : the info level.
  1792. // LPBYTE pBuffer : buffer that has the information to be set.
  1793. //
  1794. // Returns: SUCCESS or error
  1795. //
  1796. // Description: This routine sets the required information for a given root or link
  1797. //
  1798. // Assumptions: the caller is responsible for mutual exclusion.
  1799. //
  1800. //--------------------------------------------------------------------------
  1801. DFSSTATUS
  1802. DfsRootFolder::SetApiInformation(
  1803. PUNICODE_STRING pLinkName,
  1804. LPWSTR Server,
  1805. LPWSTR Share,
  1806. DWORD Level,
  1807. LPBYTE pBuffer )
  1808. {
  1809. DFSSTATUS Status = ERROR_SUCCESS;
  1810. DFS_METADATA_HANDLE RootHandle = NULL;
  1811. LPWSTR MetadataName = NULL;
  1812. DfsFolder *pFolder = NULL;
  1813. UNICODE_STRING Remaining;
  1814. Status = AcquireRootLock();
  1815. if (Status != ERROR_SUCCESS)
  1816. {
  1817. return Status;
  1818. }
  1819. //
  1820. // if the link name is empty we are dealing with
  1821. // the root itself.
  1822. // dfsdev: we need to set the root metadata appropriately!
  1823. //
  1824. if (pLinkName->Length == 0)
  1825. {
  1826. MetadataName = NULL;
  1827. }
  1828. //
  1829. // else get to the link folder, and get
  1830. // the link metadata name.
  1831. //
  1832. else {
  1833. Status = LookupFolderByLogicalName( pLinkName,
  1834. &Remaining,
  1835. &pFolder );
  1836. //
  1837. // if we did not find an EXACT match on the logical name, we are done.
  1838. //
  1839. if ( (Status == ERROR_SUCCESS) && (Remaining.Length != 0) )
  1840. {
  1841. pFolder->ReleaseReference();
  1842. Status = ERROR_NOT_FOUND;
  1843. }
  1844. if (Status == ERROR_SUCCESS)
  1845. {
  1846. MetadataName = pFolder->GetFolderMetadataNameString();
  1847. //
  1848. // if we got the metadataname, call the store with the
  1849. // details so that it can associate the information
  1850. // with this root or link.
  1851. //
  1852. }
  1853. }
  1854. if (Status == ERROR_SUCCESS)
  1855. {
  1856. if ((Level == 101) && (MetadataName == NULL))
  1857. {
  1858. Status = ERROR_NOT_SUPPORTED;
  1859. }
  1860. else
  1861. {
  1862. //
  1863. // Get the handle to the root of this metadata
  1864. //
  1865. Status = GetMetadataHandle( &RootHandle );
  1866. if (Status == ERROR_SUCCESS)
  1867. {
  1868. Status = GetMetadataStore()->SetStoreApiInformation( RootHandle,
  1869. MetadataName,
  1870. Server,
  1871. Share,
  1872. Level,
  1873. pBuffer );
  1874. if (Status != ERROR_SUCCESS)
  1875. {
  1876. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::SetApiInformation path %wZ, %ws, %ws: Status %x\n",
  1877. pLinkName, Server, Share, Status );
  1878. ReSynchronize(TRUE);
  1879. }
  1880. else
  1881. {
  1882. Status = UpdateFolderInformation(RootHandle,
  1883. MetadataName,
  1884. pFolder);
  1885. }
  1886. ReleaseMetadataHandle( RootHandle );
  1887. }
  1888. //
  1889. // If we successfully updated the metadata, update the
  1890. // link folder so that the next referral request will pick up the
  1891. // changes
  1892. //
  1893. if ((Status == ERROR_SUCCESS) &&
  1894. (MetadataName != NULL))
  1895. {
  1896. DFSSTATUS UpdateStatus;
  1897. UpdateStatus = UpdateLinkFolder( MetadataName,
  1898. pLinkName,
  1899. pFolder );
  1900. //
  1901. // dfsdev: log the update state.
  1902. //
  1903. }
  1904. }
  1905. if (pFolder != NULL) {
  1906. pFolder->ReleaseReference();
  1907. }
  1908. }
  1909. ReleaseRootLock();
  1910. return Status;
  1911. }
  1912. //+-------------------------------------------------------------------------
  1913. //
  1914. // Function: LoadReferralData - Loads the referral data.
  1915. //
  1916. // Arguments: pReferralData - the referral data to load
  1917. //
  1918. // Returns: Status: Success or error code
  1919. //
  1920. // Description: This routine sets up the ReferralData instance to have
  1921. // all the information necessary to create a referral.
  1922. //
  1923. //--------------------------------------------------------------------------
  1924. DFSSTATUS
  1925. DfsRootFolder::LoadReferralData(
  1926. DfsFolderReferralData *pReferralData )
  1927. {
  1928. DFS_METADATA_HANDLE RootMetadataHandle;
  1929. DFSSTATUS Status;
  1930. DfsFolder *pFolder;
  1931. //
  1932. // Get the Root key for this root folder.
  1933. //
  1934. DFS_TRACE_LOW( REFERRAL_SERVER, "LoadReferralData called, %p\n", pReferralData);
  1935. Status = GetMetadataHandle( &RootMetadataHandle );
  1936. if ( Status == ERROR_SUCCESS )
  1937. {
  1938. //
  1939. // Now get the owning folder of the referralDAta. Note that
  1940. // this does not give us a new reference on the Folder.
  1941. // however, the folder is guaranteed to be around till
  1942. // we return from this call, since the pReferralData that
  1943. // was passed in to us cannot go away.
  1944. //
  1945. pFolder = pReferralData->GetOwningFolder();
  1946. DFS_TRACE_LOW( REFERRAL_SERVER, "Load referral data, Got Owning Folder %p\n", pFolder );
  1947. //
  1948. // Now load the replica referral data for the passed in folder.
  1949. //
  1950. Status = LoadReplicaReferralData( RootMetadataHandle,
  1951. pFolder->GetFolderMetadataNameString(),
  1952. pReferralData );
  1953. DFS_TRACE_LOW( REFERRAL_SERVER, "LoadReferralData for %p replica data loaded %x\n",
  1954. pReferralData, Status );
  1955. if ( Status == ERROR_SUCCESS )
  1956. {
  1957. //
  1958. // Load the policy referrral data for the passedin folder.
  1959. //
  1960. Status = LoadPolicyReferralData( RootMetadataHandle );
  1961. }
  1962. ReleaseMetadataHandle( RootMetadataHandle );
  1963. }
  1964. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "[%!FUNC!]Done load referral data %p, Status %x\n",
  1965. pReferralData, Status);
  1966. return Status;
  1967. }
  1968. //+-------------------------------------------------------------------------
  1969. //
  1970. // Function: UnloadReferralData - Unload the referral data.
  1971. //
  1972. // Arguments: pReferralData - the ReferralData instance to unload.
  1973. //
  1974. // Returns: Status: Success or Error status code.
  1975. //
  1976. // Description: This routine Unloads the referral data. It undoes what
  1977. // the corresponding load routine did.
  1978. //
  1979. //--------------------------------------------------------------------------
  1980. DFSSTATUS
  1981. DfsRootFolder::UnloadReferralData(
  1982. DfsFolderReferralData *pReferralData )
  1983. {
  1984. DFSSTATUS Status;
  1985. DFS_TRACE_LOW( REFERRAL_SERVER, "Unload referral data %p\n", pReferralData);
  1986. Status = UnloadReplicaReferralData( pReferralData );
  1987. if ( Status == ERROR_SUCCESS )
  1988. {
  1989. Status = UnloadPolicyReferralData( pReferralData );
  1990. }
  1991. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Unload referral data %p, Status %x\n", pReferralData, Status);
  1992. return Status;
  1993. }
  1994. //+-------------------------------------------------------------------------
  1995. //
  1996. // Function: LoadReplicaReferralData - load the replica information.
  1997. //
  1998. // Arguments: RegKey - the registry key of the root folder,
  1999. // RegistryName - Name of the registry key relative to to Root Key
  2000. // pReferralData - the referral data to load.
  2001. //
  2002. // Returns: Status - Success or error status code.
  2003. //
  2004. // Description: This routine loads the replica referral data for the
  2005. // the passed in ReferralData instance.
  2006. //
  2007. //--------------------------------------------------------------------------
  2008. DFSSTATUS
  2009. DfsRootFolder::LoadReplicaReferralData(
  2010. DFS_METADATA_HANDLE RootMetadataHandle,
  2011. LPWSTR MetadataName,
  2012. DfsFolderReferralData *pReferralData)
  2013. {
  2014. PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo = NULL;
  2015. PDFS_REPLICA_INFORMATION pReplicaInfo = NULL;
  2016. PUNICODE_STRING pServerName = NULL;
  2017. DfsReplica *pReplica = NULL;
  2018. DFSSTATUS Status = ERROR_SUCCESS;
  2019. ULONG Replica = 0;
  2020. ULONG NumReplicas = 0;
  2021. BOOLEAN CacheHit = FALSE;
  2022. DFS_TRACE_LOW( REFERRAL_SERVER, "Load Replica Referral Data %ws, for %p\n", MetadataName, pReferralData);
  2023. pReferralData->pReplicas = NULL;
  2024. //
  2025. // Get the replica information.
  2026. //
  2027. if(!pReferralData->FolderOffLine)
  2028. {
  2029. Status = GetMetadataStore()->GetMetadataReplicaInformation(RootMetadataHandle,
  2030. MetadataName,
  2031. &pReplicaListInfo );
  2032. if(Status == ERROR_SUCCESS)
  2033. {
  2034. NumReplicas = pReplicaListInfo->ReplicaCount;
  2035. }
  2036. }
  2037. if ( Status == ERROR_SUCCESS )
  2038. {
  2039. //
  2040. // Set the appropriate count, and allocate the replicas
  2041. // required.
  2042. //
  2043. pReferralData->ReplicaCount = NumReplicas;
  2044. if (pReferralData->ReplicaCount > 0)
  2045. {
  2046. pReferralData->pReplicas = new DfsReplica [ NumReplicas ];
  2047. if ( pReferralData->pReplicas == NULL )
  2048. {
  2049. Status = ERROR_NOT_ENOUGH_MEMORY;
  2050. }
  2051. }
  2052. }
  2053. //
  2054. // Now, for each replica, set the replicas server name, the target
  2055. // folder and the replica state.
  2056. //
  2057. if ( Status == ERROR_SUCCESS )
  2058. {
  2059. for ( Replica = 0;
  2060. (Replica < NumReplicas) && (Status == ERROR_SUCCESS);
  2061. Replica++ )
  2062. {
  2063. UNICODE_STRING UseName;
  2064. RtlInitUnicodeString(&UseName, NULL);
  2065. pReplicaInfo = &pReplicaListInfo->pReplicas[Replica];
  2066. pReplica = &pReferralData->pReplicas[ Replica ];
  2067. pServerName = &pReplicaInfo->ServerName;
  2068. //
  2069. // If the servername is a ., this is a special case where
  2070. // the servername is the root itself. In this case,
  2071. // set the server name to the name of this machine.
  2072. //
  2073. if (IsLocalName(pServerName))
  2074. {
  2075. Status = GetVisibleNameContext( NULL,
  2076. &UseName);
  2077. if (Status == ERROR_SUCCESS)
  2078. {
  2079. *pServerName = UseName;
  2080. }
  2081. }
  2082. if ( Status == ERROR_SUCCESS )
  2083. {
  2084. Status = pReplica->SetTargetServer( pServerName, &CacheHit );
  2085. }
  2086. if ( Status == ERROR_SUCCESS )
  2087. {
  2088. pStatistics->UpdateServerSiteStat(CacheHit);
  2089. Status = pReplica->SetTargetFolder( &pReplicaInfo->ShareName );
  2090. }
  2091. if ( Status == ERROR_SUCCESS )
  2092. {
  2093. if ( pReplicaInfo->ReplicaState & REPLICA_STORAGE_STATE_OFFLINE )
  2094. {
  2095. pReplica->SetTargetOffline();
  2096. }
  2097. }
  2098. if (UseName.Length != 0)
  2099. {
  2100. DfsFreeUnicodeString(&UseName);
  2101. RtlInitUnicodeString(&UseName, NULL);
  2102. }
  2103. }
  2104. }
  2105. //
  2106. // Now release the replica information that was allocated
  2107. // by the store.
  2108. //
  2109. if(pReplicaListInfo)
  2110. {
  2111. GetMetadataStore()->ReleaseMetadataReplicaInformation( RootMetadataHandle,
  2112. pReplicaListInfo );
  2113. }
  2114. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Done with Load Replica Referral Data %ws, for %p, Status %x\n",
  2115. MetadataName, pReferralData, Status);
  2116. return Status;
  2117. }
  2118. //+-------------------------------------------------------------------------
  2119. //
  2120. // Function: UnloadReplicaReferralData - Unload the replicas
  2121. //
  2122. // Arguments: pReferralData - the DfsFolderReferralData to unload
  2123. //
  2124. // Returns: Status: Success always.
  2125. //
  2126. // Description: This routine gets rid of the allocate replicas in the
  2127. // folder's referral data.
  2128. //
  2129. //--------------------------------------------------------------------------
  2130. DFSSTATUS
  2131. DfsRootFolder::UnloadReplicaReferralData(
  2132. DfsFolderReferralData *pReferralData )
  2133. {
  2134. if (pReferralData->pReplicas != NULL) {
  2135. delete [] pReferralData->pReplicas;
  2136. pReferralData->pReplicas = NULL;
  2137. }
  2138. return ERROR_SUCCESS;
  2139. }
  2140. //+-------------------------------------------------------------------------
  2141. //
  2142. // Function: SetRootStandby - set the root in a standby mode.
  2143. //
  2144. // Arguments: none
  2145. //
  2146. // Returns: Status: Success always for now.
  2147. //
  2148. // Description: This routine checks if we are already in standby mode.
  2149. // If not, it releases the root share directory, removes
  2150. // all the link folders and set the root in a standby mode
  2151. // DFSDEV: need to take into consideration synchronization
  2152. // with other threads.
  2153. //
  2154. //--------------------------------------------------------------------------
  2155. DFSSTATUS
  2156. DfsRootFolder::SetRootStandby()
  2157. {
  2158. DFSSTATUS Status = ERROR_SUCCESS;
  2159. Status = AcquireRootLock();
  2160. if (Status != ERROR_SUCCESS)
  2161. {
  2162. return Status;
  2163. }
  2164. DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Root %p being set to standby\n", this);
  2165. if (IsRootFolderStandby() == FALSE)
  2166. {
  2167. //
  2168. // dfsdev:: ignore error returns from these calls?
  2169. //
  2170. DFSSTATUS ReleaseStatus;
  2171. RemoveAllLinkFolders( TRUE ); // permanent removal
  2172. ReleaseStatus = ReleaseRootShareDirectory();
  2173. DFS_TRACE_ERROR_LOW( ReleaseStatus, REFERRAL_SERVER, "[%!FUNC!]Release root share status %x\n", ReleaseStatus);
  2174. SetRootFolderStandby();
  2175. }
  2176. else
  2177. {
  2178. DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Root %p was already standby\n", this);
  2179. }
  2180. ReleaseRootLock();
  2181. return Status;
  2182. }
  2183. //+-------------------------------------------------------------------------
  2184. //
  2185. // Function: SetRootResynchronize - set the root in a ready mode.
  2186. //
  2187. // Arguments: none
  2188. //
  2189. // Returns: Status: Success always for now.
  2190. //
  2191. // Description: This routine checks if we are already in ready mode.
  2192. // If not, it acquires the root share directory, calls
  2193. // synchronize to add all the links back
  2194. // DFSDEV: need to take into consideration synchronization
  2195. // with other threads.
  2196. //
  2197. //--------------------------------------------------------------------------
  2198. DFSSTATUS
  2199. DfsRootFolder::SetRootResynchronize()
  2200. {
  2201. DFSSTATUS Status = ERROR_SUCCESS;
  2202. DFSSTATUS RootStatus;
  2203. Status = AcquireRootLock();
  2204. if (Status != ERROR_SUCCESS)
  2205. {
  2206. return Status;
  2207. }
  2208. DFS_TRACE_LOW( REFERRAL_SERVER, "[%!FUNC!]Root %p being resynced\n", this);
  2209. //
  2210. // if the root folder is already marked available, we are done
  2211. // otherwise, clear the standby mode, and try to bring this
  2212. // root into a useable state.
  2213. //
  2214. if (!IsRootFolderAvailable())
  2215. {
  2216. ClearRootFolderStandby();
  2217. //
  2218. // need to take appropriate locks.
  2219. //
  2220. RootStatus = Synchronize();
  2221. DFS_TRACE_ERROR_LOW( RootStatus, REFERRAL_SERVER, "[%!FUNC!]Set root resync: Synchronize status for %p is %x\n",
  2222. this, RootStatus);
  2223. }
  2224. else
  2225. {
  2226. //
  2227. // Synchronize without the FORCE flag here, because we don't want to
  2228. // get the entire blob unless the GUID has changed. This will still result in
  2229. // a minimum of one network call to get the GUID.
  2230. //
  2231. RootStatus = ReSynchronize();
  2232. DFS_TRACE_ERROR_LOW( RootStatus, REFERRAL_SERVER, "[%!FUNC!]Set root resync: Synchronize status for %p is %x\n",
  2233. this, RootStatus);
  2234. }
  2235. ReleaseRootLock();
  2236. return Status;
  2237. }
  2238. DFSSTATUS
  2239. DfsRootFolder::UpdateFolderInformation(
  2240. IN DFS_METADATA_HANDLE DfsHandle,
  2241. LPWSTR ChildName,
  2242. DfsFolder *pChildFolder)
  2243. {
  2244. DFSSTATUS Status = ERROR_SUCCESS;
  2245. ULONG Timeout = 0;
  2246. PDFS_NAME_INFORMATION pChild = NULL;
  2247. ULONG ChildType = 0;
  2248. ULONG ChildState = 0;
  2249. FILETIME LastModifiedTime;
  2250. Status = GetMetadataStore()->GetMetadataNameInformation( DfsHandle,
  2251. ChildName,
  2252. &pChild);
  2253. if(Status == ERROR_SUCCESS)
  2254. {
  2255. ChildType = pChild->Type;
  2256. ChildState = pChild->State;
  2257. Timeout = pChild->Timeout;
  2258. LastModifiedTime = pChild->LastModifiedTime;
  2259. if( pChildFolder != NULL)
  2260. {
  2261. if (ChildType & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM)
  2262. {
  2263. pChildFolder->SetFlag( DFS_FOLDER_OUT_OF_DOMAIN );
  2264. }
  2265. else
  2266. {
  2267. pChildFolder->ResetFlag( DFS_FOLDER_OUT_OF_DOMAIN );
  2268. }
  2269. if((ChildState & DFS_VOLUME_STATE_OFFLINE) == DFS_VOLUME_STATE_OFFLINE)
  2270. {
  2271. pChildFolder->SetFlag( DFS_FOLDER_OFFLINE );
  2272. }
  2273. else
  2274. {
  2275. pChildFolder->ResetFlag( DFS_FOLDER_OFFLINE );
  2276. }
  2277. pChildFolder->SetTimeout(Timeout);
  2278. pChildFolder->SetUSN( FILETIMETO64(LastModifiedTime) );
  2279. }
  2280. else
  2281. {
  2282. SetTimeout(Timeout);
  2283. SetUSN( FILETIMETO64(LastModifiedTime) );
  2284. }
  2285. GetMetadataStore()->ReleaseMetadataNameInformation( DfsHandle, pChild );
  2286. }
  2287. //
  2288. // Now that we have the child name, get the name information
  2289. // for this child. This is the logical namespace information
  2290. // for this child.
  2291. //
  2292. return Status;
  2293. }
  2294. //+-------------------------------------------------------------------------
  2295. //
  2296. // Function: UpdateLinkInformation
  2297. //
  2298. // Arguments:
  2299. // DfsMetadataHandle - the parent handle
  2300. // LPWSTR ChildName - the child name
  2301. //
  2302. // Returns: Status: Success or Error status code
  2303. //
  2304. // Description: This routine reads the metadata for the child and, updates
  2305. // the child folder if necessary. This includes adding
  2306. // the folder if it does not exist, or if the folder exists
  2307. // but the metadata is newer, ensuring that all future
  2308. // request use the most upto date data.
  2309. //
  2310. //--------------------------------------------------------------------------
  2311. DFSSTATUS
  2312. DfsRootFolder::UpdateLinkInformation(
  2313. IN DFS_METADATA_HANDLE DfsHandle,
  2314. LPWSTR ChildName,
  2315. BOOLEAN CalledByApi )
  2316. {
  2317. DFSSTATUS Status = ERROR_SUCCESS;
  2318. ULONG Timeout = 0;
  2319. PDFS_NAME_INFORMATION pChild = NULL;
  2320. DfsFolder *pChildFolder = NULL;
  2321. FILETIME LastModifiedTime;
  2322. ULONG ChildType = 0;
  2323. ULONG ChildState = 0;
  2324. UNICODE_STRING LinkName;
  2325. //
  2326. // Now that we have the child name, get the name information
  2327. // for this child. This is the logical namespace information
  2328. // for this child.
  2329. //
  2330. Status = GetMetadataStore()->GetMetadataNameInformation( DfsHandle,
  2331. ChildName,
  2332. &pChild);
  2333. if ( Status == ERROR_SUCCESS )
  2334. {
  2335. ChildType = pChild->Type;
  2336. ChildState = pChild->State;
  2337. Timeout = pChild->Timeout;
  2338. if ((ChildType & (PKT_ENTRY_TYPE_REFERRAL_SVC | PKT_ENTRY_TYPE_DFS)) ==
  2339. (PKT_ENTRY_TYPE_REFERRAL_SVC | PKT_ENTRY_TYPE_DFS))
  2340. {
  2341. SetTimeout(Timeout);
  2342. if (ChildType & PKT_ENTRY_TYPE_INSITE_ONLY)
  2343. {
  2344. SetFlag( DFS_FOLDER_INSITE_REFERRALS );
  2345. }
  2346. else
  2347. {
  2348. ResetFlag( DFS_FOLDER_INSITE_REFERRALS );
  2349. }
  2350. // If site-costing is turned on for this root, mark it so.
  2351. if (ChildType & PKT_ENTRY_TYPE_COST_BASED_SITE_SELECTION)
  2352. {
  2353. SetFlag( DFS_FOLDER_COST_BASED_SITE_SELECTION );
  2354. }
  2355. else
  2356. {
  2357. ResetFlag( DFS_FOLDER_COST_BASED_SITE_SELECTION );
  2358. }
  2359. if (ChildType & PKT_ENTRY_TYPE_ROOT_SCALABILITY)
  2360. {
  2361. SetRootScalabilityMode();
  2362. }
  2363. else
  2364. {
  2365. ResetRootScalabilityMode();
  2366. }
  2367. GetMetadataStore()->ReleaseMetadataNameInformation( DfsHandle, pChild );
  2368. return Status;
  2369. }
  2370. }
  2371. if (Status == ERROR_SUCCESS)
  2372. {
  2373. LastModifiedTime = pChild->LastModifiedTime;
  2374. //
  2375. // Now translate the metadata logical name to a relative
  2376. // link name: each store has its own behavior, so
  2377. // the getlinkname function is implemented by each store.
  2378. //
  2379. Status = GetMetadataLogicalToLinkName(&pChild->Prefix,
  2380. &LinkName);
  2381. if ( Status == ERROR_SUCCESS )
  2382. {
  2383. Status = LookupFolderByMetadataName( ChildName,
  2384. &pChildFolder );
  2385. if ( Status == ERROR_SUCCESS )
  2386. {
  2387. //
  2388. // IF we already know this child, check if the child
  2389. // has been updated since we last visited it.
  2390. // If so, we need to update the child.
  2391. //
  2392. if ( pChildFolder->UpdateRequired( FILETIMETO64(LastModifiedTime) ) )
  2393. {
  2394. Status = UpdateLinkFolder( ChildName,
  2395. &LinkName,
  2396. pChildFolder );
  2397. }
  2398. //
  2399. // we now check if we need to create root directories for even
  2400. // those folders that we already know about. This may be true
  2401. // when we had one or more errors creating the
  2402. // directory when we initially created this folder or it may
  2403. // be true when we are going from standby to master.
  2404. //
  2405. if (IsRootDirectoriesCreated() == FALSE)
  2406. {
  2407. DFSSTATUS CreateStatus;
  2408. CreateStatus = SetupLinkReparsePoint(pChildFolder->GetFolderLogicalNameString());
  2409. }
  2410. }
  2411. else if ( Status == ERROR_NOT_FOUND )
  2412. {
  2413. //
  2414. // We have not seen this child before: create
  2415. // a new one.
  2416. //
  2417. Status = CreateLinkFolder( ChildName,
  2418. &LinkName,
  2419. &pChildFolder,
  2420. CalledByApi );
  2421. if(CalledByApi)
  2422. {
  2423. if(Status != ERROR_SUCCESS)
  2424. {
  2425. DFSSTATUS RemoveStatus = ERROR_SUCCESS;
  2426. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::UpdateLinkInformation (1) %ws: Status %x\n",
  2427. ChildName, Status );
  2428. RemoveStatus = RemoveMetadataLink(&LinkName);
  2429. if(RemoveStatus != ERROR_SUCCESS)
  2430. {
  2431. DFS_TRACE_ERROR_HIGH(Status, API, "DfsRootFolder::UpdateLinkInformation (2)%ws: Status %x\n",
  2432. ChildName, Status );
  2433. ReSynchronize(TRUE);
  2434. }
  2435. }
  2436. }
  2437. }
  2438. ReleaseMetadataLogicalToLinkName( &LinkName );
  2439. }
  2440. //
  2441. // Now release the name information of the child.
  2442. //
  2443. GetMetadataStore()->ReleaseMetadataNameInformation( DfsHandle, pChild );
  2444. }
  2445. //
  2446. // We were successful. We have a child folder that is
  2447. // returned to us with a valid reference. Set the Last
  2448. // modified time in the folder, and release our reference
  2449. // on the child folder.
  2450. //
  2451. if ( Status == ERROR_SUCCESS )
  2452. {
  2453. if (ChildType & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM)
  2454. {
  2455. pChildFolder->SetFlag( DFS_FOLDER_OUT_OF_DOMAIN );
  2456. }
  2457. else
  2458. {
  2459. pChildFolder->ResetFlag( DFS_FOLDER_OUT_OF_DOMAIN );
  2460. }
  2461. if (ChildType & PKT_ENTRY_TYPE_INSITE_ONLY)
  2462. {
  2463. pChildFolder->SetFlag( DFS_FOLDER_INSITE_REFERRALS );
  2464. }
  2465. else
  2466. {
  2467. pChildFolder->ResetFlag( DFS_FOLDER_INSITE_REFERRALS );
  2468. }
  2469. if((ChildState & DFS_VOLUME_STATE_OFFLINE) == DFS_VOLUME_STATE_OFFLINE)
  2470. {
  2471. pChildFolder->SetFlag( DFS_FOLDER_OFFLINE );
  2472. }
  2473. else
  2474. {
  2475. pChildFolder->ResetFlag( DFS_FOLDER_OFFLINE );
  2476. }
  2477. pChildFolder->SetTimeout(Timeout);
  2478. pChildFolder->SetUSN( FILETIMETO64(LastModifiedTime) );
  2479. pChildFolder->ReleaseReference();
  2480. }
  2481. return Status;
  2482. }
  2483. void
  2484. DfsRootFolder::GenerateEventLog(DWORD EventMsg,
  2485. WORD Substrings,
  2486. const TCHAR * apszSubStrings[],
  2487. DWORD Errorcode)
  2488. {
  2489. LONG RetVal = FEWERRORS_ON_ROOT;
  2490. if(InterlockedIncrement(&_CurrentErrors) < DFS_MAX_ROOT_ERRORS)
  2491. {
  2492. DfsLogDfsEvent(EventMsg,
  2493. Substrings,
  2494. apszSubStrings,
  2495. Errorcode);
  2496. }
  2497. else
  2498. {
  2499. const TCHAR * apszErrSubStrings[1];
  2500. RetVal = InterlockedCompareExchange(&_TooManyEventLogErrors,
  2501. TOOMANY_ERRORS_ON_ROOT,
  2502. FEWERRORS_ON_ROOT);
  2503. if(RetVal == FEWERRORS_ON_ROOT)
  2504. {
  2505. apszErrSubStrings[0] = GetLogicalShare()->Buffer;
  2506. DfsLogDfsEvent(DFS_ERROR_TOO_MANY_ERRORS,
  2507. 1,
  2508. apszErrSubStrings,
  2509. 0);
  2510. }
  2511. }
  2512. }
  2513. NTSTATUS
  2514. DfsRootFolder::IsDirectoryMountPoint(
  2515. IN HANDLE DirHandle,
  2516. OUT PBOOLEAN pDfsMountPoint )
  2517. {
  2518. NTSTATUS NtStatus = STATUS_SUCCESS;
  2519. FILE_BASIC_INFORMATION BasicInfo;
  2520. IO_STATUS_BLOCK IoStatusBlock;
  2521. //
  2522. //we assume these are not reparse points.
  2523. //
  2524. *pDfsMountPoint = FALSE;
  2525. //
  2526. // Query for the basic information, which has the attributes.
  2527. //
  2528. NtStatus = NtQueryInformationFile( DirHandle,
  2529. &IoStatusBlock,
  2530. (PVOID)&BasicInfo,
  2531. sizeof(BasicInfo),
  2532. FileBasicInformation );
  2533. if (NtStatus == STATUS_SUCCESS)
  2534. {
  2535. //
  2536. // If the attributes indicate reparse point, we have a reparse
  2537. // point directory on our hands.
  2538. //
  2539. if ( BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  2540. {
  2541. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  2542. NtStatus = NtQueryInformationFile( DirHandle,
  2543. &IoStatusBlock,
  2544. (PVOID)&FileTagInformation,
  2545. sizeof(FileTagInformation),
  2546. FileAttributeTagInformation );
  2547. if (NtStatus == STATUS_SUCCESS)
  2548. {
  2549. //
  2550. // Checkif the tag indicates its a mount point,
  2551. // and setup the return accordingly.
  2552. //
  2553. if (FileTagInformation.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
  2554. {
  2555. *pDfsMountPoint = TRUE;
  2556. }
  2557. }
  2558. }
  2559. }
  2560. return NtStatus;
  2561. }
  2562. DFSSTATUS
  2563. DfsRootFolder::PrefetchReplicaData(DfsFolder *pChildFolder)
  2564. {
  2565. DFSSTATUS Status = ERROR_SUCCESS;
  2566. DFS_METADATA_HANDLE RootMetadataHandle;
  2567. Status = GetMetadataHandle( &RootMetadataHandle );
  2568. if(Status == ERROR_SUCCESS)
  2569. {
  2570. Status = LoadCachedServerSiteData(RootMetadataHandle,
  2571. pChildFolder->GetFolderMetadataNameString());
  2572. ReleaseMetadataHandle( RootMetadataHandle );
  2573. }
  2574. return Status;
  2575. }
  2576. DFSSTATUS
  2577. DfsRootFolder::LoadServerSiteData(DfsFolder *pChildFolder)
  2578. {
  2579. DFSSTATUS Status = ERROR_SUCCESS;
  2580. if(DfsServerGlobalData.IsStartupProcessingDone)
  2581. {
  2582. if(_PrefetchNeeded == FALSE)
  2583. {
  2584. _PrefetchNeeded = TRUE;
  2585. }
  2586. }
  2587. if(!_PrefetchNeeded)
  2588. {
  2589. return Status;
  2590. }
  2591. Status = PrefetchReplicaData(pChildFolder);
  2592. return Status;
  2593. }
  2594. DFSSTATUS
  2595. DfsRootFolder::LoadCachedServerSiteData(
  2596. DFS_METADATA_HANDLE RootMetadataHandle,
  2597. LPWSTR MetadataName)
  2598. {
  2599. PDFS_REPLICA_LIST_INFORMATION pReplicaListInfo = NULL;
  2600. PDFS_REPLICA_INFORMATION pReplicaInfo = NULL;
  2601. PUNICODE_STRING pServerName = NULL;
  2602. DfsReplica *pReplica = NULL;
  2603. DfsReplica *pReplicaList = NULL;
  2604. DfsServerSiteInfo *pInfo = NULL;
  2605. DFSSTATUS Status = ERROR_SUCCESS;
  2606. ULONG Replica = 0;
  2607. ULONG NumLocalReplicas = 0;
  2608. BOOLEAN CacheHit = FALSE;
  2609. DFS_TRACE_LOW( SITE, "LoadCachedServerSiteData %ws\n", MetadataName);
  2610. //
  2611. // Get the replica information.
  2612. //
  2613. Status = GetMetadataStore()->GetMetadataReplicaInformation(RootMetadataHandle,
  2614. MetadataName,
  2615. &pReplicaListInfo );
  2616. if ( Status == ERROR_SUCCESS )
  2617. {
  2618. //
  2619. // Set the appropriate count, and allocate the replicas
  2620. // required.
  2621. //
  2622. NumLocalReplicas = pReplicaListInfo->ReplicaCount;
  2623. if (NumLocalReplicas > 0)
  2624. {
  2625. pReplicaList = new DfsReplica [ pReplicaListInfo->ReplicaCount ];
  2626. if ( pReplicaList == NULL )
  2627. {
  2628. Status = ERROR_NOT_ENOUGH_MEMORY;
  2629. }
  2630. }
  2631. }
  2632. //
  2633. // Now, for each replica, set the replicas server name, the target
  2634. // folder and the replica state.
  2635. //
  2636. if ( Status == ERROR_SUCCESS )
  2637. {
  2638. for ( Replica = 0;
  2639. (Replica < pReplicaListInfo->ReplicaCount) && (Status == ERROR_SUCCESS);
  2640. Replica++ )
  2641. {
  2642. UNICODE_STRING UseName;
  2643. RtlInitUnicodeString(&UseName, NULL);
  2644. pReplicaInfo = &pReplicaListInfo->pReplicas[Replica];
  2645. pReplica = &pReplicaList[ Replica ];
  2646. pServerName = &pReplicaInfo->ServerName;
  2647. //
  2648. // If the servername is a ., this is a special case where
  2649. // the servername is the root itself. In this case,
  2650. // set the server name to the name of this machine.
  2651. //
  2652. if (IsLocalName(pServerName))
  2653. {
  2654. Status = GetVisibleNameContext( NULL,
  2655. &UseName);
  2656. if (Status == ERROR_SUCCESS)
  2657. {
  2658. *pServerName = UseName;
  2659. }
  2660. }
  2661. if ( Status == ERROR_SUCCESS )
  2662. {
  2663. Status = DfsGetServerInfo (pServerName, &pInfo, &CacheHit, TRUE);
  2664. }
  2665. if(Status == ERROR_SUCCESS)
  2666. {
  2667. DFS_TRACE_LOW( SITE, "LoadCachedServerSiteData: Server %wZ <->Site %ws\n",
  2668. pServerName, pInfo->GetSiteNameString());
  2669. pInfo->ReleaseReference();
  2670. }
  2671. if (UseName.Length != 0)
  2672. {
  2673. DfsFreeUnicodeString(&UseName);
  2674. RtlInitUnicodeString(&UseName, NULL);
  2675. }
  2676. }
  2677. }
  2678. //
  2679. // Now release the replica information that was allocated
  2680. // by the store.
  2681. //
  2682. if(pReplicaListInfo != NULL)
  2683. {
  2684. GetMetadataStore()->ReleaseMetadataReplicaInformation( RootMetadataHandle,
  2685. pReplicaListInfo );
  2686. }
  2687. if(pReplicaList)
  2688. {
  2689. delete []pReplicaList;
  2690. }
  2691. DFS_TRACE_ERROR_LOW( Status, REFERRAL_SERVER, "Done with LoadCachedServerSiteData %ws, Status %x\n",
  2692. MetadataName, Status);
  2693. return Status;
  2694. }
  2695. //this callback should not hold any child folder locks
  2696. void PrefetchCallBack(LPVOID pEntry, LPVOID pContext)
  2697. {
  2698. DfsFolder *pFolder = (DfsFolder *) pEntry;
  2699. DfsRootFolder * pRootFolder = (DfsRootFolder *) pContext;
  2700. if (!DfsIsShuttingDown())
  2701. {
  2702. if(pFolder != NULL)
  2703. {
  2704. pRootFolder->PrefetchReplicaData(pFolder);
  2705. }
  2706. }
  2707. }
  2708. DFSSTATUS
  2709. DfsRootFolder::PreloadServerSiteData(void)
  2710. {
  2711. NTSTATUS NtStatus = STATUS_SUCCESS;
  2712. NtStatus = DfsPrefixTableAcquireWriteLock( _pLogicalPrefixTable );
  2713. if (NtStatus == STATUS_SUCCESS)
  2714. {
  2715. DfsEnumeratePrefixTableLocked(_pLogicalPrefixTable, PrefetchCallBack, this);
  2716. DfsPrefixTableReleaseLock( _pLogicalPrefixTable );
  2717. }
  2718. _PrefetchNeeded = TRUE;
  2719. return NtStatus;
  2720. }
  2721. DFSSTATUS
  2722. DfsRootFolder::ValidateAPiShortName(PUNICODE_STRING pLinkName)
  2723. {
  2724. NTSTATUS NtStatus = STATUS_SUCCESS;
  2725. DFSSTATUS Status = ERROR_SUCCESS;
  2726. HANDLE DirectoryHandle = NULL;
  2727. DWORD NumComponentsExpanded = 0;
  2728. UNICODE_STRING NewLinkName;
  2729. NewLinkName.Buffer = NULL;
  2730. NewLinkName.Length = NewLinkName.MaximumLength = 0;
  2731. if(IsAShortName(pLinkName))
  2732. {
  2733. NtStatus = DfsOpenDirectory ( GetDirectoryCreatePathName(),
  2734. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2735. NULL,
  2736. &DirectoryHandle,
  2737. NULL );
  2738. if(NtStatus == STATUS_SUCCESS)
  2739. {
  2740. NtStatus = ExpandLinkDirectories(pLinkName,
  2741. &NewLinkName,
  2742. DirectoryHandle,
  2743. TRUE,
  2744. &NumComponentsExpanded);
  2745. if(NtStatus == STATUS_NAME_TOO_LONG)
  2746. {
  2747. Status = ERROR_BAD_PATHNAME;
  2748. }
  2749. else
  2750. {
  2751. Status = ERROR_SUCCESS;
  2752. }
  2753. CloseHandle (DirectoryHandle);
  2754. }
  2755. if(NewLinkName.Buffer)
  2756. {
  2757. delete [] NewLinkName.Buffer;
  2758. }
  2759. }
  2760. return Status;
  2761. }
  2762. DFSSTATUS
  2763. DfsRootFolder::ExpandShortName(PUNICODE_STRING pLinkName,
  2764. PUNICODE_STRING pNewPath,
  2765. PUNICODE_STRING pRemainingName)
  2766. {
  2767. NTSTATUS NtStatus = STATUS_SUCCESS;
  2768. DFSSTATUS Status = ERROR_NOT_FOUND;
  2769. HANDLE DirectoryHandle = NULL;
  2770. DWORD NumComponentsExpanded = 0;
  2771. pNewPath->Length = 0;
  2772. pNewPath->MaximumLength = 0;
  2773. pNewPath->Buffer = NULL;
  2774. if(IsAShortName(pLinkName))
  2775. {
  2776. NtStatus = DfsOpenDirectory ( GetDirectoryCreatePathName(),
  2777. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2778. NULL,
  2779. &DirectoryHandle,
  2780. NULL );
  2781. if(NtStatus == STATUS_SUCCESS)
  2782. {
  2783. NtStatus = ExpandLinkDirectories(pLinkName,
  2784. pNewPath,
  2785. DirectoryHandle,
  2786. FALSE,
  2787. &NumComponentsExpanded);
  2788. if((NtStatus == STATUS_DIRECTORY_IS_A_REPARSE_POINT) ||
  2789. (NtStatus == STATUS_NO_SUCH_FILE))
  2790. {
  2791. NtStatus = STATUS_SUCCESS;
  2792. }
  2793. CloseHandle (DirectoryHandle);
  2794. }
  2795. Status = RtlNtStatusToDosError(NtStatus);
  2796. if((Status == ERROR_SUCCESS) && NumComponentsExpanded && pRemainingName)
  2797. {
  2798. NtStatus = FindRemaingName(pLinkName,
  2799. pRemainingName,
  2800. NumComponentsExpanded);
  2801. Status = RtlNtStatusToDosError(NtStatus);
  2802. }
  2803. }
  2804. return Status;
  2805. }
  2806. NTSTATUS
  2807. DfsRootFolder::FindRemaingName(PUNICODE_STRING pLinkName,
  2808. PUNICODE_STRING pRemainingName,
  2809. DWORD NumComponentsExpanded)
  2810. {
  2811. DWORD LoopVar = 0;
  2812. NTSTATUS NtStatus = STATUS_SUCCESS;
  2813. UNICODE_STRING RemainingName;
  2814. UNICODE_STRING RemPath;
  2815. UNICODE_STRING TempString;
  2816. RemainingName = *pLinkName;
  2817. for (LoopVar = 0; LoopVar < NumComponentsExpanded; LoopVar++)
  2818. {
  2819. NtStatus = DfsGetNextComponent(&RemainingName,
  2820. &RemPath,
  2821. &TempString);
  2822. RemainingName = TempString;
  2823. }
  2824. *pRemainingName = RemainingName;
  2825. return NtStatus;
  2826. }
  2827. NTSTATUS
  2828. DfsRootFolder::ExpandLinkDirectories(
  2829. PUNICODE_STRING pLinkName,
  2830. PUNICODE_STRING pNewPath,
  2831. HANDLE RelativeHandle,
  2832. BOOLEAN FailOnExpand,
  2833. DWORD * NumComponentsExpanded)
  2834. {
  2835. NTSTATUS NtStatus = STATUS_SUCCESS;
  2836. DFSSTATUS Status = ERROR_SUCCESS;
  2837. HANDLE CurrentDirectory = INVALID_HANDLE_VALUE;
  2838. HANDLE LocalRelativeHandle = INVALID_HANDLE_VALUE;
  2839. ULONG ShareMode = 0;
  2840. DWORD NumExpanded = 0;
  2841. BOOLEAN Expanded = FALSE;
  2842. BOOLEAN NewlyCreated = FALSE;
  2843. UNICODE_STRING RemainingName;
  2844. UNICODE_STRING TempString;
  2845. UNICODE_STRING DirectoryToCreate;
  2846. *NumComponentsExpanded = 0;
  2847. ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  2848. LocalRelativeHandle = RelativeHandle;
  2849. RemainingName = *pLinkName;
  2850. while ( NtStatus == STATUS_SUCCESS)
  2851. {
  2852. NtStatus = DfsGetNextComponent(&RemainingName,
  2853. &DirectoryToCreate,
  2854. &TempString);
  2855. RemainingName = TempString;
  2856. Expanded = FALSE;
  2857. NtStatus = GetAShortName(LocalRelativeHandle,
  2858. &Expanded,
  2859. &DirectoryToCreate,
  2860. pNewPath);
  2861. if (NtStatus != STATUS_SUCCESS)
  2862. {
  2863. break;
  2864. }
  2865. NumExpanded++;
  2866. if( FailOnExpand && Expanded)
  2867. {
  2868. NtStatus = STATUS_NAME_TOO_LONG;
  2869. break;
  2870. }
  2871. NtStatus = DfsOpenDirectory( &DirectoryToCreate,
  2872. ShareMode,
  2873. LocalRelativeHandle,
  2874. &CurrentDirectory,
  2875. &NewlyCreated );
  2876. if (NtStatus == STATUS_SUCCESS)
  2877. {
  2878. if(LocalRelativeHandle != RelativeHandle)
  2879. {
  2880. DfsCloseDirectory( LocalRelativeHandle );
  2881. }
  2882. LocalRelativeHandle = CurrentDirectory;
  2883. CurrentDirectory = INVALID_HANDLE_VALUE;
  2884. if(RemainingName.Length == 0)
  2885. {
  2886. break;
  2887. }
  2888. }
  2889. }
  2890. *NumComponentsExpanded = NumExpanded;
  2891. if(LocalRelativeHandle != RelativeHandle)
  2892. {
  2893. if(LocalRelativeHandle != INVALID_HANDLE_VALUE)
  2894. {
  2895. DfsCloseDirectory( LocalRelativeHandle );
  2896. LocalRelativeHandle = INVALID_HANDLE_VALUE;
  2897. }
  2898. }
  2899. DFS_TRACE_ERROR_LOW(NtStatus, REFERRAL_SERVER, "ExpandLinkDirectory: %wZ: Status %x\n",
  2900. pLinkName, NtStatus );
  2901. return NtStatus;
  2902. }
  2903. BOOLEAN
  2904. DfsRootFolder::IsAShortName(PUNICODE_STRING pLinkName)
  2905. {
  2906. ULONG idx = 0;
  2907. ULONG nameLen = 0;
  2908. BOOLEAN RetVal = FALSE;
  2909. if(pLinkName->Length == 0)
  2910. {
  2911. return FALSE;
  2912. }
  2913. nameLen = pLinkName->Length / sizeof(WCHAR);
  2914. for (idx = 0; idx < nameLen; idx++)
  2915. {
  2916. if (pLinkName->Buffer[idx] == L'~')
  2917. {
  2918. RetVal = TRUE;
  2919. break;
  2920. }
  2921. }
  2922. return RetVal;
  2923. }
  2924. NTSTATUS
  2925. DfsRootFolder::GetAShortName(HANDLE ParentHandle,
  2926. BOOLEAN *Expanded,
  2927. PUNICODE_STRING pLinkName,
  2928. PUNICODE_STRING pNewPath)
  2929. {
  2930. NTSTATUS NtStatus = STATUS_SUCCESS;
  2931. PFILE_NAMES_INFORMATION pFileEntry = NULL;
  2932. ULONG NameInformationSize = 0;
  2933. IO_STATUS_BLOCK ioStatusBlock;
  2934. UNICODE_STRING LongName;
  2935. UNICODE_STRING PathSep;
  2936. *Expanded = FALSE;
  2937. PathSep.Length = sizeof(UNICODE_PATH_SEP);
  2938. PathSep.MaximumLength = sizeof(UNICODE_PATH_SEP);
  2939. PathSep.Buffer = L"\\";
  2940. NameInformationSize = sizeof(FILE_NAMES_INFORMATION) + DFS_SHORTNAME_EXPANSION_SIZE;
  2941. pFileEntry = (PFILE_NAMES_INFORMATION) new BYTE [NameInformationSize];
  2942. if (pFileEntry != NULL)
  2943. {
  2944. NtStatus = NtQueryDirectoryFile( ParentHandle,
  2945. NULL,
  2946. NULL,
  2947. NULL,
  2948. &ioStatusBlock,
  2949. pFileEntry,
  2950. NameInformationSize,
  2951. FileNamesInformation,
  2952. TRUE, // ReturnSingleEntry
  2953. pLinkName,
  2954. TRUE ); // RestartScan
  2955. if(NtStatus == STATUS_SUCCESS)
  2956. {
  2957. LongName.Buffer = pFileEntry->FileName;
  2958. LongName.Length = LongName.MaximumLength = (USHORT) pFileEntry->FileNameLength;
  2959. DFS_TRACE_ERROR_LOW(NtStatus, REFERRAL_SERVER, "GetShortName: %wZ expanded to %wZ: Status %x\n",
  2960. pLinkName, &LongName, NtStatus );
  2961. if (RtlCompareUnicodeString(&LongName, pLinkName, TRUE) != 0)
  2962. {
  2963. *Expanded = TRUE;
  2964. NtStatus = CopyShortName(&LongName,
  2965. pNewPath);
  2966. }
  2967. else
  2968. {
  2969. *Expanded = FALSE;
  2970. NtStatus = CopyShortName(pLinkName,
  2971. pNewPath);
  2972. }
  2973. //
  2974. // A previous CopyShortName may have failed because
  2975. // we were out of resources.
  2976. //
  2977. if (NtStatus == STATUS_SUCCESS)
  2978. {
  2979. NtStatus = CopyShortName(&PathSep,
  2980. pNewPath);
  2981. }
  2982. }
  2983. delete [] pFileEntry;
  2984. pFileEntry = NULL;
  2985. }
  2986. else
  2987. {
  2988. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  2989. }
  2990. DFS_TRACE_ERROR_LOW(NtStatus, REFERRAL_SERVER, "GetShortName: Status %x\n",
  2991. NtStatus );
  2992. return NtStatus;
  2993. }
  2994. NTSTATUS
  2995. DfsRootFolder::CopyShortName(PUNICODE_STRING pNewName,
  2996. PUNICODE_STRING pNewPath)
  2997. {
  2998. NTSTATUS NtStatus = STATUS_SUCCESS;
  2999. ULONG NewMaxLength = 0;
  3000. PWSTR pNewBuffer = NULL;
  3001. do {
  3002. NtStatus = RtlAppendUnicodeStringToString(pNewPath, pNewName);
  3003. //
  3004. // If the append succeeded then we are done.
  3005. //
  3006. if (NtStatus != STATUS_BUFFER_TOO_SMALL)
  3007. {
  3008. break;
  3009. }
  3010. NewMaxLength = pNewPath->MaximumLength +
  3011. pNewName->Length +
  3012. (DFS_SHORTNAME_EXPANSION_SIZE * sizeof(WCHAR));
  3013. // unicode strings can't go beyond a ushort
  3014. if (NewMaxLength > MAXUSHORT)
  3015. {
  3016. NtStatus = STATUS_INVALID_PARAMETER;
  3017. break;
  3018. }
  3019. pNewBuffer = (PWSTR) new BYTE [NewMaxLength];
  3020. if (pNewBuffer == NULL)
  3021. {
  3022. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  3023. break;
  3024. }
  3025. if (pNewPath->Buffer)
  3026. {
  3027. RtlMoveMemory( pNewBuffer, pNewPath->Buffer, pNewPath->Length );
  3028. delete [] pNewPath->Buffer;
  3029. pNewPath->Buffer = NULL;
  3030. }
  3031. pNewPath->Buffer = pNewBuffer;
  3032. pNewPath->MaximumLength = (USHORT) NewMaxLength;
  3033. NtStatus = RtlAppendUnicodeStringToString(pNewPath, pNewName);
  3034. } while (FALSE);
  3035. return NtStatus;
  3036. }
  3037. void
  3038. DfsRootFolder::FreeShortNameData(PUNICODE_STRING pLinkName)
  3039. {
  3040. if(pLinkName->Buffer != NULL)
  3041. {
  3042. delete [] pLinkName->Buffer;
  3043. pLinkName->Buffer = NULL;
  3044. }
  3045. }
  3046. DFSSTATUS
  3047. DfsRootFolder::CreateRenameName(PUNICODE_STRING pNewName)
  3048. {
  3049. DFSSTATUS Status = ERROR_SUCCESS;
  3050. LPWSTR String = NULL;
  3051. UUID NewUid;
  3052. Status = UuidCreate(&NewUid);
  3053. if (Status == ERROR_SUCCESS)
  3054. {
  3055. Status = UuidToString( &NewUid,
  3056. &String );
  3057. if (Status == ERROR_SUCCESS)
  3058. {
  3059. Status = DfsCreateUnicodePathString ( pNewName,
  3060. 0, // no leading path sep
  3061. NULL,
  3062. String );
  3063. RpcStringFree(&String );
  3064. }
  3065. }
  3066. return Status;
  3067. }
  3068. DFSSTATUS
  3069. DfsRootFolder::RenamePath(PUNICODE_STRING ParentDirectory,
  3070. PUNICODE_STRING DirectoryToRename)
  3071. {
  3072. NTSTATUS NtStatus = STATUS_SUCCESS;
  3073. DFSSTATUS Status = ERROR_SUCCESS;
  3074. ULONG NewdirectoryNameSize = 0;
  3075. ULONG OlddirectoryNameSize = 0;
  3076. BOOL fMoved = FALSE;
  3077. PUNICODE_STRING pRootDir = NULL;
  3078. PWSTR NewBuffer = NULL;
  3079. PWSTR NewBuffer2 = NULL;
  3080. PWSTR OldName = NULL;
  3081. PWSTR NewName = NULL;
  3082. UNICODE_STRING NewFileName;
  3083. UNICODE_STRING OldFileName;
  3084. UNICODE_STRING PartialName;
  3085. UNICODE_STRING PathSep;
  3086. UNICODE_STRING DfsPrefix;
  3087. UNICODE_STRING UniNull;
  3088. pRootDir = GetDirectoryCreatePathName();
  3089. DfsRtlInitUnicodeStringEx( &NewFileName, NULL);
  3090. DfsRtlInitUnicodeStringEx( &OldFileName, NULL);
  3091. DfsRtlInitUnicodeStringEx( &PartialName, NULL);
  3092. PathSep.Length = sizeof(UNICODE_PATH_SEP);
  3093. PathSep.MaximumLength = sizeof(UNICODE_PATH_SEP);
  3094. PathSep.Buffer = L"\\";
  3095. UniNull.Length = sizeof(WCHAR);
  3096. UniNull.MaximumLength = sizeof(WCHAR);
  3097. UniNull.Buffer = L"\0";
  3098. DfsRtlInitUnicodeStringEx( &DfsPrefix, DFSRENAMEPREFIX);
  3099. Status = CreateRenameName(&PartialName);
  3100. if(Status == ERROR_SUCCESS)
  3101. {
  3102. NewdirectoryNameSize = pRootDir->Length + ParentDirectory->Length +
  3103. DirectoryToRename->Length +
  3104. PartialName.Length + (3 *PathSep.Length) +
  3105. DfsPrefix.Length+UniNull.Length;
  3106. NewBuffer = (PWSTR) new BYTE[NewdirectoryNameSize];
  3107. if(NewBuffer)
  3108. {
  3109. NewFileName.Buffer = NewBuffer;
  3110. NewFileName.MaximumLength = (USHORT)NewdirectoryNameSize;
  3111. NtStatus = RtlAppendUnicodeStringToString(&NewFileName, pRootDir);
  3112. NtStatus = RtlAppendUnicodeStringToString(&NewFileName, &PathSep);
  3113. NtStatus = RtlAppendUnicodeStringToString(&NewFileName, ParentDirectory);
  3114. NtStatus = RtlAppendUnicodeStringToString(&NewFileName, &PathSep);
  3115. NtStatus = RtlAppendUnicodeStringToString(&NewFileName, &DfsPrefix);
  3116. NtStatus = RtlAppendUnicodeToString(&NewFileName, &PartialName.Buffer[1]);
  3117. NtStatus = RtlAppendUnicodeStringToString(&NewFileName, DirectoryToRename);
  3118. NtStatus = RtlAppendUnicodeStringToString(&NewFileName, &UniNull);
  3119. }
  3120. else
  3121. {
  3122. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  3123. }
  3124. if(NtStatus == STATUS_SUCCESS)
  3125. {
  3126. OlddirectoryNameSize = pRootDir->Length + ParentDirectory->Length +
  3127. (2*PathSep.Length) + DirectoryToRename->Length +
  3128. UniNull.Length;
  3129. NewBuffer2 = (PWSTR) new BYTE[OlddirectoryNameSize];
  3130. if(NewBuffer2)
  3131. {
  3132. OldFileName.Buffer = NewBuffer2;
  3133. OldFileName.MaximumLength = (USHORT)OlddirectoryNameSize;
  3134. NtStatus = RtlAppendUnicodeStringToString(&OldFileName, pRootDir);
  3135. NtStatus = RtlAppendUnicodeStringToString(&OldFileName, &PathSep);
  3136. NtStatus = RtlAppendUnicodeStringToString(&OldFileName, ParentDirectory);
  3137. NtStatus = RtlAppendUnicodeStringToString(&OldFileName, &PathSep);
  3138. NtStatus = RtlAppendUnicodeStringToString(&OldFileName, DirectoryToRename);
  3139. NtStatus = RtlAppendUnicodeStringToString(&OldFileName, &UniNull);
  3140. }
  3141. else
  3142. {
  3143. NtStatus = STATUS_INSUFFICIENT_RESOURCES;
  3144. }
  3145. }
  3146. Status = RtlNtStatusToDosError(NtStatus);
  3147. if(Status == ERROR_SUCCESS)
  3148. {
  3149. OldName = &OldFileName.Buffer[DFSDIRWHACKQOFFSET];
  3150. NewName = &NewFileName.Buffer[DFSDIRWHACKQOFFSET];
  3151. fMoved = MoveFileW(OldName, NewName);
  3152. if(fMoved == FALSE)
  3153. {
  3154. Status = GetLastError();
  3155. }
  3156. }
  3157. }
  3158. if(PartialName.Buffer)
  3159. {
  3160. DfsFreeUnicodeString( &PartialName );
  3161. }
  3162. if(OldFileName.Buffer)
  3163. {
  3164. delete [] OldFileName.Buffer;
  3165. }
  3166. if(NewFileName.Buffer)
  3167. {
  3168. delete [] NewFileName.Buffer;
  3169. }
  3170. DFS_TRACE_ERROR_LOW(Status, REFERRAL_SERVER, "RenamePath, link %wZ, Status %x\n",
  3171. ParentDirectory, Status);
  3172. return Status;
  3173. }
  3174. NTSTATUS
  3175. StripAndReturnLastPathComponent(
  3176. PUNICODE_STRING pPath,
  3177. PUNICODE_STRING pLeaf)
  3178. {
  3179. USHORT i = 0, j = 0;
  3180. USHORT OriginalLength = 0;
  3181. NTSTATUS Status = STATUS_SUCCESS;
  3182. WCHAR *Src = NULL;
  3183. if (pPath->Length == 0)
  3184. {
  3185. return Status;
  3186. }
  3187. OriginalLength = pPath->Length;
  3188. for( i = (pPath->Length - 1)/ sizeof(WCHAR); i != 0; i--)
  3189. {
  3190. if (pPath->Buffer[i] != UNICODE_PATH_SEP)
  3191. {
  3192. break;
  3193. }
  3194. }
  3195. for (j = i; j != 0; j--)
  3196. {
  3197. if (pPath->Buffer[j] == UNICODE_PATH_SEP)
  3198. {
  3199. break;
  3200. }
  3201. }
  3202. //change the length of the orignal buffer to reflect
  3203. //that the last component was stripped off
  3204. pPath->Length = (j) * sizeof(WCHAR);
  3205. if(j > 0 )
  3206. {
  3207. Src = &pPath->Buffer[((pPath->Length + sizeof( WCHAR)) /sizeof( WCHAR ))];
  3208. pLeaf->Buffer = Src;
  3209. pLeaf->Length = OriginalLength - (pPath->Length + sizeof( WCHAR));
  3210. pLeaf->MaximumLength = pLeaf->Length;
  3211. }
  3212. else //didn't find any //s
  3213. {
  3214. Src = &pPath->Buffer[pPath->Length /sizeof( WCHAR )];
  3215. pLeaf->Buffer = Src;
  3216. pLeaf->Length = OriginalLength - (pPath->Length);
  3217. pLeaf->MaximumLength = pLeaf->Length;
  3218. }
  3219. return Status;
  3220. }
  3221. NTSTATUS
  3222. SendDataToSrv(PBYTE Buffer,
  3223. ULONG BUfferLength,
  3224. DWORD IoCtl)
  3225. {
  3226. NTSTATUS status = STATUS_SUCCESS;
  3227. HANDLE hMrxSmbHandle = NULL;
  3228. UNICODE_STRING unicodeServerName;
  3229. OBJECT_ATTRIBUTES objectAttributes;
  3230. IO_STATUS_BLOCK ioStatusBlock;
  3231. //
  3232. // Open the server device.
  3233. //
  3234. DfsRtlInitUnicodeStringEx( &unicodeServerName, SERVER_DEVICE_NAME );
  3235. InitializeObjectAttributes(
  3236. &objectAttributes,
  3237. &unicodeServerName,
  3238. OBJ_CASE_INSENSITIVE,
  3239. NULL,
  3240. NULL
  3241. );
  3242. //
  3243. // Opening the server with desired access = SYNCHRONIZE and open
  3244. // options = FILE_SYNCHRONOUS_IO_NONALERT means that we don't have
  3245. // to worry about waiting for the NtFsControlFile to complete--this
  3246. // makes all IO system calls that use this handle synchronous.
  3247. //
  3248. status = NtOpenFile(
  3249. &hMrxSmbHandle,
  3250. FILE_READ_DATA | FILE_WRITE_DATA,
  3251. &objectAttributes,
  3252. &ioStatusBlock,
  3253. 0,
  3254. 0
  3255. );
  3256. if ( NT_SUCCESS(status) ) {
  3257. status = NtFsControlFile( hMrxSmbHandle,
  3258. NULL,
  3259. NULL,
  3260. NULL,
  3261. &ioStatusBlock,
  3262. IoCtl,
  3263. Buffer,
  3264. BUfferLength,
  3265. NULL,
  3266. 0 );
  3267. NtClose( hMrxSmbHandle );
  3268. }
  3269. return status;
  3270. }
  3271. DFSSTATUS
  3272. SendShareToSrv(PUNICODE_STRING pShareName,
  3273. BOOLEAN fAttach)
  3274. {
  3275. NTSTATUS Status = STATUS_SUCCESS;
  3276. DFSSTATUS DosStatus = ERROR_SUCCESS;
  3277. PDFS_ATTACH_SHARE_BUFFER pBuffer = NULL;
  3278. DWORD SizeToAllocate = 0;
  3279. if((pShareName == NULL) || (pShareName->Buffer == NULL)
  3280. || (pShareName->Length == 0))
  3281. {
  3282. return ERROR_INVALID_PARAMETER;
  3283. }
  3284. SizeToAllocate = pShareName->Length
  3285. + sizeof(DFS_ATTACH_SHARE_BUFFER);
  3286. pBuffer = (PDFS_ATTACH_SHARE_BUFFER) HeapAlloc(GetProcessHeap(),
  3287. 0,
  3288. SizeToAllocate);
  3289. if(pBuffer != NULL)
  3290. {
  3291. pBuffer->ShareNameLength = pShareName->Length ;
  3292. pBuffer->fAttach = fAttach;
  3293. RtlCopyMemory(
  3294. &pBuffer->ShareName[0],
  3295. pShareName->Buffer,
  3296. pBuffer->ShareNameLength);
  3297. Status = SendDataToSrv((PBYTE) pBuffer,
  3298. SizeToAllocate,
  3299. FSCTL_DFS_UPDATE_SHARE_TABLE);
  3300. DosStatus = RtlNtStatusToDosError(Status);
  3301. if(pBuffer)
  3302. {
  3303. HeapFree(GetProcessHeap(), 0, pBuffer);
  3304. }
  3305. if(DosStatus != ERROR_SUCCESS)
  3306. {
  3307. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!] (1) %wZ status %x DosStatus %x\n", pShareName, Status, DosStatus);
  3308. }
  3309. }
  3310. else
  3311. {
  3312. DosStatus = ERROR_NOT_ENOUGH_MEMORY;
  3313. DFS_TRACE_ERROR_HIGH(Status, REFERRAL_SERVER, "[%!FUNC!] %wZ status %x\n", pShareName, DosStatus);
  3314. }
  3315. return DosStatus;
  3316. }