#define READ_AHEAD_GRANULARITY 0x10000 // 64 KB
+#define MAX_EXTENT_SIZE 0x8000000 // 128 MB
+
#ifdef _MSC_VER
#define try __try
#define except __except
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;
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;
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;
BOOL specific_file;
ACCESS_MASK access;
file_ref* fileref;
+ UNICODE_STRING filename;
} ccb;
// typedef struct _log_to_phys {
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 address;
UINT64 size;
- UINT8 type;
LIST_ENTRY list_entry;
+ LIST_ENTRY list_entry_size;
} space;
-typedef struct {
- UINT64 address;
- UINT64 size;
- BOOL provisional;
- LIST_ENTRY listentry;
-} disk_hole;
-
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;
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;
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;
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;
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;
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);
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__
// 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);
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();
// 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);
// 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);
// 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);
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)
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()
#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. */
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