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

1466 lines
40 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: PKTFSCTL.C
  6. //
  7. // Contents: This module contains the implementation for FS controls
  8. // which manipulate the PKT.
  9. //
  10. // Functions: PktFsctrlGetRelationInfo -
  11. // PktFsctrlSetRelationInfo -
  12. // PktFsctrlIsChildnameLegal -
  13. // PktFsctrlCreateEntry -
  14. // PktFsctrlCreateSubordinateEntry -
  15. // PktFsctrlDestroyEntry -
  16. // PktFsctrlUpdateSiteCosts -
  17. // DfsAgePktEntries - Flush PKT entries periodically
  18. //
  19. // Private Functions
  20. //
  21. // DfspCreateExitPathOnRoot
  22. // PktpHashSiteCostList
  23. // PktpLookupSiteCost
  24. // PktpUpdateSiteCosts
  25. //
  26. // Debug Only Functions
  27. //
  28. // PktFsctrlFlushCache - Flush PKT entries on command
  29. //
  30. // History: 12 Jul 1993 Alanw Created from localvol.c.
  31. //
  32. //-----------------------------------------------------------------------------
  33. #include "dfsprocs.h"
  34. #include <dfserr.h>
  35. #include <netevent.h>
  36. #include "fsctrl.h"
  37. #include "log.h"
  38. #include "know.h"
  39. //
  40. // The local debug trace level
  41. //
  42. #define Dbg (DEBUG_TRACE_LOCALVOL)
  43. NTSTATUS
  44. DfspCreateExitPathOnRoot(
  45. PDFS_SERVICE service,
  46. PUNICODE_STRING RemPath
  47. );
  48. #ifdef ALLOC_PRAGMA
  49. #pragma alloc_text( PAGE, PktFsctrlGetRelationInfo )
  50. #pragma alloc_text( PAGE, PktFsctrlVerifyLocalVolumeKnowledge )
  51. #pragma alloc_text( PAGE, PktFsctrlPruneLocalVolume )
  52. #pragma alloc_text( PAGE, PktFsctrlCreateEntry )
  53. #pragma alloc_text( PAGE, PktFsctrlCreateSubordinateEntry )
  54. #pragma alloc_text( PAGE, PktFsctrlDestroyEntry )
  55. #pragma alloc_text( PAGE, DfsAgePktEntries )
  56. #pragma alloc_text( PAGE, DfspCreateExitPathOnRoot )
  57. #if DBG
  58. #pragma alloc_text( PAGE, PktFsctrlFlushCache )
  59. #endif // DBG
  60. #endif // ALLOC_PRAGMA
  61. //+-------------------------------------------------------------------------
  62. //
  63. // Function: DfspCreateExitPathOnRoot
  64. //
  65. // Synopsis: This function creates an on disk exit path on the ORGROOT vol
  66. //
  67. // Arguments:
  68. //
  69. // Returns:
  70. //
  71. //--------------------------------------------------------------------------
  72. NTSTATUS
  73. DfspCreateExitPathOnRoot(
  74. PDFS_SERVICE service,
  75. PUNICODE_STRING RemPath
  76. )
  77. {
  78. NTSTATUS status = STATUS_SUCCESS;
  79. UNICODE_STRING ExitPath;
  80. status = BuildLocalVolPath(&ExitPath, service, RemPath);
  81. if (NT_SUCCESS(status)) {
  82. //
  83. // For now make sure that StorageId Exists. Dont worry about the
  84. // actual exit pt bit on it. Fix when EXIT_PTs come along.
  85. //
  86. if (DfsFixExitPath(ExitPath.Buffer)) {
  87. DebugTrace(0, Dbg, "Succeeded to Create ExitPth on Orgroot %wZ\n",
  88. &ExitPath);
  89. status = STATUS_SUCCESS;
  90. }
  91. else {
  92. DebugTrace(0, Dbg, "Failed to Create ExitPath on Orgroot %wZ\n",
  93. &ExitPath);
  94. status = DFS_STATUS_BAD_EXIT_POINT;
  95. }
  96. ExFreePool(ExitPath.Buffer);
  97. }
  98. else {
  99. DebugTrace(0, Dbg, "Failed to create localvol path for %wZ \n",
  100. RemPath);
  101. }
  102. return(status);
  103. }
  104. //+-------------------------------------------------------------------------
  105. //
  106. // Function: PktFsctrlGetRelationInfo, public
  107. //
  108. // Synopsis:
  109. //
  110. // Arguments:
  111. //
  112. // Returns:
  113. //
  114. // Notes: We only process this FSCTRL from the file system process,
  115. // never from the driver.
  116. //
  117. //--------------------------------------------------------------------------
  118. NTSTATUS
  119. PktFsctrlGetRelationInfo(
  120. IN PIRP Irp,
  121. IN PVOID InputBuffer,
  122. IN ULONG InputBufferLength,
  123. IN PVOID OutputBuffer,
  124. IN ULONG OutputBufferLength
  125. )
  126. {
  127. NTSTATUS status = STATUS_SUCCESS;
  128. DFS_PKT_ENTRY_ID EntryId;
  129. DFS_PKT_RELATION_INFO relationInfo;
  130. ULONG size = 0;
  131. MARSHAL_BUFFER marshalBuffer;
  132. STD_FSCTRL_PROLOGUE(PktFsctrlGetRelationInfo, TRUE, TRUE );
  133. //
  134. // Unmarshal the argument...
  135. //
  136. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  137. status = DfsRtlGet(&marshalBuffer, &MiPktEntryId, &EntryId);
  138. if (NT_SUCCESS(status)) {
  139. PDFS_PKT pkt = _GetPkt();
  140. status = PktRelationInfoConstruct(&relationInfo, pkt, &EntryId);
  141. if (NT_SUCCESS(status)) {
  142. DfsRtlSize(&MiPktRelationInfo, &relationInfo, &size);
  143. if (size>OutputBufferLength) {
  144. status = STATUS_INSUFFICIENT_RESOURCES;
  145. } else {
  146. MarshalBufferInitialize(&marshalBuffer,
  147. size,
  148. OutputBuffer);
  149. DfsRtlPut(&marshalBuffer,
  150. &MiPktRelationInfo,
  151. &relationInfo);
  152. }
  153. //
  154. // Now we have to free up the relation info struct that we
  155. // created above.
  156. //
  157. PktRelationInfoDestroy(&relationInfo, FALSE);
  158. }
  159. PktEntryIdDestroy(&EntryId, FALSE);
  160. } else
  161. DebugTrace(0, Dbg,
  162. "PktFsctrlGetRelationInfo: Unmarshalling Error!\n", 0);
  163. Irp->IoStatus.Information = marshalBuffer.Current - marshalBuffer.First;
  164. DfsCompleteRequest( Irp, status );
  165. DebugTrace(-1, Dbg, "PktFsctrlGetRelationInfo: Exit -> %08lx\n", ULongToPtr( status ));
  166. return(status);
  167. }
  168. //+-------------------------------------------------------------------------
  169. //
  170. // Function: PktFsctrlSetRelationInfo, public
  171. //
  172. // Synopsis:
  173. //
  174. // Arguments:
  175. //
  176. // Returns:
  177. //
  178. // Notes: We only process this FSCTRL from the file system process,
  179. // never from the driver.
  180. //
  181. //--------------------------------------------------------------------------
  182. NTSTATUS
  183. PktFsctrlSetRelationInfo(
  184. IN PIRP Irp,
  185. IN PVOID InputBuffer,
  186. IN ULONG InputBufferLength
  187. )
  188. {
  189. NTSTATUS status = STATUS_SUCCESS;
  190. DFS_PKT_RELATION_INFO relationInfo;
  191. MARSHAL_BUFFER marshalBuffer;
  192. STD_FSCTRL_PROLOGUE(PktFsctrlSetRelationInfo, TRUE, FALSE);
  193. //
  194. // Unmarshal the argument...
  195. //
  196. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  197. status = DfsRtlGet(&marshalBuffer, &MiPktRelationInfo, &relationInfo);
  198. if (NT_SUCCESS(status)) {
  199. PDFS_PKT pkt = _GetPkt();
  200. status = PktSetRelationInfo(
  201. pkt,
  202. &relationInfo
  203. );
  204. //
  205. // Need to deallocate the relationInfo...
  206. //
  207. PktRelationInfoDestroy(&relationInfo, FALSE);
  208. } else
  209. DebugTrace(0, Dbg,
  210. "PktFsctrlSetRelationInfo: Unmarshalling Error!\n", 0);
  211. DfsCompleteRequest( Irp, status );
  212. DebugTrace(-1, Dbg, "PktFsctrlSetRelationInfo: Exit -> %08lx\n", ULongToPtr( status ));
  213. return status;
  214. }
  215. //+----------------------------------------------------------------------------
  216. //
  217. // Function: PktFsctrlIsChildnameLegal, public
  218. //
  219. // Synopsis: Determines whether the given childname is a valid one for
  220. // the given parent prefix.
  221. //
  222. // Arguments:
  223. //
  224. // Returns: [STATUS_SUCCESS] -- The childname is legal
  225. //
  226. // [STATUS_OBJECT_NAME_COLLISION] -- The childname conflicts with
  227. // another child of the parent prefix.
  228. //
  229. // [STATUS_OBJECT_PATH_NOT_FOUND] -- The childname is not a
  230. // hierarchically related to the parent
  231. //
  232. // [STATUS_INVALID_PARAMETER] -- The childname is bogus and
  233. // doesn't start with a backslash
  234. //
  235. // [STATUS_DATA_ERROR] -- If the input buffer could not be
  236. // unmarshalled.
  237. //
  238. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory unmarshalling
  239. // input buffer.
  240. //
  241. //-----------------------------------------------------------------------------
  242. NTSTATUS
  243. PktFsctrlIsChildnameLegal(
  244. IN PIRP Irp,
  245. IN PVOID InputBuffer,
  246. IN ULONG InputBufferLength)
  247. {
  248. NTSTATUS status;
  249. MARSHAL_BUFFER marshalBuffer;
  250. DFS_PKT_ENTRY_ID idParent;
  251. DFS_PKT_ENTRY_ID idChild;
  252. UNICODE_STRING ustrRem;
  253. STD_FSCTRL_PROLOGUE(PktFsctrlIsChildnameLegal, TRUE, FALSE);
  254. MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
  255. status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &idParent );
  256. if (NT_SUCCESS(status)) {
  257. status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &idChild );
  258. if (NT_SUCCESS(status)) {
  259. PDFS_PKT pPkt = _GetPkt();
  260. PDFS_PKT_ENTRY pPktEntry, pSuperiorEntry;
  261. ustrRem.Length = ustrRem.MaximumLength = 0;
  262. ustrRem.Buffer = NULL;
  263. PktAcquireShared( pPkt, TRUE );
  264. pPktEntry = PktLookupEntryByPrefix(
  265. pPkt,
  266. &idChild.Prefix,
  267. &ustrRem);
  268. if (pPktEntry != NULL) {
  269. if (ustrRem.Length != 0) {
  270. //
  271. // There is no exact match for the child, so
  272. // lets check to see if the match occured with the
  273. // parent prefix.
  274. //
  275. if (RtlCompareUnicodeString(
  276. &idParent.Prefix,
  277. &pPktEntry->Id.Prefix,
  278. FALSE) == 0) {
  279. status = STATUS_SUCCESS;
  280. } else {
  281. status = STATUS_OBJECT_NAME_COLLISION;
  282. }
  283. } else {
  284. //
  285. // This might be a legal child name. Check to see if the
  286. // passed-in child guid matches the one in the pkt entry
  287. // we found; if so, then this is a valid child name.
  288. //
  289. if (GuidEqual(&idChild.Uid, &pPktEntry->Id.Uid)) {
  290. status = STATUS_SUCCESS;
  291. } else {
  292. status = STATUS_OBJECT_NAME_COLLISION;
  293. }
  294. }
  295. } else {
  296. status = STATUS_INVALID_PARAMETER;
  297. }
  298. PktRelease( pPkt );
  299. PktEntryIdDestroy(&idChild, FALSE);
  300. }
  301. PktEntryIdDestroy(&idParent, FALSE);
  302. }
  303. DfsCompleteRequest( Irp, status );
  304. DebugTrace(-1, Dbg, "PktFsctrlIsChildnameLegal: Exit -> %08lx\n", ULongToPtr( status ));
  305. return status;
  306. }
  307. //+-------------------------------------------------------------------------
  308. //
  309. // Function: PktFsctrlCreateEntry, public
  310. //
  311. // Synopsis:
  312. //
  313. // Arguments:
  314. //
  315. // Returns:
  316. //
  317. // Notes: We only process this FSCTRL from the file system process,
  318. // never from the driver.
  319. //
  320. //--------------------------------------------------------------------------
  321. NTSTATUS
  322. PktFsctrlCreateEntry(
  323. IN PIRP Irp,
  324. IN PVOID InputBuffer,
  325. IN ULONG InputBufferLength
  326. )
  327. {
  328. NTSTATUS status = STATUS_SUCCESS;
  329. DFS_PKT_CREATE_ENTRY_ARG arg;
  330. MARSHAL_BUFFER marshalBuffer;
  331. STD_FSCTRL_PROLOGUE(PktFsctrlCreateEntry, TRUE, FALSE);
  332. //
  333. // Unmarshal the argument...
  334. //
  335. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  336. status = DfsRtlGet(&marshalBuffer, &MiPktCreateEntryArg, &arg);
  337. if (NT_SUCCESS(status)) {
  338. PDFS_PKT pkt = _GetPkt();
  339. PDFS_PKT_ENTRY entry;
  340. ULONG i;
  341. PktAcquireExclusive(pkt, TRUE);
  342. try {
  343. status = PktCreateEntry(pkt,
  344. arg.EntryType,
  345. &arg.EntryId,
  346. &arg.EntryInfo,
  347. arg.CreateDisposition,
  348. &entry);
  349. } finally {
  350. PktRelease(pkt);
  351. }
  352. //
  353. // Need to deallocate the entry Id...
  354. //
  355. PktEntryIdDestroy(&arg.EntryId, FALSE);
  356. PktEntryInfoDestroy(&arg.EntryInfo, FALSE);
  357. } else
  358. DebugTrace(0, Dbg, "PktFsctrlCreateEntry: Unmarshalling Error!\n", 0);
  359. DfsCompleteRequest( Irp, status );
  360. DebugTrace(-1, Dbg, "PktFsctrlCreateEntry: Exit -> %08lx\n", ULongToPtr( status ));
  361. return status;
  362. }
  363. //+-------------------------------------------------------------------------
  364. //
  365. // Function: PktFsctrlCreateSubordinateEntry, public
  366. //
  367. // Synopsis:
  368. //
  369. // Arguments:
  370. //
  371. // Returns:
  372. //
  373. // Notes: We only process this FSCTRL from the file system process,
  374. // never from the driver.
  375. //
  376. //--------------------------------------------------------------------------
  377. NTSTATUS
  378. PktFsctrlCreateSubordinateEntry(
  379. IN PIRP Irp,
  380. IN PVOID InputBuffer,
  381. IN ULONG InputBufferLength
  382. )
  383. {
  384. NTSTATUS status = STATUS_SUCCESS;
  385. DFS_PKT_CREATE_SUBORDINATE_ENTRY_ARG arg;
  386. MARSHAL_BUFFER marshalBuffer;
  387. STD_FSCTRL_PROLOGUE(PktFsctrlCreateSubordinateEntry, TRUE, FALSE);
  388. //
  389. // Unmarshal the argument...
  390. //
  391. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  392. status = DfsRtlGet(&marshalBuffer, &MiPktCreateSubordinateEntryArg, &arg);
  393. if (NT_SUCCESS(status)) {
  394. PDFS_PKT pkt = _GetPkt();
  395. PDFS_PKT_ENTRY superior;
  396. PDFS_PKT_ENTRY subEntry;
  397. PktAcquireExclusive(pkt, TRUE);
  398. try {
  399. superior = PktLookupEntryById(pkt, &arg.EntryId);
  400. if (superior != NULL) {
  401. status = PktCreateSubordinateEntry(
  402. pkt,
  403. superior,
  404. arg.SubEntryType,
  405. &arg.SubEntryId,
  406. &arg.SubEntryInfo,
  407. arg.CreateDisposition,
  408. &subEntry);
  409. } else {
  410. DebugTrace(0, Dbg,
  411. "PktFsctrlCreateSubordinateEntry: No Superior!\n", 0);
  412. status = DFS_STATUS_NO_SUCH_ENTRY;
  413. }
  414. } finally {
  415. PktRelease(pkt);
  416. }
  417. //
  418. // Need to deallocate the entry Id...
  419. //
  420. PktEntryIdDestroy(&arg.EntryId, FALSE);
  421. PktEntryIdDestroy(&arg.SubEntryId, FALSE);
  422. PktEntryInfoDestroy(&arg.SubEntryInfo, FALSE);
  423. } else {
  424. DebugTrace(0, Dbg,
  425. "PktFsctrlCreateSubordinateEntry: Unmarshalling Error!\n", 0);
  426. }
  427. DfsCompleteRequest( Irp, status );
  428. DebugTrace(-1, Dbg,
  429. "PktFsctrlCreateSubordinateEntry: Exit -> %08lx\n", ULongToPtr( status ));
  430. return status;
  431. }
  432. //+-------------------------------------------------------------------------
  433. //
  434. // Function: PktFsctrlDestroyEntry, public
  435. //
  436. // Synopsis:
  437. //
  438. // Arguments:
  439. //
  440. // Returns:
  441. //
  442. // Notes: We only process this FSCTRL from the file system process,
  443. // never from the driver.
  444. //
  445. //--------------------------------------------------------------------------
  446. NTSTATUS
  447. PktFsctrlDestroyEntry(
  448. IN PIRP Irp,
  449. IN PVOID InputBuffer,
  450. IN ULONG InputBufferLength
  451. )
  452. {
  453. NTSTATUS status = STATUS_SUCCESS;
  454. DFS_PKT_ENTRY_ID Id;
  455. MARSHAL_BUFFER marshalBuffer;
  456. PDFS_PKT_ENTRY victim;
  457. STD_FSCTRL_PROLOGUE(PktFsctrlDestroyEntry, TRUE, FALSE);
  458. //
  459. // Unmarshal the argument...
  460. //
  461. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  462. status = DfsRtlGet(&marshalBuffer, &MiPktEntryId, &Id);
  463. if (NT_SUCCESS(status)) {
  464. PDFS_PKT pkt = _GetPkt();
  465. PktAcquireExclusive(pkt, TRUE);
  466. victim = PktLookupEntryById(pkt, &Id);
  467. if (victim != NULL) {
  468. //
  469. // If there is a local service we first need to delete this
  470. // explicitly before we call PktEntryDestroy.
  471. //
  472. if (victim->LocalService) {
  473. UNICODE_STRING a, b;
  474. RtlInitUnicodeString(&b, L"\\");
  475. BuildLocalVolPath(&a, victim->LocalService, &b);
  476. PktEntryRemoveLocalService(pkt, victim, &a);
  477. }
  478. PktEntryDestroy( victim, pkt, (BOOLEAN) TRUE);
  479. } else {
  480. DebugTrace(0, Dbg, "PktFsctrlDestroyEntry: No Superior!\n", 0);
  481. status = DFS_STATUS_NO_SUCH_ENTRY;
  482. }
  483. PktRelease(pkt);
  484. //
  485. // Need to deallocate the entry Id...
  486. //
  487. PktEntryIdDestroy(&Id, FALSE);
  488. } else
  489. DebugTrace(0, Dbg,
  490. "PktFsctrlDestroyEntry: Unmarshalling Error!\n", 0);
  491. DfsCompleteRequest( Irp, status );
  492. DebugTrace(-1, Dbg,
  493. "PktFsctrlDestroyEntry: Exit -> %08lx\n", ULongToPtr(status) );
  494. return status;
  495. }
  496. //+----------------------------------------------------------------------------
  497. //
  498. // Function: PktpPruneAllExtraVolumes
  499. //
  500. // Synopsis: Given a set of relation infos, this helper routine will
  501. // prune all local volume entries in the pkt that are not present
  502. // in the input set of relation infos.
  503. //
  504. // Arguments: [pPkt] -- The pkt to operate upon. Should be acquired
  505. // exclusive
  506. // [cInfo] -- The number of config infos in the set
  507. // [pInfo] -- The set of config infos
  508. //
  509. // Returns: [STATUS_SUCCESS] -- No extra volumes were found.
  510. //
  511. // [STATUS_REGISTRY_RECOVERED] -- Extra volumes were found and
  512. // were successfully recovered.
  513. //
  514. // [STATUS_UNSUCCESSFUL] -- Extra volumes were found but could
  515. // not be deleted. A detailed error was logged.
  516. //
  517. // Notes: Assumes Pkt has been acquired exclusive
  518. //
  519. //-----------------------------------------------------------------------------
  520. NTSTATUS
  521. PktpPruneAllExtraVolumes(
  522. PDFS_PKT pPkt,
  523. ULONG cInfo,
  524. PDFS_LOCAL_VOLUME_CONFIG pInfo)
  525. {
  526. //
  527. // 447479: init return status.
  528. NTSTATUS status, returnStatus = STATUS_UNSUCCESSFUL;
  529. PDFS_PKT_ENTRY pPktEntry;
  530. ULONG i, j;
  531. BOOLEAN fExtra;
  532. //
  533. // This is a pretty brute-force algorithm - for each Pkt entry that is
  534. // local, we scan the entire set of infos looking for a match. If a
  535. // match is not found, we delete the local volume.
  536. //
  537. pPktEntry = CONTAINING_RECORD(pPkt->EntryList.Flink, DFS_PKT_ENTRY, Link);
  538. for (i = 0, status = STATUS_SUCCESS;
  539. i < pPkt->EntryCount && NT_SUCCESS(status);
  540. i++) {
  541. for (j = 0, fExtra = TRUE; j < cInfo && fExtra; j++) {
  542. if (GuidEqual( &pInfo[j].RelationInfo.EntryId.Uid, &pPktEntry->Id.Uid)) {
  543. fExtra = FALSE;
  544. }
  545. }
  546. if (fExtra && !(pPktEntry->Type & PKT_ENTRY_TYPE_MACHINE)) {
  547. DebugTrace(0, Dbg,
  548. "Pruning Extra volume [%wZ]\n", &pPktEntry->Id.Prefix);
  549. status = DfsInternalDeleteLocalVolume( &pPktEntry->Id );
  550. if (!NT_SUCCESS(status)) {
  551. UNICODE_STRING puStr[2];
  552. puStr[0] = pPktEntry->Id.Prefix;
  553. puStr[1].MaximumLength = sizeof(L"LocalMachine");
  554. puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
  555. puStr[1].Buffer = L"LocalMachine";
  556. LogWriteMessage(
  557. EXTRA_VOLUME_NOT_DELETED,
  558. status,
  559. 2,
  560. puStr);
  561. returnStatus = STATUS_UNSUCCESSFUL;
  562. } else {
  563. returnStatus = STATUS_REGISTRY_RECOVERED;
  564. }
  565. }
  566. pPktEntry =
  567. CONTAINING_RECORD(pPktEntry->Link.Flink, DFS_PKT_ENTRY, Link);
  568. }
  569. return( returnStatus );
  570. }
  571. //+----------------------------------------------------------------------------
  572. //
  573. // Function: PktpResetOneLocalVolume
  574. //
  575. // Synopsis: Given a relation info (as sent over by the DC), this routine
  576. // will locate a pkt entry for the given volume. If such an
  577. // entry is found, this routine will try to sync up the relation
  578. // info to that of the passed in info.
  579. //
  580. // Arguments: [pPkt] -- The pkt to operate upon. Should be acquired
  581. // exclusive
  582. // [pRemoteInfo] -- The DFS_LOCAL_VOLUME_CONFIG_INFO sent by the
  583. // DC.
  584. //
  585. // Returns: [STATUS_SUCCESS] -- Either there is no such local volume in
  586. // the Pkt, or the local volume's relation info is in
  587. // exact sync.
  588. //
  589. // [STATUS_REGISTRY_RECOVERED] -- Found a local volume, and
  590. // steps were taken to bring it in sync with the
  591. // passed in relation info.
  592. //
  593. // [STATUS_UNSUCCESSFUL] -- Found a local volume, and in
  594. // taking steps to bring it in sync, an error was
  595. // encountered. A detailed message has been logged.
  596. //
  597. // History: April 6, 1995 Milans created
  598. //
  599. //-----------------------------------------------------------------------------
  600. NTSTATUS
  601. PktpResetOneLocalVolume(
  602. PDFS_PKT pPkt,
  603. PDFS_LOCAL_VOLUME_CONFIG pRemoteInfo)
  604. {
  605. NTSTATUS status = STATUS_SUCCESS;
  606. PDFS_PKT_ENTRY pPktEntry;
  607. UNICODE_STRING LocalMachStr;
  608. LocalMachStr.MaximumLength = sizeof(L"LocalMachine");
  609. LocalMachStr.Length = LocalMachStr.MaximumLength - sizeof(WCHAR);
  610. LocalMachStr.Buffer = L"LocalMachine";
  611. pPktEntry = PktLookupEntryByUid( pPkt, &pRemoteInfo->RelationInfo.EntryId.Uid );
  612. if (pPktEntry != NULL) {
  613. DFS_PKT_RELATION_INFO LocalInfo;
  614. //
  615. // We found a matching pkt entry in the local pkt. Lets see
  616. // if it is in sync with the input relation info.
  617. //
  618. status = PktRelationInfoConstruct(
  619. &LocalInfo,
  620. pPkt,
  621. &pPktEntry->Id);
  622. if (NT_SUCCESS(status)) {
  623. status = PktRelationInfoValidate(
  624. &LocalInfo,
  625. &pRemoteInfo->RelationInfo,
  626. LocalMachStr);
  627. if (status == DFS_STATUS_RESYNC_INFO) {
  628. status = PktpFixupRelationInfo(
  629. &LocalInfo,
  630. &pRemoteInfo->RelationInfo);
  631. if (NT_SUCCESS(status)) {
  632. status = STATUS_REGISTRY_RECOVERED;
  633. }
  634. }
  635. }
  636. } else {
  637. status = DFS_STATUS_NOSUCH_LOCAL_VOLUME;
  638. }
  639. return( status );
  640. }
  641. //+----------------------------------------------------------------------------
  642. //
  643. // Function: PktpCreateIfMissing
  644. //
  645. // Synopsis: Given a relation info for a local volume, this routine
  646. // will create a local volume matching the relation info if
  647. // a volume with the given guid does not already exist.
  648. //
  649. // Arguments: [pPkt] -- The pkt to operate upon. Should be acquired
  650. // exclusive
  651. // [pInfo] -- The local volume config info required to recreate
  652. // the local volume.
  653. //
  654. // Returns: [STATUS_SUCCESS] -- The local volume already exists. Doesn't
  655. // guarantee that the relation info matches, just that
  656. // there is already a pkt entry for the given guid.
  657. //
  658. // [STATUS_REGISTRY_RECOVERED] -- The local volume was missing
  659. // and was successfully recreated.
  660. //
  661. // [STATUS_UNSUCCESSFUL] -- The local volume is missing, and
  662. // an error was encountered while recreating it; a
  663. // more detailed error message has been logged.
  664. //
  665. // History: April 6, 1995 Milans created
  666. //
  667. //-----------------------------------------------------------------------------
  668. NTSTATUS
  669. PktpCreateIfMissing(
  670. PDFS_PKT pPkt,
  671. PDFS_LOCAL_VOLUME_CONFIG pInfo)
  672. {
  673. NTSTATUS status = STATUS_SUCCESS;
  674. PDFS_PKT_ENTRY pPktEntry;
  675. pPktEntry = PktLookupEntryByUid( pPkt, &pInfo->RelationInfo.EntryId.Uid );
  676. if (pPktEntry == NULL) {
  677. //
  678. // There is no local volume matching pInfo. We try to recreate it.
  679. //
  680. pInfo->EntryType = PKT_ENTRY_TYPE_CAIRO;
  681. pInfo->ServiceType |= DFS_SERVICE_TYPE_MASTER;
  682. status = DfsInternalCreateLocalPartition(
  683. &pInfo->StgId,
  684. TRUE,
  685. pInfo);
  686. if (!NT_SUCCESS(status)) {
  687. UNICODE_STRING puStr[2];
  688. puStr[0] = pInfo->RelationInfo.EntryId.Prefix;
  689. puStr[1].MaximumLength = sizeof(L"LocalMachine");
  690. puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
  691. puStr[1].Buffer = L"LocalMachine";
  692. LogWriteMessage(
  693. MISSING_VOLUME_NOT_CREATED,
  694. status,
  695. 2,
  696. puStr);
  697. status = STATUS_UNSUCCESSFUL;
  698. } else {
  699. status = STATUS_REGISTRY_RECOVERED;
  700. }
  701. }
  702. return( status );
  703. }
  704. //+----------------------------------------------------------------------------
  705. //
  706. // Function: PktpResetLocalVolumes
  707. //
  708. // Synopsis: Given an array of relation infos for local volumes, this
  709. // routine will set the pkt to match the entire set of infos.
  710. // Local volumes in the pkt but not in the set of infos will
  711. // be deleted. Local volumes in the pkt and in the set will
  712. // be modified if needed to match the info in the set. Lastly,
  713. // infos in the set but not in the pkt will result in a new
  714. // local volume being created.
  715. //
  716. // Arguments: [cInfo] -- The number of config infos passed in.
  717. // [pInfo] -- The array of DFS_LOCAL_VOLUME_CONFIG structs.
  718. //
  719. // Returns: [STATUS_SUCCESS] -- The pkt is already in sync with the
  720. // passed in set of relation infos.
  721. //
  722. // [STATUS_REGISTRY_RECOVERED] -- The pkt was successfully
  723. // brought in sync with the passed in infos; some
  724. // needed changes were made and messages were logged.
  725. // THIS IS AN NT INFORMATION STATUS CODE!
  726. //
  727. // [STATUS_UNSUCCESSFUL] -- Unable to bring the pkt in sync;
  728. // The problem was logged.
  729. //
  730. //-----------------------------------------------------------------------------
  731. NTSTATUS
  732. PktpResetLocalVolumes(
  733. ULONG cInfo,
  734. PDFS_LOCAL_VOLUME_CONFIG pInfo)
  735. {
  736. PDFS_PKT pPkt;
  737. NTSTATUS status, returnStatus;
  738. ULONG i;
  739. pPkt = _GetPkt();
  740. PktAcquireExclusive( pPkt, TRUE );
  741. //
  742. // First, we need to see if we have any extra volumes, and if so, we
  743. // need to prune them
  744. //
  745. status = PktpPruneAllExtraVolumes( pPkt, cInfo, pInfo );
  746. if (NT_SUCCESS(status)) {
  747. returnStatus = status;
  748. //
  749. // Next, we need to sync up all the local volumes which are
  750. // out of sync
  751. //
  752. for (i = 0; i < cInfo && NT_SUCCESS(status); i++) {
  753. status = PktpResetOneLocalVolume( pPkt, &pInfo[i] );
  754. if (status == STATUS_REGISTRY_RECOVERED) {
  755. returnStatus = status;
  756. }
  757. }
  758. //
  759. // Lastly, we need to create any missing volumes
  760. //
  761. for (i = 0; i < cInfo && NT_SUCCESS(status); i++) {
  762. status = PktpCreateIfMissing( pPkt, &pInfo[i] );
  763. if (status == STATUS_REGISTRY_RECOVERED) {
  764. returnStatus = status;
  765. }
  766. }
  767. }
  768. PktRelease( pPkt );
  769. if (!NT_SUCCESS(status)) {
  770. returnStatus = STATUS_UNSUCCESSFUL;
  771. }
  772. return( returnStatus );
  773. }
  774. //+----------------------------------------------------------------------------
  775. //
  776. // Function: PktFsctrlSetServerInfo
  777. //
  778. // Synopsis: During the course of Dfs admin operations, the DC might
  779. // discover that a particular server's knowledge does not agree
  780. // with its own. If that is the case, the DC will try to force
  781. // the server to sync up to its knowledge.
  782. //
  783. // Arguments:
  784. //
  785. // Returns: [STATUS_SUCCESS] -- The pkt is already in sync with the
  786. // passed in set of relation infos.
  787. //
  788. // [STATUS_REGISTRY_RECOVERED] -- The pkt was successfully
  789. // brought in sync with the passed in infos; some
  790. // needed changes were made and messages were logged.
  791. // THIS IS AN NT INFORMATION STATUS CODE!
  792. //
  793. // [STATUS_UNSUCCESSFUL] -- Unable to bring the pkt in sync;
  794. // The problem was logged.
  795. //
  796. // [STATUS_INSUFFICIENT_RESOURCES] -- Unable to unmarshal
  797. // arguments or otherwise out of memory
  798. //
  799. // [STATUS_INVALID_DOMAIN_ROLE] -- Can't set server info because
  800. // this machine is a DC.
  801. //
  802. //-----------------------------------------------------------------------------
  803. NTSTATUS
  804. PktFsctrlSetServerInfo(
  805. IN PIRP Irp,
  806. IN PVOID InputBuffer,
  807. IN ULONG InputBufferLength)
  808. {
  809. NTSTATUS status = STATUS_SUCCESS;
  810. MARSHAL_BUFFER marshalBuffer;
  811. ULONG i, cInfo;
  812. PDFS_LOCAL_VOLUME_CONFIG pInfos = NULL;
  813. STD_FSCTRL_PROLOGUE(PktFsctrlSetServerInfo, TRUE, FALSE);
  814. //
  815. // First, check to see if this machine is a DC. If so, we should not
  816. // muck with our Pkt!
  817. //
  818. if (DfsData.MachineState == DFS_ROOT_SERVER) {
  819. DebugTrace(0, Dbg, "Ignoring SetServerInfo call on DC!\n", 0);
  820. status = STATUS_INVALID_DOMAIN_ROLE;
  821. } else {
  822. MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
  823. status = DfsRtlGetUlong( &marshalBuffer, &cInfo );
  824. }
  825. if (NT_SUCCESS(status) && cInfo > 0) {
  826. //
  827. // We want to get all the config infos first, and then fix up each
  828. // instead of unmarshalling and fixing them one by one. This way,
  829. // we won't get messeded up if we hit an unmarshalling error after
  830. // having fixed up some of our local volumes.
  831. //
  832. ULONG cbSize;
  833. cbSize = sizeof(DFS_LOCAL_VOLUME_CONFIG) * cInfo;
  834. if ((cbSize / cInfo) == sizeof(DFS_LOCAL_VOLUME_CONFIG)) {
  835. pInfos = ExAllocatePoolWithTag(PagedPool,cbSize, ' sfD');
  836. if (pInfos != NULL) {
  837. DebugTrace(0, Dbg, "Unmarshalling %d Config Infos\n", ULongToPtr( cInfo ));
  838. for (i = 0; i < cInfo && NT_SUCCESS(status); i++) {
  839. status = DfsRtlGet(
  840. &marshalBuffer,
  841. &MiLocalVolumeConfig,
  842. &pInfos[i]);
  843. }
  844. if (!NT_SUCCESS(status)) {
  845. //
  846. // Unmarshalling error - cleanup
  847. //
  848. DebugTrace(0, Dbg, "Error %08lx unmarshalling ", ULongToPtr( status ));
  849. DebugTrace(0, Dbg, "the %d th relation info", ULongToPtr( i ));
  850. for ( ; i > 0; i--) {
  851. LocalVolumeConfigInfoDestroy( &pInfos[i-1], FALSE );
  852. }
  853. }
  854. } else {
  855. DebugTrace(0, Dbg, "Unable to allocate %d bytes\n", ULongToPtr( cbSize ));
  856. status = STATUS_INSUFFICIENT_RESOURCES;
  857. }
  858. } else {
  859. DebugTrace(0, Dbg, "Interger overflow in %s\n", __FILE__);
  860. status = STATUS_INVALID_PARAMETER;
  861. }
  862. if (NT_SUCCESS(status)) {
  863. DebugTrace(0, Dbg, "Successfully unmarshalled %d Infos\n", ULongToPtr( cInfo ));
  864. status = PktpResetLocalVolumes( cInfo, pInfos );
  865. for (i = 0; i < cInfo; i++) {
  866. LocalVolumeConfigInfoDestroy( &pInfos[i], FALSE );
  867. }
  868. }
  869. } else {
  870. DebugTrace(0, Dbg, "Error %08lx getting count\n", ULongToPtr( status ));
  871. }
  872. if (pInfos != NULL) {
  873. ExFreePool( pInfos );
  874. }
  875. DfsCompleteRequest( Irp, status );
  876. DebugTrace(-1,Dbg, "PktFsctrlSetServerInfo: Exit -> %08lx\n", ULongToPtr( status ));
  877. return(status);
  878. }
  879. //+------------------------------------------------------------------
  880. //
  881. // Function: PktFsctrlVerifyLocalVolumeKnowledge
  882. //
  883. // Synopsis: This method runs on a Dfs Server and validates the local
  884. // volume knowledge with the one passed in.
  885. //
  886. // Arguments: [InputBuffer] -- Marshalled DFS_PKT_RELATION_INFO to compare
  887. // with.
  888. //
  889. // [InputBufferLength] -- the length in bytes of InputBuffer
  890. //
  891. // Returns: [STATUS_SUCCESS] -- Verified that local volume knowledge was
  892. // already in sync with passed in argument.
  893. //
  894. // [STATUS_REGISTRY_RECOVERED] -- Synced up local volume
  895. // knowledge with passed in argument
  896. //
  897. // [STATUS_UNSUCCESSFUL] -- Unable to fully sync up - a message
  898. // was logged to the local event log.
  899. //
  900. // [STATUS_DATA_ERROR] -- Passed in argument could not be
  901. // unmarshalled.
  902. //
  903. // [DFS_STATUS_NOSUCH_LOCAL_VOLUME] -- Local volume not found.
  904. //
  905. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory.
  906. //
  907. //-------------------------------------------------------------------
  908. NTSTATUS
  909. PktFsctrlVerifyLocalVolumeKnowledge(
  910. IN PIRP Irp,
  911. IN PVOID InputBuffer,
  912. IN ULONG InputBufferLength
  913. )
  914. {
  915. NTSTATUS status = STATUS_SUCCESS;
  916. MARSHAL_BUFFER marshalBuffer;
  917. DFS_LOCAL_VOLUME_CONFIG remoteInfo;
  918. PDFS_PKT pkt = _GetPkt();
  919. STD_FSCTRL_PROLOGUE(PktFsctrlVerifyLocalVolumeKnowledge, TRUE, FALSE);
  920. //
  921. // unmarshal the arguments...
  922. //
  923. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  924. RtlZeroMemory(&remoteInfo, sizeof(remoteInfo));
  925. status = DfsRtlGet(
  926. &marshalBuffer,
  927. &MiPktRelationInfo,
  928. &remoteInfo.RelationInfo);
  929. if (NT_SUCCESS(status)) {
  930. PktAcquireExclusive(pkt, TRUE);
  931. status = PktpResetOneLocalVolume(pkt, &remoteInfo);
  932. PktRelease(pkt);
  933. PktRelationInfoDestroy(&remoteInfo.RelationInfo, FALSE);
  934. } else
  935. DebugTrace(0, Dbg,
  936. "PktFsctrlVerifyLocalVolumeKnowledge: Unmarshalling Error\n",0);
  937. DfsCompleteRequest( Irp, status );
  938. DebugTrace(-1, Dbg, "DfsFsctrlVerifyLocalVolumeKnowledge: Exit -> %08lx\n",
  939. ULongToPtr( status ));
  940. return status;
  941. }
  942. //+----------------------------------------------------------------------------
  943. //
  944. // Function: PktFsctrlPruneLocalVolume, public
  945. //
  946. // Synopsis: Prunes information about an extra local volume.
  947. //
  948. // Arguments: [InputBuffer] -- Marshalled EntryId of the local volume.
  949. //
  950. // [InputBufferLength] -- length of InputBuffer
  951. //
  952. // Returns: [STATUS_REGISTRY_RECOVERED] -- Volume pruned successfully.
  953. //
  954. // [STATUS_UNSUCCESSFUL] -- Unable to delete volume - proper
  955. // event has been logged to eventlog
  956. //
  957. // [STATUS_DATA_ERROR] -- Unable to unmarshal input arguments
  958. //
  959. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory
  960. //
  961. //-----------------------------------------------------------------------------
  962. NTSTATUS
  963. PktFsctrlPruneLocalVolume(
  964. IN PIRP Irp,
  965. IN PVOID InputBuffer,
  966. IN ULONG InputBufferLength
  967. )
  968. {
  969. NTSTATUS status = STATUS_SUCCESS;
  970. MARSHAL_BUFFER marshalBuffer;
  971. DFS_PKT_ENTRY_ID EntryId;
  972. PDFS_PKT pkt = _GetPkt();
  973. STD_FSCTRL_PROLOGUE(PktFsctrlPruneLocalVolume, TRUE, FALSE);
  974. //
  975. // unmarshal the arguments...
  976. //
  977. MarshalBufferInitialize(&marshalBuffer, InputBufferLength, InputBuffer);
  978. status = DfsRtlGet(
  979. &marshalBuffer,
  980. &MiPktEntryId,
  981. &EntryId);
  982. if (NT_SUCCESS(status)) {
  983. status = DfsInternalDeleteLocalVolume(&EntryId);
  984. if (!NT_SUCCESS(status)) {
  985. UNICODE_STRING puStr[2];
  986. puStr[0] = EntryId.Prefix;
  987. puStr[1].MaximumLength = sizeof(L"LocalMachine");
  988. puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
  989. puStr[1].Buffer = L"LocalMachine";
  990. LogWriteMessage(
  991. EXTRA_VOLUME_NOT_DELETED,
  992. status,
  993. 2,
  994. puStr);
  995. status = STATUS_UNSUCCESSFUL;
  996. } else {
  997. status = STATUS_REGISTRY_RECOVERED;
  998. }
  999. PktEntryIdDestroy(&EntryId, FALSE);
  1000. } else
  1001. DebugTrace(0, Dbg,
  1002. "PktFsctrlPruneLocalVolume: Unmarshalling Error\n",0);
  1003. DfsCompleteRequest( Irp, status );
  1004. DebugTrace(-1, Dbg, "DfsFsctrlPruneLocalVolume: Exit -> %08lx\n",
  1005. ULongToPtr( status ) );
  1006. return status;
  1007. }
  1008. #if DBG
  1009. //+-------------------------------------------------------------------------
  1010. //
  1011. // Function: PktFsctrlFlushCache, public
  1012. //
  1013. // Synopsis: This function will flush all entries which have all the
  1014. // bits specified in the TYPE vairable set in their own Type field.
  1015. // However, this function will refuse to delete and Permanent
  1016. // entries of the PKT.
  1017. //
  1018. // Arguments: Type - Specifies which entries to delete.
  1019. //
  1020. // Returns:
  1021. //
  1022. // Notes: We only process this FSCTRL from the file system process,
  1023. // never from the driver.
  1024. //
  1025. //--------------------------------------------------------------------------
  1026. NTSTATUS
  1027. PktFsctrlFlushCache(
  1028. IN PIRP Irp,
  1029. IN PVOID InputBuffer,
  1030. IN ULONG InputBufferLength
  1031. )
  1032. {
  1033. NTSTATUS status = STATUS_SUCCESS;
  1034. ULONG Type;
  1035. PDFS_PKT Pkt;
  1036. PDFS_PKT_ENTRY curEntry, nextEntry;
  1037. STD_FSCTRL_PROLOGUE(PktFsctrlFlushCache, TRUE, FALSE);
  1038. //
  1039. // Unmarshalling is very simple here. We only expect a ULONG.
  1040. //
  1041. Type = (*((ULONG *)InputBuffer));
  1042. Pkt = _GetPkt();
  1043. PktAcquireExclusive(Pkt, TRUE);
  1044. curEntry = PktFirstEntry(Pkt);
  1045. while (curEntry!=NULL) {
  1046. nextEntry = PktNextEntry(Pkt, curEntry);
  1047. if (((curEntry->Type & Type) == Type) &&
  1048. !(curEntry->Type & PKT_ENTRY_TYPE_LOCAL) &&
  1049. !(curEntry->Type & PKT_ENTRY_TYPE_LOCAL_XPOINT)) {
  1050. //
  1051. // Entry has all the Type bits specified in variable
  1052. // "Type" set and hence we can destroy this entry.
  1053. //
  1054. PktEntryDestroy(curEntry, Pkt, (BOOLEAN) TRUE);
  1055. }
  1056. curEntry = nextEntry;
  1057. }
  1058. PktRelease(Pkt);
  1059. DfsCompleteRequest( Irp, status );
  1060. DebugTrace(-1,Dbg, "PktFsctrlFlushCache: Exit -> %08lx\n", ULongToPtr( status ));
  1061. return(status);
  1062. }
  1063. //+----------------------------------------------------------------------------
  1064. //
  1065. // Function: PktFsctrlShufflePktEntry
  1066. //
  1067. // Synopsis: Shuffles a pkt entry. Useful for testing.
  1068. //
  1069. // Arguments: [Irp]
  1070. // [InputBuffer] -- Marshalled Pkt entry to shuffle.
  1071. // [InputBufferLength] -- size of InputBuffer.
  1072. //
  1073. // Returns:
  1074. //
  1075. //-----------------------------------------------------------------------------
  1076. VOID
  1077. PktShuffleServiceList(
  1078. PDFS_PKT_ENTRY_INFO pInfo);
  1079. NTSTATUS
  1080. PktFsctrlShufflePktEntry(
  1081. IN PIRP Irp,
  1082. IN PVOID InputBuffer,
  1083. IN ULONG InputBufferLength)
  1084. {
  1085. NTSTATUS Status;
  1086. MARSHAL_BUFFER marshalBuffer;
  1087. DFS_PKT_ENTRY_ID PktEntryId;
  1088. PDFS_PKT_ENTRY pPktEntry;
  1089. UNICODE_STRING ustrRemaining;
  1090. MarshalBufferInitialize( &marshalBuffer, InputBufferLength, InputBuffer );
  1091. Status = DfsRtlGet( &marshalBuffer, &MiPktEntryId, &PktEntryId );
  1092. if (NT_SUCCESS(Status)) {
  1093. pPktEntry = PktLookupEntryByPrefix(
  1094. &DfsData.Pkt,
  1095. &PktEntryId.Prefix,
  1096. &ustrRemaining);
  1097. if (pPktEntry == NULL || ustrRemaining.Length != 0) {
  1098. DebugTrace(0, Dbg, "PktFsctrlShufflePktEntry : [%wZ] is not an entry\n", &PktEntryId.Prefix);
  1099. Status = STATUS_NOT_FOUND;
  1100. } else {
  1101. PktShuffleServiceList( &pPktEntry->Info );
  1102. }
  1103. PktEntryIdDestroy(&PktEntryId, FALSE);
  1104. } else {
  1105. DebugTrace(0, Dbg, "PktFsctrlShufflePktEntry : DfsRtlGet returned %08lx\n", ULongToPtr( Status ) );
  1106. }
  1107. DebugTrace(0, Dbg, "PktFsctrlShufflePktEntry - returning %08lx\n", ULongToPtr( Status ));
  1108. DfsCompleteRequest( Irp, Status );
  1109. return( Status );
  1110. }
  1111. #endif // DBG