Documentation
use core::ffi::*;

pub type POpaque = *mut c_void;
pub type Stub = *mut c_void;

pub type NTSTATUS = c_long;

#[repr(C)]
pub struct FLT_CONTEXT_REGISTRATION {
    pub ContextType: u16,
    pub Flags: u16,
    pub ContextCleanupCallback: *const extern "C" fn(POpaque, u16),
    pub Size: u64,
    pub PoolTag: u32,
    pub ContextAllocateCallback: *const extern "C" fn(Stub) -> NTSTATUS,
    pub ContextFreeCallback: *const extern "C" fn(Stub) -> NTSTATUS,
    pub Reserved1: POpaque,
}

const TestChecker: [u8; 56] = [0; core::mem::size_of::<FLT_CONTEXT_REGISTRATION>()];

#[repr(C)]
pub struct FLT_OPERATION_REGISTRATION {
    pub MajorFunction: u8,
    pub Flags: u32,
    pub PreOperation: *const extern "C" fn(POpaque, *const FLT_RELATED_OBJECTS, POpaque) -> i32,
    pub PostOperation:
        *const extern "C" fn(POpaque, *const FLT_RELATED_OBJECTS, POpaque, u32) -> i32,
    pub Reserved1: POpaque,
}

#[repr(C)]
pub struct UNICODE_STRING {
    pub Length: u16,
    pub MaximumLength: u16,
    pub buffer: *mut u16,
}

#[repr(C)]
pub struct FILE_OBJECT {
    pub Type: i16,
    pub Size: i16,
    pub DeviceObject: POpaque,
    pub Vpb: POpaque,
    pub FsContext: POpaque,
    pub FsContext2: POpaque,
    pub SectionObjectPointer: POpaque,
    pub PrivateCacheMap: POpaque,
    pub FinalStatus: i32,
    pub RelatedFileObject: *mut FILE_OBJECT,
    pub LockOperation: bool,
    pub DeletePending: bool,
    pub ReadAccess: bool,
    pub WriteAccess: bool,
    pub DeleteAccess: bool,
    pub SharedRead: bool,
    pub SharedWrite: bool,
    pub SharedDelete: bool,
    pub Flags: u32,
    pub FileName: UNICODE_STRING,
    pub CurrentByteOffset: u64,
    pub Waiters: u32, // volatile
    pub Busy: u32,    // volatile
    pub LastLock: POpaque,
    // Incomplete
}

#[repr(C)]
pub struct FLT_RELATED_OBJECTS {
    pub Size: u16,
    pub TransactionContext: u16,
    pub Filter: POpaque,
    pub Volume: POpaque,
    pub Instance: POpaque,
    pub FileObject: *const FILE_OBJECT,
    pub Transaction: POpaque,
}

#[repr(C)]
pub struct FLT_REGISTRATION {
    pub Size: u16,
    pub Version: u16,
    pub Flags: u32,
    pub ContextRegistration: *const FLT_CONTEXT_REGISTRATION,
    pub OperationRegistration: *const FLT_OPERATION_REGISTRATION,
    pub FilterUnloadCallback: *const extern "C" fn(u32) -> NTSTATUS,
    pub InstanceSetupCallback: *const extern "C" fn(POpaque, u32, u32, i32) -> NTSTATUS,
    pub InstanceQueryTeardownCallback: *const extern "C" fn(POpaque, u32) -> NTSTATUS,
    pub InstanceTeardownStartCallback: *const extern "C" fn(POpaque, u32) -> NTSTATUS,
    pub InstanceTeardownCompleteCallback: *const extern "C" fn(POpaque, u32) -> NTSTATUS,
    pub GenerateFileNameCallback: *const extern "C" fn(Stub) -> NTSTATUS,
    pub NormalizeNameComponentCallback: *const extern "C" fn(Stub) -> NTSTATUS,
    pub NormalizeContextCleanupCallback: *const extern "C" fn(Stub) -> NTSTATUS,
    pub TransactionNotificationCallback: *const extern "C" fn(Stub) -> NTSTATUS,
    pub NormalizeNameComponentExCallback: *const extern "C" fn(Stub) -> NTSTATUS,
    // pub SectionNotificationCallback: *const extern "C" fn(Stub) -> NTSTATUS,
}

extern "C" {
    pub fn DbgPrint(Format: *const u8, ...);

    pub fn FltRegisterFilter(
        driver: POpaque,
        registration: *const FLT_REGISTRATION,
        ret_filter: *mut POpaque,
    ) -> NTSTATUS;
    pub fn FltStartFiltering(filter: POpaque) -> NTSTATUS;
    pub fn FltUnregisterFilter(filter: POpaque);
    pub fn FltReferenceContext(context: POpaque);
    pub fn FltReleaseContext(context: POpaque);
    pub fn FltAllocateContext(
        filter: POpaque,
        context_type: u16,
        context_size: u64,
        pool_type: i32,
        returned_context: *mut POpaque,
    ) -> NTSTATUS;

    pub fn FltSetInstanceContext(
        instance: POpaque,
        operation: i32,
        new_context: POpaque,
        old_context: *mut POpaque,
    ) -> i32;
    pub fn FltGetInstanceContext(instance: POpaque, context: *mut POpaque) -> i32;

    pub fn FltGetRequestorProcess(callback_data: POpaque) -> POpaque;

    pub fn SeLocateProcessImageName(
        process: POpaque,
        image_file_name: *mut *mut UNICODE_STRING,
    ) -> i32;

    pub fn ExFreePoolWithTag(p: POpaque, tag: u32);
}