/* Copyright (c) Mark Harmstone 2016-17 * * This file is part of WinBtrfs. * * WinBtrfs is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public Licence as published by * the Free Software Foundation, either version 3 of the Licence, or * (at your option) any later version. * * WinBtrfs is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public Licence for more details. * * You should have received a copy of the GNU Lesser General Public Licence * along with WinBtrfs. If not, see . */ #ifndef BTRFS_DRV_H_DEFINED #define BTRFS_DRV_H_DEFINED #ifndef __REACTOS__ #undef _WIN32_WINNT #undef NTDDI_VERSION #define _WIN32_WINNT 0x0601 #define NTDDI_VERSION 0x06020000 // Win 8 #define _CRT_SECURE_NO_WARNINGS #define _NO_CRT_STDIO_INLINE #endif /* __REACTOS__ */ #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4163) #pragma warning(disable:4311) #pragma warning(disable:4312) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wsign-conversion" #endif #include #include #ifdef __REACTOS__ #include #endif /* __REACTOS__ */ #include #ifdef __REACTOS__ #include #include #include #endif /* __REACTOS__ */ #include #include #ifdef _MSC_VER #pragma warning(pop) #else #pragma GCC diagnostic pop #endif #include #include #include #ifndef __REACTOS__ // Not actually used #include #endif /* __REACTOS__ */ #include "btrfs.h" #include "btrfsioctl.h" #ifdef _DEBUG // #define DEBUG_FCB_REFCOUNTS // #define DEBUG_LONG_MESSAGES // #define DEBUG_FLUSH_TIMES // #define DEBUG_STATS // #define DEBUG_CHUNK_LOCKS #define DEBUG_PARANOID #endif #define UNUSED(x) (void)(x) #define BTRFS_NODE_TYPE_CCB 0x2295 #define BTRFS_NODE_TYPE_FCB 0x2296 #define ALLOC_TAG 0x7442484D //'MHBt' #define ALLOC_TAG_ZLIB 0x7A42484D //'MHBz' #define UID_NOBODY 65534 #define GID_NOBODY 65534 #define EA_NTACL "security.NTACL" #define EA_NTACL_HASH 0x45922146 #define EA_DOSATTRIB "user.DOSATTRIB" #define EA_DOSATTRIB_HASH 0x914f9939 #define EA_REPARSE "user.reparse" #define EA_REPARSE_HASH 0xfabad1fe #define EA_EA "user.EA" #define EA_EA_HASH 0x8270dd43 #define EA_PROP_COMPRESSION "btrfs.compression" #define EA_PROP_COMPRESSION_HASH 0x20ccdf69 #define MAX_EXTENT_SIZE 0x8000000 // 128 MB #define COMPRESSED_EXTENT_SIZE 0x20000 // 128 KB #define READ_AHEAD_GRANULARITY COMPRESSED_EXTENT_SIZE // really ought to be a multiple of COMPRESSED_EXTENT_SIZE #define IO_REPARSE_TAG_LXSS_SYMLINK 0xa000001d // undocumented? #define IO_REPARSE_TAG_LXSS_SOCKET 0x80000023 #define IO_REPARSE_TAG_LXSS_FIFO 0x80000024 #define IO_REPARSE_TAG_LXSS_CHARDEV 0x80000025 #define IO_REPARSE_TAG_LXSS_BLOCKDEV 0x80000026 #define BTRFS_VOLUME_PREFIX L"\\Device\\Btrfs{" #ifdef _MSC_VER #define try __try #define except __except #define finally __finally #else #define try if (1) #define except(x) if (0 && (x)) #define finally if (1) #endif #ifndef FILE_SUPPORTS_BLOCK_REFCOUNTING #define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 #endif #ifndef FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL #define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000 #endif typedef struct _DUPLICATE_EXTENTS_DATA { HANDLE FileHandle; LARGE_INTEGER SourceFileOffset; LARGE_INTEGER TargetFileOffset; LARGE_INTEGER ByteCount; } DUPLICATE_EXTENTS_DATA, *PDUPLICATE_EXTENTS_DATA; #define FSCTL_DUPLICATE_EXTENTS_TO_FILE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 209, METHOD_BUFFERED, FILE_WRITE_ACCESS) typedef struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER { WORD ChecksumAlgorithm; WORD Reserved; DWORD Flags; DWORD ChecksumChunkSizeInBytes; DWORD ClusterSizeInBytes; } FSCTL_GET_INTEGRITY_INFORMATION_BUFFER, *PFSCTL_GET_INTEGRITY_INFORMATION_BUFFER; typedef struct _FSCTL_SET_INTEGRITY_INFORMATION_BUFFER { WORD ChecksumAlgorithm; WORD Reserved; DWORD Flags; } FSCTL_SET_INTEGRITY_INFORMATION_BUFFER, *PFSCTL_SET_INTEGRITY_INFORMATION_BUFFER; #define FSCTL_GET_INTEGRITY_INFORMATION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 159, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_SET_INTEGRITY_INFORMATION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 160, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) #ifndef __REACTOS__ #ifndef _MSC_VER #define __drv_aliasesMem #define _Requires_lock_held_(a) #define _Requires_exclusive_lock_held_(a) #define _Releases_lock_(a) #define _Out_writes_bytes_opt_(a) #define _Pre_satisfies_(a) #define _Post_satisfies_(a) #define _Releases_exclusive_lock_(a) #define _Dispatch_type_(a) #define _Create_lock_level_(a) #define _Lock_level_order_(a,b) #define _Has_lock_level_(a) #define _Requires_lock_not_held_(a) #define _Acquires_exclusive_lock_(a) #define _Acquires_shared_lock_(a) #endif #endif _Create_lock_level_(tree_lock) _Create_lock_level_(fcb_lock) _Lock_level_order_(tree_lock, fcb_lock) struct _device_extension; typedef struct _fcb_nonpaged { FAST_MUTEX HeaderMutex; SECTION_OBJECT_POINTERS segment_object; ERESOURCE resource; ERESOURCE paging_resource; ERESOURCE dir_children_lock; } fcb_nonpaged; struct _root; typedef struct { UINT64 offset; UINT16 datalen; BOOL unique; BOOL ignore; BOOL inserted; UINT32* csum; LIST_ENTRY list_entry; EXTENT_DATA extent_data; } extent; typedef struct { UINT64 parent; UINT64 index; UNICODE_STRING name; ANSI_STRING utf8; LIST_ENTRY list_entry; } hardlink; struct _file_ref; typedef struct { KEY key; UINT64 index; UINT8 type; ANSI_STRING utf8; UINT32 hash; UNICODE_STRING name; UINT32 hash_uc; UNICODE_STRING name_uc; ULONG size; struct _file_ref* fileref; LIST_ENTRY list_entry_index; LIST_ENTRY list_entry_hash; LIST_ENTRY list_entry_hash_uc; } dir_child; enum prop_compression_type { PropCompression_None, PropCompression_Zlib, PropCompression_LZO, PropCompression_ZSTD }; typedef struct { LIST_ENTRY list_entry; USHORT namelen; USHORT valuelen; BOOL dirty; char data[1]; } xattr; typedef struct _fcb { FSRTL_ADVANCED_FCB_HEADER Header; struct _fcb_nonpaged* nonpaged; LONG refcount; POOL_TYPE pool_type; struct _device_extension* Vcb; struct _root* subvol; UINT64 inode; UINT8 type; INODE_ITEM inode_item; SECURITY_DESCRIPTOR* sd; FILE_LOCK lock; BOOL deleted; PKTHREAD lazy_writer_thread; ULONG atts; SHARE_ACCESS share_access; WCHAR* debug_desc; BOOL csum_loaded; LIST_ENTRY extents; ANSI_STRING reparse_xattr; ANSI_STRING ea_xattr; ULONG ealen; LIST_ENTRY hardlinks; struct _file_ref* fileref; BOOL inode_item_changed; enum prop_compression_type prop_compression; LIST_ENTRY xattrs; LIST_ENTRY dir_children_index; LIST_ENTRY dir_children_hash; LIST_ENTRY dir_children_hash_uc; LIST_ENTRY** hash_ptrs; LIST_ENTRY** hash_ptrs_uc; BOOL dirty; BOOL sd_dirty, sd_deleted; BOOL atts_changed, atts_deleted; BOOL extents_changed; BOOL reparse_xattr_changed; BOOL ea_changed; BOOL prop_compression_changed; BOOL xattrs_changed; BOOL created; BOOL ads; UINT32 adshash; ULONG adsmaxlen; ANSI_STRING adsxattr; ANSI_STRING adsdata; LIST_ENTRY list_entry; LIST_ENTRY list_entry_all; LIST_ENTRY list_entry_dirty; } fcb; typedef struct { ERESOURCE fileref_lock; ERESOURCE children_lock; } file_ref_nonpaged; typedef struct _file_ref { fcb* fcb; ANSI_STRING oldutf8; UINT64 oldindex; BOOL delete_on_close; BOOL deleted; BOOL created; file_ref_nonpaged* nonpaged; LIST_ENTRY children; LONG refcount; LONG open_count; struct _file_ref* parent; WCHAR* debug_desc; dir_child* dc; BOOL dirty; LIST_ENTRY list_entry; LIST_ENTRY list_entry_dirty; } file_ref; typedef struct { HANDLE thread; struct _ccb* ccb; void* context; KEVENT cleared_event; BOOL cancelling; LIST_ENTRY list_entry; } send_info; typedef struct _ccb { USHORT NodeType; CSHORT NodeSize; ULONG disposition; ULONG options; UINT64 query_dir_offset; UNICODE_STRING query_string; BOOL has_wildcard; BOOL specific_file; BOOL manage_volume_privilege; BOOL allow_extended_dasd_io; BOOL reserving; ACCESS_MASK access; file_ref* fileref; UNICODE_STRING filename; ULONG ea_index; BOOL case_sensitive; BOOL user_set_creation_time; BOOL user_set_access_time; BOOL user_set_write_time; BOOL user_set_change_time; BOOL lxss; send_info* send; NTSTATUS send_status; } ccb; struct _device_extension; typedef struct { UINT64 address; UINT64 generation; struct _tree* tree; } tree_holder; typedef struct _tree_data { KEY key; LIST_ENTRY list_entry; BOOL ignore; BOOL inserted; union { tree_holder treeholder; struct { UINT16 size; UINT8* data; }; }; } tree_data; typedef struct _tree { tree_header header; UINT32 hash; BOOL has_address; UINT32 size; struct _device_extension* Vcb; struct _tree* parent; tree_data* paritem; struct _root* root; LIST_ENTRY itemlist; LIST_ENTRY list_entry; LIST_ENTRY list_entry_hash; UINT64 new_address; BOOL has_new_address; BOOL updated_extents; BOOL write; BOOL is_unique; BOOL uniqueness_determined; UINT8* buf; } tree; typedef struct { ERESOURCE load_tree_lock; } root_nonpaged; typedef struct _root { UINT64 id; LONGLONG lastinode; // signed so we can use InterlockedIncrement64 tree_holder treeholder; root_nonpaged* nonpaged; ROOT_ITEM root_item; BOOL dirty; BOOL received; PEPROCESS reserved; UINT64 parent; LONG send_ops; LIST_ENTRY fcbs; LIST_ENTRY list_entry; LIST_ENTRY list_entry_dirty; } root; enum batch_operation { Batch_Delete, Batch_DeleteInode, Batch_DeleteDirItem, Batch_DeleteInodeRef, Batch_DeleteInodeExtRef, Batch_DeleteXattr, Batch_DeleteExtentData, Batch_DeleteFreeSpace, Batch_Insert, Batch_SetXattr, Batch_DirItem, Batch_InodeRef, Batch_InodeExtRef, }; typedef struct { KEY key; void* data; UINT16 datalen; enum batch_operation operation; LIST_ENTRY list_entry; } batch_item; typedef struct { root* r; LIST_ENTRY items; LIST_ENTRY list_entry; } batch_root; typedef struct { tree* tree; tree_data* item; } traverse_ptr; typedef struct _root_cache { root* root; struct _root_cache* next; } root_cache; typedef struct { UINT64 address; UINT64 size; LIST_ENTRY list_entry; LIST_ENTRY list_entry_size; } space; typedef struct { PDEVICE_OBJECT devobj; DEV_ITEM devitem; BOOL removable; BOOL seeding; BOOL readonly; BOOL reloc; BOOL trim; BOOL can_flush; ULONG change_count; ULONG disk_num; ULONG part_num; UINT64 stats[5]; BOOL stats_changed; LIST_ENTRY space; LIST_ENTRY list_entry; ULONG num_trim_entries; LIST_ENTRY trim_list; } device; typedef struct { UINT64 start; UINT64 length; PETHREAD thread; LIST_ENTRY list_entry; } range_lock; typedef struct { UINT64 address; ULONG* bmparr; RTL_BITMAP bmp; LIST_ENTRY list_entry; UINT8 data[1]; } partial_stripe; typedef struct { CHUNK_ITEM* chunk_item; UINT16 size; UINT64 offset; UINT64 used; UINT64 oldused; device** devices; fcb* cache; fcb* old_cache; LIST_ENTRY space; LIST_ENTRY space_size; LIST_ENTRY deleting; LIST_ENTRY changed_extents; LIST_ENTRY range_locks; ERESOURCE range_locks_lock; KEVENT range_locks_event; ERESOURCE lock; ERESOURCE changed_extents_lock; BOOL created; BOOL readonly; BOOL reloc; BOOL last_alloc_set; BOOL cache_loaded; BOOL changed; BOOL space_changed; UINT64 last_alloc; UINT16 last_stripe; LIST_ENTRY partial_stripes; ERESOURCE partial_stripes_lock; ULONG balance_num; LIST_ENTRY list_entry; LIST_ENTRY list_entry_balance; } chunk; typedef struct { UINT64 address; UINT64 size; UINT64 old_size; UINT64 count; UINT64 old_count; BOOL no_csum; BOOL superseded; LIST_ENTRY refs; LIST_ENTRY old_refs; LIST_ENTRY list_entry; } changed_extent; typedef struct { UINT8 type; union { EXTENT_DATA_REF edr; SHARED_DATA_REF sdr; }; LIST_ENTRY list_entry; } changed_extent_ref; typedef struct { KEY key; void* data; USHORT size; LIST_ENTRY list_entry; } sys_chunk; typedef struct { UINT8* data; UINT32* csum; UINT32 sectors; LONG pos, done; KEVENT event; LONG refcount; LIST_ENTRY list_entry; } calc_job; typedef struct { PDEVICE_OBJECT DeviceObject; HANDLE handle; KEVENT finished; BOOL quit; } drv_calc_thread; typedef struct { ULONG num_threads; LIST_ENTRY job_list; ERESOURCE lock; drv_calc_thread* threads; KEVENT event; } drv_calc_threads; typedef struct { BOOL ignore; BOOL compress; BOOL compress_force; UINT8 compress_type; BOOL readonly; UINT32 zlib_level; UINT32 zstd_level; UINT32 flush_interval; UINT32 max_inline; UINT64 subvol_id; BOOL skip_balance; BOOL no_barrier; BOOL no_trim; BOOL clear_cache; BOOL allow_degraded; } mount_options; #define VCB_TYPE_FS 1 #define VCB_TYPE_CONTROL 2 #define VCB_TYPE_VOLUME 3 #define VCB_TYPE_PDO 4 #ifdef DEBUG_STATS typedef struct { UINT64 num_reads; UINT64 data_read; UINT64 read_total_time; UINT64 read_csum_time; UINT64 read_disk_time; UINT64 num_opens; UINT64 open_total_time; UINT64 num_overwrites; UINT64 overwrite_total_time; UINT64 num_creates; UINT64 create_total_time; UINT64 open_fcb_calls; UINT64 open_fcb_time; UINT64 open_fileref_child_calls; UINT64 open_fileref_child_time; UINT64 fcb_lock_time; } debug_stats; #endif #define BALANCE_OPTS_DATA 0 #define BALANCE_OPTS_METADATA 1 #define BALANCE_OPTS_SYSTEM 2 typedef struct { HANDLE thread; UINT64 total_chunks; UINT64 chunks_left; btrfs_balance_opts opts[3]; BOOL paused; BOOL stopping; BOOL removing; BOOL shrinking; BOOL dev_readonly; ULONG balance_num; NTSTATUS status; KEVENT event; KEVENT finished; } balance_info; typedef struct { UINT64 address; UINT64 device; BOOL recovered; BOOL is_metadata; BOOL parity; LIST_ENTRY list_entry; union { struct { UINT64 subvol; UINT64 offset; UINT16 filename_length; WCHAR filename[1]; } data; struct { UINT64 root; UINT8 level; KEY firstitem; } metadata; }; } scrub_error; typedef struct { HANDLE thread; ERESOURCE stats_lock; KEVENT event; KEVENT finished; BOOL stopping; BOOL paused; LARGE_INTEGER start_time; LARGE_INTEGER finish_time; LARGE_INTEGER resume_time; LARGE_INTEGER duration; UINT64 total_chunks; UINT64 chunks_left; UINT64 data_scrubbed; NTSTATUS error; ULONG num_errors; LIST_ENTRY errors; } scrub_info; struct _volume_device_extension; typedef struct _device_extension { UINT32 type; mount_options options; PVPB Vpb; struct _volume_device_extension* vde; LIST_ENTRY devices; #ifdef DEBUG_STATS debug_stats stats; #endif #ifdef DEBUG_CHUNK_LOCKS LONG chunk_locks_held; #endif UINT64 devices_loaded; superblock superblock; BOOL readonly; BOOL removing; BOOL locked; BOOL lock_paused_balance; BOOL disallow_dismount; BOOL trim; PFILE_OBJECT locked_fileobj; fcb* volume_fcb; fcb* dummy_fcb; file_ref* root_fileref; LONG open_files; _Has_lock_level_(fcb_lock) ERESOURCE fcb_lock; ERESOURCE load_lock; _Has_lock_level_(tree_lock) ERESOURCE tree_lock; PNOTIFY_SYNC NotifySync; LIST_ENTRY DirNotifyList; BOOL need_write; BOOL stats_changed; UINT64 data_flags; UINT64 metadata_flags; UINT64 system_flags; LIST_ENTRY roots; LIST_ENTRY drop_roots; root* chunk_root; root* root_root; root* extent_root; root* checksum_root; root* dev_root; root* uuid_root; root* data_reloc_root; root* space_root; BOOL log_to_phys_loaded; BOOL chunk_usage_found; LIST_ENTRY sys_chunks; LIST_ENTRY chunks; LIST_ENTRY trees; LIST_ENTRY trees_hash; LIST_ENTRY* trees_ptrs[256]; LIST_ENTRY all_fcbs; LIST_ENTRY dirty_fcbs; ERESOURCE dirty_fcbs_lock; LIST_ENTRY dirty_filerefs; ERESOURCE dirty_filerefs_lock; LIST_ENTRY dirty_subvols; ERESOURCE dirty_subvols_lock; ERESOURCE chunk_lock; HANDLE flush_thread_handle; KTIMER flush_thread_timer; KEVENT flush_thread_finished; drv_calc_threads calcthreads; balance_info balance; scrub_info scrub; ERESOURCE send_load_lock; LONG running_sends; LIST_ENTRY send_ops; PFILE_OBJECT root_file; PAGED_LOOKASIDE_LIST tree_data_lookaside; PAGED_LOOKASIDE_LIST traverse_ptr_lookaside; PAGED_LOOKASIDE_LIST batch_item_lookaside; PAGED_LOOKASIDE_LIST fileref_lookaside; PAGED_LOOKASIDE_LIST fcb_lookaside; PAGED_LOOKASIDE_LIST name_bit_lookaside; NPAGED_LOOKASIDE_LIST range_lock_lookaside; NPAGED_LOOKASIDE_LIST fileref_np_lookaside; NPAGED_LOOKASIDE_LIST fcb_np_lookaside; LIST_ENTRY list_entry; } device_extension; typedef struct { UINT32 type; PDEVICE_OBJECT buspdo; PDEVICE_OBJECT attached_device; UNICODE_STRING bus_name; } control_device_extension; typedef struct { BTRFS_UUID uuid; UINT64 devid; UINT64 generation; PDEVICE_OBJECT devobj; PFILE_OBJECT fileobj; UNICODE_STRING pnp_name; UINT64 size; BOOL seeding; BOOL had_drive_letter; void* notification_entry; ULONG disk_num; ULONG part_num; LIST_ENTRY list_entry; } volume_child; struct pdo_device_extension; typedef struct _volume_device_extension { UINT32 type; UNICODE_STRING name; PDEVICE_OBJECT device; PDEVICE_OBJECT mounted_device; PDEVICE_OBJECT pdo; struct pdo_device_extension* pdode; UNICODE_STRING bus_name; PDEVICE_OBJECT attached_device; BOOL removing; LONG open_count; } volume_device_extension; typedef struct pdo_device_extension { UINT32 type; BTRFS_UUID uuid; volume_device_extension* vde; PDEVICE_OBJECT pdo; BOOL removable; UINT64 num_children; UINT64 children_loaded; ERESOURCE child_lock; LIST_ENTRY children; LIST_ENTRY list_entry; } pdo_device_extension; typedef struct { LIST_ENTRY listentry; PSID sid; UINT32 uid; } uid_map; typedef struct { LIST_ENTRY listentry; PSID sid; UINT32 gid; } gid_map; enum write_data_status { WriteDataStatus_Pending, WriteDataStatus_Success, WriteDataStatus_Error, WriteDataStatus_Cancelling, WriteDataStatus_Cancelled, WriteDataStatus_Ignore }; struct _write_data_context; typedef struct { struct _write_data_context* context; UINT8* buf; PMDL mdl; device* device; PIRP Irp; IO_STATUS_BLOCK iosb; enum write_data_status status; LIST_ENTRY list_entry; } write_data_stripe; typedef struct _write_data_context { KEVENT Event; LIST_ENTRY stripes; LONG stripes_left; BOOL need_wait; UINT8 *parity1, *parity2, *scratch; PMDL mdl, parity1_mdl, parity2_mdl; } write_data_context; typedef struct { UINT64 address; UINT32 length; UINT8* data; chunk* c; LIST_ENTRY list_entry; } tree_write; typedef struct { UNICODE_STRING us; LIST_ENTRY list_entry; } name_bit; _Requires_lock_not_held_(Vcb->fcb_lock) _Acquires_shared_lock_(Vcb->fcb_lock) static __inline void acquire_fcb_lock_shared(device_extension* Vcb) { #ifdef DEBUG_STATS LARGE_INTEGER time1, time2; if (ExAcquireResourceSharedLite(&Vcb->fcb_lock, FALSE)) return; time1 = KeQueryPerformanceCounter(NULL); #endif ExAcquireResourceSharedLite(&Vcb->fcb_lock, TRUE); #ifdef DEBUG_STATS time2 = KeQueryPerformanceCounter(NULL); Vcb->stats.fcb_lock_time += time2.QuadPart - time1.QuadPart; #endif } _Requires_lock_not_held_(Vcb->fcb_lock) _Acquires_exclusive_lock_(Vcb->fcb_lock) static __inline void acquire_fcb_lock_exclusive(device_extension* Vcb) { #ifdef DEBUG_STATS LARGE_INTEGER time1, time2; if (ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, FALSE)) return; time1 = KeQueryPerformanceCounter(NULL); #endif ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE); #ifdef DEBUG_STATS time2 = KeQueryPerformanceCounter(NULL); Vcb->stats.fcb_lock_time += time2.QuadPart - time1.QuadPart; #endif } _Requires_lock_held_(Vcb->fcb_lock) _Releases_lock_(Vcb->fcb_lock) static __inline void release_fcb_lock(device_extension* Vcb) { ExReleaseResourceLite(&Vcb->fcb_lock); } static __inline void* map_user_buffer(PIRP Irp, ULONG priority) { if (!Irp->MdlAddress) { return Irp->UserBuffer; } else { return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, priority); } } static __inline UINT64 unix_time_to_win(BTRFS_TIME* t) { return (t->seconds * 10000000) + (t->nanoseconds / 100) + 116444736000000000; } static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) { ULONGLONG l = (ULONGLONG)t.QuadPart - 116444736000000000; out->seconds = l / 10000000; out->nanoseconds = (UINT32)((l % 10000000) * 100); } _Post_satisfies_(*stripe>=0&&*stripeid << 40) | (inode & 0xffffffffff); } #define keycmp(key1, key2)\ ((key1.obj_id < key2.obj_id) ? -1 :\ ((key1.obj_id > key2.obj_id) ? 1 :\ ((key1.obj_type < key2.obj_type) ? -1 :\ ((key1.obj_type > key2.obj_type) ? 1 :\ ((key1.offset < key2.offset) ? -1 :\ ((key1.offset > key2.offset) ? 1 :\ 0)))))) _Post_satisfies_(return>=n) __inline static UINT64 sector_align(_In_ UINT64 n, _In_ UINT64 a) { if (n & (a - 1)) n = (n + a) & ~(a - 1); return n; } __inline static BOOL is_subvol_readonly(root* r, PIRP Irp) { if (!(r->root_item.flags & BTRFS_SUBVOL_READONLY)) return FALSE; if (!r->reserved) return TRUE; return (!Irp || Irp->RequestorMode == UserMode) && PsGetCurrentProcess() != r->reserved ? TRUE : FALSE; } __inline static UINT16 get_extent_data_len(UINT8 type) { switch (type) { case TYPE_TREE_BLOCK_REF: return sizeof(TREE_BLOCK_REF); case TYPE_EXTENT_DATA_REF: return sizeof(EXTENT_DATA_REF); case TYPE_EXTENT_REF_V0: return sizeof(EXTENT_REF_V0); case TYPE_SHARED_BLOCK_REF: return sizeof(SHARED_BLOCK_REF); case TYPE_SHARED_DATA_REF: return sizeof(SHARED_DATA_REF); default: return 0; } } __inline static UINT32 get_extent_data_refcount(UINT8 type, void* data) { switch (type) { case TYPE_TREE_BLOCK_REF: return 1; case TYPE_EXTENT_DATA_REF: { EXTENT_DATA_REF* edr = (EXTENT_DATA_REF*)data; return edr->count; } case TYPE_EXTENT_REF_V0: { EXTENT_REF_V0* erv0 = (EXTENT_REF_V0*)data; return erv0->count; } case TYPE_SHARED_BLOCK_REF: return 1; case TYPE_SHARED_DATA_REF: { SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data; return sdr->count; } default: return 0; } } // in btrfs.c _Ret_maybenull_ device* find_device_from_uuid(_In_ device_extension* Vcb, _In_ BTRFS_UUID* uuid); _Success_(return) BOOL get_file_attributes_from_xattr(_In_reads_bytes_(len) char* val, _In_ UINT16 len, _Out_ ULONG* atts); ULONG get_file_attributes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ UINT64 inode, _In_ UINT8 type, _In_ BOOL dotfile, _In_ BOOL ignore_xa, _In_opt_ PIRP Irp); _Success_(return) BOOL get_xattr(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* subvol, _In_ UINT64 inode, _In_z_ char* name, _In_ UINT32 crc32, _Out_ UINT8** data, _Out_ UINT16* datalen, _In_opt_ PIRP Irp); #ifndef DEBUG_FCB_REFCOUNTS void free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb); #endif void free_fileref(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ file_ref* fr); void protect_superblocks(_Inout_ chunk* c); BOOL is_top_level(_In_ PIRP Irp); NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ UINT64 id, _Out_ root** rootptr, _In_ BOOL no_tree, _In_ UINT64 offset, _In_opt_ PIRP Irp); void uninit(_In_ device_extension* Vcb); NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb); BOOL is_file_name_valid(_In_ PUNICODE_STRING us, _In_ BOOL posix); void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); #ifdef DEBUG_CHUNK_LOCKS #define acquire_chunk_lock(c, Vcb) { ExAcquireResourceExclusiveLite(&c->lock, TRUE); InterlockedIncrement(&Vcb->chunk_locks_held); } #define release_chunk_lock(c, Vcb) { InterlockedDecrement(&Vcb->chunk_locks_held); ExReleaseResourceLite(&c->lock); } #else #define acquire_chunk_lock(c, Vcb) ExAcquireResourceExclusiveLite(&(c)->lock, TRUE) #define release_chunk_lock(c, Vcb) ExReleaseResourceLite(&(c)->lock) #endif _Ret_z_ WCHAR* file_desc(_In_ PFILE_OBJECT FileObject); WCHAR* file_desc_fileref(_In_ file_ref* fileref); void mark_fcb_dirty(_In_ fcb* fcb); void mark_fileref_dirty(_In_ file_ref* fileref); NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback); void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length); void chunk_unlock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length); void init_device(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ BOOL get_nums); void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* ccfs); NTSTATUS sync_read_phys(_In_ PDEVICE_OBJECT DeviceObject, _In_ UINT64 StartingOffset, _In_ ULONG Length, _Out_writes_bytes_(Length) PUCHAR Buffer, _In_ BOOL override); NTSTATUS get_device_pnp_name(_In_ PDEVICE_OBJECT DeviceObject, _Out_ PUNICODE_STRING pnp_name, _Out_ const GUID** guid); void log_device_error(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ int error); NTSTATUS find_chunk_usage(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp); #ifdef __REACTOS__ NTSTATUS NTAPI AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject); #else NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject); #endif #ifdef _MSC_VER #define funcname __FUNCTION__ #else #define funcname __func__ #endif extern BOOL have_sse2; extern UINT32 mount_compress; extern UINT32 mount_compress_force; extern UINT32 mount_compress_type; extern UINT32 mount_zlib_level; extern UINT32 mount_zstd_level; extern UINT32 mount_flush_interval; extern UINT32 mount_max_inline; extern UINT32 mount_skip_balance; extern UINT32 mount_no_barrier; extern UINT32 mount_no_trim; extern UINT32 mount_clear_cache; extern UINT32 mount_allow_degraded; extern UINT32 mount_readonly; extern UINT32 no_pnp; #ifdef _DEBUG extern BOOL log_started; extern UINT32 debug_log_level; #ifdef DEBUG_LONG_MESSAGES #define MSG(fn, file, line, s, level, ...) (!log_started || level <= debug_log_level) ? _debug_message(fn, file, line, s, ##__VA_ARGS__) : 0 #define TRACE(s, ...) MSG(funcname, __FILE__, __LINE__, s, 3, ##__VA_ARGS__) #define WARN(s, ...) MSG(funcname, __FILE__, __LINE__, s, 2, ##__VA_ARGS__) #define FIXME(s, ...) MSG(funcname, __FILE__, __LINE__, s, 1, ##__VA_ARGS__) #define ERR(s, ...) MSG(funcname, __FILE__, __LINE__, s, 1, ##__VA_ARGS__) void _debug_message(_In_ const char* func, _In_ const char* file, _In_ unsigned int line, _In_ char* s, ...); #else #define MSG(fn, s, level, ...) (!log_started || level <= debug_log_level) ? _debug_message(fn, s, ##__VA_ARGS__) : 0 #define TRACE(s, ...) MSG(funcname, s, 3, ##__VA_ARGS__) #define WARN(s, ...) MSG(funcname, s, 2, ##__VA_ARGS__) #define FIXME(s, ...) MSG(funcname, s, 1, ##__VA_ARGS__) #define ERR(s, ...) MSG(funcname, s, 1, ##__VA_ARGS__) void _debug_message(_In_ const char* func, _In_ char* s, ...); #endif #else #define TRACE(s, ...) #define WARN(s, ...) #define FIXME(s, ...) DbgPrint("Btrfs FIXME : %s : " s, funcname, ##__VA_ARGS__) #define ERR(s, ...) DbgPrint("Btrfs ERR : %s : " s, funcname, ##__VA_ARGS__) #endif #ifdef DEBUG_FCB_REFCOUNTS void _free_fcb(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Inout_ fcb* fcb, _In_ const char* func); #define free_fcb(Vcb, fcb) _free_fcb(Vcb, fcb, funcname) #endif // in fastio.c void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod); // in crc32c.c UINT32 calc_crc32c(_In_ UINT32 seed, _In_reads_bytes_(msglen) UINT8* msg, _In_ ULONG msglen); typedef struct { LIST_ENTRY* list; LIST_ENTRY* list_size; UINT64 address; UINT64 length; chunk* chunk; } rollback_space; typedef struct { fcb* fcb; extent* ext; } rollback_extent; enum rollback_type { ROLLBACK_INSERT_EXTENT, ROLLBACK_DELETE_EXTENT, ROLLBACK_ADD_SPACE, ROLLBACK_SUBTRACT_SPACE }; typedef struct { enum rollback_type type; void* ptr; LIST_ENTRY list_entry; } rollback_item; typedef struct { ANSI_STRING name; ANSI_STRING value; UCHAR flags; LIST_ENTRY list_entry; } ea_item; static const char lxuid[] = "$LXUID"; static const char lxgid[] = "$LXGID"; static const char lxmod[] = "$LXMOD"; static const char lxdev[] = "$LXDEV"; // in treefuncs.c NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _Out_ traverse_ptr* tp, _In_ const KEY* searchkey, _In_ BOOL ignore, _In_opt_ PIRP Irp); NTSTATUS find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, UINT8 level, PIRP Irp); BOOL find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, PIRP Irp); BOOL find_prev_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, PIRP Irp); void free_trees(device_extension* Vcb); NTSTATUS insert_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ UINT64 obj_id, _In_ UINT8 obj_type, _In_ UINT64 offset, _In_reads_bytes_opt_(size) _When_(return >= 0, __drv_aliasesMem) void* data, _In_ UINT16 size, _Out_opt_ traverse_ptr* ptp, _In_opt_ PIRP Irp); NTSTATUS delete_tree_item(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _Inout_ traverse_ptr* tp); tree* free_tree(tree* t); NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, UINT64 generation, PIRP Irp); NTSTATUS do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, PIRP Irp); void clear_rollback(LIST_ENTRY* rollback); void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback); void free_trees_root(device_extension* Vcb, root* r); void add_rollback(_In_ LIST_ENTRY* rollback, _In_ enum rollback_type type, _In_ __drv_aliasesMem void* ptr); NTSTATUS commit_batch_list(_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp); void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist); NTSTATUS skip_to_difference(device_extension* Vcb, traverse_ptr* tp, traverse_ptr* tp2, BOOL* ended1, BOOL* ended2); // in search.c NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath); _Function_class_(KSTART_ROUTINE) #ifdef __REACTOS__ void NTAPI mountmgr_thread(_In_ void* context); #else void mountmgr_thread(_In_ void* context); #endif _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) #ifdef __REACTOS__ NTSTATUS NTAPI pnp_notification(PVOID NotificationStructure, PVOID Context); #else NTSTATUS pnp_notification(PVOID NotificationStructure, PVOID Context); #endif void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) #ifdef __REACTOS__ NTSTATUS NTAPI volume_notification(PVOID NotificationStructure, PVOID Context); #else NTSTATUS volume_notification(PVOID NotificationStructure, PVOID Context); #endif void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lock) _Releases_exclusive_lock_(_Curr_->child_lock) _In_ volume_device_extension* vde, _In_ volume_child* vc, _In_ BOOL skip_dev); // in cache.c NTSTATUS init_cache(); void free_cache(); extern CACHE_MANAGER_CALLBACKS* cache_callbacks; // in write.c NTSTATUS write_file(device_extension* Vcb, PIRP Irp, BOOLEAN wait, BOOLEAN deferred_write); NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, BOOLEAN paging_io, BOOLEAN no_cache, BOOLEAN wait, BOOLEAN deferred_write, BOOLEAN write_irp, LIST_ENTRY* rollback); NTSTATUS truncate_file(fcb* fcb, UINT64 end, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS extend_file(fcb* fcb, file_ref* fileref, UINT64 end, BOOL prealloc, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, PIRP Irp, LIST_ENTRY* rollback); chunk* get_chunk_from_address(device_extension* Vcb, UINT64 address); NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc, BOOL full_size); NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address, _In_reads_bytes_(length) void* data, _In_ UINT32 length, _In_ write_data_context* wtc, _In_opt_ PIRP Irp, _In_opt_ chunk* c, _In_ BOOL file_write, _In_ UINT64 irp_offset, _In_ ULONG priority); NTSTATUS write_data_complete(device_extension* Vcb, UINT64 address, void* data, UINT32 length, PIRP Irp, chunk* c, BOOL file_write, UINT64 irp_offset, ULONG priority); void free_write_data_stripes(write_data_context* wtc); _Dispatch_type_(IRP_MJ_WRITE) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); _Requires_lock_held_(c->lock) _When_(return != 0, _Releases_lock_(c->lock)) BOOL insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb, _In_ chunk* c, _In_ UINT64 start_data, _In_ UINT64 length, _In_ BOOL prealloc, _In_opt_ void* data, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback, _In_ UINT8 compression, _In_ UINT64 decoded_size, _In_ BOOL file_write, _In_ UINT64 irp_offset); NTSTATUS do_write_file(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, PIRP Irp, BOOL file_write, UINT32 irp_offset, LIST_ENTRY* rollback); NTSTATUS write_compressed(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, PIRP Irp, LIST_ENTRY* rollback); BOOL find_data_address_in_chunk(device_extension* Vcb, chunk* c, UINT64 length, UINT64* address); void get_raid56_lock_range(chunk* c, UINT64 address, UINT64 length, UINT64* lockaddr, UINT64* locklen); NTSTATUS calc_csum(_In_ device_extension* Vcb, _In_reads_bytes_(sectors*Vcb->superblock.sector_size) UINT8* data, _In_ UINT32 sectors, _Out_writes_bytes_(sectors*sizeof(UINT32)) UINT32* csum); void add_insert_extent_rollback(LIST_ENTRY* rollback, fcb* fcb, extent* ext); NTSTATUS add_extent_to_fcb(_In_ fcb* fcb, _In_ UINT64 offset, _In_reads_bytes_(edsize) EXTENT_DATA* ed, _In_ UINT16 edsize, _In_ BOOL unique, _In_opt_ _When_(return >= 0, __drv_aliasesMem) UINT32* csum, _In_ LIST_ENTRY* rollback); void add_extent(_In_ fcb* fcb, _In_ LIST_ENTRY* prevextle, _In_ __drv_aliasesMem extent* newext); // in dirctrl.c _Dispatch_type_(IRP_MJ_DIRECTORY_CONTROL) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, ULONG atts, BOOL lxss, PIRP Irp); ULONG get_reparse_tag_fcb(fcb* fcb); // in security.c _Dispatch_type_(IRP_MJ_QUERY_SECURITY) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); _Dispatch_type_(IRP_MJ_SET_SECURITY) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); void fcb_get_sd(fcb* fcb, struct _fcb* parent, BOOL look_for_xattr, PIRP Irp); void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid); void add_group_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 gid); UINT32 sid_to_uid(PSID sid); NTSTATUS uid_to_sid(UINT32 uid, PSID* sid); NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as); void find_gid(struct _fcb* fcb, struct _fcb* parfcb, PSECURITY_SUBJECT_CONTEXT subjcont); // in fileinfo.c _Dispatch_type_(IRP_MJ_SET_INFORMATION) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); _Dispatch_type_(IRP_MJ_QUERY_INFORMATION) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_query_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); _Dispatch_type_(IRP_MJ_QUERY_EA) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_query_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); _Dispatch_type_(IRP_MJ_SET_EA) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); BOOL has_open_children(file_ref* fileref); NTSTATUS stream_set_end_of_file_information(device_extension* Vcb, UINT16 end, fcb* fcb, file_ref* fileref, BOOL advance_only); NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* name_offset, ULONG* preqlen); NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb, root* subvol, UINT64 inode, file_ref** pfr, PIRP Irp); void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc); void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc); // in reparse.c NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, ULONG_PTR* retlen); NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, ccb* ccb, file_ref* fileref, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp); // in create.c _Dispatch_type_(IRP_MJ_CREATE) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Out_ file_ref** pfr, _In_ PUNICODE_STRING fnus, _In_opt_ file_ref* related, _In_ BOOL parent, _Out_opt_ USHORT* parsed, _Out_opt_ ULONG* fn_offset, _In_ POOL_TYPE pooltype, _In_ BOOL case_sensitive, _In_opt_ PIRP Irp); NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp); NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length, PIRP Irp); NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, fcb* fcb, BOOL ignore_size, PIRP Irp); NTSTATUS add_dir_child(fcb* fcb, UINT64 inode, BOOL subvol, PANSI_STRING utf8, PUNICODE_STRING name, UINT8 type, dir_child** pdc); NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _In_ file_ref* sf, _In_ PUNICODE_STRING name, _In_ BOOL case_sensitive, _In_ BOOL lastpart, _In_ BOOL streampart, _In_ POOL_TYPE pooltype, _Out_ file_ref** psf2, _In_opt_ PIRP Irp); fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type); NTSTATUS find_file_in_dir(PUNICODE_STRING filename, fcb* fcb, root** subvol, UINT64* inode, dir_child** pdc, BOOL case_sensitive); UINT32 inherit_mode(fcb* parfcb, BOOL is_dir); file_ref* create_fileref(device_extension* Vcb); // in fsctl.c NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, UINT32 type); void do_unlock_volume(device_extension* Vcb); void trim_whole_device(device* dev); void flush_subvol_fcbs(root* subvol); BOOL fcb_is_inline(fcb* fcb); // in flushthread.c _Function_class_(KSTART_ROUTINE) #ifdef __REACTOS__ void NTAPI flush_thread(void* context); #else void flush_thread(void* context); #endif NTSTATUS do_write(device_extension* Vcb, PIRP Irp); NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp); NTSTATUS write_data_phys(_In_ PDEVICE_OBJECT device, _In_ UINT64 address, _In_reads_bytes_(length) void* data, _In_ UINT32 length); BOOL is_tree_unique(device_extension* Vcb, tree* t, PIRP Irp); NTSTATUS do_tree_writes(device_extension* Vcb, LIST_ENTRY* tree_writes, BOOL no_free); void add_checksum_entry(device_extension* Vcb, UINT64 address, ULONG length, UINT32* csum, PIRP Irp); BOOL find_metadata_address_in_chunk(device_extension* Vcb, chunk* c, UINT64* address); void add_trim_entry_avoid_sb(device_extension* Vcb, device* dev, UINT64 address, UINT64 size); NTSTATUS insert_tree_item_batch(LIST_ENTRY* batchlist, device_extension* Vcb, root* r, UINT64 objid, UINT8 objtype, UINT64 offset, _In_opt_ _When_(return >= 0, __drv_aliasesMem) void* data, UINT16 datalen, enum batch_operation operation); NTSTATUS flush_partial_stripe(device_extension* Vcb, chunk* c, partial_stripe* ps); NTSTATUS update_dev_item(device_extension* Vcb, device* device, PIRP Irp); // in read.c _Dispatch_type_(IRP_MJ_READ) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr, _In_ UINT32 length, _In_reads_bytes_opt_(length*sizeof(UINT32)/Vcb->superblock.sector_size) UINT32* csum, _In_ BOOL is_tree, _Out_writes_bytes_(length) UINT8* buf, _In_opt_ chunk* c, _Out_opt_ chunk** pc, _In_opt_ PIRP Irp, _In_ UINT64 generation, _In_ BOOL file_read, _In_ ULONG priority); NTSTATUS read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr, PIRP Irp); NTSTATUS read_stream(fcb* fcb, UINT8* data, UINT64 start, ULONG length, ULONG* pbr); NTSTATUS do_read(PIRP Irp, BOOLEAN wait, ULONG* bytes_read); NTSTATUS check_csum(device_extension* Vcb, UINT8* data, UINT32 sectors, UINT32* csum); void raid6_recover2(UINT8* sectors, UINT16 num_stripes, ULONG sector_size, UINT16 missing1, UINT16 missing2, UINT8* out); // in pnp.c _Dispatch_type_(IRP_MJ_PNP) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp); NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp); // in free-space.c NTSTATUS load_cache_chunk(device_extension* Vcb, chunk* c, PIRP Irp); NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp); NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback); NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp); NTSTATUS add_space_entry(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 offset, UINT64 size); void space_list_add(chunk* c, UINT64 address, UINT64 length, LIST_ENTRY* rollback); void space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, chunk* c, LIST_ENTRY* rollback); void space_list_subtract(chunk* c, BOOL deleting, UINT64 address, UINT64 length, LIST_ENTRY* rollback); void space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, chunk* c, LIST_ENTRY* rollback); NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, BOOL load_only, PIRP Irp); // in extent-tree.c NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp); NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, BOOL superseded, PIRP Irp); NTSTATUS decrease_extent_refcount_tree(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT8 level, PIRP Irp); UINT64 get_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, PIRP Irp); BOOL is_extent_unique(device_extension* Vcb, UINT64 address, UINT64 size, PIRP Irp); NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem, UINT8 level, PIRP Irp); UINT64 get_extent_flags(device_extension* Vcb, UINT64 address, PIRP Irp); void update_extent_flags(device_extension* Vcb, UINT64 address, UINT64 flags, PIRP Irp); NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, INT32 count, BOOL no_csum, BOOL superseded, PIRP Irp); void add_changed_extent_ref(chunk* c, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, UINT32 count, BOOL no_csum); UINT64 find_extent_shared_tree_refcount(device_extension* Vcb, UINT64 address, UINT64 parent, PIRP Irp); UINT32 find_extent_shared_data_refcount(device_extension* Vcb, UINT64 address, UINT64 parent, PIRP Irp); NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem, UINT8 level, UINT64 parent, BOOL superseded, PIRP Irp); UINT64 get_extent_data_ref_hash2(UINT64 root, UINT64 objid, UINT64 offset); // in worker-thread.c void do_read_job(PIRP Irp); void do_write_job(device_extension* Vcb, PIRP Irp); BOOL add_thread_job(device_extension* Vcb, PIRP Irp); // in registry.c void read_registry(PUNICODE_STRING regpath, BOOL refresh); NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid); NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID* uuid); NTSTATUS registry_load_volume_options(device_extension* Vcb); void watch_registry(HANDLE regh); // in compress.c NTSTATUS zlib_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen); NTSTATUS lzo_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen, UINT32 inpageoff); NTSTATUS zstd_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen); NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback); // in galois.c void galois_double(UINT8* data, UINT32 len); void galois_divpower(UINT8* data, UINT8 div, UINT32 readlen); UINT8 gpow2(UINT8 e); UINT8 gmul(UINT8 a, UINT8 b); UINT8 gdiv(UINT8 a, UINT8 b); // in devctrl.c _Dispatch_type_(IRP_MJ_DEVICE_CONTROL) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); // in calcthread.c _Function_class_(KSTART_ROUTINE) #ifdef __REACTOS__ void NTAPI calc_thread(void* context); #else void calc_thread(void* context); #endif NTSTATUS add_calc_job(device_extension* Vcb, UINT8* data, UINT32 sectors, UINT32* csum, calc_job** pcj); void free_calc_job(calc_job* cj); // in balance.c NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, KPROCESSOR_MODE processor_mode); NTSTATUS query_balance(device_extension* Vcb, void* data, ULONG length); NTSTATUS pause_balance(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS resume_balance(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS stop_balance(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb); NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG length, KPROCESSOR_MODE processor_mode); _Function_class_(KSTART_ROUTINE) #ifdef __REACTOS__ void NTAPI balance_thread(void* context); #else void balance_thread(void* context); #endif // in volume.c NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_query_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_query_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_flush_buffers(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_query_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_set_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_file_system_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_lock_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_shutdown(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); NTSTATUS vol_power(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); void add_volume_device(superblock* sb, PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath, UINT64 length, ULONG disk_num, ULONG part_num); NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath); _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) #ifdef __REACTOS__ NTSTATUS NTAPI pnp_removal(PVOID NotificationStructure, PVOID Context); #else NTSTATUS pnp_removal(PVOID NotificationStructure, PVOID Context); #endif // in scrub.c NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS query_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode, void* data, ULONG length); NTSTATUS pause_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS resume_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS stop_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode); // in send.c NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJECT FileObject, PIRP Irp); NTSTATUS read_send_buffer(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG datalen, ULONG_PTR* retlen, KPROCESSOR_MODE processor_mode); // based on function in sys/sysmacros.h #define makedev(major, minor) (((minor) & 0xFF) | (((major) & 0xFFF) << 8) | (((UINT64)((minor) & ~0xFF)) << 12) | (((UINT64)((major) & ~0xFFF)) << 32)) #define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable) static __inline void print_open_trees(device_extension* Vcb) { LIST_ENTRY* le = Vcb->trees.Flink; while (le != &Vcb->trees) { tree* t = CONTAINING_RECORD(le, tree, list_entry); tree_data* td = CONTAINING_RECORD(t->itemlist.Flink, tree_data, list_entry); ERR("tree %p: root %llx, level %u, first key (%llx,%x,%llx)\n", t, t->root->id, t->header.level, td->key.obj_id, td->key.obj_type, td->key.offset); le = le->Flink; } } static __inline BOOL write_fcb_compressed(fcb* fcb) { // make sure we don't accidentally write the cache inodes or pagefile compressed if (fcb->subvol->id == BTRFS_ROOT_ROOT || fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE) return FALSE; if (fcb->Vcb->options.compress_force) return TRUE; if (fcb->inode_item.flags & BTRFS_INODE_NOCOMPRESS) return FALSE; if (fcb->inode_item.flags & BTRFS_INODE_COMPRESS || fcb->Vcb->options.compress) return TRUE; return FALSE; } static __inline void do_xor(UINT8* buf1, UINT8* buf2, UINT32 len) { UINT32 j; #ifndef __REACTOS__ __m128i x1, x2; #endif #ifndef __REACTOS__ if (have_sse2 && ((uintptr_t)buf1 & 0xf) == 0 && ((uintptr_t)buf2 & 0xf) == 0) { while (len >= 16) { x1 = _mm_load_si128((__m128i*)buf1); x2 = _mm_load_si128((__m128i*)buf2); x1 = _mm_xor_si128(x1, x2); _mm_store_si128((__m128i*)buf1, x1); buf1 += 16; buf2 += 16; len -= 16; } } #endif for (j = 0; j < len; j++) { *buf1 ^= *buf2; buf1++; buf2++; } } #ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_LONG_MESSAGES #define increase_fileref_refcount(fileref) {\ LONG rc = InterlockedIncrement(&fileref->refcount);\ MSG(funcname, __FILE__, __LINE__, "fileref %p: refcount now %i\n", 1, fileref, rc);\ } #else #define increase_fileref_refcount(fileref) {\ LONG rc = InterlockedIncrement(&fileref->refcount);\ MSG(funcname, "fileref %p: refcount now %i\n", 1, fileref, rc);\ } #endif #else #define increase_fileref_refcount(fileref) InterlockedIncrement(&fileref->refcount) #endif #ifdef _MSC_VER #define int3 __debugbreak() #else #define int3 asm("int3;") #endif #define hex_digit(c) ((c) <= 9) ? ((c) + '0') : ((c) - 10 + 'a') // FIXME - find a way to catch unfreed trees again // from sys/stat.h #define __S_IFMT 0170000 /* These bits determine file type. */ #define __S_IFDIR 0040000 /* Directory. */ #define __S_IFCHR 0020000 /* Character device. */ #define __S_IFBLK 0060000 /* Block device. */ #define __S_IFREG 0100000 /* Regular file. */ #define __S_IFIFO 0010000 /* FIFO. */ #define __S_IFLNK 0120000 /* Symbolic link. */ #define __S_IFSOCK 0140000 /* Socket. */ #define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask)) #ifndef S_ISDIR #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR) #endif #ifndef S_IRUSR #define S_IRUSR 0000400 #endif #ifndef S_IWUSR #define S_IWUSR 0000200 #endif #ifndef S_IXUSR #define S_IXUSR 0000100 #endif #ifdef __REACTOS__ #define S_IFDIR __S_IFDIR #define S_IFREG __S_IFREG #endif /* __REACTOS__ */ #ifndef S_IRGRP #define S_IRGRP (S_IRUSR >> 3) #endif #ifndef S_IWGRP #define S_IWGRP (S_IWUSR >> 3) #endif #ifndef S_IXGRP #define S_IXGRP (S_IXUSR >> 3) #endif #ifndef S_IROTH #define S_IROTH (S_IRGRP >> 3) #endif #ifndef S_IWOTH #define S_IWOTH (S_IWGRP >> 3) #endif #ifndef S_IXOTH #define S_IXOTH (S_IXGRP >> 3) #endif #ifndef S_ISUID #define S_ISUID 0004000 #endif #ifndef S_ISGID #define S_ISGID 0002000 #endif #ifndef S_ISVTX #define S_ISVTX 0001000 #endif // based on functions in sys/sysmacros.h #define major(rdev) ((((rdev) >> 8) & 0xFFF) | ((UINT32)((rdev) >> 32) & ~0xFFF)) #define minor(rdev) (((rdev) & 0xFF) | ((UINT32)((rdev) >> 12) & ~0xFF)) static __inline UINT64 fcb_alloc_size(fcb* fcb) { if (S_ISDIR(fcb->inode_item.st_mode)) return 0; else if (fcb->atts & FILE_ATTRIBUTE_SPARSE_FILE) return fcb->inode_item.st_blocks; else return sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size); } typedef BOOLEAN (*tPsIsDiskCountersEnabled)(); typedef VOID (*tPsUpdateDiskCounters)(PEPROCESS Process, ULONG64 BytesRead, ULONG64 BytesWritten, ULONG ReadOperationCount, ULONG WriteOperationCount, ULONG FlushOperationCount); typedef BOOLEAN (*tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, PVOID Buffer, PETHREAD IoIssuerThread); typedef BOOLEAN (*tCcCopyReadEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PETHREAD IoIssuerThread); #ifndef CC_ENABLE_DISK_IO_ACCOUNTING #define CC_ENABLE_DISK_IO_ACCOUNTING 0x00000010 #endif typedef VOID (*tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject, ULONG Flags); typedef VOID (*tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten); #ifndef __REACTOS__ #ifndef _MSC_VER #undef RtlIsNtDdiVersionAvailable BOOLEAN RtlIsNtDdiVersionAvailable(ULONG Version); PEPROCESS PsGetThreadProcess(_In_ PETHREAD Thread); // not in mingw #endif // not in DDK headers - taken from winternl.h typedef struct _LDR_DATA_TABLE_ENTRY { PVOID Reserved1[2]; LIST_ENTRY InMemoryOrderLinks; PVOID Reserved2[2]; PVOID DllBase; PVOID Reserved3[2]; UNICODE_STRING FullDllName; BYTE Reserved4[8]; PVOID Reserved5[3]; union { ULONG CheckSum; PVOID Reserved6; }; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY; typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; PVOID Reserved2[3]; LIST_ENTRY InMemoryOrderModuleList; } PEB_LDR_DATA,*PPEB_LDR_DATA; typedef struct _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[16]; PVOID Reserved2[10]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; } RTL_USER_PROCESS_PARAMETERS,*PRTL_USER_PROCESS_PARAMETERS; typedef VOID (NTAPI *PPS_POST_PROCESS_INIT_ROUTINE)(VOID); typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved4[104]; PVOID Reserved5[52]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved6[128]; PVOID Reserved7[1]; ULONG SessionId; } PEB,*PPEB; #ifdef _MSC_VER __kernel_entry NTSTATUS NTAPI ZwQueryInformationProcess( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ); #endif #endif #if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_VISTA) typedef struct _ECP_LIST ECP_LIST; typedef struct _ECP_LIST *PECP_LIST; #endif #if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) NTSTATUS WINAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max, ULONG *utf8_bytes_written, const WCHAR *uni_src, ULONG uni_bytes); NTSTATUS WINAPI RtlUTF8ToUnicodeN(WCHAR *uni_dest, ULONG uni_bytes_max, ULONG *uni_bytes_written, const CHAR *utf8_src, ULONG utf8_bytes); #endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */ #if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_VISTA) NTSTATUS NTAPI FsRtlRemoveDotsFromPath(PWSTR OriginalString, USHORT PathLength, USHORT *NewLength); NTSTATUS NTAPI FsRtlValidateReparsePointBuffer(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer); ULONG NTAPI KeQueryActiveProcessorCount(PKAFFINITY ActiveProcessors); NTSTATUS NTAPI FsRtlGetEcpListFromIrp(IN PIRP Irp, OUT PECP_LIST *EcpList); NTSTATUS NTAPI FsRtlGetNextExtraCreateParameter(IN PECP_LIST EcpList, IN PVOID CurrentEcpContext, OUT LPGUID NextEcpType OPTIONAL, OUT PVOID *NextEcpContext, OUT PULONG NextEcpContextSize OPTIONAL); #endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_VISTA) */ #endif