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.

2149 lines
65 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: PKT.C
  6. //
  7. // Contents: This module implements the Partition Knowledge Table routines
  8. // for the Dfs driver.
  9. //
  10. // Functions: PktInitialize -
  11. // PktInitializeLocalPartition -
  12. // RemoveLastComponent -
  13. // PktCreateEntry -
  14. // PktCreateSubordinateEntry -
  15. // PktLookupEntryById -
  16. // PktEntryModifyPrefix -
  17. // PktLookupEntryByPrefix -
  18. // PktLookupEntryByUid -
  19. // PktLookupReferralEntry -
  20. // PktSetRelationInfo -
  21. // PktTrimSubordinates -
  22. // PktpAddEntry -
  23. //
  24. // History: 5 May 1992 PeterCo Created.
  25. //
  26. //-----------------------------------------------------------------------------
  27. #include "dfsprocs.h"
  28. #include <netevent.h>
  29. #include <smbtypes.h>
  30. #include <smbtrans.h>
  31. #include "attach.h"
  32. #include "log.h"
  33. #include "know.h"
  34. #define Dbg (DEBUG_TRACE_PKT)
  35. //
  36. // Local procedure prototypes
  37. //
  38. NTSTATUS
  39. PktInitializeLocalPartition(
  40. IN PDFS_PKT Pkt,
  41. IN PUNICODE_STRING LocalVolumeName,
  42. IN PDFS_LOCAL_VOLUME_CONFIG ConfigInfo);
  43. NTSTATUS
  44. PktpAddEntry (
  45. IN PDFS_PKT Pkt,
  46. IN PUNICODE_STRING Prefix,
  47. IN PRESP_GET_DFS_REFERRAL ReferralBuffer,
  48. IN ULONG CreateDisposition,
  49. OUT PDFS_PKT_ENTRY *ppPktEntry);
  50. VOID
  51. PktShuffleServiceList(
  52. PDFS_PKT_ENTRY_INFO pInfo);
  53. VOID
  54. PktShuffleGroup(
  55. PDFS_PKT_ENTRY_INFO pInfo,
  56. ULONG nStart,
  57. ULONG nEnd);
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text( INIT, PktInitialize )
  60. #pragma alloc_text( PAGE, PktUninitialize )
  61. #pragma alloc_text( PAGE, PktInitializeLocalPartition )
  62. #pragma alloc_text( PAGE, RemoveLastComponent )
  63. #pragma alloc_text( PAGE, PktCreateEntry )
  64. #pragma alloc_text( PAGE, PktCreateSubordinateEntry )
  65. #pragma alloc_text( PAGE, PktLookupEntryById )
  66. #pragma alloc_text( PAGE, PktEntryModifyPrefix )
  67. #pragma alloc_text( PAGE, PktLookupEntryByPrefix )
  68. #pragma alloc_text( PAGE, PktLookupEntryByUid )
  69. #pragma alloc_text( PAGE, PktSetRelationInfo )
  70. #pragma alloc_text( PAGE, PktTrimSubordinates )
  71. #pragma alloc_text( PAGE, PktpAddEntry )
  72. #endif // ALLOC_PRAGMA
  73. //
  74. // declare the global null guid
  75. //
  76. GUID _TheNullGuid;
  77. //+-------------------------------------------------------------------------
  78. //
  79. // Function: PktInitialize, public
  80. //
  81. // Synopsis: PktInitialize initializes the partition knowledge table.
  82. //
  83. // Arguments: [Pkt] - pointer to an uninitialized PKT
  84. //
  85. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  86. //
  87. // Notes: This routine is called only at driver init time.
  88. //
  89. //--------------------------------------------------------------------------
  90. NTSTATUS
  91. PktInitialize(
  92. IN PDFS_PKT Pkt
  93. ) {
  94. DebugTrace(+1, Dbg, "PktInitialize: Entered\n", 0);
  95. //
  96. // initialize the NULL GUID.
  97. //
  98. RtlZeroMemory(&_TheNullGuid, sizeof(GUID));
  99. //
  100. // Always zero the pkt first
  101. //
  102. RtlZeroMemory(Pkt, sizeof(DFS_PKT));
  103. //
  104. // do basic initialization
  105. //
  106. Pkt->NodeTypeCode = DFS_NTC_PKT;
  107. Pkt->NodeByteSize = sizeof(DFS_PKT);
  108. ExInitializeResourceLite(&Pkt->Resource);
  109. InitializeListHead(&Pkt->EntryList);
  110. DfsInitializeUnicodePrefix(&Pkt->LocalVolTable);
  111. DfsInitializeUnicodePrefix(&Pkt->PrefixTable);
  112. DfsInitializeUnicodePrefix(&Pkt->ShortPrefixTable);
  113. RtlInitializeUnicodePrefix(&Pkt->DSMachineTable);
  114. //
  115. // We don't know anything about our domain yet, so we leave
  116. // it NULL. This will get initialized later to the right value!
  117. //
  118. Pkt->DomainPktEntry = NULL;
  119. DebugTrace(-1, Dbg, "PktInitialize: Exit -> VOID\n", 0 );
  120. return STATUS_SUCCESS;
  121. }
  122. VOID
  123. PktUninitialize(
  124. IN PDFS_PKT Pkt)
  125. {
  126. DfsFreePrefixTable(&Pkt->LocalVolTable);
  127. DfsFreePrefixTable(&Pkt->PrefixTable);
  128. DfsFreePrefixTable(&Pkt->ShortPrefixTable);
  129. ExDeleteResourceLite(&Pkt->Resource);
  130. }
  131. //+-------------------------------------------------------------------------
  132. //
  133. // Function: PktInitializeLocalPartition, public
  134. //
  135. // Synopsis: PktInitializeLocalPartition initializes the Pkt entry
  136. // and its subordinates specified by the ConfigInfo structure
  137. // passed in.
  138. //
  139. // Arguments: [Pkt] - a pointer to an (exclusively) acquired Pkt.
  140. // [LocalVolumeName] - the name of the local volume.
  141. // [ConfigInfo] - the parameters specifying the local
  142. // entry and all its exit points.
  143. //
  144. // Returns: [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory conditions
  145. //
  146. // [DFS_STATUS_LOCAL_ENTRY] - creation of the entry would
  147. // require the invalidation of a local entry or exit point.
  148. //
  149. // [STATUS_INVALID_PARAMETER] - the Id specified for the
  150. // new entry is invalid.
  151. //
  152. // Note: The ConfigInfo argument is stripped of all its Ids as a
  153. // by-product of this operation.
  154. //
  155. // The Pkt needs to be acquired exclusively before calling this.
  156. //
  157. //--------------------------------------------------------------------------
  158. NTSTATUS
  159. PktInitializeLocalPartition(
  160. IN PDFS_PKT Pkt,
  161. IN PUNICODE_STRING LocalVolumeName,
  162. IN PDFS_LOCAL_VOLUME_CONFIG ConfigInfo
  163. )
  164. {
  165. NTSTATUS status;
  166. PDFS_PKT_ENTRY entry;
  167. DFS_PKT_ENTRY_ID entryId;
  168. PDFS_SERVICE localService;
  169. PDFS_PKT_RELATION_INFO relationInfo;
  170. PDFS_LOCAL_VOL_ENTRY localVolEntry;
  171. UNICODE_STRING LocalVolumeRelativeName;
  172. DebugTrace(+1, Dbg, "PktInitializeLocalPartition: Entered\n", 0);
  173. ASSERT(ARGUMENT_PRESENT(Pkt) &&
  174. ARGUMENT_PRESENT(LocalVolumeName) &&
  175. ARGUMENT_PRESENT(ConfigInfo));
  176. //
  177. // Now we attempt to create a local service
  178. // structure for this Entry...so allocate some memory.
  179. //
  180. localService = (PDFS_SERVICE) ExAllocatePoolWithTag(PagedPool, sizeof(DFS_SERVICE), ' sfD');
  181. if (localService == NULL) {
  182. DebugTrace(0, Dbg,
  183. "PktInitializeLocalPartition: Cannot allocate local service!\n",0);
  184. DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
  185. ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) );
  186. return STATUS_INSUFFICIENT_RESOURCES;
  187. }
  188. localVolEntry = (PDFS_LOCAL_VOL_ENTRY) ExAllocatePoolWithTag(
  189. PagedPool,
  190. sizeof(DFS_LOCAL_VOL_ENTRY),
  191. ' sfD');
  192. if (localVolEntry == NULL) {
  193. DebugTrace(0, Dbg,
  194. "PktInitializeLocalPartition: Cannot allocate local vol entry!\n",0);
  195. DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
  196. ULongToPtr( STATUS_INSUFFICIENT_RESOURCES ) );
  197. ExFreePool(localService);
  198. return STATUS_INSUFFICIENT_RESOURCES;
  199. }
  200. //
  201. // Construct the local service. We need to first compute the
  202. // break point between the volume device object name, and the
  203. // local entry point within the volume, which will become the
  204. // service's "address".
  205. //
  206. if (!(ConfigInfo->EntryType & PKT_ENTRY_TYPE_LEAFONLY)) {
  207. status = DfsGetAttachName(
  208. LocalVolumeName,
  209. &LocalVolumeRelativeName);
  210. } else {
  211. LocalVolumeRelativeName = *LocalVolumeName;
  212. status = STATUS_SUCCESS;
  213. }
  214. if (NT_SUCCESS(status)) {
  215. status = PktServiceConstruct(
  216. localService,
  217. ConfigInfo->ServiceType | DFS_SERVICE_TYPE_LOCAL,
  218. PROV_STRIP_PREFIX,
  219. DFS_SERVICE_STATUS_VERIFIED,
  220. PROV_ID_LOCAL_FS,
  221. NULL,
  222. &LocalVolumeRelativeName
  223. );
  224. }
  225. if (!NT_SUCCESS(status)) {
  226. DebugTrace(0, Dbg,
  227. "PktInitializeLocalPartition: Cannot construct local service!\n",0);
  228. DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
  229. ULongToPtr( status ) );
  230. ExFreePool(localService);
  231. ExFreePool(localVolEntry);
  232. return status;
  233. }
  234. //
  235. // Now we attempt to create/update the entry point entry.
  236. //
  237. //
  238. // Remember! the create strips the entry Id off! so we need to
  239. // duplicate the entry id info off the relation info structure
  240. // so that we can pass it into PktCreateEntry...
  241. //
  242. relationInfo = &ConfigInfo->RelationInfo;
  243. status = PktEntryIdConstruct(&entryId,
  244. &relationInfo->EntryId.Uid,
  245. &relationInfo->EntryId.Prefix,
  246. &relationInfo->EntryId.ShortPrefix);
  247. DebugTrace(0, Dbg, "PktEntryIdConstruct returned 0x%x\n", ULongToPtr( status ));
  248. if (NT_SUCCESS(status)) {
  249. status = PktCreateEntry(
  250. Pkt,
  251. ConfigInfo->EntryType | PKT_ENTRY_TYPE_LOCAL | PKT_ENTRY_TYPE_PERMANENT,
  252. &entryId,
  253. NULL,
  254. PKT_ENTRY_SUPERSEDE,
  255. &entry);
  256. DebugTrace(0, Dbg, "PktCreateEntry returned 0x%x\n", ULongToPtr( status ));
  257. }
  258. if (NT_SUCCESS(status)) {
  259. PDFS_PKT_ENTRY subEntry;
  260. PDFS_PKT_ENTRY_ID subId;
  261. PDFS_PKT_ENTRY_ID lastSubId;
  262. //
  263. // We trim the subordinates off the entry that are not
  264. // included in the relation info.
  265. //
  266. PktTrimSubordinates(Pkt, entry, relationInfo);
  267. //
  268. // Go through and create/update all the subordinates.
  269. //
  270. subId = relationInfo->SubordinateIdList;
  271. lastSubId = &subId[ relationInfo->SubordinateIdCount ];
  272. for (subId = relationInfo->SubordinateIdList; subId < lastSubId; subId++) {
  273. PktCreateSubordinateEntry(
  274. Pkt,
  275. entry,
  276. PKT_ENTRY_TYPE_LOCAL_XPOINT | PKT_ENTRY_TYPE_PERMANENT,
  277. subId,
  278. NULL,
  279. PKT_ENTRY_SUPERSEDE,
  280. &subEntry);
  281. DebugTrace(0, Dbg, "PktCreateSubordinateEntry returned 0x%x\n", ULongToPtr( status ));
  282. }
  283. if (NT_SUCCESS(status)) {
  284. //
  285. // We set the local service of this entry...
  286. //
  287. status = PktEntrySetLocalService(
  288. Pkt,
  289. entry,
  290. localService,
  291. localVolEntry,
  292. LocalVolumeName,
  293. &ConfigInfo->Share);
  294. DebugTrace(0, Dbg, "PktEntrySetLocalService returned 0x%x\n", ULongToPtr( status ));
  295. }
  296. if (NT_SUCCESS(status) &&
  297. !(entry->Type & PKT_ENTRY_TYPE_LEAFONLY)) {
  298. status = DfsAttachVolume(
  299. LocalVolumeName,
  300. &localService->pProvider);
  301. if (!NT_SUCCESS(status)) {
  302. PktEntryUnsetLocalService( Pkt, entry, LocalVolumeName );
  303. ExFreePool(localVolEntry);
  304. }
  305. }
  306. if (!NT_SUCCESS(status)) {
  307. //
  308. // We take somewhat draconian measures here. We could
  309. // not complete the initialization so we basically
  310. // invalidate everything to do with this entry.
  311. //
  312. while ((subEntry = PktEntryFirstSubordinate(entry)) != NULL) {
  313. PktEntryDestroy(subEntry, Pkt, (BOOLEAN)TRUE);
  314. }
  315. PktEntryDestroy(entry, Pkt, (BOOLEAN)TRUE);
  316. //
  317. // We need to destroy this as well since it will not get destroyed
  318. // as part of above.
  319. //
  320. PktServiceDestroy(localService, (BOOLEAN)TRUE);
  321. DebugTrace(0, Dbg,
  322. "PktInitializeLocalPartition: Error creating subordinate!\n",0);
  323. }
  324. } else {
  325. //
  326. // we could not create the entry so we need to deallocate the
  327. // service we allocated.
  328. //
  329. PktEntryIdDestroy(&entryId, FALSE);
  330. PktServiceDestroy(localService, (BOOLEAN)TRUE);
  331. ExFreePool(localVolEntry);
  332. DebugTrace(0, Dbg,
  333. "PktInitializeLocalPartition: Cannot create entry!\n", 0);
  334. }
  335. if (NT_SUCCESS(status)) {
  336. if (localService->Type & DFS_SERVICE_TYPE_OFFLINE) {
  337. localService->ProviderId = localService->pProvider->eProviderId;
  338. status = DfspTakeVolumeOffline( Pkt, entry );
  339. }
  340. }
  341. DebugTrace(-1, Dbg, "PktInitializeLocalPartition: Exit -> %08lx\n",
  342. ULongToPtr( status ) );
  343. return status;
  344. }
  345. //+-------------------------------------------------------------------------
  346. //
  347. // Function: RemoveLastComponent, public
  348. //
  349. // Synopsis: Removes the last component of the string passed.
  350. //
  351. // Arguments: [Prefix] -- The prefix whose last component is to be returned.
  352. // [newPrefix] -- The new Prefix with the last component removed.
  353. //
  354. // Returns: NTSTATUS - STATUS_SUCCESS if no error.
  355. //
  356. // Notes: On return, the newPrefix points to the same memory buffer
  357. // as Prefix.
  358. //
  359. //--------------------------------------------------------------------------
  360. void
  361. RemoveLastComponent(
  362. PUNICODE_STRING Prefix,
  363. PUNICODE_STRING newPrefix
  364. )
  365. {
  366. PWCHAR pwch;
  367. USHORT i=0;
  368. *newPrefix = *Prefix;
  369. pwch = newPrefix->Buffer;
  370. pwch += (Prefix->Length/sizeof(WCHAR)) - 1;
  371. while ((*pwch != UNICODE_PATH_SEP) && (pwch != newPrefix->Buffer)) {
  372. i += sizeof(WCHAR);
  373. pwch--;
  374. }
  375. newPrefix->Length = newPrefix->Length - i;
  376. }
  377. //+-------------------------------------------------------------------------
  378. //
  379. // Function: PktCreateEntry, public
  380. //
  381. // Synopsis: PktCreateEntry creates a new partition table entry or
  382. // updates an existing one. The PKT must be acquired
  383. // exclusively for this operation.
  384. //
  385. // Arguments: [Pkt] - pointer to an initialized (and exclusively acquired) PKT
  386. // [PktEntryType] - the type of entry to create/update.
  387. // [PktEntryId] - pointer to the Id of the entry to create
  388. // [PktEntryInfo] - pointer to the guts of the entry
  389. // [CreateDisposition] - specifies whether to overwrite if
  390. // an entry already exists, etc.
  391. // [ppPktEntry] - the new entry is placed here.
  392. //
  393. // Returns: [STATUS_SUCCESS] - if all is well.
  394. //
  395. // [DFS_STATUS_NO_SUCH_ENTRY] - the create disposition was
  396. // set to PKT_REPLACE_ENTRY and no entry of the specified
  397. // Id exists to replace.
  398. //
  399. // [DFS_STATUS_ENTRY_EXISTS] - a create disposition of
  400. // PKT_CREATE_ENTRY was specified and an entry of the
  401. // specified Id already exists.
  402. //
  403. // [DFS_STATUS_LOCAL_ENTRY] - creation of the entry would
  404. // required the invalidation of a local entry or exit point.
  405. //
  406. // [STATUS_INVALID_PARAMETER] - the Id specified for the
  407. // new entry is invalid.
  408. //
  409. // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
  410. // available to complete the operation.
  411. //
  412. // Notes: The PktEntryId and PktEntryInfo structures are MOVED (not
  413. // COPIED) to the new entry. The memory used for UNICODE_STRINGS
  414. // and DFS_SERVICE arrays is used by the new entry. The
  415. // associated fields in the PktEntryId and PktEntryInfo
  416. // structures passed as arguments are Zero'd to indicate that
  417. // the memory has been "deallocated" from these strutures and
  418. // reallocated to the newly created PktEntry. Note that this
  419. // routine does not deallocate the PktEntryId structure or
  420. // the PktEntryInfo structure itself. On successful return from
  421. // this function, the PktEntryId structure will be modified
  422. // to have a NULL Prefix entry, and the PktEntryInfo structure
  423. // will be modified to have zero services and a null ServiceList
  424. // entry.
  425. //
  426. //--------------------------------------------------------------------------
  427. NTSTATUS
  428. PktCreateEntry(
  429. IN PDFS_PKT Pkt,
  430. IN ULONG PktEntryType,
  431. IN PDFS_PKT_ENTRY_ID PktEntryId,
  432. IN PDFS_PKT_ENTRY_INFO PktEntryInfo OPTIONAL,
  433. IN ULONG CreateDisposition,
  434. OUT PDFS_PKT_ENTRY *ppPktEntry
  435. )
  436. {
  437. NTSTATUS status = STATUS_SUCCESS;
  438. PDFS_PKT_ENTRY pfxMatchEntry = NULL;
  439. PDFS_PKT_ENTRY uidMatchEntry = NULL;
  440. PDFS_PKT_ENTRY entryToUpdate = NULL;
  441. PDFS_PKT_ENTRY entryToInvalidate = NULL;
  442. PDFS_PKT_ENTRY SupEntry = NULL;
  443. UNICODE_STRING remainingPath = {0, 0, NULL};
  444. UNICODE_STRING newRemainingPath;
  445. ASSERT(ARGUMENT_PRESENT(Pkt) &&
  446. ARGUMENT_PRESENT(PktEntryId) &&
  447. ARGUMENT_PRESENT(ppPktEntry));
  448. DebugTrace(+1, Dbg, "PktCreateEntry: Entered\n", 0);
  449. //
  450. // We're pessimistic at first...
  451. //
  452. *ppPktEntry = NULL;
  453. //
  454. // See if there exists an entry with this prefix. The prefix
  455. // must match exactly (i.e. No remaining path).
  456. //
  457. pfxMatchEntry = PktLookupEntryByPrefix(Pkt,
  458. &PktEntryId->Prefix,
  459. &remainingPath);
  460. if ((remainingPath.Length > 0) ||
  461. (PktEntryId->Prefix.Length == 0)) {
  462. SupEntry = pfxMatchEntry;
  463. pfxMatchEntry = NULL;
  464. } else {
  465. UNICODE_STRING newPrefix;
  466. RemoveLastComponent(&PktEntryId->Prefix, &newPrefix);
  467. SupEntry = PktLookupEntryByPrefix(Pkt,
  468. &newPrefix,
  469. &newRemainingPath);
  470. }
  471. //
  472. // Now search for an entry that has the same Uid.
  473. //
  474. uidMatchEntry = PktLookupEntryByUid(Pkt, &PktEntryId->Uid);
  475. //
  476. // Now we must determine if during this create, we are going to be
  477. // updating or invalidating any existing entries. If an existing
  478. // entry is found that has the same Uid as the one we are trying to
  479. // create, the entry becomes a target for "updating". If the Uid
  480. // passed in is NULL, then we check to see if an entry exists that
  481. // has a NULL Uid AND a Prefix that matches. If this is the case,
  482. // that entry becomes the target for "updating".
  483. //
  484. // To determine if there is an entry to invalidate, we look for an
  485. // entry with the same Prefix as the one we are trying to create, BUT,
  486. // which has a different Uid. If we detect such a situation, we
  487. // we make the entry with the same Prefix the target for invalidation
  488. // (we do not allow two entries with the same Prefix, and we assume
  489. // that the new entry takes precedence).
  490. //
  491. if (uidMatchEntry != NULL) {
  492. entryToUpdate = uidMatchEntry;
  493. if (pfxMatchEntry != uidMatchEntry)
  494. entryToInvalidate = pfxMatchEntry;
  495. } else if ((pfxMatchEntry != NULL) &&
  496. NullGuid(&pfxMatchEntry->Id.Uid)) {
  497. entryToUpdate = pfxMatchEntry;
  498. } else {
  499. entryToInvalidate = pfxMatchEntry;
  500. }
  501. //
  502. // Now we check to make sure that our create disposition is
  503. // consistent with what we are about to do.
  504. //
  505. if ((CreateDisposition & PKT_ENTRY_CREATE) && entryToUpdate != NULL) {
  506. *ppPktEntry = entryToUpdate;
  507. status = DFS_STATUS_ENTRY_EXISTS;
  508. } else if ((CreateDisposition & PKT_ENTRY_REPLACE) && entryToUpdate==NULL) {
  509. status = DFS_STATUS_NO_SUCH_ENTRY;
  510. }
  511. //
  512. // if we have an error here we can get out now!
  513. //
  514. if (!NT_SUCCESS(status)) {
  515. DebugTrace(-1, Dbg, "PktCreateEntry: Exit -> %08lx\n", ULongToPtr( status ) );
  516. return status;
  517. }
  518. //
  519. // At this point, we have two possible entries - entryToUpdate and
  520. // entryToInvalidate. We make an additional check to see if there is
  521. // a conflict with an 8.3 prefix. This logic works according to the
  522. // following table:
  523. //
  524. // entryToUpdate | entryToInvalidate | 8.3 match || Action
  525. // | | ||
  526. // 0 | 0 | 0 || Create
  527. // | | ||
  528. // 1 | 0 | 0 || Update
  529. // | | ||
  530. // 0 | 1 | 0 || Invalidate/Create
  531. // | | ||
  532. // 1 | 1 | 0 || Invalidate/Update
  533. // | | ||
  534. // 0 | 0 | 1 || 8.3 name conflict
  535. // | | ||
  536. // 1 | 0 | 1 || In entryToUpdate is
  537. // | | || the 8.3 match, ok
  538. // 0 | 1 | 1 || If entryToInvalidate
  539. // | | || is the 8.3 match,
  540. // 1 | 1 | 1 || then invalidate,
  541. // | | || else 8.3 name conflict
  542. //
  543. if (PktEntryId->ShortPrefix.Length != 0) {
  544. PDFS_PKT_ENTRY shortpfxMatch;
  545. shortpfxMatch = PktLookupEntryByShortPrefix(
  546. Pkt,
  547. &PktEntryId->ShortPrefix,
  548. &remainingPath);
  549. if (remainingPath.Length > 0)
  550. shortpfxMatch = NULL;
  551. if (shortpfxMatch != NULL) {
  552. if (entryToUpdate == NULL && entryToInvalidate == NULL) {
  553. status = STATUS_DUPLICATE_NAME;
  554. } else if (entryToUpdate != NULL && entryToInvalidate == NULL) {
  555. if (shortpfxMatch != entryToUpdate) {
  556. status = STATUS_DUPLICATE_NAME;
  557. }
  558. } else if (entryToInvalidate != NULL) {
  559. if (shortpfxMatch != entryToInvalidate) {
  560. status = STATUS_DUPLICATE_NAME;
  561. }
  562. }
  563. }
  564. }
  565. if (!NT_SUCCESS(status)) {
  566. DebugTrace(-1, Dbg,
  567. "PktCreateEntry: (Short name conflict) Exit -> %08lx\n", ULongToPtr( status ));
  568. return status;
  569. }
  570. //
  571. // At this point we must insure that we are not going to
  572. // be invalidating any local partition entries.
  573. //
  574. if ((entryToInvalidate != NULL) &&
  575. (!(entryToInvalidate->Type & PKT_ENTRY_TYPE_OUTSIDE_MY_DOM) ) &&
  576. (entryToInvalidate->Type &
  577. (PKT_ENTRY_TYPE_LOCAL |
  578. PKT_ENTRY_TYPE_LOCAL_XPOINT |
  579. PKT_ENTRY_TYPE_PERMANENT))) {
  580. DebugTrace(-1, Dbg, "PktCreateEntry(1): Exit -> %08lx\n",
  581. ULongToPtr( DFS_STATUS_LOCAL_ENTRY ) );
  582. return DFS_STATUS_LOCAL_ENTRY;
  583. }
  584. //
  585. // We go up the links till we reach a REFERRAL entry type. Actually
  586. // we may never go up since we always link to a REFERRAL entry. Anyway
  587. // no harm done!
  588. //
  589. while ((SupEntry != NULL) &&
  590. !(SupEntry->Type & PKT_ENTRY_TYPE_REFERRAL_SVC)) {
  591. SupEntry = SupEntry->ClosestDC;
  592. }
  593. //
  594. // If we had success then we need to see if we have to
  595. // invalidate an entry.
  596. //
  597. if (NT_SUCCESS(status) && entryToInvalidate != NULL)
  598. PktEntryDestroy(entryToInvalidate, Pkt, (BOOLEAN)TRUE);
  599. //
  600. // If we are not updating an entry we must construct a new one
  601. // from scratch. Otherwise we need to update.
  602. //
  603. if (entryToUpdate != NULL) {
  604. status = PktEntryReassemble(entryToUpdate,
  605. Pkt,
  606. PktEntryType,
  607. PktEntryId,
  608. PktEntryInfo);
  609. if (NT_SUCCESS(status)) {
  610. (*ppPktEntry) = entryToUpdate;
  611. PktEntryLinkChild(SupEntry, entryToUpdate);
  612. }
  613. } else {
  614. //
  615. // Now we are going to create a new entry. So we have to set
  616. // the ClosestDC Entry pointer while creating this entry. The
  617. // ClosestDC entry value is already in SupEntry.
  618. //
  619. PDFS_PKT_ENTRY newEntry;
  620. newEntry = (PDFS_PKT_ENTRY) ExAllocatePoolWithTag(
  621. PagedPool,
  622. sizeof(DFS_PKT_ENTRY),
  623. ' sfD');
  624. if (newEntry == NULL) {
  625. status = STATUS_INSUFFICIENT_RESOURCES;
  626. } else {
  627. status = PktEntryAssemble(newEntry,
  628. Pkt,
  629. PktEntryType,
  630. PktEntryId,
  631. PktEntryInfo);
  632. if (!NT_SUCCESS(status)) {
  633. ExFreePool(newEntry);
  634. } else {
  635. (*ppPktEntry) = newEntry;
  636. PktEntryLinkChild(SupEntry, newEntry);
  637. }
  638. }
  639. }
  640. DebugTrace(-1, Dbg, "PktCreateEntry(2): Exit -> %08lx\n", ULongToPtr( status ));
  641. return status;
  642. }
  643. //+-------------------------------------------------------------------------
  644. //
  645. // Function: PktCreateSubordinateEntry, public
  646. //
  647. // Synopsis: PktCreateSubordinateEntry creates/updates an entry to be
  648. // subordinate to an existing entry.
  649. //
  650. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  651. // [Superior] - a pointer to the superior entry.
  652. // [SubordinateType] - the type of subordinate entry to
  653. // create/update.
  654. // [SubordinateId] - the Id of the entry to create/update
  655. // to be subordinate.
  656. // [SubordinateInfo] - the Info of the entry to create/update.
  657. // [CreateDisposition] - identifies whether or not to supersede,
  658. // create, or update.
  659. // [Subordinate] - the (potentially new) subordinate entry.
  660. //
  661. // Returns: [STATUS_SUCCESS] - if all is well.
  662. // [DFS_STATUS_NO_SUCH_ENTRY] - the create disposition was
  663. // set to PKT_REPLACE_ENTRY and the Subordinate entry does
  664. // not exist.
  665. // [DFS_STATUS_ENTRY_EXISTS] - a create disposition of
  666. // PKT_CREATE_ENTRY was specified and the subordinate entry
  667. // already exists.
  668. // [DFS_STATUS_LOCAL_ENTRY] - creation of the subordinate entry
  669. // would have required that a local entry or exit point
  670. // be invalidated.
  671. // [DFS_STATUS_INCONSISTENT] - an inconsistency in the PKT
  672. // has been discovered.
  673. // [STATUS_INVALID_PARAMETER] - the Id specified for the
  674. // subordinate is invalid.
  675. // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
  676. // available to complete the operation.
  677. //
  678. //
  679. // Notes: If the subordinate exists and is currently a subordinate
  680. // of some other entry (then the Superior specified), it is
  681. // first removed from the old superior before making it
  682. // a subordinate of the Superior specified.
  683. //
  684. // The SubordinateId and SubordinateInfo structures are MOVED (not
  685. // COPIED) to the new entry. The memory used for UNICODE_STRINGS
  686. // and DFS_SERVICE arrays is used by the new entry. The
  687. // associated fields in the SubordinateId and SubordinateInfo
  688. // structures passed as arguments are Zero'd to indicate that
  689. // the memory has been "deallocated" from these strutures and
  690. // reallocated to the newly created Subordinate. Note that this
  691. // routine does not deallocate the SubordinateId structure or
  692. // the SubordinateInfo structure itself. On successful return from
  693. // this function, the SubordinateId structure will be modified
  694. // to have a NULL Prefix entry, and the SubordinateInfo structure
  695. // will be modified to have zero services and a null ServiceList
  696. // entry.
  697. //--------------------------------------------------------------------------
  698. NTSTATUS
  699. PktCreateSubordinateEntry(
  700. IN PDFS_PKT Pkt,
  701. IN PDFS_PKT_ENTRY Superior,
  702. IN ULONG SubordinateType,
  703. IN PDFS_PKT_ENTRY_ID SubordinateId,
  704. IN PDFS_PKT_ENTRY_INFO SubordinateInfo OPTIONAL,
  705. IN ULONG CreateDisposition,
  706. IN OUT PDFS_PKT_ENTRY *Subordinate
  707. )
  708. {
  709. NTSTATUS status = STATUS_SUCCESS;
  710. PDFS_PKT_ENTRY subEntry;
  711. DebugTrace(+1, Dbg, "PktCreateSubordinateEntry: Entered\n", 0);
  712. ASSERT(ARGUMENT_PRESENT(Pkt));
  713. ASSERT(ARGUMENT_PRESENT(Superior));
  714. ASSERT(ARGUMENT_PRESENT(SubordinateId));
  715. ASSERT(ARGUMENT_PRESENT(Subordinate));
  716. //
  717. // Now we go ahead and create the new sub entry...
  718. //
  719. status = PktCreateEntry(
  720. Pkt,
  721. SubordinateType,
  722. SubordinateId,
  723. SubordinateInfo,
  724. CreateDisposition,
  725. &subEntry
  726. );
  727. if (NT_SUCCESS(status)) {
  728. PktSetTypeInheritance(Superior, subEntry)
  729. //
  730. // Link the child to the parent...note that this removes the
  731. // child from any other parent.
  732. //
  733. PktEntryLinkSubordinate(Superior, subEntry);
  734. //
  735. // Don't forget to set the return value...
  736. //
  737. (*Subordinate) = subEntry;
  738. }
  739. DebugTrace(-1, Dbg, "PktCreateSubordinateEntry: Exit -> %08lx\n", ULongToPtr( status ));
  740. return status;
  741. }
  742. //+-------------------------------------------------------------------------
  743. //
  744. // Function: PktEntryModifyPrefix, public
  745. //
  746. // Synopsis: PktEntryModifyPrefix finds an entry that has a
  747. // specified prefix. The PKT must be acquired for
  748. // this operation.
  749. //
  750. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  751. // [Prefix] - the volume's new entry path
  752. // [Entry] - pointer to the PKT entry that needs to be modified.
  753. //
  754. // Returns: [DFS_STATUS_BAD_EXIT_POINT] -- If the new prefix could
  755. // not be inserted into the prefix table.
  756. //
  757. // [STATUS_INSUFFICIENT_RESOURCES] -- If room for the new
  758. // prefix could not be allocated.
  759. //
  760. // [STATUS_SUCCESS] -- If everything succeeds.
  761. //
  762. // Notes: If everything succeeds, the old Entry->Id.Prefix.Buffer is
  763. // freed up. If this function fails, then everything, including
  764. // the prefix table, is left intact.
  765. //
  766. //--------------------------------------------------------------------------
  767. NTSTATUS
  768. PktEntryModifyPrefix(
  769. IN PDFS_PKT Pkt,
  770. IN PUNICODE_STRING Prefix,
  771. IN PDFS_PKT_ENTRY Entry)
  772. {
  773. NTSTATUS status;
  774. UNICODE_STRING oldPrefix = Entry->Id.Prefix;
  775. DebugTrace(+1, Dbg, "PktEntryModifyPrefix: Entered\n", 0);
  776. //
  777. // First, try to allocate space for the new prefix. The old one has
  778. // already been saved in oldPrefix
  779. //
  780. Entry->Id.Prefix.Buffer = ExAllocatePoolWithTag(PagedPool, Prefix->MaximumLength, ' sfD');
  781. if (Entry->Id.Prefix.Buffer != NULL) {
  782. //
  783. // Next, get rid of the existing prefix from the PrefixTable.
  784. //
  785. DfsRemoveUnicodePrefix(&(Pkt->PrefixTable), &oldPrefix);
  786. //
  787. // Now we will plug in the actual prefix.
  788. //
  789. wcscpy(Entry->Id.Prefix.Buffer, Prefix->Buffer);
  790. Entry->Id.Prefix.Length = Prefix->Length;
  791. Entry->Id.Prefix.MaximumLength = Prefix->MaximumLength;
  792. if (DfsInsertUnicodePrefix(&Pkt->PrefixTable,
  793. &(Entry->Id.Prefix),
  794. &(Entry->PrefixTableEntry))) {
  795. ExFreePool(oldPrefix.Buffer);
  796. status = STATUS_SUCCESS;
  797. } else {
  798. ExFreePool( Entry->Id.Prefix.Buffer );
  799. Entry->Id.Prefix = oldPrefix;
  800. DfsInsertUnicodePrefix(&Pkt->PrefixTable,
  801. &(Entry->Id.Prefix),
  802. &(Entry->PrefixTableEntry));
  803. status = DFS_STATUS_BAD_EXIT_POINT;
  804. }
  805. } else {
  806. DebugTrace(0, Dbg,
  807. "PktEntryModifyPrefix: Unable to allocate %d bytes\n",
  808. Prefix->MaximumLength);
  809. Entry->Id.Prefix = oldPrefix;
  810. status = STATUS_INSUFFICIENT_RESOURCES;
  811. }
  812. DebugTrace(-1, Dbg, "PktEntryModifyPrefix: Exit -> %08lx\n", ULongToPtr( status ));
  813. return(status);
  814. }
  815. //+-------------------------------------------------------------------------
  816. //
  817. // Function: PktLookupEntryById, public
  818. //
  819. // Synopsis: PktLookupEntryById finds an entry that has a
  820. // specified Entry Id. The PKT must be acquired for
  821. // this operation.
  822. //
  823. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  824. // [Id] - the partitions Id to lookup.
  825. //
  826. // Returns: The PKT_ENTRY that has the exact same Id, or NULL,
  827. // if none exists.
  828. //
  829. // Notes:
  830. //
  831. //--------------------------------------------------------------------------
  832. PDFS_PKT_ENTRY
  833. PktLookupEntryById(
  834. IN PDFS_PKT Pkt,
  835. IN PDFS_PKT_ENTRY_ID Id
  836. )
  837. {
  838. PDFS_PKT_ENTRY ep;
  839. UNICODE_STRING remaining;
  840. DebugTrace(+1, Dbg, "PktLookupEntryById: Entered\n", 0);
  841. ASSERT(ARGUMENT_PRESENT(Pkt) &&
  842. ARGUMENT_PRESENT(Id));
  843. ep = PktLookupEntryByPrefix(Pkt, &Id->Prefix, &remaining);
  844. if (ep != NULL) {
  845. if (remaining.Length != 0 || !GuidEqual(&Id->Uid, &ep->Id.Uid))
  846. ep = NULL;
  847. }
  848. DebugTrace(-1, Dbg, "PktLookupEntryById: Exit -> %08lx\n", ep );
  849. return ep;
  850. }
  851. //+-------------------------------------------------------------------------
  852. //
  853. // Function: PktLookupEntryByPrefix, public
  854. //
  855. // Synopsis: PktLookupEntryByPrefix finds an entry that has a
  856. // specified prefix. The PKT must be acquired for
  857. // this operation.
  858. //
  859. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  860. // [Prefix] - the partitions prefix to lookup.
  861. // [Remaining] - any remaining path. Points within
  862. // the Prefix to where any trailing (nonmatched)
  863. // characters are.
  864. //
  865. // Returns: The PKT_ENTRY that has the exact same prefix, or NULL,
  866. // if none exists.
  867. //
  868. // Notes:
  869. //
  870. //--------------------------------------------------------------------------
  871. PDFS_PKT_ENTRY
  872. PktLookupEntryByPrefix(
  873. IN PDFS_PKT Pkt,
  874. IN PUNICODE_STRING Prefix,
  875. OUT PUNICODE_STRING Remaining
  876. )
  877. {
  878. PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
  879. PDFS_PKT_ENTRY pktEntry;
  880. UNICODE_STRING PrefixTail;
  881. UNICODE_STRING EntryTail;
  882. DebugTrace(+1, Dbg, "PktLookupEntryByPrefix: Entered\n", 0);
  883. //
  884. // If there really is a prefix to lookup, use the prefix table
  885. // to initially find an entry
  886. //
  887. if ((Prefix->Length != 0) &&
  888. (pfxEntry = DfsFindUnicodePrefix(&Pkt->PrefixTable,Prefix,Remaining))) {
  889. USHORT pfxLength;
  890. //
  891. // reset a pointer to the corresponding entry
  892. //
  893. pktEntry = CONTAINING_RECORD(pfxEntry,
  894. DFS_PKT_ENTRY,
  895. PrefixTableEntry
  896. );
  897. RemoveFirstComponent(Prefix,&PrefixTail);
  898. RemoveFirstComponent(&pktEntry->Id.Prefix,&EntryTail);
  899. pfxLength = EntryTail.Length;
  900. //
  901. // Now calculate the remaining path and return
  902. // the entry we found. Note that we bump the length
  903. // up by one char so that we skip any path separater.
  904. //
  905. if ((pfxLength < PrefixTail.Length) &&
  906. (PrefixTail.Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP))
  907. pfxLength += sizeof(WCHAR);
  908. if (pfxLength <= PrefixTail.Length) {
  909. Remaining->Length = (USHORT)(PrefixTail.Length - pfxLength);
  910. Remaining->Buffer = &PrefixTail.Buffer[pfxLength/sizeof(WCHAR)];
  911. Remaining->MaximumLength = (USHORT)(PrefixTail.MaximumLength - pfxLength);
  912. DebugTrace( 0, Dbg, "PktLookupEntryByPrefix: Remaining = %wZ\n",
  913. Remaining);
  914. } else {
  915. Remaining->Length = Remaining->MaximumLength = 0;
  916. Remaining->Buffer = NULL;
  917. DebugTrace( 0, Dbg, "PktLookupEntryByPrefix: No Remaining\n", 0);
  918. }
  919. DebugTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n",
  920. pktEntry);
  921. return pktEntry;
  922. }
  923. DebugTrace(-1, Dbg, "PktLookupEntryByPrefix: Exit -> %08lx\n", NULL);
  924. return NULL;
  925. }
  926. //+-------------------------------------------------------------------------
  927. //
  928. // Function: PktLookupEntryByShortPrefix, public
  929. //
  930. // Synopsis: PktLookupEntryByShortPrefix finds an entry that has a
  931. // specified short (8.3) prefix. The PKT must be acquired for
  932. // this operation.
  933. //
  934. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  935. // [Prefix] - the partitions prefix to lookup.
  936. // [Remaining] - any remaining path. Points within
  937. // the Prefix to where any trailing (nonmatched)
  938. // characters are.
  939. //
  940. // Returns: The PKT_ENTRY that has the exact same prefix, or NULL,
  941. // if none exists.
  942. //
  943. // Notes:
  944. //
  945. //--------------------------------------------------------------------------
  946. PDFS_PKT_ENTRY
  947. PktLookupEntryByShortPrefix(
  948. IN PDFS_PKT Pkt,
  949. IN PUNICODE_STRING Prefix,
  950. OUT PUNICODE_STRING Remaining
  951. )
  952. {
  953. PUNICODE_PREFIX_TABLE_ENTRY pfxEntry;
  954. PDFS_PKT_ENTRY pktEntry;
  955. DebugTrace(+1, Dbg, "PktLookupEntryByShortPrefix: Entered\n", 0);
  956. //
  957. // If there really is a prefix to lookup, use the prefix table
  958. // to initially find an entry
  959. //
  960. if ((Prefix->Length != 0) &&
  961. (pfxEntry = DfsFindUnicodePrefix(&Pkt->ShortPrefixTable,Prefix,Remaining))) {
  962. USHORT pfxLength;
  963. //
  964. // reset a pointer to the corresponding entry
  965. //
  966. pktEntry = CONTAINING_RECORD(pfxEntry,
  967. DFS_PKT_ENTRY,
  968. PrefixTableEntry
  969. );
  970. pfxLength = pktEntry->Id.ShortPrefix.Length;
  971. //
  972. // Now calculate the remaining path and return
  973. // the entry we found. Note that we bump the length
  974. // up by one char so that we skip any path separater.
  975. //
  976. if ((pfxLength < Prefix->Length) &&
  977. (Prefix->Buffer[pfxLength/sizeof(WCHAR)] == UNICODE_PATH_SEP))
  978. pfxLength += sizeof(WCHAR);
  979. if (pfxLength <= Prefix->Length) {
  980. Remaining->Length = (USHORT)(Prefix->Length - pfxLength);
  981. Remaining->Buffer = &Prefix->Buffer[pfxLength/sizeof(WCHAR)];
  982. Remaining->MaximumLength = (USHORT)(Prefix->MaximumLength - pfxLength);
  983. DebugTrace( 0, Dbg, "PktLookupEntryByShortPrefix: Remaining = %wZ\n",
  984. Remaining);
  985. } else {
  986. Remaining->Length = Remaining->MaximumLength = 0;
  987. Remaining->Buffer = NULL;
  988. DebugTrace( 0, Dbg, "PktLookupEntryByShortPrefix: No Remaining\n", 0);
  989. }
  990. DebugTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n",
  991. pktEntry);
  992. return pktEntry;
  993. }
  994. DebugTrace(-1, Dbg, "PktLookupEntryByShortPrefix: Exit -> %08lx\n", NULL);
  995. return NULL;
  996. }
  997. //+-------------------------------------------------------------------------
  998. //
  999. // Function: PktLookupEntryByUid, public
  1000. //
  1001. // Synopsis: PktLookupEntryByUid finds an entry that has a
  1002. // specified Uid. The PKT must be acquired for this operation.
  1003. //
  1004. // Arguments: [Pkt] - pointer to a initialized (and acquired) PKT
  1005. // [Uid] - a pointer to the partitions Uid to lookup.
  1006. //
  1007. // Returns: A pointer to the PKT_ENTRY that has the exact same
  1008. // Uid, or NULL, if none exists.
  1009. //
  1010. // Notes: The input Uid cannot be the Null GUID.
  1011. //
  1012. // On a DC where there may be *lots* of entries in the PKT,
  1013. // we may want to consider using some other algorithm for
  1014. // looking up by ID.
  1015. //
  1016. //--------------------------------------------------------------------------
  1017. PDFS_PKT_ENTRY
  1018. PktLookupEntryByUid(
  1019. IN PDFS_PKT Pkt,
  1020. IN GUID *Uid
  1021. ) {
  1022. PDFS_PKT_ENTRY entry;
  1023. DebugTrace(+1, Dbg, "PktLookupEntryByUid: Entered\n", 0);
  1024. //
  1025. // We don't lookup NULL Uids
  1026. //
  1027. if (NullGuid(Uid)) {
  1028. DebugTrace(0, Dbg, "PktLookupEntryByUid: NULL Guid\n", NULL);
  1029. entry = NULL;
  1030. } else {
  1031. entry = PktFirstEntry(Pkt);
  1032. }
  1033. while (entry != NULL) {
  1034. if (GuidEqual(&entry->Id.Uid, Uid))
  1035. break;
  1036. entry = PktNextEntry(Pkt, entry);
  1037. }
  1038. DebugTrace(-1, Dbg, "PktLookupEntryByUid: Exit -> %08lx\n", entry);
  1039. return entry;
  1040. }
  1041. //+-------------------------------------------------------------------------
  1042. //
  1043. // Function: PktSetRelationInfo, public
  1044. //
  1045. // Synopsis: PktSetRelationInfo takes the information specified in a
  1046. // relation info structure and sets the Pkt entries accordingly.
  1047. //
  1048. // Arguments: [Pkt] - a pointer to an exclusively acquired Pkt.
  1049. // [RelationInfo] - a pointer to a relation info structure
  1050. // specifying the relationship that is to be set.
  1051. //
  1052. // Returns: [STATUS_SUCCESS] - if all is well.
  1053. // [DFS_STATUS_NO_SUCH_ENTRY] - the EntryId specified in the
  1054. // Relation Info structure does not exist.
  1055. // [DFS_STATUS_LOCAL_ENTRY] - creation of the subordinate entry
  1056. // would have required that a local entry or exit point
  1057. // be invalidated.
  1058. // [DFS_STATUS_INCONSISTENT] - an inconsistency in the PKT
  1059. // has been discovered.
  1060. // [STATUS_INVALID_PARAMETER] - the Id specified for a
  1061. // subordinate is invalid.
  1062. // [STATUS_INSUFFICIENT_RESOURCES] - not enough memory was
  1063. // available to complete the operation.
  1064. //
  1065. //
  1066. // Notes: If this operation fails, all subordinates of the entry
  1067. // are cleared.
  1068. //
  1069. //--------------------------------------------------------------------------
  1070. NTSTATUS
  1071. PktSetRelationInfo(
  1072. IN PDFS_PKT Pkt,
  1073. IN PDFS_PKT_RELATION_INFO RelationInfo
  1074. )
  1075. {
  1076. NTSTATUS status = STATUS_SUCCESS;
  1077. PDFS_PKT_ENTRY entry;
  1078. ULONG i;
  1079. DebugTrace(+1, Dbg, "PktSetRelationalInfo: Entered\n", 0);
  1080. ASSERT(ARGUMENT_PRESENT(Pkt));
  1081. ASSERT(ARGUMENT_PRESENT(RelationInfo));
  1082. //
  1083. // We need to lookup the entry for which we are setting relation
  1084. // information on.
  1085. //
  1086. if ((entry = PktLookupEntryById(Pkt, &RelationInfo->EntryId)) == NULL) {
  1087. DebugTrace(-1, Dbg, "PktSetRelationalInfo: Exit -> %08lx\n",
  1088. ULongToPtr( DFS_STATUS_NO_SUCH_ENTRY ));
  1089. return DFS_STATUS_NO_SUCH_ENTRY;
  1090. }
  1091. //
  1092. // Now we go and trim off any subordinates that aren't
  1093. // currently identified in the Relation Info structure.
  1094. //
  1095. PktTrimSubordinates(Pkt, entry, RelationInfo);
  1096. //
  1097. // Go through the relation info structure creating subordinates
  1098. //
  1099. for (i = 0; i < RelationInfo->SubordinateIdCount; i++) {
  1100. PDFS_PKT_ENTRY subEntry;
  1101. status = PktCreateSubordinateEntry(
  1102. Pkt,
  1103. entry,
  1104. 0L,
  1105. &RelationInfo->SubordinateIdList[i],
  1106. NULL,
  1107. PKT_ENTRY_SUPERSEDE,
  1108. &subEntry
  1109. );
  1110. if (!NT_SUCCESS(status)) {
  1111. //
  1112. // If there was an error, we clear away all subordinates.
  1113. // ...It's an all or nothing proposition...
  1114. //
  1115. PktEntryClearSubordinates(entry);
  1116. break;
  1117. }
  1118. }
  1119. DebugTrace(-1, Dbg, "PktSetRelationalInfo: Exit -> %08lx\n", ULongToPtr( status ));
  1120. return status;
  1121. }
  1122. //+-------------------------------------------------------------------------
  1123. //
  1124. // Function: PktTrimSubordinates, public
  1125. //
  1126. // Synopsis: PktTrimSubordinates invalidates all subordinate entries
  1127. // that are not specified in the relation info structure
  1128. // supplied.
  1129. //
  1130. // Arguments: [Pkt] - a pointer to an exclusively acquired Pkt.
  1131. // [PktEntry] - a pointer to an entry that is to have all its
  1132. // subordinates unlinked.
  1133. // [RelationInfo] - a pointer to a relation info structure
  1134. // specifying the relationship that the Pkt is to
  1135. // be trimmed to.
  1136. //
  1137. // Returns: VOID
  1138. //
  1139. // Notes: This operation does not insure that all the subordinates
  1140. // exist, it only insures that no subordinates that are
  1141. // NOT specified in the relation info structure exist.
  1142. //
  1143. //--------------------------------------------------------------------------
  1144. VOID
  1145. PktTrimSubordinates(
  1146. IN PDFS_PKT Pkt,
  1147. IN PDFS_PKT_ENTRY Entry,
  1148. IN PDFS_PKT_RELATION_INFO RInfo
  1149. )
  1150. {
  1151. PDFS_PKT_ENTRY subEntry;
  1152. DebugTrace(+1, Dbg, "PktTrimSubordinates: Entered\n", 0);
  1153. ASSERT(ARGUMENT_PRESENT(Entry));
  1154. ASSERT(ARGUMENT_PRESENT(RInfo));
  1155. ASSERT(PktEntryIdEqual(&Entry->Id, &RInfo->EntryId));
  1156. //
  1157. // go through the list of subordinate entries
  1158. //
  1159. subEntry = PktEntryFirstSubordinate(Entry);
  1160. while (subEntry != NULL) {
  1161. PDFS_PKT_ENTRY_ID id;
  1162. PDFS_PKT_ENTRY nextSubEntry;
  1163. BOOLEAN onTheList;
  1164. //
  1165. // Search the list of subordinate ids to insure that this
  1166. // subordinate is on it.
  1167. //
  1168. for (onTheList = FALSE, id = RInfo->SubordinateIdList;
  1169. id < &RInfo->SubordinateIdList[RInfo->SubordinateIdCount];
  1170. id++) {
  1171. if (PktEntryIdEqual(&subEntry->Id, id)) {
  1172. onTheList = TRUE;
  1173. break;
  1174. }
  1175. }
  1176. //
  1177. // If we didn't find the subordinate on the list, we destroy...
  1178. // Note that we have to get the next subordinate prior to this
  1179. // just in case the current one gets nuked!
  1180. //
  1181. nextSubEntry = PktEntryNextSubordinate(Entry, subEntry);
  1182. if (!onTheList)
  1183. PktEntryDestroy(subEntry, Pkt, (BOOLEAN)TRUE);
  1184. //
  1185. // go to the next subordinate entry...
  1186. //
  1187. subEntry = nextSubEntry;
  1188. }
  1189. DebugTrace(-1, Dbg, "PktTrimSubordinates: Exit -> VOID\n", 0);
  1190. }
  1191. //+----------------------------------------------------------------------------
  1192. //
  1193. // Function: PktpPruneExtraVolume
  1194. //
  1195. // Synopsis: Sometimes a DC thinks this server has an extra volume, so
  1196. // that volume's knowledge needs to be pruned from the pkt and
  1197. // registry, and the volume's exit points need to be deleted
  1198. // from the disk. This routine is a helper routine to do that.
  1199. //
  1200. // Arguments: [RelationInfo] -- The Relation Info for the local volume
  1201. // that needs to be pruned.
  1202. //
  1203. // Returns: [STATUS_SUCCESS] -- Local volume and its exit pts were deleted
  1204. //
  1205. // [STATUS_UNSUCCESSFUL] -- Some errors were encountered in
  1206. // deleting the local volume; for each error, a message
  1207. // was logged.
  1208. //
  1209. // Notes: Assumes Pkt has been acquired exclusive
  1210. //
  1211. // History: 05-April-95 Milans created
  1212. //
  1213. //-----------------------------------------------------------------------------
  1214. NTSTATUS
  1215. PktpPruneExtraVolume(
  1216. IN PDFS_PKT_RELATION_INFO RelationInfo)
  1217. {
  1218. NTSTATUS status, returnStatus;
  1219. PDFS_PKT_ENTRY_ID peid;
  1220. UNICODE_STRING puStr[2];
  1221. ULONG i;
  1222. puStr[1].MaximumLength = sizeof(L"LocalMachine");
  1223. puStr[1].Length = puStr[1].MaximumLength - sizeof(WCHAR);
  1224. puStr[1].Buffer = L"LocalMachine";
  1225. //
  1226. // First we delete all the exit Points.
  1227. //
  1228. returnStatus = STATUS_SUCCESS;
  1229. peid = RelationInfo->SubordinateIdList;
  1230. for (i = 0; i < RelationInfo->SubordinateIdCount; i++) {
  1231. status = DfsInternalDeleteExitPoint(peid, PKT_ENTRY_TYPE_CAIRO);
  1232. if (!NT_SUCCESS(status)) {
  1233. DebugTrace(0, 1, "Dfs - PktpPruneExtraVolume: DeletingExitPt "
  1234. "failed: %08lx\n", ULongToPtr( status ));
  1235. puStr[0] = peid->Prefix;
  1236. LogWriteMessage(EXTRA_EXIT_POINT_NOT_DELETED, status, 2, puStr);
  1237. returnStatus = STATUS_UNSUCCESSFUL;
  1238. }
  1239. peid++;
  1240. }
  1241. status = DfsInternalDeleteLocalVolume(&RelationInfo->EntryId);
  1242. if (!NT_SUCCESS(status)) {
  1243. puStr[0] = RelationInfo->EntryId.Prefix;
  1244. DebugTrace(0, 1, "Dfs - PktpPruneExtraVolume: Deleting "
  1245. "Extra Local Volume failed: %08lx\n", ULongToPtr( status ));
  1246. LogWriteMessage(EXTRA_VOLUME_NOT_DELETED, status, 2, puStr);
  1247. returnStatus = STATUS_UNSUCCESSFUL;
  1248. }
  1249. return( status );
  1250. }
  1251. //+----------------------------------------------------------------------------
  1252. //
  1253. // Function: PktpFixupRelationInfo
  1254. //
  1255. // Synopsis: Sometimes a DC will discover that this server has the wrong
  1256. // information about a local volume. This routine will fix up
  1257. // the local knowledge to that of the DC.
  1258. //
  1259. // Arguments:
  1260. //
  1261. // Returns: [STATUS_SUCCESS] -- We managed to completely sync up with
  1262. // the DC's relation info.
  1263. //
  1264. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory.
  1265. //
  1266. // [STATUS_UNSUCCESSFUL] -- We were unable to fully sync up -
  1267. // a message was logged for the errors encountered.
  1268. //
  1269. // Notes: Assumes Pkt has been acquired exclusive
  1270. //
  1271. // History: 05-April-95 Milans created
  1272. //
  1273. //-----------------------------------------------------------------------------
  1274. NTSTATUS
  1275. PktpFixupRelationInfo(
  1276. IN PDFS_PKT_RELATION_INFO Local,
  1277. IN PDFS_PKT_RELATION_INFO Remote)
  1278. {
  1279. NTSTATUS status, returnStatus;
  1280. PUNICODE_STRING lpfx, rpfx;
  1281. ULONG i, j=0;
  1282. ULONG *pulExitPtUsed = NULL;
  1283. UNICODE_STRING LocalMachStr;
  1284. UNICODE_STRING puStr[3];
  1285. UNICODE_STRING unusedShortPrefix;
  1286. LocalMachStr.MaximumLength = sizeof(L"LocalMachine");
  1287. LocalMachStr.Length = LocalMachStr.MaximumLength - sizeof(WCHAR);
  1288. LocalMachStr.Buffer = L"LocalMachine";
  1289. returnStatus = status = STATUS_SUCCESS;
  1290. //
  1291. // The GUIDs of this volume have already been matched otherwise we
  1292. // would not be here. So we don't even look at that. We still
  1293. // need to match the prefixes. If the prefixes are different then we
  1294. // need to fix that.
  1295. //
  1296. lpfx = &Local->EntryId.Prefix;
  1297. rpfx = &Remote->EntryId.Prefix;
  1298. if (RtlCompareUnicodeString(lpfx, rpfx, TRUE)) {
  1299. //
  1300. // The Prefixes are different we need to fix this now.
  1301. // But first let us log this event.
  1302. //
  1303. DebugTrace(0, Dbg, "Fixed Prefix [%wZ]\n", rpfx);
  1304. DebugTrace(0, Dbg, "To be [%wZ]\n", lpfx);
  1305. puStr[0] = Local->EntryId.Prefix;
  1306. puStr[1] = Remote->EntryId.Prefix;
  1307. puStr[2] = LocalMachStr;
  1308. LogWriteMessage(PREFIX_MISMATCH, status, 3, puStr);
  1309. status = DfsInternalModifyPrefix(&Remote->EntryId);
  1310. if (NT_SUCCESS(status)) {
  1311. LogWriteMessage(PREFIX_MISMATCH_FIXED, status, 3, puStr);
  1312. } else {
  1313. DebugTrace(0, 1, "Dfs - PktRelationInfoValidate: "
  1314. "Status from DfsModifyePrefix = %08lx\n", ULongToPtr( status ));
  1315. LogWriteMessage(PREFIX_MISMATCH_NOT_FIXED, status, 3,puStr);
  1316. }
  1317. }
  1318. if (Remote->SubordinateIdCount != 0) {
  1319. ULONG size = sizeof(ULONG) * Remote->SubordinateIdCount;
  1320. pulExitPtUsed = ExAllocatePoolWithTag( PagedPool, size, ' sfD' );
  1321. if (pulExitPtUsed == NULL) {
  1322. return ( STATUS_INSUFFICIENT_RESOURCES );
  1323. } else {
  1324. RtlZeroMemory( pulExitPtUsed, size );
  1325. }
  1326. }
  1327. //
  1328. // We step through each exit point in the local knowledge and
  1329. // make sure that is right. If not we attempt to delete the exit
  1330. // point from this machine. So this takes care of EXTRA
  1331. // ExitPoints at this machine. We will still need to deal with
  1332. // ExitPoints which the DC knows of whereas the this machine does
  1333. // not. So we keep track of all the remote exit points which have
  1334. // been acounted for by the local Relational info and then we
  1335. // take the rest and create those exit points at this machine.
  1336. // This takes care of TOO FEW ExitPoints at this machine.
  1337. //
  1338. for (i = 0; i < Local->SubordinateIdCount; i++) {
  1339. ULONG j;
  1340. GUID *lguid, *rguid;
  1341. rpfx = &Local->SubordinateIdList[i].Prefix;
  1342. rguid = &Local->SubordinateIdList[i].Uid;
  1343. status = DFS_STATUS_BAD_EXIT_POINT;
  1344. for (j = 0; j < Remote->SubordinateIdCount; j++) {
  1345. lpfx = &Remote->SubordinateIdList[j].Prefix;
  1346. lguid = &Remote->SubordinateIdList[j].Uid;
  1347. if (!RtlCompareUnicodeString(lpfx, rpfx, TRUE) &&
  1348. GuidEqual(lguid, rguid)) {
  1349. status = STATUS_SUCCESS;
  1350. ASSERT(pulExitPtUsed[j] == FALSE);
  1351. pulExitPtUsed[j] = TRUE;
  1352. break;
  1353. }
  1354. }
  1355. if (!NT_SUCCESS(status)) {
  1356. //
  1357. // In this case we have an exit point which the DC does not
  1358. // recognise. We need to delete this.
  1359. //
  1360. puStr[0] = Local->SubordinateIdList[i].Prefix;
  1361. puStr[1] = LocalMachStr;
  1362. LogWriteMessage(EXTRA_EXIT_POINT, status, 2, puStr);
  1363. status =
  1364. DfsInternalDeleteExitPoint(&Local->SubordinateIdList[i],
  1365. PKT_ENTRY_TYPE_CAIRO);
  1366. if (!NT_SUCCESS(status)) {
  1367. //
  1368. // We want to Log an event here actually.
  1369. //
  1370. DebugTrace(0, 1,
  1371. "Dfs - PktpFixupRelationInfo: Failed to delete [%wZ]\n",
  1372. &Local->SubordinateIdList[i].Prefix );
  1373. LogWriteMessage(EXTRA_EXIT_POINT_NOT_DELETED, status, 2, puStr);
  1374. returnStatus = STATUS_UNSUCCESSFUL;
  1375. } else {
  1376. LogWriteMessage(EXTRA_EXIT_POINT_DELETED, status, 2, puStr);
  1377. }
  1378. }
  1379. }
  1380. //
  1381. // Now that we are done with getting rid of extra exit points
  1382. // we only need to deal with any exit point that we dont have
  1383. // and create any such that might exist.
  1384. //
  1385. for (i = 0; i < Remote->SubordinateIdCount; i++) {
  1386. if (pulExitPtUsed[i] == FALSE) {
  1387. puStr[0] = Remote->SubordinateIdList[i].Prefix;
  1388. puStr[1] = LocalMachStr;
  1389. LogWriteMessage(MISSING_EXIT_POINT, status, 2, puStr);
  1390. RtlInitUnicodeString(&unusedShortPrefix, NULL);
  1391. status = DfsInternalCreateExitPoint(
  1392. &Remote->SubordinateIdList[i],
  1393. PKT_ENTRY_TYPE_CAIRO,
  1394. FILE_OPEN_IF,
  1395. &unusedShortPrefix);
  1396. if (NT_SUCCESS(status) && unusedShortPrefix.Buffer != NULL) {
  1397. ExFreePool(unusedShortPrefix.Buffer);
  1398. }
  1399. if (!NT_SUCCESS(status)) {
  1400. //
  1401. // We want to Log an event here actually.
  1402. //
  1403. DebugTrace(0, 1, "DFS - PktpFixupRelationInfo: "
  1404. "Failed to Create ExitPt [%wZ]\n",
  1405. &Remote->SubordinateIdList[i].Prefix);
  1406. LogWriteMessage(MISSING_EXIT_POINT_NOT_CREATED,
  1407. status,
  1408. 2,
  1409. puStr);
  1410. returnStatus = STATUS_UNSUCCESSFUL;
  1411. } else {
  1412. LogWriteMessage(MISSING_EXIT_POINT_CREATED,
  1413. status,
  1414. 2,
  1415. puStr);
  1416. }
  1417. }
  1418. } // end for each subordinate in remote relation info
  1419. if (pulExitPtUsed != NULL) {
  1420. ExFreePool(pulExitPtUsed);
  1421. }
  1422. return( returnStatus );
  1423. }
  1424. //+----------------------------------------------------------------------------
  1425. //
  1426. // Function: PktShuffleServiceList
  1427. //
  1428. // Synopsis: Randomizes a service list for proper load balancing. This
  1429. // routine assumes that the service list is ordered based on
  1430. // site costs. For each equivalent cost group, this routine
  1431. // shuffles the service list.
  1432. //
  1433. // Arguments: [pInfo] -- Pointer to PktEntryInfo whose service list needs to
  1434. // be shuffled.
  1435. //
  1436. // Returns: Nothing, unless rand() fails!
  1437. //
  1438. //-----------------------------------------------------------------------------
  1439. VOID
  1440. PktShuffleServiceList(
  1441. PDFS_PKT_ENTRY_INFO pInfo)
  1442. {
  1443. PktShuffleGroup(pInfo, 0, pInfo->ServiceCount);
  1444. }
  1445. //+----------------------------------------------------------------------------
  1446. //
  1447. // Function: PktShuffleGroup
  1448. //
  1449. // Synopsis: Shuffles a cost equivalent group of services around for load
  1450. // balancing. Uses the classic card shuffling algorithm - for
  1451. // each card in the deck, exchange it with a random card in the
  1452. // deck.
  1453. //
  1454. // Arguments:
  1455. //
  1456. // Returns:
  1457. //
  1458. //-----------------------------------------------------------------------------
  1459. VOID
  1460. PktShuffleGroup(
  1461. PDFS_PKT_ENTRY_INFO pInfo,
  1462. ULONG nStart,
  1463. ULONG nEnd)
  1464. {
  1465. ULONG i;
  1466. LARGE_INTEGER seed;
  1467. ASSERT( nStart < pInfo->ServiceCount );
  1468. ASSERT( nEnd <= pInfo->ServiceCount );
  1469. KeQuerySystemTime( &seed );
  1470. for (i = nStart; i < nEnd; i++) {
  1471. DFS_SERVICE TempService;
  1472. ULONG j;
  1473. ASSERT (nEnd - nStart != 0);
  1474. j = (RtlRandom( &seed.LowPart ) % (nEnd - nStart)) + nStart;
  1475. ASSERT( j >= nStart && j <= nEnd );
  1476. TempService = pInfo->ServiceList[i];
  1477. pInfo->ServiceList[i] = pInfo->ServiceList[j];
  1478. pInfo->ServiceList[j] = TempService;
  1479. }
  1480. }
  1481. //+----------------------------------------------------------------------------
  1482. //
  1483. // Function: DfsBuildConnectionRequest
  1484. //
  1485. // Synopsis: Builds the EA and file names necessary to setup an
  1486. // authenticated connection to a server.
  1487. //
  1488. // Arguments: [pService] -- Pointer to DFS_SERVICE describing server
  1489. // [pProvider] -- Pointer to PROVIDER_DEF describing the
  1490. // provider to use to establish the connection.
  1491. // [pShareName] -- Share name to open.
  1492. //
  1493. // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  1494. //
  1495. //-----------------------------------------------------------------------------
  1496. NTSTATUS DfsBuildConnectionRequest(
  1497. IN PDFS_SERVICE pService,
  1498. IN PPROVIDER_DEF pProvider,
  1499. OUT PUNICODE_STRING pShareName)
  1500. {
  1501. ASSERT(pService != NULL);
  1502. ASSERT(pProvider != NULL);
  1503. RtlInitUnicodeString(pShareName, NULL);
  1504. pShareName->Length = 0;
  1505. pShareName->MaximumLength = pProvider->DeviceName.Length +
  1506. sizeof(UNICODE_PATH_SEP_STR) +
  1507. pService->Name.Length +
  1508. sizeof(ROOT_SHARE_NAME);
  1509. pShareName->Buffer = ExAllocatePoolWithTag(PagedPool, pShareName->MaximumLength, ' sfD');
  1510. if (pShareName->Buffer == NULL) {
  1511. DebugTrace(0, Dbg, "Unable to allocate pool for share name!\n", 0);
  1512. pShareName->Length = pShareName->MaximumLength = 0;
  1513. return( STATUS_INSUFFICIENT_RESOURCES );
  1514. }
  1515. RtlAppendUnicodeStringToString( pShareName, &pProvider->DeviceName );
  1516. RtlAppendUnicodeToString( pShareName, UNICODE_PATH_SEP_STR );
  1517. RtlAppendUnicodeStringToString( pShareName, &pService->Name );
  1518. RtlAppendUnicodeToString( pShareName, ROOT_SHARE_NAME );
  1519. return( STATUS_SUCCESS );
  1520. }
  1521. //+----------------------------------------------------------------------------
  1522. //
  1523. // Function: DfsFreeConnectionRequest
  1524. //
  1525. // Synopsis: Frees up the stuff allocated on a successful call to
  1526. // DfsBuildConnectionRequest
  1527. //
  1528. // Arguments: [pShareName] -- Unicode string holding share name.
  1529. //
  1530. // Returns: Nothing
  1531. //
  1532. //-----------------------------------------------------------------------------
  1533. VOID
  1534. DfsFreeConnectionRequest(
  1535. IN OUT PUNICODE_STRING pShareName)
  1536. {
  1537. if (pShareName->Buffer != NULL) {
  1538. ExFreePool ( pShareName->Buffer );
  1539. }
  1540. }
  1541. //+-------------------------------------------------------------------------
  1542. //
  1543. // Function: DfsCreateConnection -- Create a connection to a server
  1544. //
  1545. // Synopsis: DfsCreateConnection will attempt to create a connection
  1546. // to some server's IPC$ share.
  1547. //
  1548. // Arguments: [pService] -- the Service entry, giving the server principal
  1549. // name
  1550. // [remoteHandle] -- This is where the handle is returned.
  1551. //
  1552. // Returns: NTSTATUS - the status of the operation
  1553. //
  1554. // Notes: The Pkt must be acquired shared before calling this! It will
  1555. // be released and reacquired in this routine.
  1556. //
  1557. // History: 31 Mar 1993 SudK Created
  1558. //
  1559. //--------------------------------------------------------------------------
  1560. NTSTATUS
  1561. DfsCreateConnection(
  1562. IN PDFS_SERVICE pService,
  1563. IN PPROVIDER_DEF pProvider,
  1564. OUT PHANDLE remoteHandle
  1565. ) {
  1566. OBJECT_ATTRIBUTES ObjectAttributes;
  1567. IO_STATUS_BLOCK IoStatusBlock;
  1568. UNICODE_STRING ShareName;
  1569. NTSTATUS Status;
  1570. ASSERT(pService != NULL);
  1571. ASSERT(pProvider != NULL);
  1572. ASSERT(ExIsResourceAcquiredSharedLite( &DfsData.Pkt.Resource ));
  1573. Status = DfsBuildConnectionRequest(
  1574. pService,
  1575. pProvider,
  1576. &ShareName);
  1577. if (!NT_SUCCESS(Status)) {
  1578. return( Status );
  1579. }
  1580. InitializeObjectAttributes(
  1581. &ObjectAttributes,
  1582. &ShareName, // File Name
  1583. 0, // Attributes
  1584. NULL, // Root Directory
  1585. NULL // Security
  1586. );
  1587. //
  1588. // Create or open a tree connection
  1589. //
  1590. PktRelease( &DfsData.Pkt );
  1591. Status = ZwCreateFile(
  1592. remoteHandle,
  1593. SYNCHRONIZE,
  1594. &ObjectAttributes,
  1595. &IoStatusBlock,
  1596. NULL,
  1597. FILE_ATTRIBUTE_NORMAL,
  1598. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1599. FILE_OPEN_IF,
  1600. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  1601. NULL,
  1602. 0);
  1603. PktAcquireShared( &DfsData.Pkt, TRUE );
  1604. if ( NT_SUCCESS( Status ) ) {
  1605. DebugTrace(0, Dbg, "Created Connection Successfully\n", 0);
  1606. Status = IoStatusBlock.Status;
  1607. }
  1608. DfsFreeConnectionRequest( &ShareName );
  1609. return Status;
  1610. }
  1611. //+-------------------------------------------------------------------------
  1612. //
  1613. // Function: DfsCloseConnection -- Close a connection to a server
  1614. //
  1615. // Synopsis: DfsCloseConnection will attempt to Close a connection
  1616. // to some server.
  1617. //
  1618. // Effects: The file object referring to the the connection will be
  1619. // closed.
  1620. //
  1621. // Arguments: pService - the Service entry, giving the server connection
  1622. // handle
  1623. //
  1624. // Returns: NTSTATUS - the status of the operation
  1625. //
  1626. // History: 28 May 1992 Alanw Created
  1627. //
  1628. //--------------------------------------------------------------------------
  1629. NTSTATUS
  1630. DfsCloseConnection(
  1631. IN PDFS_SERVICE pService
  1632. )
  1633. {
  1634. ASSERT( pService->ConnFile != NULL );
  1635. ObDereferenceObject(pService->ConnFile);
  1636. pService->ConnFile = NULL;
  1637. return STATUS_SUCCESS;
  1638. }
  1639. //+-------------------------------------------------------------------------
  1640. //
  1641. // Function: DfsConcatenateFilePath, public
  1642. //
  1643. // Synopsis: DfsConcatenateFilePath will concatenate two strings
  1644. // representing file path names, assuring that they are
  1645. // separated by a single '\' character.
  1646. //
  1647. // Arguments: [Dest] - a pointer to the destination string
  1648. // [RemainingPath] - the final part of the path name
  1649. // [Length] - the length (in bytes) of RemainingPath
  1650. //
  1651. // Returns: BOOLEAN - TRUE unless Dest is too small to
  1652. // hold the result (assert).
  1653. //
  1654. //--------------------------------------------------------------------------
  1655. BOOLEAN
  1656. DfsConcatenateFilePath (
  1657. IN PUNICODE_STRING Dest,
  1658. IN PWSTR RemainingPath,
  1659. IN USHORT Length
  1660. ) {
  1661. PWSTR OutBuf = (PWSTR)&(((PCHAR)Dest->Buffer)[Dest->Length]);
  1662. if (Dest->Length > 0) {
  1663. ASSERT(OutBuf[-1] != UNICODE_NULL);
  1664. }
  1665. if (Dest->Length > 0 && OutBuf[-1] != UNICODE_PATH_SEP) {
  1666. *OutBuf++ = UNICODE_PATH_SEP;
  1667. Dest->Length += sizeof (WCHAR);
  1668. }
  1669. if (Length > 0 && *RemainingPath == UNICODE_PATH_SEP) {
  1670. RemainingPath++;
  1671. Length -= sizeof (WCHAR);
  1672. }
  1673. ASSERT(Dest->MaximumLength >= (USHORT)(Dest->Length + Length));
  1674. if (Length > 0) {
  1675. RtlMoveMemory(OutBuf, RemainingPath, Length);
  1676. Dest->Length += Length;
  1677. }
  1678. return TRUE;
  1679. }