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.

1578 lines
48 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. replutil.h
  5. Abstract:
  6. Header file for utility routines for the NT File Replication Service.
  7. Author:
  8. David A. Orbits (davidor) 3-Mar-1997 Created
  9. Environment:
  10. User Mode Service
  11. Revision History:
  12. --*/
  13. #ifndef _REPLUTIL_INCLUDED_
  14. #define _REPLUTIL_INCLUDED_
  15. #endif
  16. #ifdef __cplusplus
  17. extern "C" {
  18. #endif
  19. #include <frserror.h>
  20. #include <config.h>
  21. #define BACKSLASH_CHAR TEXT('\\')
  22. #define COLON_CHAR TEXT(':')
  23. #define DOT_CHAR TEXT('.')
  24. #define UNICODE_STAR (L'*')
  25. #define UNICODE_QMARK (L'?')
  26. #define UNICODE_SPACE 0x0020
  27. #define UNICODE_TAB 0x0009
  28. #define TIME_STRING_LENGTH 32
  29. //
  30. // The maximum length of a volume label. This is defined in ntos\inc\io.h
  31. // but since this is the only def needed from io.h it is copied here. sigh!
  32. //
  33. #define MAXIMUM_VOLUME_LABEL_LENGTH (32 * sizeof(WCHAR)) // 32 characters
  34. #define GUID_CHAR_LEN 40
  35. #define OBJECT_ID_LENGTH sizeof(GUID)
  36. #define FILE_ID_LENGTH sizeof(ULONGLONG)
  37. #define GUIDS_EQUAL(_a_, _b_) (memcmp((_a_), (_b_), sizeof(GUID)) == 0)
  38. #define COPY_GUID(_a_, _b_) CopyMemory((_a_), (_b_), sizeof(GUID))
  39. #define IS_GUID_ZERO(_g_) ((*((PULONG)(_g_)+0) | \
  40. *((PULONG)(_g_)+1) | \
  41. *((PULONG)(_g_)+2) | \
  42. *((PULONG)(_g_)+3) ) == 0)
  43. #define COPY_TIME(_a_, _b_) CopyMemory((_a_), (_b_), sizeof(FILETIME))
  44. #define IS_TIME_ZERO(_g_) ((*((PULONG)(&(_g_))+0) | *((PULONG)(&(_g_))+1) ) == 0)
  45. //
  46. // A few macros for working with MD5 checksums.
  47. //
  48. #define IS_MD5_CHKSUM_ZERO(_x_) \
  49. (((*(((PULONG) (_x_))+0)) | (*(((PULONG) (_x_))+1)) | \
  50. (*(((PULONG) (_x_))+2)) | (*(((PULONG) (_x_))+3)) ) == (ULONG) 0)
  51. #define MD5_EQUAL(_a_, _b_) (memcmp((_a_), (_b_), MD5DIGESTLEN) == 0)
  52. //
  53. // Is a handle valid?
  54. // Some functions set the handle to NULL and some to
  55. // INVALID_HANDLE_VALUE (-1). This define handles both
  56. // cases.
  57. //
  58. #define HANDLE_IS_VALID(_Handle) ((_Handle) && ((_Handle) != INVALID_HANDLE_VALUE))
  59. //
  60. // Only close valid handles and then set the handle invalid.
  61. // FRS_CLOSE(handle);
  62. //
  63. #define FRS_CLOSE(_Handle) \
  64. if (HANDLE_IS_VALID(_Handle)) { \
  65. CloseHandle(_Handle); \
  66. (_Handle) = INVALID_HANDLE_VALUE; \
  67. }
  68. DWORD
  69. FrsResetAttributesForReplication(
  70. PWCHAR Name,
  71. HANDLE Handle
  72. );
  73. LONG
  74. FrsIsParent(
  75. IN PWCHAR Directory,
  76. IN PWCHAR Path
  77. );
  78. LPTSTR
  79. FrsSupInitPath(
  80. OUT LPTSTR OutPath,
  81. IN LPTSTR InPath,
  82. IN ULONG MaxOutPath
  83. );
  84. ULONG
  85. FrsForceDeleteFile(
  86. PTCHAR DestName
  87. );
  88. HANDLE
  89. FrsCreateEvent(
  90. IN BOOL ManualReset,
  91. IN BOOL InitialState
  92. );
  93. HANDLE
  94. FrsCreateWaitableTimer(
  95. IN BOOL ManualReset
  96. );
  97. ULONG
  98. FrsUuidCreate(
  99. OUT GUID *Guid
  100. );
  101. VOID
  102. FrsNowAsFileTime(
  103. IN PLONGLONG Now
  104. );
  105. VOID
  106. FileTimeToString(
  107. IN FILETIME *FileTime,
  108. OUT PCHAR Buffer // buffer must be at least 32 bytes long.
  109. );
  110. VOID
  111. FileTimeToStringClockTime(
  112. IN FILETIME *FileTime,
  113. OUT PCHAR Buffer // buffer must be at least 9 bytes long.
  114. );
  115. VOID
  116. GuidToStr(
  117. IN GUID *pGuid,
  118. OUT PCHAR s
  119. );
  120. VOID
  121. GuidToStrW(
  122. IN GUID *pGuid,
  123. OUT PWCHAR ws
  124. );
  125. BOOL
  126. StrWToGuid(
  127. IN PWCHAR ws,
  128. OUT GUID *pGuid
  129. );
  130. VOID
  131. StrToGuid(
  132. IN PCHAR s,
  133. OUT GUID *pGuid
  134. );
  135. NTSTATUS
  136. SetupOnePrivilege (
  137. ULONG Privilege,
  138. PUCHAR PrivilegeName
  139. );
  140. PWCHAR
  141. FrsGetResourceStr(
  142. LONG Id
  143. );
  144. //
  145. // Convenient DesiredAccess
  146. //
  147. #define READ_ATTRIB_ACCESS (FILE_READ_ATTRIBUTES | SYNCHRONIZE)
  148. #define WRITE_ATTRIB_ACCESS (FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)
  149. #define READ_ACCESS (GENERIC_READ | GENERIC_EXECUTE | SYNCHRONIZE)
  150. #define ATTR_ACCESS (READ_ACCESS | FILE_WRITE_ATTRIBUTES)
  151. #define WRITE_ACCESS (GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE)
  152. #define RESTORE_ACCESS (READ_ACCESS | \
  153. WRITE_ACCESS | \
  154. WRITE_DAC | \
  155. WRITE_OWNER)
  156. #define OPLOCK_ACCESS (FILE_READ_ATTRIBUTES)
  157. //
  158. // Convenient CreateOptions
  159. //
  160. #define OPEN_OPTIONS (FILE_OPEN_FOR_BACKUP_INTENT | \
  161. FILE_SEQUENTIAL_ONLY | \
  162. FILE_OPEN_NO_RECALL | \
  163. FILE_OPEN_REPARSE_POINT | \
  164. FILE_SYNCHRONOUS_IO_NONALERT)
  165. #define ID_OPTIONS (OPEN_OPTIONS | FILE_OPEN_BY_FILE_ID)
  166. #define OPEN_OPLOCK_OPTIONS (FILE_RESERVE_OPFILTER | FILE_OPEN_REPARSE_POINT)
  167. #define ID_OPLOCK_OPTIONS (FILE_OPEN_FOR_BACKUP_INTENT | \
  168. FILE_RESERVE_OPFILTER | \
  169. FILE_OPEN_REPARSE_POINT | \
  170. FILE_OPEN_BY_FILE_ID)
  171. //
  172. // convenient ShareMode
  173. //
  174. #define SHARE_ALL (FILE_SHARE_READ | \
  175. FILE_SHARE_WRITE | \
  176. FILE_SHARE_DELETE)
  177. #define SHARE_NONE (0)
  178. //
  179. // File attributes that prevent installation and prevent
  180. // hammering the object id.
  181. //
  182. #define NOREPL_ATTRIBUTES (FILE_ATTRIBUTE_READONLY | \
  183. FILE_ATTRIBUTE_SYSTEM | \
  184. FILE_ATTRIBUTE_HIDDEN)
  185. DWORD
  186. FrsOpenSourceFileW(
  187. OUT PHANDLE Handle,
  188. IN LPCWSTR lpFileName,
  189. IN ACCESS_MASK DesiredAccess,
  190. IN ULONG CreateOptions
  191. );
  192. DWORD
  193. FrsOpenSourceFile2W(
  194. OUT PHANDLE Handle,
  195. IN LPCWSTR lpFileName,
  196. IN ACCESS_MASK DesiredAccess,
  197. IN ULONG CreateOptions,
  198. IN ULONG ShareMode
  199. );
  200. DWORD
  201. FrsCheckReparse(
  202. IN PWCHAR Name,
  203. IN PVOID Id,
  204. IN DWORD IdLen,
  205. IN HANDLE VolumeHandle
  206. );
  207. DWORD
  208. FrsDeleteReparsePoint(
  209. IN HANDLE Handle
  210. );
  211. DWORD
  212. FrsChaseSymbolicLink(
  213. IN PWCHAR SymLink,
  214. OUT PWCHAR *OutPrintName,
  215. OUT PWCHAR *OutSubstituteName
  216. );
  217. DWORD
  218. FrsTraverseReparsePoints(
  219. IN PWCHAR SuppliedPath,
  220. OUT PWCHAR *RealPath
  221. );
  222. DWORD
  223. FrsOpenSourceFileById(
  224. OUT PHANDLE Handle,
  225. OUT PFILE_NETWORK_OPEN_INFORMATION FileOpenInfo,
  226. OUT OVERLAPPED *OverLap,
  227. IN HANDLE VolumeHandle,
  228. IN PVOID ObjectId,
  229. IN ULONG Length,
  230. IN ACCESS_MASK DesiredAccess,
  231. IN ULONG CreateOptions,
  232. IN ULONG ShareMode,
  233. IN ULONG CreateDispostion
  234. );
  235. PWCHAR
  236. FrsGetFullPathByHandle(
  237. IN PWCHAR Name,
  238. IN HANDLE Handle
  239. );
  240. PWCHAR
  241. FrsGetRelativePathByHandle(
  242. IN PWCHAR Name,
  243. IN HANDLE Handle
  244. );
  245. DWORD
  246. FrsCreateFileRelativeById(
  247. OUT PHANDLE Handle,
  248. IN HANDLE VolumeHandle,
  249. IN PVOID ParentObjectId,
  250. IN ULONG OidLength,
  251. IN ULONG FileCreateAttributes,
  252. IN PWCHAR BaseFileName,
  253. IN USHORT FileNameLength,
  254. IN PLARGE_INTEGER AllocationSize,
  255. IN ULONG CreateDisposition,
  256. IN ACCESS_MASK DesiredAccess
  257. );
  258. DWORD
  259. FrsOpenFileRelativeByName(
  260. IN HANDLE VolumeHandle,
  261. IN PULONGLONG FileReferenceNumber,
  262. IN PWCHAR FileName,
  263. IN GUID *ParentGuid,
  264. IN GUID *FileGuid,
  265. OUT HANDLE *Handle
  266. );
  267. typedef struct _QHASH_TABLE_ QHASH_TABLE, *PQHASH_TABLE;
  268. DWORD
  269. FrsDeleteFileRelativeByName(
  270. IN HANDLE VolumeHandle,
  271. IN GUID *ParentGuid,
  272. IN PWCHAR FileName,
  273. IN PQHASH_TABLE FrsWriteFilter
  274. );
  275. DWORD
  276. FrsDeleteFileObjectId(
  277. IN HANDLE Handle,
  278. IN LPCWSTR FileName
  279. );
  280. DWORD
  281. FrsGetOrSetFileObjectId(
  282. IN HANDLE Handle,
  283. IN LPCWSTR FileName,
  284. IN BOOL CallerSupplied,
  285. OUT PFILE_OBJECTID_BUFFER ObjectIdBuffer
  286. );
  287. DWORD
  288. FrsReadFileUsnData(
  289. IN HANDLE Handle,
  290. OUT USN *UsnBuffer
  291. );
  292. DWORD
  293. FrsMarkHandle(
  294. IN HANDLE VolumeHandle,
  295. IN HANDLE Handle
  296. );
  297. DWORD
  298. FrsReadFileParentFid(
  299. IN HANDLE Handle,
  300. OUT ULONGLONG *ParentFid
  301. );
  302. DWORD
  303. FrsDeletePath(
  304. IN PWCHAR Path,
  305. IN DWORD DirectoryFlags
  306. );
  307. DWORD
  308. FrsRestrictAccessToFileOrDirectory(
  309. PWCHAR Name,
  310. HANDLE Handle,
  311. BOOL NoInherit
  312. );
  313. VOID
  314. FrsAddToMultiString(
  315. IN PWCHAR AddStr,
  316. IN OUT DWORD *IOSize,
  317. IN OUT DWORD *IOIdx,
  318. IN OUT PWCHAR *IOStr
  319. );
  320. VOID
  321. FrsCatToMultiString(
  322. IN PWCHAR CatStr,
  323. IN OUT DWORD *IOSize,
  324. IN OUT DWORD *IOIdx,
  325. IN OUT PWCHAR *IOStr
  326. );
  327. BOOL
  328. FrsSearchArgv(
  329. IN LONG ArgC,
  330. IN PWCHAR *ArgV,
  331. IN PWCHAR ArgKey,
  332. OUT PWCHAR *ArgValue
  333. );
  334. BOOL
  335. FrsSearchArgvDWord(
  336. IN LONG ArgC,
  337. IN PWCHAR *ArgV,
  338. IN PWCHAR ArgKey,
  339. OUT PDWORD ArgValue
  340. );
  341. BOOL
  342. FrsDissectCommaList (
  343. IN UNICODE_STRING RawArg,
  344. OUT PUNICODE_STRING FirstArg,
  345. OUT PUNICODE_STRING RemainingArg
  346. );
  347. BOOL
  348. FrsCheckNameFilter(
  349. IN PUNICODE_STRING Name,
  350. IN PLIST_ENTRY FilterListHead
  351. );
  352. VOID
  353. FrsEmptyNameFilter(
  354. IN PLIST_ENTRY FilterListHead
  355. );
  356. VOID
  357. FrsLoadNameFilter(
  358. IN PUNICODE_STRING FilterString,
  359. IN PLIST_ENTRY FilterListHead
  360. );
  361. ULONG
  362. FrsParseIntegerCommaList(
  363. IN PWCHAR ArgString,
  364. IN ULONG MaxResults,
  365. OUT PLONG Results,
  366. OUT PULONG NumberResults,
  367. OUT PULONG Offset
  368. );
  369. //
  370. // Unicode Name support routines, implemented in Name.c
  371. //
  372. // The routines here are used to manipulate unicode names
  373. // The code is copied here from FsRtl because it calls the pool allocator.
  374. //
  375. //
  376. // The following macro is used to determine if a character is wild.
  377. //
  378. #define FrsIsUnicodeCharacterWild(C) ( \
  379. (((C) == UNICODE_STAR) || ((C) == UNICODE_QMARK)) \
  380. )
  381. VOID
  382. FrsDissectName (
  383. IN UNICODE_STRING Path,
  384. OUT PUNICODE_STRING FirstName,
  385. OUT PUNICODE_STRING RemainingName
  386. );
  387. BOOLEAN
  388. FrsDoesNameContainWildCards (
  389. IN PUNICODE_STRING Name
  390. );
  391. BOOLEAN
  392. FrsAreNamesEqual (
  393. IN PUNICODE_STRING ConstantNameA,
  394. IN PUNICODE_STRING ConstantNameB,
  395. IN BOOLEAN IgnoreCase,
  396. IN PCWCH UpcaseTable OPTIONAL
  397. );
  398. BOOLEAN
  399. FrsIsNameInExpression (
  400. IN PUNICODE_STRING Expression,
  401. IN PUNICODE_STRING Name,
  402. IN BOOLEAN IgnoreCase,
  403. IN PWCH UpcaseTable OPTIONAL
  404. );
  405. //
  406. // The following is taken from clusrtl.h
  407. //
  408. //
  409. // Routine Description:
  410. //
  411. // Initializes the FRS run time library.
  412. //
  413. // Arguments:
  414. //
  415. // RunningAsService - TRUE if the process is running as an NT service.
  416. // FALSE if running as a console app.
  417. //
  418. // Return Value:
  419. //
  420. // ERROR_SUCCESS if the function succeeds.
  421. // A Win32 error code otherwise.
  422. //
  423. DWORD
  424. FrsRtlInitialize(
  425. IN BOOL RunningAsService
  426. );
  427. //
  428. // Routine Description:
  429. //
  430. // Cleans up the FRS run time library.
  431. //
  432. // Arguments:
  433. //
  434. // RunningAsService - TRUE if the process is running as an NT service.
  435. // FALSE if running as a console app.
  436. //
  437. // Return Value:
  438. //
  439. // None.
  440. //
  441. VOID
  442. FrsRtlCleanup(
  443. VOID
  444. );
  445. //
  446. // PLIST_ENTRY
  447. // GetListHead(
  448. // PLIST_ENTRY ListHead
  449. // );
  450. //
  451. #define GetListHead(ListHead) ((ListHead)->Flink)
  452. //
  453. // PLIST_ENTRY
  454. // GetListTail(
  455. // PLIST_ENTRY ListHead
  456. // );
  457. //
  458. #define GetListTail(ListHead) ((ListHead)->Blink)
  459. //
  460. // PLIST_ENTRY
  461. // GetListNext(
  462. // PLIST_ENTRY Entry
  463. // );
  464. //
  465. #define GetListNext(Entry) ((Entry)->Flink)
  466. //
  467. // VOID
  468. // FrsRemoveEntryList(
  469. // PLIST_ENTRY Entry
  470. // );
  471. //
  472. // *NOTE* The Flink/Blink of the removed entry are set to NULL to cause an
  473. // Access violation if a thread is following a list and an element is removed.
  474. // UNFORTUNATELY there is still code that depends on this, perhaps through
  475. // remove head/tail. Sigh. For now leave as is.
  476. //
  477. #define FrsRemoveEntryList(Entry) {\
  478. PLIST_ENTRY _EX_Blink;\
  479. PLIST_ENTRY _EX_Flink;\
  480. PLIST_ENTRY _EX_Entry;\
  481. _EX_Entry = (Entry);\
  482. _EX_Flink = _EX_Entry->Flink;\
  483. _EX_Blink = _EX_Entry->Blink;\
  484. _EX_Blink->Flink = _EX_Flink;\
  485. _EX_Flink->Blink = _EX_Blink;\
  486. _EX_Entry->Flink = _EX_Entry->Blink = _EX_Entry;\
  487. }
  488. //
  489. // VOID
  490. // RemoveEntryListB(
  491. // PLIST_ENTRY Entry
  492. // );
  493. //
  494. // The BillyF version of remove entry list. The Flink/Blink of the removed
  495. // entry are set to the entry address.
  496. //
  497. #define RemoveEntryListB(Entry) {\
  498. PLIST_ENTRY _EX_Blink;\
  499. PLIST_ENTRY _EX_Flink;\
  500. PLIST_ENTRY _EX_Entry;\
  501. _EX_Entry = (Entry);\
  502. _EX_Flink = _EX_Entry->Flink;\
  503. _EX_Blink = _EX_Entry->Blink;\
  504. _EX_Blink->Flink = _EX_Flink;\
  505. _EX_Flink->Blink = _EX_Blink;\
  506. _EX_Entry->Flink = _EX_Entry->Blink = _EX_Entry;\
  507. }
  508. //
  509. // Traverse a singlely linked NULL terminated list.
  510. // Pass in the address of the list head, the type of the containing record,
  511. // the offset to the link entry in the conatining record, and code for
  512. // the loop body. pE is the iterator and is of type specified.
  513. // Within the loop body the macros InsertSingleListEntry() and
  514. // RemoveSingleListEntry() can be used to do the obvious things.
  515. //
  516. #define ForEachSingleListEntry( _HEAD_, _TYPE_, _OFFSET_, _STMT_ ) \
  517. { \
  518. PSINGLE_LIST_ENTRY __Entry, __NextEntry, __PrevEntry; \
  519. _TYPE_ *pE; \
  520. \
  521. __Entry = (_HEAD_); \
  522. __NextEntry = (_HEAD_)->Next; \
  523. \
  524. while (__PrevEntry = __Entry, __Entry = __NextEntry, __Entry != NULL) { \
  525. \
  526. __NextEntry = __Entry->Next; \
  527. pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_); \
  528. \
  529. { _STMT_ } \
  530. \
  531. } \
  532. \
  533. }
  534. //
  535. // The following three macros are only valid within the loop body above.
  536. // Insert an entry before the current entry with pointer pE.
  537. //
  538. #define InsertSingleListEntry( _Item_, _xOFFSET_ ) \
  539. (_Item_)->_xOFFSET_.Next = __Entry; \
  540. __PrevEntry->Next = (PSINGLE_LIST_ENTRY) &((_Item_)->_xOFFSET_);
  541. //
  542. // Note that after you remove an entry the value for __Entry is set back to
  543. // the __PrevEntry so when the loop continues __PrevEntry doesn't change
  544. // since current entry had been removed.
  545. //
  546. #define RemoveSingleListEntry( _UNUSED_ ) \
  547. __PrevEntry->Next = __NextEntry; \
  548. __Entry->Next = NULL; \
  549. __Entry = __PrevEntry;
  550. //
  551. // Return ptr to the previous node. Only valid inside above FOR loop.
  552. // Useful when deleting the current entry.
  553. //
  554. #define PreviousSingleListEntry( _TYPE_, _OFFSET_) \
  555. CONTAINING_RECORD(__PrevEntry, _TYPE_, _OFFSET_)
  556. //
  557. // General-purpose queue package. Taken from cluster\clusrtl.c
  558. // *** WARNING *** To make the macros work properly for both lists and queues
  559. // the first five items in FRS_LIST and FRS_QUEUE MUST match.
  560. //
  561. typedef struct _FRS_QUEUE FRS_QUEUE, *PFRS_QUEUE;
  562. struct _FRS_QUEUE {
  563. LIST_ENTRY ListHead;
  564. CRITICAL_SECTION Lock;
  565. DWORD Count;
  566. PFRS_QUEUE Control;
  567. DWORD ControlCount;
  568. HANDLE Event;
  569. HANDLE RunDown;
  570. ULONG InitTime;
  571. LIST_ENTRY Full;
  572. LIST_ENTRY Empty;
  573. LIST_ENTRY Idled;
  574. BOOL IsRunDown;
  575. BOOL IsIdled;
  576. };
  577. VOID
  578. FrsInitializeQueue(
  579. IN PFRS_QUEUE Queue,
  580. IN PFRS_QUEUE Control
  581. );
  582. VOID
  583. FrsRtlDeleteQueue(
  584. IN PFRS_QUEUE Queue
  585. );
  586. PLIST_ENTRY
  587. FrsRtlRemoveHeadQueue(
  588. IN PFRS_QUEUE Queue
  589. );
  590. VOID
  591. FrsRtlUnIdledQueue(
  592. IN PFRS_QUEUE IdledQueue
  593. );
  594. VOID
  595. FrsRtlUnIdledQueueLock(
  596. IN PFRS_QUEUE IdledQueue
  597. );
  598. VOID
  599. FrsRtlIdleQueue(
  600. IN PFRS_QUEUE Queue
  601. );
  602. VOID
  603. FrsRtlIdleQueueLock(
  604. IN PFRS_QUEUE Queue
  605. );
  606. PLIST_ENTRY
  607. FrsRtlRemoveHeadQueueTimeoutIdled(
  608. IN PFRS_QUEUE Queue,
  609. IN DWORD dwMilliseconds,
  610. OUT PFRS_QUEUE *IdledQueue
  611. );
  612. PLIST_ENTRY
  613. FrsRtlRemoveHeadQueueTimeout(
  614. IN PFRS_QUEUE Queue,
  615. IN DWORD dwMilliseconds
  616. );
  617. VOID
  618. FrsRtlRemoveEntryQueue(
  619. IN PFRS_QUEUE Queue,
  620. IN PLIST_ENTRY Entry
  621. );
  622. DWORD
  623. FrsRtlWaitForQueueFull(
  624. IN PFRS_QUEUE Queue,
  625. IN DWORD dwMilliseconds
  626. );
  627. DWORD
  628. FrsRtlInsertTailQueue(
  629. IN PFRS_QUEUE Queue,
  630. IN PLIST_ENTRY Item
  631. );
  632. DWORD
  633. FrsRtlInsertHeadQueue(
  634. IN PFRS_QUEUE Queue,
  635. IN PLIST_ENTRY Item
  636. );
  637. VOID
  638. FrsRtlRunDownQueue(
  639. IN PFRS_QUEUE Queue,
  640. OUT PLIST_ENTRY ListHead
  641. );
  642. #define FrsRtlAcquireQueueLock(_pQueue_) \
  643. EnterCriticalSection(&(((_pQueue_)->Control)->Lock))
  644. #define FrsRtlReleaseQueueLock(_pQueue_) \
  645. LeaveCriticalSection(&(((_pQueue_)->Control)->Lock))
  646. #define FrsRtlCountQueue(_pQueue_) \
  647. (((_pQueue_)->Control)->ControlCount)
  648. #define FrsRtlCountSubQueue(_pQueue_) \
  649. ((_pQueue_)->Count)
  650. #define FrsRtlNoIdledQueues(_pQueue_) \
  651. (IsListEmpty(&(((_pQueue_)->Control)->Idled)))
  652. //
  653. // The Lock suffix on the routines below means the user already has the
  654. // queue lock.
  655. //
  656. VOID
  657. FrsRtlRemoveEntryQueueLock(
  658. IN PFRS_QUEUE Queue,
  659. IN PLIST_ENTRY Entry
  660. );
  661. DWORD
  662. FrsRtlInsertTailQueueLock(
  663. IN PFRS_QUEUE Queue,
  664. IN PLIST_ENTRY Item
  665. );
  666. DWORD
  667. FrsRtlInsertHeadQueueLock(
  668. IN PFRS_QUEUE Queue,
  669. IN PLIST_ENTRY Item
  670. );
  671. //
  672. // COMMAND SERVER
  673. // A command server is a dynamic pool of threads and a controlled queue
  674. // The default queue is set up as a controlled queue. Other
  675. // controlled queues can be added in a server specific manner.
  676. // A command server exports an initialize, abort, and none or more
  677. // submit routines. The parameters and names of these functions is
  678. // server specific. The consumers of a server's interface are intimate
  679. // with the server.
  680. //
  681. typedef struct _COMMAND_SERVER COMMAND_SERVER, *PCOMMAND_SERVER;
  682. struct _COMMAND_SERVER {
  683. DWORD MaxThreads; // Max # of threads
  684. DWORD FrsThreads; // current # of frs threads
  685. DWORD Waiters; // current # of frs threads waiting
  686. PWCHAR Name; // Thread's name
  687. HANDLE Idle; // No active threads; no queue entries
  688. DWORD (*Main)(PVOID); // Thread's entry point
  689. FRS_QUEUE Control; // controlling queue
  690. FRS_QUEUE Queue; // queue
  691. };
  692. //
  693. // Interlocked list.
  694. // *** WARNING *** To make the macros work properly for both lists and queues
  695. // the first five items in FRS_LIST and FRS_QUEUE MUST match.
  696. //
  697. typedef struct _FRS_LIST FRS_LIST, *PFRS_LIST;
  698. struct _FRS_LIST {
  699. LIST_ENTRY ListHead;
  700. CRITICAL_SECTION Lock;
  701. DWORD Count;
  702. PFRS_LIST Control;
  703. DWORD ControlCount;
  704. };
  705. DWORD
  706. FrsRtlInitializeList(
  707. PFRS_LIST List
  708. );
  709. VOID
  710. FrsRtlDeleteList(
  711. PFRS_LIST List
  712. );
  713. PLIST_ENTRY
  714. FrsRtlRemoveHeadList(
  715. IN PFRS_LIST List
  716. );
  717. VOID
  718. FrsRtlInsertHeadList(
  719. IN PFRS_LIST List,
  720. IN PLIST_ENTRY Entry
  721. );
  722. PLIST_ENTRY
  723. FrsRtlRemoveTailList(
  724. IN PFRS_LIST List
  725. );
  726. VOID
  727. FrsRtlInsertTailList(
  728. IN PFRS_LIST List,
  729. IN PLIST_ENTRY Entry
  730. );
  731. VOID
  732. FrsRtlRemoveEntryList(
  733. IN PFRS_LIST List,
  734. IN PLIST_ENTRY Entry
  735. );
  736. #define FrsRtlAcquireListLock(_pList_) EnterCriticalSection(&(((_pList_)->Control)->Lock))
  737. #define FrsRtlReleaseListLock(_pList_) LeaveCriticalSection(&(((_pList_)->Control)->Lock))
  738. #define FrsRtlCountList(_pList_) (((_pList_)->Control)->ControlCount)
  739. VOID
  740. FrsRtlRemoveEntryListLock(
  741. IN PFRS_LIST List,
  742. IN PLIST_ENTRY Entry
  743. );
  744. VOID
  745. FrsRtlInsertTailListLock(
  746. IN PFRS_LIST List,
  747. IN PLIST_ENTRY Entry
  748. );
  749. VOID
  750. FrsRtlInsertHeadListLock(
  751. IN PFRS_LIST List,
  752. IN PLIST_ENTRY Entry
  753. );
  754. //VOID
  755. //FrsRtlInsertBeforeEntryListLock(
  756. // IN PFRS_LIST List,
  757. // IN PLIST_ENTRY BeforeEntry
  758. // IN PLIST_ENTRY NewEntry
  759. // )
  760. //
  761. // Inserts newEntry before the BeforeEntry on the interlocked list (List).
  762. // This is used to keep the list elements in ascending order by KeyValue.
  763. //
  764. // Assumes caller already has the list lock.
  765. //
  766. #define FrsRtlInsertBeforeEntryListLock( _List, _BeforeEntry, _NewEntry ) \
  767. InsertTailList((_BeforeEntry), (_NewEntry)); \
  768. (_List)->Count += 1; \
  769. ((_List)->Control)->ControlCount += 1; \
  770. //
  771. // Walk thru an interlocked queue or list (_QUEUE_) with elements of type
  772. // _TYPE_ and execute {_STMT_} for each one. The list entry in _TYPE_ is
  773. // at _OFFSET_. Use pE in the statement body as a pointer to the entry.
  774. // The entry may be removed from within the loop since we capture the
  775. // link to the next entry before executing the loop body. You may also use
  776. // 'continue' within the loop body because the assignment of nextentry to entry
  777. // is in a comma expression inside the while test.
  778. //
  779. #define ForEachListEntry( _QUEUE_, _TYPE_, _OFFSET_, _STMT_ ) \
  780. { \
  781. PLIST_ENTRY __Entry, __NextEntry; \
  782. BOOL __Hold__=FALSE; \
  783. _TYPE_ *pE; \
  784. \
  785. FrsRtlAcquireQueueLock(_QUEUE_); \
  786. __NextEntry = GetListHead(&((_QUEUE_)->ListHead)); \
  787. \
  788. while (__Entry = __NextEntry, __Entry != &((_QUEUE_)->ListHead)) { \
  789. \
  790. __NextEntry = GetListNext(__Entry); \
  791. pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_); \
  792. \
  793. { _STMT_ } \
  794. \
  795. } \
  796. \
  797. if (!__Hold__) FrsRtlReleaseQueueLock(_QUEUE_); \
  798. \
  799. }
  800. #define AquireListLock( _QUEUE_ ) FrsRtlAcquireListLock(_QUEUE_)
  801. #define ReleaseListLock( _QUEUE_ ) FrsRtlReleaseListLock(_QUEUE_)
  802. #define BreakAndHoldLock __Hold__ = TRUE; break
  803. //
  804. // Just like the above except the caller already has the list lock.
  805. //
  806. #define ForEachListEntryLock( _QUEUE_, _TYPE_, _OFFSET_, _STMT_ ) \
  807. { \
  808. PLIST_ENTRY __Entry, __NextEntry; \
  809. _TYPE_ *pE; \
  810. \
  811. __NextEntry = GetListHead(&((_QUEUE_)->ListHead)); \
  812. \
  813. while (__Entry = __NextEntry, __Entry != &((_QUEUE_)->ListHead)) { \
  814. \
  815. __NextEntry = GetListNext(__Entry); \
  816. pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_); \
  817. \
  818. { _STMT_ } \
  819. \
  820. } \
  821. \
  822. }
  823. //
  824. // Just like the above except pass in the address of the list head
  825. // instead of using QUEUE->ListHEad.
  826. //
  827. #define ForEachSimpleListEntry( _HEAD_, _TYPE_, _OFFSET_, _STMT_ ) \
  828. { \
  829. PLIST_ENTRY __Entry, __NextEntry; \
  830. _TYPE_ *pE; \
  831. \
  832. __NextEntry = GetListHead(_HEAD_); \
  833. \
  834. while (__Entry = __NextEntry, __Entry != (_HEAD_)) { \
  835. \
  836. __NextEntry = GetListNext(__Entry); \
  837. pE = CONTAINING_RECORD(__Entry, _TYPE_, _OFFSET_); \
  838. \
  839. { _STMT_ } \
  840. \
  841. } \
  842. \
  843. }
  844. //VOID
  845. //FrsRtlInsertQueueOrdered(
  846. // IN PFRS_QUEUE List,
  847. // IN PLIST_ENTRY NewEntry,
  848. // IN <Entry-Data-Type>,
  849. // IN <LIST_ENTRY-offset-name>,
  850. // IN <Orderkey-Offset-name>,
  851. // IN EventHandle or NULL
  852. // )
  853. //
  854. // Inserts NewEntry on an ordered queue of <Entry-Data-Type> elements.
  855. // The offset to the LIST_ENTRY in each element is <LIST_ENTRY-offset-name>
  856. // The offset to the Ordering key (.eg. a ULONG) is <Orderkey-Offset-name>
  857. // It acquires the List Lock.
  858. // The list elements are kept in ascending order by KeyValue.
  859. // If a new element is placed at the head of the queue and the EventHandle
  860. // is non-NULL, the event is signalled.
  861. //
  862. //
  863. #define FrsRtlInsertQueueOrdered( \
  864. _QUEUE_, _NEWENTRY_, _TYPE_, _OFFSET_, _BY_, _EVENT_, _STATUS_) \
  865. { \
  866. BOOL __InsertDone = FALSE; \
  867. BOOL __FirstOnQueue = TRUE; \
  868. _STATUS_ = ERROR_SUCCESS; \
  869. \
  870. FrsRtlAcquireQueueLock(_QUEUE_); \
  871. \
  872. ForEachListEntryLock(_QUEUE_, _TYPE_, _OFFSET_, \
  873. \
  874. /* pE is loop iterator of type _TYPE_ */ \
  875. \
  876. if ((_NEWENTRY_)->_BY_ < pE->_BY_) { \
  877. FrsRtlInsertBeforeEntryListLock( _QUEUE_, \
  878. &pE->_OFFSET_, \
  879. &((_NEWENTRY_)->_OFFSET_)); \
  880. __InsertDone = TRUE; \
  881. break; \
  882. } \
  883. \
  884. __FirstOnQueue = FALSE; \
  885. ); \
  886. \
  887. /* Handle new head or new tail case. If the queue was previously */ \
  888. /* the insert will set the event. */ \
  889. \
  890. if (!__InsertDone) { \
  891. if (__FirstOnQueue) { \
  892. _STATUS_ = FrsRtlInsertHeadQueueLock(_QUEUE_, &((_NEWENTRY_)->_OFFSET_)); \
  893. } else { \
  894. _STATUS_ = FrsRtlInsertTailQueueLock(_QUEUE_, &((_NEWENTRY_)->_OFFSET_)); \
  895. } \
  896. } \
  897. \
  898. /* If this command became the new first one on the queue and the */ \
  899. /* queue wasn't previously empty we have to set the event here to */ \
  900. /* get the thread to readjust its wait time. */ \
  901. \
  902. if (__FirstOnQueue && \
  903. (FrsRtlCountQueue(_QUEUE_) != 1)) { \
  904. if (HANDLE_IS_VALID(_EVENT_)) { \
  905. SetEvent(_EVENT_); \
  906. } \
  907. } \
  908. \
  909. FrsRtlReleaseQueueLock(_QUEUE_); \
  910. \
  911. }
  912. //VOID
  913. //FrsRtlInsertListOrdered(
  914. // IN PFRS_LIST List,
  915. // IN PLIST_ENTRY NewEntry,
  916. // IN <Entry-Data-Type>,
  917. // IN <LIST_ENTRY-offset-name>,
  918. // IN <Orderkey-Offset-name>,
  919. // IN EventHandle or NULL
  920. // )
  921. //
  922. // Inserts NewEntry on an ordered list of <Entry-Data-Type> elements.
  923. // The offset to the LIST_ENTRY in each element is <LIST_ENTRY-offset-name>
  924. // The offset to the Ordering key (.eg. a ULONG) is <Orderkey-Offset-name>
  925. // It acquires the List Lock.
  926. // The list elements are kept in ascending order by KeyValue.
  927. // If a new element is placed at the head of the queue and the EventHandle
  928. // is non-NULL, the event is signalled.
  929. //
  930. //
  931. #define FrsRtlInsertListOrdered( \
  932. _FRSLIST_, _NEWENTRY_, _TYPE_, _OFFSET_, _BY_, _EVENT_) \
  933. { \
  934. BOOL __InsertDone = FALSE; \
  935. BOOL __FirstOnList = TRUE; \
  936. \
  937. FrsRtlAcquireListLock(_FRSLIST_); \
  938. \
  939. ForEachListEntryLock(_FRSLIST_, _TYPE_, _OFFSET_, \
  940. \
  941. /* pE is loop iterator of type _TYPE_ */ \
  942. \
  943. if ((_NEWENTRY_)->_BY_ < pE->_BY_) { \
  944. FrsRtlInsertBeforeEntryListLock( _FRSLIST_, \
  945. &pE->_OFFSET_, \
  946. &((_NEWENTRY_)->_OFFSET_)); \
  947. __InsertDone = TRUE; \
  948. break; \
  949. } \
  950. \
  951. __FirstOnList = FALSE; \
  952. ); \
  953. \
  954. /* Handle new head or new tail case. */ \
  955. \
  956. if (!__InsertDone) { \
  957. if (__FirstOnList) { \
  958. FrsRtlInsertHeadListLock(_FRSLIST_, &((_NEWENTRY_)->_OFFSET_)); \
  959. } else { \
  960. FrsRtlInsertTailListLock(_FRSLIST_, &((_NEWENTRY_)->_OFFSET_)); \
  961. } \
  962. } \
  963. \
  964. /* If this command became the new first one on the list */ \
  965. /* we set the event here to get the thread to readjust its wait time.*/ \
  966. \
  967. if (__FirstOnList) { \
  968. if (HANDLE_IS_VALID(_EVENT_)) { \
  969. SetEvent(_EVENT_); \
  970. } \
  971. } \
  972. \
  973. FrsRtlReleaseListLock(_FRSLIST_); \
  974. \
  975. }
  976. //
  977. // Request counts are used as a simple means for tracking the number of
  978. // command requests that are pending so the requestor can wait until
  979. // all the commands have been processed.
  980. //
  981. typedef struct _FRS_REQUEST_COUNT FRS_REQUEST_COUNT, *PFRS_REQUEST_COUNT;
  982. struct _FRS_REQUEST_COUNT {
  983. CRITICAL_SECTION Lock;
  984. LONG Count; // Number of requests active
  985. HANDLE Event; // Event set when count goes to zero.
  986. ULONG Status; // Optional status return
  987. };
  988. #define FrsIncrementRequestCount(_RC_) \
  989. EnterCriticalSection(&(_RC_)->Lock); \
  990. (_RC_)->Count += 1; \
  991. if ((_RC_)->Count == 1) { \
  992. ResetEvent((_RC_)->Event); \
  993. } \
  994. LeaveCriticalSection(&(_RC_)->Lock);
  995. #define FrsDecrementRequestCount(_RC_, _Status_) \
  996. EnterCriticalSection(&(_RC_)->Lock); \
  997. (_RC_)->Status |= _Status_; \
  998. (_RC_)->Count -= 1; \
  999. FRS_ASSERT((_RC_)->Count >= 0); \
  1000. if ((_RC_)->Count == 0) { \
  1001. SetEvent((_RC_)->Event); \
  1002. } \
  1003. LeaveCriticalSection(&(_RC_)->Lock);
  1004. ULONG
  1005. FrsWaitOnRequestCount(
  1006. IN PFRS_REQUEST_COUNT RequestCount,
  1007. IN ULONG Timeout
  1008. );
  1009. struct _COMMAND_PACKET;
  1010. VOID
  1011. FrsCompleteRequestCount(
  1012. IN struct _COMMAND_PACKET *CmdPkt,
  1013. IN PFRS_REQUEST_COUNT RequestCount
  1014. );
  1015. VOID
  1016. FrsCompleteRequestCountKeepPkt(
  1017. IN struct _COMMAND_PACKET *CmdPkt,
  1018. IN PFRS_REQUEST_COUNT RequestCount
  1019. );
  1020. VOID
  1021. FrsCompleteKeepPkt(
  1022. IN struct _COMMAND_PACKET *CmdPkt,
  1023. IN PVOID CompletionArg
  1024. );
  1025. VOID
  1026. FrsInitializeRequestCount(
  1027. IN PFRS_REQUEST_COUNT RequestCount
  1028. );
  1029. VOID
  1030. FrsDeleteRequestCount(
  1031. IN PFRS_REQUEST_COUNT RequestCount
  1032. );
  1033. #define FrsInterlockedIncrement64(_Dest_, _Data_, _Lock_) \
  1034. EnterCriticalSection(_Lock_); \
  1035. _Data_ += (ULONGLONG) 1; \
  1036. _Dest_ = (_Data_); \
  1037. LeaveCriticalSection(_Lock_);
  1038. //
  1039. // ADVANCE_VALUE_INTERLOCKED(
  1040. // IN PULONG _dest,
  1041. // IN ULONG _newval
  1042. // )
  1043. // Advance the destination to the value given in newval atomically using
  1044. // interlocked exchange. _dest is never moved to a smaller value so this
  1045. // is a no-op if _newval is < _dest.
  1046. //
  1047. // *NOTE* Other operations on _dest MUST be done with interlocked ops like
  1048. // InterlockedIncrement to ensure that an incremented value is not lost if
  1049. // it occurs simultaneously on another processor.
  1050. //
  1051. #define ADVANCE_VALUE_INTERLOCKED(_dest, _newval) { \
  1052. ULONG CurVal, SaveCurVal, Result, *pDest = (_dest); \
  1053. CurVal = SaveCurVal = *pDest; \
  1054. while ((_newval) > CurVal) { \
  1055. Result = (ULONG)InterlockedCompareExchange((PLONG)pDest, (_newval), CurVal); \
  1056. if (Result == CurVal) { \
  1057. break; \
  1058. } \
  1059. CurVal = Result; \
  1060. } \
  1061. FRS_ASSERT(*pDest >= SaveCurVal); \
  1062. }
  1063. //
  1064. //
  1065. // Avoiding a torn quadword result (without a crit sect) when 1 thread is
  1066. // writing a quadord and another is reading the quadword, or,
  1067. // 2 threads are writing the same quadword.
  1068. //
  1069. // To do this in alpha we need an assembler routine to use load_locked / store_cond.
  1070. // To do this in x86 (per DaveC):
  1071. #if 0
  1072. if (USER_SHARED_DATA->ProcessorFeatures[PF_COMPARE_EXCHANGE_DOUBLE] == FALSE) {
  1073. // code to use a crit section.
  1074. } else {
  1075. // code to use inline assembly with cmpxchg8b.
  1076. }
  1077. #endif
  1078. // KUSER_SHARED_DATA is defined in sdk\inc\ntxapi.h
  1079. // USER_SHARED_DATA is an arch specific typecast pointer to KUSER_SHARED_DATA.
  1080. // User shared data has a processor feature list with a cell for
  1081. // PF_COMPARE_EXCHANGE_DOUBLE that tells if the processor supports
  1082. // the cmpxchg8b instruction for x86. The 486 doesn't have it.
  1083. //
  1084. #define ReadQuadLock(_qw, _Lock) \
  1085. (EnterCriticalSection((_Lock)), *(_qw))
  1086. #define WriteQuadUnlock(_qw, _newval, _Lock) \
  1087. *(_qw) = (_newval); \
  1088. LeaveCriticalSection((_Lock))
  1089. #define AcquireQuadLock(_Lock) EnterCriticalSection((_Lock))
  1090. #define ReleaseQuadLock(_Lock) LeaveCriticalSection((_Lock))
  1091. //
  1092. // SET_FLAG_INTERLOCKED(
  1093. // IN PULONG _dest,
  1094. // IN ULONG _flags
  1095. // )
  1096. //
  1097. // *NOTE* Other operations on _dest MUST be done with interlocked ops like
  1098. // InterlockedIncrement to ensure that an incremented value is not lost if
  1099. // it occurs simultaneously on another processor.
  1100. //
  1101. #define SET_FLAG_INTERLOCKED(_dest, _flags) { \
  1102. ULONG CurVal, NewVal, Result, *pDest = (_dest); \
  1103. CurVal = *pDest; \
  1104. NewVal = (_flags) | CurVal; \
  1105. while ((NewVal) != CurVal) { \
  1106. Result = (ULONG)InterlockedCompareExchange((PLONG)pDest, NewVal, CurVal); \
  1107. if (Result == CurVal) { \
  1108. break; \
  1109. } \
  1110. CurVal = Result; \
  1111. NewVal = (_flags) | CurVal; \
  1112. } \
  1113. }
  1114. //
  1115. // CLEAR_FLAG_INTERLOCKED(
  1116. // IN PULONG _dest,
  1117. // IN ULONG _flags
  1118. // )
  1119. //
  1120. // *NOTE* Other operations on _dest MUST be done with interlocked ops like
  1121. // InterlockedIncrement to ensure that an incremented value is not lost if
  1122. // it occurs simultaneously on another processor.
  1123. //
  1124. #define CLEAR_FLAG_INTERLOCKED(_dest, _flags) { \
  1125. ULONG CurVal, NewVal, Result, *pDest = (_dest); \
  1126. CurVal = *pDest; \
  1127. NewVal = CurVal & ~(_flags); \
  1128. while ((NewVal) != CurVal) { \
  1129. Result = (ULONG)InterlockedCompareExchange((PLONG)pDest, NewVal, CurVal); \
  1130. if (Result == CurVal) { \
  1131. break; \
  1132. } \
  1133. CurVal = Result; \
  1134. NewVal = CurVal & ~(_flags); \
  1135. } \
  1136. }
  1137. #define FlagOn(Flags,SingleFlag) ((Flags) & (SingleFlag))
  1138. #define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)(((Flags) & (SingleFlag)) != 0))
  1139. #define SetFlag(_F,_SF) { \
  1140. (_F) |= (_SF); \
  1141. }
  1142. #define ClearFlag(_F,_SF) { \
  1143. (_F) &= ~(_SF); \
  1144. }
  1145. #define ValueIsMultOf2(_x_) (((ULONG_PTR)(_x_) & 0x00000001) == 0)
  1146. #define ValueIsMultOf4(_x_) (((ULONG_PTR)(_x_) & 0x00000003) == 0)
  1147. #define ValueIsMultOf8(_x_) (((ULONG_PTR)(_x_) & 0x00000007) == 0)
  1148. #define ValueIsMultOf16(_x_) (((ULONG_PTR)(_x_) & 0x0000000F) == 0)
  1149. #define ARRAY_SZ(_ar) (sizeof(_ar)/sizeof((_ar)[0]))
  1150. #define ARRAY_SZ2(_ar, _type) (sizeof(_ar)/sizeof(_type))
  1151. //
  1152. // This macros below take a pointer (or ulong) and return the value rounded
  1153. // up to the next aligned boundary.
  1154. //
  1155. #define WordAlign(Ptr) ((PVOID)((((ULONG_PTR)(Ptr)) + 1) & ~1))
  1156. #define LongAlign(Ptr) ((PVOID)((((ULONG_PTR)(Ptr)) + 3) & ~3))
  1157. #define QuadAlign(Ptr) ((PVOID)((((ULONG_PTR)(Ptr)) + 7) & ~7))
  1158. #define DblQuadAlign(Ptr) ((PVOID)((((ULONG_PTR)(Ptr)) + 15) & ~15))
  1159. #define QuadQuadAlign(Ptr) ((PVOID)((((ULONG_PTR)(Ptr)) + 31) & ~31))
  1160. #define QuadQuadAlignSize(Size) ((((ULONG)(Size)) + 31) & ~31)
  1161. //
  1162. // Check for a zero FILETIME.
  1163. //
  1164. #define FILETIME_IS_ZERO(_F_) \
  1165. ((_F_.dwLowDateTime == 0) && (_F_.dwHighDateTime == 0))
  1166. //
  1167. // Convert a quad to two ULONGs for printing with format: %08x %08x
  1168. //
  1169. #define PRINTQUAD(__ARG__) (ULONG)((__ARG__)>>32) ,(ULONG)(__ARG__)
  1170. //
  1171. // Convert to printable cxtion path with format: %ws\%ws\%ws -> %ws\%ws
  1172. //
  1173. #define FORMAT_CXTION_PATH2 "%ws\\%ws\\%ws %ws %ws %ws"
  1174. #define FORMAT_CXTION_PATH2W L"%ws\\%ws\\%ws %ws %ws %ws"
  1175. #define PRINT_CXTION_PATH2(_REPLICA, _CXTION) \
  1176. (_REPLICA)->ReplicaName->Name, \
  1177. (_REPLICA)->MemberName->Name, \
  1178. (((_CXTION) != NULL) ? (_CXTION)->Name->Name : L"null"), \
  1179. (((_CXTION) != NULL) ? (((_CXTION)->Inbound) ? L"<-" : L"->") : \
  1180. L"?"), \
  1181. (((_CXTION) != NULL) ? (_CXTION)->PartSrvName : L"null"), \
  1182. (((_CXTION) != NULL) ? (((_CXTION)->JrnlCxtion) ? L"JrnlCxt" : L"RemoteCxt") : L"null")
  1183. #define PRINT_CXTION_PATH(_REPLICA, _CXTION) \
  1184. (_REPLICA)->ReplicaName->Name, \
  1185. (_REPLICA)->MemberName->Name, \
  1186. (((_CXTION) != NULL) ? (_CXTION)->Name->Name : L"null"), \
  1187. (((_CXTION) != NULL) ? (_CXTION)->Partner->Name : L"null"), \
  1188. (((_CXTION) != NULL) ? (_CXTION)->PartSrvName : L"null")
  1189. //
  1190. // Lower case
  1191. //
  1192. #define FRS_WCSLWR(_s_) \
  1193. { \
  1194. if (_s_) { \
  1195. _wcslwr(_s_); \
  1196. } \
  1197. }
  1198. //
  1199. // Lock to protect the child lists in the Filter Table. (must be pwr of 2)
  1200. // Instead of paying the overhead of having one per node we just use an array
  1201. // to help reduce contention. We use the ReplicaNumber masked by the lock
  1202. // table size as the index.
  1203. //
  1204. // Acquire the lock on the ReplicaSet Filter table Child List before
  1205. // inserting or removing a child from the list.
  1206. //
  1207. #define NUMBER_FILTER_TABLE_CHILD_LOCKS 8
  1208. extern CRITICAL_SECTION JrnlFilterTableChildLock[NUMBER_FILTER_TABLE_CHILD_LOCKS];
  1209. #define FILTER_TABLE_CHILD_INDEX(_x_) \
  1210. ((ULONG)((_x_)->ReplicaNumber) & (NUMBER_FILTER_TABLE_CHILD_LOCKS - 1))
  1211. #define JrnlAcquireChildLock(_replica_) EnterCriticalSection( \
  1212. &JrnlFilterTableChildLock[FILTER_TABLE_CHILD_INDEX(_replica_)] )
  1213. #define JrnlReleaseChildLock(_replica_) LeaveCriticalSection( \
  1214. &JrnlFilterTableChildLock[FILTER_TABLE_CHILD_INDEX(_replica_)] )
  1215. //
  1216. // Renaming a subtree from one replica set to another requires the child locks
  1217. // for both replica sets. Always get them in the same order (low to high)
  1218. // to avoid deadlock. Also check if the both use the same lock.
  1219. // Note: The caller must use JrnlReleaseChildLockPair() so the check for
  1220. // using the same lock can be repeated. Release in reverse order to avoid
  1221. // an extra context switch if another thread was waiting behind the first lock.
  1222. //
  1223. #define JrnlAcquireChildLockPair(_replica1_, _replica2_) \
  1224. { \
  1225. ULONG Lx1, Lx2, Lxt; \
  1226. Lx1 = FILTER_TABLE_CHILD_INDEX(_replica1_); \
  1227. Lx2 = FILTER_TABLE_CHILD_INDEX(_replica2_); \
  1228. if (Lx1 > Lx2) { \
  1229. Lxt = Lx1; Lx1 = Lx2; Lx2 = Lxt; \
  1230. } \
  1231. EnterCriticalSection(&JrnlFilterTableChildLock[Lx1]); \
  1232. if (Lx1 != Lx2) { \
  1233. EnterCriticalSection(&JrnlFilterTableChildLock[Lx2]); \
  1234. } \
  1235. }
  1236. #define JrnlReleaseChildLockPair(_replica1_, _replica2_) \
  1237. { \
  1238. ULONG Lx1, Lx2, Lxt; \
  1239. Lx1 = FILTER_TABLE_CHILD_INDEX(_replica1_); \
  1240. Lx2 = FILTER_TABLE_CHILD_INDEX(_replica2_); \
  1241. if (Lx1 < Lx2) { \
  1242. Lxt = Lx1; Lx1 = Lx2; Lx2 = Lxt; \
  1243. } \
  1244. LeaveCriticalSection(&JrnlFilterTableChildLock[Lx1]); \
  1245. if (Lx1 != Lx2) { \
  1246. LeaveCriticalSection(&JrnlFilterTableChildLock[Lx2]); \
  1247. } \
  1248. }
  1249. #ifdef __cplusplus
  1250. }
  1251. #endif
  1252. ULONG
  1253. FrsRunProcess(
  1254. IN PWCHAR CommandLine,
  1255. IN HANDLE StandardIn,
  1256. IN HANDLE StandardOut,
  1257. IN HANDLE StandardError
  1258. );
  1259. VOID
  1260. FrsFlagsToStr(
  1261. IN DWORD Flags,
  1262. IN PFLAG_NAME_TABLE NameTable,
  1263. IN ULONG Length,
  1264. OUT PSTR Buffer
  1265. );
  1266. //
  1267. //######################### COMPRESSION OF STAGING FILE STARTS ###############
  1268. //
  1269. //
  1270. // The compressed chunk header is the structure that starts every
  1271. // new chunk in the compressed data stream. In our definition here
  1272. // we union it with a ushort to make setting and retrieving the chunk
  1273. // header easier. The header stores the size of the compressed chunk,
  1274. // its signature, and if the data stored in the chunk is compressed or
  1275. // not.
  1276. //
  1277. // Compressed Chunk Size:
  1278. //
  1279. // The actual size of a compressed chunk ranges from 4 bytes (2 byte
  1280. // header, 1 flag byte, and 1 literal byte) to 4098 bytes (2 byte
  1281. // header, and 4096 bytes of uncompressed data). The size is encoded
  1282. // in a 12 bit field biased by 3. A value of 1 corresponds to a chunk
  1283. // size of 4, 2 => 5, ..., 4095 => 4098. A value of zero is special
  1284. // because it denotes the ending chunk header.
  1285. //
  1286. // Chunk Signature:
  1287. //
  1288. // The only valid signature value is 3. This denotes a 4KB uncompressed
  1289. // chunk using with the 4/12 to 12/4 sliding offset/length encoding.
  1290. //
  1291. // Is Chunk Compressed:
  1292. //
  1293. // If the data in the chunk is compressed this field is 1 otherwise
  1294. // the data is uncompressed and this field is 0.
  1295. //
  1296. // The ending chunk header in a compressed buffer contains the a value of
  1297. // zero (space permitting).
  1298. //
  1299. typedef union _FRS_COMPRESSED_CHUNK_HEADER {
  1300. struct {
  1301. USHORT CompressedChunkSizeMinus3 : 12;
  1302. USHORT ChunkSignature : 3;
  1303. USHORT IsChunkCompressed : 1;
  1304. } Chunk;
  1305. USHORT Short;
  1306. } FRS_COMPRESSED_CHUNK_HEADER, *PFRS_COMPRESSED_CHUNK_HEADER;
  1307. typedef struct _FRS_DECOMPRESS_CONTEXT {
  1308. DWORD BytesProcessed;
  1309. } FRS_DECOMPRESS_CONTEXT, *PFRS_DECOMPRESS_CONTEXT;
  1310. #define FRS_MAX_CHUNKS_TO_DECOMPRESS 16
  1311. #define FRS_UNCOMPRESSED_CHUNK_SIZE 4096
  1312. //
  1313. //######################### COMPRESSION OF STAGING FILE ENDS ###############
  1314. //
  1315. //
  1316. // This context is used to send data to the callback functions for the RAW
  1317. // encrypt APIs.
  1318. //
  1319. typedef struct _FRS_ENCRYPT_DATA_CONTEXT {
  1320. PWCHAR StagePath;
  1321. HANDLE StageHandle;
  1322. LARGE_INTEGER RawEncryptedBytes;
  1323. } FRS_ENCRYPT_DATA_CONTEXT, *PFRS_ENCRYPT_DATA_CONTEXT;