Leaked source code of windows server 2003
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.

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