[BTRFS]
[reactos.git] / reactos / drivers / filesystems / btrfs / btrfs_drv.h
index 8eec01b..1b01d92 100644 (file)
@@ -36,6 +36,7 @@
 #ifdef __REACTOS__
 #include <rtlfuncs.h>
 #include <iotypes.h>
+#include <pseh/pseh2.h>
 #endif /* __REACTOS__ */
 //#include <windows.h>
 #include <windef.h>
@@ -46,7 +47,6 @@
 #include "btrfs.h"
 
 #ifdef _DEBUG
-// #define DEBUG_TREE_REFCOUNTS
 // #define DEBUG_FCB_REFCOUNTS
 // #define DEBUG_LONG_MESSAGES
 #define DEBUG_PARANOID
@@ -56,6 +56,7 @@
 #define BTRFS_NODE_TYPE_FCB 0x2296
 
 #define ALLOC_TAG 0x7442484D //'MHBt'
+#define ALLOC_TAG_ZLIB 0x7A42484D //'MHBz'
 
 #define STDCALL __stdcall
 
 #define EA_DOSATTRIB "user.DOSATTRIB"
 #define EA_DOSATTRIB_HASH 0x914f9939
 
-#define READ_AHEAD_GRANULARITY 0x10000 // 64 KB
+#define EA_REPARSE "system.reparse"
+#define EA_REPARSE_HASH 0x786f6167
+
+#define MAX_EXTENT_SIZE 0x8000000 // 128 MB
+#define COMPRESSED_EXTENT_SIZE 0x20000 // 128 KB
+
+#define READ_AHEAD_GRANULARITY COMPRESSED_EXTENT_SIZE // really ought to be a multiple of COMPRESSED_EXTENT_SIZE
 
 #ifdef _MSC_VER
 #define try __try
 
 // #pragma pack(push, 1)
 
-struct device_extension;
+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;
@@ -99,44 +107,120 @@ 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;
     LONG refcount;
     LONG open_count;
-    UNICODE_STRING filepart;
-    ANSI_STRING utf8;
     struct _device_extension* Vcb;
-    struct _fcb* par;
-    struct _fcb* prev;
-    struct _fcb* next;
     struct _root* subvol;
-    LIST_ENTRY children;
     UINT64 inode;
     UINT8 type;
-    BOOL delete_on_close;
     INODE_ITEM inode_item;
-    UNICODE_STRING full_filename;
-    ULONG name_offset;
     SECURITY_DESCRIPTOR* sd;
     FILE_LOCK lock;
     BOOL deleted;
     PKTHREAD lazy_writer_thread;
     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;
+    ULONG adsmaxlen;
     ANSI_STRING adsxattr;
+    ANSI_STRING adsdata;
     
     LIST_ENTRY list_entry;
+    LIST_ENTRY list_entry_all;
 } fcb;
 
+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;
+    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;
@@ -147,6 +231,9 @@ typedef struct _ccb {
     UNICODE_STRING query_string;
     BOOL has_wildcard;
     BOOL specific_file;
+    ACCESS_MASK access;
+    file_ref* fileref;
+    UNICODE_STRING filename;
 } ccb;
 
 // typedef struct _log_to_phys {
@@ -203,7 +290,7 @@ typedef struct _tree {
 //     UINT64 address;
 //     UINT8 level;
     tree_header header;
-    LONG refcount;
+    BOOL has_address;
     UINT32 size;
     struct _device_extension* Vcb;
     struct _tree* parent;
@@ -213,7 +300,9 @@ typedef struct _tree {
     LIST_ENTRY itemlist;
     LIST_ENTRY list_entry;
     UINT64 new_address;
+    BOOL has_new_address;
     UINT64 flags;
+    BOOL write;
 } tree;
 
 typedef struct {
@@ -227,9 +316,9 @@ typedef struct _root {
     root_nonpaged* nonpaged;
     UINT64 lastinode;
     ROOT_ITEM root_item;
-    
-    struct _root* prev;
-    struct _root* next;
+    UNICODE_STRING path;
+    LIST_ENTRY fcbs;
+    LIST_ENTRY list_entry;
 } root;
 
 typedef struct {
@@ -237,40 +326,25 @@ typedef struct {
     tree_data* item;
 } traverse_ptr;
 
-typedef struct _tree_cache {
-    tree* tree;
-    BOOL write;
-    LIST_ENTRY list_entry;
-} tree_cache;
-
 typedef struct _root_cache {
     root* root;
     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;
-    LIST_ENTRY disk_holes;
+    BOOL removable;
+    ULONG change_count;
+    UINT64 length;
+    LIST_ENTRY space;
 } device;
 
 typedef struct {
@@ -279,12 +353,51 @@ typedef struct {
     UINT64 offset;
     UINT64 used;
     UINT32 oldused;
-    BOOL space_changed;
     device** devices;
+    fcb* cache;
     LIST_ENTRY space;
+    LIST_ENTRY space_size;
+    LIST_ENTRY deleting;
+    LIST_ENTRY changed_extents;
+    ERESOURCE lock;
+    ERESOURCE changed_extents_lock;
+    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;
@@ -292,16 +405,57 @@ 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;
+    LONG pending_jobs;
+} drv_threads;
+
+typedef struct {
+    BOOL ignore;
+    BOOL compress;
+    BOOL compress_force;
+    UINT8 compress_type;
+    BOOL readonly;
+    UINT32 zlib_level;
+    UINT32 flush_interval;
+    UINT32 max_inline;
+    UINT64 subvol_id;
+} 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;
-    fcb* fcbs;
+    BOOL removing;
+    BOOL locked;
+    PFILE_OBJECT locked_fileobj;
     fcb* volume_fcb;
-    fcb* root_fcb;
+    file_ref* root_fileref;
     ERESOURCE DirResource;
     KSPIN_LOCK FcbListLock;
     ERESOURCE fcb_lock;
@@ -309,43 +463,99 @@ 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;
-    root* roots;
+    LIST_ENTRY roots;
+    LIST_ENTRY drop_roots;
     root* chunk_root;
     root* root_root;
     root* extent_root;
     root* checksum_root;
     root* dev_root;
+    root* uuid_root;
     BOOL log_to_phys_loaded;
-    UINT32 max_inline;
     LIST_ENTRY sys_chunks;
     LIST_ENTRY chunks;
+    LIST_ENTRY chunks_changed;
     LIST_ENTRY trees;
-    LIST_ENTRY tree_cache;
+    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;
     UINT32 uid;
 } uid_map;
 
-// #pragma pack(pop)
+typedef struct {
+    LIST_ENTRY list_entry;
+    UINT64 key;
+} ordered_list;
 
-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
-}
+typedef struct {
+    ordered_list ol;
+    ULONG length;
+    UINT32* checksums;
+    BOOL deleted;
+} changed_sector;
+
+enum write_data_status {
+    WriteDataStatus_Pending,
+    WriteDataStatus_Success,
+    WriteDataStatus_Error,
+    WriteDataStatus_Cancelling,
+    WriteDataStatus_Cancelled,
+    WriteDataStatus_Ignore
+};
+
+struct _write_data_context;
+
+typedef struct {
+    struct _write_data_context* context;
+    UINT8* buf;
+    BOOL need_free;
+    device* device;
+    PIRP Irp;
+    IO_STATUS_BLOCK iosb;
+    enum write_data_status status;
+    LIST_ENTRY list_entry;
+} write_data_stripe;
+
+typedef struct _write_data_context {
+    KEVENT Event;
+    LIST_ENTRY stripes;
+    LONG stripes_left;
+    BOOL tree;
+} write_data_context;
+
+// #pragma pack(pop)
 
 static __inline void* map_user_buffer(PIRP Irp) {
     if (!Irp->MdlAddress) {
@@ -366,24 +576,67 @@ static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) {
     out->nanoseconds = (l % 10000000) * 100;
 }
 
+static __inline void insert_into_ordered_list(LIST_ENTRY* list, ordered_list* ins) {
+    LIST_ENTRY* le = list->Flink;
+    ordered_list* ol;
+    
+    while (le != list) {
+        ol = (ordered_list*)le;
+        
+        if (ol->key > ins->key) {
+            le->Blink->Flink = &ins->list_entry;
+            ins->list_entry.Blink = le->Blink;
+            le->Blink = &ins->list_entry;
+            ins->list_entry.Flink = le;
+            return;
+        }
+        
+        le = le->Flink;
+    }
+    
+    InsertTailList(list, &ins->list_entry);
+}
+
+static __inline void get_raid0_offset(UINT64 off, UINT64 stripe_length, UINT16 num_stripes, UINT64* stripeoff, UINT16* stripe) {
+    UINT64 initoff, startoff;
+    
+    startoff = off % (num_stripes * stripe_length);
+    initoff = (off / (num_stripes * stripe_length)) * stripe_length;
+    
+    *stripe = (UINT16)(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);
+ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa, PIRP Irp);
+BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen, PIRP Irp);
 void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line);
-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_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback);
-fcb* create_fcb();
+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, PIRP Irp);
+NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback);
+fcb* create_fcb(POOL_TYPE pool_type);
+file_ref* create_fileref();
 void protect_superblocks(device_extension* Vcb, chunk* c);
 BOOL is_top_level(PIRP Irp);
+NTSTATUS create_root(device_extension* Vcb, UINT64 id, root** rootptr, BOOL no_tree, UINT64 offset, PIRP Irp, LIST_ENTRY* rollback);
+void STDCALL uninit(device_extension* Vcb, BOOL flush);
+NTSTATUS STDCALL dev_ioctl(PDEVICE_OBJECT DeviceObject, ULONG ControlCode, PVOID InputBuffer,
+                           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, PIRP Irp, LIST_ENTRY* rollback);
 
 #ifdef _MSC_VER
 #define funcname __FUNCTION__
@@ -393,26 +646,41 @@ BOOL is_top_level(PIRP Irp);
 
 // FIXME - we probably shouldn't be moving funcname etc. around if we're not printing debug messages
 #define free_fcb(fcb) _free_fcb(fcb, funcname, __FILE__, __LINE__)
+#define free_fileref(fileref) _free_fileref(fileref, funcname, __FILE__, __LINE__)
+
+extern UINT32 mount_compress;
+extern UINT32 mount_compress_force;
+extern UINT32 mount_compress_type;
+extern UINT32 mount_zlib_level;
+extern UINT32 mount_flush_interval;
+extern UINT32 mount_max_inline;
 
 #ifdef _DEBUG
 
+extern BOOL log_started;
+extern UINT32 debug_log_level;
+
 #ifdef DEBUG_LONG_MESSAGES
 
-#define TRACE(s, ...) _debug_message(funcname, 3, __FILE__, __LINE__, s, ##__VA_ARGS__)
-#define WARN(s, ...) _debug_message(funcname, 2, __FILE__, __LINE__, s, ##__VA_ARGS__)
-#define FIXME(s, ...) _debug_message(funcname, 1, __FILE__, __LINE__, s, ##__VA_ARGS__)
-#define ERR(s, ...) _debug_message(funcname, 1, __FILE__, __LINE__, s, ##__VA_ARGS__)
+#define MSG(fn, file, line, s, level, ...) (!log_started || level <= debug_log_level) ? _debug_message(fn, file, line, s, ##__VA_ARGS__) : 0
 
-void STDCALL _debug_message(const char* func, UINT8 priority, const char* file, unsigned int line, char* s, ...);
+#define TRACE(s, ...) MSG(funcname, __FILE__, __LINE__, s, 3, ##__VA_ARGS__)
+#define WARN(s, ...) MSG(funcname, __FILE__, __LINE__, s, 2, ##__VA_ARGS__)
+#define FIXME(s, ...) MSG(funcname, __FILE__, __LINE__, s, 1, ##__VA_ARGS__)
+#define ERR(s, ...) MSG(funcname, __FILE__, __LINE__, s, 1, ##__VA_ARGS__)
+
+void STDCALL _debug_message(const char* func, const char* file, unsigned int line, char* s, ...);
 
 #else
 
-#define TRACE(s, ...) _debug_message(funcname, 3, s, ##__VA_ARGS__)
-#define WARN(s, ...) _debug_message(funcname, 2, s, ##__VA_ARGS__)
-#define FIXME(s, ...) _debug_message(funcname, 1, s, ##__VA_ARGS__)
-#define ERR(s, ...) _debug_message(funcname, 1, s, ##__VA_ARGS__)
+#define MSG(fn, s, level, ...) (!log_started || level <= debug_log_level) ? _debug_message(fn, s, ##__VA_ARGS__) : 0
+
+#define TRACE(s, ...) MSG(funcname, s, 3, ##__VA_ARGS__)
+#define WARN(s, ...) MSG(funcname, s, 2, ##__VA_ARGS__)
+#define FIXME(s, ...) MSG(funcname, s, 1, ##__VA_ARGS__)
+#define ERR(s, ...) MSG(funcname, s, 1, ##__VA_ARGS__)
 
-void STDCALL _debug_message(const char* func, UINT8 priority, char* s, ...);
+void STDCALL _debug_message(const char* func, char* s, ...);
 
 #endif
 
@@ -430,37 +698,65 @@ void STDCALL _debug_message(const char* func, UINT8 priority, char* s, ...);
 
 #endif
 
+static __inline void increase_chunk_usage(chunk* c, UINT64 delta) {
+    c->used += delta;
+    
+    TRACE("increasing size of chunk %llx by %llx\n", c->offset, delta);
+}
+
 // in fastio.c
 void STDCALL init_fast_io_dispatch(FAST_IO_DISPATCH** fiod);
 
 // in crc32c.c
 UINT32 STDCALL calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen);
 
+typedef struct {
+    LIST_ENTRY* list;
+    LIST_ENTRY* list_size;
+    UINT64 address;
+    UINT64 length;
+    chunk* chunk;
+} rollback_space;
+
+typedef struct {
+    fcb* fcb;
+    extent* ext;
+} rollback_extent;
+
+enum rollback_type {
+    ROLLBACK_INSERT_ITEM,
+    ROLLBACK_DELETE_ITEM,
+    ROLLBACK_INSERT_EXTENT,
+    ROLLBACK_DELETE_EXTENT,
+    ROLLBACK_ADD_SPACE,
+    ROLLBACK_SUBTRACT_SPACE
+};
+
 // 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 _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, const char* func, const char* file, unsigned int line);
-void STDCALL _free_traverse_ptr(traverse_ptr* tp, const char* func, const char* file, unsigned int line);
-void STDCALL free_tree_cache(LIST_ENTRY* tc);
-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);
+NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
+BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
+BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
+void STDCALL free_trees(device_extension* Vcb);
+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, PIRP Irp, LIST_ENTRY* rollback);
 void STDCALL delete_tree_item(device_extension* Vcb, traverse_ptr* tp, LIST_ENTRY* rollback);
-void STDCALL add_to_tree_cache(device_extension* Vcb, tree* t, BOOL write);
 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 _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);
+NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, tree* parent, PIRP Irp, 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, PIRP Irp,
+                               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);
+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 find_item(Vcb, r, tp, searchkey, ignore, Irp) _find_item(Vcb, r, tp, searchkey, ignore, Irp, funcname, __FILE__, __LINE__)
+#define find_next_item(Vcb, tp, next_tp, ignore, Irp) _find_next_item(Vcb, tp, next_tp, ignore, Irp, funcname, __FILE__, __LINE__)
+#define find_prev_item(Vcb, tp, prev_tp, ignore, Irp) _find_prev_item(Vcb, tp, prev_tp, ignore, Irp, funcname, __FILE__, __LINE__)
 #define free_tree(t) _free_tree(t, funcname, __FILE__, __LINE__)
-#define load_tree(t, addr, r, pt) _load_tree(t, addr, r, pt, funcname, __FILE__, __LINE__)
-#define free_traverse_ptr(tp) _free_traverse_ptr(tp, 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__)  
+#define load_tree(t, addr, r, pt, parent, Irp) _load_tree(t, addr, r, pt, parent, Irp, funcname, __FILE__, __LINE__)
+#define do_load_tree(Vcb, th, r, t, td, loaded, Irp) _do_load_tree(Vcb, th, r, t, td, loaded, Irp, funcname, __FILE__, __LINE__)  
 
 // in search.c
-void STDCALL look_for_vols(LIST_ENTRY* volumes);
+void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes);
 
 // in cache.c
 NTSTATUS STDCALL init_cache();
@@ -468,65 +764,134 @@ void STDCALL free_cache();
 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 truncate_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback);
-NTSTATUS extend_file(fcb* fcb, UINT64 end, 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 STDCALL add_extent_ref(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode, UINT64 offset, LIST_ENTRY* rollback);
-NTSTATUS STDCALL remove_extent_ref(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode, UINT64 offset, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
-void print_trees(LIST_ENTRY* tc);
+NTSTATUS STDCALL do_write(device_extension* Vcb, PIRP Irp, 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, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS extend_file(fcb* fcb, file_ref* fileref, UINT64 end, BOOL prealloc, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, PIRP Irp, LIST_ENTRY* rollback);
+void commit_checksum_changes(device_extension* Vcb, LIST_ENTRY* changed_sector_list);
 chunk* get_chunk_from_address(device_extension* Vcb, UINT64 address);
-void add_to_space_list(chunk* c, UINT64 offset, UINT64 size, UINT8 type);
-NTSTATUS consider_write(device_extension* Vcb);
+chunk* alloc_chunk(device_extension* Vcb, UINT64 flags);
+NTSTATUS STDCALL write_data(device_extension* Vcb, UINT64 address, void* data, BOOL need_free, UINT32 length, write_data_context* wtc, PIRP Irp, chunk* c);
+NTSTATUS STDCALL write_data_complete(device_extension* Vcb, UINT64 address, void* data, UINT32 length, PIRP Irp, chunk* c);
+void free_write_data_stripes(write_data_context* wtc);
+NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS STDCALL drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
+void flush_fcb(fcb* fcb, BOOL cache, PIRP Irp, 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, UINT8 compression, UINT64 decoded_size);
+NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 length, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS 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, PIRP Irp);
+NTSTATUS do_write_file(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS write_compressed(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
 
 // 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, ULONG atts, PIRP Irp);
 
 // in security.c
 NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
 NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
-void fcb_get_sd(fcb* fcb);
+void fcb_get_sd(fcb* fcb, struct _fcb* parent, PIRP Irp);
 // UINT32 STDCALL get_uid();
 void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid);
-NTSTATUS fcb_get_new_sd(fcb* fcb, ACCESS_STATE* as);
+UINT32 sid_to_uid(PSID sid);
+void uid_to_sid(UINT32 uid, PSID* sid);
+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 add_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, UINT64 index, PANSI_STRING utf8, PIRP Irp, 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, PIRP Irp);
 
 // in reparse.c
-BOOL follow_symlink(fcb* fcb, PFILE_OBJECT FileObject);
 NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, DWORD* retlen);
 NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
 
 // in create.c
 NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
-NTSTATUS get_fcb(device_extension* Vcb, fcb** pfcb, PUNICODE_STRING fnus, fcb* relatedfcb, BOOL parent);
-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 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, PIRP Irp);
+NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* unparsed, ULONG* fn_offset, PIRP Irp);
+NTSTATUS open_fcb(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, PIRP Irp);
+NTSTATUS open_fcb_stream(device_extension* Vcb, root* subvol, UINT64 inode, ANSI_STRING* xattr, UINT32 streamhash, fcb* parent, fcb** pfcb, PIRP Irp);
+void insert_fileref_child(file_ref* parent, file_ref* child, BOOL do_lock);
+NTSTATUS fcb_get_last_dir_index(fcb* fcb, UINT64* index, PIRP Irp);
+NTSTATUS verify_vcb(device_extension* Vcb, PIRP Irp);
 
 // 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);
+
+// in free-space.c
+NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c, PIRP Irp);
+NTSTATUS clear_free_space_cache(device_extension* Vcb, PIRP Irp);
+NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS 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, chunk* c, 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, chunk* c, 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, NULL, 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, NULL, rollback, funcname)
+
+// in extent-tree.c
+NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS decrease_extent_refcount_shared_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, UINT64 parent, PIRP Irp, LIST_ENTRY* rollback);
+NTSTATUS decrease_extent_refcount_old(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, PIRP Irp, LIST_ENTRY* rollback);
+void decrease_chunk_usage(chunk* c, UINT64 delta);
+NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, PIRP Irp, LIST_ENTRY* rollback);
+UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, PIRP Irp);
+
+// 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(device_extension* Vcb);
+
+// in compress.c
+NTSTATUS decompress(UINT8 type, UINT8* inbuf, UINT64 inlen, UINT8* outbuf, UINT64 outlen);
+NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
+
+#define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable)
 
 static __inline void print_open_trees(device_extension* Vcb) {
     LIST_ENTRY* le = Vcb->trees.Flink;
     while (le != &Vcb->trees) {
         tree* t = CONTAINING_RECORD(le, tree, list_entry);
         tree_data* td = CONTAINING_RECORD(t->itemlist.Flink, tree_data, list_entry);
-        ERR("tree %p: root %llx, level %u, refcount %u, first key (%llx,%x,%llx)\n",
-                      t, t->root->id, t->header.level, t->refcount, td->key.obj_id, td->key.obj_type, td->key.offset);
+        ERR("tree %p: root %llx, level %u, first key (%llx,%x,%llx)\n",
+                      t, t->root->id, t->header.level, td->key.obj_id, td->key.obj_type, td->key.offset);
 
         le = le->Flink;
     }
@@ -543,6 +908,39 @@ static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY*
         head->Blink = item;
 }
 
+static __inline BOOL write_fcb_compressed(fcb* fcb) {
+    // make sure we don't accidentally write the cache inodes or pagefile compressed
+    if (fcb->subvol->id == BTRFS_ROOT_ROOT || fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE)
+        return FALSE;
+    
+    if (fcb->Vcb->options.compress_force)
+        return TRUE;
+    
+    if (fcb->inode_item.flags & BTRFS_INODE_NOCOMPRESS)
+        return FALSE;
+    
+    if (fcb->inode_item.flags & BTRFS_INODE_COMPRESS || fcb->Vcb->options.compress)
+        return TRUE;
+    
+    return FALSE;
+}
+
+#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()
@@ -550,52 +948,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); \
-}
-
-#ifdef DEBUG_TREE_REFCOUNTS
-#ifdef DEBUG_LONG_MESSAGES
-#define _increase_tree_rc(t, func, file, line) { \
-    LONG rc = InterlockedIncrement(&t->refcount); \
-    _debug_message(func, file, line, "tree %p: refcount increased to %i (increase_tree_rc)\n", t, rc); \
-}
-#else
-#define _increase_tree_rc(t, func, file, line) { \
-    LONG rc = InterlockedIncrement(&t->refcount); \
-    _debug_message(func, "tree %p: refcount increased to %i (increase_tree_rc)\n", t, rc); \
-}
-#endif
-#define increase_tree_rc(t) _increase_tree_rc(t, funcname, __FILE__, __LINE__)
-#else
-#define increase_tree_rc(t) InterlockedIncrement(&t->refcount);
-#define _increase_tree_rc(t, func, file, line) increase_tree_rc(t)
-#endif
-
 // from sys/stat.h
 #define __S_IFMT        0170000 /* These bits determine file type.  */
 #define __S_IFDIR       0040000 /* Directory.  */
@@ -611,6 +968,14 @@ static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY*
 #define S_ISDIR(mode)    __S_ISTYPE((mode), __S_IFDIR)
 #endif
 
+#ifndef S_IRUSR
+#define S_IRUSR 0000400
+#endif
+
+#ifndef S_IWUSR
+#define S_IWUSR 0000200
+#endif
+
 #ifndef S_IXUSR
 #define S_IXUSR 0000100
 #endif
@@ -620,10 +985,26 @@ static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY*
 #define S_IFREG __S_IFREG
 #endif /* __REACTOS__ */
 
+#ifndef S_IRGRP
+#define S_IRGRP (S_IRUSR >> 3)
+#endif
+
+#ifndef S_IWGRP
+#define S_IWGRP (S_IWUSR >> 3)
+#endif
+
 #ifndef S_IXGRP
 #define S_IXGRP (S_IXUSR >> 3)
 #endif
 
+#ifndef S_IROTH
+#define S_IROTH (S_IRGRP >> 3)
+#endif
+
+#ifndef S_IWOTH
+#define S_IWOTH (S_IWGRP >> 3)
+#endif
+
 #ifndef S_IXOTH
 #define S_IXOTH (S_IXGRP >> 3)
 #endif
@@ -639,6 +1020,9 @@ NTSTATUS WINAPI RtlUTF8ToUnicodeN(WCHAR *uni_dest, ULONG uni_bytes_max,
 #if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_VISTA)
 NTSTATUS NTAPI FsRtlRemoveDotsFromPath(PWSTR OriginalString,
                                        USHORT PathLength, USHORT *NewLength);
-#endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */
+NTSTATUS NTAPI FsRtlValidateReparsePointBuffer(ULONG BufferLength,
+                                               PREPARSE_DATA_BUFFER ReparseBuffer);
+ULONG NTAPI KeQueryActiveProcessorCount(PKAFFINITY ActiveProcessors);
+#endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_VISTA) */
 
 #endif