#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

global using System;
global using System.Runtime.InteropServices;
global using System.Threading;
global using Vanara.InteropServices;

global using CLFS_CONTAINER_ID = System.UInt32;
global using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
using Vanara.Extensions;

namespace Vanara.PInvoke;

/// <summary>Functions supporting the Windows Common Log File System.</summary>
public static partial class ClfsW32
{
	/// <summary>Base log file name 3-letter extension.</summary>
	public const string CLFS_BASELOG_EXTENSION = ".blf";

	/// <summary>Container name extended attribute entry name.</summary>
	public const string EA_CONTAINER_NAME = "ContainerName";

	/// <summary>Container size extended attribute entry name.</summary>
	public const string EA_CONTAINER_SIZE = "ContainerSize";

	private const string Lib_Clfsw32 = "clfsw32.dll";

	/// <summary>Allocate a blocks for marshaled reads or writes</summary>
	/// <param name="cbBufferLength">Length of the cb buffer.</param>
	/// <param name="pvUserContext">The pv user context.</param>
	[UnmanagedFunctionPointer(CallingConvention.Winapi)]
	public delegate void CLFS_BLOCK_ALLOCATION(uint cbBufferLength, IntPtr pvUserContext);

	/// <summary>A callback function that frees log blocks.</summary>
	/// <param name="pvBuffer">The pv buffer.</param>
	/// <param name="pvUserContext">The pv user context.</param>
	[UnmanagedFunctionPointer(CallingConvention.Winapi)]
	public delegate void CLFS_BLOCK_DEALLOCATION(IntPtr pvBuffer, IntPtr pvUserContext);

	/// <summary>The current state of a container.</summary>
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_CONTAINER_INFORMATION")]
	[Flags]
	public enum CLFS_CONTAINER_STATE : uint
	{
		/// <summary>The container is in the process of initializing.</summary>
		ClsContainerInitializing = 0x01,

		/// <summary>The container is allocated, but is not in the active region of the log.</summary>
		ClsContainerInactive = 0x02,

		/// <summary>The container is being used as storage for part of the log.</summary>
		ClsContainerActive = 0x04,

		/// <summary>The container is marked for deletion, but still contains part of the active log.</summary>
		ClsContainerActivePendingDelete = 0x08,

		/// <summary>The container is marked for archive.</summary>
		ClsContainerPendingArchive = 0x10,

		/// <summary>The container is marked for deletion, but still contains log data that is not archived.</summary>
		ClsContainerPendingArchiveAndDelete = 0x20,
	}

	/// <summary>
	/// Specifies a context mode type that indicates the direction and access methods that a client uses to scan a log. The context mode is
	/// set by using ReadLogRecord, and is embedded in the read context that these two functions return.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ne-clfs-clfs_context_mode typedef enum _CLFS_CONTEXT_MODE { ClfsContextNone =
	// 0x00, ClfsContextUndoNext, ClfsContextPrevious, ClfsContextForward } CLFS_CONTEXT_MODE, *PCLFS_CONTEXT_MODE, PPCLFS_CONTEXT_MODE;
	[PInvokeData("clfs.h", MSDNShortId = "NE:clfs._CLFS_CONTEXT_MODE")]
	public enum CLFS_CONTEXT_MODE
	{
		/// <summary>
		/// <para>Value:</para>
		/// <para>0x00</para>
		/// <para>Do not move the cursor.</para>
		/// </summary>
		ClfsContextNone,

		/// <summary>Move the cursor backward to the next undo record.</summary>
		ClfsContextUndoNext,

		/// <summary>Move the cursor to the previous log record from the current read context.</summary>
		ClfsContextPrevious,

		/// <summary>Move the cursor to the next client log record from the current read context.</summary>
		ClfsContextForward,
	}

	/// <summary>Common log file system public flags and constants.</summary>
	[PInvokeData("clfs.h")]
	[Flags]
	public enum CLFS_FLAG : uint
	{
		/// <summary>Assigns no flags.</summary>
		CLFS_FLAG_NO_FLAGS = 0x00000000,

		/// <summary>
		/// Assigns a physical location for all appended records in a log that have not been previously assigned a physical location. All
		/// these records are made available for reading from other marshaling contexts.
		/// </summary>
		CLFS_FLAG_FORCE_APPEND = 0x00000001,

		/// <summary>
		/// Assigns a physical location for all appended records in a log that have not been previously assigned a physical location. All
		/// these records are made available for reading from other marshaling contexts. Then, the records are flushed to disk.
		/// </summary>
		CLFS_FLAG_FORCE_FLUSH = 0x00000002,

		/// <summary>Appends the current record by using the space that is reserved in the marshaling area.</summary>
		CLFS_FLAG_USE_RESERVATION = 0x00000004,

		CLFS_FLAG_REENTRANT_FILE_SYSTEM = 0x00000008,
		CLFS_FLAG_NON_REENTRANT_FILTER = 0x00000010,
		CLFS_FLAG_REENTRANT_FILTER = 0x00000020,
		CLFS_FLAG_IGNORE_SHARE_ACCESS = 0x00000040,
		CLFS_FLAG_READ_IN_PROGRESS = 0x00000080,
		CLFS_FLAG_MINIFILTER_LEVEL = 0x00000100,
		CLFS_FLAG_HIDDEN_SYSTEM_LOG = 0x00000200,
	}

	/// <summary>
	/// Defines types of I/O statistics reported by CLFS and is used when a client calls GetLogIoStatistics. Currently, log flush rates are
	/// the only type of statistic reported, but this enumeration will reflect more types of statistics in the future.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ne-clfs-clfs_iostats_class typedef enum _CLFS_IOSTATS_CLASS {
	// ClfsIoStatsDefault = 0x0000, ClfsIoStatsMax = 0xFFFF } CLFS_IOSTATS_CLASS, *PCLFS_IOSTATS_CLASS, PPCLFS_IOSTATS_CLASS;
	[PInvokeData("clfs.h", MSDNShortId = "NE:clfs._CLFS_IOSTATS_CLASS")]
	public enum CLFS_IOSTATS_CLASS
	{
		/// <summary>
		/// <para>Value:</para>
		/// <para>0x0000</para>
		/// <para>The default I/O statistics exported.</para>
		/// </summary>
		ClfsIoStatsDefault = 0x0000,

		/// <summary>
		/// <para>Value:</para>
		/// <para>0xFFFF</para>
		/// <para>The log flush rate.</para>
		/// </summary>
		ClfsIoStatsMax = 0xFFFF,
	}

	/// <summary>Specifies whether a log is ephemeral.</summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ne-clfs-clfs_log_archive_mode typedef enum _CLFS_LOG_ARCHIVE_MODE {
	// ClfsLogArchiveEnabled = 0x01, ClfsLogArchiveDisabled = 0x02 } CLFS_LOG_ARCHIVE_MODE, *PCLFS_LOG_ARCHIVE_MODE;
	[PInvokeData("clfs.h", MSDNShortId = "NE:clfs._CLFS_LOG_ARCHIVE_MODE")]
	public enum CLFS_LOG_ARCHIVE_MODE
	{
		/// <summary>
		/// <para>Value:</para>
		/// <para>0x01</para>
		/// <para>Enables log archive (ephemeral logs) support.</para>
		/// </summary>
		ClfsLogArchiveEnabled = 1,

		/// <summary>
		/// <para>Value:</para>
		/// <para>0x02</para>
		/// <para>Disables ephemeral logs.</para>
		/// </summary>
		ClfsLogArchiveDisabled,
	}

	/// <summary>Marshalling Context Flag</summary>
	[PInvokeData("clfs.h")]
	[Flags]
	public enum CLFS_MARSHALLING_FLAG : uint
	{
		CLFS_MARSHALLING_FLAG_NONE = 0x00000000,
		CLFS_MARSHALLING_FLAG_DISABLE_BUFF_INIT = 0x00000001,
	}

	/// <summary>Container scan mode flags.</summary>
	[PInvokeData("clfs.h")]
	[Flags]
	public enum CLFS_SCAN_MODE : byte
	{
		/// <summary>
		/// Reinitializes the scan context, but does not allocate associated storage. The initialization is destructive, because all data
		/// that is stored in the current scan context is lost.
		/// </summary>
		CLFS_SCAN_INIT = 0x01,

		/// <summary>
		/// Causes the next call to ScanLogContainers to proceed in a forward direction. Cannot be used if CLFS_SCAN_BACKWARD is specified.
		/// </summary>
		CLFS_SCAN_FORWARD = 0x02,

		/// <summary>
		/// Causes the next call to ScanLogContainers to proceed in a backward direction. Cannot be used if CLFS_SCAN_FORWARD is specified.
		/// </summary>
		CLFS_SCAN_BACKWARD = 0x04,

		/// <summary>Uninitializes the scan context, and deallocates system storage that is associated with a scan context.</summary>
		CLFS_SCAN_CLOSE = 0x08,

		/// <summary>Indicates that the scan context is already initialized.</summary>
		CLFS_SCAN_INITIALIZED = 0x10,

		/// <summary>Indicates that the scanned container descriptors are pre-fetched and buffered.</summary>
		CLFS_SCAN_BUFFERED = 0x20,
	}

	/// <summary>Definition of record types.</summary>
	[PInvokeData("clfs.h")]
	[Flags]
	public enum CLS_RECORD_TYPE : byte
	{
		/// <summary>The default record type of ClfsDataRecord is used.</summary>
		ClfsNullRecord = 0x00,

		/// <summary>User data records are read.</summary>
		ClfsDataRecord = 0x01,

		/// <summary>Restart records are read.</summary>
		ClfsRestartRecord = 0x02,

		/// <summary>Both restart and data records are read.</summary>
		ClfsClientRecord = 0x03
	}

	/// <summary>Determines whether two LSNs from the same stream are equal.</summary>
	/// <param name="plsn1">A pointer to a CLFS_LSN structure to be compared with <c>plsn2</c>.</param>
	/// <param name="plsn2">A pointer to a CLFS_LSN structure to be compared with <c>plsn1</c>.</param>
	/// <returns>Returns <c>TRUE</c> if the two LSNs are equal; otherwise, <c>FALSE</c>.</returns>
	/// <remarks>
	/// <para>CLFS_LSN_NULL (the smallest LSN) and CLFS_LSN_INVALID (larger than any valid LSN) are valid arguments to this function.</para>
	/// <para>LSNs from different streams are not comparable. Do not use this function to compare LSNs from different streams.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/nf-clfs-clfslsnequal CLFSUSER_API BOOLEAN LsnEqual( [in] const CLS_LSN *plsn1,
	// [in] const CLS_LSN *plsn2 );
	[DllImport(Lib_Clfsw32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("clfs.h", MSDNShortId = "NF:clfs.ClfsLsnEqual")]
	[return: MarshalAs(UnmanagedType.U1)]
	public static extern bool LsnEqual(in CLS_LSN plsn1, in CLS_LSN plsn2);

	/// <summary>Determines whether one LSN is greater than another LSN. The two LSNs must be from the same stream.</summary>
	/// <param name="plsn1">A pointer to a CLFS_LSN structure to be compared with <c>plsn2</c>.</param>
	/// <param name="plsn2">A pointer to a CLFS_LSN structure to be compared with <c>plsn1</c>.</param>
	/// <returns><c>TRUE</c> if <c>plsn1</c> is strictly greater than <c>plsn2</c>; otherwise, <c>FALSE</c>.</returns>
	/// <remarks>
	/// <para>CLFS_LSN_NULL (the smallest LSN) and CLFS_LSN_INVALID (larger than any valid LSN) are valid arguments to this function.</para>
	/// <para>LSNs from different streams are not comparable. Do not use this function to compare LSNs from different streams.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/nf-clfs-clfslsngreater CLFSUSER_API BOOLEAN LsnGreater( [in] const CLS_LSN
	// *plsn1, [in] const CLS_LSN *plsn2 );
	[DllImport(Lib_Clfsw32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("clfs.h", MSDNShortId = "NF:clfs.ClfsLsnGreater")]
	[return: MarshalAs(UnmanagedType.U1)]
	public static extern bool LsnGreater(in CLS_LSN plsn1, in CLS_LSN plsn2);

	/// <summary>Determines whether one LSN is less than another LSN. The two LSNs must be from the same stream.</summary>
	/// <param name="plsn1">A pointer to a CLFS_LSN structure to be compared with <c>plsn2</c>.</param>
	/// <param name="plsn2">A pointer to a CLFS_LSN structure to be compared with <c>plsn1</c>.</param>
	/// <returns><c>TRUE</c> if <c>plsn1</c> is strictly less than <c>plsn2</c>; otherwise, <c>FALSE</c>.</returns>
	/// <remarks>
	/// <para>CLFS_LSN_NULL (the smallest LSN) and CLFS_LSN_INVALID (larger than any valid LSN) are valid arguments to this function.</para>
	/// <para>LSNs from different streams are not comparable. Do not use this function to compare LSNs from different streams.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/nf-clfs-clfslsnless CLFSUSER_API BOOLEAN LsnLess( [in] const CLS_LSN *plsn1,
	// [in] const CLS_LSN *plsn2 );
	[DllImport(Lib_Clfsw32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("clfs.h", MSDNShortId = "NF:clfs.ClfsLsnLess")]
	[return: MarshalAs(UnmanagedType.U1)]
	public static extern bool LsnLess(in CLS_LSN plsn1, in CLS_LSN plsn2);

	/// <summary>Determines whether a specified LSN is equal to the smallest possible LSN, which is CLFS_LSN_NULL.</summary>
	/// <param name="plsn">A pointer to the CLFS_LSN structure to be tested.</param>
	/// <returns><c>TRUE</c> if <c>plsn</c> is equal to CLFS_LSN_NULL; otherwise, <c>FALSE</c>.</returns>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/nf-clfs-clfslsnnull CLFSUSER_API BOOLEAN LsnNull( [in] const CLS_LSN *plsn );
	[DllImport(Lib_Clfsw32, SetLastError = false, ExactSpelling = true)]
	[PInvokeData("clfs.h", MSDNShortId = "NF:clfs.ClfsLsnNull")]
	[return: MarshalAs(UnmanagedType.U1)]
	public static extern bool LsnNull(in CLS_LSN plsn);

	/// <summary>Represents a node identifier.</summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-clfs_node_id typedef struct _CLFS_NODE_ID { ULONG cType; ULONG cbNode;
	// } CLFS_NODE_ID, *PCLFS_NODE_ID;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLFS_NODE_ID")]
	[StructLayout(LayoutKind.Sequential)]
	public struct CLFS_NODE_ID
	{
		/// <summary>The CLFS node type.</summary>
		public uint cType;

		/// <summary>The size of the CLFS node, in bytes.</summary>
		public uint cbNode;
	}

	/// <summary>Used by the GetNextLogArchiveExtent function to return information about log archive extents.</summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_archive_descriptor typedef struct _CLS_ARCHIVE_DESCRIPTOR {
	// ULONGLONG coffLow; ULONGLONG coffHigh; CLS_CONTAINER_INFORMATION infoContainer; } CLS_ARCHIVE_DESCRIPTOR, *PCLS_ARCHIVE_DESCRIPTOR, PPCLS_ARCHIVE_DESCRIPTOR;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_ARCHIVE_DESCRIPTOR")]
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
	public struct CLS_ARCHIVE_DESCRIPTOR
	{
		/// <summary>The offset in the container to the first byte of the archive extent.</summary>
		public ulong coffLow;

		/// <summary>The offset in the container to the last byte of the archive extent.</summary>
		public ulong coffHigh;

		/// <summary>
		/// The container information structure that describes the container associated with the archive extent. For more information, see CLFS_CONTAINER_INFORMATION.
		/// </summary>
		public CLS_CONTAINER_INFORMATION infoContainer;
	}

	/// <summary>
	/// Describes general information about a container. The CreateLogContainerScanContext and ScanLogContainers functions use container
	/// descriptors to scan and return information about all Common Log File System (CLFS) containers.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_container_information typedef struct _CLS_CONTAINER_INFORMATION {
	// ULONG FileAttributes; ULONGLONG CreationTime; ULONGLONG LastAccessTime; ULONGLONG LastWriteTime; LONGLONG ContainerSize; ULONG
	// FileNameActualLength; ULONG FileNameLength; WCHAR FileName[CLFS_MAX_CONTAINER_INFO]; CLFS_CONTAINER_STATE State; CLFS_CONTAINER_ID
	// PhysicalContainerId; CLFS_CONTAINER_ID LogicalContainerId; } CLS_CONTAINER_INFORMATION, *PCLS_CONTAINER_INFORMATION, PPCLS_CONTAINER_INFORMATION;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_CONTAINER_INFORMATION")]
	[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
	public struct CLS_CONTAINER_INFORMATION
	{
		/// <summary>
		/// <para>The file system attributes. CLFS uses the following attributes:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>FILE_ATTRIBUTE_ARCHIVE - The log is not ephemeral.</term>
		/// </item>
		/// <item>
		/// <term>FILE_ATTRIBUTE_DEDICATED - The log is not multiplexed.</term>
		/// </item>
		/// <item>
		/// <term>FILE_ATTRIBUTE_READONLY - The file is read-only. Applications can read the file, but cannot write to it or delete it.</term>
		/// </item>
		/// </list>
		/// <para>CLFS ignores but preserves all other file attribute values. The</para>
		/// <para>SetFileAttributes</para>
		/// <para>topic lists the valid values for attributes.</para>
		/// </summary>
		public FileFlagsAndAttributes FileAttributes;

		/// <summary>The time a file is created.</summary>
		public FILETIME CreationTime;

		/// <summary>The last time a container is read from or written to.</summary>
		public FILETIME LastAccessTime;

		/// <summary>The last time a container is written to.</summary>
		public FILETIME LastWriteTime;

		/// <summary>The size of a container, in bytes.</summary>
		public long ContainerSize;

		/// <summary>
		/// <para>The size of the actual file name, in characters.</para>
		/// <para>This number is different than <c>FileNameLength</c> when the file name of the container is longer than MAX_PATH_LENGTH.</para>
		/// </summary>
		public uint FileNameActualLength;

		/// <summary>The size of the file name in the <c>FileName</c> buffer, in characters.</summary>
		public uint FileNameLength;

		/// <summary>A pointer to a string that contains the file name for a container.</summary>
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
		public string FileName;

		/// <summary>
		/// <para>The current state of a container.</para>
		/// <para>This member can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term><c>ClfsContainerInitializing</c></term>
		/// <term>The container is in the process of initializing.</term>
		/// </item>
		/// <item>
		/// <term><c>ClfsContainerInactive</c></term>
		/// <term>The container is allocated, but is not in the active region of the log.</term>
		/// </item>
		/// <item>
		/// <term><c>ClfsContainerActive</c></term>
		/// <term>The container is being used as storage for part of the log.</term>
		/// </item>
		/// <item>
		/// <term><c>ClfsContainerActivePendingDelete</c></term>
		/// <term>The container is marked for deletion, but still contains part of the active log.</term>
		/// </item>
		/// <item>
		/// <term><c>ClfsContainerPendingArchive</c></term>
		/// <term>The container is marked for archive.</term>
		/// </item>
		/// <item>
		/// <term><c>ClfsContainerPendingArchiveAndDelete</c></term>
		/// <term>The container is marked for deletion, but still contains log data that is not archived.</term>
		/// </item>
		/// </list>
		/// </summary>
		public CLFS_CONTAINER_STATE State;

		/// <summary>The physical container identifier that cannot be changed.</summary>
		public CLFS_CONTAINER_ID PhysicalContainerId;

		/// <summary>The logical container identifier that changes every time the container is recycled.</summary>
		public CLFS_CONTAINER_ID LogicalContainerId;
	}

	/// <summary>Describes general information about a log. The GetLogFileInformation function returns the <c>CLFS_INFORMATION</c> structure.</summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_information typedef struct _CLS_INFORMATION { LONGLONG
	// TotalAvailable; LONGLONG CurrentAvailable; LONGLONG TotalReservation; ULONGLONG BaseFileSize; ULONGLONG ContainerSize; ULONG
	// TotalContainers; ULONG FreeContainers; ULONG TotalClients; ULONG Attributes; ULONG FlushThreshold; ULONG SectorSize; CLS_LSN
	// MinArchiveTailLsn; CLS_LSN BaseLsn; CLS_LSN LastFlushedLsn; CLS_LSN LastLsn; CLS_LSN RestartLsn; GUID Identity; } CLS_INFORMATION,
	// *PCLS_INFORMATION, *PPCLS_INFORMATION;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_INFORMATION")]
	[StructLayout(LayoutKind.Sequential)]
	public struct CLS_INFORMATION
	{
		/// <summary>
		/// <para>The total available space that is allocated to a log, in bytes.</para>
		/// <para>This member is the sum of the sizes of all containers that are allocated to the dedicated log.</para>
		/// </summary>
		public long TotalAvailable;

		/// <summary>The space that is available in a log to append new records and reservation allocations, in bytes.</summary>
		public long CurrentAvailable;

		/// <summary>The total space in a log that is dedicated to reservation allocations.</summary>
		public long TotalReservation;

		/// <summary>The size of the base log, in bytes.</summary>
		public ulong BaseFileSize;

		/// <summary>The size of a container, in bytes.</summary>
		public ulong ContainerSize;

		/// <summary>The number of active containers that are associated with a dedicated log.</summary>
		public uint TotalContainers;

		/// <summary>The number of containers that are not in an active log.</summary>
		public uint FreeContainers;

		/// <summary>The number of log streams that are active in a physical log.</summary>
		public uint TotalClients;

		/// <summary>
		/// The log attributes that are set by using the <c>fFlagsAndAttributes</c> parameter of CreateLogFile when a log is created.
		/// </summary>
		public uint Attributes;

		/// <summary>
		/// The number of bytes of data that can remain pending on the internal flush queue before the Common Log File System (CLFS)
		/// automatically writes the data to disk.
		/// </summary>
		public uint FlushThreshold;

		/// <summary>
		/// <para>The sector size of the underlying disk geometry, in bytes.</para>
		/// <para>The sector size is assumed to be a multiple of 512 and consistent across log containers.</para>
		/// </summary>
		public uint SectorSize;

		/// <summary>The log sequence number (LSN) of the log archive tail.</summary>
		public CLS_LSN MinArchiveTailLsn;

		/// <summary>The LSN that marks the start of the active region of a log.</summary>
		public CLS_LSN BaseLsn;

		/// <summary>
		/// The value of <c>LastFlushedLsn</c> indicates that any LSNs smaller than the one specified are already flushed to disk.
		/// </summary>
		public CLS_LSN LastFlushedLsn;

		/// <summary>The value of <c>LastLsn</c> indicates that any LSNs smaller than the one specified are already appended to the log.</summary>
		public CLS_LSN LastLsn;

		/// <summary>
		/// <para>The LSN of the last written restart record.</para>
		/// <para>If the log does not have a restart area, the LSN has the value of CLFS_LSN_INVALID.</para>
		/// </summary>
		public CLS_LSN RestartLsn;

		/// <summary>The unique identifier for a log.</summary>
		public Guid Identity;
	}

	/// <summary>
	/// Defines the statistics that are reported by GetLogIoStatistics. Initially, statistics packets report only flush statistics, including
	/// the frequency of data and metadata flushes on a physical log and the amount of data and metadata flushed. The flush statistics are
	/// defined by the following I/O statistics packet types.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_io_statistics typedef struct _CLS_IO_STATISTICS {
	// CLS_IO_STATISTICS_HEADER hdrIoStats; ULONGLONG cFlush; ULONGLONG cbFlush; ULONGLONG cMetaFlush; ULONGLONG cbMetaFlush; }
	// CLS_IO_STATISTICS, *PCLS_IO_STATISTICS, PPCLS_IO_STATISTICS;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_IO_STATISTICS")]
	[StructLayout(LayoutKind.Sequential)]
	public struct CLS_IO_STATISTICS
	{
		/// <summary>The header for the statistics buffer.</summary>
		public CLS_IO_STATISTICS_HEADER hdrIoStats;

		/// <summary>The frequency of data flushes for the logging session.</summary>
		public ulong cFlush;

		/// <summary>The cumulative number of bytes of data flushed in the logging session.</summary>
		public ulong cbFlush;

		/// <summary>The frequency of metadata flushes for the logging session.</summary>
		public ulong cMetaFlush;

		/// <summary>The cumulative number of bytes of metadata flushed in the logging session.</summary>
		public ulong cbMetaFlush;
	}

	/// <summary>
	/// Header for information retrieved by the GetLogIoStatistics function, which defines the I/O performance counters of a log.
	/// </summary>
	/// <remarks>This header is followed by the I/O statistics counters.</remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_io_statistics_header typedef struct _CLS_IO_STATISTICS_HEADER {
	// UCHAR ubMajorVersion; UCHAR ubMinorVersion; CLFS_IOSTATS_CLASS eStatsClass; USHORT cbLength; ULONG coffData; }
	// CLS_IO_STATISTICS_HEADER, *PCLS_IO_STATISTICS_HEADER, PPCLS_IO_STATISTICS_HEADER;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_IO_STATISTICS_HEADER")]
	[StructLayout(LayoutKind.Sequential)]
	public struct CLS_IO_STATISTICS_HEADER
	{
		/// <summary>The major version of the statistics buffer.</summary>
		public byte ubMajorVersion;

		/// <summary>The minor version of the statistics buffer.</summary>
		public byte ubMinorVersion;

		/// <summary>
		/// The class of I/O statistics that is exported. Currently, flush statistics are the only statistics information exported. These
		/// statistics include the frequency of data and metadata flushes on a dedicated log and the amount of data and metadata flushed.
		/// Because flush statistics are the sole statistics class, this member is currently unused but will be used in the future.
		/// </summary>
		public CLFS_IOSTATS_CLASS eStatsClass;

		/// <summary>The length of the statistics buffer, including the header.</summary>
		public ushort cbLength;

		/// <summary>
		/// The offset of statistics counters from the beginning of the packet where the statistics data begins. This field allows
		/// transparent modifications to the header and length without affecting how the statistics data is accessed.
		/// </summary>
		public uint coffData;
	}

	/// <summary>Represents a valid log address.</summary>
	/// <remarks>
	/// <para>
	/// The LSN is the valid address that is unique to a client, and returned after the client appends a record to the log. The address
	/// remains valid if the system does not fail, or its marshaled log buffer is flushed successfully to disk.
	/// </para>
	/// <para>In log streams, LSNs increase monotonically. You cannot compare LSNs between log streams.</para>
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_lsn typedef struct _CLS_LSN { ULONGLONG Internal; } CLS_LSN,
	// *PCLS_LSN, PPCLS_LSN;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_LSN")]
	[StructLayout(LayoutKind.Sequential)]
	public struct CLS_LSN : IEquatable<CLS_LSN>, IComparable<CLS_LSN>
	{
		/// <summary>The log sequence number (LSN).</summary>
		public ulong Internal;

		/// <summary>Creates a log sequence number (LSN), given a container ID, a block offset, and a record sequence number.</summary>
		/// <param name="cidContainer">The container ID. This value must be an integer between 0x0 and 0xFFFFFFFF.</param>
		/// <param name="offBlock">The block offset. This value must be a multiple of 512.</param>
		/// <param name="cRecord">The record sequence number. This value must be an integer between 0 - 511.</param>
		public CLS_LSN(CLFS_CONTAINER_ID cidContainer, uint offBlock, uint cRecord) => Internal = LsnCreate(cidContainer, offBlock, cRecord).Internal;

		/// <summary>Retrieves the logical container ID from this LSN.</summary>
		/// <value>
		/// Returns the logical container ID. The logical container ID is not necessarily the same as the ID of the physical container on
		/// stable storage.
		/// </value>
		public CLFS_CONTAINER_ID ContainerId => LsnContainer(this);

		/// <summary>Returns the sector-aligned block offset that is contained in this LSN.</summary>
		/// <value><c>LsnBlockOffset</c> returns the block offset.</value>
		/// <remarks>
		/// <para>
		/// The block offset that is returned is a multiple of the sector size on the stable storage medium. For example, if the sector size
		/// is 1024 bytes, the block offset is a multiple of 1024.
		/// </para>
		/// </remarks>
		public uint BlockOffset => LsnBlockOffset(this);

		/// <summary>Retrieves the record sequence number.</summary>
		/// <value>The record sequence number.</value>
		public uint RecordSequence => LsnRecordSequence(this);

		/// <summary>Determines if this is equal to CLFS_LSN_INVALID.</summary>
		/// <value><see langword="true"/> if <c>plsn</c> is equal to CLFS_LSN_INVALID; otherwise, <see langword="false"/>.</value>
		public bool IsInvalid => LsnInvalid(this);

		/// <summary>Determines if this is equal to the smallest possible LSN, which is CLFS_LSN_NULL.</summary>
		/// <value><see langword="true"/> if <c>plsn</c> is equal to CLFS_LSN_NULL; otherwise, <see langword="false"/>.</value>
		public bool IsNull => LsnNull(this);

		/// <summary>Implements the operator ==.</summary>
		/// <param name="left">The left.</param>
		/// <param name="right">The right.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator ==(CLS_LSN left, CLS_LSN right) => left.Equals(right);

		/// <summary>Implements the operator !=.</summary>
		/// <param name="left">The left.</param>
		/// <param name="right">The right.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator !=(CLS_LSN left, CLS_LSN right) => !(left==right);

		/// <summary>Implements the operator &gt;.</summary>
		/// <param name="left">The left.</param>
		/// <param name="right">The right.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator >(CLS_LSN left, CLS_LSN right) => LsnGreater(left, right);

		/// <summary>Implements the operator &lt;.</summary>
		/// <param name="left">The left.</param>
		/// <param name="right">The right.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator <(CLS_LSN left, CLS_LSN right) => LsnLess(left, right);

		/// <summary>Implements the operator op_Increment.</summary>
		/// <param name="value">The value.</param>
		/// <returns>The result of the operator.</returns>
		public static CLS_LSN operator ++(CLS_LSN value) => LsnIncrement(value);

		/// <summary>Implements the operator op_Decrement.</summary>
		/// <param name="value">The value.</param>
		/// <returns>The result of the operator.</returns>
		public static CLS_LSN operator --(CLS_LSN value) => LsnDecrement(value);

		/// <inheritdoc/>
		public int CompareTo(CLS_LSN other) => LsnLess(this, other) ? -1 : (LsnEqual(this, other) ? 0 : 1);

		/// <inheritdoc/>
		public override bool Equals(object obj) => obj is CLS_LSN lSN && Equals(lSN);

		/// <inheritdoc/>
		public bool Equals(CLS_LSN other) => LsnEqual(this, other);

		/// <inheritdoc/>
		public override int GetHashCode() => 158955808+Internal.GetHashCode();

		/// <inheritdoc/>
		public override string ToString() => $"{{{Internal}}}";

		/// <summary>Represents an invalid LSN.</summary>
		public static readonly CLS_LSN CLFS_LSN_INVALID = new() { Internal = 0xFFFFFFFF00000000UL };

		/// <summary>Represents a NULL LSN.</summary>
		public static readonly CLS_LSN CLFS_LSN_NULL = default;
	}

	/// <summary>
	/// Contains information about the containers that are being scanned by ScanLogContainers, the kind of scan that is being performed, and
	/// a cursor to track which containers have been scanned.
	/// </summary>
	/// <remarks>
	/// This structure is allocated by the client, initialized using CreateLogContainerScanContext, and then passed to ScanLogContainers in
	/// repeated calls.
	/// </remarks>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_scan_context-r1 typedef struct _CLS_SCAN_CONTEXT { CLFS_NODE_ID
	// cidNode; HANDLE hLog; ULONG cIndex; ULONG cContainers; ULONG cContainersReturned; CLFS_SCAN_MODE eScanMode; PCLS_CONTAINER_INFORMATION
	// pinfoContainer; } CLS_SCAN_CONTEXT, *PCLS_SCAN_CONTEXT, PPCLS_SCAN_CONTEXT;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_SCAN_CONTEXT~r1")]
	[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
	public struct CLS_SCAN_CONTEXT
	{
		/// <summary>The ID of the current node. For more information, see CLFS_NODE_ID.</summary>
		[FieldOffset(0)]
		public CLFS_NODE_ID cidNode;

		/// <summary>A handle to the log being scanned that is obtained from CreateLogFile with permissions to scan the log containers.</summary>
		[FieldOffset(8)]
		public HLOG hLog;

		/// <summary>The index of the current container.</summary>
		[FieldOffset(16)]
		public uint cIndex;

		/// <summary>
		/// <para>The number of system-allocated CLFS_CONTAINER_INFORMATION structures in an array that is pointed to by <c>pinfoContainer</c>.</para>
		/// <para>
		/// That is, this member is the number of containers to scan with each scan call. The caller knows the scan is complete when the
		/// number of containers returned is less than this value.
		/// </para>
		/// </summary>
		[FieldOffset(24)]
		public uint cContainers;

		/// <summary>The number of containers that are returned after a call to ScanLogContainers.</summary>
		[FieldOffset(32)]
		public uint cContainersReturned;

		/// <summary>
		/// <para>The mode in which containers are scanned.</para>
		/// <para>Containers can be scanned in one of the following modes.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term><c>CLFS_SCAN_INIT</c></term>
		/// <term>
		/// Initializes the scan context, but does not allocate associated storage. The initialization is destructive, because all data that
		/// is stored in the current scan context is lost.
		/// </term>
		/// </item>
		/// <item>
		/// <term><c>CLFS_SCAN_CLOSE</c></term>
		/// <term>Uninitializes the scan context and deallocates system storage that is associated with a scan context.</term>
		/// </item>
		/// <item>
		/// <term><c>CLFS_SCAN_FORWARD</c></term>
		/// <term>
		/// Causes the next call to ScanLogContainers to proceed in a forward direction. Cannot be used if <c>CLFS_SCAN_BACKWARD</c> is specified.
		/// </term>
		/// </item>
		/// <item>
		/// <term><c>CLFS_SCAN_BACKWARD</c></term>
		/// <term>
		/// Causes the next call to ScanLogContainers to proceed in a backward direction. Cannot be used if <c>CLFS_SCAN_FORWARD</c> is specified.
		/// </term>
		/// </item>
		/// </list>
		/// </summary>
		[FieldOffset(40)]
		public CLFS_SCAN_MODE eScanMode;

		[FieldOffset(48)]
		private IntPtr _pinfoContainer;

		/// <summary>
		/// A pointer to a client-allocated array of CLFS_CONTAINER_INFORMATION structures to be filled by ScanLogContainers after each
		/// successful call.
		/// </summary>
		public CLS_CONTAINER_INFORMATION[] pinfoContainer => _pinfoContainer.ToArray<CLS_CONTAINER_INFORMATION>((int)cContainersReturned);
	}

	/// <summary>
	/// Contains a user buffer, which is to become part of a log record, and its length. The ReserveAndAppendLog function uses
	/// <c>CLFS_WRITE_ENTRY</c> structures in the routine that appends log records to logs. This routine requires the client to specify a set
	/// of structures. <c>ReserveAndAppendLog</c> gathers these structures and formats them into a log record in a marshaling buffer, which
	/// is eventually flushed to the log.
	/// </summary>
	// https://docs.microsoft.com/en-us/windows/win32/api/clfs/ns-clfs-cls_write_entry typedef struct _CLS_WRITE_ENTRY { PVOID Buffer; ULONG
	// ByteLength; } CLS_WRITE_ENTRY, *PCLS_WRITE_ENTRY, PPCLS_WRITE_ENTRY;
	[PInvokeData("clfs.h", MSDNShortId = "NS:clfs._CLS_WRITE_ENTRY")]
	[StructLayout(LayoutKind.Sequential)]
	public struct CLS_WRITE_ENTRY
	{
		/// <summary>The log record data buffer.</summary>
		public IntPtr Buffer;

		/// <summary>The length of the log record data buffer, in bytes.</summary>
		public uint ByteLength;
	}
}