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.

982 lines
28 KiB

  1. //+------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation
  4. //
  5. // File: Know.C
  6. //
  7. // Contents: This file has all the code that involves with knowledge
  8. // synchronisation on the DC.
  9. //
  10. // Synoposis: This code handles the fixing of knowledge inconsistencies.
  11. // All this code runs only on the DC in response to FSCTRLs from
  12. // a client etc.
  13. //
  14. // Functions: DfsModifyRemotePrefix -
  15. // DfsCreateRemoteExitPoint -
  16. // DfsDeleteRemoteExitPoint -
  17. // DfsTriggerKnowledgeVerification -
  18. // DfsFsctrlVerifyLocalVolumeKnowledge -
  19. // DfsFsctrlGetKnowledgeSyncParameters -
  20. // DfsFsctrlFixLocalVolumeKnowledge -
  21. //
  22. // History: 22-March-1993 SudK Created
  23. // 18-June-1992 SudK Added FixLocalVolumeKnowledge
  24. //
  25. //-------------------------------------------------------------------
  26. #include "dfsprocs.h"
  27. #include <netevent.h>
  28. #include "fsctrl.h"
  29. #include "registry.h"
  30. #include "know.h"
  31. #include "log.h"
  32. #include "localvol.h"
  33. #include "dfswml.h"
  34. #define Dbg (DEBUG_TRACE_LOCALVOL)
  35. //
  36. // local function prototypes
  37. //
  38. BOOLEAN
  39. DfsFileExists(
  40. UNICODE_STRING DirPath
  41. );
  42. BOOLEAN
  43. DfsFileCreate(
  44. UNICODE_STRING DirPath
  45. );
  46. BOOLEAN
  47. DfsFixExitPath(
  48. PWSTR ExitPath
  49. );
  50. DfspFixExitPoints(
  51. PDFS_FIX_LOCAL_VOLUME_ARG arg
  52. );
  53. #ifdef ALLOC_PRAGMA
  54. #pragma alloc_text( PAGE, DfsModifyRemotePrefix )
  55. #pragma alloc_text( PAGE, DfsCreateRemoteExitPoint )
  56. #pragma alloc_text( PAGE, DfsDeleteRemoteExitPoint )
  57. #pragma alloc_text( PAGE, DfsFileExists )
  58. #pragma alloc_text( PAGE, DfsFileCreate )
  59. #pragma alloc_text( PAGE, DfsStorageIdExists )
  60. #pragma alloc_text( PAGE, DfsFixExitPath )
  61. #pragma alloc_text( PAGE, DfspFixExitPoints )
  62. #pragma alloc_text( PAGE, DfsFsctrlFixLocalVolumeKnowledge )
  63. #endif // ALLOC_PRAGMA
  64. //+------------------------------------------------------------------
  65. //
  66. // Function: DfsModifyRemotePrefix
  67. //
  68. // Synopsis: This function creates an ExitPoint knowledge at a remote client.
  69. // Serves as a wrapper and merely makes an FSCTRL to the remote
  70. // Client.
  71. //
  72. // Arguments: [ExitPtId] -- The exit Point ID that needs to be sent across.
  73. // [remoteHandle] -- The Handle to be used for FSCTRLs.
  74. //
  75. // Returns:
  76. //
  77. // History: 22-March-1992 SudK Created
  78. //
  79. // Notes:
  80. //
  81. //-------------------------------------------------------------------
  82. NTSTATUS
  83. DfsModifyRemotePrefix(DFS_PKT_ENTRY_ID ExitPtId, HANDLE remoteHandle)
  84. {
  85. ULONG size;
  86. PVOID buffer = NULL;
  87. IO_STATUS_BLOCK ioStatusBlock;
  88. MARSHAL_BUFFER marshalBuffer;
  89. NTSTATUS status;
  90. DebugTrace(0, Dbg, "DfsModifyRemotePrefix: %ws\n", ExitPtId.Prefix.Buffer);
  91. size = 0L;
  92. status = DfsRtlSize(&MiPktEntryId, &ExitPtId, &size);
  93. if (NT_SUCCESS(status)) {
  94. buffer = ExAllocatePoolWithTag(PagedPool, size, ' sfD');
  95. if (buffer != NULL) {
  96. MarshalBufferInitialize(&marshalBuffer, size, buffer);
  97. status = DfsRtlPut(
  98. &marshalBuffer,
  99. &MiPktEntryId,
  100. &ExitPtId
  101. );
  102. } else {
  103. status = STATUS_NO_MEMORY;
  104. }
  105. }
  106. if (NT_SUCCESS(status)) {
  107. status = ZwFsControlFile(
  108. remoteHandle,
  109. NULL,
  110. NULL,
  111. NULL,
  112. &ioStatusBlock,
  113. FSCTL_DFS_MODIFY_PREFIX,
  114. buffer,
  115. size,
  116. NULL,
  117. 0
  118. );
  119. }
  120. if (NT_SUCCESS(status))
  121. status = ioStatusBlock.Status;
  122. if (buffer != NULL)
  123. ExFreePool(buffer);
  124. return(status);
  125. }
  126. //+------------------------------------------------------------------
  127. //
  128. // Function: DfsCreateRemoteExitPoint
  129. //
  130. // Synopsis: This function creates an ExitPoint knowledge at a remote client.
  131. // Serves as a wrapper and merely makes an FSCTRL to the remote
  132. // Client.
  133. //
  134. // Arguments: [ExitPtId] -- The exit Point ID that needs to be sent across.
  135. // [remoteHandle] -- The Handle to be used for FSCTRLs.
  136. //
  137. // Returns:
  138. //
  139. // History: 22-March-1992 SudK Created
  140. //
  141. // Notes:
  142. //
  143. //-------------------------------------------------------------------
  144. NTSTATUS
  145. DfsCreateRemoteExitPoint(DFS_PKT_ENTRY_ID ExitPtId, HANDLE remoteHandle)
  146. {
  147. ULONG size;
  148. PVOID buffer = NULL;
  149. IO_STATUS_BLOCK ioStatusBlock;
  150. MARSHAL_BUFFER marshalBuffer;
  151. NTSTATUS status;
  152. DebugTrace(0, Dbg, "DfsCreateRemoteExitPt: %ws\n", ExitPtId.Prefix.Buffer);
  153. DFS_TRACE_LOW(PROVIDER, DfsCreateRemoteExitPt_Entry,
  154. LOGGUID(ExitPtId.Uid)
  155. LOGUSTR(ExitPtId.Prefix)
  156. LOGUSTR(ExitPtId.ShortPrefix)
  157. LOGHANDLE(remoteHandle));
  158. size = 0L;
  159. status = DfsRtlSize(&MiPktEntryId, &ExitPtId, &size);
  160. if (NT_SUCCESS(status)) {
  161. buffer = ExAllocatePoolWithTag(PagedPool, size, ' sfD');
  162. if (buffer != NULL) {
  163. MarshalBufferInitialize(&marshalBuffer, size, buffer);
  164. status = DfsRtlPut(
  165. &marshalBuffer,
  166. &MiPktEntryId,
  167. &ExitPtId
  168. );
  169. } else {
  170. status = STATUS_NO_MEMORY;
  171. }
  172. }
  173. if (NT_SUCCESS(status)) {
  174. status = ZwFsControlFile(
  175. remoteHandle,
  176. NULL,
  177. NULL,
  178. NULL,
  179. &ioStatusBlock,
  180. FSCTL_DFS_CREATE_EXIT_POINT,
  181. buffer,
  182. size,
  183. NULL,
  184. 0
  185. );
  186. DFS_TRACE_ERROR_HIGH(status, ALL_ERROR, DfsCreateRemoteExitPt_Error_ZwFsControlFile,
  187. LOGSTATUS(status)
  188. LOGGUID(ExitPtId.Uid)
  189. LOGUSTR(ExitPtId.Prefix)
  190. LOGUSTR(ExitPtId.ShortPrefix));
  191. }
  192. if (NT_SUCCESS(status))
  193. status = ioStatusBlock.Status;
  194. if (buffer != NULL)
  195. ExFreePool(buffer);
  196. DFS_TRACE_LOW(PROVIDER, DfsCreateRemoteExitPt_Exit, LOGSTATUS(status)
  197. LOGGUID(ExitPtId.Uid)
  198. LOGUSTR(ExitPtId.Prefix)
  199. LOGUSTR(ExitPtId.ShortPrefix));
  200. return(status);
  201. }
  202. //+------------------------------------------------------------------
  203. //
  204. // Function: DfsDeleteRemoteExitPoint
  205. //
  206. // Synopsis: This function deletes a remote exitpoint knowledeg by making
  207. // an FSCTRL to the remote client.
  208. //
  209. // Arguments: [ExitPtId] -- The exit Point ID that needs to be sent across.
  210. // [remoteHandle] -- The Handle to be used for FSCTRLs.
  211. //
  212. // Returns:
  213. //
  214. // History: 22-March-1992 SudK Created
  215. //
  216. // Notes:
  217. //
  218. //-------------------------------------------------------------------
  219. NTSTATUS
  220. DfsDeleteRemoteExitPoint(
  221. IN DFS_PKT_ENTRY_ID ExitPtId,
  222. IN HANDLE remoteHandle
  223. ) {
  224. ULONG size;
  225. PVOID buffer = NULL;
  226. IO_STATUS_BLOCK ioStatusBlock;
  227. MARSHAL_BUFFER marshalBuffer;
  228. NTSTATUS status;
  229. DebugTrace(0, Dbg, "DeleteRemoteExitPt: %ws\n", ExitPtId.Prefix.Buffer);
  230. size = 0L;
  231. status = DfsRtlSize(&MiPktEntryId, &ExitPtId, &size);
  232. if (NT_SUCCESS(status)) {
  233. buffer = ExAllocatePoolWithTag(PagedPool, size, ' sfD');
  234. if (buffer != NULL) {
  235. MarshalBufferInitialize(&marshalBuffer, size, buffer);
  236. status = DfsRtlPut(&marshalBuffer, &MiPktEntryId, &ExitPtId);
  237. } else {
  238. status = STATUS_NO_MEMORY;
  239. }
  240. }
  241. if (NT_SUCCESS(status)) {
  242. status = ZwFsControlFile(remoteHandle,
  243. NULL,
  244. NULL,
  245. NULL,
  246. &ioStatusBlock,
  247. FSCTL_DFS_DELETE_EXIT_POINT,
  248. buffer,
  249. size,
  250. NULL,
  251. 0);
  252. }
  253. if (NT_SUCCESS(status))
  254. status = ioStatusBlock.Status;
  255. if (buffer != NULL)
  256. ExFreePool(buffer);
  257. return(status);
  258. }
  259. //+-------------------------------------------------------------------------
  260. //
  261. // Function: DfsFileExists
  262. //
  263. // Synopsis: This function verifies the existence of a given directory.
  264. // It does not create it if it does not exist.
  265. //
  266. // Arguments: [DirPath] -- The StorageId in the form of UnicodeString.
  267. //
  268. // Returns: TRUE - If directory exists else FALSE.
  269. //
  270. // History: 15 Jun 1993 SudK Created
  271. //
  272. //--------------------------------------------------------------------------
  273. BOOLEAN
  274. DfsFileExists(
  275. UNICODE_STRING DirPath
  276. )
  277. {
  278. HANDLE DirHandle;
  279. OBJECT_ATTRIBUTES objectAttributes;
  280. IO_STATUS_BLOCK ioStatus;
  281. NTSTATUS status;
  282. BOOLEAN fPreviousErrorMode;
  283. InitializeObjectAttributes(
  284. &objectAttributes,
  285. &DirPath,
  286. OBJ_CASE_INSENSITIVE,
  287. NULL,
  288. NULL
  289. );
  290. status = ZwCreateFile(
  291. &DirHandle,
  292. FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES,
  293. &objectAttributes,
  294. &ioStatus,
  295. NULL,
  296. FILE_ATTRIBUTE_NORMAL,
  297. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  298. FILE_OPEN,
  299. FILE_DIRECTORY_FILE,
  300. NULL,
  301. 0
  302. );
  303. if (NT_SUCCESS(status)) {
  304. status = ioStatus.Status;
  305. ZwClose(DirHandle);
  306. }
  307. if (NT_SUCCESS(status))
  308. return(TRUE);
  309. else if (status == STATUS_NO_MEDIA_IN_DEVICE)
  310. return(TRUE);
  311. else
  312. return(FALSE);
  313. }
  314. //+-------------------------------------------------------------------------
  315. //
  316. // Function: DfsFileCreate
  317. //
  318. // Synopsis: This function verifies the existence of a given directory.
  319. // If it does not exist then it creates it.
  320. //
  321. // Arguments: [DirPath] -- The StorageId in the form of UnicodeString.
  322. //
  323. // Returns: TRUE - If it created and all is fine else FALSE.
  324. //
  325. // History: 15 Jun 1993 SudK Created
  326. //
  327. //--------------------------------------------------------------------------
  328. BOOLEAN
  329. DfsFileCreate(
  330. UNICODE_STRING DirPath
  331. )
  332. {
  333. HANDLE DirHandle;
  334. OBJECT_ATTRIBUTES objectAttributes;
  335. IO_STATUS_BLOCK ioStatus;
  336. NTSTATUS status;
  337. InitializeObjectAttributes(
  338. &objectAttributes,
  339. &DirPath,
  340. OBJ_CASE_INSENSITIVE,
  341. NULL,
  342. NULL
  343. );
  344. status = ZwCreateFile(
  345. &DirHandle,
  346. FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES,
  347. &objectAttributes,
  348. &ioStatus,
  349. NULL,
  350. FILE_ATTRIBUTE_NORMAL,
  351. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  352. FILE_OPEN_IF,
  353. FILE_DIRECTORY_FILE,
  354. NULL,
  355. 0
  356. );
  357. if (NT_SUCCESS(status)) {
  358. status = ioStatus.Status;
  359. ZwClose(DirHandle);
  360. }
  361. if (!NT_SUCCESS(status))
  362. return(FALSE);
  363. else
  364. return(TRUE);
  365. }
  366. //+-------------------------------------------------------------------------
  367. //
  368. // Function: DfsStorageIdExists
  369. //
  370. // Synopsis: This function makes sure that a given storageId exists and if
  371. // it does not then it attempts to create the storageId if req.
  372. //
  373. // Arguments: [StorageId] -- The storage id to test in the form of an
  374. // NT Path name (eg, \??\C:\foo )
  375. // [bCreate] -- If this is TRUE, then the function will attempt
  376. // to create the stg else it will check for existence.
  377. //
  378. // Returns: TRUE - If it created and all is fine else FALSE.
  379. //
  380. // History: 15 Jun 1993 SudK Created
  381. //
  382. //--------------------------------------------------------------------------
  383. BOOLEAN
  384. DfsStorageIdExists(
  385. UNICODE_STRING StgPath,
  386. BOOLEAN bCreate
  387. )
  388. {
  389. PWCHAR pwch = NULL;
  390. UNICODE_STRING StorageId;
  391. BOOLEAN StgIdCreated = FALSE;
  392. StorageId = StgPath;
  393. StorageId.Buffer = ExAllocatePoolWithTag(
  394. PagedPool,
  395. StorageId.MaximumLength + sizeof(WCHAR),
  396. ' sfD');
  397. if (StorageId.Buffer == NULL) {
  398. return FALSE;
  399. }
  400. wcsncpy(StorageId.Buffer, StgPath.Buffer, StgPath.Length/sizeof(WCHAR));
  401. StorageId.Buffer[StgPath.Length/sizeof(WCHAR)] = UNICODE_NULL;
  402. ASSERT(StorageId.Length >= wcslen(L"\\??\\C:")*sizeof(WCHAR));
  403. //
  404. // If the storage Id refers only to a root drive the trailing backslash
  405. // may not exist and we need to put it in there to open the right thing.
  406. //
  407. if (StorageId.Length < wcslen(L"\\??\\C:\\")*sizeof(WCHAR)) {
  408. StorageId.Buffer[StorageId.Length/sizeof(WCHAR)] = L'\\';
  409. StorageId.Buffer[StorageId.Length/sizeof(WCHAR) + 1] = UNICODE_NULL;
  410. }
  411. //
  412. // First verify that the Drive does exist and then we will go into the
  413. // next stage.
  414. //
  415. StorageId.Length = sizeof(L"\\??\\c:\\") - sizeof(UNICODE_NULL);
  416. if (!DfsFileExists(StorageId)) {
  417. ExFreePool(StorageId.Buffer);
  418. return(FALSE);
  419. }
  420. //
  421. // If all that we have is a drive letter then we are done with this step.
  422. //
  423. if (wcslen(StorageId.Buffer) <= wcslen(L"\\??\\C:\\")) {
  424. ExFreePool(StorageId.Buffer);
  425. return(TRUE);
  426. }
  427. //
  428. // Now that the drive does exist we can check for each of the directories
  429. // and create them as we go along.
  430. //
  431. pwch = StorageId.Buffer + StorageId.Length/sizeof(WCHAR);
  432. while (pwch != NULL) {
  433. ASSERT(pwch < StorageId.Buffer + StorageId.MaximumLength/sizeof(WCHAR));
  434. pwch = wcschr(pwch, L'\\');
  435. if (pwch != NULL) {
  436. StorageId.Length = (wcslen(StorageId.Buffer) - wcslen(pwch))*
  437. sizeof(WCHAR);
  438. if (bCreate) {
  439. if (!DfsFileCreate(StorageId))
  440. break;
  441. }
  442. else {
  443. if (!DfsFileExists(StorageId))
  444. break;
  445. }
  446. pwch++; //Skip the last L'\'
  447. }
  448. else {
  449. StorageId.Length = wcslen(StorageId.Buffer)*sizeof(WCHAR);
  450. if (bCreate) {
  451. if (DfsFileCreate(StorageId))
  452. StgIdCreated = TRUE;
  453. }
  454. else {
  455. if (DfsFileExists(StorageId))
  456. StgIdCreated = TRUE;
  457. }
  458. }
  459. }
  460. //
  461. // If we came out without the pwch != NULL then it means we were unable
  462. // to create one of the directories along the way due to some wierd
  463. // reason. We return a FALSE from this function else a SUCCESS.
  464. //
  465. ExFreePool(StorageId.Buffer);
  466. if (StgIdCreated)
  467. return(TRUE);
  468. else
  469. return(FALSE);
  470. return(TRUE);
  471. }
  472. //+-------------------------------------------------------------------------
  473. //
  474. // Function: DfsFixExitPath
  475. //
  476. // Synopsis: This function makes sure
  477. //
  478. //
  479. //
  480. //--------------------------------------------------------------------------
  481. BOOLEAN
  482. DfsFixExitPath(
  483. PWSTR ExitPath
  484. )
  485. {
  486. UNICODE_STRING ustrExitPath;
  487. PWCHAR pwcLastComponent;
  488. OBJECT_ATTRIBUTES objectAttributes;
  489. HANDLE exitPtHandle;
  490. IO_STATUS_BLOCK ioStatus;
  491. NTSTATUS status;
  492. pwcLastComponent = wcsrchr(ExitPath, L'\\');
  493. if (pwcLastComponent == NULL) {
  494. //
  495. // This should not happen.
  496. //
  497. DebugTrace(0, 1, "DfsFixExitPath: Bad Exitpath %ws given here\n",
  498. ExitPath);
  499. return(FALSE);
  500. }
  501. //
  502. // Now let us verify that everything except for exit pt exists.
  503. //
  504. ustrExitPath.Length = (USHORT)(pwcLastComponent - ExitPath);
  505. ustrExitPath.MaximumLength = ustrExitPath.Length + sizeof(WCHAR);
  506. ustrExitPath.Buffer = ExitPath;
  507. if (!DfsStorageIdExists(ustrExitPath, TRUE)) {
  508. DebugTrace(0, Dbg, "DfsFixExitPath:Fail createstg %wZ\n",&ustrExitPath);
  509. return(FALSE);
  510. }
  511. //
  512. // Now let us just create the exit pt.
  513. //
  514. ustrExitPath.Length = wcslen(ExitPath) * sizeof(WCHAR);
  515. ustrExitPath.MaximumLength = ustrExitPath.Length + sizeof(WCHAR);
  516. InitializeObjectAttributes(
  517. &objectAttributes,
  518. &ustrExitPath,
  519. OBJ_CASE_INSENSITIVE,
  520. NULL,
  521. NULL
  522. );
  523. status = ZwCreateFile(
  524. &exitPtHandle,
  525. DELETE | FILE_READ_ATTRIBUTES,
  526. &objectAttributes,
  527. &ioStatus,
  528. NULL,
  529. FILE_ATTRIBUTE_NORMAL,
  530. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  531. FILE_OPEN_IF,
  532. FILE_DIRECTORY_FILE |
  533. FILE_SYNCHRONOUS_IO_NONALERT,
  534. NULL,
  535. 0
  536. );
  537. if (NT_SUCCESS(status)) {
  538. ZwClose( exitPtHandle );
  539. status = ioStatus.Status;
  540. }
  541. if (status == STATUS_FILE_IS_A_DIRECTORY) {
  542. status = STATUS_SUCCESS;
  543. }
  544. if (!NT_SUCCESS(status))
  545. status = DFS_STATUS_BAD_EXIT_POINT;
  546. if (NT_SUCCESS(status)) {
  547. return(TRUE);
  548. }
  549. else {
  550. DebugTrace(0, Dbg, "DfsFixExtPath: Fail create extpath %08lx\n", ULongToPtr( status ));
  551. DebugTrace(0, Dbg, "DfsFixExtPath: %wZ\n", &ustrExitPath);
  552. return(FALSE);
  553. }
  554. }
  555. //+-------------------------------------------------------------------------
  556. //
  557. // Function: DfspFixExitPoints
  558. //
  559. // Synopsis: This function ensures that the exit points for a volume are
  560. // all in place and if not it attempts to create them.
  561. //
  562. // Arguments: [arg] -- Pointer to DFS_FIX_LOCAL_VOLUME_ARG.
  563. //
  564. // Returns: STATUS_SUCCESS -- If all went well.
  565. //
  566. // History: 15 Jun 1993 SudK Created
  567. //
  568. //--------------------------------------------------------------------------
  569. DfspFixExitPoints(
  570. PDFS_FIX_LOCAL_VOLUME_ARG arg
  571. )
  572. {
  573. NTSTATUS status = STATUS_SUCCESS;
  574. LPNET_DFS_ENTRY_ID_CONTAINER pRelInfo;
  575. ULONG i, len, volLen, exitPointLen;
  576. WCHAR wszExitPath[MAX_PATH];
  577. PWSTR pwszExitPath;
  578. PWCHAR pwch;
  579. pRelInfo = arg->RelationInfo;
  580. len = wcslen(arg->EntryPrefix);
  581. volLen = wcslen(arg->VolumeName);
  582. for (i=0; i < pRelInfo->Count && NT_SUCCESS(status); i++) {
  583. exitPointLen = wcslen( pRelInfo->Buffer[i].Prefix );
  584. if (volLen + exitPointLen < MAX_PATH) {
  585. pwszExitPath = wszExitPath;
  586. } else {
  587. pwszExitPath = ExAllocatePoolWithTag(
  588. PagedPool,
  589. (volLen + exitPointLen + 1) * sizeof(WCHAR),
  590. ' sfD');
  591. }
  592. if (pwszExitPath != NULL) {
  593. wcscpy(pwszExitPath, arg->VolumeName);
  594. //
  595. // Now we need to get the last part of the exit path so that
  596. // we can concatenate to above to get local path to create.
  597. //
  598. pwch = pRelInfo->Buffer[i].Prefix + len;
  599. wcscat(pwszExitPath, pwch);
  600. //
  601. // Now we have the local path to create. Call off to appropriate func
  602. //
  603. if (!DfsFixExitPath(pwszExitPath)) {
  604. DebugTrace(0, Dbg, "Unable to forcibly Create %ws exitpath",
  605. pwszExitPath);
  606. }
  607. if (pwszExitPath != wszExitPath) {
  608. ExFreePool(pwszExitPath);
  609. }
  610. } else {
  611. status = STATUS_INSUFFICIENT_RESOURCES;
  612. }
  613. }
  614. return(status);
  615. }
  616. //+-------------------------------------------------------------------------
  617. //
  618. // Function: DfsFsctrlFixLocalVolumeKnowledge
  619. //
  620. // Synopsis: This function gets called on a server by the DC when the
  621. // DC discovers a knowledge inconsistency where the server is
  622. // entirely unaware of a particular volume.
  623. //
  624. // Arguments:
  625. //
  626. // Returns:
  627. //
  628. // History: 15 Jun 1993 SudK Created.
  629. //
  630. //--------------------------------------------------------------------------
  631. NTSTATUS
  632. DfsFsctrlFixLocalVolumeKnowledge(
  633. IN PIRP Irp,
  634. IN PVOID InputBuffer,
  635. IN ULONG InputBufferLength
  636. )
  637. {
  638. NTSTATUS status = STATUS_SUCCESS;
  639. MARSHAL_BUFFER marshalBuffer;
  640. PDFS_FIX_LOCAL_VOLUME_ARG arg;
  641. PDFS_LOCAL_VOLUME_CONFIG configInfo;
  642. ULONG i;
  643. PDFS_PKT pkt = _GetPkt();
  644. UNICODE_STRING volume, path, remainingPath;
  645. PDFS_PKT_ENTRY Entry;
  646. STD_FSCTRL_PROLOGUE(DfsFsctrlFixLocalVolumeKnowledge, TRUE, FALSE);
  647. if (InputBufferLength < sizeof(*arg)) {
  648. status = STATUS_INVALID_PARAMETER;
  649. goto exit_with_status;
  650. }
  651. //
  652. // unmarshal the arguments...
  653. //
  654. arg = (PDFS_FIX_LOCAL_VOLUME_ARG) InputBuffer;
  655. OFFSET_TO_POINTER( arg->VolumeName, arg );
  656. OFFSET_TO_POINTER( arg->StgId, arg );
  657. OFFSET_TO_POINTER( arg->EntryPrefix, arg );
  658. OFFSET_TO_POINTER( arg->ShortPrefix, arg );
  659. OFFSET_TO_POINTER( arg->RelationInfo, arg );
  660. if (
  661. !DfspStringInBuffer(arg->VolumeName, InputBuffer, InputBufferLength) ||
  662. !DfspStringInBuffer(arg->StgId, InputBuffer, InputBufferLength) ||
  663. !DfspStringInBuffer(arg->EntryPrefix, InputBuffer, InputBufferLength) ||
  664. !DfspStringInBuffer(arg->ShortPrefix, InputBuffer, InputBufferLength) ||
  665. !POINTER_IS_VALID(arg->RelationInfo, InputBuffer, InputBufferLength)
  666. ) {
  667. status = STATUS_INVALID_PARAMETER;
  668. goto exit_with_status;
  669. }
  670. if (!POINTER_IN_BUFFER(
  671. &arg->RelationInfo->Buffer,
  672. sizeof(arg->RelationInfo->Buffer),
  673. InputBuffer,
  674. InputBufferLength)) {
  675. status = STATUS_INVALID_PARAMETER;
  676. goto exit_with_status;
  677. }
  678. OFFSET_TO_POINTER( arg->RelationInfo->Buffer, arg );
  679. if (!POINTER_IS_VALID(arg->RelationInfo->Buffer, InputBuffer, InputBufferLength)) {
  680. status = STATUS_INVALID_PARAMETER;
  681. goto exit_with_status;
  682. }
  683. for (i = 0; i < arg->RelationInfo->Count; i++) {
  684. if (!POINTER_IN_BUFFER(
  685. &arg->RelationInfo->Buffer[i].Prefix,
  686. sizeof(arg->RelationInfo->Buffer[i].Prefix),
  687. InputBuffer,
  688. InputBufferLength)) {
  689. status = STATUS_INVALID_PARAMETER;
  690. goto exit_with_status;
  691. }
  692. OFFSET_TO_POINTER( arg->RelationInfo->Buffer[i].Prefix, arg );
  693. if (!DfspStringInBuffer(
  694. arg->RelationInfo->Buffer[i].Prefix,
  695. InputBuffer,
  696. InputBufferLength)) {
  697. status = STATUS_INVALID_PARAMETER;
  698. goto exit_with_status;
  699. }
  700. }
  701. RtlInitUnicodeString( &volume, arg->VolumeName );
  702. configInfo = DfsNetInfoToConfigInfo(
  703. arg->EntryType,
  704. arg->ServiceType,
  705. arg->StgId,
  706. arg->VolumeName,
  707. &arg->EntryUid,
  708. arg->EntryPrefix,
  709. arg->ShortPrefix,
  710. arg->RelationInfo);
  711. if (configInfo == NULL) {
  712. status = STATUS_INSUFFICIENT_RESOURCES;
  713. }
  714. //
  715. // Make sure that the storage id is legal
  716. //
  717. if (NT_SUCCESS(status)) {
  718. if (!DfsStorageIdLegal(&volume)) {
  719. status = DFS_STATUS_STORAGEID_ALREADY_INUSE;
  720. }
  721. }
  722. if (NT_SUCCESS(status)) {
  723. //
  724. // Next we need to make sure that we dont already have a local volume
  725. // with the same prefix. So we acquire resources in the right order.
  726. //
  727. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  728. //
  729. // Now we need to acquire the PKT and try to update PKT with new
  730. // partition's information.
  731. //
  732. PktAcquireExclusive(pkt, TRUE);
  733. //
  734. // Let us lookup in the PKT first.
  735. //
  736. RtlInitUnicodeString( &path, arg->EntryPrefix );
  737. Entry = PktLookupEntryByPrefix(
  738. pkt,
  739. &path,
  740. &remainingPath);
  741. //
  742. // If we already have a local volume with exactly this prefix then we
  743. // fail this call.
  744. //
  745. if ((Entry != NULL) &&
  746. (Entry->LocalService != NULL) &&
  747. (remainingPath.Length == 0)) {
  748. status = DFS_STATUS_LOCAL_ENTRY;
  749. goto Cleanup;
  750. }
  751. //
  752. // Now that we are here we have determined that we can go ahead and
  753. // attempt to perform this operation. First we need to make sure that
  754. // the required storageId does exist on disk.
  755. //
  756. if (!DfsStorageIdExists(volume, TRUE)) {
  757. status = DFS_STATUS_BAD_STORAGEID;
  758. goto Cleanup;
  759. }
  760. //
  761. // Next, store the local volume info persistently in the registry.
  762. //
  763. status = DfsStoreLvolInfo(
  764. configInfo,
  765. &volume );
  766. if (!NT_SUCCESS(status)) {
  767. DebugTrace(0, Dbg,
  768. "DfsFsctrlFixLocalVolumeKnowledge: Error storing local volume info %08lx\n", ULongToPtr( status ));
  769. status = DFS_STATUS_BAD_STORAGEID;
  770. goto Cleanup;
  771. }
  772. //
  773. // Now we are done with the storing the local volume info in the
  774. // registry. We still need to make sure that each of the exit Points
  775. // exist on disk appropriately.
  776. //
  777. if (NT_SUCCESS(status)) {
  778. status = DfspFixExitPoints(arg);
  779. }
  780. //
  781. // Now we need to initialize the PKT with this new partition info.
  782. //
  783. if (NT_SUCCESS(status)) {
  784. status = PktInitializeLocalPartition(
  785. pkt,
  786. &volume,
  787. configInfo);
  788. if (!NT_SUCCESS(status)) {
  789. DebugTrace(0, Dbg,
  790. "DfsFixLocalVolumeKnowledge: Failed PktInitialize %08lx\n",
  791. ULongToPtr( status ));
  792. }
  793. }
  794. Cleanup:
  795. if (pkt != NULL)
  796. PktRelease(pkt);
  797. ExReleaseResourceLite(&DfsData.Resource);
  798. if (configInfo != NULL)
  799. ExFreePool( configInfo );
  800. } else {
  801. DebugTrace(0,Dbg, "DfsFsctrlFixLocalVolumeKnowledge:Error %08lx\n", ULongToPtr( status ));
  802. }
  803. exit_with_status:
  804. DfsCompleteRequest( Irp, status );
  805. DebugTrace(-1, Dbg,"DfsFsctrlFixLocalVolumeKnowledge:Exit-> %08lx\n", ULongToPtr( status ));
  806. return status;
  807. }