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.

946 lines
25 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1998, Microsoft Corporation.
  4. //
  5. // File: spcsup.c
  6. //
  7. // Contents: Support routines for managing DFS_SPECIAL_INFO entries
  8. //
  9. // DfsInitSpcInfoHashTable - Initialize a DFS_SPECIAL_HASH table
  10. // DfsLookupSpcInfo - Lookup a DFS_SPECIAL_INFO
  11. // DfsAllocateSpcInfo - Allocate a DFS_SPECIAL_INFO
  12. // DfsInsertSpcInfo - Put a DFS_SPECIAL_INFO into the table
  13. // DfsDeleteSpcInfo - Remove a DFS_SPECIAL_INFO from the table
  14. // DfsReleaseSpcInfo - Stop using a DFS_SPECIAL_INFO
  15. //
  16. // DfsFsctrlCreateSpcInfo - Load a special table entry
  17. // DfsFsctrlDeleteSpcInfo - Remove a special table entry
  18. //
  19. //--------------------------------------------------------------------------
  20. #include "dfsprocs.h"
  21. #include "attach.h"
  22. #include "spcsup.h"
  23. #include "fsctrl.h"
  24. #include "dfssrv.h"
  25. #define Dbg 0x4000
  26. #define DEFAULT_HASH_SIZE 16 // default size of hash table
  27. NTSTATUS
  28. DfsAllocateSpcInfo(
  29. IN PUNICODE_STRING pSpecialName,
  30. IN ULONG TypeFlags,
  31. IN ULONG TrustDirection,
  32. IN ULONG TrustType,
  33. IN ULONG TimeToLive,
  34. IN LONG NameCount,
  35. IN PUNICODE_STRING pNames,
  36. OUT PDFS_SPECIAL_INFO *ppSpcInfo
  37. );
  38. VOID
  39. DfsInsertSpcInfo(
  40. IN PSPECIAL_HASH_TABLE pHashTable,
  41. IN PUNICODE_STRING pSpecialName,
  42. IN ULONG Timeout,
  43. IN PDFS_SPECIAL_INFO pSpcInfo
  44. );
  45. ULONG
  46. DfsHashSpcName(
  47. IN PUNICODE_STRING SpecialName,
  48. IN DWORD HashMask
  49. );
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text(INIT, DfsInitSpcHashTable)
  52. #pragma alloc_text(PAGE, DfsUninitSpcHashTable)
  53. #pragma alloc_text(PAGE, DfsAllocateSpcInfo)
  54. #pragma alloc_text(PAGE, DfsReleaseSpcInfo)
  55. #pragma alloc_text(PAGE, DfsHashSpcName)
  56. #pragma alloc_text(PAGE, DfsFsctrlCreateSpcInfo)
  57. #pragma alloc_text(PAGE, DfsFsctrlDeleteSpcInfo)
  58. #pragma alloc_text(PAGE, DfsLookupSpcInfo)
  59. #pragma alloc_text(PAGE, DfsInsertSpcInfo)
  60. #pragma alloc_text(PAGE, DfsDeleteSpcInfo)
  61. #endif
  62. #ifdef DBG
  63. VOID
  64. DfsDumpSpcTable(
  65. PSPECIAL_HASH_TABLE pHashTable
  66. );
  67. #endif
  68. //+-------------------------------------------------------------------------
  69. //
  70. // Function: DfsInitSpcHashTable - Initialize the DFS_SPECIAL_INFO lookup hash table
  71. //
  72. // Synopsis: This function initializes data structures which are
  73. // used for looking up a DFS_SPECIAL_INFO.
  74. //
  75. // Arguments: [cHash] -- Size of the hash table to be allocated. Must be
  76. // a power of two. If zero, a default size is used.
  77. //
  78. // Returns: NTSTATUS -- STATUS_SUCCESS, unless memory allocation
  79. // fails.
  80. //
  81. // Note: The hash buckets are initialized to zero, then later
  82. // initialized to a list head when used. This is a debugging
  83. // aid to determine if some hash buckets are never used.
  84. //
  85. //--------------------------------------------------------------------------
  86. NTSTATUS
  87. DfsInitSpcHashTable(
  88. PSPECIAL_HASH_TABLE *ppHashTable,
  89. ULONG cHash)
  90. {
  91. PSPECIAL_HASH_TABLE pHashTable;
  92. ULONG cbHashTable;
  93. NTSTATUS NtStatus = STATUS_SUCCESS;
  94. if (cHash == 0) {
  95. cHash = DEFAULT_HASH_SIZE;
  96. }
  97. ASSERT ((cHash & (cHash-1)) == 0); // Assure cHash is a power of two
  98. cbHashTable = sizeof(SPECIAL_HASH_TABLE) + (cHash-1) * sizeof(LIST_ENTRY);
  99. pHashTable = ExAllocatePoolWithTag(NonPagedPool, cbHashTable, ' sfD');
  100. if (pHashTable == NULL) {
  101. NtStatus = STATUS_NO_MEMORY;
  102. }
  103. if (NT_SUCCESS(NtStatus)) {
  104. pHashTable->NodeTypeCode = DFS_NTC_SPECIAL_HASH;
  105. pHashTable->NodeByteSize = (NODE_BYTE_SIZE) cbHashTable;
  106. pHashTable->HashMask = (cHash-1);
  107. pHashTable->SpcTimeout = 0;
  108. ExInitializeFastMutex( &pHashTable->HashListMutex );
  109. RtlZeroMemory(&pHashTable->HashBuckets[0], cHash * sizeof(LIST_ENTRY));
  110. *ppHashTable = pHashTable;
  111. }
  112. return NtStatus;
  113. }
  114. VOID
  115. DfsUninitSpcHashTable (
  116. PSPECIAL_HASH_TABLE pHashTable
  117. )
  118. {
  119. ExFreePool (pHashTable);
  120. }
  121. //+-------------------------------------------------------------------------
  122. //
  123. // Function: DfsLookupSpcInfo - Lookup a DFS_SPECIAL_INFO in the hash table
  124. //
  125. // Synopsis: This function will lookup a DFS_SPECIAL_INFO.
  126. // It will increment the UseCount on the DFS_SPECIAL_INFO.
  127. //
  128. // Arguments: [SpecialName] -- SpecialName for which the DFS_SPECIAL_INFO is
  129. // being looked up.
  130. //
  131. // Returns: pointer to the DFS_SPECIAL_INFO found, or NULL if none
  132. //
  133. // Algorithm: Knuth would call it hashing with conflict resoulution
  134. // by chaining.
  135. //
  136. //--------------------------------------------------------------------------
  137. PDFS_SPECIAL_INFO
  138. DfsLookupSpcInfo(
  139. PSPECIAL_HASH_TABLE pHashTable,
  140. PUNICODE_STRING SpecialName)
  141. {
  142. PLIST_ENTRY pListHead, pLink;
  143. PDFS_SPECIAL_INFO pSpcInfo;
  144. ExAcquireFastMutex( &pHashTable->HashListMutex );
  145. pListHead = &pHashTable->HashBuckets[ DfsHashSpcName(SpecialName, pHashTable->HashMask) ];
  146. if ((pListHead->Flink == NULL) || // list not initialized
  147. (pListHead->Flink == pListHead)) { // list empty
  148. ExReleaseFastMutex( &pHashTable->HashListMutex );
  149. return NULL;
  150. }
  151. for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
  152. pSpcInfo = CONTAINING_RECORD(pLink, DFS_SPECIAL_INFO, HashChain);
  153. if (RtlCompareUnicodeString(&pSpcInfo->SpecialName,SpecialName,TRUE) == 0) {
  154. pSpcInfo->UseCount++;
  155. ExReleaseFastMutex( &pHashTable->HashListMutex );
  156. return pSpcInfo;
  157. }
  158. }
  159. ExReleaseFastMutex( &pHashTable->HashListMutex );
  160. return NULL;
  161. }
  162. //+-------------------------------------------------------------------------
  163. //
  164. // Function: DfsInsertSpcInfo - Inserts a DFS_SPECIAL_INFO into the hash table
  165. //
  166. // Synopsis: This function associates a DFS_SPECIAL_INFO to a SpecialName. This
  167. // involves removing any existing entry, and adding the new.
  168. //
  169. // Arguments: [pSpcInfo] -- Pointer to the DFS_SPECIAL_INFO to be inserted.
  170. // [Timeout] -- Timeout, in seconds, to put on the special info table
  171. // [pSpecialName] -- Pointer to the corresponding SpecialName name, used
  172. // as the hash key.
  173. //
  174. // Returns: -nothing-
  175. //
  176. //--------------------------------------------------------------------------
  177. VOID
  178. DfsInsertSpcInfo(
  179. PSPECIAL_HASH_TABLE pHashTable,
  180. PUNICODE_STRING pSpecialName,
  181. ULONG Timeout,
  182. PDFS_SPECIAL_INFO pSpcInfo)
  183. {
  184. PLIST_ENTRY pListHead;
  185. PDFS_SPECIAL_INFO pExistingSpcInfo;
  186. pExistingSpcInfo = DfsLookupSpcInfo(
  187. pHashTable,
  188. &pSpcInfo->SpecialName);
  189. //
  190. // Put the new one in
  191. //
  192. ExAcquireFastMutex( &pHashTable->HashListMutex );
  193. pListHead = &pHashTable->HashBuckets[ DfsHashSpcName(pSpecialName, pHashTable->HashMask) ];
  194. if (pListHead->Flink == NULL) {
  195. InitializeListHead(pListHead);
  196. }
  197. InsertHeadList(pListHead, &pSpcInfo->HashChain);
  198. //
  199. // Set timeout to give to clients (global timeout)
  200. //
  201. pHashTable->SpcTimeout = Timeout;
  202. ExReleaseFastMutex( &pHashTable->HashListMutex );
  203. if (pExistingSpcInfo != NULL) {
  204. DfsDeleteSpcInfo(
  205. pHashTable,
  206. pExistingSpcInfo);
  207. DfsReleaseSpcInfo(
  208. pHashTable,
  209. pExistingSpcInfo);
  210. }
  211. DebugTrace(0, Dbg, "Added SpcInfo %08lx ", pSpcInfo);
  212. DebugTrace(0, Dbg, "For SpecialName %wZ ", pSpecialName);
  213. }
  214. //+-------------------------------------------------------------------------
  215. //
  216. // Function: DfsDeleteSpcInfo - Delete a DFS_SPECIAL_INFO from the lookup hash table
  217. //
  218. // Synopsis: This function Deletes a DFS_SPECIAL_INFO from the hash table.
  219. //
  220. // Arguments: [pSpcInfo] -- Pointer to the DFS_SPECIAL_INFO to delete
  221. //
  222. // Returns: -nothing-
  223. //
  224. //--------------------------------------------------------------------------
  225. VOID
  226. DfsDeleteSpcInfo(
  227. PSPECIAL_HASH_TABLE pHashTable,
  228. PDFS_SPECIAL_INFO pSpcInfo)
  229. {
  230. ExAcquireFastMutex( &pHashTable->HashListMutex);
  231. pSpcInfo->Flags |= SPECIAL_INFO_DELETE_PENDING;
  232. RemoveEntryList(&pSpcInfo->HashChain);
  233. //
  234. // This InitializeListHead is to prevent two simultaneous deleters
  235. // from corrupting memory
  236. //
  237. InitializeListHead( &pSpcInfo->HashChain );
  238. ExReleaseFastMutex( &pHashTable->HashListMutex );
  239. DebugTrace(0, Dbg, "deleted SpcInfo %08lx ", pSpcInfo);
  240. DebugTrace(0, Dbg, "For SpecialName %wZ ", &pSpcInfo->SpecialName);
  241. }
  242. //+----------------------------------------------------------------------------
  243. //
  244. // Function: DfsAllocateSpcInfo - Allocate a DFS_SPECIAL_INFO
  245. //
  246. // Synopsis: This function allocates a contiguous DFS_SPECIAL_INFO struct. The
  247. // strings are stored in the allocated buffer after the DFS_SPECIAL_INFO
  248. // structure.
  249. //
  250. // Arguments: [pSpecialName] -- The SpecialName name for the spc list
  251. // [TypeFlags] -- Indicates PRIMARY/SECONDARY and NETBIOS/DNS
  252. // [TimeToLive] -- Time, in seconds, for this entry to live
  253. // [NameCount] -- Number of names
  254. // [pNames] -- pointer to array (of size NameCount) of names
  255. // [ppSpcInfo] -- On successful return, has pointer to newly allocated
  256. // DFS_SPECIAL_INFO.
  257. //
  258. // Returns: [STATUS_SUCCESS] -- Successfully allocated DFS_SPECIAL_INFO
  259. //
  260. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition
  261. //
  262. //-----------------------------------------------------------------------------
  263. NTSTATUS
  264. DfsAllocateSpcInfo(
  265. PUNICODE_STRING pSpecialName,
  266. ULONG TypeFlags,
  267. ULONG TrustDirection,
  268. ULONG TrustType,
  269. ULONG TimeToLive,
  270. LONG NameCount,
  271. PUNICODE_STRING pNames,
  272. PDFS_SPECIAL_INFO *ppSpcInfo)
  273. {
  274. NTSTATUS status;
  275. PDFS_SPECIAL_INFO pSpcInfo;
  276. ULONG Size;
  277. LONG i;
  278. LPWSTR pwCh;
  279. PUNICODE_STRING pustr;
  280. LARGE_INTEGER now;
  281. DebugTrace(0, Dbg, "DfsAllocateSpcInfo(%wZ)\n", pSpecialName);
  282. //
  283. // Size the buffer - include storage for the unicode strings after the
  284. // DFS_SPECIAL_INFO structure.
  285. //
  286. Size = sizeof(DFS_SPECIAL_INFO) +
  287. pSpecialName->Length;
  288. if (NameCount > 1) {
  289. Size += (sizeof(UNICODE_STRING) * (NameCount - 1));
  290. }
  291. for (i = 0; i < NameCount; i++) {
  292. Size += pNames[i].Length;
  293. }
  294. pSpcInfo = (PDFS_SPECIAL_INFO) ExAllocatePoolWithTag( NonPagedPool, Size, ' sfD' );
  295. if (pSpcInfo != NULL) {
  296. RtlZeroMemory( pSpcInfo, Size );
  297. pSpcInfo->NodeTypeCode = DFS_NTC_SPECIAL_INFO;
  298. pSpcInfo->NodeByteSize = (USHORT)Size;
  299. pwCh = (LPWSTR) &pSpcInfo->Name[NameCount < 0 ? 0 : NameCount];
  300. pustr = &pSpcInfo->SpecialName;
  301. pustr->Length = pustr->MaximumLength = pSpecialName->Length;
  302. pustr->Buffer = pwCh;
  303. RtlCopyMemory(pwCh, pSpecialName->Buffer, pSpecialName->Length);
  304. pwCh += pustr->Length / sizeof(WCHAR);
  305. if (pustr->Length > ((MAX_SPCNAME_LEN - 1) * sizeof(WCHAR))) {
  306. pSpcInfo->Flags |= SPECIAL_INFO_IS_LONG_NAME;
  307. }
  308. KeQuerySystemTime(&now);
  309. pSpcInfo->NameCount = NameCount;
  310. pSpcInfo->TypeFlags = TypeFlags;
  311. pSpcInfo->TrustDirection = TrustDirection;
  312. pSpcInfo->TrustType = TrustType;
  313. pSpcInfo->ExpireTime.QuadPart = now.QuadPart + UInt32x32To64(
  314. TimeToLive,
  315. 10 * 1000 * 1000);
  316. for (i = 0; i < NameCount; i++) {
  317. pustr = &pSpcInfo->Name[i];
  318. pustr->Length = pustr->MaximumLength = pNames[i].Length;
  319. pustr->Buffer = pwCh;
  320. RtlCopyMemory(pwCh, pNames[i].Buffer, pNames[i].Length);
  321. pwCh += pustr->Length / sizeof(WCHAR);
  322. }
  323. *ppSpcInfo = pSpcInfo;
  324. status = STATUS_SUCCESS;
  325. DebugTrace(0, Dbg, "DfsAllocateSpcInfo pSpcInfo = %d\n", pSpcInfo);
  326. } else {
  327. status = STATUS_INSUFFICIENT_RESOURCES;
  328. }
  329. return( status );
  330. }
  331. //+----------------------------------------------------------------------------
  332. //
  333. // Function: DfsReleaseSpcInfo
  334. //
  335. // Synopsis: Decrements UseCount of and possibly frees a DFS_SPECIAL_INFO
  336. //
  337. // Arguments: [pSpcInfo] -- The DFS_SPECIAL_INFO to release
  338. //
  339. // Returns: Nothing
  340. //
  341. //-----------------------------------------------------------------------------
  342. VOID
  343. DfsReleaseSpcInfo(
  344. PSPECIAL_HASH_TABLE pHashTable,
  345. PDFS_SPECIAL_INFO pSpcInfo)
  346. {
  347. //
  348. // There's a potential race with DfsDeleteSpcInfo's setting of the
  349. // DELETE_PENDING and the test below of DELETE_PENDING, so we still have
  350. // to acquire the lock to safely test the DELETE_PENDING bit.
  351. //
  352. ExAcquireFastMutex( &pHashTable->HashListMutex );
  353. pSpcInfo->UseCount--;
  354. if ((pSpcInfo->Flags & SPECIAL_INFO_DELETE_PENDING) != 0 && pSpcInfo->UseCount == 0) {
  355. ExFreePool(pSpcInfo);
  356. }
  357. ExReleaseFastMutex( &pHashTable->HashListMutex );
  358. }
  359. //+----------------------------------------------------------------------------
  360. //
  361. // Function: DfsSpcInfoFindOpen
  362. //
  363. // Synopsis: Notifies the table that the first/next calls are about to start
  364. //
  365. // Arguments: None.
  366. //
  367. // Returns: Nothing.
  368. //
  369. //-----------------------------------------------------------------------------
  370. VOID
  371. DfsSpcInfoFindOpen(
  372. PSPECIAL_HASH_TABLE pHashTable)
  373. {
  374. ExAcquireFastMutex( &pHashTable->HashListMutex );
  375. }
  376. //+----------------------------------------------------------------------------
  377. //
  378. // Function: DfsSpcInfoFindFirst
  379. //
  380. // Synopsis: Gets the first entry in the Special table.
  381. //
  382. // Arguments: None.
  383. //
  384. // Returns: [pSpcInfo] -- The first entry in the table.
  385. //
  386. //-----------------------------------------------------------------------------
  387. PDFS_SPECIAL_INFO
  388. DfsSpcInfoFindFirst(
  389. PSPECIAL_HASH_TABLE pHashTable)
  390. {
  391. PLIST_ENTRY pListHead, pLink;
  392. PDFS_SPECIAL_INFO pSpcInfo;
  393. ULONG i, j;
  394. for (i = 0; i <= pHashTable->HashMask; i++) {
  395. pListHead = &pHashTable->HashBuckets[i];
  396. if ((pListHead->Flink == NULL) || // list not initialized
  397. (pListHead->Flink == pListHead)) { // list empty
  398. continue;
  399. }
  400. pLink = pListHead->Flink;
  401. pSpcInfo = CONTAINING_RECORD(pLink, DFS_SPECIAL_INFO, HashChain);
  402. return pSpcInfo;
  403. }
  404. //
  405. // Table is empty. Return NULL
  406. //
  407. return NULL;
  408. }
  409. //+----------------------------------------------------------------------------
  410. //
  411. // Function: DfsSpcInfoFindNext
  412. //
  413. // Synopsis: Gets the next entry in the Special table.
  414. //
  415. // Arguments: [pSpcInfo] -- The current DFS_SPECIAL_INFO entry.
  416. //
  417. // Returns: [pSpcInfo] -- The next DFS_SPECIAL_INFO entry in the table.
  418. // NULL - No more entries
  419. //
  420. //-----------------------------------------------------------------------------
  421. PDFS_SPECIAL_INFO
  422. DfsSpcInfoFindNext(
  423. PSPECIAL_HASH_TABLE pHashTable,
  424. PDFS_SPECIAL_INFO pSpcInfo)
  425. {
  426. PLIST_ENTRY pListHead, pLink;
  427. ULONG i, j;
  428. //
  429. // Point to the next entry. It might be a hash chain head!!!
  430. //
  431. pLink = pSpcInfo->HashChain.Flink;
  432. //
  433. // See if we're pointing to the head
  434. //
  435. for (i = 0; i <= pHashTable->HashMask; i++) {
  436. if (pLink == &pHashTable->HashBuckets[i]) {
  437. //
  438. // We're in hash chain i, and we hit the end.
  439. // Go to the next chain.
  440. //
  441. for (j = i+1; j <= pHashTable->HashMask; j++) {
  442. pListHead = &pHashTable->HashBuckets[j];
  443. if ((pListHead->Flink == NULL) || // list not initialized
  444. (pListHead->Flink == pListHead)) { // list empty
  445. continue;
  446. }
  447. //
  448. // We found another hash chain. Point to the 1st entry
  449. //
  450. pLink = pListHead->Flink;
  451. pSpcInfo = CONTAINING_RECORD(pLink, DFS_SPECIAL_INFO, HashChain);
  452. return pSpcInfo;
  453. }
  454. //
  455. // We got to the end without finding any more entries.
  456. //
  457. return NULL;
  458. }
  459. }
  460. //
  461. // Still in the same hash chain, and there's an entry after this one
  462. //
  463. pSpcInfo = CONTAINING_RECORD(pLink, DFS_SPECIAL_INFO, HashChain);
  464. return pSpcInfo;
  465. }
  466. //+----------------------------------------------------------------------------
  467. //
  468. // Function: DfsSpcInfoFindClose
  469. //
  470. // Synopsis: Notifies the table that the first/next calls are complete.
  471. //
  472. // Arguments: None.
  473. //
  474. // Returns: Nothing.
  475. //
  476. //-----------------------------------------------------------------------------
  477. VOID
  478. DfsSpcInfoFindClose(
  479. PSPECIAL_HASH_TABLE pHashTable)
  480. {
  481. ExReleaseFastMutex( &pHashTable->HashListMutex );
  482. }
  483. //+----------------------------------------------------------------------------
  484. //
  485. // Function: DfsHashSpcNames
  486. //
  487. // Synopsis: Generates a hash 0-N - ignores case
  488. //
  489. // Arguments: [pSpecialName] -- The SpecialName name to hash
  490. //
  491. // Returns: Nothing
  492. //
  493. // Notes: Might need to convert DNS-style names to short names (??)
  494. //
  495. //-----------------------------------------------------------------------------
  496. ULONG
  497. DfsHashSpcName(
  498. PUNICODE_STRING SpecialName,
  499. DWORD HashMask)
  500. {
  501. ULONG BucketNo = 0;
  502. WCHAR *pBuffer = SpecialName->Buffer;
  503. WCHAR *pBufferEnd = &pBuffer[SpecialName->Length / sizeof(WCHAR)];
  504. ULONG wCh;
  505. BucketNo = 0;
  506. while (pBuffer != pBufferEnd) {
  507. wCh = (*pBuffer < L'a')
  508. ? *pBuffer
  509. : ((*pBuffer < L'z')
  510. ? (*pBuffer - L'a' + L'A')
  511. : RtlUpcaseUnicodeChar(*pBuffer));
  512. BucketNo *= 131;
  513. BucketNo += wCh;
  514. pBuffer++;
  515. }
  516. BucketNo = BucketNo & HashMask;
  517. return BucketNo;
  518. }
  519. //+-------------------------------------------------------------------------
  520. //
  521. // Function: DfsFsctrlCreateSpcInfo, public
  522. //
  523. // Synopsis:
  524. //
  525. // Arguments:
  526. //
  527. // Returns:
  528. //
  529. //--------------------------------------------------------------------------
  530. NTSTATUS
  531. DfsFsctrlCreateSpcInfo(
  532. PSPECIAL_HASH_TABLE pHashTable,
  533. PIRP Irp,
  534. PVOID InputBuffer,
  535. ULONG InputBufferLength)
  536. {
  537. NTSTATUS status = STATUS_SUCCESS;
  538. PDFS_CREATE_SPECIAL_INFO_ARG arg;
  539. PDFS_SPECIAL_INFO pSpcInfo;
  540. PDFS_SPECIAL_INFO pExistingSpcInfo = NULL;
  541. LONG i;
  542. ULONG Size;
  543. STD_FSCTRL_PROLOGUE(DfsFsctrlCreateSpcInfo, TRUE, FALSE);
  544. //
  545. // Namecount can be -1 as a special case (names need to be expanded)
  546. //
  547. arg = (PDFS_CREATE_SPECIAL_INFO_ARG) InputBuffer;
  548. if (InputBufferLength < sizeof(DFS_CREATE_SPECIAL_INFO_ARG) ||
  549. arg->NameCount < -1 ) {
  550. status = STATUS_INVALID_PARAMETER;
  551. goto exit_with_status;
  552. }
  553. //
  554. // unmarshal the arguments...
  555. //
  556. Size = InputBufferLength - FIELD_OFFSET(DFS_CREATE_SPECIAL_INFO_ARG, Name);
  557. OFFSET_TO_POINTER(arg->SpecialName.Buffer, arg);
  558. if (!UNICODESTRING_IS_VALID(arg->SpecialName, InputBuffer, InputBufferLength)) {
  559. status = STATUS_INVALID_PARAMETER;
  560. goto exit_with_status;
  561. }
  562. for (i = 0; i < arg->NameCount; i++) {
  563. //
  564. // Make sure we haven't overrun the buffer supplied!
  565. //
  566. if( (PBYTE)(&arg->Name[i]) + sizeof(arg->Name[i]) >
  567. (PBYTE)InputBuffer + InputBufferLength ) {
  568. status = STATUS_INVALID_PARAMETER;
  569. goto exit_with_status;
  570. }
  571. OFFSET_TO_POINTER(arg->Name[i].Buffer, arg);
  572. if (!UNICODESTRING_IS_VALID(arg->Name[i], InputBuffer, InputBufferLength)) {
  573. status = STATUS_INVALID_PARAMETER;
  574. goto exit_with_status;
  575. }
  576. }
  577. status = DfsAllocateSpcInfo(
  578. &arg->SpecialName,
  579. arg->Flags,
  580. arg->TrustDirection,
  581. arg->TrustType,
  582. arg->Timeout,
  583. arg->NameCount,
  584. &arg->Name[0],
  585. &pSpcInfo);
  586. if (NT_SUCCESS(status)) {
  587. if (pSpcInfo->NameCount >= 0) {
  588. DfsInsertSpcInfo(
  589. pHashTable,
  590. &arg->SpecialName,
  591. arg->Timeout,
  592. pSpcInfo);
  593. } else {
  594. pExistingSpcInfo = DfsLookupSpcInfo(
  595. pHashTable,
  596. &pSpcInfo->SpecialName);
  597. if (pExistingSpcInfo == NULL) {
  598. DfsInsertSpcInfo(
  599. pHashTable,
  600. &arg->SpecialName,
  601. arg->Timeout,
  602. pSpcInfo);
  603. } else {
  604. pHashTable->SpcTimeout = arg->Timeout;
  605. pExistingSpcInfo->ExpireTime.QuadPart = 0;
  606. DfsReleaseSpcInfo(pHashTable, pExistingSpcInfo);
  607. ExFreePool(pSpcInfo);
  608. }
  609. }
  610. }
  611. exit_with_status:
  612. DfsCompleteRequest( Irp, status );
  613. DebugTrace(-1, Dbg,
  614. "DfsFsctrlCreateSpcInfo: Exit -> %08lx\n", ULongToPtr( status ) );
  615. return status;
  616. }
  617. //+-------------------------------------------------------------------------
  618. //
  619. // Function: DfsFsctrlDeleteSpcInfo, public
  620. //
  621. // Synopsis:
  622. //
  623. // Arguments:
  624. //
  625. // Returns:
  626. //
  627. // Notes: We only process this FSCTRL from the file system process,
  628. // never from the driver.
  629. //
  630. //--------------------------------------------------------------------------
  631. NTSTATUS
  632. DfsFsctrlDeleteSpcInfo(
  633. PSPECIAL_HASH_TABLE pHashTable,
  634. PIRP Irp,
  635. PVOID InputBuffer,
  636. ULONG InputBufferLength)
  637. {
  638. NTSTATUS status = STATUS_SUCCESS;
  639. PDFS_DELETE_SPECIAL_INFO_ARG arg;
  640. PDFS_SPECIAL_INFO pSpcInfo;
  641. STD_FSCTRL_PROLOGUE(DfsFsctrlDeleteSpcInfo, TRUE, FALSE);
  642. if (InputBufferLength < sizeof(DFS_DELETE_SPECIAL_INFO_ARG)) {
  643. status = STATUS_INVALID_PARAMETER;
  644. goto exit_with_status;
  645. }
  646. //
  647. // unmarshal the arguments...
  648. //
  649. arg = (PDFS_DELETE_SPECIAL_INFO_ARG) InputBuffer;
  650. OFFSET_TO_POINTER(arg->SpecialName.Buffer, arg);
  651. if (!UNICODESTRING_IS_VALID(arg->SpecialName, InputBuffer, InputBufferLength)) {
  652. status = STATUS_INVALID_PARAMETER;
  653. goto exit_with_status;
  654. }
  655. pSpcInfo = DfsLookupSpcInfo(
  656. pHashTable,
  657. &arg->SpecialName);
  658. //
  659. // The DfsLookupSpcInfo() call bumped the usecount, so we're sure pSpcInfo
  660. // won't become invalid as we're using it.
  661. //
  662. if (pSpcInfo != NULL) {
  663. //
  664. // Removes from the table, but doesn't free the memory
  665. //
  666. DfsDeleteSpcInfo(
  667. pHashTable,
  668. pSpcInfo);
  669. //
  670. // This will decrement the usecount, and if it goes to zero, frees the memory
  671. //
  672. DfsReleaseSpcInfo(
  673. pHashTable,
  674. pSpcInfo);
  675. }
  676. exit_with_status:
  677. DfsCompleteRequest( Irp, status );
  678. DebugTrace(-1, Dbg,
  679. "DfsFsctrlDeleteSpcInfo: Exit -> %08lx\n", ULongToPtr( status ));
  680. return status;
  681. }
  682. #ifdef DBG
  683. VOID
  684. DfsDumpSpcTable(
  685. PSPECIAL_HASH_TABLE pHashTable)
  686. {
  687. PLIST_ENTRY pListHead, pLink;
  688. PDFS_SPECIAL_INFO pSpcInfo;
  689. LONG i, j;
  690. DbgPrint("---------Spc Table----------\n");
  691. DbgPrint("\tTimeout=0x%x(%d)\n", pHashTable->SpcTimeout);
  692. DfsSpcInfoFindOpen(pHashTable);
  693. for (pSpcInfo = DfsSpcInfoFindFirst(pHashTable);
  694. pSpcInfo != NULL;
  695. pSpcInfo = DfsSpcInfoFindNext(pHashTable,pSpcInfo)) {
  696. DbgPrint("\t[%wZ][%d]", &pSpcInfo->SpecialName, pSpcInfo->NameCount);
  697. for (j = 0; j < pSpcInfo->NameCount; j++) {
  698. DbgPrint("(%wZ)", &pSpcInfo->Name[j]);
  699. }
  700. DbgPrint("\n");
  701. }
  702. DfsSpcInfoFindClose(pHashTable);
  703. DbgPrint("-----------------------------\n");
  704. }
  705. #endif
  706. NTSTATUS
  707. DfsFsctrlGetDomainToRefresh(
  708. PIRP Irp,
  709. PVOID OutputBuffer,
  710. ULONG OutputBufferLength)
  711. {
  712. LPWSTR Buffer;
  713. BOOLEAN Found = FALSE;
  714. PSPECIAL_HASH_TABLE pHashTable;
  715. ULONG i;
  716. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  717. PLIST_ENTRY pListHead, pLink;
  718. PDFS_SPECIAL_INFO pSpcInfo;
  719. PUNICODE_STRING pustr;
  720. pHashTable = DfsData.SpcHashTable;
  721. ExAcquireFastMutex( &pHashTable->HashListMutex );
  722. for (i = 0; (i <= pHashTable->HashMask) && (Found == FALSE); i++) {
  723. pListHead = &pHashTable->HashBuckets[i];
  724. if ((pListHead->Flink == NULL) || // list not initialized
  725. (pListHead->Flink == pListHead)) { // list empty
  726. continue;
  727. }
  728. for(pLink = pListHead->Flink;
  729. (pLink) && (Found == FALSE);
  730. pLink = pSpcInfo->HashChain.Flink) {
  731. if (pLink == pListHead) {
  732. break;
  733. }
  734. pSpcInfo = CONTAINING_RECORD(pLink, DFS_SPECIAL_INFO, HashChain);
  735. if (pSpcInfo->Flags & SPECIAL_INFO_NEEDS_REFRESH) {
  736. pSpcInfo->Flags &= ~SPECIAL_INFO_NEEDS_REFRESH;
  737. pustr = &pSpcInfo->SpecialName;
  738. if (pustr->Length < (OutputBufferLength - sizeof(WCHAR))) {
  739. RtlCopyMemory(OutputBuffer, pustr->Buffer, pustr->Length);
  740. Buffer = OutputBuffer;
  741. Buffer += (pustr->Length / sizeof(WCHAR));
  742. *Buffer = UNICODE_NULL;
  743. Irp->IoStatus.Information = pustr->Length + sizeof(WCHAR);
  744. Status = STATUS_SUCCESS;
  745. Found = TRUE;
  746. break;
  747. }
  748. }
  749. }
  750. }
  751. ExReleaseFastMutex( &pHashTable->HashListMutex );
  752. DfsCompleteRequest( Irp, Status );
  753. return Status;
  754. }