mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[BTRFS]
Sync btrfs to 0.5. This breaks BTRFS in ReactOS. CORE-11674 svn path=/trunk/; revision=72023
This commit is contained in:
parent
8c418c8bdb
commit
7695f39c11
21 changed files with 15007 additions and 9814 deletions
|
@ -16,10 +16,12 @@ list(APPEND SOURCE
|
|||
fsctl.c
|
||||
pnp.c
|
||||
read.c
|
||||
registry.c
|
||||
reparse.c
|
||||
search.c
|
||||
security.c
|
||||
treefuncs.c
|
||||
worker-thread.c
|
||||
write.c
|
||||
btrfs_drv.h)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -70,12 +70,12 @@ BEGIN
|
|||
BLOCK "080904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "WinBtrfs"
|
||||
VALUE "FileVersion", "0.4"
|
||||
VALUE "FileVersion", "0.5"
|
||||
VALUE "InternalName", "btrfs"
|
||||
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016"
|
||||
VALUE "OriginalFilename", "btrfs.sys"
|
||||
VALUE "ProductName", "WinBtrfs"
|
||||
VALUE "ProductVersion", "0.4"
|
||||
VALUE "ProductVersion", "0.5"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -73,6 +73,8 @@
|
|||
|
||||
#define READ_AHEAD_GRANULARITY 0x10000 // 64 KB
|
||||
|
||||
#define MAX_EXTENT_SIZE 0x8000000 // 128 MB
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define try __try
|
||||
#define except __except
|
||||
|
@ -88,11 +90,12 @@
|
|||
struct device_extension;
|
||||
|
||||
typedef struct {
|
||||
PDEVICE_OBJECT devobj;
|
||||
BTRFS_UUID fsuuid;
|
||||
BTRFS_UUID devuuid;
|
||||
UINT64 devnum;
|
||||
UNICODE_STRING devpath;
|
||||
UINT64 length;
|
||||
UINT64 gen1, gen2;
|
||||
BOOL processed;
|
||||
LIST_ENTRY list_entry;
|
||||
} volume;
|
||||
|
@ -102,10 +105,42 @@ typedef struct _fcb_nonpaged {
|
|||
SECTION_OBJECT_POINTERS segment_object;
|
||||
ERESOURCE resource;
|
||||
ERESOURCE paging_resource;
|
||||
ERESOURCE index_lock;
|
||||
} fcb_nonpaged;
|
||||
|
||||
struct _root;
|
||||
|
||||
typedef struct {
|
||||
UINT64 offset;
|
||||
EXTENT_DATA* data;
|
||||
ULONG datalen;
|
||||
BOOL unique;
|
||||
BOOL ignore;
|
||||
|
||||
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;
|
||||
UNICODE_STRING name;
|
||||
ANSI_STRING utf8;
|
||||
LIST_ENTRY list_entry;
|
||||
} hardlink;
|
||||
|
||||
struct _file_ref;
|
||||
|
||||
typedef struct _fcb {
|
||||
FSRTL_ADVANCED_FCB_HEADER Header;
|
||||
struct _fcb_nonpaged* nonpaged;
|
||||
|
@ -123,33 +158,66 @@ typedef struct _fcb {
|
|||
ULONG atts;
|
||||
SHARE_ACCESS share_access;
|
||||
WCHAR* debug_desc;
|
||||
LIST_ENTRY extents;
|
||||
UINT64 last_dir_index;
|
||||
ANSI_STRING reparse_xattr;
|
||||
LIST_ENTRY hardlinks;
|
||||
struct _file_ref* fileref;
|
||||
|
||||
BOOL index_loaded;
|
||||
LIST_ENTRY index_list;
|
||||
|
||||
BOOL dirty;
|
||||
BOOL sd_dirty;
|
||||
BOOL atts_changed, atts_deleted;
|
||||
BOOL extents_changed;
|
||||
BOOL reparse_xattr_changed;
|
||||
BOOL created;
|
||||
|
||||
BOOL ads;
|
||||
UINT32 adssize;
|
||||
UINT32 adshash;
|
||||
ANSI_STRING adsxattr;
|
||||
ANSI_STRING adsdata;
|
||||
|
||||
LIST_ENTRY list_entry;
|
||||
LIST_ENTRY list_entry_all;
|
||||
} fcb;
|
||||
|
||||
struct _file_ref;
|
||||
typedef struct {
|
||||
fcb* fcb;
|
||||
LIST_ENTRY list_entry;
|
||||
} dirty_fcb;
|
||||
|
||||
typedef struct {
|
||||
ERESOURCE children_lock;
|
||||
} file_ref_nonpaged;
|
||||
|
||||
typedef struct _file_ref {
|
||||
fcb* fcb;
|
||||
UNICODE_STRING filepart;
|
||||
UNICODE_STRING filepart_uc;
|
||||
ANSI_STRING utf8;
|
||||
UNICODE_STRING full_filename;
|
||||
ULONG name_offset;
|
||||
ANSI_STRING oldutf8;
|
||||
UINT64 index;
|
||||
BOOL delete_on_close;
|
||||
BOOL deleted;
|
||||
BOOL created;
|
||||
file_ref_nonpaged* nonpaged;
|
||||
LIST_ENTRY children;
|
||||
LONG refcount;
|
||||
struct _file_ref* parent;
|
||||
WCHAR* debug_desc;
|
||||
|
||||
BOOL dirty;
|
||||
|
||||
LIST_ENTRY list_entry;
|
||||
} file_ref;
|
||||
|
||||
typedef struct {
|
||||
file_ref* fileref;
|
||||
LIST_ENTRY list_entry;
|
||||
} dirty_fileref;
|
||||
|
||||
typedef struct _ccb {
|
||||
USHORT NodeType;
|
||||
CSHORT NodeSize;
|
||||
|
@ -162,6 +230,7 @@ typedef struct _ccb {
|
|||
BOOL specific_file;
|
||||
ACCESS_MASK access;
|
||||
file_ref* fileref;
|
||||
UNICODE_STRING filename;
|
||||
} ccb;
|
||||
|
||||
// typedef struct _log_to_phys {
|
||||
|
@ -259,47 +328,77 @@ typedef struct _root_cache {
|
|||
struct _root_cache* next;
|
||||
} root_cache;
|
||||
|
||||
#define SPACE_TYPE_FREE 0
|
||||
#define SPACE_TYPE_USED 1
|
||||
#define SPACE_TYPE_DELETING 2
|
||||
#define SPACE_TYPE_WRITING 3
|
||||
|
||||
typedef struct {
|
||||
UINT64 offset;
|
||||
UINT64 size;
|
||||
UINT8 type;
|
||||
LIST_ENTRY list_entry;
|
||||
} space;
|
||||
|
||||
typedef struct {
|
||||
UINT64 address;
|
||||
UINT64 size;
|
||||
BOOL provisional;
|
||||
LIST_ENTRY listentry;
|
||||
} disk_hole;
|
||||
LIST_ENTRY list_entry;
|
||||
LIST_ENTRY list_entry_size;
|
||||
} space;
|
||||
|
||||
typedef struct {
|
||||
PDEVICE_OBJECT devobj;
|
||||
DEV_ITEM devitem;
|
||||
BOOL removable;
|
||||
ULONG change_count;
|
||||
LIST_ENTRY disk_holes;
|
||||
UINT64 length;
|
||||
LIST_ENTRY space;
|
||||
} device;
|
||||
|
||||
typedef struct {
|
||||
ERESOURCE lock;
|
||||
ERESOURCE changed_extents_lock;
|
||||
} chunk_nonpaged;
|
||||
|
||||
typedef struct {
|
||||
CHUNK_ITEM* chunk_item;
|
||||
UINT32 size;
|
||||
UINT64 offset;
|
||||
UINT64 used;
|
||||
UINT32 oldused;
|
||||
BOOL space_changed;
|
||||
device** devices;
|
||||
UINT64 cache_size;
|
||||
UINT64 cache_inode;
|
||||
fcb* cache;
|
||||
LIST_ENTRY space;
|
||||
LIST_ENTRY space_size;
|
||||
LIST_ENTRY deleting;
|
||||
LIST_ENTRY changed_extents;
|
||||
chunk_nonpaged* nonpaged;
|
||||
BOOL created;
|
||||
|
||||
LIST_ENTRY list_entry;
|
||||
LIST_ENTRY list_entry_changed;
|
||||
} chunk;
|
||||
|
||||
typedef struct {
|
||||
UINT64 address;
|
||||
UINT64 size;
|
||||
UINT64 old_size;
|
||||
UINT64 count;
|
||||
UINT64 old_count;
|
||||
BOOL no_csum;
|
||||
LIST_ENTRY refs;
|
||||
LIST_ENTRY old_refs;
|
||||
LIST_ENTRY list_entry;
|
||||
} changed_extent;
|
||||
|
||||
typedef struct {
|
||||
EXTENT_DATA_REF edr;
|
||||
LIST_ENTRY list_entry;
|
||||
} changed_extent_ref;
|
||||
|
||||
typedef struct {
|
||||
UINT64 address;
|
||||
UINT64 size;
|
||||
EXTENT_DATA_REF edr;
|
||||
LIST_ENTRY list_entry;
|
||||
} shared_data_entry;
|
||||
|
||||
typedef struct {
|
||||
UINT64 address;
|
||||
UINT64 parent;
|
||||
LIST_ENTRY entries;
|
||||
LIST_ENTRY list_entry;
|
||||
} shared_data;
|
||||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
void* data;
|
||||
|
@ -307,14 +406,46 @@ typedef struct {
|
|||
LIST_ENTRY list_entry;
|
||||
} sys_chunk;
|
||||
|
||||
typedef struct {
|
||||
PIRP Irp;
|
||||
LIST_ENTRY list_entry;
|
||||
} thread_job;
|
||||
|
||||
typedef struct {
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
HANDLE handle;
|
||||
KEVENT event, finished;
|
||||
BOOL quit;
|
||||
LIST_ENTRY jobs;
|
||||
KSPIN_LOCK spin_lock;
|
||||
} drv_thread;
|
||||
|
||||
typedef struct {
|
||||
ULONG num_threads;
|
||||
LONG next_thread;
|
||||
drv_thread* threads;
|
||||
} drv_threads;
|
||||
|
||||
typedef struct {
|
||||
BOOL ignore;
|
||||
} mount_options;
|
||||
|
||||
#define VCB_TYPE_VOLUME 1
|
||||
#define VCB_TYPE_PARTITION0 2
|
||||
|
||||
typedef struct _device_extension {
|
||||
UINT32 type;
|
||||
mount_options options;
|
||||
PVPB Vpb;
|
||||
device* devices;
|
||||
UINT64 devices_loaded;
|
||||
// DISK_GEOMETRY geometry;
|
||||
UINT64 length;
|
||||
superblock superblock;
|
||||
// WCHAR label[MAX_LABEL_SIZE];
|
||||
BOOL readonly;
|
||||
BOOL removing;
|
||||
BOOL locked;
|
||||
PFILE_OBJECT locked_fileobj;
|
||||
fcb* volume_fcb;
|
||||
file_ref* root_fileref;
|
||||
ERESOURCE DirResource;
|
||||
|
@ -324,12 +455,12 @@ typedef struct _device_extension {
|
|||
ERESOURCE tree_lock;
|
||||
PNOTIFY_SYNC NotifySync;
|
||||
LIST_ENTRY DirNotifyList;
|
||||
LONG tree_lock_counter;
|
||||
LONG open_trees;
|
||||
ULONG write_trees;
|
||||
BOOL need_write;
|
||||
// ERESOURCE LogToPhysLock;
|
||||
// UINT64 chunk_root_phys_addr;
|
||||
UINT64 root_tree_phys_addr;
|
||||
UINT64 data_flags;
|
||||
// log_to_phys* log_to_phys;
|
||||
LIST_ENTRY roots;
|
||||
LIST_ENTRY drop_roots;
|
||||
|
@ -343,11 +474,33 @@ typedef struct _device_extension {
|
|||
UINT32 max_inline;
|
||||
LIST_ENTRY sys_chunks;
|
||||
LIST_ENTRY chunks;
|
||||
LIST_ENTRY chunks_changed;
|
||||
LIST_ENTRY trees;
|
||||
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;
|
||||
LIST_ENTRY shared_extents;
|
||||
KSPIN_LOCK shared_extents_lock;
|
||||
HANDLE flush_thread_handle;
|
||||
KTIMER flush_thread_timer;
|
||||
KEVENT flush_thread_finished;
|
||||
drv_threads threads;
|
||||
PFILE_OBJECT root_file;
|
||||
LIST_ENTRY list_entry;
|
||||
} device_extension;
|
||||
|
||||
typedef struct {
|
||||
UINT32 type;
|
||||
PDEVICE_OBJECT devobj;
|
||||
BTRFS_UUID uuid;
|
||||
UNICODE_STRING name;
|
||||
} part0_device_extension;
|
||||
|
||||
typedef struct {
|
||||
LIST_ENTRY listentry;
|
||||
PSID sid;
|
||||
|
@ -366,39 +519,37 @@ typedef struct {
|
|||
BOOL deleted;
|
||||
} changed_sector;
|
||||
|
||||
enum write_tree_status {
|
||||
WriteTreeStatus_Pending,
|
||||
WriteTreeStatus_Success,
|
||||
WriteTreeStatus_Error,
|
||||
WriteTreeStatus_Cancelling,
|
||||
WriteTreeStatus_Cancelled
|
||||
enum write_data_status {
|
||||
WriteDataStatus_Pending,
|
||||
WriteDataStatus_Success,
|
||||
WriteDataStatus_Error,
|
||||
WriteDataStatus_Cancelling,
|
||||
WriteDataStatus_Cancelled,
|
||||
WriteDataStatus_Ignore
|
||||
};
|
||||
|
||||
struct write_tree_context;
|
||||
struct write_data_context;
|
||||
|
||||
typedef struct {
|
||||
struct write_tree_context* context;
|
||||
struct write_data_context* context;
|
||||
UINT8* buf;
|
||||
BOOL need_free;
|
||||
device* device;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
enum write_tree_status status;
|
||||
enum write_data_status status;
|
||||
LIST_ENTRY list_entry;
|
||||
} write_tree_stripe;
|
||||
} write_data_stripe;
|
||||
|
||||
typedef struct {
|
||||
KEVENT Event;
|
||||
LIST_ENTRY stripes;
|
||||
} write_tree_context;
|
||||
LONG stripes_left;
|
||||
BOOL tree;
|
||||
} write_data_context;
|
||||
|
||||
// #pragma pack(pop)
|
||||
|
||||
static __inline void init_tree_holder(tree_holder* th) {
|
||||
// th->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_holder_nonpaged), ALLOC_TAG);
|
||||
// KeInitializeSpinLock(&th->nonpaged->spin_lock);
|
||||
// ExInitializeResourceLite(&th->nonpaged->lock); // FIXME - delete this later
|
||||
}
|
||||
|
||||
static __inline void* map_user_buffer(PIRP Irp) {
|
||||
if (!Irp->MdlAddress) {
|
||||
return Irp->UserBuffer;
|
||||
|
@ -439,22 +590,28 @@ static __inline void insert_into_ordered_list(LIST_ENTRY* list, ordered_list* in
|
|||
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;
|
||||
|
||||
startoff = off % (num_stripes * stripe_length);
|
||||
initoff = (off / (num_stripes * stripe_length)) * stripe_length;
|
||||
|
||||
*stripe = startoff / stripe_length;
|
||||
*stripeoff = initoff + startoff - (*stripe * stripe_length);
|
||||
}
|
||||
|
||||
// in btrfs.c
|
||||
device* find_device_from_uuid(device_extension* Vcb, BTRFS_UUID* uuid);
|
||||
ULONG sector_align( ULONG NumberToBeAligned, ULONG Alignment );
|
||||
UINT64 sector_align( UINT64 NumberToBeAligned, UINT64 Alignment );
|
||||
int keycmp(const KEY* key1, const KEY* key2);
|
||||
ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa);
|
||||
BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen);
|
||||
NTSTATUS STDCALL set_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8* data, UINT16 datalen, LIST_ENTRY* rollback);
|
||||
BOOL STDCALL delete_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, LIST_ENTRY* rollback);
|
||||
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);
|
||||
BOOL STDCALL get_last_inode(device_extension* Vcb, root* r);
|
||||
NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, LIST_ENTRY* rollback);
|
||||
NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, LIST_ENTRY* rollback);
|
||||
UINT64 find_next_dir_index(device_extension* Vcb, root* subvol, UINT64 inode);
|
||||
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, UINT64* index, LIST_ENTRY* rollback);
|
||||
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, LIST_ENTRY* rollback);
|
||||
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, LIST_ENTRY* rollback);
|
||||
fcb* create_fcb();
|
||||
file_ref* create_fileref();
|
||||
void protect_superblocks(device_extension* Vcb, chunk* c);
|
||||
|
@ -465,8 +622,14 @@ NTSTATUS STDCALL dev_ioctl(PDEVICE_OBJECT DeviceObject, ULONG ControlCode, PVOID
|
|||
ULONG InputBufferSize, PVOID OutputBuffer, ULONG OutputBufferSize, BOOLEAN Override, IO_STATUS_BLOCK* iosb);
|
||||
BOOL is_file_name_valid(PUNICODE_STRING us);
|
||||
void send_notification_fileref(file_ref* fileref, ULONG filter_match, ULONG action);
|
||||
void send_notification_fcb(file_ref* fileref, ULONG filter_match, ULONG action);
|
||||
WCHAR* file_desc(PFILE_OBJECT FileObject);
|
||||
WCHAR* file_desc_fileref(file_ref* fileref);
|
||||
BOOL add_thread_job(device_extension* Vcb, PIRP Irp);
|
||||
NTSTATUS part0_passthrough(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
void mark_fcb_dirty(fcb* fcb);
|
||||
void mark_fileref_dirty(file_ref* fileref);
|
||||
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, LIST_ENTRY* rollback);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define funcname __FUNCTION__
|
||||
|
@ -533,6 +696,13 @@ void STDCALL init_fast_io_dispatch(FAST_IO_DISPATCH** fiod);
|
|||
// in crc32c.c
|
||||
UINT32 STDCALL calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen);
|
||||
|
||||
enum rollback_type {
|
||||
ROLLBACK_INSERT_ITEM,
|
||||
ROLLBACK_DELETE_ITEM,
|
||||
ROLLBACK_INSERT_EXTENT,
|
||||
ROLLBACK_DELETE_EXTENT
|
||||
};
|
||||
|
||||
// in treefuncs.c
|
||||
NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, 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, const char* func, const char* file, unsigned int line);
|
||||
|
@ -541,22 +711,22 @@ void STDCALL free_trees(device_extension* Vcb);
|
|||
BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset, void* data, UINT32 size, traverse_ptr* ptp, LIST_ENTRY* rollback);
|
||||
void STDCALL delete_tree_item(device_extension* Vcb, traverse_ptr* tp, LIST_ENTRY* rollback);
|
||||
tree* STDCALL _free_tree(tree* t, const char* func, const char* file, unsigned int line);
|
||||
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, const char* func, const char* file, unsigned int line);
|
||||
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, tree* parent, const char* func, const char* file, unsigned int line);
|
||||
NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, const char* func, const char* file, unsigned int line);
|
||||
void clear_rollback(LIST_ENTRY* rollback);
|
||||
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback);
|
||||
void free_trees_root(device_extension* Vcb, root* r);
|
||||
NTSTATUS STDCALL read_tree(device_extension* Vcb, UINT64 addr, UINT8* buf);
|
||||
void add_rollback(LIST_ENTRY* rollback, enum rollback_type type, void* ptr);
|
||||
|
||||
#define find_item(Vcb, r, tp, searchkey, ignore) _find_item(Vcb, r, tp, searchkey, ignore, funcname, __FILE__, __LINE__)
|
||||
#define find_next_item(Vcb, tp, next_tp, ignore) _find_next_item(Vcb, tp, next_tp, ignore, funcname, __FILE__, __LINE__)
|
||||
#define find_prev_item(Vcb, tp, prev_tp, ignore) _find_prev_item(Vcb, tp, prev_tp, ignore, funcname, __FILE__, __LINE__)
|
||||
#define free_tree(t) _free_tree(t, funcname, __FILE__, __LINE__)
|
||||
#define load_tree(t, addr, r, pt) _load_tree(t, addr, r, pt, funcname, __FILE__, __LINE__)
|
||||
#define load_tree(t, addr, r, pt, parent) _load_tree(t, addr, r, pt, parent, funcname, __FILE__, __LINE__)
|
||||
#define do_load_tree(Vcb, th, r, t, td, loaded) _do_load_tree(Vcb, th, r, t, td, loaded, funcname, __FILE__, __LINE__)
|
||||
|
||||
// in search.c
|
||||
void STDCALL look_for_vols(LIST_ENTRY* volumes);
|
||||
void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes);
|
||||
|
||||
// in cache.c
|
||||
NTSTATUS STDCALL init_cache();
|
||||
|
@ -565,28 +735,32 @@ extern CACHE_MANAGER_CALLBACKS* cache_callbacks;
|
|||
|
||||
// in write.c
|
||||
NTSTATUS STDCALL do_write(device_extension* Vcb, LIST_ENTRY* rollback);
|
||||
NTSTATUS write_file(PDEVICE_OBJECT DeviceObject, PIRP Irp);
|
||||
NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, BOOL paging_io, BOOL no_cache, LIST_ENTRY* rollback);
|
||||
NTSTATUS write_file(device_extension* Vcb, PIRP Irp, BOOL wait, BOOL deferred_write);
|
||||
NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, BOOL paging_io, BOOL no_cache,
|
||||
BOOL wait, BOOL deferred_write, LIST_ENTRY* rollback);
|
||||
NTSTATUS truncate_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback);
|
||||
NTSTATUS extend_file(fcb* fcb, file_ref* fileref, UINT64 end, BOOL prealloc, LIST_ENTRY* rollback);
|
||||
NTSTATUS excise_extents_inode(device_extension* Vcb, root* subvol, UINT64 inode, INODE_ITEM* ii, UINT64 start_data, UINT64 end_data, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
void update_checksum_tree(device_extension* Vcb, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
NTSTATUS insert_sparse_extent(device_extension* Vcb, root* r, UINT64 inode, UINT64 start, UINT64 length, 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, LIST_ENTRY* rollback);
|
||||
void commit_checksum_changes(device_extension* Vcb, LIST_ENTRY* changed_sector_list);
|
||||
NTSTATUS insert_sparse_extent(fcb* fcb, UINT64 start, UINT64 length, LIST_ENTRY* rollback);
|
||||
chunk* get_chunk_from_address(device_extension* Vcb, UINT64 address);
|
||||
void add_to_space_list(chunk* c, UINT64 offset, UINT64 size, UINT8 type);
|
||||
NTSTATUS consider_write(device_extension* Vcb);
|
||||
BOOL insert_extent_chunk_inode(device_extension* Vcb, root* subvol, UINT64 inode, INODE_ITEM* inode_item, chunk* c, UINT64 start_data,
|
||||
UINT64 length, BOOL prealloc, void* data, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
chunk* alloc_chunk(device_extension* Vcb, UINT64 flags, LIST_ENTRY* rollback);
|
||||
NTSTATUS STDCALL write_data(device_extension* Vcb, UINT64 address, void* data, UINT32 length);
|
||||
NTSTATUS write_tree(device_extension* Vcb, UINT64 addr, UINT8* data, write_tree_context* wtc);
|
||||
void free_write_tree_stripes(write_tree_context* wtc);
|
||||
NTSTATUS STDCALL write_data(device_extension* Vcb, UINT64 address, void* data, BOOL need_free, UINT32 length, write_data_context* wtc, PIRP Irp);
|
||||
NTSTATUS STDCALL write_data_complete(device_extension* Vcb, UINT64 address, void* data, UINT32 length, PIRP Irp);
|
||||
void free_write_data_stripes(write_data_context* wtc);
|
||||
NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, LIST_ENTRY* rollback);
|
||||
NTSTATUS STDCALL drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
void flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* rollback);
|
||||
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,
|
||||
PIRP Irp, LIST_ENTRY* rollback);
|
||||
NTSTATUS do_nocow_write(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
|
||||
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);
|
||||
void remove_fcb_extent(extent* ext, LIST_ENTRY* rollback);
|
||||
NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset,
|
||||
signed long long count, BOOL no_csum, UINT64 new_size);
|
||||
|
||||
// in dirctrl.c
|
||||
NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type);
|
||||
|
||||
// in security.c
|
||||
NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
|
@ -595,16 +769,16 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent);
|
|||
// UINT32 STDCALL get_uid();
|
||||
void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid);
|
||||
UINT32 sid_to_uid(PSID sid);
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* fileref, ACCESS_STATE* as);
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as);
|
||||
|
||||
// in fileinfo.c
|
||||
NTSTATUS STDCALL drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
NTSTATUS STDCALL drv_query_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
NTSTATUS add_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, UINT64 index, PANSI_STRING utf8, LIST_ENTRY* rollback);
|
||||
NTSTATUS delete_root_ref(device_extension* Vcb, UINT64 subvolid, UINT64 parsubvolid, UINT64 parinode, PANSI_STRING utf8, UINT64* index, LIST_ENTRY* rollback);
|
||||
NTSTATUS STDCALL update_root_backref(device_extension* Vcb, UINT64 subvolid, UINT64 parsubvolid, LIST_ENTRY* rollback);
|
||||
BOOL has_open_children(file_ref* fileref);
|
||||
NTSTATUS STDCALL stream_set_end_of_file_information(device_extension* Vcb, UINT64 end, fcb* fcb, file_ref* fileref, PFILE_OBJECT FileObject, BOOL advance_only, LIST_ENTRY* rollback);
|
||||
NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* name_offset);
|
||||
NTSTATUS open_fileref_by_inode(device_extension* Vcb, root* subvol, UINT64 inode, file_ref** pfr);
|
||||
|
||||
// in reparse.c
|
||||
NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, DWORD* retlen);
|
||||
|
@ -613,20 +787,28 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
|
|||
|
||||
// in create.c
|
||||
NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
BOOL STDCALL find_file_in_dir_with_crc32(device_extension* Vcb, PUNICODE_STRING filename, UINT32 crc32, root* r, UINT64 parinode, root** subvol,
|
||||
UINT64* inode, UINT8* type, PANSI_STRING utf8);
|
||||
NTSTATUS update_inode_item(device_extension* Vcb, root* subvol, UINT64 inode, INODE_ITEM* ii, LIST_ENTRY* rollback);
|
||||
NTSTATUS STDCALL find_file_in_dir_with_crc32(device_extension* Vcb, PUNICODE_STRING filename, UINT32 crc32, file_ref* fr, root** subvol,
|
||||
UINT64* inode, UINT8* type, UINT64* index, PANSI_STRING utf8);
|
||||
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);
|
||||
NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* unparsed);
|
||||
NTSTATUS open_fcb(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb);
|
||||
NTSTATUS open_fcb_stream(device_extension* Vcb, root* subvol, UINT64 inode, ANSI_STRING* xattr, UINT32 streamhash, fcb* parent, fcb** pfcb);
|
||||
void insert_fileref_child(file_ref* parent, file_ref* child, BOOL do_lock);
|
||||
NTSTATUS fcb_get_last_dir_index(fcb* fcb, UINT64* index);
|
||||
|
||||
// in fsctl.c
|
||||
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user);
|
||||
void do_unlock_volume(device_extension* Vcb);
|
||||
|
||||
// in flushthread.c
|
||||
void STDCALL flush_thread(void* context);
|
||||
|
||||
// in read.c
|
||||
NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp);
|
||||
NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr);
|
||||
NTSTATUS STDCALL read_data(device_extension* Vcb, UINT64 addr, UINT32 length, UINT32* csum, BOOL is_tree, UINT8* buf, chunk** pc, PIRP Irp);
|
||||
NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr, PIRP Irp);
|
||||
NTSTATUS do_read(PIRP Irp, BOOL wait, ULONG* bytes_read);
|
||||
|
||||
// in pnp.c
|
||||
NTSTATUS STDCALL drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp);
|
||||
|
@ -636,13 +818,36 @@ NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c);
|
|||
NTSTATUS clear_free_space_cache(device_extension* Vcb);
|
||||
NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, LIST_ENTRY* rollback);
|
||||
NTSTATUS update_chunk_caches(device_extension* Vcb, LIST_ENTRY* rollback);
|
||||
NTSTATUS add_space_entry(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 offset, UINT64 size);
|
||||
void _space_list_add(device_extension* Vcb, chunk* c, BOOL deleting, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
|
||||
void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
|
||||
void _space_list_subtract(device_extension* Vcb, chunk* c, BOOL deleting, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
|
||||
void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
|
||||
|
||||
#define space_list_add(Vcb, c, deleting, address, length, rollback) _space_list_add(Vcb, c, deleting, address, length, rollback, funcname)
|
||||
#define space_list_add2(list, list_size, address, length, rollback) _space_list_add2(list, list_size, address, length, rollback, funcname)
|
||||
#define space_list_subtract(Vcb, c, deleting, address, length, rollback) _space_list_subtract(Vcb, c, deleting, address, length, rollback, funcname)
|
||||
#define space_list_subtract2(list, list_size, address, length, rollback) _space_list_subtract2(list, list_size, address, length, rollback, funcname)
|
||||
|
||||
// in extent-tree.c
|
||||
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback);
|
||||
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback);
|
||||
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback);
|
||||
NTSTATUS decrease_extent_refcount_shared_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, UINT64 parent, LIST_ENTRY* rollback);
|
||||
NTSTATUS decrease_extent_refcount_old(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, LIST_ENTRY* rollback);
|
||||
void decrease_chunk_usage(chunk* c, UINT64 delta);
|
||||
NTSTATUS convert_shared_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, LIST_ENTRY* rollback);
|
||||
NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, LIST_ENTRY* rollback);
|
||||
UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset);
|
||||
|
||||
// in worker-thread.c
|
||||
void STDCALL worker_thread(void* context);
|
||||
void do_read_job(PIRP Irp);
|
||||
void do_write_job(device_extension* Vcb, PIRP Irp);
|
||||
|
||||
// in registry.c
|
||||
void STDCALL read_registry(PUNICODE_STRING regpath);
|
||||
NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid);
|
||||
NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID* uuid);
|
||||
NTSTATUS registry_load_volume_options(BTRFS_UUID* uuid, mount_options* options);
|
||||
|
||||
#define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable)
|
||||
|
||||
|
@ -669,6 +874,22 @@ static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY*
|
|||
head->Blink = item;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FCB_REFCOUNTS
|
||||
#ifdef DEBUG_LONG_MESSAGES
|
||||
#define increase_fileref_refcount(fileref) {\
|
||||
LONG rc = InterlockedIncrement(&fileref->refcount);\
|
||||
MSG(funcname, __FILE__, __LINE__, "fileref %p: refcount now %i\n", 1, fileref, rc);\
|
||||
}
|
||||
#else
|
||||
#define increase_fileref_refcount(fileref) {\
|
||||
LONG rc = InterlockedIncrement(&fileref->refcount);\
|
||||
MSG(funcname, "fileref %p: refcount now %i\n", 1, fileref, rc);\
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define increase_fileref_refcount(fileref) InterlockedIncrement(&fileref->refcount)
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// #define int3 __asm { int 3 }
|
||||
#define int3 __debugbreak()
|
||||
|
@ -676,34 +897,11 @@ static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY*
|
|||
#define int3 asm("int3;")
|
||||
#endif
|
||||
|
||||
#define acquire_tree_lock(Vcb, exclusive) {\
|
||||
LONG ref = InterlockedIncrement(&Vcb->tree_lock_counter); \
|
||||
ref = ref; \
|
||||
if (exclusive) { \
|
||||
TRACE("getting tree_lock (exclusive) %u->%u\n", ref-1, ref); \
|
||||
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); \
|
||||
TRACE("open tree count = %i\n", Vcb->open_trees); \
|
||||
} else { \
|
||||
TRACE("getting tree_lock %u->%u\n", ref-1, ref); \
|
||||
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); \
|
||||
} \
|
||||
}
|
||||
|
||||
// if (Vcb->open_trees > 0) { ERR("open tree count = %i\n", Vcb->open_trees); print_open_trees(Vcb); int3; }
|
||||
// else TRACE("open tree count = %i\n", Vcb->open_trees);
|
||||
|
||||
// FIXME - find a way to catch unfreed trees again
|
||||
|
||||
#define release_tree_lock(Vcb, exclusive) {\
|
||||
LONG ref = InterlockedDecrement(&Vcb->tree_lock_counter); \
|
||||
ref = ref; \
|
||||
TRACE("releasing tree_lock %u->%u\n", ref+1, ref); \
|
||||
if (exclusive) {\
|
||||
TRACE("open tree count = %i\n", Vcb->open_trees); \
|
||||
} \
|
||||
ExReleaseResourceLite(&Vcb->tree_lock); \
|
||||
}
|
||||
|
||||
// from sys/stat.h
|
||||
#define __S_IFMT 0170000 /* These bits determine file type. */
|
||||
#define __S_IFDIR 0040000 /* Directory. */
|
||||
|
@ -773,6 +971,7 @@ NTSTATUS NTAPI FsRtlRemoveDotsFromPath(PWSTR OriginalString,
|
|||
USHORT PathLength, USHORT *NewLength);
|
||||
NTSTATUS NTAPI FsRtlValidateReparsePointBuffer(ULONG BufferLength,
|
||||
PREPARSE_DATA_BUFFER ReparseBuffer);
|
||||
#endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */
|
||||
ULONG NTAPI KeQueryActiveProcessorCount(PKAFFINITY ActiveProcessors);
|
||||
#endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_VISTA) */
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -25,14 +25,16 @@ enum DirEntryType {
|
|||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
BOOL name_alloc;
|
||||
char* name;
|
||||
ULONG namelen;
|
||||
UINT8 type;
|
||||
enum DirEntryType dir_entry_type;
|
||||
} dir_entry;
|
||||
|
||||
ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type) {
|
||||
ULONG att, tag, br;
|
||||
static ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, ULONG atts) {
|
||||
fcb* fcb;
|
||||
ULONG tag = 0, br;
|
||||
NTSTATUS Status;
|
||||
|
||||
// FIXME - will this slow things down?
|
||||
|
@ -43,43 +45,41 @@ ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode,
|
|||
if (type != BTRFS_TYPE_FILE && type != BTRFS_TYPE_DIRECTORY)
|
||||
return 0;
|
||||
|
||||
att = get_file_attributes(Vcb, NULL, subvol, inode, type, FALSE, FALSE);
|
||||
|
||||
if (!(att & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
if (!(atts & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
return 0;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
|
||||
Status = open_fcb(Vcb, subvol, inode, type, NULL, NULL, &fcb);
|
||||
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);
|
||||
|
||||
if (type == BTRFS_TYPE_DIRECTORY) {
|
||||
UINT8* data;
|
||||
UINT16 datalen;
|
||||
if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length < sizeof(ULONG))
|
||||
goto end;
|
||||
|
||||
if (!get_xattr(Vcb, subvol, inode, EA_REPARSE, EA_REPARSE_HASH, &data, &datalen))
|
||||
return 0;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (datalen < sizeof(ULONG)) {
|
||||
ExFreePool(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
RtlCopyMemory(&tag, data, sizeof(ULONG));
|
||||
|
||||
ExFreePool(data);
|
||||
RtlCopyMemory(&tag, fcb->reparse_xattr.Buffer, sizeof(ULONG));
|
||||
} else {
|
||||
// FIXME - see if file loaded and cached, and do CcCopyRead if it is
|
||||
|
||||
Status = read_file(Vcb, subvol, inode, (UINT8*)&tag, 0, sizeof(ULONG), &br);
|
||||
|
||||
Status = read_file(fcb, (UINT8*)&tag, 0, sizeof(ULONG), &br, NULL);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_file returned %08x\n", Status);
|
||||
return 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (br < sizeof(ULONG))
|
||||
return 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
|
||||
free_fcb(fcb);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
INODE_ITEM ii;
|
||||
NTSTATUS Status;
|
||||
ULONG stringlen;
|
||||
BOOL dotfile;
|
||||
ULONG atts;
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
|
@ -128,24 +128,23 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
LIST_ENTRY* le;
|
||||
BOOL found = FALSE;
|
||||
|
||||
if (fileref) {
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->fcb_lock, TRUE);
|
||||
|
||||
le = fileref->children.Flink;
|
||||
while (le != &fileref->children) {
|
||||
file_ref* c = CONTAINING_RECORD(le, file_ref, list_entry);
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->fcb_lock, TRUE);
|
||||
if (!IsListEmpty(&r->fcbs)) {
|
||||
le = r->fcbs.Flink;
|
||||
while (le != &r->fcbs) {
|
||||
struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
|
||||
|
||||
if (c->fcb->subvol == r && c->fcb->inode == inode && !c->fcb->ads) {
|
||||
ii = c->fcb->inode_item;
|
||||
if (fcb2->inode == inode && !fcb2->ads) {
|
||||
ii = fcb2->inode_item;
|
||||
atts = fcb2->atts;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
|
||||
}
|
||||
ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
|
||||
|
||||
if (!found) {
|
||||
KEY searchkey;
|
||||
|
@ -170,6 +169,16 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
|
||||
if (tp.item->size > 0)
|
||||
RtlCopyMemory(&ii, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
|
||||
|
||||
if (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
|
||||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileDirectoryInformation ||
|
||||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileFullDirectoryInformation ||
|
||||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation) {
|
||||
|
||||
BOOL dotfile = de->namelen > 1 && de->name[0] == '.';
|
||||
|
||||
atts = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -179,6 +188,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
ii = fcb->inode_item;
|
||||
r = fcb->subvol;
|
||||
inode = fcb->inode;
|
||||
atts = fcb->atts;
|
||||
break;
|
||||
|
||||
case DirEntryType_Parent:
|
||||
|
@ -186,6 +196,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
ii = fileref->parent->fcb->inode_item;
|
||||
r = fileref->parent->fcb->subvol;
|
||||
inode = fileref->parent->fcb->inode;
|
||||
atts = fileref->parent->fcb->atts;
|
||||
} else {
|
||||
ERR("no fileref\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
|
@ -208,8 +219,6 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
}
|
||||
}
|
||||
|
||||
dotfile = de->name[0] == '.' && (de->name[1] != '.' || de->name[2] != 0) && (de->name[1] != 0);
|
||||
|
||||
switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
|
||||
case FileBothDirectoryInformation:
|
||||
{
|
||||
|
@ -220,7 +229,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
needed = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
TRACE("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
|
@ -232,9 +241,9 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
fbdi->ChangeTime.QuadPart = 0;
|
||||
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 = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
fbdi->FileAttributes = atts;
|
||||
fbdi->FileNameLength = stringlen;
|
||||
fbdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type);
|
||||
fbdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts);
|
||||
fbdi->ShortNameLength = 0;
|
||||
// fibdi->ShortName[12];
|
||||
|
||||
|
@ -259,7 +268,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
needed = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
TRACE("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
|
@ -271,7 +280,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
fdi->ChangeTime.QuadPart = 0;
|
||||
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 = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
fdi->FileAttributes = atts;
|
||||
fdi->FileNameLength = stringlen;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(fdi->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
@ -295,7 +304,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
needed = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
TRACE("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
|
@ -307,9 +316,9 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
ffdi->ChangeTime.QuadPart = 0;
|
||||
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 = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
ffdi->FileAttributes = atts;
|
||||
ffdi->FileNameLength = stringlen;
|
||||
ffdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type);
|
||||
ffdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts);
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(ffdi->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
||||
|
@ -332,7 +341,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
needed = sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
TRACE("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
|
@ -347,9 +356,9 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
fibdi->ChangeTime.QuadPart = 0;
|
||||
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 = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
fibdi->FileAttributes = atts;
|
||||
fibdi->FileNameLength = stringlen;
|
||||
fibdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type);
|
||||
fibdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts);
|
||||
fibdi->ShortNameLength = 0;
|
||||
// fibdi->ShortName[12];
|
||||
fibdi->FileId.QuadPart = inode;
|
||||
|
@ -379,7 +388,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
|
|||
needed = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
TRACE("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
|
@ -419,19 +428,23 @@ 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(fcb* fcb, file_ref* fileref, UINT64* offset, dir_entry* de, traverse_ptr* tp) {
|
||||
static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_entry* de) {
|
||||
KEY searchkey;
|
||||
traverse_ptr next_tp;
|
||||
traverse_ptr tp, next_tp;
|
||||
DIR_ITEM* di;
|
||||
NTSTATUS Status;
|
||||
file_ref* fr;
|
||||
LIST_ENTRY* le;
|
||||
char* name;
|
||||
|
||||
if (fileref && fileref->parent) { // don't return . and .. if root directory
|
||||
if (fileref->parent) { // don't return . and .. if root directory
|
||||
if (*offset == 0) {
|
||||
de->key.obj_id = fcb->inode;
|
||||
de->key.obj_id = fileref->fcb->inode;
|
||||
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->type = BTRFS_TYPE_DIRECTORY;
|
||||
|
||||
|
@ -444,6 +457,7 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, file_ref* fileref, UINT64* offs
|
|||
de->key.offset = 0;
|
||||
de->dir_entry_type = DirEntryType_Parent;
|
||||
de->name = "..";
|
||||
de->name_alloc = FALSE;
|
||||
de->namelen = 2;
|
||||
de->type = BTRFS_TYPE_DIRECTORY;
|
||||
|
||||
|
@ -453,77 +467,171 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, file_ref* fileref, UINT64* offs
|
|||
}
|
||||
}
|
||||
|
||||
if (!tp->tree) {
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_DIR_INDEX;
|
||||
searchkey.offset = *offset;
|
||||
if (*offset < 2)
|
||||
*offset = 2;
|
||||
|
||||
ExAcquireResourceSharedLite(&fileref->nonpaged->children_lock, TRUE);
|
||||
|
||||
fr = NULL;
|
||||
le = fileref->children.Flink;
|
||||
|
||||
// skip entries before offset
|
||||
while (le != &fileref->children) {
|
||||
file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry);
|
||||
|
||||
Status = find_item(fcb->Vcb, fcb->subvol, tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
tp->tree = NULL;
|
||||
return Status;
|
||||
if (fr2->index >= *offset) {
|
||||
fr = fr2;
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE("found item %llx,%x,%llx\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
|
||||
|
||||
if (keycmp(&tp->item->key, &searchkey) == -1) {
|
||||
if (find_next_item(fcb->Vcb, tp, &next_tp, FALSE)) {
|
||||
*tp = next_tp;
|
||||
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;
|
||||
}
|
||||
|
||||
TRACE("moving on to %llx,%x,%llx\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (tp->item->key.obj_id != searchkey.obj_id || tp->item->key.obj_type != searchkey.obj_type || tp->item->key.offset < *offset) {
|
||||
tp->tree = NULL;
|
||||
return STATUS_NO_MORE_FILES;
|
||||
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);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
*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));
|
||||
|
||||
tp->tree = NULL;
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
if (keycmp(&tp.item->key, &searchkey) == -1) {
|
||||
if (find_next_item(fileref->fcb->Vcb, &tp, &next_tp, FALSE))
|
||||
tp = next_tp;
|
||||
}
|
||||
|
||||
de->key = di->key;
|
||||
de->name = di->name;
|
||||
de->namelen = di->n;
|
||||
de->type = di->type;
|
||||
de->dir_entry_type = DirEntryType_File;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else {
|
||||
if (find_next_item(fcb->Vcb, tp, &next_tp, FALSE)) {
|
||||
if (next_tp.item->key.obj_type == TYPE_DIR_INDEX && next_tp.item->key.obj_id == tp->item->key.obj_id) {
|
||||
*tp = next_tp;
|
||||
|
||||
*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));
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
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);
|
||||
}
|
||||
|
||||
de->key = di->key;
|
||||
de->name = di->name;
|
||||
de->namelen = di->n;
|
||||
de->type = di->type;
|
||||
} 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;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else
|
||||
return STATUS_NO_MORE_FILES;
|
||||
} else
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
*offset = fr->index + 1;
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
goto end;
|
||||
} else {
|
||||
Status = STATUS_NO_MORE_FILES;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
} while (TRUE);
|
||||
|
||||
end:
|
||||
ExReleaseResourceLite(&fileref->nonpaged->children_lock);
|
||||
|
||||
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;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
|
@ -538,8 +646,9 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
ULONG count;
|
||||
BOOL has_wildcard = FALSE, specific_file = FALSE, initial;
|
||||
// UINT64 num_reads_orig;
|
||||
traverse_ptr tp;
|
||||
dir_entry de;
|
||||
UINT64 newoffset;
|
||||
ANSI_STRING utf8;
|
||||
|
||||
TRACE("query directory\n");
|
||||
|
||||
|
@ -552,7 +661,22 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
ccb = IrpSp->FileObject->FsContext2;
|
||||
fileref = ccb ? ccb->fileref : NULL;
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
utf8.Buffer = NULL;
|
||||
|
||||
if (!fileref)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
if (!ccb) {
|
||||
ERR("ccb was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!(ccb->access & FILE_LIST_DIRECTORY)) {
|
||||
WARN("insufficient privileges\n");
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
|
||||
|
||||
TRACE("%S\n", file_desc(IrpSp->FileObject));
|
||||
|
||||
|
@ -593,82 +717,65 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
}
|
||||
}
|
||||
|
||||
if (IrpSp->Parameters.QueryDirectory.FileName) {
|
||||
// int i;
|
||||
// WCHAR* us;
|
||||
|
||||
if (IrpSp->Parameters.QueryDirectory.FileName && IrpSp->Parameters.QueryDirectory.FileName->Length > 1) {
|
||||
TRACE("QD filename: %.*S\n", IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR), IrpSp->Parameters.QueryDirectory.FileName->Buffer);
|
||||
|
||||
// if (IrpSp->Parameters.QueryDirectory.FileName->Length > 1 || IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != '*') {
|
||||
// specific_file = TRUE;
|
||||
// for (i = 0; i < IrpSp->Parameters.QueryDirectory.FileName->Length; i++) {
|
||||
// if (IrpSp->Parameters.QueryDirectory.FileName->Buffer[i] == '?' || IrpSp->Parameters.QueryDirectory.FileName->Buffer[i] == '*') {
|
||||
// has_wildcard = TRUE;
|
||||
// specific_file = FALSE;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
has_wildcard = TRUE;
|
||||
if (IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != '*') {
|
||||
specific_file = TRUE;
|
||||
if (FsRtlDoesNameContainWildCards(IrpSp->Parameters.QueryDirectory.FileName)) {
|
||||
has_wildcard = TRUE;
|
||||
specific_file = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ccb->query_string.Buffer)
|
||||
RtlFreeUnicodeString(&ccb->query_string);
|
||||
|
||||
// us = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length + sizeof(WCHAR), ALLOC_TAG);
|
||||
// RtlCopyMemory(us, IrpSp->Parameters.QueryDirectory.FileName->Buffer, IrpSp->Parameters.QueryDirectory.FileName->Length);
|
||||
// us[IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR)] = 0;
|
||||
|
||||
// ccb->query_string = ExAllocatePoolWithTag(NonPagedPool, utf16_to_utf8_len(us), ALLOC_TAG);
|
||||
// utf16_to_utf8(us, ccb->query_string);
|
||||
|
||||
// ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG);
|
||||
// RtlCopyMemory(ccb->query_string.Buffer, IrpSp->Parameters.QueryDirectory.FileName->Buffer,
|
||||
// IrpSp->Parameters.QueryDirectory.FileName->Length);
|
||||
// ccb->query_string.Length = IrpSp->Parameters.QueryDirectory.FileName->Length;
|
||||
// ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length;
|
||||
if (has_wildcard)
|
||||
RtlUpcaseUnicodeString(&ccb->query_string, IrpSp->Parameters.QueryDirectory.FileName, TRUE);
|
||||
else {
|
||||
ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG);
|
||||
if (!ccb->query_string.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ccb->query_string.Length = ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length;
|
||||
RtlCopyMemory(ccb->query_string.Buffer, IrpSp->Parameters.QueryDirectory.FileName->Buffer, IrpSp->Parameters.QueryDirectory.FileName->Length);
|
||||
}
|
||||
|
||||
ccb->has_wildcard = has_wildcard;
|
||||
ccb->specific_file = specific_file;
|
||||
|
||||
// ExFreePool(us);
|
||||
} else {
|
||||
has_wildcard = ccb->has_wildcard;
|
||||
specific_file = ccb->specific_file;
|
||||
|
||||
if (!(IrpSp->Flags & SL_RESTART_SCAN))
|
||||
if (!(IrpSp->Flags & SL_RESTART_SCAN)) {
|
||||
initial = FALSE;
|
||||
|
||||
if (specific_file) {
|
||||
Status = STATUS_NO_MORE_FILES;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ccb->query_string.Buffer) {
|
||||
TRACE("query string = %.*S\n", ccb->query_string.Length / sizeof(WCHAR), ccb->query_string.Buffer);
|
||||
}
|
||||
|
||||
tp.tree = NULL;
|
||||
Status = next_dir_entry(fcb, fileref, &ccb->query_dir_offset, &de, &tp);
|
||||
newoffset = ccb->query_dir_offset;
|
||||
Status = next_dir_entry(fileref, &newoffset, &de);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
if (Status == STATUS_NO_MORE_FILES && initial)
|
||||
Status = STATUS_NO_SUCH_FILE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// FIXME - make this work
|
||||
// if (specific_file) {
|
||||
// UINT64 filesubvol, fileinode;
|
||||
// WCHAR* us;
|
||||
//
|
||||
// us = ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length + sizeof(WCHAR), ALLOC_TAG);
|
||||
// RtlCopyMemory(us, IrpSp->Parameters.QueryDirectory.FileName->Buffer, IrpSp->Parameters.QueryDirectory.FileName->Length);
|
||||
// us[IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR)] = 0;
|
||||
//
|
||||
// if (!find_file_in_dir(fcb->Vcb, us, fcb->subvolume, fcb->inode, &filesubvol, &fileinode)) {
|
||||
// ExFreePool(us);
|
||||
// return STATUS_NO_MORE_FILES;
|
||||
// }
|
||||
//
|
||||
// ExFreePool(us);
|
||||
// }
|
||||
|
||||
ccb->query_dir_offset = newoffset;
|
||||
|
||||
buf = map_user_buffer(Irp);
|
||||
|
||||
if (Irp->MdlAddress && !buf) {
|
||||
|
@ -679,8 +786,89 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
length = IrpSp->Parameters.QueryDirectory.Length;
|
||||
|
||||
// if (specific_file) {
|
||||
if (has_wildcard) {
|
||||
if (specific_file) {
|
||||
BOOL found = FALSE;
|
||||
root* found_subvol;
|
||||
UINT64 found_inode, found_index;
|
||||
UINT8 found_type;
|
||||
UNICODE_STRING us;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
Status = RtlUpcaseUnicodeString(&us, &ccb->query_string, TRUE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
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 && fr2->filepart_uc.Length == us.Length &&
|
||||
RtlCompareMemory(fr2->filepart_uc.Buffer, us.Buffer, us.Length) == us.Length) {
|
||||
found = TRUE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&fileref->nonpaged->children_lock);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
} else if (has_wildcard) {
|
||||
WCHAR* uni_fn;
|
||||
ULONG stringlen;
|
||||
UNICODE_STRING di_uni_fn;
|
||||
|
@ -709,10 +897,16 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
di_uni_fn.Buffer = uni_fn;
|
||||
|
||||
while (!FsRtlIsNameInExpression(&ccb->query_string, &di_uni_fn, TRUE, NULL)) {
|
||||
Status = next_dir_entry(fcb, fileref, &ccb->query_dir_offset, &de, &tp);
|
||||
if (de.name_alloc)
|
||||
ExFreePool(de.name);
|
||||
|
||||
newoffset = ccb->query_dir_offset;
|
||||
Status = next_dir_entry(fileref, &newoffset, &de);
|
||||
|
||||
ExFreePool(uni_fn);
|
||||
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);
|
||||
|
@ -752,6 +946,9 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
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;
|
||||
|
@ -778,7 +975,8 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
WCHAR* uni_fn = NULL;
|
||||
UNICODE_STRING di_uni_fn;
|
||||
|
||||
Status = next_dir_entry(fcb, fileref, &ccb->query_dir_offset, &de, &tp);
|
||||
newoffset = ccb->query_dir_offset;
|
||||
Status = next_dir_entry(fileref, &newoffset, &de);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (has_wildcard) {
|
||||
ULONG stringlen;
|
||||
|
@ -786,6 +984,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -793,6 +992,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
if (!uni_fn) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
if (de.name_alloc) ExFreePool(de.name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -801,6 +1001,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
ExFreePool(uni_fn);
|
||||
if (de.name_alloc) ExFreePool(de.name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -821,19 +1022,24 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
ULONG* lastoffset = (ULONG*)lastitem;
|
||||
|
||||
*lastoffset = (ULONG)(curitem - lastitem);
|
||||
ccb->query_dir_offset = newoffset;
|
||||
|
||||
lastitem = curitem;
|
||||
} else {
|
||||
if (uni_fn) ExFreePool(uni_fn);
|
||||
|
||||
if (de.name_alloc) ExFreePool(de.name);
|
||||
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;
|
||||
|
@ -848,10 +1054,12 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
Irp->IoStatus.Information = IrpSp->Parameters.QueryDirectory.Length - length;
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
|
||||
|
||||
// TRACE("query directory performed %u reads\n", (UINT32)(num_reads-num_reads_orig));
|
||||
TRACE("returning %08x\n", Status);
|
||||
|
||||
if (utf8.Buffer)
|
||||
ExFreePool(utf8.Buffer);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -863,16 +1071,26 @@ static NTSTATUS STDCALL notify_change_directory(device_extension* Vcb, PIRP Irp)
|
|||
ccb* ccb = FileObject->FsContext2;
|
||||
file_ref* fileref = ccb->fileref;
|
||||
NTSTATUS Status;
|
||||
// WCHAR fn[MAX_PATH];
|
||||
|
||||
TRACE("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
|
||||
|
||||
if (!ccb) {
|
||||
ERR("ccb was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!fileref) {
|
||||
ERR("no fileref\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
if (!(ccb->access & FILE_LIST_DIRECTORY)) {
|
||||
WARN("insufficient privileges\n");
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
|
||||
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
|
||||
|
||||
if (fcb->type != BTRFS_TYPE_DIRECTORY) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
|
@ -882,14 +1100,24 @@ static NTSTATUS STDCALL notify_change_directory(device_extension* Vcb, PIRP Irp)
|
|||
// FIXME - raise exception if FCB marked for deletion?
|
||||
|
||||
TRACE("%S\n", file_desc(FileObject));
|
||||
|
||||
if (ccb->filename.Length == 0) {
|
||||
Status = fileref_get_filename(fileref, &ccb->filename, NULL);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("fileref_get_filename returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext2, (PSTRING)&fileref->full_filename,
|
||||
IrpSp->Flags & SL_WATCH_TREE, FALSE, IrpSp->Parameters.NotifyDirectory.CompletionFilter, Irp, NULL, NULL);
|
||||
FsRtlNotifyFilterChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext2, (PSTRING)&ccb->filename,
|
||||
IrpSp->Flags & SL_WATCH_TREE, FALSE, IrpSp->Parameters.NotifyDirectory.CompletionFilter, Irp,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
Status = STATUS_PENDING;
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -899,6 +1127,7 @@ NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP I
|
|||
NTSTATUS Status;
|
||||
ULONG func;
|
||||
BOOL top_level;
|
||||
device_extension* Vcb = DeviceObject->DeviceExtension;
|
||||
|
||||
TRACE("directory control\n");
|
||||
|
||||
|
@ -906,6 +1135,11 @@ NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP I
|
|||
|
||||
top_level = is_top_level(Irp);
|
||||
|
||||
if (Vcb && Vcb->type == VCB_TYPE_PARTITION0) {
|
||||
Status = part0_passthrough(DeviceObject, Irp);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
@ -914,7 +1148,7 @@ NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP I
|
|||
|
||||
switch (func) {
|
||||
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
|
||||
Status = notify_change_directory(DeviceObject->DeviceExtension, Irp);
|
||||
Status = notify_change_directory(Vcb, Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_QUERY_DIRECTORY:
|
||||
|
@ -927,16 +1161,18 @@ NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP I
|
|||
Irp->IoStatus.Status = Status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (func != IRP_MN_NOTIFY_CHANGE_DIRECTORY || Status != STATUS_PENDING) {
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
if (Irp->UserIosb)
|
||||
*Irp->UserIosb = Irp->IoStatus;
|
||||
|
||||
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
|
||||
}
|
||||
|
||||
if (Status == STATUS_PENDING)
|
||||
goto exit;
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
// if (Irp->UserIosb)
|
||||
// *Irp->UserIosb = Irp->IoStatus;
|
||||
|
||||
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
||||
|
||||
exit:
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ static __inline ULONG get_extent_data_len(UINT8 type) {
|
|||
case TYPE_EXTENT_DATA_REF:
|
||||
return sizeof(EXTENT_DATA_REF);
|
||||
|
||||
// FIXME - TYPE_EXTENT_REF_V0
|
||||
case TYPE_EXTENT_REF_V0:
|
||||
return sizeof(EXTENT_REF_V0);
|
||||
|
||||
// FIXME - TYPE_SHARED_BLOCK_REF
|
||||
|
||||
case TYPE_SHARED_DATA_REF:
|
||||
|
@ -47,7 +49,12 @@ static __inline UINT64 get_extent_data_refcount(UINT8 type, void* data) {
|
|||
return edr->count;
|
||||
}
|
||||
|
||||
// FIXME - TYPE_EXTENT_REF_V0
|
||||
case TYPE_EXTENT_REF_V0:
|
||||
{
|
||||
EXTENT_REF_V0* erv0 = (EXTENT_REF_V0*)data;
|
||||
return erv0->count;
|
||||
}
|
||||
|
||||
// FIXME - TYPE_SHARED_BLOCK_REF
|
||||
|
||||
case TYPE_SHARED_DATA_REF:
|
||||
|
@ -61,16 +68,20 @@ static __inline UINT64 get_extent_data_refcount(UINT8 type, void* data) {
|
|||
}
|
||||
}
|
||||
|
||||
static UINT64 get_extent_data_ref_hash(EXTENT_DATA_REF* edr) {
|
||||
static 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*)&edr->root, sizeof(UINT64));
|
||||
low_crc = calc_crc32c(low_crc, (UINT8*)&edr->objid, sizeof(UINT64));
|
||||
low_crc = calc_crc32c(low_crc, (UINT8*)&edr->offset, sizeof(UINT64));
|
||||
high_crc = calc_crc32c(high_crc, (UINT8*)&root, sizeof(UINT64));
|
||||
low_crc = calc_crc32c(low_crc, (UINT8*)&objid, sizeof(UINT64));
|
||||
low_crc = calc_crc32c(low_crc, (UINT8*)&offset, sizeof(UINT64));
|
||||
|
||||
return ((UINT64)high_crc << 31) ^ (UINT64)low_crc;
|
||||
}
|
||||
|
||||
static __inline UINT64 get_extent_data_ref_hash(EXTENT_DATA_REF* edr) {
|
||||
return get_extent_data_ref_hash2(edr->root, edr->objid, edr->offset);
|
||||
}
|
||||
|
||||
static UINT64 get_extent_hash(UINT8 type, void* data) {
|
||||
if (type == TYPE_EXTENT_DATA_REF) {
|
||||
return get_extent_data_ref_hash((EXTENT_DATA_REF*)data);
|
||||
|
@ -153,17 +164,40 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
} else if (tp.item->key.offset != size) {
|
||||
ERR("extent %llx exists, but with size %llx rather than %llx expected\n", tp.item->key.obj_id, tp.item->key.offset, size);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
} else if (tp.item->size == sizeof(EXTENT_ITEM_V0)) {
|
||||
}
|
||||
|
||||
if (tp.item->size == sizeof(EXTENT_ITEM_V0)) {
|
||||
EXTENT_ITEM_V0* eiv0 = (EXTENT_ITEM_V0*)tp.item->data;
|
||||
|
||||
TRACE("converting old-style extent at (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
|
||||
Status = convert_old_data_extent(Vcb, address, size, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("convert_old_data_extent returned %08x\n", Status);
|
||||
return Status;
|
||||
ei = ExAllocatePoolWithTag(PagedPool, sizeof(EXTENT_ITEM), ALLOC_TAG);
|
||||
|
||||
if (!ei) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
return increase_extent_refcount(Vcb, address, size, type, data, firstitem, level, rollback);
|
||||
} else if (tp.item->size < sizeof(EXTENT_ITEM)) {
|
||||
ei->refcount = eiv0->refcount;
|
||||
ei->generation = Vcb->superblock.generation;
|
||||
ei->flags = EXTENT_ITEM_DATA;
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
|
||||
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, ei, sizeof(EXTENT_ITEM), NULL, rollback)) {
|
||||
ERR("insert_tree_item failed\n");
|
||||
ExFreePool(ei);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
if (tp.item->size < sizeof(EXTENT_ITEM)) {
|
||||
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(EXTENT_ITEM));
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
@ -204,18 +238,6 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (secttype == TYPE_SHARED_DATA_REF) {
|
||||
TRACE("found shared data extent at %llx, converting\n", tp.item->key.obj_id);
|
||||
|
||||
Status = convert_shared_data_extent(Vcb, address, size, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("convert_shared_data_extent returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
return increase_extent_refcount(Vcb, address, size, type, data, firstitem, level, rollback);
|
||||
}
|
||||
|
||||
// If inline extent already present, increase refcount and return
|
||||
|
||||
if (secttype == type) {
|
||||
|
@ -286,8 +308,6 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
if (secttype > type)
|
||||
break;
|
||||
|
||||
len--;
|
||||
|
||||
if (secttype == type) {
|
||||
UINT64 sectoff = get_extent_hash(secttype, ptr + 1);
|
||||
|
||||
|
@ -295,7 +315,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
break;
|
||||
}
|
||||
|
||||
len -= sectlen;
|
||||
len -= sectlen + sizeof(UINT8);
|
||||
ptr += sizeof(UINT8) + sectlen;
|
||||
}
|
||||
|
||||
|
@ -306,7 +326,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
newei->refcount += get_extent_data_refcount(type, data);
|
||||
|
||||
if (len > 0)
|
||||
RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data) + sizeof(UINT8) + datalen, ptr, len + 1);
|
||||
RtlCopyMemory((UINT8*)newei + (ptr - tp.item->data) + sizeof(UINT8) + datalen, ptr, len);
|
||||
|
||||
ptr = (ptr - tp.item->data) + (UINT8*)newei;
|
||||
|
||||
|
@ -409,10 +429,10 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback) {
|
||||
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback) {
|
||||
EXTENT_DATA_REF edr;
|
||||
|
||||
edr.root = subvol->id;
|
||||
edr.root = root;
|
||||
edr.objid = inode;
|
||||
edr.offset = offset;
|
||||
edr.count = refcount;
|
||||
|
@ -426,57 +446,16 @@ void decrease_chunk_usage(chunk* c, UINT64 delta) {
|
|||
TRACE("decreasing size of chunk %llx by %llx\n", c->offset, delta);
|
||||
}
|
||||
|
||||
static NTSTATUS remove_extent(device_extension* Vcb, UINT64 address, UINT64 size, LIST_ENTRY* changed_sector_list) {
|
||||
chunk* c;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
if (changed_sector_list) {
|
||||
changed_sector* sc = ExAllocatePoolWithTag(PagedPool, sizeof(changed_sector), ALLOC_TAG);
|
||||
if (!sc) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
sc->ol.key = address;
|
||||
sc->checksums = NULL;
|
||||
sc->length = size / Vcb->superblock.sector_size;
|
||||
|
||||
sc->deleted = TRUE;
|
||||
|
||||
insert_into_ordered_list(changed_sector_list, &sc->ol);
|
||||
}
|
||||
|
||||
c = NULL;
|
||||
le = Vcb->chunks.Flink;
|
||||
while (le != &Vcb->chunks) {
|
||||
c = CONTAINING_RECORD(le, chunk, list_entry);
|
||||
|
||||
if (address >= c->offset && address + size < c->offset + c->chunk_item->size)
|
||||
break;
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
if (le == &Vcb->chunks) c = NULL;
|
||||
|
||||
if (c) {
|
||||
decrease_chunk_usage(c, size);
|
||||
|
||||
add_to_space_list(c, address, size, SPACE_TYPE_DELETING);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem,
|
||||
UINT8 level, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback) {
|
||||
UINT8 level, UINT64 parent, LIST_ENTRY* rollback) {
|
||||
KEY searchkey;
|
||||
NTSTATUS Status;
|
||||
traverse_ptr tp, tp2;
|
||||
EXTENT_ITEM* ei;
|
||||
ULONG len;
|
||||
UINT64 inline_rc, offset;
|
||||
UINT64 inline_rc;
|
||||
UINT8* ptr;
|
||||
UINT32 rc = get_extent_data_refcount(type, data);
|
||||
UINT32 rc = data ? get_extent_data_refcount(type, data) : 1;
|
||||
ULONG datalen = get_extent_data_len(type);
|
||||
|
||||
// FIXME - handle trees
|
||||
|
@ -502,15 +481,34 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
}
|
||||
|
||||
if (tp.item->size == sizeof(EXTENT_ITEM_V0)) {
|
||||
EXTENT_ITEM_V0* eiv0 = (EXTENT_ITEM_V0*)tp.item->data;
|
||||
|
||||
TRACE("converting old-style extent at (%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
|
||||
Status = convert_old_data_extent(Vcb, address, size, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("convert_old_data_extent returned %08x\n", Status);
|
||||
return Status;
|
||||
ei = ExAllocatePoolWithTag(PagedPool, sizeof(EXTENT_ITEM), ALLOC_TAG);
|
||||
|
||||
if (!ei) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
return decrease_extent_refcount(Vcb, address, size, type, data, firstitem, level, changed_sector_list, rollback);
|
||||
ei->refcount = eiv0->refcount;
|
||||
ei->generation = Vcb->superblock.generation;
|
||||
ei->flags = EXTENT_ITEM_DATA;
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
|
||||
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, ei, sizeof(EXTENT_ITEM), &tp, rollback)) {
|
||||
ERR("insert_tree_item failed\n");
|
||||
ExFreePool(ei);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
if (tp.item->size < sizeof(EXTENT_ITEM)) {
|
||||
|
@ -559,18 +557,6 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (secttype == TYPE_SHARED_DATA_REF) {
|
||||
TRACE("found shared data extent at %llx, converting\n", tp.item->key.obj_id);
|
||||
|
||||
Status = convert_shared_data_extent(Vcb, address, size, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("convert_shared_data_extent returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
return decrease_extent_refcount(Vcb, address, size, type, data, firstitem, level, changed_sector_list, rollback);
|
||||
}
|
||||
|
||||
if (secttype == type) {
|
||||
if (type == TYPE_EXTENT_DATA_REF) {
|
||||
EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)(ptr + sizeof(UINT8));
|
||||
|
@ -580,12 +566,6 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
|
||||
if (sectedr->root == edr->root && sectedr->objid == edr->objid && sectedr->offset == edr->offset) {
|
||||
if (ei->refcount == edr->count) {
|
||||
Status = remove_extent(Vcb, address, size, changed_sector_list);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("remove_extent returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -631,9 +611,45 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
// } else if (type == TYPE_TREE_BLOCK_REF) {
|
||||
// ERR("trying to increase refcount of tree extent\n");
|
||||
// return STATUS_INTERNAL_ERROR;
|
||||
} else if (type == TYPE_SHARED_DATA_REF) {
|
||||
SHARED_DATA_REF* sectsdr = (SHARED_DATA_REF*)(ptr + sizeof(UINT8));
|
||||
SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data;
|
||||
ULONG neweilen;
|
||||
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);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
neweilen = tp.item->size - sizeof(UINT8) - sectlen;
|
||||
|
||||
newei = ExAllocatePoolWithTag(PagedPool, neweilen, ALLOC_TAG);
|
||||
if (!newei) {
|
||||
ERR("out of memory\n");
|
||||
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;
|
||||
newei->refcount -= rc;
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
|
||||
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, neweilen, NULL, rollback)) {
|
||||
ERR("insert_tree_item failed\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
ERR("unhandled extent type %x\n", type);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
|
@ -650,11 +666,9 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
offset = get_extent_hash(type, data);
|
||||
|
||||
searchkey.obj_id = address;
|
||||
searchkey.obj_type = type;
|
||||
searchkey.offset = offset;
|
||||
searchkey.offset = (type == TYPE_SHARED_DATA_REF || type == TYPE_EXTENT_REF_V0) ? parent : get_extent_hash(type, data);
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp2, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
|
@ -679,12 +693,6 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
|
||||
if (sectedr->root == edr->root && sectedr->objid == edr->objid && sectedr->offset == edr->offset) {
|
||||
if (ei->refcount == edr->count) {
|
||||
Status = remove_extent(Vcb, address, size, changed_sector_list);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("remove_extent returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
delete_tree_item(Vcb, &tp2, rollback);
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -738,25 +746,105 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
|
|||
ERR("error - hash collision?\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
// } else if (type == TYPE_TREE_BLOCK_REF) {
|
||||
// ERR("trying to increase refcount of tree extent\n");
|
||||
// return STATUS_INTERNAL_ERROR;
|
||||
} else if (type == TYPE_SHARED_DATA_REF) {
|
||||
SHARED_DATA_REF* sectsdr = (SHARED_DATA_REF*)tp2.item->data;
|
||||
SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)data;
|
||||
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) {
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
delete_tree_item(Vcb, &tp2, rollback);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
delete_tree_item(Vcb, &tp2, rollback);
|
||||
|
||||
newei = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
|
||||
if (!newei) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(newei, tp.item->data, tp.item->size);
|
||||
|
||||
newei->generation = Vcb->superblock.generation;
|
||||
newei->refcount -= rc;
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
|
||||
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
|
||||
ERR("insert_tree_item failed\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else {
|
||||
ERR("error - collision?\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
} else if (type == TYPE_EXTENT_REF_V0) {
|
||||
EXTENT_REF_V0* erv0 = (EXTENT_REF_V0*)tp2.item->data;
|
||||
EXTENT_ITEM* newei;
|
||||
|
||||
if (ei->refcount == erv0->count) {
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
delete_tree_item(Vcb, &tp2, rollback);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
delete_tree_item(Vcb, &tp2, rollback);
|
||||
|
||||
newei = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
|
||||
if (!newei) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(newei, tp.item->data, tp.item->size);
|
||||
|
||||
newei->generation = Vcb->superblock.generation;
|
||||
newei->refcount -= rc;
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
|
||||
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
|
||||
ERR("insert_tree_item failed\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else {
|
||||
ERR("unhandled extent type %x\n", type);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode,
|
||||
UINT64 offset, UINT32 refcount, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback) {
|
||||
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode,
|
||||
UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback) {
|
||||
EXTENT_DATA_REF edr;
|
||||
|
||||
edr.root = subvol->id;
|
||||
edr.root = root;
|
||||
edr.objid = inode;
|
||||
edr.offset = offset;
|
||||
edr.count = refcount;
|
||||
|
||||
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, changed_sector_list, rollback);
|
||||
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, 0, rollback);
|
||||
}
|
||||
|
||||
NTSTATUS decrease_extent_refcount_shared_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, UINT64 parent, LIST_ENTRY* rollback) {
|
||||
SHARED_DATA_REF sdr;
|
||||
|
||||
sdr.offset = treeaddr;
|
||||
sdr.count = 1;
|
||||
|
||||
return decrease_extent_refcount(Vcb, address, size, TYPE_SHARED_DATA_REF, &sdr, NULL, 0, parent, rollback);
|
||||
}
|
||||
|
||||
NTSTATUS decrease_extent_refcount_old(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, LIST_ENTRY* rollback) {
|
||||
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_REF_V0, NULL, NULL, 0, treeaddr, rollback);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
@ -954,9 +1042,9 @@ static NTSTATUS populate_extent_refs_from_tree(device_extension* Vcb, UINT64 tre
|
|||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
Status = read_tree(Vcb, tree_address, buf);
|
||||
Status = read_data(Vcb, tree_address, Vcb->superblock.node_size, NULL, TRUE, buf, NULL, NULL);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_tree returned %08x\n", Status);
|
||||
ERR("read_data returned %08x\n", Status);
|
||||
ExFreePool(buf);
|
||||
return Status;
|
||||
}
|
||||
|
@ -993,177 +1081,6 @@ static NTSTATUS populate_extent_refs_from_tree(device_extension* Vcb, UINT64 tre
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS convert_shared_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, LIST_ENTRY* rollback) {
|
||||
KEY searchkey;
|
||||
traverse_ptr tp;
|
||||
LIST_ENTRY extent_refs;
|
||||
LIST_ENTRY *le, *next_le;
|
||||
EXTENT_ITEM* ei;
|
||||
UINT64 eiflags, inline_rc;
|
||||
UINT8* siptr;
|
||||
ULONG len;
|
||||
NTSTATUS Status;
|
||||
|
||||
searchkey.obj_id = address;
|
||||
searchkey.obj_type = TYPE_EXTENT_ITEM;
|
||||
searchkey.offset = size;
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (keycmp(&tp.item->key, &searchkey)) {
|
||||
WARN("extent item not found for address %llx, size %llx\n", address, size);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (tp.item->size < sizeof(EXTENT_ITEM)) {
|
||||
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(EXTENT_ITEM));
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ei = (EXTENT_ITEM*)tp.item->data;
|
||||
len = tp.item->size - sizeof(EXTENT_ITEM);
|
||||
eiflags = ei->flags;
|
||||
|
||||
InitializeListHead(&extent_refs);
|
||||
|
||||
inline_rc = 0;
|
||||
siptr = (UINT8*)&ei[1];
|
||||
|
||||
do {
|
||||
extent_ref* er;
|
||||
ULONG extlen;
|
||||
|
||||
extlen = get_extent_data_len(*siptr);
|
||||
|
||||
if (extlen == 0) {
|
||||
ERR("unrecognized extent subitem %x\n", *siptr);
|
||||
free_extent_refs(&extent_refs);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (extlen > len - 1) {
|
||||
ERR("extent %llx was truncated\n", address);
|
||||
free_extent_refs(&extent_refs);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
er = ExAllocatePoolWithTag(PagedPool, sizeof(extent_ref), ALLOC_TAG);
|
||||
if (!er) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
er->type = *siptr;
|
||||
|
||||
er->data = ExAllocatePoolWithTag(PagedPool, extlen, ALLOC_TAG);
|
||||
if (!er->data) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(er);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(er->data, siptr+1, extlen);
|
||||
er->allocated = TRUE;
|
||||
|
||||
InsertTailList(&extent_refs, &er->list_entry);
|
||||
|
||||
siptr += extlen;
|
||||
len -= extlen + 1;
|
||||
|
||||
inline_rc += get_extent_data_refcount(er->type, er->data);
|
||||
} while (len > 0);
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
|
||||
if (inline_rc < ei->refcount) {
|
||||
BOOL b;
|
||||
traverse_ptr next_tp;
|
||||
|
||||
do {
|
||||
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
|
||||
|
||||
if (tp.item->key.obj_id == address) {
|
||||
ULONG extlen;
|
||||
|
||||
extlen = get_extent_data_len(tp.item->key.obj_type);
|
||||
|
||||
if (extlen != 0 && tp.item->size >= extlen) {
|
||||
extent_ref* er = ExAllocatePoolWithTag(PagedPool, sizeof(extent_ref), ALLOC_TAG);
|
||||
if (!er) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
er->type = tp.item->key.obj_type;
|
||||
|
||||
er->data = ExAllocatePoolWithTag(PagedPool, extlen, ALLOC_TAG);
|
||||
if (!er->data) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(er);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(er->data, siptr+1, extlen);
|
||||
er->allocated = TRUE;
|
||||
|
||||
InsertTailList(&extent_refs, &er->list_entry);
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
}
|
||||
}
|
||||
|
||||
if (b) {
|
||||
tp = next_tp;
|
||||
|
||||
if (tp.item->key.obj_id > address)
|
||||
break;
|
||||
}
|
||||
} while (b);
|
||||
}
|
||||
|
||||
le = extent_refs.Flink;
|
||||
while (le != &extent_refs) {
|
||||
extent_ref* er = CONTAINING_RECORD(le, extent_ref, list_entry);
|
||||
next_le = le->Flink;
|
||||
|
||||
if (er->type == TYPE_SHARED_DATA_REF) {
|
||||
SHARED_DATA_REF* sdr = er->data;
|
||||
|
||||
Status = populate_extent_refs_from_tree(Vcb, sdr->offset, address, &extent_refs);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("populate_extent_refs_from_tree returned %08x\n", Status);
|
||||
free_extent_refs(&extent_refs);
|
||||
return Status;
|
||||
}
|
||||
|
||||
RemoveEntryList(&er->list_entry);
|
||||
|
||||
if (er->allocated)
|
||||
ExFreePool(er->data);
|
||||
|
||||
ExFreePool(er);
|
||||
}
|
||||
// FIXME - also do for SHARED_BLOCK_REF?
|
||||
|
||||
le = next_le;
|
||||
}
|
||||
|
||||
Status = construct_extent_item(Vcb, address, size, eiflags, &extent_refs, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("construct_extent_item returned %08x\n", Status);
|
||||
free_extent_refs(&extent_refs);
|
||||
return Status;
|
||||
}
|
||||
|
||||
free_extent_refs(&extent_refs);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, LIST_ENTRY* rollback) {
|
||||
KEY searchkey;
|
||||
traverse_ptr tp, next_tp;
|
||||
|
@ -1237,3 +1154,241 @@ NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 s
|
|||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset) {
|
||||
NTSTATUS Status;
|
||||
KEY searchkey;
|
||||
traverse_ptr tp;
|
||||
EXTENT_DATA_REF* edr;
|
||||
BOOL old = FALSE;
|
||||
|
||||
searchkey.obj_id = address;
|
||||
searchkey.obj_type = TYPE_EXTENT_ITEM;
|
||||
searchkey.offset = 0xffffffffffffffff;
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
|
||||
ERR("could not find address %llx in extent tree\n", address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tp.item->key.offset != size) {
|
||||
ERR("extent %llx had size %llx, not %llx as expected\n", address, tp.item->key.offset, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tp.item->size >= sizeof(EXTENT_ITEM)) {
|
||||
EXTENT_ITEM* ei = (EXTENT_ITEM*)tp.item->data;
|
||||
UINT32 len = tp.item->size - sizeof(EXTENT_ITEM);
|
||||
UINT8* ptr = (UINT8*)&ei[1];
|
||||
|
||||
while (len > 0) {
|
||||
UINT8 secttype = *ptr;
|
||||
ULONG sectlen = get_extent_data_len(secttype);
|
||||
UINT64 sectcount = get_extent_data_refcount(secttype, ptr + sizeof(UINT8));
|
||||
|
||||
len--;
|
||||
|
||||
if (sectlen > len) {
|
||||
ERR("(%llx,%x,%llx): %x bytes left, expecting at least %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sectlen == 0) {
|
||||
ERR("(%llx,%x,%llx): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (secttype == TYPE_EXTENT_DATA_REF) {
|
||||
EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)(ptr + sizeof(UINT8));
|
||||
|
||||
if (sectedr->root == root && sectedr->objid == objid && sectedr->offset == offset)
|
||||
return sectcount;
|
||||
} else if (secttype == TYPE_SHARED_DATA_REF) {
|
||||
SHARED_DATA_REF* sectsdr = (SHARED_DATA_REF*)(ptr + sizeof(UINT8));
|
||||
BOOL found = FALSE;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
le = Vcb->shared_extents.Flink;
|
||||
while (le != &Vcb->shared_extents) {
|
||||
shared_data* sd = CONTAINING_RECORD(le, shared_data, list_entry);
|
||||
|
||||
if (sd->address == sectsdr->offset) {
|
||||
LIST_ENTRY* le2 = sd->entries.Flink;
|
||||
while (le2 != &sd->entries) {
|
||||
shared_data_entry* sde = CONTAINING_RECORD(le2, shared_data_entry, list_entry);
|
||||
|
||||
if (sde->edr.root == root && sde->edr.objid == objid && sde->edr.offset == offset)
|
||||
return sde->edr.count;
|
||||
|
||||
le2 = le2->Flink;
|
||||
}
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
WARN("shared data extents not loaded for tree at %llx\n", sectsdr->offset);
|
||||
}
|
||||
|
||||
len -= sectlen;
|
||||
ptr += sizeof(UINT8) + sectlen;
|
||||
}
|
||||
} else if (tp.item->size == sizeof(EXTENT_ITEM_V0))
|
||||
old = TRUE;
|
||||
|
||||
searchkey.obj_id = address;
|
||||
searchkey.obj_type = TYPE_EXTENT_DATA_REF;
|
||||
searchkey.offset = get_extent_data_ref_hash2(root, objid, offset);
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!keycmp(&searchkey, &tp.item->key)) {
|
||||
if (tp.item->size < sizeof(EXTENT_DATA_REF))
|
||||
ERR("(%llx,%x,%llx) has size %u, not %u as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA_REF));
|
||||
else {
|
||||
edr = (EXTENT_DATA_REF*)tp.item->data;
|
||||
|
||||
return edr->count;
|
||||
}
|
||||
}
|
||||
|
||||
if (old) {
|
||||
BOOL b;
|
||||
|
||||
searchkey.obj_id = address;
|
||||
searchkey.obj_type = TYPE_EXTENT_REF_V0;
|
||||
searchkey.offset = 0;
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
traverse_ptr next_tp;
|
||||
|
||||
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
|
||||
|
||||
if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
|
||||
if (tp.item->size >= sizeof(EXTENT_REF_V0)) {
|
||||
EXTENT_REF_V0* erv0 = (EXTENT_REF_V0*)tp.item->data;
|
||||
|
||||
if (erv0->root == root && erv0->objid == objid) {
|
||||
LIST_ENTRY* le;
|
||||
BOOL found = FALSE;
|
||||
|
||||
le = Vcb->shared_extents.Flink;
|
||||
while (le != &Vcb->shared_extents) {
|
||||
shared_data* sd = CONTAINING_RECORD(le, shared_data, list_entry);
|
||||
|
||||
if (sd->address == tp.item->key.offset) {
|
||||
LIST_ENTRY* le2 = sd->entries.Flink;
|
||||
while (le2 != &sd->entries) {
|
||||
shared_data_entry* sde = CONTAINING_RECORD(le2, shared_data_entry, list_entry);
|
||||
|
||||
if (sde->edr.root == root && sde->edr.objid == objid && sde->edr.offset == offset)
|
||||
return sde->edr.count;
|
||||
|
||||
le2 = le2->Flink;
|
||||
}
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
WARN("shared data extents not loaded for tree at %llx\n", tp.item->key.offset);
|
||||
}
|
||||
} else {
|
||||
ERR("(%llx,%x,%llx) was %x bytes, not %x as expected\n", tp.item->key.obj_id, tp.item->key.obj_type,
|
||||
tp.item->key.offset, tp.item->size, sizeof(EXTENT_REF_V0));
|
||||
}
|
||||
}
|
||||
|
||||
if (b) {
|
||||
tp = next_tp;
|
||||
|
||||
if (tp.item->key.obj_id > searchkey.obj_id || (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type > searchkey.obj_type))
|
||||
break;
|
||||
}
|
||||
} while (b);
|
||||
} else {
|
||||
BOOL b;
|
||||
|
||||
searchkey.obj_id = address;
|
||||
searchkey.obj_type = TYPE_SHARED_DATA_REF;
|
||||
searchkey.offset = 0;
|
||||
|
||||
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
traverse_ptr next_tp;
|
||||
|
||||
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
|
||||
|
||||
if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
|
||||
if (tp.item->size >= sizeof(SHARED_DATA_REF)) {
|
||||
SHARED_DATA_REF* sdr = (SHARED_DATA_REF*)tp.item->data;
|
||||
LIST_ENTRY* le;
|
||||
BOOL found = FALSE;
|
||||
|
||||
le = Vcb->shared_extents.Flink;
|
||||
while (le != &Vcb->shared_extents) {
|
||||
shared_data* sd = CONTAINING_RECORD(le, shared_data, list_entry);
|
||||
|
||||
if (sd->address == sdr->offset) {
|
||||
LIST_ENTRY* le2 = sd->entries.Flink;
|
||||
while (le2 != &sd->entries) {
|
||||
shared_data_entry* sde = CONTAINING_RECORD(le2, shared_data_entry, list_entry);
|
||||
|
||||
if (sde->edr.root == root && sde->edr.objid == objid && sde->edr.offset == offset)
|
||||
return sde->edr.count;
|
||||
|
||||
le2 = le2->Flink;
|
||||
}
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
WARN("shared data extents not loaded for tree at %llx\n", sdr->offset);
|
||||
} else {
|
||||
ERR("(%llx,%x,%llx) was %x bytes, not %x as expected\n", tp.item->key.obj_id, tp.item->key.obj_type,
|
||||
tp.item->key.offset, tp.item->size, sizeof(SHARED_DATA_REF));
|
||||
}
|
||||
}
|
||||
|
||||
if (b) {
|
||||
tp = next_tp;
|
||||
|
||||
if (tp.item->key.obj_id > searchkey.obj_id || (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type > searchkey.obj_type))
|
||||
break;
|
||||
}
|
||||
} while (b);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
* 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 <ntifs.h>
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
FAST_IO_DISPATCH FastIoDispatch;
|
||||
|
@ -28,20 +27,128 @@ static void STDCALL release_file_for_create_section(PFILE_OBJECT FileObject) {
|
|||
TRACE("STUB: release_file_for_create_section\n");
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_BASIC_INFORMATION buf,
|
||||
PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
|
||||
static BOOLEAN STDCALL fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_BASIC_INFORMATION fbi,
|
||||
PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
|
||||
fcb* fcb;
|
||||
ccb* ccb;
|
||||
|
||||
TRACE("STUB: fast_query_basic_info\n");
|
||||
TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fbi, IoStatus, DeviceObject);
|
||||
|
||||
return FALSE;
|
||||
if (!FileObject)
|
||||
return FALSE;
|
||||
|
||||
fcb = FileObject->FsContext;
|
||||
|
||||
if (!fcb)
|
||||
return FALSE;
|
||||
|
||||
ccb = FileObject->FsContext2;
|
||||
|
||||
if (!ccb)
|
||||
return FALSE;
|
||||
|
||||
if (!(ccb->access & (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES)))
|
||||
return FALSE;
|
||||
|
||||
if (fcb->ads) {
|
||||
if (!ccb || !ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb)
|
||||
return FALSE;
|
||||
|
||||
fcb = ccb->fileref->parent->fcb;
|
||||
}
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
|
||||
FsRtlExitFileSystem();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fbi->CreationTime.QuadPart = unix_time_to_win(&fcb->inode_item.otime);
|
||||
fbi->LastAccessTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_atime);
|
||||
fbi->LastWriteTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_mtime);
|
||||
fbi->ChangeTime.QuadPart = 0;
|
||||
fbi->FileAttributes = fcb->atts;
|
||||
|
||||
IoStatus->Status = STATUS_SUCCESS;
|
||||
IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
|
||||
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_query_standard_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_STANDARD_INFORMATION buf,
|
||||
PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
|
||||
static BOOLEAN STDCALL fast_query_standard_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_STANDARD_INFORMATION fsi,
|
||||
PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
|
||||
fcb* fcb;
|
||||
ccb* ccb;
|
||||
BOOL ads;
|
||||
ULONG adssize;
|
||||
|
||||
TRACE("STUB: fast_query_standard_info\n");
|
||||
TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fsi, IoStatus, DeviceObject);
|
||||
|
||||
return FALSE;
|
||||
if (!FileObject)
|
||||
return FALSE;
|
||||
|
||||
fcb = FileObject->FsContext;
|
||||
ccb = FileObject->FsContext2;
|
||||
|
||||
if (!fcb)
|
||||
return FALSE;
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
|
||||
FsRtlExitFileSystem();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ads = fcb->ads;
|
||||
|
||||
if (ads) {
|
||||
struct _fcb* fcb2;
|
||||
|
||||
if (!ccb || !ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb) {
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
FsRtlExitFileSystem();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
adssize = fcb->adsdata.Length;
|
||||
|
||||
fcb2 = ccb->fileref->parent->fcb;
|
||||
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
|
||||
fcb = fcb2;
|
||||
|
||||
if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
|
||||
FsRtlExitFileSystem();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fsi->AllocationSize.QuadPart = fsi->EndOfFile.QuadPart = adssize;
|
||||
fsi->NumberOfLinks = fcb->inode_item.st_nlink;
|
||||
fsi->Directory = S_ISDIR(fcb->inode_item.st_mode);
|
||||
} else {
|
||||
fsi->AllocationSize.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 : sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
|
||||
fsi->EndOfFile.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 : fcb->inode_item.st_size;
|
||||
fsi->NumberOfLinks = fcb->inode_item.st_nlink;
|
||||
fsi->Directory = S_ISDIR(fcb->inode_item.st_mode);
|
||||
}
|
||||
|
||||
fsi->DeletePending = ccb->fileref ? ccb->fileref->delete_on_close : FALSE;
|
||||
|
||||
IoStatus->Status = STATUS_SUCCESS;
|
||||
IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
|
||||
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_query_open(PIRP Irp, PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, PDEVICE_OBJECT DeviceObject) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -26,16 +26,16 @@ static void do_flush(device_extension* Vcb) {
|
|||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
acquire_tree_lock(Vcb, TRUE);
|
||||
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
|
||||
|
||||
if (Vcb->write_trees > 0)
|
||||
if (Vcb->need_write)
|
||||
do_write(Vcb, &rollback);
|
||||
|
||||
free_trees(Vcb);
|
||||
|
||||
clear_rollback(&rollback);
|
||||
|
||||
release_tree_lock(Vcb, TRUE);
|
||||
ExReleaseResourceLite(&Vcb->tree_lock);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
|
@ -44,28 +44,30 @@ void STDCALL flush_thread(void* context) {
|
|||
DEVICE_OBJECT* devobj = context;
|
||||
device_extension* Vcb = devobj->DeviceExtension;
|
||||
LARGE_INTEGER due_time;
|
||||
KTIMER flush_thread_timer;
|
||||
|
||||
ObReferenceObject(devobj);
|
||||
|
||||
KeInitializeTimer(&flush_thread_timer);
|
||||
KeInitializeTimer(&Vcb->flush_thread_timer);
|
||||
|
||||
due_time.QuadPart = -INTERVAL * 10000;
|
||||
|
||||
KeSetTimer(&flush_thread_timer, due_time, NULL);
|
||||
KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
|
||||
|
||||
while (TRUE) {
|
||||
KeWaitForSingleObject(&flush_thread_timer, Executive, KernelMode, FALSE, NULL);
|
||||
KeWaitForSingleObject(&Vcb->flush_thread_timer, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
if (!(devobj->Vpb->Flags & VPB_MOUNTED))
|
||||
if (!(devobj->Vpb->Flags & VPB_MOUNTED) || Vcb->removing)
|
||||
break;
|
||||
|
||||
do_flush(Vcb);
|
||||
|
||||
KeSetTimer(&flush_thread_timer, due_time, NULL);
|
||||
KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
|
||||
}
|
||||
|
||||
ObDereferenceObject(devobj);
|
||||
KeCancelTimer(&flush_thread_timer);
|
||||
KeCancelTimer(&Vcb->flush_thread_timer);
|
||||
|
||||
KeSetEvent(&Vcb->flush_thread_finished, 0, FALSE);
|
||||
|
||||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -174,14 +174,14 @@ static NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
InitializeListHead(&rollback);
|
||||
|
||||
acquire_tree_lock(Vcb, TRUE);
|
||||
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
|
||||
|
||||
if (Vcb->write_trees > 0)
|
||||
if (Vcb->need_write)
|
||||
do_write(Vcb, &rollback);
|
||||
|
||||
clear_rollback(&rollback);
|
||||
|
||||
release_tree_lock(Vcb, TRUE);
|
||||
ExReleaseResourceLite(&Vcb->tree_lock);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
end:
|
||||
|
@ -200,8 +200,13 @@ static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
}
|
||||
|
||||
if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
|
||||
Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status);
|
||||
}
|
||||
|
||||
uninit(Vcb, FALSE);
|
||||
DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
|
||||
Vcb->Vpb->Flags &= ~VPB_MOUNTED;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -229,6 +234,11 @@ NTSTATUS STDCALL drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
top_level = is_top_level(Irp);
|
||||
|
||||
if (Vcb && Vcb->type == VCB_TYPE_PARTITION0) {
|
||||
Status = part0_passthrough(DeviceObject, Irp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
switch (IrpSp->MinorFunction) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
667
reactos/drivers/filesystems/btrfs/registry.c
Normal file
667
reactos/drivers/filesystems/btrfs/registry.c
Normal file
|
@ -0,0 +1,667 @@
|
|||
#include "btrfs_drv.h"
|
||||
|
||||
extern UNICODE_STRING log_device, log_file, registry_path;
|
||||
|
||||
static WCHAR option_mounted[] = L"Mounted";
|
||||
static WCHAR option_ignore[] = L"Ignore";
|
||||
|
||||
#define hex_digit(c) ((c) >= 0 && (c) <= 9) ? ((c) + '0') : ((c) - 10 + 'a')
|
||||
|
||||
NTSTATUS registry_load_volume_options(BTRFS_UUID* uuid, mount_options* options) {
|
||||
UNICODE_STRING path, ignoreus;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
NTSTATUS Status;
|
||||
ULONG i, j, kvfilen, index, retlen;
|
||||
KEY_VALUE_FULL_INFORMATION* kvfi = NULL;
|
||||
HANDLE h;
|
||||
|
||||
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
|
||||
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
||||
|
||||
if (!path.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
|
||||
i = registry_path.Length / sizeof(WCHAR);
|
||||
|
||||
path.Buffer[i] = '\\';
|
||||
i++;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
|
||||
path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
|
||||
|
||||
i += 2;
|
||||
|
||||
if (j == 3 || j == 5 || j == 7 || j == 9) {
|
||||
path.Buffer[i] = '-';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR));
|
||||
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
||||
if (!kvfi) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
||||
|
||||
Status = ZwOpenKey(&h, KEY_QUERY_VALUE, &oa);
|
||||
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||||
Status = STATUS_SUCCESS;
|
||||
goto end;
|
||||
} else if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwOpenKey returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
ignoreus.Buffer = option_ignore;
|
||||
ignoreus.Length = ignoreus.MaximumLength = wcslen(option_ignore) * sizeof(WCHAR);
|
||||
|
||||
do {
|
||||
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
|
||||
|
||||
index++;
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
UNICODE_STRING us;
|
||||
|
||||
us.Length = us.MaximumLength = kvfi->NameLength;
|
||||
us.Buffer = kvfi->Name;
|
||||
|
||||
if (FsRtlAreNamesEqual(&ignoreus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
|
||||
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
|
||||
|
||||
options->ignore = *val != 0 ? TRUE : FALSE;
|
||||
}
|
||||
} else if (Status != STATUS_NO_MORE_ENTRIES) {
|
||||
ERR("ZwEnumerateValueKey returned %08x\n", Status);
|
||||
goto end2;
|
||||
}
|
||||
} while (NT_SUCCESS(Status));
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
end2:
|
||||
ZwClose(h);
|
||||
|
||||
end:
|
||||
ExFreePool(path.Buffer);
|
||||
|
||||
if (kvfi)
|
||||
ExFreePool(kvfi);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid) {
|
||||
UNICODE_STRING path, mountedus;
|
||||
ULONG i, j;
|
||||
NTSTATUS Status;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
HANDLE h;
|
||||
DWORD data;
|
||||
|
||||
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
|
||||
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
||||
|
||||
if (!path.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
|
||||
i = registry_path.Length / sizeof(WCHAR);
|
||||
|
||||
path.Buffer[i] = '\\';
|
||||
i++;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
|
||||
path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
|
||||
|
||||
i += 2;
|
||||
|
||||
if (j == 3 || j == 5 || j == 7 || j == 9) {
|
||||
path.Buffer[i] = '-';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
||||
|
||||
Status = ZwCreateKey(&h, KEY_SET_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwCreateKey returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
mountedus.Buffer = option_mounted;
|
||||
mountedus.Length = mountedus.MaximumLength = wcslen(option_mounted) * sizeof(WCHAR);
|
||||
|
||||
data = 1;
|
||||
|
||||
Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwSetValueKey returned %08x\n", Status);
|
||||
goto end2;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
end2:
|
||||
ZwClose(h);
|
||||
|
||||
end:
|
||||
ExFreePool(path.Buffer);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS registry_mark_volume_unmounted_path(PUNICODE_STRING path) {
|
||||
HANDLE h;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
NTSTATUS Status;
|
||||
ULONG index, kvbilen = sizeof(KEY_VALUE_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen;
|
||||
KEY_VALUE_BASIC_INFORMATION* kvbi;
|
||||
BOOL has_options = FALSE;
|
||||
UNICODE_STRING mountedus;
|
||||
|
||||
// If a volume key has any options in it, we set Mounted to 0 and return. Otherwise,
|
||||
// we delete the whole thing.
|
||||
|
||||
kvbi = ExAllocatePoolWithTag(PagedPool, kvbilen, ALLOC_TAG);
|
||||
if (!kvbi) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes(&oa, path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
||||
|
||||
Status = ZwOpenKey(&h, KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE, &oa);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwOpenKey returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
|
||||
mountedus.Buffer = option_mounted;
|
||||
mountedus.Length = mountedus.MaximumLength = wcslen(option_mounted) * sizeof(WCHAR);
|
||||
|
||||
do {
|
||||
Status = ZwEnumerateValueKey(h, index, KeyValueBasicInformation, kvbi, kvbilen, &retlen);
|
||||
|
||||
index++;
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
UNICODE_STRING us;
|
||||
|
||||
us.Length = us.MaximumLength = kvbi->NameLength;
|
||||
us.Buffer = kvbi->Name;
|
||||
|
||||
if (!FsRtlAreNamesEqual(&mountedus, &us, TRUE, NULL)) {
|
||||
has_options = TRUE;
|
||||
break;
|
||||
}
|
||||
} else if (Status != STATUS_NO_MORE_ENTRIES) {
|
||||
ERR("ZwEnumerateValueKey returned %08x\n", Status);
|
||||
goto end2;
|
||||
}
|
||||
} while (NT_SUCCESS(Status));
|
||||
|
||||
if (has_options) {
|
||||
DWORD data = 0;
|
||||
|
||||
Status = ZwSetValueKey(h, &mountedus, 0, REG_DWORD, &data, sizeof(DWORD));
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwSetValueKey returned %08x\n", Status);
|
||||
goto end2;
|
||||
}
|
||||
} else {
|
||||
Status = ZwDeleteKey(h);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwDeleteKey returned %08x\n", Status);
|
||||
goto end2;
|
||||
}
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
end2:
|
||||
ZwClose(h);
|
||||
|
||||
end:
|
||||
ExFreePool(kvbi);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID* uuid) {
|
||||
UNICODE_STRING path;
|
||||
NTSTATUS Status;
|
||||
ULONG i, j;
|
||||
|
||||
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
|
||||
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
||||
|
||||
if (!path.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
|
||||
i = registry_path.Length / sizeof(WCHAR);
|
||||
|
||||
path.Buffer[i] = '\\';
|
||||
i++;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
|
||||
path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
|
||||
|
||||
i += 2;
|
||||
|
||||
if (j == 3 || j == 5 || j == 7 || j == 9) {
|
||||
path.Buffer[i] = '-';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
Status = registry_mark_volume_unmounted_path(&path);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("registry_mark_volume_unmounted_path returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
ExFreePool(path.Buffer);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
#define is_hex(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
|
||||
|
||||
static BOOL is_uuid(ULONG namelen, WCHAR* name) {
|
||||
ULONG i;
|
||||
|
||||
if (namelen != 36 * sizeof(WCHAR))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < 36; i++) {
|
||||
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
||||
if (name[i] != '-')
|
||||
return FALSE;
|
||||
} else if (!is_hex(name[i]))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
UNICODE_STRING name;
|
||||
LIST_ENTRY list_entry;
|
||||
} key_name;
|
||||
|
||||
static void reset_subkeys(HANDLE h, PUNICODE_STRING reg_path) {
|
||||
NTSTATUS Status;
|
||||
KEY_BASIC_INFORMATION* kbi;
|
||||
ULONG kbilen = sizeof(KEY_BASIC_INFORMATION) - sizeof(WCHAR) + (255 * sizeof(WCHAR)), retlen, index = 0;
|
||||
LIST_ENTRY key_names, *le;
|
||||
|
||||
InitializeListHead(&key_names);
|
||||
|
||||
kbi = ExAllocatePoolWithTag(PagedPool, kbilen, ALLOC_TAG);
|
||||
if (!kbi) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
Status = ZwEnumerateKey(h, index, KeyBasicInformation, kbi, kbilen, &retlen);
|
||||
|
||||
index++;
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
key_name* kn;
|
||||
|
||||
ERR("key: %.*S\n", kbi->NameLength / sizeof(WCHAR), kbi->Name);
|
||||
|
||||
if (is_uuid(kbi->NameLength, kbi->Name)) {
|
||||
kn = ExAllocatePoolWithTag(PagedPool, sizeof(key_name), ALLOC_TAG);
|
||||
if (!kn) {
|
||||
ERR("out of memory\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
kn->name.Length = kn->name.MaximumLength = kbi->NameLength;
|
||||
kn->name.Buffer = ExAllocatePoolWithTag(PagedPool, kn->name.Length, ALLOC_TAG);
|
||||
|
||||
if (!kn->name.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(kn);
|
||||
goto end;
|
||||
}
|
||||
|
||||
RtlCopyMemory(kn->name.Buffer, kbi->Name, kbi->NameLength);
|
||||
|
||||
InsertTailList(&key_names, &kn->list_entry);
|
||||
}
|
||||
} else if (Status != STATUS_NO_MORE_ENTRIES)
|
||||
ERR("ZwEnumerateKey returned %08x\n", Status);
|
||||
} while (NT_SUCCESS(Status));
|
||||
|
||||
le = key_names.Flink;
|
||||
while (le != &key_names) {
|
||||
key_name* kn = CONTAINING_RECORD(le, key_name, list_entry);
|
||||
UNICODE_STRING path;
|
||||
|
||||
path.Length = path.MaximumLength = reg_path->Length + sizeof(WCHAR) + kn->name.Length;
|
||||
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
|
||||
|
||||
if (!path.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
RtlCopyMemory(path.Buffer, reg_path->Buffer, reg_path->Length);
|
||||
path.Buffer[reg_path->Length / sizeof(WCHAR)] = '\\';
|
||||
RtlCopyMemory(&path.Buffer[(reg_path->Length / sizeof(WCHAR)) + 1], kn->name.Buffer, kn->name.Length);
|
||||
|
||||
Status = registry_mark_volume_unmounted_path(&path);
|
||||
if (!NT_SUCCESS(Status))
|
||||
WARN("registry_mark_volume_unmounted_path returned %08x\n", Status);
|
||||
|
||||
ExFreePool(path.Buffer);
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
end:
|
||||
while (!IsListEmpty(&key_names)) {
|
||||
key_name* kn;
|
||||
|
||||
le = RemoveHeadList(&key_names);
|
||||
kn = CONTAINING_RECORD(le, key_name, list_entry);
|
||||
|
||||
if (kn->name.Buffer)
|
||||
ExFreePool(kn->name.Buffer);
|
||||
|
||||
ExFreePool(kn);
|
||||
}
|
||||
|
||||
ExFreePool(kbi);
|
||||
}
|
||||
|
||||
static void read_mappings(PUNICODE_STRING regpath) {
|
||||
WCHAR* path;
|
||||
UNICODE_STRING us;
|
||||
HANDLE h;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
ULONG dispos;
|
||||
NTSTATUS Status;
|
||||
ULONG kvfilen, retlen, i;
|
||||
KEY_VALUE_FULL_INFORMATION* kvfi;
|
||||
|
||||
const WCHAR mappings[] = L"\\Mappings";
|
||||
|
||||
path = ExAllocatePoolWithTag(PagedPool, regpath->Length + (wcslen(mappings) * sizeof(WCHAR)), ALLOC_TAG);
|
||||
if (!path) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(path, regpath->Buffer, regpath->Length);
|
||||
RtlCopyMemory((UINT8*)path + regpath->Length, mappings, wcslen(mappings) * sizeof(WCHAR));
|
||||
|
||||
us.Buffer = path;
|
||||
us.Length = us.MaximumLength = regpath->Length + ((USHORT)wcslen(mappings) * sizeof(WCHAR));
|
||||
|
||||
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
||||
|
||||
// FIXME - keep open and do notify for changes
|
||||
Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwCreateKey returned %08x\n", Status);
|
||||
ExFreePool(path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispos == REG_OPENED_EXISTING_KEY) {
|
||||
kvfilen = sizeof(KEY_VALUE_FULL_INFORMATION) + 256;
|
||||
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
||||
|
||||
if (!kvfi) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(path);
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
Status = ZwEnumerateValueKey(h, i, KeyValueFullInformation, kvfi, kvfilen, &retlen);
|
||||
|
||||
if (NT_SUCCESS(Status) && kvfi->DataLength > 0) {
|
||||
UINT32 val = 0;
|
||||
|
||||
RtlCopyMemory(&val, (UINT8*)kvfi + kvfi->DataOffset, min(kvfi->DataLength, sizeof(UINT32)));
|
||||
|
||||
TRACE("entry %u = %.*S = %u\n", i, kvfi->NameLength / sizeof(WCHAR), kvfi->Name, val);
|
||||
|
||||
add_user_mapping(kvfi->Name, kvfi->NameLength / sizeof(WCHAR), val);
|
||||
}
|
||||
|
||||
i = i + 1;
|
||||
} while (Status != STATUS_NO_MORE_ENTRIES);
|
||||
}
|
||||
|
||||
ZwClose(h);
|
||||
|
||||
ExFreePool(path);
|
||||
}
|
||||
|
||||
void STDCALL read_registry(PUNICODE_STRING regpath) {
|
||||
#ifndef __REACTOS__
|
||||
UNICODE_STRING us;
|
||||
#endif
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
NTSTATUS Status;
|
||||
HANDLE h;
|
||||
ULONG dispos;
|
||||
#ifndef __REACTOS__
|
||||
ULONG kvfilen;
|
||||
KEY_VALUE_FULL_INFORMATION* kvfi;
|
||||
#endif
|
||||
|
||||
#ifndef __REACTOS__
|
||||
static WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
|
||||
#endif
|
||||
|
||||
read_mappings(regpath);
|
||||
|
||||
InitializeObjectAttributes(&oa, regpath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
|
||||
|
||||
Status = ZwCreateKey(&h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwCreateKey returned %08x\n", Status);
|
||||
return;
|
||||
}
|
||||
|
||||
reset_subkeys(h, regpath);
|
||||
|
||||
#ifdef _DEBUG
|
||||
RtlInitUnicodeString(&us, L"DebugLogLevel");
|
||||
|
||||
kvfi = NULL;
|
||||
kvfilen = 0;
|
||||
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
||||
|
||||
if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
|
||||
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
||||
|
||||
if (!kvfi) {
|
||||
ERR("out of memory\n");
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (kvfi->Type == REG_DWORD && kvfi->DataLength >= sizeof(UINT32)) {
|
||||
RtlCopyMemory(&debug_log_level, ((UINT8*)kvfi) + kvfi->DataOffset, sizeof(UINT32));
|
||||
} else {
|
||||
Status = ZwDeleteValueKey(h, &us);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwDeleteValueKey returned %08x\n", Status);
|
||||
}
|
||||
|
||||
Status = ZwSetValueKey(h, &us, 0, REG_DWORD, &debug_log_level, sizeof(debug_log_level));
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwSetValueKey reutrned %08x\n", Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(kvfi);
|
||||
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||||
Status = ZwSetValueKey(h, &us, 0, REG_DWORD, &debug_log_level, sizeof(debug_log_level));
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwSetValueKey reutrned %08x\n", Status);
|
||||
}
|
||||
} else {
|
||||
ERR("ZwQueryValueKey returned %08x\n", Status);
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&us, L"LogDevice");
|
||||
|
||||
kvfi = NULL;
|
||||
kvfilen = 0;
|
||||
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
||||
|
||||
if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
|
||||
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
||||
|
||||
if (!kvfi) {
|
||||
ERR("out of memory\n");
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
|
||||
log_device.Length = log_device.MaximumLength = kvfi->DataLength;
|
||||
log_device.Buffer = ExAllocatePoolWithTag(PagedPool, kvfi->DataLength, ALLOC_TAG);
|
||||
|
||||
if (!log_device.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(kvfi);
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(log_device.Buffer, ((UINT8*)kvfi) + kvfi->DataOffset, kvfi->DataLength);
|
||||
|
||||
if (log_device.Buffer[(log_device.Length / sizeof(WCHAR)) - 1] == 0)
|
||||
log_device.Length -= sizeof(WCHAR);
|
||||
} else {
|
||||
ERR("LogDevice was type %u, length %u\n", kvfi->Type, kvfi->DataLength);
|
||||
|
||||
Status = ZwDeleteValueKey(h, &us);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwDeleteValueKey returned %08x\n", Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(kvfi);
|
||||
} else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
|
||||
ERR("ZwQueryValueKey returned %08x\n", Status);
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&us, L"LogFile");
|
||||
|
||||
kvfi = NULL;
|
||||
kvfilen = 0;
|
||||
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
||||
|
||||
if ((Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW) && kvfilen > 0) {
|
||||
kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
|
||||
|
||||
if (!kvfi) {
|
||||
ERR("out of memory\n");
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if ((kvfi->Type == REG_SZ || kvfi->Type == REG_EXPAND_SZ) && kvfi->DataLength >= sizeof(WCHAR)) {
|
||||
log_file.Length = log_file.MaximumLength = kvfi->DataLength;
|
||||
log_file.Buffer = ExAllocatePoolWithTag(PagedPool, kvfi->DataLength, ALLOC_TAG);
|
||||
|
||||
if (!log_file.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(kvfi);
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(log_file.Buffer, ((UINT8*)kvfi) + kvfi->DataOffset, kvfi->DataLength);
|
||||
|
||||
if (log_file.Buffer[(log_file.Length / sizeof(WCHAR)) - 1] == 0)
|
||||
log_file.Length -= sizeof(WCHAR);
|
||||
} else {
|
||||
ERR("LogFile was type %u, length %u\n", kvfi->Type, kvfi->DataLength);
|
||||
|
||||
Status = ZwDeleteValueKey(h, &us);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwDeleteValueKey returned %08x\n", Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(kvfi);
|
||||
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
||||
Status = ZwSetValueKey(h, &us, 0, REG_SZ, def_log_file, (wcslen(def_log_file) + 1) * sizeof(WCHAR));
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwSetValueKey returned %08x\n", Status);
|
||||
}
|
||||
} else {
|
||||
ERR("ZwQueryValueKey returned %08x\n", Status);
|
||||
}
|
||||
|
||||
if (log_file.Length == 0) {
|
||||
log_file.Length = log_file.MaximumLength = wcslen(def_log_file) * sizeof(WCHAR);
|
||||
log_file.Buffer = ExAllocatePoolWithTag(PagedPool, log_file.MaximumLength, ALLOC_TAG);
|
||||
|
||||
if (!log_file.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(log_file.Buffer, def_log_file, log_file.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
ZwClose(h);
|
||||
}
|
|
@ -30,7 +30,8 @@ NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
|||
|
||||
TRACE("(%p, %p, %p, %x, %p)\n", DeviceObject, FileObject, buffer, buflen, retlen);
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
|
||||
ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE);
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_SYMLINK) {
|
||||
data = ExAllocatePoolWithTag(PagedPool, fcb->inode_item.st_size, ALLOC_TAG);
|
||||
|
@ -41,7 +42,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(DeviceObject->DeviceExtension, fcb->subvol, fcb->inode, (UINT8*)data, 0, fcb->inode_item.st_size, NULL);
|
||||
Status = read_file(fcb, (UINT8*)data, 0, fcb->inode_item.st_size, NULL, NULL);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_file returned %08x\n", Status);
|
||||
|
@ -101,38 +102,22 @@ NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
|||
Status = STATUS_SUCCESS;
|
||||
} else if (fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
if (fcb->type == BTRFS_TYPE_FILE) {
|
||||
Status = read_file(DeviceObject->DeviceExtension, fcb->subvol, fcb->inode, buffer, 0, buflen, retlen);
|
||||
Status = read_file(fcb, buffer, 0, buflen, retlen, NULL);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_file returned %08x\n", Status);
|
||||
}
|
||||
} else if (fcb->type == BTRFS_TYPE_DIRECTORY) {
|
||||
UINT8* data;
|
||||
UINT16 datalen;
|
||||
|
||||
if (!get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_REPARSE, EA_REPARSE_HASH, &data, &datalen)) {
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (datalen < sizeof(ULONG)) {
|
||||
ExFreePool(data);
|
||||
if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length < sizeof(ULONG)) {
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (buflen > 0) {
|
||||
*retlen = min(buflen, datalen);
|
||||
RtlCopyMemory(buffer, data, *retlen);
|
||||
*retlen = min(buflen, fcb->reparse_xattr.Length);
|
||||
RtlCopyMemory(buffer, fcb->reparse_xattr.Buffer, *retlen);
|
||||
} else
|
||||
*retlen = 0;
|
||||
|
||||
ExFreePool(data);
|
||||
} else
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
} else {
|
||||
|
@ -140,115 +125,19 @@ NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
|||
}
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS change_file_type(device_extension* Vcb, UINT64 inode, root* subvol, UINT64 parinode, UINT64 index, PANSI_STRING utf8, UINT8 type, LIST_ENTRY* rollback) {
|
||||
KEY searchkey;
|
||||
UINT32 crc32;
|
||||
traverse_ptr tp;
|
||||
NTSTATUS Status;
|
||||
|
||||
crc32 = calc_crc32c(0xfffffffe, (UINT8*)utf8->Buffer, (ULONG)utf8->Length);
|
||||
|
||||
searchkey.obj_id = parinode;
|
||||
searchkey.obj_type = TYPE_DIR_ITEM;
|
||||
searchkey.offset = crc32;
|
||||
|
||||
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!keycmp(&tp.item->key, &searchkey)) {
|
||||
if (tp.item->size < sizeof(DIR_ITEM)) {
|
||||
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));
|
||||
} else {
|
||||
DIR_ITEM *di = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG), *di2;
|
||||
BOOL found = FALSE;
|
||||
ULONG len = tp.item->size;
|
||||
|
||||
if (!di) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(di, tp.item->data, tp.item->size);
|
||||
|
||||
di2 = di;
|
||||
do {
|
||||
if (len < sizeof(DIR_ITEM) || len < sizeof(DIR_ITEM) - 1 + di2->m + di2->n) {
|
||||
ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
if (di2->n == utf8->Length && RtlCompareMemory(di2->name, utf8->Buffer, utf8->Length) == utf8->Length) {
|
||||
di2->type = type;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > sizeof(DIR_ITEM) - sizeof(char) + di2->m + di2->n) {
|
||||
len -= sizeof(DIR_ITEM) - sizeof(char) + di2->m + di2->n;
|
||||
di2 = (DIR_ITEM*)&di2->name[di2->m + di2->n];
|
||||
} else
|
||||
break;
|
||||
} while (len > 0);
|
||||
|
||||
if (found) {
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, di, tp.item->size, NULL, rollback);
|
||||
} else
|
||||
ExFreePool(di);
|
||||
}
|
||||
} else {
|
||||
WARN("search for DIR_ITEM by crc32 failed\n");
|
||||
}
|
||||
|
||||
searchkey.obj_id = parinode;
|
||||
searchkey.obj_type = TYPE_DIR_INDEX;
|
||||
searchkey.offset = index;
|
||||
|
||||
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!keycmp(&tp.item->key, &searchkey)) {
|
||||
if (tp.item->size < sizeof(DIR_ITEM)) {
|
||||
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));
|
||||
} else {
|
||||
DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
|
||||
DIR_ITEM* di2 = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
|
||||
if (!di2) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(di2, di, tp.item->size);
|
||||
di2->type = type;
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, di2, tp.item->size, NULL, rollback);
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS set_symlink(PIRP Irp, fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, LIST_ENTRY* rollback) {
|
||||
static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, REPARSE_DATA_BUFFER* rdb, ULONG buflen, LIST_ENTRY* rollback) {
|
||||
NTSTATUS Status;
|
||||
ULONG minlen;
|
||||
UNICODE_STRING subname;
|
||||
ANSI_STRING target;
|
||||
KEY searchkey;
|
||||
traverse_ptr tp, next_tp;
|
||||
BOOL b;
|
||||
LARGE_INTEGER offset;
|
||||
LARGE_INTEGER offset, time;
|
||||
BTRFS_TIME now;
|
||||
USHORT i;
|
||||
|
||||
minlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + sizeof(WCHAR);
|
||||
|
@ -260,125 +149,13 @@ static NTSTATUS set_symlink(PIRP Irp, fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG
|
|||
subname.Buffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)];
|
||||
subname.MaximumLength = subname.Length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||
|
||||
ERR("substitute name = %.*S\n", subname.Length / sizeof(WCHAR), subname.Buffer);
|
||||
TRACE("substitute name = %.*S\n", subname.Length / sizeof(WCHAR), subname.Buffer);
|
||||
|
||||
fcb->type = BTRFS_TYPE_SYMLINK;
|
||||
fileref->fcb->type = BTRFS_TYPE_SYMLINK;
|
||||
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_INODE_REF;
|
||||
searchkey.offset = 0;
|
||||
fileref->fcb->inode_item.st_mode |= __S_IFLNK;
|
||||
|
||||
Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_REF) {
|
||||
if (tp.item->size < sizeof(INODE_REF)) {
|
||||
WARN("(%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(INODE_REF));
|
||||
} else {
|
||||
INODE_REF* ir;
|
||||
ULONG size = tp.item->size;
|
||||
ANSI_STRING utf8;
|
||||
|
||||
ir = (INODE_REF*)tp.item->data;
|
||||
|
||||
do {
|
||||
if (size < sizeof(INODE_REF) || size < sizeof(INODE_REF) - 1 + ir->n) {
|
||||
WARN("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
utf8.Buffer = ir->name;
|
||||
utf8.Length = utf8.MaximumLength = ir->n;
|
||||
|
||||
Status = change_file_type(fcb->Vcb, fcb->inode, fcb->subvol, tp.item->key.offset, ir->index, &utf8, BTRFS_TYPE_SYMLINK, rollback);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - change_file_type returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (size > sizeof(INODE_REF) - 1 + ir->n) {
|
||||
size -= sizeof(INODE_REF) - 1 + ir->n;
|
||||
|
||||
ir = (INODE_REF*)&ir->name[ir->n];
|
||||
} else
|
||||
break;
|
||||
} while (TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
b = find_next_item(fcb->Vcb, &tp, &next_tp, FALSE);
|
||||
if (b) {
|
||||
tp = next_tp;
|
||||
|
||||
b = tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_REF;
|
||||
}
|
||||
} while (b);
|
||||
|
||||
if (fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) {
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_INODE_EXTREF;
|
||||
searchkey.offset = 0;
|
||||
|
||||
Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_EXTREF) {
|
||||
if (tp.item->size < sizeof(INODE_EXTREF)) {
|
||||
WARN("(%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(INODE_EXTREF));
|
||||
} else {
|
||||
INODE_EXTREF* ier;
|
||||
ULONG size = tp.item->size;
|
||||
ANSI_STRING utf8;
|
||||
|
||||
ier = (INODE_EXTREF*)tp.item->data;
|
||||
|
||||
do {
|
||||
if (size < sizeof(INODE_EXTREF) || size < sizeof(INODE_EXTREF) - 1 + ier->n) {
|
||||
WARN("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
utf8.Buffer = ier->name;
|
||||
utf8.Length = utf8.MaximumLength = ier->n;
|
||||
|
||||
Status = change_file_type(fcb->Vcb, fcb->inode, fcb->subvol, ier->dir, ier->index, &utf8, BTRFS_TYPE_SYMLINK, rollback);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - change_file_type returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (size > sizeof(INODE_EXTREF) - 1 + ier->n) {
|
||||
size -= sizeof(INODE_EXTREF) - 1 + ier->n;
|
||||
|
||||
ier = (INODE_EXTREF*)&ier->name[ier->n];
|
||||
} else
|
||||
break;
|
||||
} while (TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
b = find_next_item(fcb->Vcb, &tp, &next_tp, FALSE);
|
||||
if (b) {
|
||||
tp = next_tp;
|
||||
|
||||
b = tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_EXTREF;
|
||||
}
|
||||
} while (b);
|
||||
}
|
||||
|
||||
fcb->inode_item.st_mode |= __S_IFLNK;
|
||||
|
||||
Status = truncate_file(fcb, 0, rollback);
|
||||
Status = truncate_file(fileref->fcb, 0, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("truncate_file returned %08x\n", Status);
|
||||
return Status;
|
||||
|
@ -386,7 +163,7 @@ static NTSTATUS set_symlink(PIRP Irp, fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG
|
|||
|
||||
Status = RtlUnicodeToUTF8N(NULL, 0, (PULONG)&target.Length, subname.Buffer, subname.Length);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUnicodeToUTF8N 3 failed with error %08x\n", Status);
|
||||
ERR("RtlUnicodeToUTF8N 1 failed with error %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
@ -399,7 +176,7 @@ static NTSTATUS set_symlink(PIRP Irp, fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG
|
|||
|
||||
Status = RtlUnicodeToUTF8N(target.Buffer, target.Length, (PULONG)&target.Length, subname.Buffer, subname.Length);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUnicodeToUTF8N 4 failed with error %08x\n", Status);
|
||||
ERR("RtlUnicodeToUTF8N 2 failed with error %08x\n", Status);
|
||||
ExFreePool(target.Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
@ -410,159 +187,23 @@ static NTSTATUS set_symlink(PIRP Irp, fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG
|
|||
}
|
||||
|
||||
offset.QuadPart = 0;
|
||||
Status = write_file2(fcb->Vcb, Irp, offset, target.Buffer, (ULONG*)&target.Length, Irp->Flags & IRP_PAGING_IO, Irp->Flags & IRP_NOCACHE, rollback);
|
||||
|
||||
Status = write_file2(fileref->fcb->Vcb, Irp, offset, target.Buffer, (ULONG*)&target.Length, FALSE, TRUE,
|
||||
TRUE, FALSE, rollback);
|
||||
ExFreePool(target.Buffer);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS delete_symlink(fcb* fcb, LIST_ENTRY* rollback) {
|
||||
NTSTATUS Status;
|
||||
KEY searchkey;
|
||||
traverse_ptr tp, next_tp;
|
||||
BOOL b;
|
||||
LARGE_INTEGER time;
|
||||
BTRFS_TIME now;
|
||||
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_INODE_REF;
|
||||
searchkey.offset = 0;
|
||||
|
||||
Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_REF) {
|
||||
if (tp.item->size < sizeof(INODE_REF)) {
|
||||
WARN("(%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(INODE_REF));
|
||||
} else {
|
||||
INODE_REF* ir;
|
||||
ULONG size = tp.item->size;
|
||||
ANSI_STRING utf8;
|
||||
|
||||
ir = (INODE_REF*)tp.item->data;
|
||||
|
||||
do {
|
||||
if (size < sizeof(INODE_REF) || size < sizeof(INODE_REF) - 1 + ir->n) {
|
||||
WARN("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
utf8.Buffer = ir->name;
|
||||
utf8.Length = utf8.MaximumLength = ir->n;
|
||||
|
||||
Status = change_file_type(fcb->Vcb, fcb->inode, fcb->subvol, tp.item->key.offset, ir->index, &utf8, BTRFS_TYPE_FILE, rollback);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - change_file_type returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (size > sizeof(INODE_REF) - 1 + ir->n) {
|
||||
size -= sizeof(INODE_REF) - 1 + ir->n;
|
||||
|
||||
ir = (INODE_REF*)&ir->name[ir->n];
|
||||
} else
|
||||
break;
|
||||
} while (TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
b = find_next_item(fcb->Vcb, &tp, &next_tp, FALSE);
|
||||
if (b) {
|
||||
tp = next_tp;
|
||||
|
||||
b = tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_REF;
|
||||
}
|
||||
} while (b);
|
||||
|
||||
if (fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) {
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_INODE_EXTREF;
|
||||
searchkey.offset = 0;
|
||||
|
||||
Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_EXTREF) {
|
||||
if (tp.item->size < sizeof(INODE_EXTREF)) {
|
||||
WARN("(%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(INODE_EXTREF));
|
||||
} else {
|
||||
INODE_EXTREF* ier;
|
||||
ULONG size = tp.item->size;
|
||||
ANSI_STRING utf8;
|
||||
|
||||
ier = (INODE_EXTREF*)tp.item->data;
|
||||
|
||||
do {
|
||||
if (size < sizeof(INODE_EXTREF) || size < sizeof(INODE_EXTREF) - 1 + ier->n) {
|
||||
WARN("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
utf8.Buffer = ier->name;
|
||||
utf8.Length = utf8.MaximumLength = ier->n;
|
||||
|
||||
Status = change_file_type(fcb->Vcb, fcb->inode, fcb->subvol, ier->dir, ier->index, &utf8, BTRFS_TYPE_FILE, rollback);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - change_file_type returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (size > sizeof(INODE_EXTREF) - 1 + ier->n) {
|
||||
size -= sizeof(INODE_EXTREF) - 1 + ier->n;
|
||||
|
||||
ier = (INODE_EXTREF*)&ier->name[ier->n];
|
||||
} else
|
||||
break;
|
||||
} while (TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
b = find_next_item(fcb->Vcb, &tp, &next_tp, FALSE);
|
||||
if (b) {
|
||||
tp = next_tp;
|
||||
|
||||
b = tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_EXTREF;
|
||||
}
|
||||
} while (b);
|
||||
}
|
||||
|
||||
Status = truncate_file(fcb, 0, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("truncate_file returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
KeQuerySystemTime(&time);
|
||||
|
||||
win_time_to_unix(time, &now);
|
||||
|
||||
fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
|
||||
fileref->fcb->inode_item.sequence++;
|
||||
fileref->fcb->inode_item.st_ctime = now;
|
||||
fileref->fcb->inode_item.st_mtime = now;
|
||||
|
||||
fcb->type = BTRFS_TYPE_FILE;
|
||||
fcb->inode_item.st_mode &= ~__S_IFLNK;
|
||||
fcb->inode_item.st_mode |= __S_IFREG;
|
||||
fcb->inode_item.transid = fcb->Vcb->superblock.generation;
|
||||
fcb->inode_item.sequence++;
|
||||
fcb->inode_item.st_ctime = now;
|
||||
fcb->inode_item.st_mtime = now;
|
||||
|
||||
Status = update_inode_item(fcb->Vcb, fcb->subvol, fcb->inode, &fcb->inode_item, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("update_inode_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
|
||||
fcb->subvol->root_item.ctime = now;
|
||||
fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
|
||||
fileref->fcb->subvol->root_item.ctime = now;
|
||||
|
||||
mark_fcb_dirty(fileref->fcb);
|
||||
mark_fileref_dirty(fileref);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -575,6 +216,8 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
fcb* fcb;
|
||||
ccb* ccb;
|
||||
file_ref* fileref;
|
||||
ULONG tag;
|
||||
LIST_ENTRY rollback;
|
||||
|
||||
|
@ -591,10 +234,24 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
}
|
||||
|
||||
fcb = FileObject->FsContext;
|
||||
ccb = FileObject->FsContext2;
|
||||
|
||||
if (!ccb) {
|
||||
ERR("ccb was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
fileref = ccb->fileref;
|
||||
|
||||
if (!fileref) {
|
||||
ERR("fileref was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
TRACE("%S\n", file_desc(FileObject));
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, TRUE);
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
|
||||
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_SYMLINK) {
|
||||
WARN("tried to set a reparse point on an existing symlink\n");
|
||||
|
@ -616,17 +273,32 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
RtlCopyMemory(&tag, buffer, sizeof(ULONG));
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_FILE && tag == IO_REPARSE_TAG_SYMLINK && rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) {
|
||||
Status = set_symlink(Irp, fcb, rdb, buflen, &rollback);
|
||||
Status = set_symlink(Irp, fileref, rdb, buflen, &rollback);
|
||||
fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
} else {
|
||||
LARGE_INTEGER offset;
|
||||
char val[64];
|
||||
LARGE_INTEGER offset, time;
|
||||
BTRFS_TIME now;
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_DIRECTORY) { // for directories, store as xattr
|
||||
Status = set_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_REPARSE, EA_REPARSE_HASH, buffer, buflen, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("set_xattr returned %08x\n", Status);
|
||||
ANSI_STRING buf;
|
||||
|
||||
buf.Buffer = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG);
|
||||
if (!buf.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
buf.Length = buf.MaximumLength = buflen;
|
||||
|
||||
if (fcb->reparse_xattr.Buffer)
|
||||
ExFreePool(fcb->reparse_xattr.Buffer);
|
||||
|
||||
fcb->reparse_xattr = buf;
|
||||
RtlCopyMemory(fcb->reparse_xattr.Buffer, buffer, buflen);
|
||||
|
||||
fcb->reparse_xattr_changed = TRUE;
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
} else { // otherwise, store as file data
|
||||
Status = truncate_file(fcb, 0, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
|
@ -636,26 +308,30 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
offset.QuadPart = 0;
|
||||
|
||||
Status = write_file2(fcb->Vcb, Irp, offset, buffer, &buflen, Irp->Flags & IRP_PAGING_IO, Irp->Flags & IRP_NOCACHE, &rollback);
|
||||
Status = write_file2(fcb->Vcb, Irp, offset, buffer, &buflen, FALSE, TRUE, TRUE, FALSE, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("write_file2 returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
|
||||
sprintf(val, "0x%lx", fcb->atts);
|
||||
|
||||
Status = set_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8*)val, strlen(val), &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("set_xattr returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
KeQuerySystemTime(&time);
|
||||
win_time_to_unix(time, &now);
|
||||
|
||||
fcb->inode_item.transid = fcb->Vcb->superblock.generation;
|
||||
fcb->inode_item.sequence++;
|
||||
fcb->inode_item.st_ctime = now;
|
||||
fcb->inode_item.st_mtime = now;
|
||||
fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
fcb->atts_changed = TRUE;
|
||||
|
||||
fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
|
||||
fcb->subvol->root_item.ctime = now;
|
||||
|
||||
mark_fcb_dirty(fcb);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = consider_write(fcb->Vcb);
|
||||
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED);
|
||||
|
||||
end:
|
||||
if (NT_SUCCESS(Status))
|
||||
|
@ -663,7 +339,8 @@ end:
|
|||
else
|
||||
do_rollback(fcb->Vcb, &rollback);
|
||||
|
||||
release_tree_lock(fcb->Vcb, TRUE);
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
@ -679,7 +356,6 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
file_ref* fileref;
|
||||
LIST_ENTRY rollback;
|
||||
|
||||
// FIXME - send notification if this succeeds? The attributes will have changed.
|
||||
// FIXME - check permissions
|
||||
|
||||
TRACE("(%p, %p)\n", DeviceObject, Irp);
|
||||
|
@ -695,25 +371,29 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
ccb = FileObject->FsContext2;
|
||||
fileref = ccb ? ccb->fileref : NULL;
|
||||
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
|
||||
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
|
||||
|
||||
TRACE("%S\n", file_desc(FileObject));
|
||||
|
||||
if (!fileref) {
|
||||
ERR("fileref was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) {
|
||||
ERR("buffer was too short\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (rdb->ReparseDataLength > 0) {
|
||||
WARN("rdb->ReparseDataLength was not zero\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, TRUE);
|
||||
|
||||
if (fcb->ads) {
|
||||
WARN("tried to delete reparse point on ADS\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
|
@ -721,21 +401,35 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
}
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_SYMLINK) {
|
||||
LARGE_INTEGER time;
|
||||
BTRFS_TIME now;
|
||||
|
||||
if (rdb->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
|
||||
WARN("reparse tag was not IO_REPARSE_TAG_SYMLINK\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = delete_symlink(fcb, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("delete_symlink returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
KeQuerySystemTime(&time);
|
||||
win_time_to_unix(time, &now);
|
||||
|
||||
fileref->fcb->type = BTRFS_TYPE_FILE;
|
||||
fileref->fcb->inode_item.st_mode &= ~__S_IFLNK;
|
||||
fileref->fcb->inode_item.st_mode |= __S_IFREG;
|
||||
fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation;
|
||||
fileref->fcb->inode_item.sequence++;
|
||||
fileref->fcb->inode_item.st_ctime = now;
|
||||
fileref->fcb->inode_item.st_mtime = now;
|
||||
fileref->fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
|
||||
mark_fileref_dirty(fileref);
|
||||
mark_fcb_dirty(fileref->fcb);
|
||||
|
||||
fileref->fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
|
||||
fileref->fcb->subvol->root_item.ctime = now;
|
||||
} else if (fcb->type == BTRFS_TYPE_FILE) {
|
||||
LARGE_INTEGER time;
|
||||
BTRFS_TIME now;
|
||||
ULONG defda;
|
||||
|
||||
// FIXME - do we need to check that the reparse tags match?
|
||||
|
||||
|
@ -746,24 +440,9 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
}
|
||||
|
||||
fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
|
||||
defda = get_file_attributes(fcb->Vcb, &fcb->inode_item, fcb->subvol, fcb->inode, fcb->type, fileref->filepart.Length > 0 && fileref->filepart.Buffer[0] == '.', TRUE);
|
||||
|
||||
if (defda != fcb->atts) {
|
||||
char val[64];
|
||||
|
||||
sprintf(val, "0x%lx", fcb->atts);
|
||||
|
||||
Status = set_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8*)val, strlen(val), &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("set_xattr returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
delete_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, &rollback);
|
||||
fcb->atts_changed = TRUE;
|
||||
|
||||
KeQuerySystemTime(&time);
|
||||
|
||||
win_time_to_unix(time, &now);
|
||||
|
||||
fcb->inode_item.transid = fcb->Vcb->superblock.generation;
|
||||
|
@ -771,55 +450,35 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
fcb->inode_item.st_ctime = now;
|
||||
fcb->inode_item.st_mtime = now;
|
||||
|
||||
Status = update_inode_item(fcb->Vcb, fcb->subvol, fcb->inode, &fcb->inode_item, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("update_inode_item returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
mark_fcb_dirty(fcb);
|
||||
|
||||
fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
|
||||
fcb->subvol->root_item.ctime = now;
|
||||
} else if (fcb->type == BTRFS_TYPE_DIRECTORY) {
|
||||
LARGE_INTEGER time;
|
||||
BTRFS_TIME now;
|
||||
ULONG defda;
|
||||
|
||||
// FIXME - do we need to check that the reparse tags match?
|
||||
|
||||
fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
fcb->atts_changed = TRUE;
|
||||
|
||||
defda = get_file_attributes(fcb->Vcb, &fcb->inode_item, fcb->subvol, fcb->inode, fcb->type, fileref->filepart.Length > 0 && fileref->filepart.Buffer[0] == '.', TRUE);
|
||||
defda |= FILE_ATTRIBUTE_DIRECTORY;
|
||||
if (fcb->reparse_xattr.Buffer) {
|
||||
ExFreePool(fcb->reparse_xattr.Buffer);
|
||||
fcb->reparse_xattr.Buffer = NULL;
|
||||
}
|
||||
|
||||
if (defda != fcb->atts) {
|
||||
char val[64];
|
||||
|
||||
sprintf(val, "0x%lx", fcb->atts);
|
||||
|
||||
Status = set_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8*)val, strlen(val), &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("set_xattr returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
delete_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, &rollback);
|
||||
|
||||
delete_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_REPARSE, EA_REPARSE_HASH, &rollback);
|
||||
fcb->reparse_xattr_changed = TRUE;
|
||||
|
||||
KeQuerySystemTime(&time);
|
||||
|
||||
win_time_to_unix(time, &now);
|
||||
|
||||
|
||||
fcb->inode_item.transid = fcb->Vcb->superblock.generation;
|
||||
fcb->inode_item.sequence++;
|
||||
fcb->inode_item.st_ctime = now;
|
||||
fcb->inode_item.st_mtime = now;
|
||||
|
||||
Status = update_inode_item(fcb->Vcb, fcb->subvol, fcb->inode, &fcb->inode_item, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("update_inode_item returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
mark_fcb_dirty(fcb);
|
||||
|
||||
fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
|
||||
fcb->subvol->root_item.ctime = now;
|
||||
|
@ -831,16 +490,16 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = consider_write(fcb->Vcb);
|
||||
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED);
|
||||
|
||||
end:
|
||||
if (NT_SUCCESS(Status))
|
||||
clear_rollback(&rollback);
|
||||
else
|
||||
do_rollback(fcb->Vcb, &rollback);
|
||||
|
||||
release_tree_lock(fcb->Vcb, TRUE);
|
||||
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,63 @@ VOID WINAPI IopNotifyPlugPlayNotification(
|
|||
|
||||
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) {
|
||||
PDEVICE_OBJECT newdevobj;
|
||||
UNICODE_STRING name;
|
||||
NTSTATUS Status;
|
||||
part0_device_extension* p0de;
|
||||
|
||||
static const WCHAR btrfs_partition[] = L"\\BtrfsPartition";
|
||||
|
||||
name.Length = name.MaximumLength = pardir->Length + (wcslen(btrfs_partition) * 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));
|
||||
|
||||
Status = IoCreateDevice(DriverObject, sizeof(part0_device_extension), &name, FILE_DEVICE_DISK, FILE_DEVICE_SECURE_OPEN, FALSE, &newdevobj);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("IoCreateDevice returned %08x\n", Status);
|
||||
ExFreePool(name.Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
p0de = newdevobj->DeviceExtension;
|
||||
p0de->type = VCB_TYPE_PARTITION0;
|
||||
p0de->devobj = DeviceObject;
|
||||
RtlCopyMemory(&p0de->uuid, uuid, sizeof(BTRFS_UUID));
|
||||
|
||||
p0de->name.Length = name.Length;
|
||||
p0de->name.MaximumLength = name.MaximumLength;
|
||||
p0de->name.Buffer = ExAllocatePoolWithTag(PagedPool, p0de->name.MaximumLength, ALLOC_TAG);
|
||||
|
||||
if (!p0de->name.Buffer) {
|
||||
ERR("out of memory\b");
|
||||
ExFreePool(name.Buffer);
|
||||
ExFreePool(p0de->name.Buffer);
|
||||
IoDeleteDevice(newdevobj);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(p0de->name.Buffer, name.Buffer, name.Length);
|
||||
|
||||
ObReferenceObject(DeviceObject);
|
||||
|
||||
newdevobj->StackSize = DeviceObject->StackSize + 1;
|
||||
|
||||
newdevobj->Flags |= DO_DIRECT_IO;
|
||||
newdevobj->Flags &= ~DO_DEVICE_INITIALIZING;
|
||||
|
||||
*nameus = name;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
|
||||
ULONG tnsize;
|
||||
MOUNTMGR_TARGET_NAME* tn;
|
||||
|
@ -81,7 +138,8 @@ static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
|
|||
mountmgr, tn, tnsize,
|
||||
NULL, 0, FALSE, &Event, &IoStatusBlock);
|
||||
if (!Irp) {
|
||||
ERR("IoBuildDeviceIoControlRequest failed\n");
|
||||
ERR("%.*S: IoBuildDeviceIoControlRequest 1 failed\n", us->Length / sizeof(WCHAR), us->Buffer);
|
||||
ExFreePool(tn);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -91,8 +149,10 @@ static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
|
|||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
ERR("IoCallDriver (1) returned %08x\n", Status);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("%.*S: IoCallDriver 1 returned %08x\n", us->Length / sizeof(WCHAR), us->Buffer, Status);
|
||||
return;
|
||||
}
|
||||
|
||||
ExFreePool(tn);
|
||||
|
||||
|
@ -113,7 +173,7 @@ static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
|
|||
mountmgr, mmdlt, mmdltsize,
|
||||
&mmdli, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION), FALSE, &Event, &IoStatusBlock);
|
||||
if (!Irp) {
|
||||
ERR("IoBuildDeviceIoControlRequest failed\n");
|
||||
ERR("%.*S: IoBuildDeviceIoControlRequest 2 failed\n", us->Length / sizeof(WCHAR), us->Buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -123,15 +183,15 @@ static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
|
|||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
ERR("IoCallDriver (2) returned %08x\n", Status);
|
||||
else
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("%.*S: IoCallDriver 2 returned %08x\n", us->Length / sizeof(WCHAR), us->Buffer, Status);
|
||||
} else
|
||||
TRACE("DriveLetterWasAssigned = %u, CurrentDriveLetter = %c\n", mmdli.DriveLetterWasAssigned, mmdli.CurrentDriveLetter);
|
||||
|
||||
ExFreePool(mmdlt);
|
||||
}
|
||||
|
||||
static void STDCALL test_vol(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us, LIST_ENTRY* volumes) {
|
||||
static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmgr, PUNICODE_STRING pardir, PUNICODE_STRING us, BOOL part0, LIST_ENTRY* volumes) {
|
||||
KEVENT Event;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
@ -143,10 +203,11 @@ static void STDCALL test_vol(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us, LIST_E
|
|||
UINT8* data;
|
||||
UNICODE_STRING us2;
|
||||
BOOL added_entry = FALSE;
|
||||
UINT32 sector_size;
|
||||
|
||||
TRACE("%.*S\n", us->Length / sizeof(WCHAR), us->Buffer);
|
||||
|
||||
us2.Length = ((wcslen(devpath) + 1) * sizeof(WCHAR)) + us->Length;
|
||||
us2.Length = pardir->Length + sizeof(WCHAR) + us->Length;
|
||||
us2.MaximumLength = us2.Length;
|
||||
us2.Buffer = ExAllocatePoolWithTag(PagedPool, us2.Length, ALLOC_TAG);
|
||||
if (!us2.Buffer) {
|
||||
|
@ -154,9 +215,9 @@ static void STDCALL test_vol(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us, LIST_E
|
|||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(us2.Buffer, devpath, wcslen(devpath) * sizeof(WCHAR));
|
||||
us2.Buffer[wcslen(devpath)] = '\\';
|
||||
RtlCopyMemory(&us2.Buffer[wcslen(devpath)+1], us->Buffer, us->Length);
|
||||
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);
|
||||
|
||||
|
@ -165,12 +226,40 @@ static void STDCALL test_vol(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us, LIST_E
|
|||
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sector_size = DeviceObject->SectorSize;
|
||||
|
||||
if (sector_size == 0) {
|
||||
DISK_GEOMETRY geometry;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
|
||||
Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
|
||||
&geometry, sizeof(DISK_GEOMETRY), TRUE, &iosb);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
Offset.QuadPart = superblock_addrs[0];
|
||||
|
||||
toread = sector_align(sizeof(superblock), DeviceObject->SectorSize);
|
||||
toread = sector_align(sizeof(superblock), sector_size);
|
||||
data = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
|
||||
if (!data) {
|
||||
ERR("out of memory\n");
|
||||
|
@ -192,22 +281,85 @@ static void STDCALL test_vol(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us, LIST_E
|
|||
}
|
||||
|
||||
if (NT_SUCCESS(Status) && IoStatusBlock.Information > 0 && ((superblock*)data)->magic == BTRFS_MAGIC) {
|
||||
int i;
|
||||
GET_LENGTH_INFORMATION gli;
|
||||
superblock* sb = (superblock*)data;
|
||||
volume* v = ExAllocatePoolWithTag(PagedPool, sizeof(volume), ALLOC_TAG);
|
||||
|
||||
if (!v) {
|
||||
ERR("out of memory\n");
|
||||
goto deref;
|
||||
}
|
||||
|
||||
v->devobj = DeviceObject;
|
||||
Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
|
||||
&gli, sizeof(gli), TRUE, NULL);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error reading length information: %08x\n", Status);
|
||||
goto deref;
|
||||
}
|
||||
|
||||
if (part0) {
|
||||
UNICODE_STRING us3;
|
||||
|
||||
Status = create_part0(DriverObject, DeviceObject, pardir, &us3, &sb->dev_item.device_uuid);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("create_part0 returned %08x\n", Status);
|
||||
goto deref;
|
||||
}
|
||||
|
||||
ExFreePool(us2.Buffer);
|
||||
us2 = us3;
|
||||
}
|
||||
|
||||
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;
|
||||
InsertTailList(volumes, &v->list_entry);
|
||||
|
||||
i = 1;
|
||||
while (superblock_addrs[i] != 0 && superblock_addrs[i] + toread <= v->length) {
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
Offset.QuadPart = superblock_addrs[i];
|
||||
|
||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, data, toread, &Offset, &Event, &IoStatusBlock);
|
||||
|
||||
if (!Irp) {
|
||||
ERR("IoBuildSynchronousFsdRequest failed\n");
|
||||
goto deref;
|
||||
}
|
||||
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
|
||||
|
||||
if (crc32 != *((UINT32*)sb->checksum))
|
||||
WARN("superblock %u CRC error\n", i);
|
||||
else if (sb->generation > v->gen1) {
|
||||
v->gen2 = v->gen1;
|
||||
v->gen1 = sb->generation;
|
||||
}
|
||||
} else {
|
||||
ERR("got error %08x while reading superblock %u\n", Status, i);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
TRACE("volume found\n");
|
||||
TRACE("gen1 = %llx, gen2 = %llx\n", v->gen1, v->gen2);
|
||||
TRACE("FS uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
|
||||
v->fsuuid.uuid[0], v->fsuuid.uuid[1], v->fsuuid.uuid[2], v->fsuuid.uuid[3], v->fsuuid.uuid[4], v->fsuuid.uuid[5], v->fsuuid.uuid[6], v->fsuuid.uuid[7],
|
||||
v->fsuuid.uuid[8], v->fsuuid.uuid[9], v->fsuuid.uuid[10], v->fsuuid.uuid[11], v->fsuuid.uuid[12], v->fsuuid.uuid[13], v->fsuuid.uuid[14], v->fsuuid.uuid[15]);
|
||||
|
@ -228,7 +380,192 @@ exit:
|
|||
ExFreePool(us2.Buffer);
|
||||
}
|
||||
|
||||
void STDCALL look_for_vols(LIST_ENTRY* volumes) {
|
||||
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) {
|
||||
NTSTATUS Status;
|
||||
KEVENT Event;
|
||||
PIRP Irp;
|
||||
MOUNTMGR_MOUNT_POINT* mmp;
|
||||
ULONG mmpsize;
|
||||
MOUNTMGR_MOUNT_POINTS mmps1, *mmps2;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
mmpsize = sizeof(MOUNTMGR_MOUNT_POINT) + v->devpath.Length;
|
||||
|
||||
mmp = ExAllocatePoolWithTag(PagedPool, mmpsize, ALLOC_TAG);
|
||||
if (!mmp) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
RtlZeroMemory(mmp, mmpsize);
|
||||
|
||||
mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
|
||||
mmp->DeviceNameLength = v->devpath.Length;
|
||||
RtlCopyMemory(&mmp[1], v->devpath.Buffer, v->devpath.Length);
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
|
||||
mountmgr, mmp, mmpsize,
|
||||
&mmps1, sizeof(MOUNTMGR_MOUNT_POINTS), FALSE, &Event, &IoStatusBlock);
|
||||
if (!Irp) {
|
||||
ERR("%.*S: IoBuildDeviceIoControlRequest 1 failed\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer);
|
||||
ExFreePool(mmp);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = IoCallDriver(mountmgr, Irp);
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
|
||||
ERR("%.*S: IoCallDriver 1 returned %08x\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer, Status);
|
||||
ExFreePool(mmp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Status != STATUS_BUFFER_OVERFLOW || mmps1.Size == 0) {
|
||||
ExFreePool(mmp);
|
||||
return;
|
||||
}
|
||||
|
||||
mmps2 = ExAllocatePoolWithTag(PagedPool, mmps1.Size, ALLOC_TAG);
|
||||
if (!mmps2) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(mmp);
|
||||
return;
|
||||
}
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
|
||||
mountmgr, mmp, mmpsize,
|
||||
mmps2, mmps1.Size, FALSE, &Event, &IoStatusBlock);
|
||||
if (!Irp) {
|
||||
ERR("%.*S: IoBuildDeviceIoControlRequest 2 failed\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer);
|
||||
ExFreePool(mmps2);
|
||||
ExFreePool(mmp);
|
||||
return;
|
||||
}
|
||||
|
||||
Status = IoCallDriver(mountmgr, Irp);
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("%.*S: IoCallDriver 2 returned %08x\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer, Status);
|
||||
ExFreePool(mmps2);
|
||||
ExFreePool(mmp);
|
||||
return;
|
||||
}
|
||||
|
||||
ExFreePool(mmps2);
|
||||
ExFreePool(mmp);
|
||||
}
|
||||
|
||||
void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes) {
|
||||
PFILE_OBJECT FileObject;
|
||||
PDEVICE_OBJECT mountmgr;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
|
@ -241,8 +578,8 @@ void STDCALL look_for_vols(LIST_ENTRY* volumes) {
|
|||
NTSTATUS Status;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
static const WCHAR hdv[] = {'H','a','r','d','d','i','s','k','V','o','l','u','m','e',0};
|
||||
static const WCHAR device[] = {'D','e','v','i','c','e',0};
|
||||
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);
|
||||
|
@ -271,6 +608,7 @@ void STDCALL look_for_vols(LIST_ENTRY* volumes) {
|
|||
odi = ExAllocatePoolWithTag(PagedPool, odisize, ALLOC_TAG);
|
||||
if (!odi) {
|
||||
ERR("out of memory\n");
|
||||
ZwClose(h);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -286,21 +624,21 @@ void STDCALL look_for_vols(LIST_ENTRY* volumes) {
|
|||
OBJECT_DIRECTORY_INFORMATION* odi2 = odi;
|
||||
|
||||
while (odi2->Name.Buffer) {
|
||||
if (odi2->TypeName.Length == wcslen(device) * sizeof(WCHAR) &&
|
||||
RtlCompareMemory(odi2->TypeName.Buffer, device, wcslen(device) * sizeof(WCHAR)) == wcslen(device) * sizeof(WCHAR) &&
|
||||
odi2->Name.Length > wcslen(hdv) * sizeof(WCHAR) &&
|
||||
RtlCompareMemory(odi2->Name.Buffer, hdv, wcslen(hdv) * sizeof(WCHAR)) == wcslen(hdv) * sizeof(WCHAR)) {
|
||||
test_vol(mountmgr, &odi2->Name, volumes);
|
||||
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);
|
||||
|
||||
// FIXME - if Windows has already added the second device of a filesystem itself, delete it
|
||||
|
||||
le = volumes->Flink;
|
||||
while (le != volumes) {
|
||||
volume* v = CONTAINING_RECORD(le, volume, list_entry);
|
||||
|
@ -315,8 +653,11 @@ void STDCALL look_for_vols(LIST_ENTRY* volumes) {
|
|||
if (RtlCompareMemory(&v2->fsuuid, &v->fsuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
|
||||
v2->processed = TRUE;
|
||||
|
||||
if (v2->devnum < mountvol->devnum)
|
||||
if (v2->devnum < mountvol->devnum) {
|
||||
remove_drive_letter(mountmgr, mountvol);
|
||||
mountvol = v2;
|
||||
} else if (v2->devnum > mountvol->devnum)
|
||||
remove_drive_letter(mountmgr, v2);
|
||||
}
|
||||
|
||||
le2 = le2->Flink;
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
#define SEF_DACL_AUTO_INHERIT 0x01
|
||||
#define SEF_SACL_AUTO_INHERIT 0x02
|
||||
|
||||
typedef struct {
|
||||
UCHAR revision;
|
||||
UCHAR elements;
|
||||
|
@ -382,103 +385,6 @@ static ACL* load_default_acl() {
|
|||
return acl;
|
||||
}
|
||||
|
||||
static ACL* inherit_acl(SECURITY_DESCRIPTOR* parsd, BOOL file) {
|
||||
ULONG size;
|
||||
NTSTATUS Status;
|
||||
ACL *paracl, *acl;
|
||||
BOOLEAN parhasdacl, pardefaulted;
|
||||
ACE_HEADER *ah, *parah;
|
||||
UINT32 i;
|
||||
USHORT num_aces;
|
||||
|
||||
// FIXME - replace this with SeAssignSecurity
|
||||
|
||||
Status = RtlGetDaclSecurityDescriptor(parsd, &parhasdacl, ¶cl, &pardefaulted);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlGetDaclSecurityDescriptor returned %08x\n", Status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// FIXME - handle parhasdacl == FALSE
|
||||
|
||||
// OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE
|
||||
num_aces = 0;
|
||||
size = sizeof(ACL);
|
||||
ah = (ACE_HEADER*)¶cl[1];
|
||||
for (i = 0; i < paracl->AceCount; i++) {
|
||||
if (!file && ah->AceFlags & CONTAINER_INHERIT_ACE) {
|
||||
num_aces++;
|
||||
size += ah->AceSize;
|
||||
|
||||
if (ah->AceFlags & INHERIT_ONLY_ACE) {
|
||||
num_aces++;
|
||||
size += ah->AceSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (ah->AceFlags & OBJECT_INHERIT_ACE && (file || !(ah->AceFlags & CONTAINER_INHERIT_ACE))) {
|
||||
num_aces++;
|
||||
size += ah->AceSize;
|
||||
}
|
||||
|
||||
ah = (ACE_HEADER*)((UINT8*)ah + ah->AceSize);
|
||||
}
|
||||
|
||||
acl = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
|
||||
if (!acl) {
|
||||
ERR("out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
acl->AclRevision = ACL_REVISION;
|
||||
acl->Sbz1 = 0;
|
||||
acl->AclSize = size;
|
||||
acl->AceCount = num_aces;
|
||||
acl->Sbz2 = 0;
|
||||
|
||||
ah = (ACE_HEADER*)&acl[1];
|
||||
parah = (ACE_HEADER*)¶cl[1];
|
||||
for (i = 0; i < paracl->AceCount; i++) {
|
||||
if (!file && parah->AceFlags & CONTAINER_INHERIT_ACE) {
|
||||
if (parah->AceFlags & INHERIT_ONLY_ACE) {
|
||||
RtlCopyMemory(ah, parah, parah->AceSize);
|
||||
ah->AceFlags &= ~INHERIT_ONLY_ACE;
|
||||
ah->AceFlags |= INHERITED_ACE;
|
||||
ah->AceFlags &= ~(OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
||||
|
||||
ah = (ACE_HEADER*)((UINT8*)ah + ah->AceSize);
|
||||
}
|
||||
|
||||
RtlCopyMemory(ah, parah, parah->AceSize);
|
||||
ah->AceFlags |= INHERITED_ACE;
|
||||
|
||||
if (ah->AceFlags & NO_PROPAGATE_INHERIT_ACE)
|
||||
ah->AceFlags &= ~(OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
||||
|
||||
ah = (ACE_HEADER*)((UINT8*)ah + ah->AceSize);
|
||||
}
|
||||
|
||||
if (parah->AceFlags & OBJECT_INHERIT_ACE && (file || !(parah->AceFlags & CONTAINER_INHERIT_ACE))) {
|
||||
RtlCopyMemory(ah, parah, parah->AceSize);
|
||||
ah->AceFlags |= INHERITED_ACE;
|
||||
|
||||
if (file)
|
||||
ah->AceFlags &= ~INHERIT_ONLY_ACE;
|
||||
else
|
||||
ah->AceFlags |= INHERIT_ONLY_ACE;
|
||||
|
||||
if (ah->AceFlags & NO_PROPAGATE_INHERIT_ACE || file)
|
||||
ah->AceFlags &= ~(OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
|
||||
|
||||
ah = (ACE_HEADER*)((UINT8*)ah + ah->AceSize);
|
||||
}
|
||||
|
||||
parah = (ACE_HEADER*)((UINT8*)parah + parah->AceSize);
|
||||
}
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
// static void STDCALL sid_to_string(PSID sid, char* s) {
|
||||
// sid_header* sh = (sid_header*)sid;
|
||||
// LARGE_INTEGER authnum;
|
||||
|
@ -532,7 +438,7 @@ static BOOL get_sd_from_xattr(fcb* fcb) {
|
|||
ERR("RtlSelfRelativeToAbsoluteSD 1 returned %08x\n", Status);
|
||||
}
|
||||
|
||||
ERR("sdsize = %u, daclsize = %u, saclsize = %u, ownersize = %u, groupsize = %u\n", sdsize, daclsize, saclsize, ownersize, groupsize);
|
||||
TRACE("sdsize = %u, daclsize = %u, saclsize = %u, ownersize = %u, groupsize = %u\n", sdsize, daclsize, saclsize, ownersize, groupsize);
|
||||
|
||||
newsd2 = sdsize == 0 ? NULL : ExAllocatePoolWithTag(PagedPool, sdsize, ALLOC_TAG);
|
||||
dacl = daclsize == 0 ? NULL : ExAllocatePoolWithTag(PagedPool, daclsize, ALLOC_TAG);
|
||||
|
@ -540,7 +446,7 @@ static BOOL get_sd_from_xattr(fcb* fcb) {
|
|||
owner = ownersize == 0 ? NULL : ExAllocatePoolWithTag(PagedPool, ownersize, ALLOC_TAG);
|
||||
group = groupsize == 0 ? NULL : ExAllocatePoolWithTag(PagedPool, groupsize, ALLOC_TAG);
|
||||
|
||||
if ((sdsize > 0 && !newsd2) || (daclsize > 0 && !dacl) || (saclsize > 0 && !sacl) || (ownersize > 0 && !owner) || (groupsize > 0 || !group)) {
|
||||
if ((sdsize > 0 && !newsd2) || (daclsize > 0 && !dacl) || (saclsize > 0 && !sacl) || (ownersize > 0 && !owner) || (groupsize > 0 && !group)) {
|
||||
ERR("out of memory\n");
|
||||
if (newsd2) ExFreePool(newsd2);
|
||||
if (dacl) ExFreePool(dacl);
|
||||
|
@ -646,16 +552,13 @@ static BOOL get_sd_from_xattr(fcb* fcb) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void fcb_get_sd(fcb* fcb, struct _fcb* parent) {
|
||||
static void get_top_level_sd(fcb* fcb) {
|
||||
NTSTATUS Status;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
ULONG buflen;
|
||||
ACL* acl = NULL;
|
||||
PSID usersid = NULL, groupsid = NULL;
|
||||
|
||||
if (get_sd_from_xattr(fcb))
|
||||
goto end;
|
||||
|
||||
Status = RtlCreateSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
|
@ -694,14 +597,10 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent) {
|
|||
}
|
||||
// }
|
||||
|
||||
if (!parent)
|
||||
acl = load_default_acl();
|
||||
else
|
||||
acl = inherit_acl(parent->sd, fcb->type != BTRFS_TYPE_DIRECTORY);
|
||||
acl = load_default_acl();
|
||||
|
||||
if (!acl) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -755,6 +654,47 @@ end:
|
|||
ExFreePool(groupsid);
|
||||
}
|
||||
|
||||
void fcb_get_sd(fcb* fcb, struct _fcb* parent) {
|
||||
NTSTATUS Status;
|
||||
PSID usersid = NULL, groupsid = NULL;
|
||||
SECURITY_SUBJECT_CONTEXT subjcont;
|
||||
|
||||
if (get_sd_from_xattr(fcb))
|
||||
return;
|
||||
|
||||
if (!parent) {
|
||||
get_top_level_sd(fcb);
|
||||
return;
|
||||
}
|
||||
|
||||
SeCaptureSubjectContext(&subjcont);
|
||||
|
||||
Status = SeAssignSecurityEx(parent->sd, NULL, (void**)&fcb->sd, NULL, fcb->type == BTRFS_TYPE_DIRECTORY, SEF_DACL_AUTO_INHERIT,
|
||||
&subjcont, IoGetFileObjectGenericMapping(), PagedPool);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("SeAssignSecurityEx returned %08x\n", Status);
|
||||
}
|
||||
|
||||
uid_to_sid(fcb->inode_item.st_uid, &usersid);
|
||||
if (!usersid) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
RtlSetOwnerSecurityDescriptor(&fcb->sd, usersid, FALSE);
|
||||
|
||||
gid_to_sid(fcb->inode_item.st_gid, &groupsid);
|
||||
if (!groupsid) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
RtlSetGroupSecurityDescriptor(&fcb->sd, groupsid, FALSE);
|
||||
|
||||
ExFreePool(usersid);
|
||||
ExFreePool(groupsid);
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL get_file_security(device_extension* Vcb, PFILE_OBJECT FileObject, SECURITY_DESCRIPTOR* relsd, ULONG* buflen, SECURITY_INFORMATION flags) {
|
||||
NTSTATUS Status;
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
|
@ -787,8 +727,11 @@ NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|||
NTSTATUS Status;
|
||||
SECURITY_DESCRIPTOR* sd;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
device_extension* Vcb = DeviceObject->DeviceExtension;
|
||||
ULONG buflen;
|
||||
BOOL top_level;
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
ccb* ccb = FileObject ? FileObject->FsContext2 : NULL;
|
||||
|
||||
TRACE("query security\n");
|
||||
|
||||
|
@ -796,6 +739,23 @@ NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|||
|
||||
top_level = is_top_level(Irp);
|
||||
|
||||
if (Vcb && Vcb->type == VCB_TYPE_PARTITION0) {
|
||||
Status = part0_passthrough(DeviceObject, Irp);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!ccb) {
|
||||
ERR("no ccb\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (Irp->RequestorMode == UserMode && !(ccb->access & READ_CONTROL)) {
|
||||
WARN("insufficient permissions\n");
|
||||
Status = STATUS_ACCESS_DENIED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
@ -820,12 +780,13 @@ NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|||
|
||||
if (Irp->MdlAddress && !sd) {
|
||||
ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
buflen = IrpSp->Parameters.QuerySecurity.Length;
|
||||
|
||||
Status = get_file_security(DeviceObject->DeviceExtension, IrpSp->FileObject, sd, &buflen, IrpSp->Parameters.QuerySecurity.SecurityInformation);
|
||||
Status = get_file_security(Vcb, IrpSp->FileObject, sd, &buflen, IrpSp->Parameters.QuerySecurity.SecurityInformation);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Irp->IoStatus.Information = IrpSp->Parameters.QuerySecurity.Length;
|
||||
|
@ -835,12 +796,14 @@ NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|||
} else
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
end:
|
||||
TRACE("Irp->IoStatus.Information = %u\n", Irp->IoStatus.Information);
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
exit:
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
|
@ -857,31 +820,26 @@ static NTSTATUS STDCALL set_file_security(device_extension* Vcb, PFILE_OBJECT Fi
|
|||
ccb* ccb = FileObject->FsContext2;
|
||||
file_ref* fileref = ccb ? ccb->fileref : NULL;
|
||||
SECURITY_DESCRIPTOR* oldsd;
|
||||
INODE_ITEM* ii;
|
||||
KEY searchkey;
|
||||
traverse_ptr tp;
|
||||
LARGE_INTEGER time;
|
||||
BTRFS_TIME now;
|
||||
LIST_ENTRY rollback;
|
||||
|
||||
TRACE("(%p, %p, %p, %x)\n", Vcb, FileObject, sd, flags);
|
||||
|
||||
InitializeListHead(&rollback);
|
||||
|
||||
if (Vcb->readonly)
|
||||
return STATUS_MEDIA_WRITE_PROTECTED;
|
||||
|
||||
acquire_tree_lock(Vcb, TRUE);
|
||||
|
||||
if (fcb->ads) {
|
||||
if (fileref && fileref->parent)
|
||||
fcb = fileref->parent->fcb;
|
||||
else {
|
||||
ERR("could not find parent fcb for stream\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
|
||||
|
||||
if (fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY) {
|
||||
Status = STATUS_ACCESS_DENIED;
|
||||
goto end;
|
||||
|
@ -898,24 +856,6 @@ static NTSTATUS STDCALL set_file_security(device_extension* Vcb, PFILE_OBJECT Fi
|
|||
|
||||
ExFreePool(oldsd);
|
||||
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_INODE_ITEM;
|
||||
searchkey.offset = 0;
|
||||
|
||||
Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (keycmp(&tp.item->key, &searchkey)) {
|
||||
ERR("error - could not find INODE_ITEM for inode %llx in subvol %llx\n", fcb->inode, fcb->subvol->id);
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto end;
|
||||
}
|
||||
|
||||
delete_tree_item(Vcb, &tp, &rollback);
|
||||
|
||||
KeQuerySystemTime(&time);
|
||||
win_time_to_unix(time, &now);
|
||||
|
||||
|
@ -937,48 +877,28 @@ static NTSTATUS STDCALL set_file_security(device_extension* Vcb, PFILE_OBJECT Fi
|
|||
fcb->inode_item.st_uid = sid_to_uid(owner);
|
||||
}
|
||||
|
||||
ii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
|
||||
if (!ii) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
RtlCopyMemory(ii, &fcb->inode_item, sizeof(INODE_ITEM));
|
||||
|
||||
if (!insert_tree_item(Vcb, fcb->subvol, fcb->inode, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, &rollback)) {
|
||||
ERR("error - failed to insert INODE_ITEM\n");
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
ExFreePool(ii);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = set_xattr(Vcb, fcb->subvol, fcb->inode, EA_NTACL, EA_NTACL_HASH, (UINT8*)fcb->sd, RtlLengthSecurityDescriptor(fcb->sd), &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("set_xattr returned %08x\n", Status);
|
||||
ExFreePool(ii);
|
||||
goto end;
|
||||
}
|
||||
fcb->sd_dirty = TRUE;
|
||||
|
||||
fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
|
||||
fcb->subvol->root_item.ctime = now;
|
||||
|
||||
Status = consider_write(Vcb);
|
||||
mark_fcb_dirty(fcb);
|
||||
|
||||
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED);
|
||||
|
||||
end:
|
||||
if (NT_SUCCESS(Status))
|
||||
clear_rollback(&rollback);
|
||||
else
|
||||
do_rollback(Vcb, &rollback);
|
||||
ExReleaseResourceLite(fcb->Header.Resource);
|
||||
|
||||
release_tree_lock(Vcb, TRUE);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
|
||||
NTSTATUS Status;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
ccb* ccb = FileObject ? FileObject->FsContext2 : NULL;
|
||||
device_extension* Vcb = DeviceObject->DeviceExtension;
|
||||
ULONG access_req = 0;
|
||||
BOOL top_level;
|
||||
|
||||
TRACE("set security\n");
|
||||
|
@ -987,34 +907,58 @@ NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
|
|||
|
||||
top_level = is_top_level(Irp);
|
||||
|
||||
if (Vcb && Vcb->type == VCB_TYPE_PARTITION0) {
|
||||
Status = part0_passthrough(DeviceObject, Irp);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!ccb) {
|
||||
ERR("no ccb\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & OWNER_SECURITY_INFORMATION)
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & OWNER_SECURITY_INFORMATION) {
|
||||
TRACE("OWNER_SECURITY_INFORMATION\n");
|
||||
access_req |= WRITE_OWNER;
|
||||
}
|
||||
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & GROUP_SECURITY_INFORMATION)
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & GROUP_SECURITY_INFORMATION) {
|
||||
TRACE("GROUP_SECURITY_INFORMATION\n");
|
||||
access_req |= WRITE_OWNER;
|
||||
}
|
||||
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & DACL_SECURITY_INFORMATION)
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & DACL_SECURITY_INFORMATION) {
|
||||
TRACE("DACL_SECURITY_INFORMATION\n");
|
||||
access_req |= WRITE_DAC;
|
||||
}
|
||||
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & SACL_SECURITY_INFORMATION)
|
||||
if (IrpSp->Parameters.QuerySecurity.SecurityInformation & SACL_SECURITY_INFORMATION) {
|
||||
TRACE("SACL_SECURITY_INFORMATION\n");
|
||||
access_req |= ACCESS_SYSTEM_SECURITY;
|
||||
}
|
||||
|
||||
Status = set_file_security(DeviceObject->DeviceExtension, IrpSp->FileObject, IrpSp->Parameters.SetSecurity.SecurityDescriptor,
|
||||
if ((ccb->access & access_req) != access_req) {
|
||||
Status = STATUS_ACCESS_DENIED;
|
||||
WARN("insufficient privileges\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = set_file_security(DeviceObject->DeviceExtension, FileObject, IrpSp->Parameters.SetSecurity.SecurityDescriptor,
|
||||
IrpSp->Parameters.SetSecurity.SecurityInformation);
|
||||
|
||||
end:
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
TRACE("returning %08x\n", Status);
|
||||
|
||||
|
||||
exit:
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
|
@ -1023,16 +967,16 @@ NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
|
|||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* fileref, ACCESS_STATE* as) {
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as) {
|
||||
NTSTATUS Status;
|
||||
PSID owner;
|
||||
BOOLEAN defaulted;
|
||||
|
||||
Status = SeAssignSecurity((fileref && fileref->parent) ? fileref->parent->fcb->sd : NULL, as->SecurityDescriptor, (void**)&fcb->sd, fcb->type == BTRFS_TYPE_DIRECTORY,
|
||||
&as->SubjectSecurityContext, IoGetFileObjectGenericMapping(), PagedPool);
|
||||
|
||||
Status = SeAssignSecurityEx(parfileref ? parfileref->fcb->sd : NULL, as->SecurityDescriptor, (void**)&fcb->sd, NULL, fcb->type == BTRFS_TYPE_DIRECTORY,
|
||||
SEF_SACL_AUTO_INHERIT, &as->SubjectSecurityContext, IoGetFileObjectGenericMapping(), PagedPool);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("SeAssignSecurity returned %08x\n", Status);
|
||||
ERR("SeAssignSecurityEx returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,355 +19,20 @@
|
|||
|
||||
// #define DEBUG_TREE_LOCKS
|
||||
|
||||
enum read_tree_status {
|
||||
ReadTreeStatus_Pending,
|
||||
ReadTreeStatus_Success,
|
||||
ReadTreeStatus_Cancelling,
|
||||
ReadTreeStatus_Cancelled,
|
||||
ReadTreeStatus_Error,
|
||||
ReadTreeStatus_CRCError,
|
||||
ReadTreeStatus_MissingDevice
|
||||
};
|
||||
|
||||
struct read_tree_context;
|
||||
|
||||
typedef struct {
|
||||
struct read_tree_context* context;
|
||||
UINT8* buf;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
enum read_tree_status status;
|
||||
} read_tree_stripe;
|
||||
|
||||
typedef struct {
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
chunk* c;
|
||||
// UINT8* buf;
|
||||
UINT32 buflen;
|
||||
UINT64 num_stripes;
|
||||
LONG stripes_left;
|
||||
UINT64 type;
|
||||
read_tree_stripe* stripes;
|
||||
} read_tree_context;
|
||||
|
||||
enum rollback_type {
|
||||
ROLLBACK_INSERT_ITEM,
|
||||
ROLLBACK_DELETE_ITEM
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum rollback_type type;
|
||||
void* ptr;
|
||||
LIST_ENTRY list_entry;
|
||||
} rollback_item;
|
||||
|
||||
static NTSTATUS STDCALL read_tree_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
|
||||
read_tree_stripe* stripe = conptr;
|
||||
read_tree_context* context = (read_tree_context*)stripe->context;
|
||||
UINT64 i;
|
||||
|
||||
if (stripe->status == ReadTreeStatus_Cancelling) {
|
||||
stripe->status = ReadTreeStatus_Cancelled;
|
||||
goto end;
|
||||
}
|
||||
|
||||
stripe->iosb = Irp->IoStatus;
|
||||
|
||||
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
||||
tree_header* th = (tree_header*)stripe->buf;
|
||||
UINT32 crc32;
|
||||
|
||||
crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&th->fs_uuid, context->buflen - sizeof(th->csum));
|
||||
|
||||
if (crc32 == *((UINT32*)th->csum)) {
|
||||
stripe->status = ReadTreeStatus_Success;
|
||||
|
||||
for (i = 0; i < context->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadTreeStatus_Pending) {
|
||||
context->stripes[i].status = ReadTreeStatus_Cancelling;
|
||||
IoCancelIrp(context->stripes[i].Irp);
|
||||
}
|
||||
}
|
||||
|
||||
goto end;
|
||||
} else
|
||||
stripe->status = ReadTreeStatus_CRCError;
|
||||
} else {
|
||||
stripe->status = ReadTreeStatus_Error;
|
||||
}
|
||||
|
||||
end:
|
||||
if (InterlockedDecrement(&context->stripes_left) == 0)
|
||||
KeSetEvent(&context->Event, 0, FALSE);
|
||||
|
||||
// return STATUS_SUCCESS;
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL read_tree(device_extension* Vcb, UINT64 addr, UINT8* buf) {
|
||||
CHUNK_ITEM* ci;
|
||||
CHUNK_ITEM_STRIPE* cis;
|
||||
read_tree_context* context;
|
||||
UINT64 i/*, type*/, offset;
|
||||
NTSTATUS Status;
|
||||
device** devices;
|
||||
|
||||
// FIXME - make this work with RAID
|
||||
|
||||
if (Vcb->log_to_phys_loaded) {
|
||||
chunk* c = get_chunk_from_address(Vcb, addr);
|
||||
|
||||
if (!c) {
|
||||
ERR("get_chunk_from_address failed\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ci = c->chunk_item;
|
||||
offset = c->offset;
|
||||
devices = c->devices;
|
||||
} else {
|
||||
LIST_ENTRY* le = Vcb->sys_chunks.Flink;
|
||||
|
||||
ci = NULL;
|
||||
|
||||
while (le != &Vcb->sys_chunks) {
|
||||
sys_chunk* sc = CONTAINING_RECORD(le, sys_chunk, list_entry);
|
||||
|
||||
if (sc->key.obj_id == 0x100 && sc->key.obj_type == TYPE_CHUNK_ITEM && sc->key.offset <= addr) {
|
||||
CHUNK_ITEM* chunk_item = sc->data;
|
||||
|
||||
if ((addr - sc->key.offset) < chunk_item->size && chunk_item->num_stripes > 0) {
|
||||
ci = chunk_item;
|
||||
offset = sc->key.offset;
|
||||
cis = (CHUNK_ITEM_STRIPE*)&chunk_item[1];
|
||||
|
||||
devices = ExAllocatePoolWithTag(PagedPool, sizeof(device*) * ci->num_stripes, ALLOC_TAG);
|
||||
if (!devices) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
if (!ci) {
|
||||
ERR("could not find chunk for %llx in bootstrap\n", addr);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// if (ci->type & BLOCK_FLAG_DUPLICATE) {
|
||||
// type = BLOCK_FLAG_DUPLICATE;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID0) {
|
||||
// FIXME("RAID0 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID1) {
|
||||
// FIXME("RAID1 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID10) {
|
||||
// FIXME("RAID10 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID5) {
|
||||
// FIXME("RAID5 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID6) {
|
||||
// FIXME("RAID6 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else { // SINGLE
|
||||
// type = 0;
|
||||
// }
|
||||
|
||||
cis = (CHUNK_ITEM_STRIPE*)&ci[1];
|
||||
|
||||
context = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_tree_context), ALLOC_TAG);
|
||||
if (!context) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(context, sizeof(read_tree_context));
|
||||
KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
|
||||
|
||||
context->stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_tree_stripe) * ci->num_stripes, ALLOC_TAG);
|
||||
if (!context->stripes) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(context);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(context->stripes, sizeof(read_tree_stripe) * ci->num_stripes);
|
||||
|
||||
context->buflen = Vcb->superblock.node_size;
|
||||
context->num_stripes = ci->num_stripes;
|
||||
context->stripes_left = context->num_stripes;
|
||||
// context->type = type;
|
||||
|
||||
// FIXME - for RAID, check beforehand whether there's enough devices to satisfy request
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
if (!devices[i]) {
|
||||
context->stripes[i].status = ReadTreeStatus_MissingDevice;
|
||||
context->stripes[i].buf = NULL;
|
||||
context->stripes_left--;
|
||||
} else {
|
||||
context->stripes[i].context = (struct read_tree_context*)context;
|
||||
context->stripes[i].buf = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.node_size, ALLOC_TAG);
|
||||
|
||||
if (!context->stripes[i].buf) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
context->stripes[i].Irp = IoAllocateIrp(devices[i]->devobj->StackSize, FALSE);
|
||||
|
||||
if (!context->stripes[i].Irp) {
|
||||
ERR("IoAllocateIrp failed\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
IrpSp = IoGetNextIrpStackLocation(context->stripes[i].Irp);
|
||||
IrpSp->MajorFunction = IRP_MJ_READ;
|
||||
|
||||
if (devices[i]->devobj->Flags & DO_BUFFERED_IO) {
|
||||
FIXME("FIXME - buffered IO\n");
|
||||
} else if (devices[i]->devobj->Flags & DO_DIRECT_IO) {
|
||||
context->stripes[i].Irp->MdlAddress = IoAllocateMdl(context->stripes[i].buf, Vcb->superblock.node_size, FALSE, FALSE, NULL);
|
||||
if (!context->stripes[i].Irp->MdlAddress) {
|
||||
ERR("IoAllocateMdl failed\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
MmProbeAndLockPages(context->stripes[i].Irp->MdlAddress, KernelMode, IoWriteAccess);
|
||||
} else {
|
||||
context->stripes[i].Irp->UserBuffer = context->stripes[i].buf;
|
||||
}
|
||||
|
||||
IrpSp->Parameters.Read.Length = Vcb->superblock.node_size;
|
||||
IrpSp->Parameters.Read.ByteOffset.QuadPart = addr - offset + cis[i].offset;
|
||||
|
||||
context->stripes[i].Irp->UserIosb = &context->stripes[i].iosb;
|
||||
|
||||
IoSetCompletionRoutine(context->stripes[i].Irp, read_tree_completion, &context->stripes[i], TRUE, TRUE, TRUE);
|
||||
|
||||
context->stripes[i].status = ReadTreeStatus_Pending;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status != ReadTreeStatus_MissingDevice) {
|
||||
IoCallDriver(devices[i]->devobj, context->stripes[i].Irp);
|
||||
}
|
||||
}
|
||||
|
||||
KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
// FIXME - if checksum error, write good data over bad
|
||||
|
||||
// check if any of the devices return a "user-induced" error
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadTreeStatus_Error && IoIsErrorUserInduced(context->stripes[i].iosb.Status)) {
|
||||
IoSetHardErrorOrVerifyDevice(context->stripes[i].Irp, devices[i]->devobj);
|
||||
|
||||
Status = context->stripes[i].iosb.Status;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// check if any of the stripes succeeded
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadTreeStatus_Success) {
|
||||
RtlCopyMemory(buf, context->stripes[i].buf, Vcb->superblock.node_size);
|
||||
Status = STATUS_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// if not, see if we got a checksum error
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadTreeStatus_CRCError) {
|
||||
#ifdef _DEBUG
|
||||
tree_header* th = (tree_header*)context->stripes[i].buf;
|
||||
UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&th->fs_uuid, context->buflen - sizeof(th->csum));
|
||||
// UINT64 j;
|
||||
|
||||
WARN("stripe %llu had a checksum error\n", i);
|
||||
WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)th->csum));
|
||||
#endif
|
||||
|
||||
// for (j = 0; j < ci->num_stripes; j++) {
|
||||
// WARN("stripe %llu: device = %p, status = %u\n", j, c->devices[j], context->stripes[j].status);
|
||||
// }
|
||||
// int3;
|
||||
|
||||
Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// failing that, return the first error we encountered
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadTreeStatus_Error) {
|
||||
Status = context->stripes[i].iosb.Status;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// if we somehow get here, return STATUS_INTERNAL_ERROR
|
||||
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
|
||||
// for (i = 0; i < ci->num_stripes; i++) {
|
||||
// ERR("%llx: status = %u, NTSTATUS = %08x\n", i, context->stripes[i].status, context->stripes[i].iosb.Status);
|
||||
// }
|
||||
exit:
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].Irp) {
|
||||
if (devices[i]->devobj->Flags & DO_DIRECT_IO) {
|
||||
MmUnlockPages(context->stripes[i].Irp->MdlAddress);
|
||||
IoFreeMdl(context->stripes[i].Irp->MdlAddress);
|
||||
}
|
||||
IoFreeIrp(context->stripes[i].Irp);
|
||||
}
|
||||
|
||||
if (context->stripes[i].buf)
|
||||
ExFreePool(context->stripes[i].buf);
|
||||
}
|
||||
|
||||
ExFreePool(context->stripes);
|
||||
ExFreePool(context);
|
||||
|
||||
if (!Vcb->log_to_phys_loaded)
|
||||
ExFreePool(devices);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, const char* func, const char* file, unsigned int line) {
|
||||
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, tree* parent, const char* func, const char* file, unsigned int line) {
|
||||
UINT8* buf;
|
||||
NTSTATUS Status;
|
||||
tree_header* th;
|
||||
tree* t;
|
||||
tree_data* td;
|
||||
chunk* c;
|
||||
shared_data* sd;
|
||||
|
||||
TRACE("(%p, %llx)\n", Vcb, addr);
|
||||
|
||||
|
@ -377,9 +42,9 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
Status = read_tree(Vcb, addr, buf);
|
||||
Status = read_data(Vcb, addr, Vcb->superblock.node_size, NULL, TRUE, buf, &c, NULL);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_tree returned 0x%08x\n", Status);
|
||||
ERR("read_data returned 0x%08x\n", Status);
|
||||
ExFreePool(buf);
|
||||
return Status;
|
||||
}
|
||||
|
@ -407,8 +72,6 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
t->has_new_address = FALSE;
|
||||
t->write = FALSE;
|
||||
|
||||
c = get_chunk_from_address(Vcb, addr);
|
||||
|
||||
if (c)
|
||||
t->flags = c->chunk_item->type;
|
||||
else
|
||||
|
@ -419,10 +82,31 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
// t->items = ExAllocatePoolWithTag(PagedPool, num_items * sizeof(tree_data), ALLOC_TAG);
|
||||
InitializeListHead(&t->itemlist);
|
||||
|
||||
if (t->header.flags & HEADER_FLAG_SHARED_BACKREF || !(t->header.flags & HEADER_FLAG_MIXED_BACKREF)) {
|
||||
sd = ExAllocatePoolWithTag(NonPagedPool, sizeof(shared_data), ALLOC_TAG);
|
||||
if (!sd) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(buf);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
sd->address = addr;
|
||||
sd->parent = parent ? parent->header.address : addr;
|
||||
InitializeListHead(&sd->entries);
|
||||
|
||||
ExInterlockedInsertTailList(&Vcb->shared_extents, &sd->list_entry, &Vcb->shared_extents_lock);
|
||||
}
|
||||
|
||||
if (t->header.level == 0) { // leaf node
|
||||
leaf_node* ln = (leaf_node*)(buf + sizeof(tree_header));
|
||||
unsigned int i;
|
||||
|
||||
if ((t->header.num_items * sizeof(leaf_node)) + sizeof(tree_header) > Vcb->superblock.node_size) {
|
||||
ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items);
|
||||
ExFreePool(buf);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
for (i = 0; i < t->header.num_items; i++) {
|
||||
td = ExAllocatePoolWithTag(PagedPool, sizeof(tree_data), ALLOC_TAG);
|
||||
if (!td) {
|
||||
|
@ -446,6 +130,55 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
} else
|
||||
td->data = NULL;
|
||||
|
||||
if ((t->header.flags & HEADER_FLAG_SHARED_BACKREF || !(t->header.flags & HEADER_FLAG_MIXED_BACKREF)) &&
|
||||
ln[i].key.obj_type == TYPE_EXTENT_DATA && ln[i].size >= sizeof(EXTENT_DATA)) {
|
||||
EXTENT_DATA* ed = (EXTENT_DATA*)td->data;
|
||||
|
||||
if ((ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) && ln[i].size >= sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
|
||||
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
|
||||
|
||||
if (ed2->size != 0) {
|
||||
LIST_ENTRY* le;
|
||||
BOOL found = FALSE;
|
||||
|
||||
TRACE("shared extent %llx,%llx\n", ed2->address, ed2->size);
|
||||
|
||||
le = sd->entries.Flink;
|
||||
while (le != &sd->entries) {
|
||||
shared_data_entry* sde = CONTAINING_RECORD(le, shared_data_entry, list_entry);
|
||||
|
||||
if (sde->address == ed2->address && sde->size == ed2->size && sde->edr.root == t->header.tree_id &&
|
||||
sde->edr.objid == ln[i].key.obj_id && sde->edr.offset == ln[i].key.offset - ed2->offset) {
|
||||
sde->edr.count++;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
shared_data_entry* sde = ExAllocatePoolWithTag(PagedPool, sizeof(shared_data_entry), ALLOC_TAG);
|
||||
|
||||
if (!sde) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(buf);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
sde->address = ed2->address;
|
||||
sde->size = ed2->size;
|
||||
sde->edr.root = t->header.tree_id;
|
||||
sde->edr.objid = ln[i].key.obj_id;
|
||||
sde->edr.offset = ln[i].key.offset - ed2->offset;
|
||||
sde->edr.count = 1;
|
||||
|
||||
InsertTailList(&sd->entries, &sde->list_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td->size = ln[i].size;
|
||||
td->ignore = FALSE;
|
||||
td->inserted = FALSE;
|
||||
|
@ -460,6 +193,12 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
internal_node* in = (internal_node*)(buf + sizeof(tree_header));
|
||||
unsigned int i;
|
||||
|
||||
if ((t->header.num_items * sizeof(internal_node)) + sizeof(tree_header) > Vcb->superblock.node_size) {
|
||||
ERR("tree at %llx has more items than expected (%x)\n", t->header.num_items);
|
||||
ExFreePool(buf);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
for (i = 0; i < t->header.num_items; i++) {
|
||||
td = ExAllocatePoolWithTag(PagedPool, sizeof(tree_data), ALLOC_TAG);
|
||||
if (!td) {
|
||||
|
@ -474,7 +213,6 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
td->treeholder.address = in[i].address;
|
||||
td->treeholder.generation = in[i].generation;
|
||||
td->treeholder.tree = NULL;
|
||||
init_tree_holder(&td->treeholder);
|
||||
// td->treeholder.nonpaged->status = tree_holder_unloaded;
|
||||
td->ignore = FALSE;
|
||||
td->inserted = FALSE;
|
||||
|
@ -587,7 +325,7 @@ NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r,
|
|||
if (!th->tree) {
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = _load_tree(Vcb, th->address, r, &th->tree, func, file, line);
|
||||
Status = _load_tree(Vcb, th->address, r, &th->tree, t, func, file, line);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("load_tree returned %08x\n", Status);
|
||||
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
|
||||
|
@ -964,17 +702,20 @@ void free_trees_root(device_extension* Vcb, root* r) {
|
|||
LIST_ENTRY* nextle = le->Flink;
|
||||
tree* t = CONTAINING_RECORD(le, tree, list_entry);
|
||||
|
||||
if (t->root == r && t->header.level == level) {
|
||||
BOOL top = !t->paritem;
|
||||
|
||||
empty = FALSE;
|
||||
|
||||
free_tree2(t, funcname, __FILE__, __LINE__);
|
||||
if (top && r->treeholder.tree == t)
|
||||
r->treeholder.tree = NULL;
|
||||
|
||||
if (IsListEmpty(&Vcb->trees))
|
||||
return;
|
||||
if (t->root == r) {
|
||||
if (t->header.level == level) {
|
||||
BOOL top = !t->paritem;
|
||||
|
||||
empty = FALSE;
|
||||
|
||||
free_tree2(t, funcname, __FILE__, __LINE__);
|
||||
if (top && r->treeholder.tree == t)
|
||||
r->treeholder.tree = NULL;
|
||||
|
||||
if (IsListEmpty(&Vcb->trees))
|
||||
return;
|
||||
} else if (t->header.level > level)
|
||||
empty = FALSE;
|
||||
}
|
||||
|
||||
le = nextle;
|
||||
|
@ -986,22 +727,59 @@ void free_trees_root(device_extension* Vcb, root* r) {
|
|||
}
|
||||
|
||||
void STDCALL free_trees(device_extension* Vcb) {
|
||||
tree* t;
|
||||
root* r;
|
||||
|
||||
while (!IsListEmpty(&Vcb->trees)) {
|
||||
t = CONTAINING_RECORD(Vcb->trees.Flink, tree, list_entry);
|
||||
r = t->root;
|
||||
LIST_ENTRY* le;
|
||||
UINT8 level;
|
||||
|
||||
for (level = 0; level <= 255; level++) {
|
||||
BOOL empty = TRUE;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
|
||||
le = Vcb->trees.Flink;
|
||||
|
||||
free_trees_root(Vcb, r);
|
||||
while (le != &Vcb->trees) {
|
||||
LIST_ENTRY* nextle = le->Flink;
|
||||
tree* t = CONTAINING_RECORD(le, tree, list_entry);
|
||||
root* r = t->root;
|
||||
|
||||
if (t->header.level == level) {
|
||||
BOOL top = !t->paritem;
|
||||
|
||||
empty = FALSE;
|
||||
|
||||
free_tree2(t, funcname, __FILE__, __LINE__);
|
||||
if (top && r->treeholder.tree == t)
|
||||
r->treeholder.tree = NULL;
|
||||
|
||||
if (IsListEmpty(&Vcb->trees))
|
||||
goto free_shared;
|
||||
} else if (t->header.level > level)
|
||||
empty = FALSE;
|
||||
|
||||
le = nextle;
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
|
||||
if (empty)
|
||||
break;
|
||||
}
|
||||
|
||||
free_shared:
|
||||
while (!IsListEmpty(&Vcb->shared_extents)) {
|
||||
shared_data* sd;
|
||||
|
||||
le = RemoveHeadList(&Vcb->shared_extents);
|
||||
sd = CONTAINING_RECORD(le, shared_data, list_entry);
|
||||
|
||||
while (!IsListEmpty(&sd->entries)) {
|
||||
LIST_ENTRY* le2 = RemoveHeadList(&sd->entries);
|
||||
shared_data_entry* sde = CONTAINING_RECORD(le2, shared_data_entry, list_entry);
|
||||
|
||||
ExFreePool(sde);
|
||||
}
|
||||
|
||||
ExFreePool(sd);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_rollback(LIST_ENTRY* rollback, enum rollback_type type, void* ptr) {
|
||||
void add_rollback(LIST_ENTRY* rollback, enum rollback_type type, void* ptr) {
|
||||
rollback_item* ri;
|
||||
|
||||
ri = ExAllocatePoolWithTag(PagedPool, sizeof(rollback_item), ALLOC_TAG);
|
||||
|
@ -1031,6 +809,13 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
|
|||
|
||||
TRACE("(%p, %p, %llx, %x, %llx, %p, %x, %p, %p)\n", Vcb, r, obj_id, obj_type, offset, data, size, ptp, rollback);
|
||||
|
||||
#ifdef DEBUG_PARANOID
|
||||
if (!ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock)) {
|
||||
ERR("ERROR - tree_lock not held exclusively\n");
|
||||
int3;
|
||||
}
|
||||
#endif
|
||||
|
||||
searchkey.obj_id = obj_id;
|
||||
searchkey.obj_type = obj_type;
|
||||
searchkey.offset = offset;
|
||||
|
@ -1123,7 +908,7 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
|
|||
|
||||
if (!tp.tree->write) {
|
||||
tp.tree->write = TRUE;
|
||||
Vcb->write_trees++;
|
||||
Vcb->need_write = TRUE;
|
||||
}
|
||||
|
||||
if (ptp)
|
||||
|
@ -1185,6 +970,11 @@ void STDCALL delete_tree_item(device_extension* Vcb, traverse_ptr* tp, LIST_ENTR
|
|||
TRACE("deleting item %llx,%x,%llx (ignore = %s)\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, tp->item->ignore ? "TRUE" : "FALSE");
|
||||
|
||||
#ifdef DEBUG_PARANOID
|
||||
if (!ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock)) {
|
||||
ERR("ERROR - tree_lock not held exclusively\n");
|
||||
int3;
|
||||
}
|
||||
|
||||
if (tp->item->ignore) {
|
||||
ERR("trying to delete already-deleted item %llx,%x,%llx\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
|
||||
int3;
|
||||
|
@ -1195,7 +985,7 @@ void STDCALL delete_tree_item(device_extension* Vcb, traverse_ptr* tp, LIST_ENTR
|
|||
|
||||
if (!tp->tree->write) {
|
||||
tp->tree->write = TRUE;
|
||||
Vcb->write_trees++;
|
||||
Vcb->need_write = TRUE;
|
||||
}
|
||||
|
||||
tp->tree->header.num_items--;
|
||||
|
@ -1237,6 +1027,9 @@ void clear_rollback(LIST_ENTRY* rollback) {
|
|||
case ROLLBACK_DELETE_ITEM:
|
||||
ExFreePool(ri->ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ExFreePool(ri);
|
||||
|
@ -1247,7 +1040,7 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
|
|||
rollback_item* ri;
|
||||
|
||||
while (!IsListEmpty(rollback)) {
|
||||
LIST_ENTRY* le = RemoveHeadList(rollback);
|
||||
LIST_ENTRY* le = RemoveTailList(rollback);
|
||||
ri = CONTAINING_RECORD(le, rollback_item, list_entry);
|
||||
|
||||
switch (ri->type) {
|
||||
|
@ -1286,6 +1079,22 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
|
|||
ExFreePool(tp);
|
||||
break;
|
||||
}
|
||||
|
||||
case ROLLBACK_INSERT_EXTENT:
|
||||
{
|
||||
extent* ext = ri->ptr;
|
||||
|
||||
ext->ignore = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
case ROLLBACK_DELETE_EXTENT:
|
||||
{
|
||||
extent* ext = ri->ptr;
|
||||
|
||||
ext->ignore = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(ri);
|
||||
|
|
108
reactos/drivers/filesystems/btrfs/worker-thread.c
Normal file
108
reactos/drivers/filesystems/btrfs/worker-thread.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "btrfs_drv.h"
|
||||
|
||||
void do_read_job(PIRP Irp) {
|
||||
NTSTATUS Status;
|
||||
ULONG bytes_read;
|
||||
BOOL top_level = is_top_level(Irp);
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
Status = do_read(Irp, TRUE, &bytes_read);
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
// // fastfat doesn't do this, but the Wine ntdll file test seems to think we ought to
|
||||
// if (Irp->UserIosb)
|
||||
// *Irp->UserIosb = Irp->IoStatus;
|
||||
|
||||
TRACE("Irp->IoStatus.Status = %08x\n", Irp->IoStatus.Status);
|
||||
TRACE("Irp->IoStatus.Information = %lu\n", Irp->IoStatus.Information);
|
||||
TRACE("returning %08x\n", Status);
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
}
|
||||
|
||||
void do_write_job(device_extension* Vcb, PIRP Irp) {
|
||||
BOOL top_level = is_top_level(Irp);
|
||||
NTSTATUS Status;
|
||||
|
||||
_SEH2_TRY {
|
||||
Status = write_file(Vcb, Irp, TRUE, TRUE);
|
||||
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
||||
Status = _SEH2_GetExceptionCode();
|
||||
} _SEH2_END;
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
TRACE("wrote %u bytes\n", Irp->IoStatus.Information);
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
TRACE("returning %08x\n", Status);
|
||||
}
|
||||
|
||||
static void do_job(drv_thread* thread, LIST_ENTRY* le) {
|
||||
thread_job* tj = CONTAINING_RECORD(le, thread_job, list_entry);
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(tj->Irp);
|
||||
|
||||
if (IrpSp->MajorFunction == IRP_MJ_READ) {
|
||||
do_read_job(tj->Irp);
|
||||
} else if (IrpSp->MajorFunction == IRP_MJ_WRITE) {
|
||||
do_write_job(thread->DeviceObject->DeviceExtension, tj->Irp);
|
||||
} else {
|
||||
ERR("unsupported major function %x\n", IrpSp->MajorFunction);
|
||||
tj->Irp->IoStatus.Status = STATUS_INTERNAL_ERROR;
|
||||
tj->Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(tj->Irp, IO_NO_INCREMENT);
|
||||
}
|
||||
|
||||
ExFreePool(tj);
|
||||
}
|
||||
|
||||
void STDCALL worker_thread(void* context) {
|
||||
drv_thread* thread = context;
|
||||
KIRQL irql;
|
||||
|
||||
ObReferenceObject(thread->DeviceObject);
|
||||
|
||||
while (TRUE) {
|
||||
KeWaitForSingleObject(&thread->event, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
while (TRUE) {
|
||||
LIST_ENTRY* le;
|
||||
|
||||
KeAcquireSpinLock(&thread->spin_lock, &irql);
|
||||
|
||||
if (IsListEmpty(&thread->jobs)) {
|
||||
KeReleaseSpinLock(&thread->spin_lock, irql);
|
||||
break;
|
||||
}
|
||||
|
||||
le = thread->jobs.Flink;
|
||||
RemoveEntryList(le);
|
||||
|
||||
KeReleaseSpinLock(&thread->spin_lock, irql);
|
||||
|
||||
do_job(thread, le);
|
||||
}
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
if (thread->quit)
|
||||
break;
|
||||
}
|
||||
|
||||
ObDereferenceObject(thread->DeviceObject);
|
||||
|
||||
KeSetEvent(&thread->finished, 0, FALSE);
|
||||
|
||||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
}
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue