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.

2416 lines
75 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: PktSup.C
  6. //
  7. // Contents: This module implements routines specific to the partition
  8. // knowledge table entry.
  9. //
  10. // Functions: PktEntrySetLocalService -
  11. // PktEntryLookupLocalService -
  12. // PktEntryRemoveLocalService -
  13. // PktDSTransportDestroy -
  14. // PktDSMachineDestroy -
  15. // PktServiceConstruct -
  16. // PktServiceDestroy -
  17. // PktEntryIdConstruct -
  18. // PktEntryIdDestroy -
  19. // PktEntryInfoConstruct -
  20. // PktEntryInfoDestroy -
  21. // PktEntryAssemble -
  22. // PktEntryReassemble -
  23. // PktEntryDestroy -
  24. // PktEntryClearSubordinates -
  25. // PktEntryClearChildren -
  26. // PktRelationInfoConstruct -
  27. // PktRelationInfoValidate -
  28. // PktRelationInfoDestroy -
  29. // PktGetService -
  30. // DfsFixDSMachineStructs -
  31. // DfspFixService -
  32. // DfsDecrementMachEntryCount -
  33. //
  34. // History: 27 May 1992 PeterCo Created.
  35. //
  36. //-----------------------------------------------------------------------------
  37. #include "dfsprocs.h"
  38. #include <netevent.h>
  39. #include "fsctrl.h"
  40. #include "attach.h"
  41. #include "know.h"
  42. #include "log.h"
  43. #include "localvol.h"
  44. #define Dbg (DEBUG_TRACE_PKT)
  45. NTSTATUS
  46. DfsFixDSMachineStructs(
  47. PDFS_PKT_ENTRY pEntry
  48. );
  49. NTSTATUS
  50. DfspFixService(
  51. PDFS_SERVICE pService
  52. );
  53. VOID
  54. DfsDecrementMachEntryCount(
  55. PDFS_MACHINE_ENTRY pMachEntry,
  56. BOOLEAN DeallocateMachine
  57. );
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text( PAGE, PktEntrySetLocalService )
  60. #pragma alloc_text( PAGE, PktEntryLookupLocalService )
  61. #pragma alloc_text( PAGE, PktEntryRemoveLocalService )
  62. #pragma alloc_text( PAGE, PktServiceConstruct )
  63. #pragma alloc_text( PAGE, PktServiceDestroy )
  64. #pragma alloc_text( PAGE, PktEntryIdConstruct )
  65. #pragma alloc_text( PAGE, PktEntryIdDestroy )
  66. #pragma alloc_text( PAGE, PktEntryInfoDestroy )
  67. #pragma alloc_text( PAGE, PktEntryAssemble )
  68. #pragma alloc_text( PAGE, PktEntryReassemble )
  69. #pragma alloc_text( PAGE, PktEntryDestroy )
  70. #pragma alloc_text( PAGE, PktEntryClearSubordinates )
  71. #pragma alloc_text( PAGE, PktEntryClearChildren )
  72. #pragma alloc_text( PAGE, PktRelationInfoConstruct )
  73. #pragma alloc_text( PAGE, PktRelationInfoValidate )
  74. #pragma alloc_text( PAGE, PktRelationInfoDestroy )
  75. #pragma alloc_text( PAGE, PktGetService )
  76. #pragma alloc_text( PAGE, DfsFixDSMachineStructs )
  77. #pragma alloc_text( PAGE, DfspFixService )
  78. #pragma alloc_text( PAGE, DfsDecrementMachEntryCount )
  79. #endif // ALLOC_PRAGMA
  80. //
  81. // NOTE - we designed for only one system-wide PKT; there is no provision
  82. // for multiple PKTs.
  83. //
  84. #define _GetPkt() (&DfsData.Pkt)
  85. //+-------------------------------------------------------------------------
  86. //
  87. // Function: PktEntrySetLocalService, public
  88. //
  89. // Synopsis: PktEntrySetLocalService sets the local service field of
  90. // the entry (deallocating any previous local service field
  91. // that may exist).
  92. //
  93. // Arguments: [Pkt] -- pointer to the Pkt
  94. // [Entry] -- pointer to the PKT entry to set the local service on.
  95. // [LocalService] -- pointer to the local service to be set.
  96. // [LocalVolEntry] -- pointer to a local volume table entry
  97. // [LocalPath] -- the storage ID for the local service
  98. // [ShareName] -- The LM share through which LocalPath is to be
  99. // accessed.
  100. //
  101. // Returns: STATUS_SUCCESS if all's well that ends well
  102. // STATUS_DEVICE_ALREADY_ATTACHED if the entry has a local service,
  103. // and the new service to be set is different.
  104. // STATUS_INSUFFICIENT_RESOURCES if memory alloc fails.
  105. //
  106. //--------------------------------------------------------------------------
  107. NTSTATUS
  108. PktEntrySetLocalService(
  109. IN PDFS_PKT Pkt,
  110. IN PDFS_PKT_ENTRY Entry,
  111. IN PDFS_SERVICE LocalService,
  112. IN PDFS_LOCAL_VOL_ENTRY LocalVolEntry,
  113. IN PUNICODE_STRING LocalPath,
  114. IN PUNICODE_STRING ShareName
  115. ) {
  116. //
  117. // When setting a local service, we don't expect there
  118. // to be one already.
  119. //
  120. ASSERT(LocalService != NULL);
  121. ASSERT(LocalVolEntry != NULL);
  122. DebugTrace(+1, Dbg, "PktEntrySetLocalService(%wZ)\n", LocalPath);
  123. DebugTrace(+1, Dbg, " (%wZ)\n", ShareName);
  124. if (Entry->LocalService != NULL) {
  125. UNICODE_STRING ustrLocalVolName;
  126. //
  127. // The entry has an existing local service. Make sure its the "same"
  128. // as the new one we are setting. By same we mean that the new
  129. // service has the same provider def and address.
  130. //
  131. //
  132. // The problem is, we are given LocalPath of the form
  133. // \??\X:\path. The existing Entry->LocalService has a pointer
  134. // to a provider def that has the the \??\X: part, while the
  135. // \path part is stored in Entry->LocalService.Address. So, here, we
  136. // first make sure that the \??\X: matches with the existing
  137. // provider def, and then we make sure that the \path matches with the
  138. // Address part.
  139. //
  140. ustrLocalVolName = *LocalPath;
  141. ustrLocalVolName.Length = Entry->LocalService->pProvider->DeviceName.Length;
  142. if (!RtlEqualUnicodeString(&ustrLocalVolName,
  143. &Entry->LocalService->pProvider->DeviceName,
  144. TRUE)) {
  145. DebugTrace(-1, Dbg, "PktEntrySetLocalService->STATUS_DEVICE_ALREADY_ATTACHED(1)\n", 0);
  146. return (STATUS_DEVICE_ALREADY_ATTACHED);
  147. }
  148. ustrLocalVolName.Buffer += (ustrLocalVolName.Length / sizeof(WCHAR));
  149. ustrLocalVolName.Length = LocalPath->Length - ustrLocalVolName.Length;
  150. if (!RtlEqualUnicodeString(&ustrLocalVolName,
  151. (PUNICODE_STRING) &Entry->LocalService->Address,
  152. TRUE)) {
  153. DebugTrace(-1, Dbg, "PktEntrySetLocalService->STATUS_DEVICE_ALREADY_ATTACHED(2)\n", 0);
  154. return(STATUS_DEVICE_ALREADY_ATTACHED);
  155. }
  156. //
  157. // Attaching the same local service - all is ok.
  158. //
  159. PktEntryRemoveLocalService(Pkt, Entry, LocalPath);
  160. }
  161. Entry->LocalService = LocalService;
  162. //
  163. // We now have to setup the LocalVolEntry.
  164. //
  165. LocalVolEntry->PktEntry = Entry;
  166. LocalVolEntry->ShareName.Buffer = ExAllocatePoolWithTag(
  167. PagedPool,
  168. ShareName->Length+sizeof(WCHAR),
  169. ' sfD');
  170. if (LocalVolEntry->ShareName.Buffer != NULL) {
  171. LocalVolEntry->ShareName.Length = ShareName->Length;
  172. LocalVolEntry->ShareName.MaximumLength = ShareName->Length + sizeof(WCHAR);
  173. RtlMoveMemory( LocalVolEntry->ShareName.Buffer,
  174. ShareName->Buffer,
  175. ShareName->Length);
  176. } else {
  177. DebugTrace(-1, Dbg, "PktEntrySetLocalService exit STATUS_INSUFFICIENT_RESOURCES(1)\n", 0);
  178. return( STATUS_INSUFFICIENT_RESOURCES );
  179. }
  180. LocalVolEntry->LocalPath.Buffer = ExAllocatePoolWithTag(
  181. PagedPool,
  182. LocalPath->Length+sizeof(WCHAR),
  183. ' sfD');
  184. if (LocalVolEntry->LocalPath.Buffer != NULL) {
  185. LocalVolEntry->LocalPath.Length = LocalPath->Length;
  186. LocalVolEntry->LocalPath.MaximumLength = LocalPath->Length + sizeof(WCHAR);
  187. RtlMoveMemory( LocalVolEntry->LocalPath.Buffer,
  188. LocalPath->Buffer,
  189. LocalPath->Length);
  190. DfsInsertUnicodePrefix(&Pkt->LocalVolTable,
  191. &(LocalVolEntry->LocalPath),
  192. &(LocalVolEntry->PrefixTableEntry));
  193. } else {
  194. ExFreePool( LocalVolEntry->ShareName.Buffer );
  195. LocalVolEntry->ShareName.Buffer = NULL;
  196. DebugTrace(-1, Dbg, "PktEntrySetLocalService exit STATUS_INSUFFICIENT_RESOURCES(2)\n", 0);
  197. return(STATUS_INSUFFICIENT_RESOURCES);
  198. }
  199. Entry->Type |= (PKT_ENTRY_TYPE_LOCAL | PKT_ENTRY_TYPE_PERMANENT);
  200. DebugTrace(-1, Dbg, "PktEntrySetLocalService exit STATUS_SUCCESS)\n", 0);
  201. return(STATUS_SUCCESS);
  202. }
  203. //+----------------------------------------------------------------------------
  204. //
  205. // Function: PktEntryUnsetLocalService, public
  206. //
  207. // Synopsis: The exact inverse of PktEntrySetLocalService. It is different
  208. // from PktEntryRemoveLocalService in that it does not try to
  209. // call DfsDetachVolume.
  210. //
  211. // Arguments:
  212. //
  213. // Returns:
  214. //
  215. //-----------------------------------------------------------------------------
  216. VOID
  217. PktEntryUnsetLocalService(
  218. IN PDFS_PKT Pkt,
  219. IN PDFS_PKT_ENTRY Entry,
  220. IN PUNICODE_STRING LocalPath)
  221. {
  222. ASSERT( Entry != NULL );
  223. if (Entry->LocalService != NULL) {
  224. PUNICODE_PREFIX_TABLE_ENTRY lvpfx;
  225. PDFS_LOCAL_VOL_ENTRY lv;
  226. UNICODE_STRING lvRemPath;
  227. lvpfx = DfsFindUnicodePrefix(
  228. &Pkt->LocalVolTable,
  229. LocalPath,
  230. &lvRemPath);
  231. ASSERT(lvpfx != NULL);
  232. lv = CONTAINING_RECORD(lvpfx, DFS_LOCAL_VOL_ENTRY, PrefixTableEntry);
  233. ASSERT(lv->PktEntry == Entry);
  234. //
  235. // Get rid of the local volume table entry
  236. //
  237. DfsRemoveUnicodePrefix( &Pkt->LocalVolTable, &lv->LocalPath);
  238. if (lv->ShareName.Buffer != NULL)
  239. ExFreePool(lv->ShareName.Buffer);
  240. if (lv->LocalPath.Buffer != NULL)
  241. ExFreePool(lv->LocalPath.Buffer);
  242. Entry->LocalService = NULL;
  243. }
  244. }
  245. //+-------------------------------------------------------------------------
  246. //
  247. // Function: PktEntryLookupLocalService, public
  248. //
  249. // Synopsis: PktEntryLookupLocalService finds the best match for a given
  250. // LocalPath and returns the rest of the path and the best match.
  251. //
  252. // Arguments: [LocalPath] -- pointer to the local service to be set.
  253. // [Remaining] -- The Remaining part of LocalPath.
  254. //
  255. // Returns: The LOCAL_VOL_ENTRY if a match was found in the PrefixTable.
  256. //
  257. //--------------------------------------------------------------------------
  258. PDFS_LOCAL_VOL_ENTRY
  259. PktEntryLookupLocalService(
  260. IN PDFS_PKT Pkt,
  261. IN PUNICODE_STRING LocalPath,
  262. OUT PUNICODE_STRING Remaining
  263. )
  264. {
  265. PUNICODE_PREFIX_TABLE_ENTRY lvpfx;
  266. PDFS_LOCAL_VOL_ENTRY lv = NULL;
  267. DebugTrace(+1, Dbg, "PktLookupLocalService: LocalPath: %wZ\n", LocalPath);
  268. if (LocalPath->Length != 0) {
  269. lvpfx = DfsFindUnicodePrefix(&Pkt->LocalVolTable,
  270. LocalPath,
  271. Remaining);
  272. if (lvpfx != NULL) {
  273. USHORT LPathLen;
  274. lv = CONTAINING_RECORD(lvpfx, DFS_LOCAL_VOL_ENTRY, PrefixTableEntry);
  275. LPathLen = lv->LocalPath.Length;
  276. if (LocalPath->Buffer[LPathLen/sizeof(WCHAR)]==UNICODE_PATH_SEP)
  277. LPathLen += sizeof(WCHAR);
  278. if (LPathLen < LocalPath->Length) {
  279. Remaining->Length = LocalPath->Length - LPathLen;
  280. Remaining->Buffer = &LocalPath->Buffer[LPathLen/sizeof(WCHAR)];
  281. DebugTrace(0,Dbg,"PktEntryLookupLocalService: Remaining: %wZ\n",
  282. Remaining);
  283. }
  284. else {
  285. Remaining->Length = Remaining->MaximumLength = 0;
  286. Remaining->Buffer = NULL;
  287. DebugTrace(0,Dbg,"PktEntryLookupLocalService:No Remaining\n",0);
  288. }
  289. }
  290. }
  291. DebugTrace(-1, Dbg, "PktLookupLocalService: Exit: %08lx\n", lv);
  292. return(lv);
  293. }
  294. //+-------------------------------------------------------------------------
  295. //
  296. // Function: PktEntryRemoveLocalService, public
  297. //
  298. // Synopsis: PktEntryRemoveLocalService clears the local service field of
  299. // the entry (deallocating any previous local service field
  300. // that may exist).
  301. //
  302. // Arguments: [Pkt] - pointer to the Pkt, must be acquired exclusive
  303. // [Entry] - pointer to the PKT entry to set the local service on.
  304. // [LocalPath] - pointer to the local service to be set.
  305. //
  306. // Returns: VOID
  307. //
  308. //--------------------------------------------------------------------------
  309. VOID
  310. PktEntryRemoveLocalService(
  311. IN PDFS_PKT Pkt,
  312. IN PDFS_PKT_ENTRY Entry,
  313. IN PUNICODE_STRING LocalPath
  314. ) {
  315. ASSERT (Entry->LocalService != NULL);
  316. if (Entry->LocalService != NULL) {
  317. PUNICODE_PREFIX_TABLE_ENTRY lvpfx;
  318. PDFS_LOCAL_VOL_ENTRY lv;
  319. UNICODE_STRING remPath;
  320. lvpfx = DfsFindUnicodePrefix(&Pkt->LocalVolTable,
  321. LocalPath,
  322. &remPath);
  323. if (lvpfx != NULL) {
  324. lv = CONTAINING_RECORD(lvpfx, DFS_LOCAL_VOL_ENTRY, PrefixTableEntry);
  325. ASSERT(lv->PktEntry == Entry);
  326. //
  327. // Get rid of the local volume table entry
  328. //
  329. DfsRemoveUnicodePrefix(&(Pkt->LocalVolTable), &(lv->LocalPath));
  330. if (lv->ShareName.Buffer != NULL)
  331. ExFreePool(lv->ShareName.Buffer);
  332. if (lv->LocalPath.Buffer != NULL)
  333. ExFreePool(lv->LocalPath.Buffer);
  334. ExFreePool(lv);
  335. //
  336. // Detach if needed
  337. //
  338. if ((Entry->LocalService->pProvider) &&
  339. !(Entry->LocalService->pProvider->fProvCapability & PROV_UNAVAILABLE)) {
  340. DfsDetachVolume(LocalPath);
  341. }
  342. PktServiceDestroy(Entry->LocalService, (BOOLEAN)TRUE);
  343. }
  344. Entry->LocalService = NULL;
  345. }
  346. Entry->Type &= ~PKT_ENTRY_TYPE_LOCAL;
  347. }
  348. //+-------------------------------------------------------------------------
  349. //
  350. // Function: PktServiceConstruct, public
  351. //
  352. // Synopsis: PktServiceConstruct creates a new service structure.
  353. //
  354. // Arguments: [Service] - a pointer to a service structure to fill.
  355. // [ServiceType] - the type of the new service.
  356. // [ServiceCapability] - the capabilities of the new service.
  357. // [ServiceStatus] - the initial status of the new service.
  358. // [ServiceProviderId] - the provider Id of the new service.
  359. // [ServiceName] - the name of the principal for the service
  360. // [ServiceAddress] - a string which gives the address
  361. // of the service.
  362. //
  363. // Returns: [STATUS_SUCCESS] - all is well.
  364. // [STATUS_INSUFFICIENT_RESOURCES] - memory could not be
  365. // allocated for this new service.
  366. //
  367. // Notes: All data is copied (Not MOVED).
  368. //
  369. //--------------------------------------------------------------------------
  370. NTSTATUS
  371. PktServiceConstruct(
  372. OUT PDFS_SERVICE Service,
  373. IN ULONG ServiceType,
  374. IN ULONG ServiceCapability,
  375. IN ULONG ServiceStatus,
  376. IN ULONG ServiceProviderId,
  377. IN PUNICODE_STRING ServiceName OPTIONAL,
  378. IN PUNICODE_STRING ServiceAddress OPTIONAL
  379. ) {
  380. DebugTrace(+1, Dbg, "PktServiceConstruct: Entered\n", 0);
  381. ASSERT(ARGUMENT_PRESENT(Service));
  382. RtlZeroMemory(Service, sizeof(DFS_SERVICE));
  383. if (ARGUMENT_PRESENT(ServiceName)) {
  384. Service->Name.Buffer = ExAllocatePoolWithTag(
  385. PagedPool,
  386. ServiceName->Length,
  387. ' sfD');
  388. if (Service->Name.Buffer == NULL) {
  389. DebugTrace(-1, Dbg, "PktServiceConstruct: Exit -> %08lx\n",
  390. ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) );
  391. return STATUS_INSUFFICIENT_RESOURCES;
  392. }
  393. Service->Name.Length = ServiceName->Length;
  394. Service->Name.MaximumLength = ServiceName->Length;
  395. RtlCopyUnicodeString(&Service->Name, ServiceName);
  396. }
  397. if (ARGUMENT_PRESENT(ServiceAddress) && ServiceAddress->Length != 0) {
  398. Service->Address.Buffer = ExAllocatePoolWithTag(
  399. PagedPool,
  400. ServiceAddress->Length,
  401. ' sfD');
  402. if (Service->Address.Buffer == NULL) {
  403. if (Service->Name.Buffer != NULL)
  404. DfsFree(Service->Name.Buffer);
  405. DebugTrace(-1, Dbg, "PktServiceConstruct: Exit -> %08lx\n",
  406. ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) );
  407. return STATUS_INSUFFICIENT_RESOURCES;
  408. }
  409. RtlMoveMemory(Service->Address.Buffer, ServiceAddress->Buffer,
  410. ServiceAddress->Length);
  411. Service->Address.Length =
  412. Service->Address.MaximumLength = ServiceAddress->Length;
  413. } else {
  414. Service->Address.Buffer = NULL;
  415. Service->Address.Length = Service->Address.MaximumLength = 0;
  416. }
  417. Service->Type = ServiceType;
  418. Service->Capability = ServiceCapability;
  419. Service->Status = ServiceStatus;
  420. Service->ProviderId = ServiceProviderId;
  421. Service->pProvider = NULL;
  422. DebugTrace(-1, Dbg, "PktServiceConstruct: Exit -> %08lx\n",
  423. STATUS_SUCCESS );
  424. return STATUS_SUCCESS;
  425. }
  426. //+-------------------------------------------------------------------------
  427. //
  428. // Function: PktDSTransportDestroy, public
  429. //
  430. // Synopsis: PktDSTransportDestroy destroys a DS_TRANSPORT structure, and
  431. // optionally deallocates the structure itself.
  432. //
  433. // Arguments: [Victim] - the DS_TRANSPORT structure to destroy
  434. // [DeallocateAll] - if True, indicates that the structure
  435. // it self is to be deallocated, otherwise, only the
  436. // strings within the structure are deallocated.
  437. //
  438. // Returns: VOID
  439. //
  440. // Notes:
  441. //
  442. //--------------------------------------------------------------------------
  443. VOID
  444. PktDSTransportDestroy(
  445. IN PDS_TRANSPORT Victim OPTIONAL,
  446. IN BOOLEAN DeallocateAll
  447. )
  448. {
  449. DebugTrace(+1, Dbg, "PktDSTransportDestroy: Entered\n", 0);
  450. if (ARGUMENT_PRESENT(Victim)) {
  451. //
  452. // Nothing to free in this structure??
  453. //
  454. if (DeallocateAll)
  455. ExFreePool(Victim);
  456. } else
  457. DebugTrace(0, Dbg, "PktDSTransportDestroy: No Victim\n", 0 );
  458. DebugTrace(-1, Dbg, "PktDSTransportDestroy: Exit -> VOID\n", 0 );
  459. }
  460. //+-------------------------------------------------------------------------
  461. //
  462. // Function: PktDSMachineDestroy, public
  463. //
  464. // Synopsis: PktDSMachineDestroy destroys a DS_MACHINE structure, and
  465. // optionally deallocates the structure itself.
  466. //
  467. // Arguments: [Victim] - the DS_MACHINE structure to destroy
  468. // [DeallocateAll] - if True, indicates that the structure
  469. // it self is to be deallocated, otherwise, only the
  470. // strings within the structure are deallocated.
  471. //
  472. // Returns: VOID
  473. //
  474. // Notes:
  475. //
  476. //--------------------------------------------------------------------------
  477. VOID
  478. PktDSMachineDestroy(
  479. IN PDS_MACHINE Victim OPTIONAL,
  480. IN BOOLEAN DeallocateAll
  481. )
  482. {
  483. ULONG i;
  484. DebugTrace(+1, Dbg, "PktDSMachineDestroy: Entered\n", 0);
  485. if (ARGUMENT_PRESENT(Victim)) {
  486. if (Victim->pwszShareName != NULL) {
  487. DfsFree(Victim->pwszShareName);
  488. }
  489. if (Victim->prgpwszPrincipals != NULL && Victim->cPrincipals > 0) {
  490. for (i = 0; i < Victim->cPrincipals; i++) {
  491. if (Victim->prgpwszPrincipals[i] != NULL)
  492. DfsFree(Victim->prgpwszPrincipals[i]);
  493. }
  494. }
  495. if (Victim->prgpwszPrincipals) {
  496. ExFreePool(Victim->prgpwszPrincipals);
  497. }
  498. for (i = 0; i < Victim->cTransports; i++) {
  499. PktDSTransportDestroy(Victim->rpTrans[i], TRUE);
  500. }
  501. if (DeallocateAll)
  502. ExFreePool(Victim);
  503. } else
  504. DebugTrace(0, Dbg, "PktDSMachineDestroy: No Victim\n", 0 );
  505. DebugTrace(-1, Dbg, "PktDSMachineDestroy: Exit -> VOID\n", 0 );
  506. }
  507. //+-------------------------------------------------------------------------
  508. //
  509. // Function: DfsDecrementMachEntryCount
  510. //
  511. // Synopsis: This function decrements the count for the pMachine passed
  512. // in and if necessary will also free up the DS_MACHINE struct
  513. //
  514. //--------------------------------------------------------------------------
  515. VOID
  516. DfsDecrementMachEntryCount(
  517. PDFS_MACHINE_ENTRY pMachEntry,
  518. BOOLEAN DeallocateMachine
  519. )
  520. {
  521. NTSTATUS status = STATUS_SUCCESS;
  522. UNICODE_STRING ustrMachineName;
  523. PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
  524. PDS_MACHINE pMachine;
  525. PDFS_PKT Pkt;
  526. ASSERT(pMachEntry != NULL);
  527. if (pMachEntry == NULL)
  528. return;
  529. pMachine = pMachEntry->pMachine;
  530. ASSERT(pMachine != NULL);
  531. if (pMachine == NULL)
  532. return;
  533. //
  534. // We already have appropriate locks
  535. //
  536. Pkt = _GetPkt();
  537. //
  538. // For now we only expect one principal.
  539. //
  540. ASSERT(pMachine->cPrincipals == 1);
  541. pMachEntry->UseCount--;
  542. if (pMachEntry->UseCount == 0) {
  543. //
  544. // This means we can now actually delete this DS_MACHINE structure
  545. //
  546. RtlRemoveUnicodePrefix(&Pkt->DSMachineTable,
  547. &pMachEntry->PrefixTableEntry);
  548. if (DeallocateMachine)
  549. PktDSMachineDestroy(pMachine, TRUE);
  550. //
  551. // Free the entry itself. Note that the UNICODE_STRING in the
  552. // entry gets freed up as part of above pMachine deletion.
  553. //
  554. DfsFree(pMachEntry);
  555. }
  556. }
  557. //+-------------------------------------------------------------------------
  558. //
  559. // Function: PktServiceDestroy, public
  560. //
  561. // Synopsis: PktServiceDestroy destroys a service structure, and
  562. // optionally deallocates the structure itself.
  563. //
  564. // Arguments: [Victim] - the service structure to destroy
  565. // [DeallocateAll] - if True, indicates that the structure
  566. // it self is to be deallocated, otherwise, only the
  567. // strings within the structure are deallocated.
  568. //
  569. // Returns: VOID
  570. //
  571. // Notes:
  572. //
  573. //--------------------------------------------------------------------------
  574. VOID
  575. PktServiceDestroy(
  576. IN PDFS_SERVICE Victim OPTIONAL,
  577. IN BOOLEAN DeallocateAll
  578. )
  579. {
  580. DebugTrace(+1, Dbg, "PktServiceDestroy: Entered\n", 0);
  581. if (ARGUMENT_PRESENT(Victim)) {
  582. if (Victim->ConnFile != NULL) {
  583. DfsCloseConnection(Victim);
  584. Victim->ConnFile = NULL;
  585. }
  586. if (Victim->Name.Buffer != NULL)
  587. DfsFree(Victim->Name.Buffer);
  588. Victim->Name.Buffer = NULL;
  589. if (Victim->Address.Buffer != NULL)
  590. DfsFree(Victim->Address.Buffer);
  591. Victim->Address.Buffer = NULL;
  592. //
  593. // Decrement the usage count. If it is to be deleted it will happen
  594. // automatically.
  595. //
  596. if (Victim->pMachEntry != NULL) {
  597. DfsDecrementMachEntryCount(Victim->pMachEntry, TRUE);
  598. }
  599. if (DeallocateAll)
  600. ExFreePool(Victim);
  601. } else
  602. DebugTrace(0, Dbg, "PktServiceDestroy: No Victim\n", 0 );
  603. DebugTrace(-1, Dbg, "PktServiceDestroy: Exit -> VOID\n", 0 );
  604. }
  605. //+-------------------------------------------------------------------------
  606. //
  607. // Function: PktEntryIdConstruct, public
  608. //
  609. // Synopsis: PktEntryIdConstruct creates a PKT Entry Id
  610. //
  611. // Arguments: [PktEntryId] - Where the new entry is placed
  612. // [Uid] - The UID of the new Pkt Entry
  613. // [Prefix] - The prefix of the new Pkt Entry
  614. // [ShortPrefix] - The 8.3 form of Prefix
  615. //
  616. // Returns: [STATUS_SUCCESS] - all is well.
  617. // [STATUS_INSUFFICIENT_RESOURCES] - could not allocate
  618. // memory for the Prefix part of the Id.
  619. //
  620. // Notes: The UNICODE_STRING used in the Prefix of the Id is COPIED,
  621. // not MOVED!
  622. //
  623. //--------------------------------------------------------------------------
  624. NTSTATUS
  625. PktEntryIdConstruct(
  626. OUT PDFS_PKT_ENTRY_ID PktEntryId,
  627. IN GUID *Uid,
  628. IN UNICODE_STRING *Prefix,
  629. IN UNICODE_STRING *ShortPrefix
  630. )
  631. {
  632. PUNICODE_STRING pus;
  633. DebugTrace(+1, Dbg, "PktEntryIdConstruct: Entered\n", 0);
  634. ASSERT(ARGUMENT_PRESENT(PktEntryId));
  635. ASSERT(ARGUMENT_PRESENT(Prefix));
  636. //
  637. // Zero the memory
  638. //
  639. RtlZeroMemory(PktEntryId, sizeof(DFS_PKT_ENTRY_ID));
  640. //
  641. // deal with the prefix.
  642. //
  643. pus = &PktEntryId->Prefix;
  644. if (Prefix->Length != 0) {
  645. pus->Length = pus->MaximumLength = Prefix->Length;
  646. pus->Buffer = ExAllocatePoolWithTag(
  647. PagedPool,
  648. pus->Length,
  649. ' sfD');
  650. if (pus->Buffer != NULL) {
  651. RtlCopyUnicodeString(pus, Prefix);
  652. } else {
  653. DebugTrace(-1,Dbg,"PktEntryIdConstruct: Exit -> %08lx\n",
  654. ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ));
  655. return STATUS_INSUFFICIENT_RESOURCES;
  656. }
  657. }
  658. pus = &PktEntryId->ShortPrefix;
  659. if (ShortPrefix->Length != 0) {
  660. pus->Length = pus->MaximumLength = ShortPrefix->Length;
  661. pus->Buffer = ExAllocatePoolWithTag(
  662. PagedPool,
  663. pus->Length,
  664. ' sfD');
  665. if (pus->Buffer != NULL) {
  666. RtlCopyUnicodeString(pus, ShortPrefix);
  667. } else {
  668. ExFreePool(PktEntryId->Prefix.Buffer);
  669. PktEntryId->Prefix.Buffer = NULL;
  670. DebugTrace(-1,Dbg,"PktEntryIdConstruct: Exit -> %08lx\n",
  671. ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ));
  672. return STATUS_INSUFFICIENT_RESOURCES;
  673. }
  674. }
  675. //
  676. // deal with the GUID.
  677. //
  678. if (ARGUMENT_PRESENT(Uid)) {
  679. PktEntryId->Uid = (*Uid);
  680. }
  681. DebugTrace(-1,Dbg,"PktEntryIdConstruct: Exit -> %08lx\n",STATUS_SUCCESS);
  682. return STATUS_SUCCESS;
  683. }
  684. //+-------------------------------------------------------------------------
  685. //
  686. // Function: PktEntryIdDestroy, public
  687. //
  688. // Synopsis: PktEntryIdDestroy destroys a PKT Entry Id
  689. //
  690. // Arguments: [Victim] - Id to destroy
  691. // [DeallocateAll] - if true, indicates that the memory
  692. // for the Id itself is to be release, otherwise,
  693. // this memory is not released (only the memory for
  694. // the UNICODE_STRING in the Prefix is released).
  695. //
  696. // Returns: VOID
  697. //
  698. // Notes: Memory for the UNICODE_STRING in the Prefix is released.
  699. //
  700. //--------------------------------------------------------------------------
  701. VOID
  702. PktEntryIdDestroy(
  703. IN PDFS_PKT_ENTRY_ID Victim OPTIONAL,
  704. IN BOOLEAN DeallocateAll
  705. )
  706. {
  707. DebugTrace(+1, Dbg, "PktEntryIdDestroy: Entered\n", 0);
  708. if (ARGUMENT_PRESENT(Victim)) {
  709. if (Victim->Prefix.Buffer != NULL)
  710. DfsFree(Victim->Prefix.Buffer);
  711. if (Victim->ShortPrefix.Buffer != NULL)
  712. DfsFree(Victim->ShortPrefix.Buffer);
  713. if (DeallocateAll)
  714. ExFreePool(Victim);
  715. } else
  716. DebugTrace(0, Dbg, "PktEntryIdDestroy: No Victim\n", 0 );
  717. DebugTrace(-1, Dbg, "PktEntryIdDestroy: Exit -> VOID\n", 0 );
  718. }
  719. //+-------------------------------------------------------------------------
  720. //
  721. // Function: PktEntryInfoDestroy, public
  722. //
  723. // Synopsis: PktEntryInfoDestroy destroys an info structure, and
  724. // optionally deallocates the structure itself.
  725. //
  726. // Arguments: [Victim] - the info structure to destroy
  727. // [DeallocateAll] - if True, indicates that the structure
  728. // itself is to be deallocated, otherwise, only the
  729. // service list within the structure is deallocated.
  730. //
  731. // Returns: VOID
  732. //
  733. // Notes:
  734. //
  735. //--------------------------------------------------------------------------
  736. VOID
  737. PktEntryInfoDestroy(
  738. IN PDFS_PKT_ENTRY_INFO Victim OPTIONAL,
  739. IN BOOLEAN DeallocateAll
  740. )
  741. {
  742. DebugTrace(+1, Dbg, "PktEntryInfoDestroy: Entered\n", 0);
  743. if (ARGUMENT_PRESENT(Victim)) {
  744. ULONG i;
  745. for (i = 0; i < Victim->ServiceCount; i++)
  746. PktServiceDestroy(&Victim->ServiceList[i], FALSE);
  747. if (Victim->ServiceCount)
  748. ExFreePool(Victim->ServiceList);
  749. if (DeallocateAll)
  750. ExFreePool(Victim);
  751. } else
  752. DebugTrace(0, Dbg, "PktEntryInfoDestroy: No Victim\n", 0 );
  753. DebugTrace(-1, Dbg, "PktEntryInfoDestroy: Exit -> VOID\n", 0 );
  754. }
  755. //+-------------------------------------------------------------------------
  756. //
  757. // Function: DfspFixService
  758. //
  759. // Synopsis: This function should be called when a new service's DS_MACHINE
  760. // struct has to be adjusted to make sure there is a unique one
  761. // for each machine in the PKT.
  762. //
  763. // Arguments: [pService] -- The Service struct to fix up.
  764. //
  765. // History: 23 August 1994 SudK Created.
  766. //
  767. //--------------------------------------------------------------------------
  768. NTSTATUS
  769. DfspFixService(
  770. PDFS_SERVICE pService
  771. )
  772. {
  773. NTSTATUS status = STATUS_SUCCESS;
  774. UNICODE_STRING ustrMachineName;
  775. PDS_MACHINE pMachine;
  776. PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
  777. PDFS_MACHINE_ENTRY machEntry;
  778. PDFS_PKT Pkt;
  779. ASSERT(pService != NULL);
  780. ASSERT(pService->pMachEntry != NULL);
  781. pMachine = pService->pMachEntry->pMachine;
  782. if (pMachine->cPrincipals == 0) {
  783. ASSERT(pService->Type && DFS_SERVICE_TYPE_DOWN_LEVEL);
  784. pService->pMachEntry->UseCount = 1;
  785. return(status);
  786. }
  787. //
  788. // We are called during PktCreateEntry. We already have appropriate locks
  789. //
  790. Pkt = _GetPkt();
  791. //
  792. // For now we only expect one principal.
  793. //
  794. ASSERT(pMachine->cPrincipals == 1);
  795. RtlInitUnicodeString(&ustrMachineName,
  796. pMachine->prgpwszPrincipals[0]);
  797. ASSERT(ustrMachineName.Buffer != NULL);
  798. pfxEntry = RtlFindUnicodePrefix(&Pkt->DSMachineTable,&ustrMachineName,TRUE);
  799. if (pfxEntry != NULL) {
  800. //
  801. // In this case the DS_Machine structure already exists. Just use the
  802. // existing DS_Machine struct and bump the UseCount
  803. //
  804. machEntry = CONTAINING_RECORD(pfxEntry,
  805. DFS_MACHINE_ENTRY,
  806. PrefixTableEntry);
  807. machEntry->UseCount++;
  808. //
  809. // Even though we are "reusing" the Machine Entry, we might have a
  810. // better DS_MACHINE (ie, one with more transports) in the incoming
  811. // one. If so, lets use the new one.
  812. //
  813. if (pMachine->cTransports > machEntry->pMachine->cTransports) {
  814. PDS_MACHINE pTempMachine;
  815. DebugTrace(0, 0, "DfspFixService: Using new DS_MACHINE for [%wZ]\n", &ustrMachineName);
  816. pTempMachine = machEntry->pMachine;
  817. machEntry->pMachine = pMachine;
  818. pService->pMachEntry->pMachine = pTempMachine;
  819. RtlRemoveUnicodePrefix(
  820. &Pkt->DSMachineTable,
  821. &machEntry->PrefixTableEntry);
  822. machEntry->MachineName = ustrMachineName;
  823. RtlInsertUnicodePrefix(
  824. &Pkt->DSMachineTable,
  825. &machEntry->MachineName,
  826. &machEntry->PrefixTableEntry);
  827. }
  828. pService->pMachEntry = machEntry;
  829. } else {
  830. //
  831. // In this case the DS_Machine is not there in the table. Need to add
  832. // current one to the table.
  833. //
  834. machEntry = pService->pMachEntry;
  835. machEntry->UseCount = 1;
  836. machEntry->MachineName = ustrMachineName; // Use same mem in DS_MACHINE.
  837. //
  838. // Now insert the machEntry and then we are done. This better not fail.
  839. //
  840. if (!RtlInsertUnicodePrefix(&Pkt->DSMachineTable,
  841. &machEntry->MachineName,
  842. &machEntry->PrefixTableEntry)) {
  843. BugCheck("DFS Pkt inconsistent DfspFixService");
  844. }
  845. }
  846. return(status);
  847. }
  848. //+-------------------------------------------------------------------------
  849. //
  850. // Function: DfsFixDSMachineStructs
  851. //
  852. // Synopsis: For the entry given this function makes sure that there is
  853. // only one DS_MACHINE structure in the PKT. If there isn't one
  854. // then one is registered. If there is one then the same one is
  855. // used and the current one in the DFS_SERVICE struct is freed up.
  856. //
  857. // Arguments: [pEntry] -- The PKT entry that has to be fixed.
  858. //
  859. // Notes: If this function fails then it will reset the pEntry to the
  860. // same format it was when it was called.
  861. //
  862. // History: 22 Aug 1994 SudK Created.
  863. //
  864. //--------------------------------------------------------------------------
  865. NTSTATUS
  866. DfsFixDSMachineStructs(
  867. PDFS_PKT_ENTRY pEntry
  868. )
  869. {
  870. NTSTATUS status = STATUS_SUCCESS;
  871. ULONG i;
  872. PDFS_MACHINE_ENTRY *apMachineEntry;
  873. PDFS_SERVICE pService;
  874. if (pEntry->Info.ServiceCount == 0)
  875. return(status);
  876. //
  877. // In case of downlevel we do nothing
  878. //
  879. if (pEntry->Type & PKT_ENTRY_TYPE_NONCAIRO)
  880. return(status);
  881. apMachineEntry = ExAllocatePoolWithTag(
  882. PagedPool,
  883. sizeof(PDFS_MACHINE_ENTRY) * pEntry->Info.ServiceCount,
  884. ' sfD');
  885. if (apMachineEntry == NULL) {
  886. return(STATUS_INSUFFICIENT_RESOURCES);
  887. }
  888. for (i=0; i < pEntry->Info.ServiceCount; i++) {
  889. //
  890. // First Save the current DS_Machine and then fix up
  891. //
  892. apMachineEntry[i] = pEntry->Info.ServiceList[i].pMachEntry;
  893. status = DfspFixService(&pEntry->Info.ServiceList[i]);
  894. if (!NT_SUCCESS(status)) {
  895. //
  896. // In this case we break and let the cleanup part below take care
  897. // of cleaning up everything.
  898. //
  899. break;
  900. }
  901. }
  902. if (!NT_SUCCESS(status)) {
  903. //
  904. // We need to cleanup in this case. I.E. reset all the PDS_MACHINEs
  905. // back to old values and decrement any usage counts on DS_MACHINE
  906. // structures.
  907. //
  908. ULONG j;
  909. for (j=0; j < i; j++) {
  910. pService = &pEntry->Info.ServiceList[j];
  911. //
  912. // These have already been fixed up so decrement the count on the
  913. // pMachine structs. Dont want to deallocate the pMachine structs
  914. // if we were the last one to use it.
  915. //
  916. DfsDecrementMachEntryCount(pService->pMachEntry, FALSE);
  917. if (apMachineEntry[j] != pService->pMachEntry)
  918. pService->pMachEntry = apMachineEntry[j];
  919. }
  920. }
  921. else {
  922. //
  923. // In this case everything went fine. So we need to free up the
  924. // DS_MACHINE structures that were superfluously allocated for now.
  925. //
  926. for (i=0; i<pEntry->Info.ServiceCount; i++) {
  927. if (apMachineEntry[i] != pEntry->Info.ServiceList[i].pMachEntry) {
  928. //
  929. // This means that the pMachine in the service list got replaced
  930. // by a different one so let us free this one now.
  931. //
  932. PktDSMachineDestroy(apMachineEntry[i]->pMachine, TRUE);
  933. ExFreePool( apMachineEntry[i] );
  934. }
  935. }
  936. }
  937. ExFreePool(apMachineEntry);
  938. return(status);
  939. }
  940. //+-------------------------------------------------------------------------
  941. //
  942. // Function: PktEntryAssemble, private
  943. //
  944. // Synopsis: PktpEntryAssemble blindly constructs a new partition
  945. // table entry and places it in the PKT. The caller must
  946. // have previously determined that no other entry with this
  947. // UID or Prefix existed. The PKT must be acquired exclusively
  948. // for this operation.
  949. //
  950. // Arguments: [Entry] - a pointer to an entry to be filled.
  951. // [Pkt] - pointer to a initialized (and acquired
  952. // exclusively) PKT
  953. // [EntryType] - the type of entry to assemble.
  954. // [EntryId] - pointer to the new entry's Id.
  955. // [EntryInfo] - pointer to the guts of the entry.
  956. //
  957. // Returns: [STATUS_SUCCESS] if no error.
  958. // [STATUS_INVALID_PARAMETER] - if the EntryId does not have a
  959. // UID or a Prefix (no such thing as an anonymous entry).
  960. // [PKT_ENTRY_EXISTS] - a new prefix table entry could not
  961. // be made.
  962. //
  963. // Notes: The EntryId and EntryInfo structures are MOVED (not
  964. // COPIED) to the new entry. The memory used for UNICODE_STRINGS
  965. // and DFS_SERVICE arrays is used by the new entry. The
  966. // associated fields in the EntryId and EntryInfo
  967. // structures passed as arguments are Zero'd to indicate that
  968. // the memory has been "deallocated" from these strutures and
  969. // reallocated to the newly create Entry. Note that this
  970. // routine does not deallocate the EntryId structure or
  971. // the EntryInfo structure itself. On successful return from
  972. // this function, the EntryId structure will be modified
  973. // to have a NULL Prefix entry, and the EntryInfo structure
  974. // will be modified to have zero services and a null ServiceList
  975. // entry.
  976. //
  977. //--------------------------------------------------------------------------
  978. NTSTATUS
  979. PktEntryAssemble(
  980. IN OUT PDFS_PKT_ENTRY Entry,
  981. IN PDFS_PKT Pkt,
  982. IN ULONG EntryType,
  983. IN PDFS_PKT_ENTRY_ID EntryId,
  984. IN PDFS_PKT_ENTRY_INFO EntryInfo OPTIONAL
  985. )
  986. {
  987. NTSTATUS status = STATUS_SUCCESS;
  988. ULONG i;
  989. PDFS_SERVICE pService;
  990. DebugTrace(+1, Dbg, "PktEntryAssemble: Entered\n", 0);
  991. ASSERT(ARGUMENT_PRESENT(Entry) &&
  992. ARGUMENT_PRESENT(EntryId));
  993. //
  994. // We do not allow the creation of entries
  995. // without any Uid or Prefix.
  996. //
  997. if (NullGuid(&EntryId->Uid) && EntryId->Prefix.Length == 0) {
  998. DebugTrace(-1, Dbg, "PktEntryAssemble: Exit -> %08lx\n",
  999. ULongToPtr( STATUS_INVALID_PARAMETER ) );
  1000. return STATUS_INVALID_PARAMETER;
  1001. }
  1002. //
  1003. // Zero out the entry.
  1004. //
  1005. RtlZeroMemory(Entry, sizeof(DFS_PKT_ENTRY));
  1006. //
  1007. // Mundane initialization
  1008. //
  1009. Entry->NodeTypeCode = DFS_NTC_PKT_ENTRY;
  1010. Entry->NodeByteSize = sizeof(DFS_PKT_ENTRY);
  1011. //
  1012. // Initialize the USN to 1
  1013. //
  1014. Entry->USN = 1;
  1015. //
  1016. // Move the Type, Id, and Info into this entry.
  1017. //
  1018. Entry->Type = EntryType;
  1019. PktpEntryIdMove(&Entry->Id, EntryId);
  1020. if (ARGUMENT_PRESENT(EntryInfo)) {
  1021. PktpEntryInfoMove(&Entry->Info, EntryInfo);
  1022. for (i = 0; i < Entry->Info.ServiceCount; i++) {
  1023. Entry->Info.ServiceList[i].pMachEntry->UseCount = 1;
  1024. }
  1025. //
  1026. // If we are setting up a PKT_ENTRY_TYPE_REFERRAL_SVC entry then we want
  1027. // to mark ALL of its services to be REFERRAL_SERVICES as well.
  1028. //
  1029. if (EntryType & PKT_ENTRY_TYPE_REFERRAL_SVC) {
  1030. pService = Entry->Info.ServiceList;
  1031. for (i=0; i<Entry->Info.ServiceCount; i++) {
  1032. pService->Type = pService->Type | DFS_SERVICE_TYPE_REFERRAL;
  1033. pService++;
  1034. }
  1035. }
  1036. //
  1037. // Now we need to make sure that there is only one copy of the
  1038. // DS_MACHINE structures for each of the above services that we added.
  1039. //
  1040. if (!(EntryType & PKT_ENTRY_TYPE_NONCAIRO)) {
  1041. status = DfsFixDSMachineStructs(Entry);
  1042. if (!NT_SUCCESS(status)) {
  1043. //
  1044. // We messed up. This means that something is really messed up.
  1045. //
  1046. DebugTrace(0, 1,
  1047. "DFS: DfsFixDSMachineStructs failed for %wZ\n",
  1048. &Entry->Id.Prefix);
  1049. PktpEntryIdMove(EntryId, &Entry->Id);
  1050. if (ARGUMENT_PRESENT(EntryInfo))
  1051. PktpEntryInfoMove(EntryInfo, &Entry->Info);
  1052. return(status);
  1053. }
  1054. }
  1055. }
  1056. //
  1057. // Initialize the head of the subordinate list.
  1058. //
  1059. InitializeListHead(&Entry->SubordinateList);
  1060. //
  1061. // Initialize the head of the childList.
  1062. //
  1063. InitializeListHead(&Entry->ChildList);
  1064. //
  1065. // Try to get us into the prefix table.
  1066. //
  1067. if (DfsInsertUnicodePrefix(&Pkt->PrefixTable,
  1068. &Entry->Id.Prefix,
  1069. &Entry->PrefixTableEntry)) {
  1070. //
  1071. // We successfully created the prefix entry, so now we link
  1072. // this entry into the PKT.
  1073. //
  1074. PktLinkEntry(Pkt, Entry);
  1075. //
  1076. // And insert into the short prefix table. We don't do error
  1077. // recovery if this fails.
  1078. //
  1079. DfsInsertUnicodePrefix(&Pkt->ShortPrefixTable,
  1080. &Entry->Id.ShortPrefix,
  1081. &Entry->PrefixTableEntry);
  1082. } else {
  1083. //
  1084. // We failed to get the entry into the prefix table. This
  1085. // can only happen if a prefix already exists, and a prefix
  1086. // can only exist if we've really gotten messed up...
  1087. // We disassemble the entry and return an error.
  1088. //
  1089. DebugTrace(0, 1,
  1090. "DFS: PktEntryAssemble failed prefix table insert of %wZ\n",
  1091. &Entry->Id.Prefix);
  1092. PktpEntryIdMove(EntryId, &Entry->Id);
  1093. if (ARGUMENT_PRESENT(EntryInfo))
  1094. PktpEntryInfoMove(EntryInfo, &Entry->Info);
  1095. status = DFS_STATUS_ENTRY_EXISTS;
  1096. }
  1097. DebugTrace(-1, Dbg, "PktEntryAssemble: Exit -> %08lX\n", ULongToPtr( status ) );
  1098. return STATUS_SUCCESS;
  1099. }
  1100. //+-------------------------------------------------------------------------
  1101. //
  1102. // Function: PktEntryReassemble, private
  1103. //
  1104. // Synopsis: PktpEntryReassemble blindly reconstructs a partition
  1105. // table entry. It provides a mechanism by which an existing
  1106. // entry can be modified. The caller must have previously
  1107. // determined that no other entry with this UID or Prefix
  1108. // existed. The PKT must be acquired exclusively for this
  1109. // operation.
  1110. //
  1111. // Arguments: [Entry] - a pointer to an entry to be reassembled.
  1112. // [Pkt] - pointer to a initialized (and acquired
  1113. // exclusively) PKT - must be provided if EntryId
  1114. // is provided.
  1115. // [EntryType] - the type of entry to reassemble.
  1116. // [EntryId] - pointer to the entry's new Id.
  1117. // [EntryInfo] - pointer to the new guts of the entry.
  1118. //
  1119. // Returns: [STATUS_SUCCESS] if no error.
  1120. // [STATUS_INVALID_PARAMETER] - if the EntryId does not have a
  1121. // UID or a Prefix (no such thing as an anonymous entry), or
  1122. // and EntryId was provided but a PKT argument was not.
  1123. // [DFS_STATUS_ENTRY_EXISTS] - a new prefix table entry could not
  1124. // be made.
  1125. // [DFS_STATUS_INCONSISTENT] - a new prefix table entry could
  1126. // not be made, and we could not back out of the operation.
  1127. // This status return indicates that the entry is no longer
  1128. // in the prefix table associated with the PKT and that
  1129. // it is likely that the PKT is inconsistent as a result.
  1130. //
  1131. // Notes: The EntryId and EntryInfo structures are MOVED (not
  1132. // COPIED) to the entry, the old Id and Info are destroyed.
  1133. // The memory used for UNICODE_STRINGS and DFS_SERVICE arrays
  1134. // is used by the entry. The associated fields in the EntryId
  1135. // and EntryInfo structures passed as arguments are Zero'd to
  1136. // indicate that the memory has been "deallocated" from these
  1137. // structures and reallocated to the newly created Entry. Note
  1138. // that this routine does not deallocate the EntryId structure
  1139. // or the EntryInfo structure itself. On successful return from
  1140. // this function, the EntryId structure will be modified
  1141. // to have a NULL Prefix entry, and the EntryInfo structure
  1142. // will be modified to have zero services and a null ServiceList
  1143. // entry.
  1144. //
  1145. //--------------------------------------------------------------------------
  1146. NTSTATUS
  1147. PktEntryReassemble(
  1148. IN OUT PDFS_PKT_ENTRY Entry,
  1149. IN PDFS_PKT Pkt,
  1150. IN ULONG EntryType,
  1151. IN PDFS_PKT_ENTRY_ID EntryId OPTIONAL,
  1152. IN PDFS_PKT_ENTRY_INFO EntryInfo OPTIONAL
  1153. )
  1154. {
  1155. NTSTATUS status = STATUS_SUCCESS;
  1156. ULONG i;
  1157. PDFS_SERVICE pService;
  1158. DebugTrace(+1, Dbg, "PktEntryReassemble: Entered\n", 0);
  1159. ASSERT(ARGUMENT_PRESENT(Entry) &&
  1160. ARGUMENT_PRESENT(Pkt));
  1161. if (ARGUMENT_PRESENT(EntryId)) {
  1162. DFS_PKT_ENTRY_ID oldId;
  1163. //
  1164. // We do not allow the creation of entries
  1165. // without any Prefix.
  1166. //
  1167. if (EntryId->Prefix.Length == 0) {
  1168. DebugTrace(-1, Dbg, "PktEntryReassemble: Exit -> %08lx\n",
  1169. ULongToPtr( STATUS_INVALID_PARAMETER ));
  1170. return STATUS_INVALID_PARAMETER;
  1171. }
  1172. //
  1173. // need to get rid of our current prefix info. We save the
  1174. // old Id in case we fail to reassemble the new entry.
  1175. //
  1176. DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &Entry->Id.Prefix);
  1177. DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &Entry->Id.ShortPrefix);
  1178. PktpEntryIdMove(&oldId, &Entry->Id);
  1179. //
  1180. // Now we assemble the new Id and attempt to make a new entry
  1181. // in the Pkt prefix table.
  1182. //
  1183. PktpEntryIdMove(&Entry->Id, EntryId);
  1184. if (DfsInsertUnicodePrefix(&Pkt->PrefixTable,
  1185. &Entry->Id.Prefix,
  1186. &Entry->PrefixTableEntry))
  1187. {
  1188. USHORT len = oldId.Prefix.Length/sizeof(WCHAR);
  1189. //
  1190. // We get ourselves into the short prefix table
  1191. //
  1192. DfsInsertUnicodePrefix(&Pkt->ShortPrefixTable,
  1193. &Entry->Id.ShortPrefix,
  1194. &Entry->PrefixTableEntry);
  1195. //
  1196. // If we just dealt with a LocalVolEntry then we need to fix the
  1197. // registry as well if the prefixes actually changed.
  1198. //
  1199. if ((Entry->LocalService != NULL) &&
  1200. ((Entry->Id.Prefix.Length != oldId.Prefix.Length) ||
  1201. (_wcsnicmp(oldId.Prefix.Buffer,Entry->Id.Prefix.Buffer,len)))) {
  1202. if (!NT_SUCCESS(DfsChangeLvolInfoEntryPath(&Entry->Id.Uid,&Entry->Id.Prefix))) {
  1203. DebugTrace(0, Dbg,
  1204. "Failed to modify registry info for %wZ\n",
  1205. &oldId.Prefix);
  1206. }
  1207. }
  1208. //
  1209. // Everything looks good so its safe to unload the old Id.
  1210. //
  1211. PktEntryIdDestroy(&oldId, FALSE);
  1212. } else {
  1213. //
  1214. // We were unable to make the new prefix entry, so we
  1215. // attempt to back out and put things back the way
  1216. // they were.
  1217. //
  1218. status = DFS_STATUS_ENTRY_EXISTS;
  1219. PktpEntryIdMove(EntryId, &Entry->Id);
  1220. PktpEntryIdMove(&Entry->Id, &oldId);
  1221. status = DfsInsertInPrefixTable(&Pkt->PrefixTable,
  1222. &Entry->Id.Prefix,
  1223. &Entry->PrefixTableEntry);
  1224. if( !NT_SUCCESS( status ) ) {
  1225. //
  1226. // We can't get things back to where they were. Return
  1227. // the error that DfsInsertInPrefixTable returned to us
  1228. // (probably STATUS_INSUFFICIENT_RESOURCES)
  1229. //
  1230. // Destory the entry since it can't be found.
  1231. //
  1232. PktEntryDestroy(Entry, Pkt, TRUE);
  1233. DebugTrace(-1, Dbg, "PktEntryReassemble: Exit -> %08lx\n", ULongToPtr( status ));
  1234. return status;
  1235. } else {
  1236. DfsInsertUnicodePrefix(&Pkt->ShortPrefixTable,
  1237. &Entry->Id.ShortPrefix,
  1238. &Entry->PrefixTableEntry);
  1239. }
  1240. }
  1241. }
  1242. //
  1243. // Now we work on the entry info
  1244. //
  1245. if (NT_SUCCESS(status) && EntryInfo != 0) {
  1246. //
  1247. // Destroy the existing info structure and move the new
  1248. // one into its place. Note that the active service is
  1249. // Nulled.
  1250. //
  1251. PktEntryInfoDestroy(&Entry->Info, FALSE);
  1252. PktpEntryInfoMove(&Entry->Info, EntryInfo);
  1253. for (i = 0; i < Entry->Info.ServiceCount; i++) {
  1254. Entry->Info.ServiceList[i].pMachEntry->UseCount = 1;
  1255. }
  1256. if (EntryType & PKT_ENTRY_TYPE_REFERRAL_SVC) {
  1257. pService = Entry->Info.ServiceList;
  1258. for (i=0; i<Entry->Info.ServiceCount; i++) {
  1259. pService->Type = pService->Type | DFS_SERVICE_TYPE_REFERRAL;
  1260. pService++;
  1261. }
  1262. }
  1263. Entry->ActiveService = NULL;
  1264. //
  1265. // Now we need to make sure that there is only one copy of the
  1266. // DS_MACHINE structures for each of the above services that we added.
  1267. //
  1268. if (!(EntryType & PKT_ENTRY_TYPE_NONCAIRO)) {
  1269. status = DfsFixDSMachineStructs(Entry);
  1270. if (!NT_SUCCESS(status)) {
  1271. //
  1272. // We messed up. This means that something is really messed up.
  1273. //
  1274. DebugTrace(0, 1,
  1275. "DFS: DfsFixDSMachineStructs failed for %wZ\n",
  1276. &Entry->Id.Prefix);
  1277. PktpEntryIdMove(EntryId, &Entry->Id);
  1278. if (ARGUMENT_PRESENT(EntryInfo))
  1279. PktpEntryInfoMove(EntryInfo, &Entry->Info);
  1280. return(status);
  1281. }
  1282. }
  1283. }
  1284. if (NT_SUCCESS(status)) {
  1285. Entry->Type |= EntryType;
  1286. //
  1287. // If the new entry type is "local" we adjust all the
  1288. // subordinates to indicate that they are all now
  1289. // local exit points.
  1290. //
  1291. if (Entry->Type & PKT_ENTRY_TYPE_LOCAL) {
  1292. PDFS_PKT_ENTRY subEntry;
  1293. for (subEntry = PktEntryFirstSubordinate(Entry);
  1294. subEntry != NULL;
  1295. subEntry = PktEntryNextSubordinate(Entry, subEntry)) {
  1296. subEntry->Type |= PKT_ENTRY_TYPE_LOCAL_XPOINT;
  1297. }
  1298. }
  1299. //
  1300. // Finally, we update the USN
  1301. //
  1302. Entry->USN++;
  1303. //
  1304. // And turn off the STALE bit
  1305. //
  1306. Entry->Type &= ~PKT_ENTRY_TYPE_STALE;
  1307. DebugTrace(0, Dbg, "Updated USN for %wz", &Entry->Id.Prefix);
  1308. DebugTrace(0, Dbg, " to %d\n", ULongToPtr( Entry->USN ));
  1309. }
  1310. DebugTrace(-1, Dbg, "PktEntryReassemble: Exit -> %08lx\n", ULongToPtr( status ));
  1311. return status;
  1312. }
  1313. //+-------------------------------------------------------------------------
  1314. //
  1315. // Function: PktEntryDestroy, public
  1316. //
  1317. // Synopsis: PktEntryDestroy destroys an pkt entry structure, and
  1318. // optionally deallocates the structure itself.
  1319. //
  1320. // Arguments: [Victim] - the entry structure to destroy
  1321. // [Pkt] - pointer to the PKT this entry is in.
  1322. // [DeallocateAll] - if True, indicates that the structure
  1323. // itself is to be deallocated, otherwise, only the
  1324. // service list within the structure is deallocated.
  1325. //
  1326. // Returns: VOID
  1327. //
  1328. // Notes: This should not be called on an entry that has a
  1329. // local service attached, or which is a local exit point.
  1330. //
  1331. //--------------------------------------------------------------------------
  1332. VOID
  1333. PktEntryDestroy(
  1334. IN PDFS_PKT_ENTRY Victim OPTIONAL,
  1335. IN PDFS_PKT Pkt,
  1336. IN BOOLEAN DeallocateAll
  1337. )
  1338. {
  1339. NTSTATUS Status;
  1340. DebugTrace(+1, Dbg, "PktEntryDestroy: Entered\n", 0);
  1341. ASSERT(ARGUMENT_PRESENT(Pkt));
  1342. //
  1343. // Make sure we have a victim...
  1344. //
  1345. if (!ARGUMENT_PRESENT(Victim)) {
  1346. DebugTrace(-1, Dbg, "PktEntryDestroy: Exit -> No Victim\n", 0);
  1347. return;
  1348. }
  1349. //
  1350. // We really don't expect to have a LocalService but then even if we
  1351. // do have one due to running DFSINIT again etc. let us try to handle it.
  1352. //
  1353. if (Victim->LocalService != NULL) {
  1354. UNICODE_STRING a, b;
  1355. RtlInitUnicodeString(&b, L"\\");
  1356. Status = BuildLocalVolPath(&a, Victim->LocalService, &b);
  1357. if (NT_SUCCESS(Status)) {
  1358. PktEntryRemoveLocalService(Pkt, Victim, &a);
  1359. ExFreePool(a.Buffer);
  1360. }
  1361. }
  1362. //
  1363. // Remove the entry from the prefix table and from the PKT.
  1364. //
  1365. DfsRemoveUnicodePrefix(&Pkt->PrefixTable, &(Victim->Id.Prefix));
  1366. DfsRemoveUnicodePrefix(&Pkt->ShortPrefixTable, &(Victim->Id.ShortPrefix));
  1367. PktUnlinkEntry(Pkt, Victim);
  1368. //
  1369. // We clear away all subordinates and parents.
  1370. //
  1371. PktEntryClearSubordinates(Victim);
  1372. if (Victim->Superior)
  1373. PktEntryUnlinkSubordinate(Victim->Superior, Victim);
  1374. //
  1375. // We clear all the children and parent pointers from here.
  1376. //
  1377. PktEntryClearChildren(Victim);
  1378. if (Victim->ClosestDC) {
  1379. PktEntryUnlinkChild(Victim->ClosestDC, Victim);
  1380. };
  1381. //
  1382. // Now destroy the body of the entry (id, and info).
  1383. //
  1384. Victim->ActiveService = NULL;
  1385. PktEntryIdDestroy(&Victim->Id, FALSE);
  1386. PktEntryInfoDestroy(&Victim->Info, FALSE);
  1387. //
  1388. // Deallocate everything if they want us to.
  1389. //
  1390. if (DeallocateAll)
  1391. ExFreePool(Victim);
  1392. DebugTrace(-1, Dbg, "PktEntryDestroy: Exit -> VOID\n", 0);
  1393. }
  1394. //+-------------------------------------------------------------------------
  1395. //
  1396. // Function: PktEntryClearSubordinates, public
  1397. //
  1398. // Synopsis: PktEntryClearSubordinates unlinks all subordinates from
  1399. // this entry.
  1400. //
  1401. // Arguments: [PktEntry] - a pointer to an entry that is to have all its
  1402. // subordinates unlinked.
  1403. //
  1404. // Returns: VOID
  1405. //
  1406. // Notes:
  1407. //
  1408. //--------------------------------------------------------------------------
  1409. VOID
  1410. PktEntryClearSubordinates(
  1411. IN PDFS_PKT_ENTRY PktEntry
  1412. )
  1413. {
  1414. PDFS_PKT_ENTRY subEntry;
  1415. DebugTrace(+1, Dbg, "PktEntryClearSubordinates: Entered\n", 0);
  1416. ASSERT(ARGUMENT_PRESENT(PktEntry));
  1417. subEntry = PktEntryFirstSubordinate(PktEntry);
  1418. while (subEntry) {
  1419. PktEntryUnlinkSubordinate(PktEntry, subEntry);
  1420. subEntry = PktEntryFirstSubordinate(PktEntry);
  1421. }
  1422. DebugTrace(-1, Dbg, "PktEntryClearSubordinates: Exit -> VOID\n", 0)
  1423. }
  1424. //+-------------------------------------------------------------------------
  1425. //
  1426. // Function: PktEntryClearChildren, public
  1427. //
  1428. // Synopsis: PktEntryClearChildren unlinks all children from
  1429. // this entry.
  1430. //
  1431. // Arguments: [PktEntry] - a pointer to an entry that is to have all its
  1432. // children unlinked.
  1433. //
  1434. // Returns: VOID
  1435. //
  1436. // Notes:
  1437. //
  1438. //--------------------------------------------------------------------------
  1439. VOID
  1440. PktEntryClearChildren(
  1441. IN PDFS_PKT_ENTRY PktEntry
  1442. )
  1443. {
  1444. PDFS_PKT_ENTRY subEntry;
  1445. DebugTrace(+1, Dbg, "PktEntryClearChildren: Entered\n", 0);
  1446. ASSERT(ARGUMENT_PRESENT(PktEntry));
  1447. subEntry = PktEntryFirstChild(PktEntry);
  1448. while (subEntry) {
  1449. PktEntryUnlinkAndRelinkChild(PktEntry, subEntry);
  1450. subEntry = PktEntryFirstChild(PktEntry);
  1451. }
  1452. DebugTrace(-1, Dbg, "PktEntryClearChildren: Exit -> VOID\n", 0)
  1453. }
  1454. //+-------------------------------------------------------------------------
  1455. //
  1456. // Function: PktRelationInfoConstruct, public
  1457. //
  1458. // Synopsis: PktRelationInfoConstruct creates a pkt relation info
  1459. // structure for the entry id passed in.
  1460. //
  1461. // Arguments: [RelationInfo] -- a pointer to a relation info structure
  1462. // to be filled.
  1463. // [Pkt] -- pointer to a initialized (and acquired) PKT
  1464. // [PktEntryId] -- pointer to the Id of the entry whose
  1465. // subordinates we will find.
  1466. //
  1467. // Returns: [STATUS_SUCCESS] - all is well.
  1468. // [STATUS_INSUFFICIENT_RESOURCES] - the operation could not
  1469. // get enough memory.
  1470. // [DFS_STATUS_NO_SUCH_ENTRY] - no entry exists with an Id
  1471. // specified by PktEntryId.
  1472. //
  1473. // Notes:
  1474. //
  1475. //--------------------------------------------------------------------------
  1476. NTSTATUS
  1477. PktRelationInfoConstruct(
  1478. IN OUT PDFS_PKT_RELATION_INFO RelationInfo,
  1479. IN PDFS_PKT Pkt,
  1480. IN PDFS_PKT_ENTRY_ID PktEntryId
  1481. )
  1482. {
  1483. NTSTATUS status = STATUS_SUCCESS;
  1484. ULONG subCnt = 0;
  1485. PDFS_PKT_ENTRY entry;
  1486. PDFS_PKT_ENTRY_ID subId = NULL;
  1487. DebugTrace(+1, Dbg, "PktRelationalInfoConstruct: Entered\n", 0);
  1488. ASSERT(ARGUMENT_PRESENT(RelationInfo));
  1489. ASSERT(ARGUMENT_PRESENT(Pkt));
  1490. ASSERT(ARGUMENT_PRESENT(PktEntryId));
  1491. //
  1492. // We need to lookup the entry for which we are getting relation
  1493. // information about.
  1494. //
  1495. entry = PktLookupEntryById(Pkt, PktEntryId);
  1496. if (entry == NULL) {
  1497. DebugTrace(-1, Dbg, "PktRelationalInfoConstruct: Exit -> %08lx\n",
  1498. ULongToPtr( DFS_STATUS_NO_SUCH_ENTRY ));
  1499. return DFS_STATUS_NO_SUCH_ENTRY;
  1500. }
  1501. //
  1502. // Construct the entry part of the Relational information
  1503. //
  1504. status = PktEntryIdConstruct(&RelationInfo->EntryId,
  1505. &entry->Id.Uid,
  1506. &entry->Id.Prefix,
  1507. &entry->Id.ShortPrefix);
  1508. //
  1509. // Now go through and construct all the subordinate stuff.
  1510. //
  1511. if (NT_SUCCESS(status) && entry->SubordinateCount > 0) {
  1512. //
  1513. // Calculate how many subordinates and allocate enough room
  1514. // to hold an array of Ids.
  1515. //
  1516. subCnt = entry->SubordinateCount;
  1517. subId = ExAllocatePoolWithTag(PagedPool, sizeof(DFS_PKT_ENTRY_ID) * subCnt, ' sfD');
  1518. if (subId != NULL) {
  1519. ULONG i;
  1520. PDFS_PKT_ENTRY subEntry;
  1521. //
  1522. // Go through all the subordinates and create copies of their
  1523. // Ids in the Relation Info structure.
  1524. //
  1525. for ((i = 0, subEntry = PktEntryFirstSubordinate(entry));
  1526. (subEntry != NULL) && (i < subCnt);
  1527. (subEntry = PktEntryNextSubordinate(entry, subEntry), i++)) {
  1528. status = PktEntryIdConstruct(&subId[i],
  1529. &subEntry->Id.Uid,
  1530. &subEntry->Id.Prefix,
  1531. &subEntry->Id.ShortPrefix);
  1532. if (!NT_SUCCESS(status)) {
  1533. ULONG j;
  1534. //
  1535. // If we get an error around here we back out all
  1536. // the Ids we've so far created...
  1537. //
  1538. for (j = 0; j < i; j++)
  1539. PktEntryIdDestroy(&subId[j], FALSE);
  1540. break;
  1541. }
  1542. }
  1543. //
  1544. // If sucessful, we assert that the subEntry is null (we've
  1545. // go through the entire list of subordinates), and that the
  1546. // count is the same as we expect. If we weren't successful
  1547. // we need to deallocate the array.
  1548. //
  1549. if (NT_SUCCESS(status)) {
  1550. //
  1551. // If sucess, we need to jump out now.
  1552. // We assert that the subEntry is null (we've gone through
  1553. // the entire list of subordinates), and that the
  1554. // count is the same as we expect.
  1555. //
  1556. ASSERT((subEntry == NULL) && (i == subCnt));
  1557. RelationInfo->SubordinateIdCount = subCnt;
  1558. RelationInfo->SubordinateIdList = subId;
  1559. DebugTrace(-1, Dbg,
  1560. "PktRelationalInfoConstruct: Exit -> %08lx\n", ULongToPtr( status ));
  1561. return status;
  1562. }
  1563. //
  1564. // At this point, we have hit an error. We need to deallocate
  1565. // the array.
  1566. //
  1567. ExFreePool(subId);
  1568. subId = NULL;
  1569. DebugTrace(0, Dbg,
  1570. "PktRelationalInfoConstruct: Error filling in sublist!\n", 0);
  1571. } else {
  1572. status = STATUS_INSUFFICIENT_RESOURCES;
  1573. DebugTrace(0, Dbg,
  1574. "PktRelationalInfoConstruct: Error allocating sublist!\n", 0);
  1575. }
  1576. //
  1577. // If we get here, we failed at allocating the array, or we
  1578. // hit an error filling in the array. In any case we need
  1579. // to destroy the entry Id we made at the top.
  1580. //
  1581. PktEntryIdDestroy(&RelationInfo->EntryId, FALSE);
  1582. subCnt = 0;
  1583. }
  1584. //
  1585. // Fill in the relational info and exit.
  1586. //
  1587. RelationInfo->SubordinateIdCount = subCnt;
  1588. RelationInfo->SubordinateIdList = subId;
  1589. DebugTrace(-1, Dbg, "PktRelationalInfoConstruct: Exit -> %08lx\n", ULongToPtr( status ));
  1590. return status;
  1591. }
  1592. //+-------------------------------------------------------------------------
  1593. //
  1594. // Function: PktRelationInfoDestroy, public
  1595. //
  1596. // Synopsis: PktRelationInfoDestroy destroys a pkt relation info
  1597. // structure.
  1598. //
  1599. // Arguments: [RelationInfo] - a pointer to a relation info structure
  1600. // to be destroyed.
  1601. // [DeallocateAll] - if true, indicates that the info structure
  1602. // itself is to be deallocated, otherwise, the base
  1603. // structure is not deallocated.
  1604. //
  1605. // Returns: VOID
  1606. //
  1607. // Notes:
  1608. //
  1609. //--------------------------------------------------------------------------
  1610. VOID
  1611. PktRelationInfoDestroy(
  1612. IN PDFS_PKT_RELATION_INFO RelationInfo,
  1613. IN BOOLEAN DeallocateAll
  1614. )
  1615. {
  1616. DebugTrace(+1, Dbg, "PktRelationalInfoDestroy: Entered\n", 0);
  1617. ASSERT(ARGUMENT_PRESENT(RelationInfo));
  1618. PktEntryIdDestroy(&RelationInfo->EntryId, FALSE);
  1619. if (RelationInfo->SubordinateIdCount > 0) {
  1620. ULONG i;
  1621. for (i = 0; i < RelationInfo->SubordinateIdCount; i++)
  1622. PktEntryIdDestroy(&RelationInfo->SubordinateIdList[i], FALSE);
  1623. ExFreePool(RelationInfo->SubordinateIdList);
  1624. }
  1625. if (DeallocateAll)
  1626. ExFreePool(RelationInfo);
  1627. DebugTrace(-1, Dbg, "PktRelationalInfoDestroy: Exit -> VOID\n", 0);
  1628. }
  1629. //+-------------------------------------------------------------------------
  1630. //
  1631. // Function: PktRelationInfoValidate, public
  1632. //
  1633. // Synopsis: PktRelationInfoValidate compares a local version of the
  1634. // relation info to a remote version.
  1635. //
  1636. // Arguments: [Local] - a pointer to a local version of relation info.
  1637. // [Remote] - a pointer to a remote version of relation info.
  1638. // [ServiceName] -- used exclusively for logging messages.
  1639. //
  1640. // Returns: [STATUS_SUCCESS] - both version are identical.
  1641. //
  1642. // [DFS_STATUS_RESYNC_INFO] -- If relation info's did not match.
  1643. //
  1644. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory conditions
  1645. //
  1646. // Notes: Note that the priority of error returns is such that no
  1647. // checking is done if the entry point is inconsistent; no
  1648. // exit point checking is done if the remote version has too
  1649. // few exit points; checking for "too-many-xpoints" is not
  1650. // done if a "bad-xpoint" is discovered. "Too-many-xpoints"
  1651. // is returned only if all the xpoints in the local version
  1652. // are verified, and there are additional exit points in the
  1653. // remote version left.
  1654. //
  1655. //--------------------------------------------------------------------------
  1656. NTSTATUS
  1657. PktRelationInfoValidate(
  1658. IN PDFS_PKT_RELATION_INFO Local,
  1659. IN PDFS_PKT_RELATION_INFO Remote,
  1660. IN UNICODE_STRING ServiceName
  1661. )
  1662. {
  1663. NTSTATUS status = STATUS_SUCCESS;
  1664. PUNICODE_STRING lpfx;
  1665. PUNICODE_STRING rpfx;
  1666. ULONG i;
  1667. ULONG *pulExitPtUsed = NULL;
  1668. UNICODE_STRING puStr[3];
  1669. DebugTrace(+1, Dbg, "PktRelationInfoValidate: Entered\n", 0);
  1670. ASSERT(ARGUMENT_PRESENT(Local));
  1671. ASSERT(ARGUMENT_PRESENT(Remote));
  1672. //
  1673. // The GUIDs of this volume have already been matched otherwise we
  1674. // would not be here. So we don't even look at that. We still
  1675. // need to match the prefixes. If the prefixes are different then we
  1676. // need to fix that at this machine.
  1677. //
  1678. lpfx = &Local->EntryId.Prefix;
  1679. rpfx = &Remote->EntryId.Prefix;
  1680. if (RtlCompareUnicodeString(lpfx, rpfx, TRUE)) {
  1681. //
  1682. // The Prefixes are different we need to fix this now. But first, let
  1683. // us log this event.
  1684. //
  1685. DebugTrace(0, Dbg, "PktRelationInfoValidate: Prefixes did not match\n",
  1686. 0);
  1687. DebugTrace(0, Dbg, "Fixed Prefix %ws\n", rpfx->Buffer);
  1688. DebugTrace(0, Dbg, "To be %ws\n", lpfx->Buffer);
  1689. puStr[0] = Local->EntryId.Prefix;
  1690. puStr[1] = Remote->EntryId.Prefix;
  1691. puStr[2] = ServiceName;
  1692. LogWriteMessage(PREFIX_MISMATCH, status, 3, puStr);
  1693. status = DFS_STATUS_RESYNC_INFO;
  1694. }
  1695. if (Local->SubordinateIdCount != 0) {
  1696. pulExitPtUsed = ExAllocatePoolWithTag(
  1697. PagedPool,
  1698. sizeof(ULONG)*(Local->SubordinateIdCount),
  1699. ' sfD');
  1700. if (pulExitPtUsed == NULL) {
  1701. status = STATUS_NO_MEMORY;
  1702. goto exit_with_status;
  1703. }
  1704. RtlZeroMemory(pulExitPtUsed, sizeof(ULONG)*(Local->SubordinateIdCount));
  1705. }
  1706. //
  1707. // We step through each exit point in the remote knowledge and make sure
  1708. // that is right.
  1709. //
  1710. puStr[1] = ServiceName; // We set this once and for all.
  1711. for (i = 0; i < Remote->SubordinateIdCount; i++) {
  1712. ULONG j;
  1713. GUID *lguid, *rguid;
  1714. BOOLEAN bExitPtFound = FALSE;
  1715. rpfx = &Remote->SubordinateIdList[i].Prefix;
  1716. rguid = &Remote->SubordinateIdList[i].Uid;
  1717. for (j = 0; j < Local->SubordinateIdCount; j++) {
  1718. lpfx = &Local->SubordinateIdList[j].Prefix;
  1719. lguid = &Local->SubordinateIdList[j].Uid;
  1720. if (!RtlCompareUnicodeString(lpfx, rpfx, TRUE) &&
  1721. GuidEqual(lguid, rguid)) {
  1722. ASSERT(pulExitPtUsed[j] == FALSE);
  1723. if (pulExitPtUsed[j] == TRUE) {
  1724. status = DFS_STATUS_RESYNC_INFO;
  1725. DebugTrace(0, Dbg, "Found Duplicate ExitPts %ws\n",
  1726. rpfx->Buffer);
  1727. }
  1728. else
  1729. bExitPtFound = TRUE;
  1730. pulExitPtUsed[j] = TRUE;
  1731. break;
  1732. }
  1733. }
  1734. if (bExitPtFound == FALSE) {
  1735. //
  1736. // In this case we have an exit point which the DC does not
  1737. // recognise. We need to log this fact here.
  1738. //
  1739. puStr[0] = Remote->SubordinateIdList[i].Prefix;
  1740. LogWriteMessage(EXTRA_EXIT_POINT, status, 2, puStr);
  1741. status = DFS_STATUS_RESYNC_INFO;
  1742. }
  1743. }
  1744. //
  1745. // Now that we are done stepping through the list of Remote ExitPts and
  1746. // either validating them or deleting them from the remote server we now
  1747. // need to step through the local Info and see if we have any extra exit
  1748. // points which the remote server needs to be informed about. This is
  1749. // where the pulExitPtUsed array comes in.
  1750. //
  1751. for (i=0; i < Local->SubordinateIdCount; i++) {
  1752. if (pulExitPtUsed[i] == FALSE) {
  1753. status = DFS_STATUS_RESYNC_INFO;
  1754. puStr[1] = Local->SubordinateIdList[i].Prefix;
  1755. LogWriteMessage(MISSING_EXIT_POINT, status, 2, puStr);
  1756. }
  1757. }
  1758. if (pulExitPtUsed != NULL) {
  1759. ExFreePool(pulExitPtUsed);
  1760. }
  1761. exit_with_status:
  1762. DebugTrace(-1, Dbg, "PktRelationInfoValidate: Exit -> %08lx\n", ULongToPtr( status ) );
  1763. return status;
  1764. }
  1765. //+---------------------------------------------------------------
  1766. //
  1767. // Function: PktGetService
  1768. //
  1769. // Synopsis: This function retrieves a specific service entry given a
  1770. // PKT entry and the service name required.
  1771. //
  1772. // Arguments: [Entry] -- The Pkt Entry that has to be scanned for the
  1773. // requested service.
  1774. // [ServiceName] -- Look for this service entry.
  1775. //
  1776. // Returns: NULL - If not found else a valid pointer to Service struct.
  1777. //
  1778. //----------------------------------------------------------------
  1779. PDFS_SERVICE
  1780. PktGetService(PDFS_PKT_ENTRY entry, PUNICODE_STRING pustrServiceName)
  1781. {
  1782. PDFS_SERVICE pService = NULL;
  1783. ULONG i;
  1784. ASSERT(ARGUMENT_PRESENT(entry));
  1785. ASSERT(ARGUMENT_PRESENT(pustrServiceName));
  1786. pService = entry->Info.ServiceList;
  1787. for (i=0; i < entry->Info.ServiceCount; i++) {
  1788. if (!RtlCompareUnicodeString(pustrServiceName, &pService->Name, TRUE)) {
  1789. //
  1790. // We found the required service entry. We can return this right
  1791. // away.
  1792. //
  1793. return(pService);
  1794. }
  1795. pService = pService + 1;
  1796. }
  1797. //
  1798. // We did not find any match. So we return back a NULL.
  1799. //
  1800. return(NULL);
  1801. }
  1802. //+----------------------------------------------------------------------------
  1803. //
  1804. // Function: DfsNetInfoToConfigInfo
  1805. //
  1806. // Synopsis: Converts a LPNET_DFS_ENTRY_ID_CONTAINER to a
  1807. // LPDFS_LOCAL_VOLUME_CONFIG
  1808. //
  1809. // Arguments: [EntryType] -- Type of local volume (see PKT_ENTRY_TYPE_XXX)
  1810. // [ServiceType] -- Type of local service (DFS_SERVICE_TYPE_XXX)
  1811. // [pwszStgId] -- Storage Id for local volume.
  1812. // [pwszShareName] -- Lanman share name of local volume.
  1813. // [pUid] -- Id of local volume.
  1814. // [pwszEntryPrefix] -- Entry path of local volume.
  1815. // [NetInfo] -- Pointer to LPNET_DFS_ENTRY_ID_CONTAINTER
  1816. //
  1817. // Notes: The returned pointer to DFS_LOCAL_VOLUME_CONFIG should be
  1818. // freed using LocalVolumeConfigInfoDestroy( x, TRUE ).
  1819. //
  1820. // If you change this routine, carefully update the cleanup
  1821. // code in case of failure!
  1822. //
  1823. // Returns: Pointer to LPDFS_LOCAL_VOLUME_CONFIG if successful, NULL
  1824. // otherwise.
  1825. //
  1826. //-----------------------------------------------------------------------------
  1827. PDFS_LOCAL_VOLUME_CONFIG
  1828. DfsNetInfoToConfigInfo(
  1829. ULONG EntryType,
  1830. ULONG ServiceType,
  1831. LPWSTR pwszStgId,
  1832. LPWSTR pwszShareName,
  1833. GUID *pUid,
  1834. LPWSTR pwszEntryPrefix,
  1835. LPWSTR pwszShortPrefix,
  1836. LPNET_DFS_ENTRY_ID_CONTAINER NetInfo)
  1837. {
  1838. PDFS_LOCAL_VOLUME_CONFIG configInfo;
  1839. ULONG i = 0;
  1840. NTSTATUS status;
  1841. configInfo = (PDFS_LOCAL_VOLUME_CONFIG) ExAllocatePoolWithTag(
  1842. PagedPool,
  1843. sizeof(DFS_LOCAL_VOLUME_CONFIG) +
  1844. NetInfo->Count * sizeof(DFS_PKT_ENTRY_ID),
  1845. ' sfD' );
  1846. if (configInfo != NULL) {
  1847. RtlZeroMemory( configInfo, sizeof(configInfo) );
  1848. configInfo->EntryType = EntryType;
  1849. configInfo->ServiceType = ServiceType;
  1850. DFS_DUPLICATE_STRING( configInfo->StgId, pwszStgId, status );
  1851. configInfo->RelationInfo.EntryId.Uid = *pUid;
  1852. if (NT_SUCCESS(status)) {
  1853. DFS_DUPLICATE_STRING( configInfo->Share, pwszShareName, status );
  1854. }
  1855. if (NT_SUCCESS(status)) {
  1856. DFS_DUPLICATE_STRING(
  1857. configInfo->RelationInfo.EntryId.Prefix,
  1858. pwszEntryPrefix,
  1859. status );
  1860. }
  1861. if (NT_SUCCESS(status) && pwszShortPrefix != NULL) {
  1862. DFS_DUPLICATE_STRING(
  1863. configInfo->RelationInfo.EntryId.ShortPrefix,
  1864. pwszShortPrefix,
  1865. status );
  1866. }
  1867. if (NT_SUCCESS(status)) {
  1868. configInfo->RelationInfo.SubordinateIdCount = NetInfo->Count;
  1869. configInfo->RelationInfo.SubordinateIdList =
  1870. (PDFS_PKT_ENTRY_ID) (configInfo + 1);
  1871. for (i = 0; (i < NetInfo->Count) && NT_SUCCESS(status); i++) {
  1872. configInfo->RelationInfo.SubordinateIdList[i].Uid =
  1873. NetInfo->Buffer[i].Uid;
  1874. DFS_DUPLICATE_STRING(
  1875. configInfo->RelationInfo.SubordinateIdList[i].Prefix,
  1876. NetInfo->Buffer[i].Prefix,
  1877. status);
  1878. }
  1879. }
  1880. } else {
  1881. status = STATUS_INSUFFICIENT_RESOURCES;
  1882. }
  1883. if (!NT_SUCCESS(status)) {
  1884. //
  1885. // Cleanup whatever we allocated. The cleanup routine works as
  1886. // follows:
  1887. //
  1888. // 1. allocation of configInfo failed - Nothing to do
  1889. //
  1890. // 2. allocation of configInfo->StgId failed or
  1891. // allocation of configInfo->RelationInfo.EntryId failed - Set
  1892. // SubordinateIdCount to i (initialized to 0!) and call
  1893. // LocalVolumeConfigInfoDestroy.
  1894. //
  1895. // 3. allocation of a configInfo->RelationInfo Id failed - Set
  1896. // SubordinateIdCount to i and call
  1897. // LocalVolumeConfigInfoDestroy. Note that the i'th Id
  1898. // will have its Prefix.Buffer set to NULL!
  1899. //
  1900. if (configInfo != NULL) {
  1901. configInfo->RelationInfo.SubordinateIdCount = i;
  1902. LocalVolumeConfigInfoDestroy( configInfo, TRUE );
  1903. configInfo = NULL;
  1904. }
  1905. }
  1906. return( configInfo );
  1907. }
  1908. //+-------------------------------------------------------------------------
  1909. //
  1910. // Function: LocalVolumeConfigInfoDestroy, public
  1911. //
  1912. // Synopsis: LocalVolumeConfigInfoDestroy deallocates a
  1913. // DFS_LOCAL_VOLUME_CONFIG structure.
  1914. //
  1915. // Arguments: [Victim] -- a pointer the DFS_LOCAL_VOLUME_CONFIG structure to
  1916. // free.
  1917. // [DeallocateAll] -- if true, the memory for the base structure
  1918. // is freed as well.
  1919. //
  1920. // Returns: VOID
  1921. //
  1922. //--------------------------------------------------------------------------
  1923. VOID
  1924. LocalVolumeConfigInfoDestroy(
  1925. IN PDFS_LOCAL_VOLUME_CONFIG Victim OPTIONAL,
  1926. IN BOOLEAN DeallocateAll
  1927. )
  1928. {
  1929. DebugTrace(+1, Dbg, "LocalVolumeConfigInfoDestroy: Entered\n", 0);
  1930. if (!ARGUMENT_PRESENT(Victim)) {
  1931. DebugTrace(-1, Dbg, "LocalVolumeConfigInfoDestroy: Exit -> No Victim\n",0);
  1932. return;
  1933. }
  1934. //
  1935. // Get a hold of the relation info part and deallocate it.
  1936. //
  1937. PktRelationInfoDestroy(&Victim->RelationInfo, FALSE);
  1938. //
  1939. // If a StgId is specified, free it.
  1940. //
  1941. if (Victim->StgId.Buffer != NULL) {
  1942. ExFreePool(Victim->StgId.Buffer);
  1943. }
  1944. //
  1945. // If a ShareName is specified, free it.
  1946. //
  1947. if (Victim->Share.Buffer != NULL) {
  1948. ExFreePool(Victim->Share.Buffer);
  1949. }
  1950. //
  1951. // If specified, free the base structure as well.
  1952. //
  1953. if (DeallocateAll)
  1954. ExFreePool(Victim);
  1955. DebugTrace(-1, Dbg, "LocalVolumeConfigInfoDestroy: Exit -> VOID\n",0);
  1956. }