Sync btrfs to 0.8.

CORE-12617

svn path=/trunk/; revision=73498
This commit is contained in:
Pierre Schweitzer 2017-01-01 17:12:12 +00:00
parent 3175ed2860
commit 3049f1a5b4
28 changed files with 11655 additions and 5966 deletions

View file

@ -4,8 +4,10 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/drivers
inc)
list(APPEND SOURCE
balance.c
btrfs.c
cache.c
calcthread.c
compress.c
crc32c.c
create.c
@ -33,7 +35,7 @@ add_library(btrfs SHARED ${SOURCE} btrfs.rc)
add_definitions(-D__KERNEL__)
set_module_type(btrfs kernelmodedriver)
target_link_libraries(btrfs ntoskrnl_vista zlib_solo ${PSEH_LIB})
target_link_libraries(btrfs rtlver ntoskrnl_vista zlib_solo wdmguid ${PSEH_LIB})
add_importlibs(btrfs ntoskrnl hal)
add_pch(btrfs btrfs_drv.h SOURCE)
add_cd_file(TARGET btrfs DESTINATION reactos/system32/drivers NO_CAB FOR all)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,8 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4
#define TYPE_DEV_EXTENT 0xCC
#define TYPE_DEV_ITEM 0xD8
#define TYPE_CHUNK_ITEM 0xE4
#define TYPE_TEMP_ITEM 0xF8
#define TYPE_DEV_STATS 0xF9
#define TYPE_SUBVOL_UUID 0xFB
#define BTRFS_ROOT_ROOT 1
@ -72,6 +74,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4
#define FREE_SPACE_CACHE_ID 0xFFFFFFFFFFFFFFF5
#define EXTENT_CSUM_ID 0xFFFFFFFFFFFFFFF6
#define BALANCE_ITEM_ID 0xFFFFFFFFFFFFFFFC
#define BTRFS_INODE_NODATASUM 0x001
#define BTRFS_INODE_NODATACOW 0x002
@ -436,6 +439,62 @@ typedef struct {
BTRFS_UUID chunktree_uuid;
} DEV_EXTENT;
#define BALANCE_FLAGS_DATA 0x1
#define BALANCE_FLAGS_SYSTEM 0x2
#define BALANCE_FLAGS_METADATA 0x4
#define BALANCE_ARGS_FLAGS_PROFILES 0x001
#define BALANCE_ARGS_FLAGS_USAGE 0x002
#define BALANCE_ARGS_FLAGS_DEVID 0x004
#define BALANCE_ARGS_FLAGS_DRANGE 0x008
#define BALANCE_ARGS_FLAGS_VRANGE 0x010
#define BALANCE_ARGS_FLAGS_LIMIT 0x020
#define BALANCE_ARGS_FLAGS_LIMIT_RANGE 0x040
#define BALANCE_ARGS_FLAGS_STRIPES_RANGE 0x080
#define BALANCE_ARGS_FLAGS_CONVERT 0x100
#define BALANCE_ARGS_FLAGS_SOFT 0x200
#define BALANCE_ARGS_FLAGS_USAGE_RANGE 0x400
typedef struct {
UINT64 profiles;
union {
UINT64 usage;
struct {
UINT32 usage_start;
UINT32 usage_end;
};
};
UINT64 devid;
UINT64 drange_start;
UINT64 drange_end;
UINT64 vrange_start;
UINT64 vrange_end;
UINT64 convert;
UINT64 flags;
union {
UINT64 limit;
struct {
UINT32 limit_start;
UINT32 limit_end;
};
};
UINT32 stripes_start;
UINT32 stripes_end;
UINT8 reserved[48];
} BALANCE_ARGS;
typedef struct {
UINT64 flags;
BALANCE_ARGS data;
BALANCE_ARGS metadata;
BALANCE_ARGS system;
UINT8 reserved[32];
} BALANCE_ITEM;
#pragma pack(pop)
#endif

View file

@ -70,12 +70,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs"
VALUE "FileVersion", "0.7"
VALUE "FileVersion", "0.8"
VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016"
VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "0.7"
VALUE "ProductVersion", "0.8"
END
END
BLOCK "VarFileInfo"

View file

@ -46,6 +46,7 @@
#include <stddef.h>
#include <emmintrin.h>
#include "btrfs.h"
#include "btrfsioctl.h"
#ifdef _DEBUG
// #define DEBUG_FCB_REFCOUNTS
@ -108,15 +109,23 @@ typedef struct {
UINT64 gen1, gen2;
BOOL seeding;
BOOL processed;
DWORD disk_num;
DWORD part_num;
LIST_ENTRY list_entry;
} volume;
typedef struct {
UNICODE_STRING devpath;
ULONG disk_num;
LIST_ENTRY list_entry;
} pnp_disk;
typedef struct _fcb_nonpaged {
FAST_MUTEX HeaderMutex;
SECTION_OBJECT_POINTERS segment_object;
ERESOURCE resource;
ERESOURCE paging_resource;
ERESOURCE index_lock;
ERESOURCE dir_children_lock;
} fcb_nonpaged;
struct _root;
@ -127,21 +136,12 @@ typedef struct {
ULONG datalen;
BOOL unique;
BOOL ignore;
BOOL inserted;
UINT32* csum;
LIST_ENTRY list_entry;
} extent;
typedef struct {
UINT32 hash;
KEY key;
UINT8 type;
UINT64 index;
ANSI_STRING utf8;
UNICODE_STRING filepart_uc;
LIST_ENTRY list_entry;
} index_entry;
typedef struct {
UINT64 parent;
UINT64 index;
@ -152,6 +152,21 @@ typedef struct {
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;
struct _file_ref* fileref;
LIST_ENTRY list_entry_index;
LIST_ENTRY list_entry_hash;
LIST_ENTRY list_entry_hash_uc;
} dir_child;
typedef struct _fcb {
FSRTL_ADVANCED_FCB_HEADER Header;
struct _fcb_nonpaged* nonpaged;
@ -177,8 +192,11 @@ typedef struct _fcb {
struct _file_ref* fileref;
BOOL inode_item_changed;
BOOL index_loaded;
LIST_ENTRY index_list;
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;
@ -223,6 +241,7 @@ typedef struct _file_ref {
LONG open_count;
struct _file_ref* parent;
WCHAR* debug_desc;
dir_child* dc;
BOOL dirty;
@ -244,6 +263,8 @@ typedef struct _ccb {
UNICODE_STRING query_string;
BOOL has_wildcard;
BOOL specific_file;
BOOL manage_volume_privilege;
BOOL allow_extended_dasd_io;
ACCESS_MASK access;
file_ref* fileref;
UNICODE_STRING filename;
@ -309,6 +330,7 @@ typedef struct _tree {
// UINT64 address;
// UINT8 level;
tree_header header;
UINT32 hash;
BOOL has_address;
UINT32 size;
struct _device_extension* Vcb;
@ -318,10 +340,10 @@ typedef struct _tree {
// tree_nonpaged* nonpaged;
LIST_ENTRY itemlist;
LIST_ENTRY list_entry;
LIST_ENTRY list_entry_hash;
UINT64 new_address;
BOOL has_new_address;
BOOL updated_extents;
UINT64 flags;
BOOL write;
} tree;
@ -343,10 +365,15 @@ typedef struct _root {
enum batch_operation {
Batch_Insert,
Batch_Delete,
Batch_SetXattr,
Batch_DirItem,
Batch_InodeRef,
Batch_InodeExtRef,
Batch_DeleteInode,
Batch_DeleteDirItem,
Batch_DeleteInodeRef,
Batch_DeleteInodeExtRef,
};
typedef struct {
@ -386,11 +413,15 @@ typedef struct {
BOOL removable;
BOOL seeding;
BOOL readonly;
BOOL reloc;
BOOL ssd;
BOOL trim;
ULONG change_count;
UINT64 length;
ULONG disk_num;
ULONG part_num;
LIST_ENTRY space;
LIST_ENTRY list_entry;
} device;
typedef struct {
@ -419,9 +450,13 @@ typedef struct {
ERESOURCE changed_extents_lock;
BOOL created;
BOOL readonly;
BOOL reloc;
BOOL last_alloc_set;
UINT64 last_alloc;
LIST_ENTRY list_entry;
LIST_ENTRY list_entry_changed;
LIST_ENTRY list_entry_balance;
} chunk;
typedef struct {
@ -455,6 +490,31 @@ typedef struct {
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;
@ -467,10 +527,12 @@ typedef struct {
UINT64 subvol_id;
UINT32 raid5_recalculation;
UINT32 raid6_recalculation;
BOOL skip_balance;
} mount_options;
#define VCB_TYPE_VOLUME 1
#define VCB_TYPE_PARTITION0 2
#define VCB_TYPE_CONTROL 3
#ifdef DEBUG_STATS
typedef struct {
@ -479,14 +541,40 @@ typedef struct {
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;
} 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 cancelling;
BOOL removing;
BOOL dev_readonly;
NTSTATUS status;
KEVENT event;
KEVENT finished;
} balance_info;
typedef struct _device_extension {
UINT32 type;
mount_options options;
PVPB Vpb;
device* devices;
LIST_ENTRY devices;
#ifdef DEBUG_STATS
debug_stats stats;
#endif
@ -497,14 +585,13 @@ typedef struct _device_extension {
BOOL readonly;
BOOL removing;
BOOL locked;
BOOL lock_paused_balance;
BOOL disallow_dismount;
BOOL trim;
PFILE_OBJECT locked_fileobj;
fcb* volume_fcb;
file_ref* root_fileref;
LONG open_files;
ERESOURCE DirResource;
KSPIN_LOCK FcbListLock;
ERESOURCE fcb_lock;
ERESOURCE load_lock;
ERESOURCE tree_lock;
@ -514,8 +601,9 @@ typedef struct _device_extension {
BOOL need_write;
// ERESOURCE LogToPhysLock;
// UINT64 chunk_root_phys_addr;
UINT64 root_tree_phys_addr;
UINT64 data_flags;
UINT64 metadata_flags;
UINT64 system_flags;
// log_to_phys* log_to_phys;
LIST_ENTRY roots;
LIST_ENTRY drop_roots;
@ -531,17 +619,19 @@ typedef struct _device_extension {
LIST_ENTRY chunks;
LIST_ENTRY chunks_changed;
LIST_ENTRY trees;
LIST_ENTRY trees_hash;
LIST_ENTRY* trees_ptrs[256];
LIST_ENTRY all_fcbs;
LIST_ENTRY dirty_fcbs;
KSPIN_LOCK dirty_fcbs_lock;
LIST_ENTRY dirty_filerefs;
KSPIN_LOCK dirty_filerefs_lock;
ERESOURCE checksum_lock;
ERESOURCE chunk_lock;
LIST_ENTRY sector_checksums;
HANDLE flush_thread_handle;
KTIMER flush_thread_timer;
KEVENT flush_thread_finished;
drv_calc_threads calcthreads;
balance_info balance;
PFILE_OBJECT root_file;
PAGED_LOOKASIDE_LIST tree_data_lookaside;
PAGED_LOOKASIDE_LIST traverse_ptr_lookaside;
@ -558,24 +648,16 @@ typedef struct {
UNICODE_STRING name;
} part0_device_extension;
typedef struct {
UINT32 type;
} control_device_extension;
typedef struct {
LIST_ENTRY listentry;
PSID sid;
UINT32 uid;
} uid_map;
typedef struct {
LIST_ENTRY list_entry;
UINT64 key;
} ordered_list;
typedef struct {
ordered_list ol;
ULONG length;
UINT32* checksums;
BOOL deleted;
} changed_sector;
enum write_data_status {
WriteDataStatus_Pending,
WriteDataStatus_Success,
@ -605,6 +687,14 @@ typedef struct _write_data_context {
BOOL tree;
} write_data_context;
typedef struct {
UINT64 address;
UINT32 length;
BOOL overlap;
UINT8* data;
LIST_ENTRY list_entry;
} tree_write;
// #pragma pack(pop)
static __inline void* map_user_buffer(PIRP Irp) {
@ -626,27 +716,6 @@ static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) {
out->nanoseconds = (l % 10000000) * 100;
}
static __inline void insert_into_ordered_list(LIST_ENTRY* list, ordered_list* ins) {
LIST_ENTRY* le = list->Flink;
ordered_list* ol;
while (le != list) {
ol = (ordered_list*)le;
if (ol->key > ins->key) {
le->Blink->Flink = &ins->list_entry;
ins->list_entry.Blink = le->Blink;
le->Blink = &ins->list_entry;
ins->list_entry.Flink = le;
return;
}
le = le->Flink;
}
InsertTailList(list, &ins->list_entry);
}
static __inline void get_raid0_offset(UINT64 off, UINT64 stripe_length, UINT16 num_stripes, UINT64* stripeoff, UINT16* stripe) {
UINT64 initoff, startoff;
@ -682,12 +751,12 @@ static UINT64 __inline make_file_id(root* r, UINT64 inode) {
// in btrfs.c
device* find_device_from_uuid(device_extension* Vcb, BTRFS_UUID* uuid);
UINT64 sector_align( UINT64 NumberToBeAligned, UINT64 Alignment );
BOOL get_file_attributes_from_xattr(char* val, UINT16 len, ULONG* atts);
ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa, PIRP Irp);
BOOL extract_xattr(void* item, USHORT size, char* name, UINT8** data, UINT16* datalen);
BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen, PIRP Irp);
void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line);
void _free_fileref(file_ref* fr, const char* func, const char* file, unsigned int line);
NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback);
fcb* create_fcb(POOL_TYPE pool_type);
file_ref* create_fileref();
void protect_superblocks(device_extension* Vcb, chunk* c);
@ -708,6 +777,9 @@ void mark_fileref_dirty(file_ref* fileref);
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, PIRP Irp, LIST_ENTRY* rollback);
void chunk_lock_range(device_extension* Vcb, chunk* c, UINT64 start, UINT64 length);
void chunk_unlock_range(device_extension* Vcb, chunk* c, UINT64 start, UINT64 length);
void init_device(device_extension* Vcb, device* dev, BOOL get_length, BOOL get_nums);
void init_file_cache(PFILE_OBJECT FileObject, CC_FILE_SIZES* ccfs);
NTSTATUS sync_read_phys(PDEVICE_OBJECT DeviceObject, LONGLONG StartingOffset, ULONG Length, PUCHAR Buffer, BOOL override);
#ifdef _MSC_VER
#define funcname __FUNCTION__
@ -729,6 +801,7 @@ extern UINT32 mount_flush_interval;
extern UINT32 mount_max_inline;
extern UINT32 mount_raid5_recalculation;
extern UINT32 mount_raid6_recalculation;
extern UINT32 mount_skip_balance;
#ifdef _DEBUG
@ -815,6 +888,8 @@ typedef struct {
// in treefuncs.c
NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
NTSTATUS STDCALL _find_item_to_level(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, UINT8 level,
PIRP Irp, const char* func, const char* file, unsigned int line);
BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
void STDCALL free_trees(device_extension* Vcb);
@ -832,6 +907,7 @@ void commit_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist, PIRP Irp, L
void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist);
#define find_item(Vcb, r, tp, searchkey, ignore, Irp) _find_item(Vcb, r, tp, searchkey, ignore, Irp, funcname, __FILE__, __LINE__)
#define find_item_to_level(Vcb, r, tp, searchkey, ignore, level, Irp) _find_item_to_level(Vcb, r, tp, searchkey, ignore, level, Irp, funcname, __FILE__, __LINE__)
#define find_next_item(Vcb, tp, next_tp, ignore, Irp) _find_next_item(Vcb, tp, next_tp, ignore, Irp, funcname, __FILE__, __LINE__)
#define find_prev_item(Vcb, tp, prev_tp, ignore, Irp) _find_prev_item(Vcb, tp, prev_tp, ignore, Irp, funcname, __FILE__, __LINE__)
#define free_tree(t) _free_tree(t, funcname, __FILE__, __LINE__)
@ -839,7 +915,13 @@ void clear_batch_list(device_extension* Vcb, LIST_ENTRY* batchlist);
#define do_load_tree(Vcb, th, r, t, td, loaded, Irp) _do_load_tree(Vcb, th, r, t, td, loaded, Irp, funcname, __FILE__, __LINE__)
// in search.c
void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes);
void remove_drive_letter(PDEVICE_OBJECT mountmgr, volume* v);
void add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us);
#ifdef __REACTOS__
NTSTATUS NTAPI pnp_notification(PVOID NotificationStructure, PVOID Context);
#else
NTSTATUS pnp_notification(PVOID NotificationStructure, PVOID Context);
#endif
// in cache.c
NTSTATUS STDCALL init_cache();
@ -853,19 +935,18 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
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);
void commit_checksum_changes(device_extension* Vcb, LIST_ENTRY* changed_sector_list);
chunk* get_chunk_from_address(device_extension* Vcb, UINT64 address);
chunk* alloc_chunk(device_extension* Vcb, UINT64 flags);
NTSTATUS STDCALL write_data(device_extension* Vcb, UINT64 address, void* data, BOOL need_free, UINT32 length, write_data_context* wtc, PIRP Irp, chunk* c);
NTSTATUS STDCALL write_data_complete(device_extension* Vcb, UINT64 address, void* data, UINT32 length, PIRP Irp, chunk* c);
void free_write_data_stripes(write_data_context* wtc);
NTSTATUS STDCALL drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
BOOL insert_extent_chunk(device_extension* Vcb, fcb* fcb, chunk* c, UINT64 start_data, UINT64 length, BOOL prealloc, void* data, LIST_ENTRY* changed_sector_list,
BOOL insert_extent_chunk(device_extension* Vcb, fcb* fcb, chunk* c, UINT64 start_data, UINT64 length, BOOL prealloc, void* data,
PIRP Irp, LIST_ENTRY* rollback, UINT8 compression, UINT64 decoded_size);
NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 length, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS do_write_file(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS write_compressed(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
BOOL find_address_in_chunk(device_extension* Vcb, chunk* c, UINT64 length, UINT64* address);
NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 length, void* data, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS do_write_file(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, PIRP Irp, 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);
// in dirctrl.c
@ -875,7 +956,8 @@ ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode,
// in security.c
NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
void fcb_get_sd(fcb* fcb, struct _fcb* parent, PIRP Irp);
BOOL get_sd_from_xattr(fcb* fcb, ULONG buflen);
void fcb_get_sd(fcb* fcb, struct _fcb* parent, BOOL look_for_xattr, PIRP Irp);
// UINT32 STDCALL get_uid();
void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid);
UINT32 sid_to_uid(PSID sid);
@ -891,6 +973,8 @@ NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* nam
NTSTATUS open_fileref_by_inode(device_extension* Vcb, root* subvol, UINT64 inode, file_ref** pfr, PIRP Irp);
NTSTATUS STDCALL drv_query_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS STDCALL drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN 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);
@ -899,15 +983,16 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
// in create.c
NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS STDCALL find_file_in_dir(device_extension* Vcb, PUNICODE_STRING filename, file_ref* fr,
root** subvol, UINT64* inode, UINT8* type, UINT64* index, PANSI_STRING utf8, BOOL case_sensitive, PIRP Irp);
NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* unparsed, ULONG* fn_offset,
NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* parsed, ULONG* fn_offset,
POOL_TYPE pooltype, BOOL case_sensitive, PIRP Irp);
NTSTATUS open_fcb(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp);
NTSTATUS open_fcb_stream(device_extension* Vcb, root* subvol, UINT64 inode, ANSI_STRING* xattr, UINT32 streamhash, fcb* parent, fcb** pfcb, PIRP Irp);
void insert_fileref_child(file_ref* parent, file_ref* child, BOOL do_lock);
NTSTATUS fcb_get_last_dir_index(fcb* fcb, UINT64* index, PIRP Irp);
NTSTATUS verify_vcb(device_extension* Vcb, PIRP Irp);
NTSTATUS load_csum(device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length, PIRP Irp);
NTSTATUS load_dir_children(fcb* fcb, BOOL ignore_size, PIRP Irp);
NTSTATUS add_dir_child(fcb* fcb, UINT64 inode, BOOL subvol, UINT64 index, PANSI_STRING utf8, PUNICODE_STRING name, PUNICODE_STRING name_uc, UINT8 type, dir_child** pdc);
// in fsctl.c
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user);
@ -920,11 +1005,15 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENT
void flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS STDCALL write_data_phys(PDEVICE_OBJECT device, UINT64 address, void* data, UINT32 length);
BOOL is_tree_unique(device_extension* Vcb, tree* t, PIRP Irp);
NTSTATUS do_tree_writes(device_extension* Vcb, LIST_ENTRY* tree_writes, PIRP Irp);
void add_checksum_entry(device_extension* Vcb, UINT64 address, ULONG length, UINT32* csum, PIRP Irp, LIST_ENTRY* rollback);
BOOL find_metadata_address_in_chunk(device_extension* Vcb, chunk* c, UINT64* address);
// in read.c
NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS STDCALL read_data(device_extension* Vcb, UINT64 addr, UINT32 length, UINT32* csum, BOOL is_tree, UINT8* buf, chunk* c, chunk** pc, PIRP Irp);
NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr, PIRP Irp);
NTSTATUS STDCALL read_data(device_extension* Vcb, UINT64 addr, UINT32 length, UINT32* csum, BOOL is_tree, UINT8* buf, chunk* c, chunk** pc,
PIRP Irp, BOOL check_nocsum_parity);
NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr, PIRP Irp, BOOL check_nocsum_parity);
NTSTATUS do_read(PIRP Irp, BOOL wait, ULONG* bytes_read);
// in pnp.c
@ -948,7 +1037,8 @@ void _space_list_subtract2(device_extension* Vcb, LIST_ENTRY* list, LIST_ENTRY*
// 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, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset,
UINT32 refcount, BOOL superseded, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_tree(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT8 level, PIRP Irp, LIST_ENTRY* rollback);
void decrease_chunk_usage(chunk* c, UINT64 delta);
// NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, PIRP Irp, LIST_ENTRY* rollback);
@ -963,7 +1053,8 @@ void add_changed_extent_ref(chunk* c, UINT64 address, UINT64 size, UINT64 root,
UINT64 find_extent_shared_tree_refcount(device_extension* Vcb, UINT64 address, UINT64 parent, PIRP Irp);
UINT64 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, PIRP Irp, LIST_ENTRY* rollback);
UINT8 level, UINT64 parent, BOOL superseded, PIRP Irp, LIST_ENTRY* rollback);
UINT64 get_extent_data_ref_hash2(UINT64 root, UINT64 objid, UINT64 offset);
// in worker-thread.c
void do_read_job(PIRP Irp);
@ -977,7 +1068,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb);
// in compress.c
NTSTATUS decompress(UINT8 type, UINT8* inbuf, UINT64 inlen, UINT8* outbuf, UINT64 outlen);
NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
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);
@ -989,6 +1080,24 @@ UINT8 gdiv(UINT8 a, UINT8 b);
// in devctrl.c
NTSTATUS STDCALL drv_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
// in calcthread.c
#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(device_extension* Vcb);
NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG length, KPROCESSOR_MODE processor_mode);
#define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable)
static __inline void print_open_trees(device_extension* Vcb) {
@ -1048,6 +1157,8 @@ static __inline void do_xor(UINT8* buf1, UINT8* buf2, UINT32 len) {
}
}
#define first_device(Vcb) CONTAINING_RECORD(Vcb->devices.Flink, device, list_entry)
#ifdef DEBUG_FCB_REFCOUNTS
#ifdef DEBUG_LONG_MESSAGES
#define increase_fileref_refcount(fileref) {\
@ -1144,6 +1255,29 @@ static __inline void do_xor(UINT8* buf1, UINT8* buf2, UINT32 len) {
#define called_from_lxss() FALSE
#endif
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);
#define CC_ENABLE_DISK_IO_ACCOUNTING 0x00000010
typedef VOID (*tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject, ULONG Flags);
#ifndef __REACTOS__
#undef RtlIsNtDdiVersionAvailable
BOOLEAN RtlIsNtDdiVersionAvailable(ULONG Version);
PEPROCESS PsGetThreadProcess(PETHREAD Thread); // not in mingw
#endif
#if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7)
NTSTATUS WINAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
ULONG *utf8_bytes_written,

View file

@ -8,6 +8,17 @@
#define FSCTL_BTRFS_CREATE_SNAPSHOT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82b, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_GET_INODE_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82c, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_SET_INODE_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82d, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_GET_DEVICES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82e, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_GET_USAGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82f, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_START_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x830, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_QUERY_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x831, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_PAUSE_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x832, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_RESUME_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x833, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_STOP_BALANCE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x834, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_ADD_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x835, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_REMOVE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x836, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_BTRFS_QUERY_FILESYSTEMS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x837, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_GET_UUID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x838, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
typedef struct {
UINT64 subvol;
@ -46,4 +57,92 @@ typedef struct {
BOOL mode_changed;
} btrfs_set_inode_info;
typedef struct {
UINT32 next_entry;
UINT64 dev_id;
UINT64 size;
BOOL readonly;
ULONG device_number;
ULONG partition_number;
USHORT namelen;
WCHAR name[1];
} btrfs_device;
typedef struct {
UINT64 dev_id;
UINT64 alloc;
} btrfs_usage_device;
typedef struct {
UINT32 next_entry;
UINT64 type;
UINT64 size;
UINT64 used;
UINT64 num_devices;
btrfs_usage_device devices[1];
} btrfs_usage;
#define BTRFS_BALANCE_OPTS_ENABLED 0x001
#define BTRFS_BALANCE_OPTS_PROFILES 0x002
#define BTRFS_BALANCE_OPTS_DEVID 0x004
#define BTRFS_BALANCE_OPTS_DRANGE 0x008
#define BTRFS_BALANCE_OPTS_VRANGE 0x010
#define BTRFS_BALANCE_OPTS_LIMIT 0x020
#define BTRFS_BALANCE_OPTS_STRIPES 0x040
#define BTRFS_BALANCE_OPTS_USAGE 0x080
#define BTRFS_BALANCE_OPTS_CONVERT 0x100
#define BTRFS_BALANCE_OPTS_SOFT 0x200
#define BLOCK_FLAG_SINGLE 0x1000000000000 // only used in balance
typedef struct {
UINT64 flags;
UINT64 profiles;
UINT64 devid;
UINT64 drange_start;
UINT64 drange_end;
UINT64 vrange_start;
UINT64 vrange_end;
UINT64 limit_start;
UINT64 limit_end;
UINT16 stripes_start;
UINT16 stripes_end;
UINT8 usage_start;
UINT8 usage_end;
UINT64 convert;
} btrfs_balance_opts;
#define BTRFS_BALANCE_STOPPED 0
#define BTRFS_BALANCE_RUNNING 1
#define BTRFS_BALANCE_PAUSED 2
#define BTRFS_BALANCE_REMOVAL 4
#define BTRFS_BALANCE_ERROR 8
typedef struct {
UINT32 status;
UINT64 chunks_left;
UINT64 total_chunks;
NTSTATUS error;
btrfs_balance_opts data_opts;
btrfs_balance_opts metadata_opts;
btrfs_balance_opts system_opts;
} btrfs_query_balance;
typedef struct {
btrfs_balance_opts opts[3];
} btrfs_start_balance;
typedef struct {
UINT8 uuid[16];
USHORT name_length;
WCHAR name[1];
} btrfs_filesystem_device;
typedef struct {
UINT32 next_entry;
UINT8 uuid[16];
UINT32 num_devices;
btrfs_filesystem_device device;
} btrfs_filesystem;
#endif

View file

@ -28,9 +28,14 @@ static BOOLEAN STDCALL acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) {
// if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE)
// return FALSE;
if (!ExAcquireResourceSharedLite(fcb->Header.PagingIoResource, Wait))
if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, Wait))
return FALSE;
if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, Wait)) {
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
return FALSE;
}
fcb->lazy_writer_thread = KeGetCurrentThread();
@ -48,7 +53,9 @@ static void STDCALL release_from_lazy_write(PVOID Context) {
fcb->lazy_writer_thread = NULL;
ExReleaseResourceLite(fcb->Header.PagingIoResource);
ExReleaseResourceLite(fcb->Header.Resource);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
}
static BOOLEAN STDCALL acquire_for_read_ahead(PVOID Context, BOOLEAN Wait) {

View file

@ -0,0 +1,142 @@
/* Copyright (c) Mark Harmstone 2016
*
* 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 <http://www.gnu.org/licenses/>. */
#include "btrfs_drv.h"
#define SECTOR_BLOCK 16
NTSTATUS add_calc_job(device_extension* Vcb, UINT8* data, UINT32 sectors, UINT32* csum, calc_job** pcj) {
calc_job* cj;
cj = ExAllocatePoolWithTag(NonPagedPool, sizeof(calc_job), ALLOC_TAG);
if (!cj) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
cj->data = data;
cj->sectors = sectors;
cj->csum = csum;
cj->pos = 0;
cj->done = 0;
cj->refcount = 1;
KeInitializeEvent(&cj->event, NotificationEvent, FALSE);
ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE);
InsertTailList(&Vcb->calcthreads.job_list, &cj->list_entry);
ExReleaseResourceLite(&Vcb->calcthreads.lock);
KeSetEvent(&Vcb->calcthreads.event, 0, FALSE);
KeClearEvent(&Vcb->calcthreads.event);
*pcj = cj;
return STATUS_SUCCESS;
}
void free_calc_job(calc_job* cj) {
LONG rc = InterlockedDecrement(&cj->refcount);
if (rc == 0)
ExFreePool(cj);
}
static BOOL do_calc(device_extension* Vcb, calc_job* cj) {
LONG pos, done;
UINT32* csum;
UINT8* data;
ULONG blocksize, i;
pos = InterlockedIncrement(&cj->pos) - 1;
if (pos * SECTOR_BLOCK >= cj->sectors)
return FALSE;
csum = &cj->csum[pos * SECTOR_BLOCK];
data = cj->data + (pos * SECTOR_BLOCK * Vcb->superblock.sector_size);
blocksize = min(SECTOR_BLOCK, cj->sectors - (pos * SECTOR_BLOCK));
for (i = 0; i < blocksize; i++) {
*csum = ~calc_crc32c(0xffffffff, data, Vcb->superblock.sector_size);
csum++;
data += Vcb->superblock.sector_size;
}
done = InterlockedIncrement(&cj->done);
if (done * SECTOR_BLOCK >= cj->sectors) {
ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE);
RemoveEntryList(&cj->list_entry);
ExReleaseResourceLite(&Vcb->calcthreads.lock);
KeSetEvent(&cj->event, 0, FALSE);
}
return TRUE;
}
#ifdef __REACTOS__
void NTAPI calc_thread(void* context) {
#else
void calc_thread(void* context) {
#endif
drv_calc_thread* thread = context;
device_extension* Vcb = thread->DeviceObject->DeviceExtension;
ObReferenceObject(thread->DeviceObject);
while (TRUE) {
KeWaitForSingleObject(&Vcb->calcthreads.event, Executive, KernelMode, FALSE, NULL);
FsRtlEnterFileSystem();
while (TRUE) {
calc_job* cj;
BOOL b;
ExAcquireResourceExclusiveLite(&Vcb->calcthreads.lock, TRUE);
if (IsListEmpty(&Vcb->calcthreads.job_list)) {
ExReleaseResourceLite(&Vcb->calcthreads.lock);
break;
}
cj = CONTAINING_RECORD(Vcb->calcthreads.job_list.Flink, calc_job, list_entry);
cj->refcount++;
ExReleaseResourceLite(&Vcb->calcthreads.lock);
b = do_calc(Vcb, cj);
free_calc_job(cj);
if (!b)
break;
}
FsRtlExitFileSystem();
if (thread->quit)
break;
}
ObDereferenceObject(thread->DeviceObject);
KeSetEvent(&thread->finished, 0, FALSE);
PsTerminateSystemThread(STATUS_SUCCESS);
}

View file

@ -357,7 +357,7 @@ NTSTATUS decompress(UINT8 type, UINT8* inbuf, UINT64 inlen, UINT8* outbuf, UINT6
}
}
static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback) {
static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
UINT8 compression;
UINT64 comp_length;
@ -444,11 +444,11 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 en
while (le != &fcb->Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly) {
if (!c->readonly && !c->reloc) {
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data)) {
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
if (compression != BTRFS_COMPRESSION_NONE)
@ -474,7 +474,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 en
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data)) {
if (compression != BTRFS_COMPRESSION_NONE)
ExFreePool(comp_data);
@ -732,7 +732,7 @@ static __inline UINT32 lzo_max_outlen(UINT32 inlen) {
return inlen + (inlen / 16) + 64 + 3; // formula comes from LZO.FAQ
}
static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback) {
static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
UINT8 compression;
UINT64 comp_length;
@ -829,11 +829,11 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end
while (le != &fcb->Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly) {
if (!c->readonly && !c->reloc) {
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data)) {
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
if (compression != BTRFS_COMPRESSION_NONE)
@ -859,7 +859,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, Irp, rollback, compression, end_data - start_data)) {
if (compression != BTRFS_COMPRESSION_NONE)
ExFreePool(comp_data);
@ -876,7 +876,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end
return STATUS_DISK_FULL;
}
NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback) {
UINT8 type;
if (fcb->Vcb->options.compress_type != 0)
@ -890,7 +890,7 @@ NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void
if (type == BTRFS_COMPRESSION_LZO) {
fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO;
return lzo_write_compressed_bit(fcb, start_data, end_data, data, compressed, changed_sector_list, Irp, rollback);
return lzo_write_compressed_bit(fcb, start_data, end_data, data, compressed, Irp, rollback);
} else
return zlib_write_compressed_bit(fcb, start_data, end_data, data, compressed, changed_sector_list, Irp, rollback);
return zlib_write_compressed_bit(fcb, start_data, end_data, data, compressed, Irp, rollback);
}

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,9 @@
#include <initguid.h>
#include <diskguid.h>
extern LIST_ENTRY VcbList;
extern ERESOURCE global_loading_lock;
static NTSTATUS part0_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
NTSTATUS Status;
part0_device_extension* p0de = DeviceObject->DeviceExtension;
@ -79,7 +82,7 @@ static NTSTATUS part0_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp
name = Irp->AssociatedIrp.SystemBuffer;
name->NameLength = p0de->name.Length;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME) - 1 + name->NameLength) {
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < offsetof(MOUNTDEV_NAME, Name[0]) + name->NameLength) {
Status = STATUS_BUFFER_OVERFLOW;
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
@ -91,7 +94,7 @@ static NTSTATUS part0_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp
Status = STATUS_SUCCESS;
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME) - 1 + name->NameLength;
Irp->IoStatus.Information = offsetof(MOUNTDEV_NAME, Name[0]) + name->NameLength;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
@ -130,7 +133,7 @@ static NTSTATUS get_partition_info_ex(device_extension* Vcb, PIRP Irp) {
TRACE("IOCTL_DISK_GET_PARTITION_INFO_EX\n");
Status = dev_ioctl(Vcb->devices[0].devobj, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
Status = dev_ioctl(Vcb->Vpb->RealDevice, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0,
Irp->UserBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, TRUE, &Irp->IoStatus);
if (!NT_SUCCESS(Status))
return Status;
@ -153,6 +156,132 @@ static NTSTATUS is_writable(device_extension* Vcb, PIRP Irp) {
return Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_SUCCESS;
}
static NTSTATUS query_filesystems(void* data, ULONG length) {
NTSTATUS Status;
LIST_ENTRY *le, *le2;
btrfs_filesystem* bfs = NULL;
ULONG itemsize;
ExAcquireResourceSharedLite(&global_loading_lock, TRUE);
if (IsListEmpty(&VcbList)) {
if (length < sizeof(btrfs_filesystem)) {
Status = STATUS_BUFFER_OVERFLOW;
goto end;
} else {
RtlZeroMemory(data, sizeof(btrfs_filesystem));
Status = STATUS_SUCCESS;
goto end;
}
}
le = VcbList.Flink;
while (le != &VcbList) {
device_extension* Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
btrfs_filesystem_device* bfd;
if (bfs) {
bfs->next_entry = itemsize;
bfs = (btrfs_filesystem*)((UINT8*)bfs + itemsize);
} else
bfs = data;
if (length < offsetof(btrfs_filesystem, device)) {
Status = STATUS_BUFFER_OVERFLOW;
goto end;
}
itemsize = offsetof(btrfs_filesystem, device);
length -= offsetof(btrfs_filesystem, device);
bfs->next_entry = 0;
RtlCopyMemory(&bfs->uuid, &Vcb->superblock.uuid, sizeof(BTRFS_UUID));
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
bfs->num_devices = Vcb->superblock.num_devices;
bfd = NULL;
le2 = Vcb->devices.Flink;
while (le2 != &Vcb->devices) {
device* dev = CONTAINING_RECORD(le2, device, list_entry);
MOUNTDEV_NAME mdn;
if (bfd)
bfd = (btrfs_filesystem_device*)((UINT8*)bfd + offsetof(btrfs_filesystem_device, name[0]) + bfd->name_length);
else
bfd = &bfs->device;
if (length < offsetof(btrfs_filesystem_device, name[0])) {
ExReleaseResourceLite(&Vcb->tree_lock);
Status = STATUS_BUFFER_OVERFLOW;
goto end;
}
itemsize += offsetof(btrfs_filesystem_device, name[0]);
length -= offsetof(btrfs_filesystem_device, name[0]);
RtlCopyMemory(&bfd->uuid, &dev->devitem.device_uuid, sizeof(BTRFS_UUID));
Status = dev_ioctl(dev->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), TRUE, NULL);
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
ExReleaseResourceLite(&Vcb->tree_lock);
ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
goto end;
}
if (mdn.NameLength > length) {
ExReleaseResourceLite(&Vcb->tree_lock);
Status = STATUS_BUFFER_OVERFLOW;
goto end;
}
Status = dev_ioctl(dev->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &bfd->name_length, offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength, TRUE, NULL);
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
ExReleaseResourceLite(&Vcb->tree_lock);
ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
goto end;
}
itemsize += bfd->name_length;
length -= bfd->name_length;
le2 = le2->Flink;
}
ExReleaseResourceLite(&Vcb->tree_lock);
le = le->Flink;
}
Status = STATUS_SUCCESS;
end:
ExReleaseResourceLite(&global_loading_lock);
return Status;
}
static NTSTATUS control_ioctl(PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status;
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_BTRFS_QUERY_FILESYSTEMS:
Status = query_filesystems(map_user_buffer(Irp), IrpSp->Parameters.FileSystemControl.OutputBufferLength);
break;
default:
TRACE("unhandled ioctl %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
Status = STATUS_NOT_IMPLEMENTED;
break;
}
return Status;
}
NTSTATUS STDCALL drv_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
@ -165,9 +294,22 @@ NTSTATUS STDCALL drv_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Irp->IoStatus.Information = 0;
if (Vcb && Vcb->type == VCB_TYPE_PARTITION0) {
Status = part0_device_control(DeviceObject, Irp);
goto end2;
if (Vcb) {
if (Vcb->type == VCB_TYPE_PARTITION0) {
Status = part0_device_control(DeviceObject, Irp);
goto end2;
} else if (Vcb->type == VCB_TYPE_CONTROL) {
Status = control_ioctl(Irp);
goto end;
}
} else {
Status = STATUS_INVALID_PARAMETER;
goto end;
}
if (!IrpSp->FileObject || IrpSp->FileObject->FsContext != Vcb->volume_fcb) {
Status = STATUS_INVALID_PARAMETER;
goto end;
}
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
@ -190,7 +332,7 @@ NTSTATUS STDCALL drv_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp);
goto end2;

View file

@ -25,9 +25,7 @@ enum DirEntryType {
typedef struct {
KEY key;
BOOL name_alloc;
char* name;
ULONG namelen;
UNICODE_STRING name;
UINT8 type;
enum DirEntryType dir_entry_type;
} dir_entry;
@ -50,14 +48,11 @@ ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode,
if (!(atts & FILE_ATTRIBUTE_REPARSE_POINT))
return 0;
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
Status = open_fcb(Vcb, subvol, inode, type, NULL, NULL, &fcb, PagedPool, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fcb returned %08x\n", Status);
ExReleaseResourceLite(&Vcb->fcb_lock);
return 0;
}
ExReleaseResourceLite(&Vcb->fcb_lock);
ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE);
@ -67,7 +62,7 @@ ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode,
RtlCopyMemory(&tag, fcb->reparse_xattr.Buffer, sizeof(ULONG));
} else {
Status = read_file(fcb, (UINT8*)&tag, 0, sizeof(ULONG), &br, NULL);
Status = read_file(fcb, (UINT8*)&tag, 0, sizeof(ULONG), &br, NULL, TRUE);
if (!NT_SUCCESS(Status)) {
ERR("read_file returned %08x\n", Status);
goto end;
@ -80,9 +75,7 @@ ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode,
end:
ExReleaseResourceLite(fcb->Header.Resource);
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
free_fcb(fcb);
ExReleaseResourceLite(&Vcb->fcb_lock);
return tag;
}
@ -130,7 +123,6 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
UINT64 inode;
INODE_ITEM ii;
NTSTATUS Status;
ULONG stringlen;
ULONG atts, ealen;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
@ -169,7 +161,6 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
LIST_ENTRY* le;
BOOL found = FALSE;
ExAcquireResourceSharedLite(&fcb->Vcb->fcb_lock, TRUE);
if (!IsListEmpty(&r->fcbs)) {
le = r->fcbs.Flink;
while (le != &r->fcbs) {
@ -181,12 +172,12 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
ealen = fcb2->ealen;
found = TRUE;
break;
}
} else if (fcb2->inode > inode)
break;
le = le->Flink;
}
}
ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
if (!found) {
KEY searchkey;
@ -218,7 +209,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation ||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation) {
BOOL dotfile = de->namelen > 1 && de->name[0] == '.';
BOOL dotfile = de->name.Length > sizeof(WCHAR) && de->name.Buffer[0] == '.';
atts = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE, Irp);
}
@ -257,21 +248,6 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
}
}
// FICs which return the filename
if (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileDirectoryInformation ||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileFullDirectoryInformation ||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation ||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation ||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileNamesInformation) {
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de->name, de->namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
return Status;
}
}
switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
case FileBothDirectoryInformation:
{
@ -279,7 +255,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
TRACE("FileBothDirectoryInformation\n");
needed = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
needed = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;
if (needed > *len) {
TRACE("buffer overflow - %u > %u\n", needed, *len);
@ -295,17 +271,12 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fbdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
fbdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
fbdi->FileAttributes = atts;
fbdi->FileNameLength = stringlen;
fbdi->FileNameLength = de->name.Length;
fbdi->EaSize = atts & FILE_ATTRIBUTE_REPARSE_POINT ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, Irp) : ealen;
fbdi->ShortNameLength = 0;
// fibdi->ShortName[12];
Status = RtlUTF8ToUnicodeN(fbdi->FileName, stringlen, &stringlen, de->name, de->namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
return Status;
}
RtlCopyMemory(fbdi->FileName, de->name.Buffer, de->name.Length);
*len -= needed;
@ -318,7 +289,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
TRACE("FileDirectoryInformation\n");
needed = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR) + stringlen;
needed = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR) + de->name.Length;
if (needed > *len) {
TRACE("buffer overflow - %u > %u\n", needed, *len);
@ -334,14 +305,9 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
fdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
fdi->FileAttributes = atts;
fdi->FileNameLength = stringlen;
fdi->FileNameLength = de->name.Length;
Status = RtlUTF8ToUnicodeN(fdi->FileName, stringlen, &stringlen, de->name, de->namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
return Status;
}
RtlCopyMemory(fdi->FileName, de->name.Buffer, de->name.Length);
*len -= needed;
@ -354,7 +320,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
TRACE("FileFullDirectoryInformation\n");
needed = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
needed = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;
if (needed > *len) {
TRACE("buffer overflow - %u > %u\n", needed, *len);
@ -370,15 +336,10 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
ffdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
ffdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
ffdi->FileAttributes = atts;
ffdi->FileNameLength = stringlen;
ffdi->FileNameLength = de->name.Length;
ffdi->EaSize = atts & FILE_ATTRIBUTE_REPARSE_POINT ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, Irp) : ealen;
Status = RtlUTF8ToUnicodeN(ffdi->FileName, stringlen, &stringlen, de->name, de->namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
return Status;
}
RtlCopyMemory(ffdi->FileName, de->name.Buffer, de->name.Length);
*len -= needed;
@ -391,7 +352,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
TRACE("FileIdBothDirectoryInformation\n");
needed = sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
needed = sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;
if (needed > *len) {
TRACE("buffer overflow - %u > %u\n", needed, *len);
@ -410,18 +371,13 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fibdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
fibdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
fibdi->FileAttributes = atts;
fibdi->FileNameLength = stringlen;
fibdi->FileNameLength = de->name.Length;
fibdi->EaSize = atts & FILE_ATTRIBUTE_REPARSE_POINT ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, Irp) : ealen;
fibdi->ShortNameLength = 0;
// fibdi->ShortName[12];
fibdi->FileId.QuadPart = make_file_id(r, inode);
Status = RtlUTF8ToUnicodeN(fibdi->FileName, stringlen, &stringlen, de->name, de->namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
return Status;
}
RtlCopyMemory(fibdi->FileName, de->name.Buffer, de->name.Length);
*len -= needed;
@ -434,7 +390,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
TRACE("FileIdFullDirectoryInformation\n");
needed = sizeof(FILE_ID_FULL_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
needed = sizeof(FILE_ID_FULL_DIR_INFORMATION) - sizeof(WCHAR) + de->name.Length;
if (needed > *len) {
TRACE("buffer overflow - %u > %u\n", needed, *len);
@ -453,16 +409,11 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fifdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
fifdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
fifdi->FileAttributes = atts;
fifdi->FileNameLength = stringlen;
fifdi->FileNameLength = de->name.Length;
fifdi->EaSize = atts & FILE_ATTRIBUTE_REPARSE_POINT ? get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, Irp) : ealen;
fifdi->FileId.QuadPart = make_file_id(r, inode);
Status = RtlUTF8ToUnicodeN(fifdi->FileName, stringlen, &stringlen, de->name, de->namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
return Status;
}
RtlCopyMemory(fifdi->FileName, de->name.Buffer, de->name.Length);
*len -= needed;
@ -475,7 +426,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
TRACE("FileNamesInformation\n");
needed = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR) + stringlen;
needed = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR) + de->name.Length;
if (needed > *len) {
TRACE("buffer overflow - %u > %u\n", needed, *len);
@ -484,14 +435,9 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fni->NextEntryOffset = 0;
fni->FileIndex = 0;
fni->FileNameLength = stringlen;
fni->FileNameLength = de->name.Length;
Status = RtlUTF8ToUnicodeN(fni->FileName, stringlen, &stringlen, de->name, de->namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
return Status;
}
RtlCopyMemory(fni->FileName, de->name.Buffer, de->name.Length);
*len -= needed;
@ -518,14 +464,20 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
return STATUS_NO_MORE_FILES;
}
static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_entry* de, PIRP Irp) {
KEY searchkey;
traverse_ptr tp, next_tp;
DIR_ITEM* di;
NTSTATUS Status;
file_ref* fr;
static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_entry* de, dir_child** pdc, PIRP Irp) {
LIST_ENTRY* le;
char* name;
dir_child* dc;
if (*pdc) {
dir_child* dc2 = *pdc;
if (dc2->list_entry_index.Flink != &fileref->fcb->dir_children_index)
dc = CONTAINING_RECORD(dc2->list_entry_index.Flink, dir_child, list_entry_index);
else
dc = NULL;
goto next;
}
if (fileref->parent) { // don't return . and .. if root directory
if (*offset == 0) {
@ -533,12 +485,12 @@ static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_en
de->key.obj_type = TYPE_INODE_ITEM;
de->key.offset = 0;
de->dir_entry_type = DirEntryType_Self;
de->name = ".";
de->name_alloc = FALSE;
de->namelen = 1;
de->name.Buffer = L".";
de->name.Length = de->name.MaximumLength = sizeof(WCHAR);
de->type = BTRFS_TYPE_DIRECTORY;
*offset = 1;
*pdc = NULL;
return STATUS_SUCCESS;
} else if (*offset == 1) {
@ -546,12 +498,12 @@ static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_en
de->key.obj_type = TYPE_INODE_ITEM;
de->key.offset = 0;
de->dir_entry_type = DirEntryType_Parent;
de->name = "..";
de->name_alloc = FALSE;
de->namelen = 2;
de->name.Buffer = L"..";
de->name.Length = de->name.MaximumLength = sizeof(WCHAR) * 2;
de->type = BTRFS_TYPE_DIRECTORY;
*offset = 2;
*pdc = NULL;
return STATUS_SUCCESS;
}
@ -560,168 +512,34 @@ static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_en
if (*offset < 2)
*offset = 2;
ExAcquireResourceSharedLite(&fileref->nonpaged->children_lock, TRUE);
fr = NULL;
le = fileref->children.Flink;
dc = NULL;
le = fileref->fcb->dir_children_index.Flink;
// skip entries before offset
while (le != &fileref->children) {
file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry);
while (le != &fileref->fcb->dir_children_index) {
dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
if (fr2->index >= *offset) {
fr = fr2;
if (dc2->index >= *offset) {
dc = dc2;
break;
}
le = le->Flink;
}
do {
if (fr && fr->index == *offset) {
if (!fr->deleted) {
if (fr->fcb->subvol == fileref->fcb->subvol) {
de->key.obj_id = fr->fcb->inode;
de->key.obj_type = TYPE_INODE_ITEM;
de->key.offset = 0;
} else {
de->key.obj_id = fr->fcb->subvol->id;
de->key.obj_type = TYPE_ROOT_ITEM;
de->key.offset = 0;
}
name = fr->utf8.Buffer;
de->namelen = fr->utf8.Length;
de->type = fr->fcb->type;
de->dir_entry_type = DirEntryType_File;
(*offset)++;
Status = STATUS_SUCCESS;
goto end;
} else {
(*offset)++;
fr = fr->list_entry.Flink == &fileref->children ? NULL : CONTAINING_RECORD(fr->list_entry.Flink, file_ref, list_entry);
continue;
}
}
searchkey.obj_id = fileref->fcb->inode;
searchkey.obj_type = TYPE_DIR_INDEX;
searchkey.offset = *offset;
Status = find_item(fileref->fcb->Vcb, fileref->fcb->subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
goto end;
}
if (keycmp(tp.item->key, searchkey) == -1) {
if (find_next_item(fileref->fcb->Vcb, &tp, &next_tp, FALSE, Irp))
tp = next_tp;
}
if (keycmp(tp.item->key, searchkey) != -1 && tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
do {
if (fr) {
if (fr->index <= tp.item->key.offset && !fr->deleted) {
if (fr->fcb->subvol == fileref->fcb->subvol) {
de->key.obj_id = fr->fcb->inode;
de->key.obj_type = TYPE_INODE_ITEM;
de->key.offset = 0;
} else {
de->key.obj_id = fr->fcb->subvol->id;
de->key.obj_type = TYPE_ROOT_ITEM;
de->key.offset = 0;
}
name = fr->utf8.Buffer;
de->namelen = fr->utf8.Length;
de->type = fr->fcb->type;
de->dir_entry_type = DirEntryType_File;
*offset = fr->index + 1;
Status = STATUS_SUCCESS;
goto end;
}
if (fr->index == tp.item->key.offset && fr->deleted)
break;
fr = fr->list_entry.Flink == &fileref->children ? NULL : CONTAINING_RECORD(fr->list_entry.Flink, file_ref, list_entry);
}
} while (fr && fr->index < tp.item->key.offset);
if (fr && fr->index == tp.item->key.offset && fr->deleted) {
*offset = fr->index + 1;
fr = fr->list_entry.Flink == &fileref->children ? NULL : CONTAINING_RECORD(fr->list_entry.Flink, file_ref, list_entry);
continue;
}
*offset = tp.item->key.offset + 1;
di = (DIR_ITEM*)tp.item->data;
if (tp.item->size < sizeof(DIR_ITEM) || tp.item->size < sizeof(DIR_ITEM) - 1 + di->m + di->n) {
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
Status = STATUS_INTERNAL_ERROR;
goto end;
}
de->key = di->key;
name = di->name;
de->namelen = di->n;
de->type = di->type;
de->dir_entry_type = DirEntryType_File;
Status = STATUS_SUCCESS;
goto end;
} else {
if (fr) {
if (fr->fcb->subvol == fileref->fcb->subvol) {
de->key.obj_id = fr->fcb->inode;
de->key.obj_type = TYPE_INODE_ITEM;
de->key.offset = 0;
} else {
de->key.obj_id = fr->fcb->subvol->id;
de->key.obj_type = TYPE_ROOT_ITEM;
de->key.offset = 0;
}
name = fr->utf8.Buffer;
de->namelen = fr->utf8.Length;
de->type = fr->fcb->type;
de->dir_entry_type = DirEntryType_File;
*offset = fr->index + 1;
Status = STATUS_SUCCESS;
goto end;
} else {
Status = STATUS_NO_MORE_FILES;
goto end;
}
}
} while (TRUE);
next:
if (!dc)
return STATUS_NO_MORE_FILES;
end:
ExReleaseResourceLite(&fileref->nonpaged->children_lock);
de->key = dc->key;
de->name = dc->name;
de->type = dc->type;
de->dir_entry_type = DirEntryType_File;
if (NT_SUCCESS(Status)) {
de->name_alloc = TRUE;
de->name = ExAllocatePoolWithTag(PagedPool, de->namelen, ALLOC_TAG);
if (!de->name) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(de->name, name, de->namelen);
} else
de->name_alloc = FALSE;
*offset = dc->index + 1;
*pdc = dc;
return Status;
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
@ -739,6 +557,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
dir_entry de;
UINT64 newoffset;
ANSI_STRING utf8;
dir_child* dc = NULL;
TRACE("query directory\n");
@ -767,6 +586,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
}
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
ExAcquireResourceSharedLite(&fcb->Vcb->fcb_lock, TRUE);
TRACE("%S\n", file_desc(IrpSp->FileObject));
@ -828,7 +648,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (!ccb->query_string.Buffer) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
goto end2;
}
ccb->query_string.Length = ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length;
@ -846,7 +666,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (specific_file) {
Status = STATUS_NO_MORE_FILES;
goto end;
goto end2;
}
}
}
@ -856,7 +676,10 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
}
newoffset = ccb->query_dir_offset;
Status = next_dir_entry(fileref, &newoffset, &de, Irp);
ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE);
Status = next_dir_entry(fileref, &newoffset, &de, &dc, Irp);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_NO_MORE_FILES && initial)
@ -878,11 +701,10 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (specific_file) {
BOOL found = FALSE;
root* found_subvol;
UINT64 found_inode, found_index;
UINT8 found_type;
UNICODE_STRING us;
LIST_ENTRY* le;
UINT32 hash;
UINT8 c;
us.Buffer = NULL;
@ -892,163 +714,89 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
goto end;
}
}
ExAcquireResourceSharedLite(&fileref->nonpaged->children_lock, TRUE);
le = fileref->children.Flink;
while (le != &fileref->children) {
file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry);
if (!fr2->deleted) {
if (!ccb->case_sensitive && fr2->filepart_uc.Length == us.Length &&
RtlCompareMemory(fr2->filepart_uc.Buffer, us.Buffer, us.Length) == us.Length)
found = TRUE;
else if (ccb->case_sensitive && fr2->filepart.Length == ccb->query_string.Length &&
RtlCompareMemory(fr2->filepart.Buffer, ccb->query_string.Buffer, ccb->query_string.Length) == ccb->query_string.Length)
found = TRUE;
}
if (found) {
if (fr2->fcb->subvol == fcb->subvol) {
de.key.obj_id = fr2->fcb->inode;
de.key.obj_type = TYPE_INODE_ITEM;
de.key.offset = 0;
} else {
de.key.obj_id = fr2->fcb->subvol->id;
de.key.obj_type = TYPE_ROOT_ITEM;
de.key.offset = 0;
}
de.name = ExAllocatePoolWithTag(PagedPool, fr2->utf8.Length, ALLOC_TAG);
if (!de.name) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
RtlCopyMemory(de.name, fr2->utf8.Buffer, fr2->utf8.Length);
de.name_alloc = TRUE;
de.namelen = fr2->utf8.Length;
de.type = fr2->fcb->type;
de.dir_entry_type = DirEntryType_File;
break;
}
le = le->Flink;
}
hash = calc_crc32c(0xffffffff, (UINT8*)us.Buffer, us.Length);
} else
hash = calc_crc32c(0xffffffff, (UINT8*)ccb->query_string.Buffer, ccb->query_string.Length);
ExReleaseResourceLite(&fileref->nonpaged->children_lock);
c = hash >> 24;
if (ccb->case_sensitive) {
if (fileref->fcb->hash_ptrs[c]) {
le = fileref->fcb->hash_ptrs[c];
while (le != &fileref->fcb->dir_children_hash) {
dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash);
if (dc2->hash == hash) {
if (dc2->name.Length == ccb->query_string.Length && RtlCompareMemory(dc2->name.Buffer, ccb->query_string.Buffer, ccb->query_string.Length) == ccb->query_string.Length) {
found = TRUE;
de.key = dc2->key;
de.name = dc2->name;
de.type = dc2->type;
de.dir_entry_type = DirEntryType_File;
break;
}
} else if (dc2->hash > hash)
break;
le = le->Flink;
}
}
} else {
if (fileref->fcb->hash_ptrs_uc[c]) {
le = fileref->fcb->hash_ptrs_uc[c];
while (le != &fileref->fcb->dir_children_hash_uc) {
dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
if (dc2->hash_uc == hash) {
if (dc2->name_uc.Length == us.Length && RtlCompareMemory(dc2->name_uc.Buffer, us.Buffer, us.Length) == us.Length) {
found = TRUE;
de.key = dc2->key;
de.name = dc2->name;
de.type = dc2->type;
de.dir_entry_type = DirEntryType_File;
break;
}
} else if (dc2->hash_uc > hash)
break;
le = le->Flink;
}
}
}
if (us.Buffer)
ExFreePool(us.Buffer);
if (!found) {
Status = find_file_in_dir(fcb->Vcb, &ccb->query_string, fileref, &found_subvol, &found_inode, &found_type, &found_index, &utf8, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
Status = STATUS_NO_SUCH_FILE;
goto end;
}
if (found_subvol == fcb->subvol) {
de.key.obj_id = found_inode;
de.key.obj_type = TYPE_INODE_ITEM;
de.key.offset = 0;
} else {
de.key.obj_id = found_subvol->id;
de.key.obj_type = TYPE_ROOT_ITEM;
de.key.offset = 0;
}
de.name = utf8.Buffer;
de.name_alloc = FALSE;
de.namelen = utf8.Length;
de.type = found_type;
de.dir_entry_type = DirEntryType_File;
Status = STATUS_NO_SUCH_FILE;
goto end;
}
} else if (has_wildcard) {
WCHAR* uni_fn;
ULONG stringlen;
UNICODE_STRING di_uni_fn;
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de.name, de.namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
goto end;
}
uni_fn = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
if (!uni_fn) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
Status = RtlUTF8ToUnicodeN(uni_fn, stringlen, &stringlen, de.name, de.namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
goto end;
}
di_uni_fn.Length = di_uni_fn.MaximumLength = stringlen;
di_uni_fn.Buffer = uni_fn;
while (!FsRtlIsNameInExpression(&ccb->query_string, &di_uni_fn, !ccb->case_sensitive, NULL)) {
if (de.name_alloc)
ExFreePool(de.name);
while (!FsRtlIsNameInExpression(&ccb->query_string, &de.name, !ccb->case_sensitive, NULL)) {
newoffset = ccb->query_dir_offset;
Status = next_dir_entry(fileref, &newoffset, &de, Irp);
Status = next_dir_entry(fileref, &newoffset, &de, &dc, Irp);
ExFreePool(uni_fn);
if (NT_SUCCESS(Status)) {
if (NT_SUCCESS(Status))
ccb->query_dir_offset = newoffset;
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de.name, de.namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
goto end;
}
uni_fn = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
if (!uni_fn) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
Status = RtlUTF8ToUnicodeN(uni_fn, stringlen, &stringlen, de.name, de.namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
ExFreePool(uni_fn);
goto end;
}
di_uni_fn.Length = di_uni_fn.MaximumLength = stringlen;
di_uni_fn.Buffer = uni_fn;
} else {
else {
if (Status == STATUS_NO_MORE_FILES && initial)
Status = STATUS_NO_SUCH_FILE;
goto end;
}
}
ExFreePool(uni_fn);
}
TRACE("file(0) = %.*s\n", de.namelen, de.name);
TRACE("file(0) = %.*S\n", de.name.Length / sizeof(WCHAR), de.name.Buffer);
TRACE("offset = %u\n", ccb->query_dir_offset - 1);
Status = query_dir_item(fcb, fileref, buf, &length, Irp, &de, fcb->subvol);
if (de.name_alloc)
ExFreePool(de.name);
count = 0;
if (NT_SUCCESS(Status) && !(IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) && !specific_file) {
lastitem = (UINT8*)buf;
@ -1073,48 +821,14 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
}
if (length > 0) {
WCHAR* uni_fn = NULL;
UNICODE_STRING di_uni_fn;
newoffset = ccb->query_dir_offset;
Status = next_dir_entry(fileref, &newoffset, &de, Irp);
Status = next_dir_entry(fileref, &newoffset, &de, &dc, Irp);
if (NT_SUCCESS(Status)) {
if (has_wildcard) {
ULONG stringlen;
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de.name, de.namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
if (de.name_alloc) ExFreePool(de.name);
goto end;
}
uni_fn = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
if (!uni_fn) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
if (de.name_alloc) ExFreePool(de.name);
goto end;
}
Status = RtlUTF8ToUnicodeN(uni_fn, stringlen, &stringlen, de.name, de.namelen);
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
ExFreePool(uni_fn);
if (de.name_alloc) ExFreePool(de.name);
goto end;
}
di_uni_fn.Length = di_uni_fn.MaximumLength = stringlen;
di_uni_fn.Buffer = uni_fn;
}
if (!has_wildcard || FsRtlIsNameInExpression(&ccb->query_string, &di_uni_fn, !ccb->case_sensitive, NULL)) {
if (!has_wildcard || FsRtlIsNameInExpression(&ccb->query_string, &de.name, !ccb->case_sensitive, NULL)) {
curitem = (UINT8*)buf + IrpSp->Parameters.QueryDirectory.Length - length;
count++;
TRACE("file(%u) %u = %.*s\n", count, curitem - (UINT8*)buf, de.namelen, de.name);
TRACE("file(%u) %u = %.*S\n", count, curitem - (UINT8*)buf, de.name.Length / sizeof(WCHAR), de.name.Buffer);
TRACE("offset = %u\n", ccb->query_dir_offset - 1);
status2 = query_dir_item(fcb, fileref, curitem, &length, Irp, &de, fcb->subvol);
@ -1126,21 +840,10 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ccb->query_dir_offset = newoffset;
lastitem = curitem;
} else {
if (uni_fn) ExFreePool(uni_fn);
if (de.name_alloc) ExFreePool(de.name);
} else
break;
}
} else
ccb->query_dir_offset = newoffset;
if (uni_fn) {
ExFreePool(uni_fn);
uni_fn = NULL;
}
if (de.name_alloc)
ExFreePool(de.name);
} else {
if (Status == STATUS_NO_MORE_FILES)
Status = STATUS_SUCCESS;
@ -1155,6 +858,10 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Irp->IoStatus.Information = IrpSp->Parameters.QueryDirectory.Length - length;
end:
ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
end2:
ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
TRACE("returning %08x\n", Status);

View file

@ -84,7 +84,7 @@ static __inline UINT64 get_extent_data_refcount(UINT8 type, void* data) {
}
}
static UINT64 get_extent_data_ref_hash2(UINT64 root, UINT64 objid, UINT64 offset) {
UINT64 get_extent_data_ref_hash2(UINT64 root, UINT64 objid, UINT64 offset) {
UINT32 high_crc = 0xffffffff, low_crc = 0xffffffff;
high_crc = calc_crc32c(high_crc, (UINT8*)&root, sizeof(UINT64));
@ -474,7 +474,7 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
UINT8* ptr;
eisize = sizeof(EXTENT_ITEM);
if (is_tree) eisize += sizeof(EXTENT_ITEM2);
if (is_tree && !(Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)) eisize += sizeof(EXTENT_ITEM2);
eisize += sizeof(UINT8);
eisize += datalen;
@ -590,7 +590,6 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount += rc;
sectedr2 = (EXTENT_DATA_REF*)((UINT8*)newei + ((UINT8*)sectedr - tp.item->data));
@ -635,7 +634,6 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount += rc;
sectsdr2 = (SHARED_DATA_REF*)((UINT8*)newei + ((UINT8*)sectsdr - tp.item->data));
@ -697,7 +695,6 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
newei = ExAllocatePoolWithTag(PagedPool, tp.item->size + sizeof(UINT8) + datalen, ALLOC_TAG);
RtlCopyMemory(newei, tp.item->data, ptr - tp.item->data);
newei->generation = Vcb->superblock.generation;
newei->refcount += get_extent_data_refcount(type, data);
if (len > 0)
@ -733,9 +730,9 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
return Status;
}
if (!keycmp(tp.item->key, searchkey)) {
if (tp.item->size < datalen) {
ERR("(%llx,%x,%llx) was %x bytes, expecting %x\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, tp.item->size, datalen);
if (!keycmp(tp2.item->key, searchkey)) {
if (tp2.item->size < datalen) {
ERR("(%llx,%x,%llx) was %x bytes, expecting %x\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, tp2.item->size, datalen);
return STATUS_INTERNAL_ERROR;
}
@ -770,7 +767,6 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
newei = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount += get_extent_data_refcount(type, data);
delete_tree_item(Vcb, &tp, rollback);
@ -797,7 +793,6 @@ NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
newei = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount += get_extent_data_refcount(type, data);
delete_tree_item(Vcb, &tp, rollback);
@ -828,7 +823,7 @@ void decrease_chunk_usage(chunk* c, UINT64 delta) {
}
NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem,
UINT8 level, UINT64 parent, PIRP Irp, LIST_ENTRY* rollback) {
UINT8 level, UINT64 parent, BOOL superseded, PIRP Irp, LIST_ENTRY* rollback) {
KEY searchkey;
NTSTATUS Status;
traverse_ptr tp, tp2;
@ -884,7 +879,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
return Status;
}
return decrease_extent_refcount(Vcb, address, size, type, data, firstitem, level, parent, Irp, rollback);
return decrease_extent_refcount(Vcb, address, size, type, data, firstitem, level, parent, superseded, Irp, rollback);
}
}
@ -944,6 +939,10 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
if (sectedr->root == edr->root && sectedr->objid == edr->objid && sectedr->offset == edr->offset) {
if (ei->refcount == edr->count) {
delete_tree_item(Vcb, &tp, rollback);
if (!superseded)
add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
return STATUS_SUCCESS;
}
@ -976,7 +975,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
}
newei->generation = Vcb->superblock.generation;
newei->refcount -= rc;
delete_tree_item(Vcb, &tp, rollback);
@ -995,14 +993,24 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
EXTENT_ITEM* newei;
if (sectsdr->offset == sdr->offset) {
// We ignore sdr->count, and assume that we want to remove the whole bit
if (ei->refcount == sectsdr->count) {
delete_tree_item(Vcb, &tp, rollback);
if (!superseded)
add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
return STATUS_SUCCESS;
}
neweilen = tp.item->size - sizeof(UINT8) - sectlen;
if (sectsdr->count < sdr->count) {
ERR("error - SHARED_DATA_REF has refcount %x, trying to reduce by %x\n", sectsdr->count, sdr->count);
return STATUS_INTERNAL_ERROR;
}
if (sectsdr->count > sdr->count) // reduce section refcount
neweilen = tp.item->size;
else // remove section entirely
neweilen = tp.item->size - sizeof(UINT8) - sectlen;
newei = ExAllocatePoolWithTag(PagedPool, neweilen, ALLOC_TAG);
if (!newei) {
@ -1010,12 +1018,19 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(newei, ei, ptr - tp.item->data);
if (len > sectlen)
RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
newei->generation = Vcb->superblock.generation;
if (sectsdr->count > sdr->count) {
SHARED_DATA_REF* newsdr = (SHARED_DATA_REF*)((UINT8*)newei + ((UINT8*)sectsdr - tp.item->data));
RtlCopyMemory(newei, ei, neweilen);
newsdr->count -= rc;
} else {
RtlCopyMemory(newei, ei, ptr - tp.item->data);
if (len > sectlen)
RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
}
newei->refcount -= rc;
delete_tree_item(Vcb, &tp, rollback);
@ -1052,7 +1067,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
if (len > sectlen)
RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
newei->generation = Vcb->superblock.generation;
newei->refcount--;
delete_tree_item(Vcb, &tp, rollback);
@ -1089,7 +1103,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
if (len > sectlen)
RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data), ptr + sectlen + sizeof(UINT8), len - sectlen);
newei->generation = Vcb->superblock.generation;
newei->refcount--;
delete_tree_item(Vcb, &tp, rollback);
@ -1146,6 +1159,10 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
if (ei->refcount == edr->count) {
delete_tree_item(Vcb, &tp, rollback);
delete_tree_item(Vcb, &tp2, rollback);
if (!superseded)
add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
return STATUS_SUCCESS;
}
@ -1182,7 +1199,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount -= rc;
delete_tree_item(Vcb, &tp, rollback);
@ -1203,16 +1219,41 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
EXTENT_ITEM* newei;
if (sectsdr->offset == sdr->offset) {
// As above, we assume that we want to remove the whole shared data ref
if (ei->refcount == sectsdr->count) {
if (ei->refcount == sdr->count) {
delete_tree_item(Vcb, &tp, rollback);
delete_tree_item(Vcb, &tp2, rollback);
if (!superseded)
add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
return STATUS_SUCCESS;
}
if (sectsdr->count < sdr->count) {
ERR("error - extent section has refcount %x, trying to reduce by %x\n", sectsdr->count, sdr->count);
return STATUS_INTERNAL_ERROR;
}
delete_tree_item(Vcb, &tp2, rollback);
if (sectsdr->count > sdr->count) {
SHARED_DATA_REF* newsdr = ExAllocatePoolWithTag(PagedPool, tp2.item->size, ALLOC_TAG);
if (!newsdr) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(newsdr, sectsdr, tp2.item->size);
newsdr->count -= sdr->count;
if (!insert_tree_item(Vcb, Vcb->extent_root, tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, newsdr, tp2.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
}
newei = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
if (!newei) {
ERR("out of memory\n");
@ -1221,7 +1262,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount -= rc;
delete_tree_item(Vcb, &tp, rollback);
@ -1258,7 +1298,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount -= rc;
delete_tree_item(Vcb, &tp, rollback);
@ -1295,7 +1334,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount -= rc;
delete_tree_item(Vcb, &tp, rollback);
@ -1317,6 +1355,10 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
if (ei->refcount == erv0->count) {
delete_tree_item(Vcb, &tp, rollback);
delete_tree_item(Vcb, &tp2, rollback);
if (!superseded)
add_checksum_entry(Vcb, address, size / Vcb->superblock.sector_size, NULL, Irp, rollback);
return STATUS_SUCCESS;
}
@ -1330,7 +1372,6 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
RtlCopyMemory(newei, tp.item->data, tp.item->size);
newei->generation = Vcb->superblock.generation;
newei->refcount -= rc;
delete_tree_item(Vcb, &tp, rollback);
@ -1348,7 +1389,7 @@ NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64
}
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode,
UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback) {
UINT64 offset, UINT32 refcount, BOOL superseded, PIRP Irp, LIST_ENTRY* rollback) {
EXTENT_DATA_REF edr;
edr.root = root;
@ -1356,7 +1397,7 @@ NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UI
edr.offset = offset;
edr.count = refcount;
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, 0, Irp, rollback);
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, 0, superseded, Irp, rollback);
}
NTSTATUS decrease_extent_refcount_tree(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root,
@ -1365,7 +1406,7 @@ NTSTATUS decrease_extent_refcount_tree(device_extension* Vcb, UINT64 address, UI
tbr.offset = root;
return decrease_extent_refcount(Vcb, address, size, TYPE_TREE_BLOCK_REF, &tbr, NULL/*FIXME*/, level, 0, Irp, rollback);
return decrease_extent_refcount(Vcb, address, size, TYPE_TREE_BLOCK_REF, &tbr, NULL/*FIXME*/, level, 0, FALSE, Irp, rollback);
}
static UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, PIRP Irp) {

View file

@ -265,26 +265,35 @@ static NTSTATUS STDCALL fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDE
return STATUS_SUCCESS;
}
#ifdef DEBUG
static BOOLEAN STDCALL fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p (%.*S), %llx, %x, %x, %x, %p, %p, %p)\n", FileObject, FileObject->FileName.Length / sizeof(WCHAR), FileObject->FileName.Buffer,
*FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
if (FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject)) {
fcb* fcb = FileObject->FsContext;
fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart;
return TRUE;
}
return FALSE;
}
#ifdef _DEBUG
static BOOLEAN STDCALL fast_io_read(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %x, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
return FsRtlCopyRead(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %x, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
return FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_mdl_read(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PMDL* MdlChain, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
return FsRtlMdlReadDev(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_mdl_read_complete(PFILE_OBJECT FileObject, PMDL* MdlChain, PDEVICE_OBJECT DeviceObject) {
static BOOLEAN STDCALL fast_io_mdl_read_complete(PFILE_OBJECT FileObject, PMDL MdlChain, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %p)\n", FileObject, MdlChain, DeviceObject);
return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject);
@ -296,7 +305,7 @@ static BOOLEAN STDCALL fast_io_prepare_mdl_write(PFILE_OBJECT FileObject, PLARGE
return FsRtlPrepareMdlWriteDev(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject);
}
static BOOLEAN STDCALL fast_io_mdl_write_complete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL* MdlChain, PDEVICE_OBJECT DeviceObject) {
static BOOLEAN STDCALL fast_io_mdl_write_complete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain, PDEVICE_OBJECT DeviceObject) {
TRACE("(%p, %p, %p, %p)\n", FileObject, FileOffset, MdlChain, DeviceObject);
return FsRtlMdlWriteCompleteDev(FileObject, FileOffset, MdlChain, DeviceObject);
@ -329,17 +338,16 @@ void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
FastIoDispatch.ReleaseForModWrite = fast_io_release_for_mod_write;
FastIoDispatch.AcquireForCcFlush = fast_io_acquire_for_ccflush;
FastIoDispatch.ReleaseForCcFlush = fast_io_release_for_ccflush;
#ifdef DEBUG
FastIoDispatch.FastIoRead = fast_io_read;
FastIoDispatch.FastIoWrite = fast_io_write;
#ifdef _DEBUG
FastIoDispatch.FastIoRead = fast_io_read;
FastIoDispatch.MdlRead = fast_io_mdl_read;
FastIoDispatch.MdlReadComplete = fast_io_mdl_read_complete;
FastIoDispatch.PrepareMdlWrite = fast_io_prepare_mdl_write;
FastIoDispatch.MdlWriteComplete = fast_io_mdl_write_complete;
#else
FastIoDispatch.FastIoRead = FsRtlCopyRead;
FastIoDispatch.FastIoWrite = FsRtlCopyWrite;
FastIoDispatch.MdlRead = FsRtlMdlReadDev;
FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -88,10 +88,8 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY* batchlist, PI
Status = remove_free_space_inode(Vcb, fsi->key.obj_id, batchlist, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
if (!NT_SUCCESS(Status))
ERR("remove_free_space_inode for (%llx,%x,%llx) returned %08x\n", fsi->key.obj_id, fsi->key.obj_type, fsi->key.offset, Status);
goto end;
}
le = Vcb->chunks.Flink;
while (le != &Vcb->chunks) {
@ -116,7 +114,6 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY* batchlist, PI
Status = STATUS_SUCCESS;
end:
if (NT_SUCCESS(Status))
clear_rollback(Vcb, &rollback);
else
@ -251,30 +248,44 @@ typedef struct {
LIST_ENTRY list_entry;
} superblock_stripe;
static void add_superblock_stripe(LIST_ENTRY* stripes, UINT64 off, UINT64 len) {
static NTSTATUS add_superblock_stripe(LIST_ENTRY* stripes, UINT64 off, UINT64 len) {
UINT64 i;
for (i = 0; i < len; i++) {
LIST_ENTRY* le;
superblock_stripe* ss;
BOOL ignore = FALSE;
le = stripes->Flink;
while (le != stripes) {
ss = CONTAINING_RECORD(le, superblock_stripe, list_entry);
if (ss->stripe == off + i)
continue;
if (ss->stripe == off + i) {
ignore = TRUE;
break;
}
le = le->Flink;
}
if (ignore)
continue;
ss = ExAllocatePoolWithTag(PagedPool, sizeof(superblock_stripe), ALLOC_TAG);
if (!ss) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
ss->stripe = off + i;
InsertTailList(stripes, &ss->list_entry);
}
return STATUS_SUCCESS;
}
static UINT64 get_superblock_size(chunk* c) {
static NTSTATUS get_superblock_size(chunk* c, UINT64* size) {
NTSTATUS Status;
CHUNK_ITEM* ci = c->chunk_item;
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1];
UINT64 off_start, off_end, space;
@ -296,7 +307,11 @@ static UINT64 get_superblock_size(chunk* c) {
off_end = off_start + ci->stripe_length;
add_superblock_stripe(&stripes, off_start / ci->stripe_length, 1);
Status = add_superblock_stripe(&stripes, off_start / ci->stripe_length, 1);
if (!NT_SUCCESS(Status)) {
ERR("add_superblock_stripe returned %08x\n", Status);
goto end;
}
}
}
} else if (ci->type & BLOCK_FLAG_RAID5) {
@ -310,7 +325,11 @@ static UINT64 get_superblock_size(chunk* c) {
off_end = off_start + (ci->stripe_length * (ci->num_stripes - 1));
add_superblock_stripe(&stripes, off_start / ci->stripe_length, (off_end - off_start) / ci->stripe_length);
Status = add_superblock_stripe(&stripes, off_start / ci->stripe_length, (off_end - off_start) / ci->stripe_length);
if (!NT_SUCCESS(Status)) {
ERR("add_superblock_stripe returned %08x\n", Status);
goto end;
}
}
}
} else if (ci->type & BLOCK_FLAG_RAID6) {
@ -324,7 +343,11 @@ static UINT64 get_superblock_size(chunk* c) {
off_end = off_start + (ci->stripe_length * (ci->num_stripes - 2));
add_superblock_stripe(&stripes, off_start / ci->stripe_length, (off_end - off_start) / ci->stripe_length);
Status = add_superblock_stripe(&stripes, off_start / ci->stripe_length, (off_end - off_start) / ci->stripe_length);
if (!NT_SUCCESS(Status)) {
ERR("add_superblock_stripe returned %08x\n", Status);
goto end;
}
}
}
} else { // SINGLE, DUPLICATE, RAID1
@ -333,7 +356,11 @@ static UINT64 get_superblock_size(chunk* c) {
off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length;
off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length);
add_superblock_stripe(&stripes, off_start / ci->stripe_length, (off_end - off_start) / ci->stripe_length);
Status = add_superblock_stripe(&stripes, off_start / ci->stripe_length, (off_end - off_start) / ci->stripe_length);
if (!NT_SUCCESS(Status)) {
ERR("add_superblock_stripe returned %08x\n", Status);
goto end;
}
}
}
}
@ -343,6 +370,9 @@ static UINT64 get_superblock_size(chunk* c) {
space = 0;
Status = STATUS_SUCCESS;
end:
while (!IsListEmpty(&stripes)) {
LIST_ENTRY* le = RemoveHeadList(&stripes);
superblock_stripe* ss = CONTAINING_RECORD(le, superblock_stripe, list_entry);
@ -352,7 +382,10 @@ static UINT64 get_superblock_size(chunk* c) {
ExFreePool(ss);
}
return space * ci->stripe_length;
if (NT_SUCCESS(Status))
*size = space * ci->stripe_length;
return Status;
}
static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, PIRP Irp) {
@ -368,7 +401,6 @@ static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, PI
LIST_ENTRY *le, rollback;
// FIXME - does this break if Vcb->superblock.sector_size is not 4096?
// FIXME - remove INODE_ITEM etc. if cache invalid for whatever reason
TRACE("(%p, %llx)\n", Vcb, c->offset);
@ -432,7 +464,7 @@ static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, PI
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = read_file(c->cache, data, 0, c->cache->inode_item.st_size, NULL, NULL);
Status = read_file(c->cache, data, 0, c->cache->inode_item.st_size, NULL, NULL, FALSE);
if (!NT_SUCCESS(Status)) {
ERR("read_file returned %08x\n", Status);
ExFreePool(data);
@ -529,7 +561,13 @@ static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, PI
// do sanity check
superblock_size = get_superblock_size(c);
Status = get_superblock_size(c, &superblock_size);
if (!NT_SUCCESS(Status)) {
ERR("get_superblock_size returned %08x\n", Status);
ExFreePool(data);
return Status;
}
if (c->chunk_item->size - c->used != total_space + superblock_size) {
WARN("invalidating cache for chunk %llx: space was %llx, expected %llx\n", c->offset, total_space + superblock_size, c->chunk_item->size - c->used);
goto clearcache;
@ -569,6 +607,8 @@ clearcache:
InitializeListHead(&rollback);
delete_tree_item(Vcb, &tp, &rollback);
Status = excise_extents(Vcb, c->cache, 0, c->cache->inode_item.st_size, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("excise_extents returned %08x\n", Status);
@ -696,11 +736,11 @@ static NTSTATUS insert_cache_extent(fcb* fcb, UINT64 start, UINT64 length, LIST_
while (le != &fcb->Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly) {
if (!c->readonly && !c->reloc) {
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length)) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length)) {
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
return STATUS_SUCCESS;
}
@ -722,7 +762,7 @@ static NTSTATUS insert_cache_extent(fcb* fcb, UINT64 start, UINT64 length, LIST_
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length))
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length))
return STATUS_SUCCESS;
}
@ -740,6 +780,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
NTSTATUS Status;
UINT64 num_entries, new_cache_size, i;
UINT32 num_sectors;
BOOL realloc_extents = FALSE;
// FIXME - also do bitmaps
// FIXME - make sure this works when sector_size is not 4096
@ -788,6 +829,33 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
TRACE("chunk %llx: cache_size = %llx, new_cache_size = %llx\n", c->offset, c->cache ? c->cache->inode_item.st_size : 0, new_cache_size);
if (c->cache) {
if (new_cache_size > c->cache->inode_item.st_size)
realloc_extents = TRUE;
else {
le = c->cache->extents.Flink;
while (le != &c->cache->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (!ext->ignore && (ext->data->type == EXTENT_TYPE_REGULAR || ext->data->type == EXTENT_TYPE_PREALLOC)) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->data->data[0];
if (ed2->size != 0) {
chunk* c2 = get_chunk_from_address(Vcb, ed2->address);
if (c2 && (c2->readonly || c2->reloc)) {
realloc_extents = TRUE;
break;
}
}
}
le = le->Flink;
}
}
}
if (!c->cache) {
FREE_SPACE_ITEM* fsi;
KEY searchkey;
@ -869,19 +937,17 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
}
c->cache->extents_changed = TRUE;
InsertTailList(&Vcb->all_fcbs, &c->cache->list_entry_all);
flush_fcb(c->cache, TRUE, batchlist, Irp, rollback);
*changed = TRUE;
} else if (new_cache_size > c->cache->inode_item.st_size) {
} else if (realloc_extents) {
KEY searchkey;
traverse_ptr tp;
ERR("extending existing inode\n");
TRACE("reallocating extents\n");
// FIXME - try to extend existing extent first of all
// Or ditch all existing extents and replace with one new one?
// add free_space entry to tree cache
searchkey.obj_id = FREE_SPACE_CACHE_ID;
@ -906,9 +972,38 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
tp.tree->write = TRUE;
// remove existing extents
if (c->cache->inode_item.st_size > 0) {
le = c->cache->extents.Flink;
while (le != &c->cache->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (!ext->ignore && (ext->data->type == EXTENT_TYPE_REGULAR || ext->data->type == EXTENT_TYPE_PREALLOC)) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->data->data[0];
if (ed2->size != 0) {
chunk* c2 = get_chunk_from_address(Vcb, ed2->address);
if (!c2->list_entry_changed.Flink)
InsertTailList(&Vcb->chunks_changed, &c2->list_entry_changed);
}
}
le = le->Flink;
}
Status = excise_extents(Vcb, c->cache, 0, c->cache->inode_item.st_size, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("excise_extents returned %08x\n", Status);
return Status;
}
}
// add new extent
Status = insert_cache_extent(c->cache, c->cache->inode_item.st_size, new_cache_size - c->cache->inode_item.st_size, rollback);
Status = insert_cache_extent(c->cache, 0, new_cache_size, rollback);
if (!NT_SUCCESS(Status)) {
ERR("insert_cache_extent returned %08x\n", Status);
return Status;
@ -1372,7 +1467,7 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
// write cache
Status = do_write_file(c->cache, 0, c->cache->inode_item.st_size, data, NULL, NULL, rollback);
Status = do_write_file(c->cache, 0, c->cache->inode_item.st_size, data, NULL, rollback);
if (!NT_SUCCESS(Status)) {
ERR("do_write_file returned %08x\n", Status);
return Status;

File diff suppressed because it is too large Load diff

View file

@ -24,6 +24,7 @@ typedef struct {
PIRP Irp;
IO_STATUS_BLOCK iosb;
NTSTATUS Status;
device* dev;
} pnp_stripe;
typedef struct {
@ -51,6 +52,7 @@ static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
pnp_context* context;
UINT64 num_devices, i;
NTSTATUS Status;
LIST_ENTRY* le;
context = ExAllocatePoolWithTag(NonPagedPool, sizeof(pnp_context), ALLOC_TAG);
if (!context) {
@ -58,6 +60,8 @@ static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
return STATUS_INSUFFICIENT_RESOURCES;
}
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
RtlZeroMemory(context, sizeof(pnp_context));
KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
@ -67,18 +71,23 @@ static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
if (!context->stripes) {
ERR("out of memory\n");
ExFreePool(context);
return STATUS_INSUFFICIENT_RESOURCES;
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end2;
}
RtlZeroMemory(context->stripes, sizeof(pnp_stripe) * num_devices);
for (i = 0; i < num_devices; i++) {
i = 0;
le = Vcb->devices.Flink;
while (le != &Vcb->devices) {
PIO_STACK_LOCATION IrpSp;
device* dev = CONTAINING_RECORD(le, device, list_entry);
if (Vcb->devices[i].devobj) {
if (dev->devobj) {
context->stripes[i].context = (struct pnp_context*)context;
context->stripes[i].Irp = IoAllocateIrp(Vcb->devices[i].devobj->StackSize, FALSE);
context->stripes[i].Irp = IoAllocateIrp(dev->devobj->StackSize, FALSE);
if (!context->stripes[i].Irp) {
UINT64 j;
@ -86,14 +95,15 @@ static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
ERR("IoAllocateIrp failed\n");
for (j = 0; j < i; j++) {
if (Vcb->devices[j].devobj) {
if (context->stripes[j].dev->devobj) {
IoFreeIrp(context->stripes[j].Irp);
}
}
ExFreePool(context->stripes);
ExFreePool(context);
return STATUS_INSUFFICIENT_RESOURCES;
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end2;
}
IrpSp = IoGetNextIrpStackLocation(context->stripes[i].Irp);
@ -105,9 +115,12 @@ static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
IoSetCompletionRoutine(context->stripes[i].Irp, pnp_completion, &context->stripes[i], TRUE, TRUE, TRUE);
context->stripes[i].Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
context->stripes[i].dev = dev;
context->left++;
}
le = le->Flink;
}
if (context->left == 0) {
@ -117,7 +130,7 @@ static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
for (i = 0; i < num_devices; i++) {
if (context->stripes[i].Irp) {
IoCallDriver(Vcb->devices[i].devobj, context->stripes[i].Irp);
IoCallDriver(context->stripes[i].dev->devobj, context->stripes[i].Irp);
}
}
@ -141,6 +154,9 @@ end:
ExFreePool(context->stripes);
ExFreePool(context);
end2:
ExReleaseResourceLite(&Vcb->tree_lock);
return Status;
}
@ -296,7 +312,7 @@ NTSTATUS STDCALL drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
TRACE("passing minor function 0x%x on\n", IrpSp->MinorFunction);
IoSkipCurrentIrpStackLocation(Irp);
Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp);
goto end;
}
@ -305,7 +321,7 @@ NTSTATUS STDCALL drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
//
// IoSkipCurrentIrpStackLocation(Irp);
//
// Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
// Status = IoCallDriver(first_device(Vcb)->devobj, Irp);
//
// // IoCompleteRequest(Irp, IO_NO_INCREMENT);

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
BTRFS_UUID* uuid = &Vcb->superblock.uuid;
mount_options* options = &Vcb->options;
UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus,
maxinlineus, subvolidus, raid5recalcus, raid6recalcus;
maxinlineus, subvolidus, raid5recalcus, raid6recalcus, skipbalanceus;
OBJECT_ATTRIBUTES oa;
NTSTATUS Status;
ULONG i, j, kvfilen, index, retlen;
@ -43,6 +43,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
options->max_inline = min(mount_max_inline, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
options->raid5_recalculation = mount_raid5_recalculation;
options->raid6_recalculation = mount_raid6_recalculation;
options->skip_balance = mount_skip_balance;
options->subvol_id = 0;
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
@ -103,6 +104,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
RtlInitUnicodeString(&subvolidus, L"SubvolId");
RtlInitUnicodeString(&raid5recalcus, L"Raid5Recalculation");
RtlInitUnicodeString(&raid6recalcus, L"Raid6Recalculation");
RtlInitUnicodeString(&skipbalanceus, L"SkipBalance");
do {
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
@ -159,6 +161,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->raid6_recalculation = *val;
} else if (FsRtlAreNamesEqual(&skipbalanceus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->skip_balance = *val;
}
} else if (Status != STATUS_NO_MORE_ENTRIES) {
ERR("ZwEnumerateValueKey returned %08x\n", Status);
@ -655,6 +661,7 @@ void STDCALL read_registry(PUNICODE_STRING regpath) {
get_registry_value(h, L"MaxInline", REG_DWORD, &mount_max_inline, sizeof(mount_max_inline));
get_registry_value(h, L"Raid5Recalculation", REG_DWORD, &mount_raid5_recalculation, sizeof(mount_raid5_recalculation));
get_registry_value(h, L"Raid6Recalculation", REG_DWORD, &mount_raid6_recalculation, sizeof(mount_raid6_recalculation));
get_registry_value(h, L"SkipBalance", REG_DWORD, &mount_skip_balance, sizeof(mount_skip_balance));
if (mount_flush_interval == 0)
mount_flush_interval = 1;

View file

@ -56,7 +56,7 @@ NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
}
TRACE("data = %p, size = %x\n", data, fcb->inode_item.st_size);
Status = read_file(fcb, (UINT8*)data, 0, fcb->inode_item.st_size, NULL, NULL);
Status = read_file(fcb, (UINT8*)data, 0, fcb->inode_item.st_size, NULL, NULL, TRUE);
if (!NT_SUCCESS(Status)) {
ERR("read_file returned %08x\n", Status);
@ -119,7 +119,7 @@ NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
if (fcb->type == BTRFS_TYPE_FILE) {
ULONG len;
Status = read_file(fcb, buffer, 0, buflen, &len, NULL);
Status = read_file(fcb, buffer, 0, buflen, &len, NULL, TRUE);
if (!NT_SUCCESS(Status)) {
ERR("read_file returned %08x\n", Status);
@ -177,6 +177,9 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb, REPARSE_DATA_
fileref->fcb->inode_item.st_mode |= __S_IFLNK;
if (fileref->dc)
fileref->dc->type = fileref->fcb->type;
if (write) {
Status = truncate_file(fileref->fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
@ -485,6 +488,9 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
fileref->fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT;
if (fileref->dc)
fileref->dc->type = fileref->fcb->type;
mark_fileref_dirty(fileref);
fileref->fcb->inode_item_changed = TRUE;

View file

@ -30,47 +30,28 @@
#endif
#include <wdmguid.h>
#ifndef __REACTOS__
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#endif
extern LIST_ENTRY volumes;
extern ERESOURCE volumes_lock;
extern LIST_ENTRY pnp_disks;
#if !defined (_GNU_NTIFS_) || defined(__REACTOS__)
NTSTATUS WINAPI ZwQueryDirectoryObject(HANDLE DirectoryHandle, PVOID Buffer, ULONG Length,
BOOLEAN ReturnSingleEntry, BOOLEAN RestartScan, PULONG Context,
PULONG ReturnLength);
#endif
VOID WINAPI IopNotifyPlugPlayNotification(
IN PDEVICE_OBJECT DeviceObject,
IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
IN LPCGUID Event,
IN PVOID EventCategoryData1,
IN PVOID EventCategoryData2
);
static const WCHAR devpath[] = {'\\','D','e','v','i','c','e',0};
static NTSTATUS create_part0(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject, PUNICODE_STRING pardir, PUNICODE_STRING nameus,
BTRFS_UUID* uuid) {
static NTSTATUS create_part0(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject, PUNICODE_STRING devpath,
PUNICODE_STRING nameus, BTRFS_UUID* uuid) {
PDEVICE_OBJECT newdevobj;
UNICODE_STRING name;
NTSTATUS Status;
part0_device_extension* p0de;
static const WCHAR btrfs_partition[] = L"\\BtrfsPartition";
static const WCHAR part0_suffix[] = L"Btrfs";
name.Length = name.MaximumLength = pardir->Length + (wcslen(btrfs_partition) * sizeof(WCHAR));
name.Length = name.MaximumLength = devpath->Length + (wcslen(part0_suffix) * sizeof(WCHAR));
name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG);
if (!name.Buffer) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(name.Buffer, pardir->Buffer, pardir->Length);
RtlCopyMemory(&name.Buffer[pardir->Length / sizeof(WCHAR)], btrfs_partition, wcslen(btrfs_partition) * sizeof(WCHAR));
RtlCopyMemory(name.Buffer, devpath->Buffer, devpath->Length);
RtlCopyMemory(&name.Buffer[devpath->Length / sizeof(WCHAR)], part0_suffix, wcslen(part0_suffix) * sizeof(WCHAR));
Status = IoCreateDevice(DriverObject, sizeof(part0_device_extension), &name, FILE_DEVICE_DISK, FILE_DEVICE_SECURE_OPEN, FALSE, &newdevobj);
if (!NT_SUCCESS(Status)) {
@ -101,6 +82,7 @@ static NTSTATUS create_part0(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceO
ObReferenceObject(DeviceObject);
newdevobj->StackSize = DeviceObject->StackSize + 1;
newdevobj->SectorSize = DeviceObject->SectorSize;
newdevobj->Flags |= DO_DIRECT_IO;
newdevobj->Flags &= ~DO_DEVICE_INITIALIZING;
@ -110,7 +92,7 @@ static NTSTATUS create_part0(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceO
return STATUS_SUCCESS;
}
static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
void add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
ULONG tnsize;
MOUNTMGR_TARGET_NAME* tn;
KEVENT Event;
@ -156,7 +138,7 @@ static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
ExFreePool(tn);
mmdltsize = sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) - 1 + us->Length;
mmdltsize = offsetof(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName[0]) + us->Length;
mmdlt = ExAllocatePoolWithTag(NonPagedPool, mmdltsize, ALLOC_TAG);
if (!mmdlt) {
@ -191,7 +173,7 @@ static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
ExFreePool(mmdlt);
}
static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmgr, PUNICODE_STRING pardir, PUNICODE_STRING us, BOOL part0, LIST_ENTRY* volumes) {
static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath, DWORD disk_num, DWORD part_num, LIST_ENTRY* volumes) {
KEVENT Event;
PIRP Irp;
IO_STATUS_BLOCK IoStatusBlock;
@ -200,31 +182,15 @@ static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmg
PDEVICE_OBJECT DeviceObject;
LARGE_INTEGER Offset;
ULONG toread;
UINT8* data;
UNICODE_STRING us2;
BOOL added_entry = FALSE;
UINT8* data = NULL;
UINT32 sector_size;
TRACE("%.*S\n", us->Length / sizeof(WCHAR), us->Buffer);
TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
us2.Length = pardir->Length + sizeof(WCHAR) + us->Length;
us2.MaximumLength = us2.Length;
us2.Buffer = ExAllocatePoolWithTag(PagedPool, us2.Length, ALLOC_TAG);
if (!us2.Buffer) {
ERR("out of memory\n");
return;
}
RtlCopyMemory(us2.Buffer, pardir->Buffer, pardir->Length);
us2.Buffer[pardir->Length / sizeof(WCHAR)] = '\\';
RtlCopyMemory(&us2.Buffer[(pardir->Length / sizeof(WCHAR))+1], us->Buffer, us->Length);
TRACE("%.*S\n", us2.Length / sizeof(WCHAR), us2.Buffer);
Status = IoGetDeviceObjectPointer(&us2, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
if (!NT_SUCCESS(Status)) {
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
goto exit;
return;
}
sector_size = DeviceObject->SectorSize;
@ -238,20 +204,20 @@ static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmg
if (!NT_SUCCESS(Status)) {
ERR("%.*S had a sector size of 0, and IOCTL_DISK_GET_DRIVE_GEOMETRY returned %08x\n",
us2.Length / sizeof(WCHAR), us2.Buffer, Status);
goto exit;
devpath->Length / sizeof(WCHAR), devpath->Buffer, Status);
goto deref;
}
if (iosb.Information < sizeof(DISK_GEOMETRY)) {
ERR("%.*S: IOCTL_DISK_GET_DRIVE_GEOMETRY returned %u bytes, expected %u\n",
us2.Length / sizeof(WCHAR), us2.Buffer, iosb.Information, sizeof(DISK_GEOMETRY));
devpath->Length / sizeof(WCHAR), devpath->Buffer, iosb.Information, sizeof(DISK_GEOMETRY));
}
sector_size = geometry.BytesPerSector;
if (sector_size == 0) {
ERR("%.*S had a sector size of 0\n", us2.Length / sizeof(WCHAR), us2.Buffer);
goto exit;
ERR("%.*S had a sector size of 0\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
goto deref;
}
}
@ -295,33 +261,49 @@ static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmg
&gli, sizeof(gli), TRUE, NULL);
if (!NT_SUCCESS(Status)) {
ERR("error reading length information: %08x\n", Status);
ExFreePool(v);
goto deref;
}
if (part0) {
if (part_num == 0) {
UNICODE_STRING us3;
Status = create_part0(DriverObject, DeviceObject, pardir, &us3, &sb->dev_item.device_uuid);
Status = create_part0(DriverObject, DeviceObject, devpath, &us3, &sb->dev_item.device_uuid);
if (!NT_SUCCESS(Status)) {
ERR("create_part0 returned %08x\n", Status);
ExFreePool(v);
goto deref;
}
ExFreePool(us2.Buffer);
us2 = us3;
v->devpath = us3;
} else {
v->devpath.Length = v->devpath.MaximumLength = devpath->Length;
v->devpath.Buffer = ExAllocatePoolWithTag(PagedPool, v->devpath.Length, ALLOC_TAG);
if (!v->devpath.Buffer) {
ERR("out of memory\n");
ExFreePool(v);
goto deref;
}
RtlCopyMemory(v->devpath.Buffer, devpath->Buffer, v->devpath.Length);
}
RtlCopyMemory(&v->fsuuid, &sb->uuid, sizeof(BTRFS_UUID));
RtlCopyMemory(&v->devuuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID));
v->devnum = sb->dev_item.dev_id;
v->devpath = us2;
v->processed = FALSE;
v->length = gli.Length.QuadPart;
v->gen1 = sb->generation;
v->gen2 = 0;
v->seeding = sb->flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE;
v->disk_num = disk_num;
v->part_num = part_num;
ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
InsertTailList(volumes, &v->list_entry);
ExReleaseResourceLite(&volumes_lock);
i = 1;
while (superblock_addrs[i] != 0 && superblock_addrs[i] + toread <= v->length) {
@ -368,120 +350,16 @@ static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmg
v->devuuid.uuid[0], v->devuuid.uuid[1], v->devuuid.uuid[2], v->devuuid.uuid[3], v->devuuid.uuid[4], v->devuuid.uuid[5], v->devuuid.uuid[6], v->devuuid.uuid[7],
v->devuuid.uuid[8], v->devuuid.uuid[9], v->devuuid.uuid[10], v->devuuid.uuid[11], v->devuuid.uuid[12], v->devuuid.uuid[13], v->devuuid.uuid[14], v->devuuid.uuid[15]);
TRACE("device number %llx\n", v->devnum);
added_entry = TRUE;
}
deref:
ExFreePool(data);
if (data)
ExFreePool(data);
ObDereferenceObject(FileObject);
exit:
if (!added_entry)
ExFreePool(us2.Buffer);
}
static NTSTATUS look_in_harddisk_dir(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmgr, PUNICODE_STRING name, LIST_ENTRY* volumes) {
UNICODE_STRING path;
OBJECT_ATTRIBUTES attr;
NTSTATUS Status;
HANDLE h;
OBJECT_DIRECTORY_INFORMATION* odi;
ULONG odisize, context;
BOOL restart, has_part0 = FALSE, has_parts = FALSE;
static const WCHAR partition[] = L"Partition";
static WCHAR partition0[] = L"Partition0";
path.Buffer = ExAllocatePoolWithTag(PagedPool, ((wcslen(devpath) + 1) * sizeof(WCHAR)) + name->Length, ALLOC_TAG);
if (!path.Buffer) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(path.Buffer, devpath, wcslen(devpath) * sizeof(WCHAR));
path.Buffer[wcslen(devpath)] = '\\';
RtlCopyMemory(&path.Buffer[wcslen(devpath) + 1], name->Buffer, name->Length);
path.Length = path.MaximumLength = ((wcslen(devpath) + 1) * sizeof(WCHAR)) + name->Length;
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.Attributes = OBJ_CASE_INSENSITIVE;
attr.ObjectName = &path;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
Status = ZwOpenDirectoryObject(&h, DIRECTORY_TRAVERSE, &attr);
if (!NT_SUCCESS(Status)) {
ERR("ZwOpenDirectoryObject returned %08x\n", Status);
goto end;
}
odisize = sizeof(OBJECT_DIRECTORY_INFORMATION) * 16;
odi = ExAllocatePoolWithTag(PagedPool, odisize, ALLOC_TAG);
if (!odi) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
ZwClose(h);
goto end;
}
restart = TRUE;
do {
Status = ZwQueryDirectoryObject(h, odi, odisize, FALSE, restart, &context, NULL/*&retlen*/);
restart = FALSE;
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_NO_MORE_ENTRIES)
ERR("ZwQueryDirectoryObject returned %08x\n", Status);
} else {
OBJECT_DIRECTORY_INFORMATION* odi2 = odi;
while (odi2->Name.Buffer) {
TRACE("%.*S, %.*S\n", odi2->TypeName.Length / sizeof(WCHAR), odi2->TypeName.Buffer, odi2->Name.Length / sizeof(WCHAR), odi2->Name.Buffer);
if (odi2->Name.Length > wcslen(partition) * sizeof(WCHAR) &&
RtlCompareMemory(odi2->Name.Buffer, partition, wcslen(partition) * sizeof(WCHAR)) == wcslen(partition) * sizeof(WCHAR)) {
if (odi2->Name.Length == (wcslen(partition) + 1) * sizeof(WCHAR) && odi2->Name.Buffer[(odi2->Name.Length / sizeof(WCHAR)) - 1] == '0') {
// Partition0 refers to the whole disk
has_part0 = TRUE;
} else {
has_parts = TRUE;
test_vol(DriverObject, mountmgr, &path, &odi2->Name, FALSE, volumes);
}
}
odi2 = &odi2[1];
}
}
} while (NT_SUCCESS(Status));
// If disk had no partitions, test the whole disk
if (!has_parts && has_part0) {
UNICODE_STRING part0us;
part0us.Buffer = partition0;
part0us.Length = part0us.MaximumLength = wcslen(partition0) * sizeof(WCHAR);
test_vol(DriverObject, mountmgr, &path, &part0us, TRUE, volumes);
}
ZwClose(h);
ExFreePool(odi);
Status = STATUS_SUCCESS;
end:
ExFreePool(path.Buffer);
return Status;
}
static void remove_drive_letter(PDEVICE_OBJECT mountmgr, volume* v) {
void remove_drive_letter(PDEVICE_OBJECT mountmgr, volume* v) {
NTSTATUS Status;
KEVENT Event;
PIRP Irp;
@ -566,79 +444,10 @@ static void remove_drive_letter(PDEVICE_OBJECT mountmgr, volume* v) {
ExFreePool(mmp);
}
void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes) {
PFILE_OBJECT FileObject;
PDEVICE_OBJECT mountmgr;
OBJECT_ATTRIBUTES attr;
UNICODE_STRING mmdevpath, us;
HANDLE h;
OBJECT_DIRECTORY_INFORMATION* odi;
ULONG odisize;
ULONG context;
BOOL restart;
NTSTATUS Status;
static void refresh_mountmgr(PDEVICE_OBJECT mountmgr, LIST_ENTRY* volumes) {
LIST_ENTRY* le;
static const WCHAR directory[] = L"Directory";
static const WCHAR harddisk[] = L"Harddisk";
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr);
if (!NT_SUCCESS(Status)) {
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return;
}
RtlInitUnicodeString(&us, devpath);
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.Attributes = OBJ_CASE_INSENSITIVE;
attr.ObjectName = &us;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
Status = ZwOpenDirectoryObject(&h, DIRECTORY_TRAVERSE, &attr);
if (!NT_SUCCESS(Status)) {
ERR("ZwOpenDirectoryObject returned %08x\n", Status);
return;
}
odisize = sizeof(OBJECT_DIRECTORY_INFORMATION) * 16;
odi = ExAllocatePoolWithTag(PagedPool, odisize, ALLOC_TAG);
if (!odi) {
ERR("out of memory\n");
ZwClose(h);
return;
}
restart = TRUE;
do {
Status = ZwQueryDirectoryObject(h, odi, odisize, FALSE, restart, &context, NULL/*&retlen*/);
restart = FALSE;
if (!NT_SUCCESS(Status)) {
if (Status != STATUS_NO_MORE_ENTRIES)
ERR("ZwQueryDirectoryObject returned %08x\n", Status);
} else {
OBJECT_DIRECTORY_INFORMATION* odi2 = odi;
while (odi2->Name.Buffer) {
if (odi2->TypeName.Length == wcslen(directory) * sizeof(WCHAR) &&
RtlCompareMemory(odi2->TypeName.Buffer, directory, odi2->TypeName.Length) == odi2->TypeName.Length &&
odi2->Name.Length > wcslen(harddisk) * sizeof(WCHAR) &&
RtlCompareMemory(odi2->Name.Buffer, harddisk, wcslen(harddisk) * sizeof(WCHAR)) == wcslen(harddisk) * sizeof(WCHAR)) {
look_in_harddisk_dir(DriverObject, mountmgr, &odi2->Name, volumes);
}
odi2 = &odi2[1];
}
}
} while (NT_SUCCESS(Status));
ExFreePool(odi);
ZwClose(h);
ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
le = volumes->Flink;
while (le != volumes) {
@ -670,5 +479,215 @@ void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes) {
le = le->Flink;
}
ObDereferenceObject(FileObject);
ExReleaseResourceLite(&volumes_lock);
}
static void add_pnp_disk(ULONG disk_num, PUNICODE_STRING devpath) {
LIST_ENTRY* le;
pnp_disk* disk;
le = pnp_disks.Flink;
while (le != &pnp_disks) {
disk = CONTAINING_RECORD(le, pnp_disk, list_entry);
if (disk->devpath.Length == devpath->Length &&
RtlCompareMemory(disk->devpath.Buffer, devpath->Buffer, devpath->Length) == devpath->Length)
return;
le = le->Flink;
}
disk = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_disk), ALLOC_TAG);
if (!disk) {
ERR("out of memory\n");
return;
}
disk->devpath.Length = disk->devpath.MaximumLength = devpath->Length;
disk->devpath.Buffer = ExAllocatePoolWithTag(PagedPool, devpath->Length, ALLOC_TAG);
if (!disk->devpath.Buffer) {
ERR("out of memory\n");
ExFreePool(disk);
return;
}
RtlCopyMemory(disk->devpath.Buffer, devpath->Buffer, devpath->Length);
disk->disk_num = disk_num;
InsertTailList(&pnp_disks, &disk->list_entry);
}
static void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
PFILE_OBJECT FileObject, FileObject2;
PDEVICE_OBJECT devobj, mountmgr;
NTSTATUS Status;
STORAGE_DEVICE_NUMBER sdn;
ULONG dlisize;
DRIVE_LAYOUT_INFORMATION_EX* dli;
IO_STATUS_BLOCK iosb;
int i, num_parts = 0;
UNICODE_STRING devname, num, bspus, mmdevpath;
WCHAR devnamew[255], numw[20];
USHORT preflen;
static WCHAR device_harddisk[] = L"\\Device\\Harddisk";
static WCHAR bs_partition[] = L"\\Partition";
// FIXME - work with CD-ROMs and floppies(?)
Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &devobj);
if (!NT_SUCCESS(Status)) {
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return;
}
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject2, &mountmgr);
if (!NT_SUCCESS(Status)) {
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
ObDereferenceObject(FileObject);
return;
}
Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
&sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, &iosb);
if (!NT_SUCCESS(Status)) {
ERR("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
goto end;
}
ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
add_pnp_disk(sdn.DeviceNumber, devpath);
ExReleaseResourceLite(&volumes_lock);
dlisize = 0;
do {
dlisize += 1024;
dli = ExAllocatePoolWithTag(PagedPool, dlisize, ALLOC_TAG);
Status = dev_ioctl(devobj, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0,
dli, dlisize, TRUE, &iosb);
} while (Status == STATUS_BUFFER_TOO_SMALL);
if (!NT_SUCCESS(Status)) {
ExFreePool(dli);
goto no_parts;
}
wcscpy(devnamew, device_harddisk);
devname.Buffer = devnamew;
devname.MaximumLength = sizeof(devnamew);
devname.Length = wcslen(device_harddisk) * sizeof(WCHAR);
num.Buffer = numw;
num.MaximumLength = sizeof(numw);
RtlIntegerToUnicodeString(sdn.DeviceNumber, 10, &num);
RtlAppendUnicodeStringToString(&devname, &num);
bspus.Buffer = bs_partition;
bspus.Length = bspus.MaximumLength = wcslen(bs_partition) * sizeof(WCHAR);
RtlAppendUnicodeStringToString(&devname, &bspus);
preflen = devname.Length;
for (i = 0; i < dli->PartitionCount; i++) {
if (dli->PartitionEntry[i].PartitionLength.QuadPart != 0 && dli->PartitionEntry[i].PartitionNumber != 0) {
devname.Length = preflen;
RtlIntegerToUnicodeString(dli->PartitionEntry[i].PartitionNumber, 10, &num);
RtlAppendUnicodeStringToString(&devname, &num);
test_vol(DriverObject, mountmgr, &devname, sdn.DeviceNumber, dli->PartitionEntry[i].PartitionNumber, &volumes);
num_parts++;
}
}
ExFreePool(dli);
no_parts:
if (num_parts == 0) {
devname.Length = preflen;
devname.Buffer[devname.Length / sizeof(WCHAR)] = '0';
devname.Length += sizeof(WCHAR);
test_vol(DriverObject, mountmgr, &devname, sdn.DeviceNumber, 0, &volumes);
}
end:
refresh_mountmgr(mountmgr, &volumes);
ObDereferenceObject(FileObject);
ObDereferenceObject(FileObject2);
}
static void disk_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
LIST_ENTRY* le;
pnp_disk* disk = NULL;
// FIXME - remove Partition0Btrfs devices and unlink from mountmgr
// FIXME - emergency unmount of RAIDed volumes
ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
le = pnp_disks.Flink;
while (le != &pnp_disks) {
pnp_disk* disk2 = CONTAINING_RECORD(le, pnp_disk, list_entry);
if (disk2->devpath.Length == devpath->Length &&
RtlCompareMemory(disk2->devpath.Buffer, devpath->Buffer, devpath->Length) == devpath->Length) {
disk = disk2;
break;
}
le = le->Flink;
}
if (!disk) {
ExReleaseResourceLite(&volumes_lock);
return;
}
le = volumes.Flink;
while (le != &volumes) {
volume* v = CONTAINING_RECORD(le, volume, list_entry);
LIST_ENTRY* le2 = le->Flink;
if (v->disk_num == disk->disk_num) {
if (v->devpath.Buffer)
ExFreePool(v->devpath.Buffer);
RemoveEntryList(&v->list_entry);
ExFreePool(v);
}
le = le2;
}
ExReleaseResourceLite(&volumes_lock);
ExFreePool(disk->devpath.Buffer);
RemoveEntryList(&disk->list_entry);
ExFreePool(disk);
}
#ifdef __REACTOS__
NTSTATUS NTAPI pnp_notification(PVOID NotificationStructure, PVOID Context) {
#else
NTSTATUS pnp_notification(PVOID NotificationStructure, PVOID Context) {
#endif
DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure;
PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context;
if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID))
disk_arrival(DriverObject, dicn->SymbolicLinkName);
else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID))
disk_removal(DriverObject, dicn->SymbolicLinkName);
return STATUS_SUCCESS;
}

View file

@ -401,14 +401,10 @@ static ACL* load_default_acl() {
// }
// }
static BOOL get_sd_from_xattr(fcb* fcb, PIRP Irp) {
ULONG buflen;
BOOL get_sd_from_xattr(fcb* fcb, ULONG buflen) {
NTSTATUS Status;
PSID sid, usersid;
if (!get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_NTACL, EA_NTACL_HASH, (UINT8**)&fcb->sd, (UINT16*)&buflen, Irp))
return FALSE;
TRACE("using xattr " EA_NTACL " for security descriptor\n");
if (fcb->inode_item.st_uid != UID_NOBODY) {
@ -655,13 +651,16 @@ end:
ExFreePool(groupsid);
}
void fcb_get_sd(fcb* fcb, struct _fcb* parent, PIRP Irp) {
void fcb_get_sd(fcb* fcb, struct _fcb* parent, BOOL look_for_xattr, PIRP Irp) {
NTSTATUS Status;
PSID usersid = NULL, groupsid = NULL;
SECURITY_SUBJECT_CONTEXT subjcont;
ULONG buflen;
if (get_sd_from_xattr(fcb, Irp))
return;
if (look_for_xattr && get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_NTACL, EA_NTACL_HASH, (UINT8**)&fcb->sd, (UINT16*)&buflen, Irp)) {
if (get_sd_from_xattr(fcb, buflen))
return;
}
if (!parent) {
get_top_level_sd(fcb);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
The following FSD are shared with: https://github.com/maharmstone/btrfs.
reactos/drivers/filesystems/btrfs # Synced to 0.7
reactos/drivers/filesystems/btrfs # Synced to 0.8
reactos/dll/shellext/shellbtrfs # Synced to 0.7
The following FSD are shared with: http://www.ext2fsd.com/