mirror of
https://github.com/reactos/reactos.git
synced 2025-05-16 15:50:24 +00:00
[BTRFS]
Upgrade the WinBtrfs to release 0.4. CORE-11172 #resolve #Committed in r71265 svn path=/trunk/; revision=71265
This commit is contained in:
parent
3c7f167e24
commit
ae7080e660
20 changed files with 9448 additions and 3985 deletions
|
@ -8,10 +8,13 @@ list(APPEND SOURCE
|
|||
crc32c.c
|
||||
create.c
|
||||
dirctrl.c
|
||||
extent-tree.c
|
||||
fastio.c
|
||||
fileinfo.c
|
||||
flushthread.c
|
||||
free-space.c
|
||||
fsctl.c
|
||||
pnp.c
|
||||
read.c
|
||||
reparse.c
|
||||
search.c
|
||||
|
@ -30,7 +33,7 @@ endif()
|
|||
|
||||
add_definitions(-D__KERNEL__)
|
||||
set_module_type(btrfs kernelmodedriver)
|
||||
target_link_libraries(btrfs ntoskrnl_vista)
|
||||
target_link_libraries(btrfs ntoskrnl_vista ${PSEH_LIB})
|
||||
add_importlibs(btrfs ntoskrnl hal)
|
||||
add_pch(btrfs btrfs_drv.h SOURCE)
|
||||
add_cd_file(TARGET btrfs DESTINATION reactos/system32/drivers NO_CAB FOR all)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,6 +37,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4
|
|||
#define TYPE_DEV_EXTENT 0xCC
|
||||
#define TYPE_DEV_ITEM 0xD8
|
||||
#define TYPE_CHUNK_ITEM 0xE4
|
||||
#define TYPE_SUBVOL_UUID 0xFB
|
||||
|
||||
#define BTRFS_ROOT_ROOT 1
|
||||
#define BTRFS_ROOT_EXTENT 2
|
||||
|
@ -44,6 +45,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4
|
|||
#define BTRFS_ROOT_DEVTREE 4
|
||||
#define BTRFS_ROOT_FSTREE 5
|
||||
#define BTRFS_ROOT_CHECKSUM 7
|
||||
#define BTRFS_ROOT_UUID 9
|
||||
|
||||
#define BTRFS_COMPRESSION_NONE 0
|
||||
#define BTRFS_COMPRESSION_ZLIB 1
|
||||
|
@ -155,6 +157,33 @@ typedef struct {
|
|||
} DEV_ITEM;
|
||||
|
||||
#define SYS_CHUNK_ARRAY_SIZE 0x800
|
||||
#define BTRFS_NUM_BACKUP_ROOTS 4
|
||||
|
||||
typedef struct {
|
||||
UINT64 root_tree_addr;
|
||||
UINT64 root_tree_generation;
|
||||
UINT64 chunk_tree_addr;
|
||||
UINT64 chunk_tree_generation;
|
||||
UINT64 extent_tree_addr;
|
||||
UINT64 extent_tree_generation;
|
||||
UINT64 fs_tree_addr;
|
||||
UINT64 fs_tree_generation;
|
||||
UINT64 dev_root_addr;
|
||||
UINT64 dev_root_generation;
|
||||
UINT64 csum_root_addr;
|
||||
UINT64 csum_root_generation;
|
||||
UINT64 total_bytes;
|
||||
UINT64 bytes_used;
|
||||
UINT64 num_devices;
|
||||
UINT64 reserved[4];
|
||||
UINT8 root_level;
|
||||
UINT8 chunk_root_level;
|
||||
UINT8 extent_root_level;
|
||||
UINT8 fs_root_level;
|
||||
UINT8 dev_root_level;
|
||||
UINT8 csum_root_level;
|
||||
UINT8 reserved2[10];
|
||||
} superblock_backup;
|
||||
|
||||
typedef struct {
|
||||
UINT8 checksum[32];
|
||||
|
@ -190,8 +219,8 @@ typedef struct {
|
|||
UINT64 uuid_tree_generation;
|
||||
UINT64 reserved[30];
|
||||
UINT8 sys_chunk_array[SYS_CHUNK_ARRAY_SIZE];
|
||||
// struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS];
|
||||
UINT8 reserved2[1237];
|
||||
superblock_backup backup[BTRFS_NUM_BACKUP_ROOTS];
|
||||
UINT8 reserved2[565];
|
||||
} superblock;
|
||||
|
||||
#define BTRFS_TYPE_UNKNOWN 0
|
||||
|
@ -324,6 +353,11 @@ typedef struct {
|
|||
UINT64 flags;
|
||||
} EXTENT_ITEM;
|
||||
|
||||
typedef struct {
|
||||
KEY firstitem;
|
||||
UINT8 level;
|
||||
} EXTENT_ITEM2;
|
||||
|
||||
typedef struct {
|
||||
UINT32 refcount;
|
||||
} EXTENT_ITEM_V0;
|
||||
|
@ -355,7 +389,7 @@ typedef struct {
|
|||
UINT64 root;
|
||||
UINT64 gen;
|
||||
UINT64 objid;
|
||||
UINT64 count;
|
||||
UINT32 count;
|
||||
} EXTENT_REF_V0;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -70,12 +70,12 @@ BEGIN
|
|||
BLOCK "080904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "WinBtrfs"
|
||||
VALUE "FileVersion", "0.2"
|
||||
VALUE "FileVersion", "0.4"
|
||||
VALUE "InternalName", "btrfs"
|
||||
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016"
|
||||
VALUE "OriginalFilename", "btrfs.sys"
|
||||
VALUE "ProductName", "WinBtrfs"
|
||||
VALUE "ProductVersion", "0.2"
|
||||
VALUE "ProductVersion", "0.4"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
|
@ -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
|
||||
|
@ -68,6 +68,9 @@
|
|||
#define EA_DOSATTRIB "user.DOSATTRIB"
|
||||
#define EA_DOSATTRIB_HASH 0x914f9939
|
||||
|
||||
#define EA_REPARSE "system.reparse"
|
||||
#define EA_REPARSE_HASH 0x786f6167
|
||||
|
||||
#define READ_AHEAD_GRANULARITY 0x10000 // 64 KB
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -108,26 +111,18 @@ typedef struct _fcb {
|
|||
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;
|
||||
|
||||
BOOL ads;
|
||||
UINT32 adssize;
|
||||
|
@ -137,6 +132,24 @@ typedef struct _fcb {
|
|||
LIST_ENTRY list_entry;
|
||||
} fcb;
|
||||
|
||||
struct _file_ref;
|
||||
|
||||
typedef struct _file_ref {
|
||||
fcb* fcb;
|
||||
UNICODE_STRING filepart;
|
||||
ANSI_STRING utf8;
|
||||
UNICODE_STRING full_filename;
|
||||
ULONG name_offset;
|
||||
BOOL delete_on_close;
|
||||
BOOL deleted;
|
||||
LIST_ENTRY children;
|
||||
LONG refcount;
|
||||
struct _file_ref* parent;
|
||||
WCHAR* debug_desc;
|
||||
|
||||
LIST_ENTRY list_entry;
|
||||
} file_ref;
|
||||
|
||||
typedef struct _ccb {
|
||||
USHORT NodeType;
|
||||
CSHORT NodeSize;
|
||||
|
@ -147,6 +160,8 @@ typedef struct _ccb {
|
|||
UNICODE_STRING query_string;
|
||||
BOOL has_wildcard;
|
||||
BOOL specific_file;
|
||||
ACCESS_MASK access;
|
||||
file_ref* fileref;
|
||||
} ccb;
|
||||
|
||||
// typedef struct _log_to_phys {
|
||||
|
@ -203,7 +218,6 @@ typedef struct _tree {
|
|||
// UINT64 address;
|
||||
// UINT8 level;
|
||||
tree_header header;
|
||||
LONG refcount;
|
||||
BOOL has_address;
|
||||
UINT32 size;
|
||||
struct _device_extension* Vcb;
|
||||
|
@ -216,6 +230,7 @@ typedef struct _tree {
|
|||
UINT64 new_address;
|
||||
BOOL has_new_address;
|
||||
UINT64 flags;
|
||||
BOOL write;
|
||||
} tree;
|
||||
|
||||
typedef struct {
|
||||
|
@ -229,9 +244,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 {
|
||||
|
@ -239,12 +254,6 @@ 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;
|
||||
|
@ -272,6 +281,8 @@ typedef struct {
|
|||
typedef struct {
|
||||
PDEVICE_OBJECT devobj;
|
||||
DEV_ITEM devitem;
|
||||
BOOL removable;
|
||||
ULONG change_count;
|
||||
LIST_ENTRY disk_holes;
|
||||
} device;
|
||||
|
||||
|
@ -283,6 +294,8 @@ typedef struct {
|
|||
UINT32 oldused;
|
||||
BOOL space_changed;
|
||||
device** devices;
|
||||
UINT64 cache_size;
|
||||
UINT64 cache_inode;
|
||||
LIST_ENTRY space;
|
||||
LIST_ENTRY list_entry;
|
||||
} chunk;
|
||||
|
@ -301,9 +314,9 @@ typedef struct _device_extension {
|
|||
superblock superblock;
|
||||
// WCHAR label[MAX_LABEL_SIZE];
|
||||
BOOL readonly;
|
||||
fcb* fcbs;
|
||||
BOOL removing;
|
||||
fcb* volume_fcb;
|
||||
fcb* root_fcb;
|
||||
file_ref* root_fileref;
|
||||
ERESOURCE DirResource;
|
||||
KSPIN_LOCK FcbListLock;
|
||||
ERESOURCE fcb_lock;
|
||||
|
@ -318,20 +331,20 @@ typedef struct _device_extension {
|
|||
// UINT64 chunk_root_phys_addr;
|
||||
UINT64 root_tree_phys_addr;
|
||||
// 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 trees;
|
||||
LIST_ENTRY tree_cache;
|
||||
HANDLE flush_thread_handle;
|
||||
KTIMER flush_thread_timer;
|
||||
LIST_ENTRY list_entry;
|
||||
} device_extension;
|
||||
|
||||
|
@ -341,6 +354,43 @@ typedef struct {
|
|||
UINT32 uid;
|
||||
} uid_map;
|
||||
|
||||
typedef struct {
|
||||
LIST_ENTRY list_entry;
|
||||
UINT64 key;
|
||||
} ordered_list;
|
||||
|
||||
typedef struct {
|
||||
ordered_list ol;
|
||||
ULONG length;
|
||||
UINT32* checksums;
|
||||
BOOL deleted;
|
||||
} changed_sector;
|
||||
|
||||
enum write_tree_status {
|
||||
WriteTreeStatus_Pending,
|
||||
WriteTreeStatus_Success,
|
||||
WriteTreeStatus_Error,
|
||||
WriteTreeStatus_Cancelling,
|
||||
WriteTreeStatus_Cancelled
|
||||
};
|
||||
|
||||
struct write_tree_context;
|
||||
|
||||
typedef struct {
|
||||
struct write_tree_context* context;
|
||||
UINT8* buf;
|
||||
device* device;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
enum write_tree_status status;
|
||||
LIST_ENTRY list_entry;
|
||||
} write_tree_stripe;
|
||||
|
||||
typedef struct {
|
||||
KEVENT Event;
|
||||
LIST_ENTRY stripes;
|
||||
} write_tree_context;
|
||||
|
||||
// #pragma pack(pop)
|
||||
|
||||
static __inline void init_tree_holder(tree_holder* th) {
|
||||
|
@ -368,6 +418,27 @@ 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);
|
||||
}
|
||||
|
||||
// in btrfs.c
|
||||
device* find_device_from_uuid(device_extension* Vcb, BTRFS_UUID* uuid);
|
||||
ULONG sector_align( ULONG NumberToBeAligned, ULONG Alignment );
|
||||
|
@ -377,15 +448,25 @@ BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char*
|
|||
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_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback);
|
||||
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, LIST_ENTRY* rollback);
|
||||
fcb* create_fcb();
|
||||
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, 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);
|
||||
WCHAR* file_desc(PFILE_OBJECT FileObject);
|
||||
WCHAR* file_desc_fileref(file_ref* fileref);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define funcname __FUNCTION__
|
||||
|
@ -395,26 +476,34 @@ 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__)
|
||||
|
||||
#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
|
||||
|
||||
void STDCALL _debug_message(const char* func, UINT8 priority, char* s, ...);
|
||||
#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, char* s, ...);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -432,6 +521,12 @@ 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);
|
||||
|
||||
|
@ -442,23 +537,22 @@ UINT32 STDCALL calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen);
|
|||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
#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 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__)
|
||||
|
||||
// in search.c
|
||||
|
@ -474,43 +568,55 @@ 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 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 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);
|
||||
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 get_tree_new_address(device_extension* Vcb, tree* t, 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);
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* fileref, 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);
|
||||
|
||||
// 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 update_inode_item(device_extension* Vcb, root* subvol, UINT64 inode, INODE_ITEM* ii, LIST_ENTRY* rollback);
|
||||
NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* unparsed);
|
||||
|
||||
// in fsctl.c
|
||||
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user);
|
||||
|
@ -522,13 +628,31 @@ void STDCALL flush_thread(void* context);
|
|||
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);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -580,24 +704,6 @@ static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY*
|
|||
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. */
|
||||
|
@ -613,6 +719,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
|
||||
|
@ -622,10 +736,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
|
||||
|
@ -641,6 +771,8 @@ 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);
|
||||
NTSTATUS NTAPI FsRtlValidateReparsePointBuffer(ULONG BufferLength,
|
||||
PREPARSE_DATA_BUFFER ReparseBuffer);
|
||||
#endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define BTRFSIOCTL_H_DEFINED
|
||||
|
||||
#define FSCTL_BTRFS_GET_FILE_IDS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x829, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||
#define FSCTL_BTRFS_CREATE_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82a, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||
#define FSCTL_BTRFS_CREATE_SNAPSHOT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82b, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
|
||||
|
||||
typedef struct {
|
||||
UINT64 subvol;
|
||||
|
@ -9,4 +11,10 @@ typedef struct {
|
|||
BOOL top;
|
||||
} btrfs_get_file_ids;
|
||||
|
||||
typedef struct {
|
||||
HANDLE subvol;
|
||||
UINT32 namelen;
|
||||
WCHAR name[1];
|
||||
} btrfs_create_snapshot;
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,7 +31,59 @@ typedef struct {
|
|||
enum DirEntryType dir_entry_type;
|
||||
} dir_entry;
|
||||
|
||||
static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp, dir_entry* de, root* r) {
|
||||
ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type) {
|
||||
ULONG att, tag, br;
|
||||
NTSTATUS Status;
|
||||
|
||||
// FIXME - will this slow things down?
|
||||
|
||||
if (type == BTRFS_TYPE_SYMLINK)
|
||||
return IO_REPARSE_TAG_SYMLINK;
|
||||
|
||||
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))
|
||||
return 0;
|
||||
|
||||
if (type == BTRFS_TYPE_DIRECTORY) {
|
||||
UINT8* data;
|
||||
UINT16 datalen;
|
||||
|
||||
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);
|
||||
} 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);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_file returned %08x\n", Status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (br < sizeof(ULONG))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, LONG* len, PIRP Irp, dir_entry* de, root* r) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
UINT32 needed;
|
||||
UINT64 inode;
|
||||
|
@ -43,9 +95,21 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
if (de->key.obj_type == TYPE_ROOT_ITEM) { // subvol
|
||||
r = fcb->Vcb->roots;
|
||||
while (r && r->id != de->key.obj_id)
|
||||
r = r->next;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
r = NULL;
|
||||
|
||||
le = fcb->Vcb->roots.Flink;
|
||||
while (le != &fcb->Vcb->roots) {
|
||||
root* subvol = CONTAINING_RECORD(le, root, list_entry);
|
||||
|
||||
if (subvol->id == de->key.obj_id) {
|
||||
r = subvol;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
if (!r) {
|
||||
ERR("could not find root %llx\n", de->key.obj_id);
|
||||
|
@ -64,17 +128,23 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
LIST_ENTRY* le;
|
||||
BOOL found = FALSE;
|
||||
|
||||
le = fcb->children.Flink;
|
||||
while (le != &fcb->children) {
|
||||
struct _fcb* c = CONTAINING_RECORD(le, struct _fcb, list_entry);
|
||||
if (fileref) {
|
||||
ExAcquireResourceSharedLite(&fcb->Vcb->fcb_lock, TRUE);
|
||||
|
||||
if (c->subvol == r && c->inode == inode) {
|
||||
ii = c->inode_item;
|
||||
found = TRUE;
|
||||
break;
|
||||
le = fileref->children.Flink;
|
||||
while (le != &fileref->children) {
|
||||
file_ref* c = CONTAINING_RECORD(le, file_ref, list_entry);
|
||||
|
||||
if (c->fcb->subvol == r && c->fcb->inode == inode && !c->fcb->ads) {
|
||||
ii = c->fcb->inode_item;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
|
@ -93,7 +163,6 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
|
||||
if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
|
||||
ERR("could not find inode item for inode %llx in root %llx\n", inode, r->id);
|
||||
free_traverse_ptr(&tp);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
|
@ -101,8 +170,6 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
|
||||
if (tp.item->size > 0)
|
||||
RtlCopyMemory(&ii, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -115,9 +182,14 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
break;
|
||||
|
||||
case DirEntryType_Parent:
|
||||
ii = fcb->par->inode_item;
|
||||
r = fcb->par->subvol;
|
||||
inode = fcb->par->inode;
|
||||
if (fileref && fileref->parent) {
|
||||
ii = fileref->parent->fcb->inode_item;
|
||||
r = fileref->parent->fcb->subvol;
|
||||
inode = fileref->parent->fcb->inode;
|
||||
} else {
|
||||
ERR("no fileref\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -162,7 +234,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
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->FileNameLength = stringlen;
|
||||
fbdi->EaSize = de->type == BTRFS_TYPE_SYMLINK ? IO_REPARSE_TAG_SYMLINK : 0;
|
||||
fbdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type);
|
||||
fbdi->ShortNameLength = 0;
|
||||
// fibdi->ShortName[12];
|
||||
|
||||
|
@ -237,7 +309,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
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->FileNameLength = stringlen;
|
||||
ffdi->EaSize = de->type == BTRFS_TYPE_SYMLINK ? IO_REPARSE_TAG_SYMLINK : 0;
|
||||
ffdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type);
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(ffdi->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
||||
|
@ -277,7 +349,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
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->FileNameLength = stringlen;
|
||||
fibdi->EaSize = de->type == BTRFS_TYPE_SYMLINK ? IO_REPARSE_TAG_SYMLINK : 0;
|
||||
fibdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type);
|
||||
fibdi->ShortNameLength = 0;
|
||||
// fibdi->ShortName[12];
|
||||
fibdi->FileId.QuadPart = inode;
|
||||
|
@ -347,13 +419,13 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, void* buf, LONG* len, PIRP Irp,
|
|||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de, traverse_ptr* tp) {
|
||||
static NTSTATUS STDCALL next_dir_entry(fcb* fcb, file_ref* fileref, UINT64* offset, dir_entry* de, traverse_ptr* tp) {
|
||||
KEY searchkey;
|
||||
traverse_ptr next_tp;
|
||||
DIR_ITEM* di;
|
||||
NTSTATUS Status;
|
||||
|
||||
if (fcb->par) { // don't return . and .. if root directory
|
||||
if (fileref && fileref->parent) { // don't return . and .. if root directory
|
||||
if (*offset == 0) {
|
||||
de->key.obj_id = fcb->inode;
|
||||
de->key.obj_type = TYPE_INODE_ITEM;
|
||||
|
@ -367,7 +439,7 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
|
||||
return STATUS_SUCCESS;
|
||||
} else if (*offset == 1) {
|
||||
de->key.obj_id = fcb->par->inode;
|
||||
de->key.obj_id = fileref->parent->fcb->inode;
|
||||
de->key.obj_type = TYPE_INODE_ITEM;
|
||||
de->key.offset = 0;
|
||||
de->dir_entry_type = DirEntryType_Parent;
|
||||
|
@ -389,7 +461,6 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
Status = find_item(fcb->Vcb, fcb->subvol, tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
free_traverse_ptr(tp);
|
||||
tp->tree = NULL;
|
||||
return Status;
|
||||
}
|
||||
|
@ -398,7 +469,6 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
|
||||
if (keycmp(&tp->item->key, &searchkey) == -1) {
|
||||
if (find_next_item(fcb->Vcb, tp, &next_tp, FALSE)) {
|
||||
free_traverse_ptr(tp);
|
||||
*tp = next_tp;
|
||||
|
||||
TRACE("moving on to %llx,%x,%llx\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
|
||||
|
@ -406,7 +476,6 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
}
|
||||
|
||||
if (tp->item->key.obj_id != searchkey.obj_id || tp->item->key.obj_type != searchkey.obj_type || tp->item->key.offset < *offset) {
|
||||
free_traverse_ptr(tp);
|
||||
tp->tree = NULL;
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
@ -418,7 +487,6 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
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));
|
||||
|
||||
free_traverse_ptr(tp);
|
||||
tp->tree = NULL;
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
@ -433,7 +501,6 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
} 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) {
|
||||
free_traverse_ptr(tp);
|
||||
*tp = next_tp;
|
||||
|
||||
*offset = tp->item->key.offset + 1;
|
||||
|
@ -442,8 +509,6 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
|
||||
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));
|
||||
|
||||
free_traverse_ptr(&next_tp);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
|
@ -454,10 +519,8 @@ static NTSTATUS STDCALL next_dir_entry(fcb* fcb, UINT64* offset, dir_entry* de,
|
|||
de->dir_entry_type = DirEntryType_File;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else {
|
||||
free_traverse_ptr(&next_tp);
|
||||
} else
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
} else
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
@ -468,11 +531,12 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
NTSTATUS Status, status2;
|
||||
fcb* fcb;
|
||||
ccb* ccb;
|
||||
file_ref* fileref;
|
||||
void* buf;
|
||||
UINT8 *curitem, *lastitem;
|
||||
LONG length;
|
||||
ULONG count;
|
||||
BOOL has_wildcard = FALSE, specific_file = FALSE;
|
||||
BOOL has_wildcard = FALSE, specific_file = FALSE, initial;
|
||||
// UINT64 num_reads_orig;
|
||||
traverse_ptr tp;
|
||||
dir_entry de;
|
||||
|
@ -486,10 +550,11 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
fcb = IrpSp->FileObject->FsContext;
|
||||
ccb = IrpSp->FileObject->FsContext2;
|
||||
fileref = ccb ? ccb->fileref : NULL;
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
TRACE("%.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
|
||||
TRACE("%S\n", file_desc(IrpSp->FileObject));
|
||||
|
||||
if (IrpSp->Flags == 0) {
|
||||
TRACE("QD flags: (none)\n");
|
||||
|
@ -517,6 +582,8 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
TRACE(" unknown flags: %u\n", flags);
|
||||
}
|
||||
|
||||
initial = !ccb->query_string.Buffer;
|
||||
|
||||
if (IrpSp->Flags & SL_RESTART_SCAN) {
|
||||
ccb->query_dir_offset = 0;
|
||||
|
||||
|
@ -567,6 +634,9 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
} else {
|
||||
has_wildcard = ccb->has_wildcard;
|
||||
specific_file = ccb->specific_file;
|
||||
|
||||
if (!(IrpSp->Flags & SL_RESTART_SCAN))
|
||||
initial = FALSE;
|
||||
}
|
||||
|
||||
if (ccb->query_string.Buffer) {
|
||||
|
@ -574,10 +644,10 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
}
|
||||
|
||||
tp.tree = NULL;
|
||||
Status = next_dir_entry(fcb, &ccb->query_dir_offset, &de, &tp);
|
||||
Status = next_dir_entry(fcb, fileref, &ccb->query_dir_offset, &de, &tp);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
if (Status == STATUS_NO_MORE_FILES && IrpSp->Flags & SL_RETURN_SINGLE_ENTRY)
|
||||
if (Status == STATUS_NO_MORE_FILES && initial)
|
||||
Status = STATUS_NO_SUCH_FILE;
|
||||
goto end;
|
||||
}
|
||||
|
@ -604,7 +674,6 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
if (Irp->MdlAddress && !buf) {
|
||||
ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -619,14 +688,12 @@ 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 (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
uni_fn = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
|
||||
if (!uni_fn) {
|
||||
ERR("out of memory\n");
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
@ -635,7 +702,6 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -643,21 +709,19 @@ 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, &ccb->query_dir_offset, &de, &tp);
|
||||
Status = next_dir_entry(fcb, fileref, &ccb->query_dir_offset, &de, &tp);
|
||||
|
||||
ExFreePool(uni_fn);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de.name, de.namelen);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
uni_fn = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
|
||||
if (!uni_fn) {
|
||||
ERR("out of memory\n");
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
@ -667,16 +731,13 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
ExFreePool(uni_fn);
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
di_uni_fn.Length = di_uni_fn.MaximumLength = stringlen;
|
||||
di_uni_fn.Buffer = uni_fn;
|
||||
} else {
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
|
||||
if (Status == STATUS_NO_MORE_FILES && IrpSp->Flags & SL_RETURN_SINGLE_ENTRY)
|
||||
if (Status == STATUS_NO_MORE_FILES && initial)
|
||||
Status = STATUS_NO_SUCH_FILE;
|
||||
|
||||
goto end;
|
||||
|
@ -689,7 +750,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
TRACE("file(0) = %.*s\n", de.namelen, de.name);
|
||||
TRACE("offset = %u\n", ccb->query_dir_offset - 1);
|
||||
|
||||
Status = query_dir_item(fcb, buf, &length, Irp, &de, fcb->subvol);
|
||||
Status = query_dir_item(fcb, fileref, buf, &length, Irp, &de, fcb->subvol);
|
||||
|
||||
count = 0;
|
||||
if (NT_SUCCESS(Status) && !(IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) && !specific_file) {
|
||||
|
@ -717,7 +778,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
WCHAR* uni_fn = NULL;
|
||||
UNICODE_STRING di_uni_fn;
|
||||
|
||||
Status = next_dir_entry(fcb, &ccb->query_dir_offset, &de, &tp);
|
||||
Status = next_dir_entry(fcb, fileref, &ccb->query_dir_offset, &de, &tp);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (has_wildcard) {
|
||||
ULONG stringlen;
|
||||
|
@ -725,14 +786,12 @@ 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 (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
uni_fn = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
|
||||
if (!uni_fn) {
|
||||
ERR("out of memory\n");
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
@ -742,7 +801,6 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
ExFreePool(uni_fn);
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -757,7 +815,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
TRACE("file(%u) %u = %.*s\n", count, curitem - (UINT8*)buf, de.namelen, de.name);
|
||||
TRACE("offset = %u\n", ccb->query_dir_offset - 1);
|
||||
|
||||
status2 = query_dir_item(fcb, curitem, &length, Irp, &de, fcb->subvol);
|
||||
status2 = query_dir_item(fcb, fileref, curitem, &length, Irp, &de, fcb->subvol);
|
||||
|
||||
if (NT_SUCCESS(status2)) {
|
||||
ULONG* lastoffset = (ULONG*)lastitem;
|
||||
|
@ -789,8 +847,6 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
Irp->IoStatus.Information = IrpSp->Parameters.QueryDirectory.Length - length;
|
||||
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
|
@ -804,11 +860,18 @@ static NTSTATUS STDCALL notify_change_directory(device_extension* Vcb, PIRP Irp)
|
|||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
ccb* ccb = FileObject->FsContext2;
|
||||
file_ref* fileref = ccb->fileref;
|
||||
NTSTATUS Status;
|
||||
// WCHAR fn[MAX_PATH];
|
||||
|
||||
TRACE("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
|
||||
|
||||
if (!fileref) {
|
||||
ERR("no fileref\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
if (fcb->type != BTRFS_TYPE_DIRECTORY) {
|
||||
|
@ -818,9 +881,9 @@ static NTSTATUS STDCALL notify_change_directory(device_extension* Vcb, PIRP Irp)
|
|||
|
||||
// FIXME - raise exception if FCB marked for deletion?
|
||||
|
||||
TRACE("%.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
|
||||
TRACE("%S\n", file_desc(FileObject));
|
||||
|
||||
FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext2, (PSTRING)&fcb->full_filename,
|
||||
FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext2, (PSTRING)&fileref->full_filename,
|
||||
IrpSp->Flags & SL_WATCH_TREE, FALSE, IrpSp->Parameters.NotifyDirectory.CompletionFilter, Irp, NULL, NULL);
|
||||
|
||||
Status = STATUS_PENDING;
|
||||
|
@ -867,6 +930,10 @@ NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP I
|
|||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
|
1239
reactos/drivers/filesystems/btrfs/extent-tree.c
Normal file
1239
reactos/drivers/filesystems/btrfs/extent-tree.c
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -31,7 +31,7 @@ static void do_flush(device_extension* Vcb) {
|
|||
if (Vcb->write_trees > 0)
|
||||
do_write(Vcb, &rollback);
|
||||
|
||||
free_tree_cache(&Vcb->tree_cache);
|
||||
free_trees(Vcb);
|
||||
|
||||
clear_rollback(&rollback);
|
||||
|
||||
|
@ -41,23 +41,31 @@ static void do_flush(device_extension* Vcb) {
|
|||
}
|
||||
|
||||
void STDCALL flush_thread(void* context) {
|
||||
device_extension* Vcb = context;
|
||||
DEVICE_OBJECT* devobj = context;
|
||||
device_extension* Vcb = devobj->DeviceExtension;
|
||||
LARGE_INTEGER due_time;
|
||||
KTIMER flush_thread_timer;
|
||||
|
||||
KeInitializeTimer(&Vcb->flush_thread_timer);
|
||||
ObReferenceObject(devobj);
|
||||
|
||||
KeInitializeTimer(&flush_thread_timer);
|
||||
|
||||
due_time.QuadPart = -INTERVAL * 10000;
|
||||
|
||||
KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
|
||||
KeSetTimer(&flush_thread_timer, due_time, NULL);
|
||||
|
||||
while (TRUE) {
|
||||
KeWaitForSingleObject(&Vcb->flush_thread_timer, Executive, KernelMode, FALSE, NULL);
|
||||
KeWaitForSingleObject(&flush_thread_timer, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
if (!(devobj->Vpb->Flags & VPB_MOUNTED))
|
||||
break;
|
||||
|
||||
do_flush(Vcb);
|
||||
|
||||
KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
|
||||
KeSetTimer(&flush_thread_timer, due_time, NULL);
|
||||
}
|
||||
|
||||
KeCancelTimer(&Vcb->flush_thread_timer);
|
||||
ObDereferenceObject(devobj);
|
||||
KeCancelTimer(&flush_thread_timer);
|
||||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
}
|
||||
|
|
1089
reactos/drivers/filesystems/btrfs/free-space.c
Normal file
1089
reactos/drivers/filesystems/btrfs/free-space.c
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* Adapted from code at http://support.fccps.cz/download/adv/frr/win32_ddk_mingw/win32_ddk_mingw.html - thanks!
|
||||
*
|
||||
File created by Frank Rysanek <rysanek@fccps.cz>
|
||||
Source code taken almost verbatim from "Driver Development, Part 1"
|
||||
published by Toby Opferman at CodeProject.com
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
/*#include <string.h>*/
|
||||
#include <unistd.h> /* getcwd() */
|
||||
|
||||
#define MY_DRIVER_NAME "btrfs"
|
||||
#define MY_DEVICE_NAME "\\Btrfs"
|
||||
#define MY_DOSDEVICE_NAME "\\DosDevices\\" MY_DRIVER_NAME /* AKA symlink name */
|
||||
/* for the loader and app */
|
||||
#define MY_SERVICE_NAME_LONG "Driver Test2"
|
||||
#define MY_SERVICE_NAME_SHORT MY_DRIVER_NAME
|
||||
#define MY_DRIVER_FILENAME MY_DRIVER_NAME ".sys"
|
||||
|
||||
#define MAX_CWD_LEN 1024
|
||||
static char cwd[MAX_CWD_LEN+3]; /* the XXXXX.sys filename will get appended to this as well */
|
||||
|
||||
/* geterrstr() taken verbatim from some code snippet at www.mingw.org by Dan Osborne. */
|
||||
/* Apparently, it's a way to get a classic null-terminated string containing "last error". */
|
||||
static char errbuffer[256];
|
||||
|
||||
static const char *geterrstr(DWORD errcode)
|
||||
{
|
||||
size_t skip = 0;
|
||||
DWORD chars;
|
||||
|
||||
chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errcode, 0, errbuffer, sizeof(errbuffer)-1, 0);
|
||||
errbuffer[sizeof(errbuffer)-1] = 0;
|
||||
|
||||
if (chars)
|
||||
{
|
||||
while (errbuffer[chars-1] == '\r' || errbuffer[chars-1] == '\n')
|
||||
{
|
||||
errbuffer[--chars] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (chars && errbuffer[chars-1] == '.') errbuffer[--chars] = 0;
|
||||
|
||||
if (chars >= 2 && errbuffer[0] == '%'
|
||||
&& errbuffer[1] >= '0' && errbuffer[1] <= '9')
|
||||
{
|
||||
skip = 2;
|
||||
|
||||
while (chars > skip && errbuffer[skip] == ' ') ++skip;
|
||||
|
||||
if (chars >= skip+2 && errbuffer[skip] == 'i' && errbuffer[skip+1] == 's')
|
||||
{
|
||||
skip += 2;
|
||||
while (chars > skip && errbuffer[skip] == ' ') ++skip;
|
||||
}
|
||||
}
|
||||
|
||||
if (chars > skip && errbuffer[skip] >= 'A' && errbuffer[skip] <= 'Z')
|
||||
{
|
||||
errbuffer[skip] += 'a' - 'A';
|
||||
}
|
||||
|
||||
return errbuffer+skip;
|
||||
}
|
||||
|
||||
void process_error(void)
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
printf("Error: %lu = \"%s\"\n", (unsigned long)err, geterrstr(err));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
HANDLE hSCManager;
|
||||
HANDLE hService;
|
||||
SERVICE_STATUS ss;
|
||||
int retval = 0;
|
||||
BOOL amd64;
|
||||
|
||||
/* First of all, maybe concatenate the current working directory
|
||||
with the desired driver file name - before we start messing with
|
||||
the service manager etc. */
|
||||
if (getcwd(cwd, MAX_CWD_LEN) == NULL) /* error */
|
||||
{
|
||||
printf("Failed to learn the current working directory!\n");
|
||||
retval = -8;
|
||||
goto err_out1;
|
||||
} /* else got CWD just fine */
|
||||
|
||||
if (strlen(cwd) + strlen(MY_DRIVER_FILENAME) + 1 > MAX_CWD_LEN)
|
||||
{
|
||||
printf("Current working dir + driver filename > longer than %d ?!?\n", MAX_CWD_LEN);
|
||||
retval = -9;
|
||||
goto err_out1;
|
||||
} /* else our buffer is long enough :-) */
|
||||
|
||||
strcat(cwd, "\\");
|
||||
|
||||
IsWow64Process(GetCurrentProcess(),&amd64);
|
||||
strcat(cwd, amd64 ? "x64" : "x86");
|
||||
|
||||
strcat(cwd, "\\");
|
||||
strcat(cwd, MY_DRIVER_FILENAME);
|
||||
printf("Driver path+name: %s\n", cwd);
|
||||
|
||||
|
||||
printf("Going to open the service manager... ");
|
||||
|
||||
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
|
||||
if (! hSCManager)
|
||||
{
|
||||
printf("Uh oh:\n");
|
||||
process_error();
|
||||
retval = -1;
|
||||
goto err_out1;
|
||||
}
|
||||
|
||||
printf("okay.\n");
|
||||
printf("Going to create the service... ");
|
||||
|
||||
hService = CreateService(hSCManager, MY_SERVICE_NAME_SHORT,
|
||||
MY_SERVICE_NAME_LONG,
|
||||
SERVICE_START | DELETE | SERVICE_STOP,
|
||||
SERVICE_KERNEL_DRIVER,
|
||||
SERVICE_DEMAND_START,
|
||||
SERVICE_ERROR_IGNORE,
|
||||
cwd,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if(!hService)
|
||||
{
|
||||
process_error();
|
||||
printf("\n already exists? Trying to open it... ");
|
||||
hService = OpenService(hSCManager, MY_SERVICE_NAME_SHORT,
|
||||
SERVICE_START | DELETE | SERVICE_STOP);
|
||||
}
|
||||
|
||||
if(!hService)
|
||||
{
|
||||
printf("FAILED!\n");
|
||||
process_error();
|
||||
retval = -2;
|
||||
goto err_out2;
|
||||
}
|
||||
|
||||
printf("okay.\n");
|
||||
printf("Going to start the service... ");
|
||||
|
||||
if (StartService(hService, 0, NULL) == 0) /* error */
|
||||
{
|
||||
printf("Uh oh:\n");
|
||||
process_error();
|
||||
retval = -3;
|
||||
goto err_out3;
|
||||
}
|
||||
|
||||
printf("okay.\n");
|
||||
|
||||
// TCHAR VolumeName[] = _T("Z:");
|
||||
// TCHAR DeviceName[] = _T("\\Device\\VDisk1");
|
||||
|
||||
// printf("Mounting volume... ");
|
||||
// if (!DefineDosDeviceA(DDD_RAW_TARGET_PATH, "T:", "\\Device\\HarddiskVolume3"))
|
||||
// {
|
||||
// printf("Uh oh:\n");
|
||||
// process_error();
|
||||
// } else {
|
||||
// printf("okay.\n");
|
||||
// }
|
||||
|
||||
// if (!SetVolumeMountPointA("T:\\", "\\\\?\\Volume{9bd714c3-4379-11e5-b26c-806e6f6e6963}\\")) {
|
||||
// printf("Uh oh:\n");
|
||||
// process_error();
|
||||
// } else {
|
||||
// printf("okay.\n");
|
||||
// }
|
||||
|
||||
printf("\n >>> Press Enter to unload the driver! <<<\n");
|
||||
getchar();
|
||||
|
||||
// printf("Unmounting volume... ");
|
||||
// if (!DefineDosDeviceA(DDD_REMOVE_DEFINITION, "T:", NULL))
|
||||
// {
|
||||
// printf("Uh oh:\n");
|
||||
// process_error();
|
||||
// } else {
|
||||
// printf("okay.\n");
|
||||
// }
|
||||
|
||||
printf("Going to stop the service... ");
|
||||
if (ControlService(hService, SERVICE_CONTROL_STOP, &ss) == 0) /* error */
|
||||
{
|
||||
printf("Uh oh:\n");
|
||||
process_error();
|
||||
retval = -4;
|
||||
}
|
||||
else printf("okay.\n");
|
||||
|
||||
err_out3:
|
||||
|
||||
printf("Going to close the service handle... ");
|
||||
if (CloseServiceHandle(hService) == 0) /* error */
|
||||
{
|
||||
printf("Uh oh:\n");
|
||||
process_error();
|
||||
retval = -6;
|
||||
}
|
||||
else printf("okay.\n");
|
||||
|
||||
err_out2:
|
||||
|
||||
printf("Going to close the service manager... ");
|
||||
if (CloseServiceHandle(hSCManager) == 0) /* error */
|
||||
{
|
||||
printf("Uh oh:\n");
|
||||
process_error();
|
||||
retval = -7;
|
||||
}
|
||||
else printf("okay.\n");
|
||||
|
||||
err_out1:
|
||||
|
||||
printf("Finished! :-b\n");
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
283
reactos/drivers/filesystems/btrfs/pnp.c
Normal file
283
reactos/drivers/filesystems/btrfs/pnp.c
Normal file
|
@ -0,0 +1,283 @@
|
|||
#include "btrfs_drv.h"
|
||||
|
||||
struct pnp_context;
|
||||
|
||||
typedef struct {
|
||||
struct pnp_context* context;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
NTSTATUS Status;
|
||||
} pnp_stripe;
|
||||
|
||||
typedef struct {
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
LONG left;
|
||||
pnp_stripe* stripes;
|
||||
} pnp_context;
|
||||
|
||||
static NTSTATUS STDCALL pnp_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
|
||||
pnp_stripe* stripe = conptr;
|
||||
pnp_context* context = (pnp_context*)stripe->context;
|
||||
|
||||
stripe->Status = Irp->IoStatus.Status;
|
||||
|
||||
InterlockedDecrement(&context->left);
|
||||
|
||||
if (context->left == 0)
|
||||
KeSetEvent(&context->Event, 0, FALSE);
|
||||
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
static NTSTATUS send_disks_pnp_message(device_extension* Vcb, UCHAR minor) {
|
||||
pnp_context* context;
|
||||
UINT64 num_devices, i;
|
||||
NTSTATUS Status;
|
||||
|
||||
context = ExAllocatePoolWithTag(NonPagedPool, sizeof(pnp_context), ALLOC_TAG);
|
||||
if (!context) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(context, sizeof(pnp_context));
|
||||
KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
|
||||
|
||||
num_devices = Vcb->superblock.num_devices;
|
||||
|
||||
context->stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(pnp_stripe) * num_devices, ALLOC_TAG);
|
||||
if (!context->stripes) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(context);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(context->stripes, sizeof(pnp_stripe) * num_devices);
|
||||
|
||||
for (i = 0; i < num_devices; i++) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
if (Vcb->devices[i].devobj) {
|
||||
context->stripes[i].context = (struct pnp_context*)context;
|
||||
|
||||
context->stripes[i].Irp = IoAllocateIrp(Vcb->devices[i].devobj->StackSize, FALSE);
|
||||
|
||||
if (!context->stripes[i].Irp) {
|
||||
UINT64 j;
|
||||
|
||||
ERR("IoAllocateIrp failed\n");
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
if (Vcb->devices[j].devobj) {
|
||||
IoFreeIrp(context->stripes[j].Irp);
|
||||
}
|
||||
}
|
||||
ExFreePool(context->stripes);
|
||||
ExFreePool(context);
|
||||
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
IrpSp = IoGetNextIrpStackLocation(context->stripes[i].Irp);
|
||||
IrpSp->MajorFunction = IRP_MJ_PNP;
|
||||
IrpSp->MinorFunction = minor;
|
||||
|
||||
context->stripes[i].Irp->UserIosb = &context->stripes[i].iosb;
|
||||
|
||||
IoSetCompletionRoutine(context->stripes[i].Irp, pnp_completion, &context->stripes[i], TRUE, TRUE, TRUE);
|
||||
|
||||
context->stripes[i].Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
context->left++;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->left == 0) {
|
||||
Status = STATUS_SUCCESS;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_devices; i++) {
|
||||
if (context->stripes[i].Irp) {
|
||||
IoCallDriver(Vcb->devices[i].devobj, context->stripes[i].Irp);
|
||||
}
|
||||
}
|
||||
|
||||
KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
for (i = 0; i < num_devices; i++) {
|
||||
if (context->stripes[i].Irp) {
|
||||
if (context->stripes[i].Status != STATUS_SUCCESS)
|
||||
Status = context->stripes[i].Status;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
for (i = 0; i < num_devices; i++) {
|
||||
if (context->stripes[i].Irp) {
|
||||
IoFreeIrp(context->stripes[i].Irp);
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(context->stripes);
|
||||
ExFreePool(context);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS pnp_cancel_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
device_extension* Vcb = DeviceObject->DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
|
||||
|
||||
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->fcb->open_count > 0 || has_open_children(Vcb->root_fileref))) {
|
||||
Status = STATUS_ACCESS_DENIED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = send_disks_pnp_message(Vcb, IRP_MN_CANCEL_REMOVE_DEVICE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
WARN("send_disks_pnp_message returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Vcb->removing = FALSE;
|
||||
end:
|
||||
ExReleaseResourceLite(&Vcb->fcb_lock);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
device_extension* Vcb = DeviceObject->DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
LIST_ENTRY rollback;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
|
||||
|
||||
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->fcb->open_count > 0 || has_open_children(Vcb->root_fileref))) {
|
||||
Status = STATUS_ACCESS_DENIED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
WARN("send_disks_pnp_message returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Vcb->removing = TRUE;
|
||||
|
||||
InitializeListHead(&rollback);
|
||||
|
||||
acquire_tree_lock(Vcb, TRUE);
|
||||
|
||||
if (Vcb->write_trees > 0)
|
||||
do_write(Vcb, &rollback);
|
||||
|
||||
clear_rollback(&rollback);
|
||||
|
||||
release_tree_lock(Vcb, TRUE);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
end:
|
||||
ExReleaseResourceLite(&Vcb->fcb_lock);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
device_extension* Vcb = DeviceObject->DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = send_disks_pnp_message(Vcb, IRP_MN_REMOVE_DEVICE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
WARN("send_disks_pnp_message returned %08x\n", Status);
|
||||
}
|
||||
|
||||
if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
|
||||
uninit(Vcb, FALSE);
|
||||
DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS pnp_start_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
FIXME("STUB\n");
|
||||
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
FIXME("STUB\n");
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
device_extension* Vcb = DeviceObject->DeviceExtension;
|
||||
NTSTATUS Status;
|
||||
BOOL top_level;
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
top_level = is_top_level(Irp);
|
||||
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
switch (IrpSp->MinorFunction) {
|
||||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||||
Status = pnp_cancel_remove_device(DeviceObject, Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||||
Status = pnp_query_remove_device(DeviceObject, Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_REMOVE_DEVICE:
|
||||
Status = pnp_remove_device(DeviceObject, Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_START_DEVICE:
|
||||
Status = pnp_start_device(DeviceObject, Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_SURPRISE_REMOVAL:
|
||||
Status = pnp_surprise_removal(DeviceObject, Irp);
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("passing minor function 0x%x on\n", IrpSp->MinorFunction);
|
||||
|
||||
IoSkipCurrentIrpStackLocation(Irp);
|
||||
Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
// // Irp->IoStatus.Status = Status;
|
||||
// // Irp->IoStatus.Information = 0;
|
||||
//
|
||||
// IoSkipCurrentIrpStackLocation(Irp);
|
||||
//
|
||||
// Status = IoCallDriver(Vcb->devices[0].devobj, Irp);
|
||||
//
|
||||
// // IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
end:
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -331,7 +331,6 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
|
||||
if (tp.item->key.obj_id < searchkey.obj_id || tp.item->key.obj_type < searchkey.obj_type) {
|
||||
if (find_next_item(Vcb, &tp, &next_tp, FALSE)) {
|
||||
free_traverse_ptr(&tp);
|
||||
tp = next_tp;
|
||||
|
||||
TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
|
@ -339,7 +338,6 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
}
|
||||
|
||||
if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
|
||||
free_traverse_ptr(&tp);
|
||||
ERR("couldn't find EXTENT_DATA for inode %llx in subvol %llx\n", searchkey.obj_id, subvol->id);
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
|
@ -347,7 +345,6 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
|
||||
if (tp.item->key.offset > start) {
|
||||
ERR("first EXTENT_DATA was after offset\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -375,14 +372,12 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
|
||||
if (tp.item->size < sizeof(EXTENT_DATA)) {
|
||||
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_DATA));
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) && tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
|
||||
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_DATA) - 1 + sizeof(EXTENT_DATA2));
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -393,28 +388,24 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
|
||||
if (tp.item->key.offset + len < start) {
|
||||
ERR("Tried to read beyond end of file\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_END_OF_FILE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ed->compression != BTRFS_COMPRESSION_NONE) {
|
||||
FIXME("FIXME - compression not yet supported\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ed->encryption != BTRFS_ENCRYPTION_NONE) {
|
||||
WARN("Encryption not supported\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ed->encoding != BTRFS_ENCODING_NONE) {
|
||||
WARN("Other encodings not supported\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -452,7 +443,6 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
|
||||
if (!buf) {
|
||||
ERR("out of memory\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -463,7 +453,6 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_data returned %08x\n", Status);
|
||||
ExFreePool(buf);
|
||||
free_traverse_ptr(&tp);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -495,7 +484,6 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
|
||||
default:
|
||||
WARN("Unsupported extent data type %u\n", ed->type);
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -509,20 +497,16 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI
|
|||
next_tp.item->key.obj_type != TYPE_EXTENT_DATA ||
|
||||
next_tp.item->key.offset != tp.item->key.offset + len
|
||||
) {
|
||||
free_traverse_ptr(&next_tp);
|
||||
break;
|
||||
} else {
|
||||
TRACE("found next key (%llx,%x,%llx)\n", next_tp.item->key.obj_id, next_tp.item->key.obj_type, next_tp.item->key.offset);
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
tp = next_tp;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
} while (TRUE);
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
if (pbr)
|
||||
*pbr = bytes_read;
|
||||
|
@ -547,53 +531,18 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
TRACE("read\n");
|
||||
|
||||
switch (IrpSp->MinorFunction) {
|
||||
case IRP_MN_COMPLETE:
|
||||
FIXME("unsupported - IRP_MN_COMPLETE\n");
|
||||
break;
|
||||
|
||||
case IRP_MN_COMPLETE_MDL:
|
||||
FIXME("unsupported - IRP_MN_COMPLETE_MDL\n");
|
||||
break;
|
||||
|
||||
case IRP_MN_COMPLETE_MDL_DPC:
|
||||
FIXME("unsupported - IRP_MN_COMPLETE_MDL_DPC\n");
|
||||
break;
|
||||
|
||||
case IRP_MN_COMPRESSED:
|
||||
FIXME("unsupported - IRP_MN_COMPRESSED\n");
|
||||
break;
|
||||
|
||||
case IRP_MN_DPC:
|
||||
FIXME("unsupported - IRP_MN_DPC\n");
|
||||
break;
|
||||
|
||||
case IRP_MN_MDL:
|
||||
FIXME("unsupported - IRP_MN_MDL\n");
|
||||
break;
|
||||
|
||||
case IRP_MN_MDL_DPC:
|
||||
FIXME("unsupported - IRP_MN_MDL_DPC\n");
|
||||
break;
|
||||
|
||||
case IRP_MN_NORMAL:
|
||||
TRACE("IRP_MN_NORMAL\n");
|
||||
break;
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
if (IrpSp->MinorFunction & IRP_MN_COMPLETE) {
|
||||
CcMdlReadComplete(IrpSp->FileObject, Irp->MdlAddress);
|
||||
|
||||
Irp->MdlAddress = NULL;
|
||||
Status = STATUS_SUCCESS;
|
||||
bytes_read = 0;
|
||||
|
||||
default:
|
||||
WARN("unknown minor %u\n", IrpSp->MinorFunction);
|
||||
}
|
||||
|
||||
data = map_user_buffer(Irp);
|
||||
|
||||
if (Irp->MdlAddress && !data) {
|
||||
ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
start = IrpSp->Parameters.Read.ByteOffset.QuadPart;
|
||||
length = IrpSp->Parameters.Read.Length;
|
||||
bytes_read = 0;
|
||||
|
@ -603,11 +552,14 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
goto exit;
|
||||
}
|
||||
|
||||
TRACE("file = %.*S (fcb = %p)\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb);
|
||||
TRACE("file = %S (fcb = %p)\n", file_desc(FileObject), fcb);
|
||||
TRACE("offset = %llx, length = %x\n", start, length);
|
||||
TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO ? "TRUE" : "FALSE", Irp->Flags & IRP_NOCACHE ? "TRUE" : "FALSE");
|
||||
|
||||
// FIXME - shouldn't be able to read from a directory
|
||||
if (fcb->type == BTRFS_TYPE_DIRECTORY) {
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(Irp->Flags & IRP_PAGING_IO) && !FsRtlCheckLockForReadAccess(&fcb->lock, Irp)) {
|
||||
WARN("tried to read locked region\n");
|
||||
|
@ -630,9 +582,19 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
TRACE("FileObject %p fcb %p FileSize = %llx st_size = %llx (%p)\n", FileObject, fcb, fcb->Header.FileSize.QuadPart, fcb->inode_item.st_size, &fcb->inode_item.st_size);
|
||||
// int3;
|
||||
|
||||
if (length + start > fcb->Header.ValidDataLength.QuadPart) {
|
||||
RtlZeroMemory(data + (fcb->Header.ValidDataLength.QuadPart - start), length - (fcb->Header.ValidDataLength.QuadPart - start));
|
||||
length = fcb->Header.ValidDataLength.QuadPart - start;
|
||||
if (Irp->Flags & IRP_NOCACHE || !(IrpSp->MinorFunction & IRP_MN_MDL)) {
|
||||
data = map_user_buffer(Irp);
|
||||
|
||||
if (Irp->MdlAddress && !data) {
|
||||
ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (length + start > fcb->Header.ValidDataLength.QuadPart) {
|
||||
RtlZeroMemory(data + (fcb->Header.ValidDataLength.QuadPart - start), length - (fcb->Header.ValidDataLength.QuadPart - start));
|
||||
length = fcb->Header.ValidDataLength.QuadPart - start;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Irp->Flags & IRP_NOCACHE)) {
|
||||
|
@ -640,7 +602,7 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
// try {
|
||||
try {
|
||||
if (!FileObject->PrivateCacheMap) {
|
||||
CC_FILE_SIZES ccfs;
|
||||
|
||||
|
@ -659,19 +621,23 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
// wait = IoIsOperationSynchronous(Irp) ? TRUE : FALSE;
|
||||
wait = TRUE;
|
||||
|
||||
TRACE("CcCopyRead(%p, %llx, %x, %u, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, length, wait, data, &Irp->IoStatus);
|
||||
TRACE("sizes = %llx, %llx, %llx\n", fcb->Header.AllocationSize, fcb->Header.FileSize, fcb->Header.ValidDataLength);
|
||||
if (!CcCopyRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus)) {
|
||||
TRACE("CcCopyRead failed\n");
|
||||
|
||||
IoMarkIrpPending(Irp);
|
||||
Status = STATUS_PENDING;
|
||||
goto exit;
|
||||
if (IrpSp->MinorFunction & IRP_MN_MDL) {
|
||||
CcMdlRead(FileObject,&IrpSp->Parameters.Read.ByteOffset, length, &Irp->MdlAddress, &Irp->IoStatus);
|
||||
} else {
|
||||
TRACE("CcCopyRead(%p, %llx, %x, %u, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, length, wait, data, &Irp->IoStatus);
|
||||
TRACE("sizes = %llx, %llx, %llx\n", fcb->Header.AllocationSize, fcb->Header.FileSize, fcb->Header.ValidDataLength);
|
||||
if (!CcCopyRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus)) {
|
||||
TRACE("CcCopyRead failed\n");
|
||||
|
||||
IoMarkIrpPending(Irp);
|
||||
Status = STATUS_PENDING;
|
||||
goto exit;
|
||||
}
|
||||
TRACE("CcCopyRead finished\n");
|
||||
}
|
||||
TRACE("CcCopyRead finished\n");
|
||||
// } except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
// Status = GetExceptionCode();
|
||||
// }
|
||||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
Status = GetExceptionCode();
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
Status = Irp->IoStatus.Status;
|
||||
|
@ -711,6 +677,10 @@ exit:
|
|||
if (FileObject->Flags & FO_SYNCHRONOUS_IO && !(Irp->Flags & IRP_PAGING_IO))
|
||||
FileObject->CurrentByteOffset.QuadPart = start + (NT_SUCCESS(Status) ? bytes_read : 0);
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -17,148 +17,6 @@
|
|||
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
BOOL follow_symlink(fcb* fcb, PFILE_OBJECT FileObject) {
|
||||
NTSTATUS Status;
|
||||
ULONG len, stringlen;
|
||||
USHORT newlen;
|
||||
OBJECT_NAME_INFORMATION* oni;
|
||||
UINT8* data;
|
||||
UINT32 i;
|
||||
BOOL success = FALSE;
|
||||
WCHAR* utf16;
|
||||
UNICODE_STRING abspath;
|
||||
|
||||
if (fcb->inode_item.st_size == 0) {
|
||||
WARN("can't follow symlink with no data\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Status = ObQueryNameString(FileObject->DeviceObject, NULL, 0, &len);
|
||||
|
||||
if (Status != STATUS_INFO_LENGTH_MISMATCH) {
|
||||
ERR("ObQueryNameString 1 returned %08x\n", Status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
oni = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG);
|
||||
if (!oni) {
|
||||
ERR("out of memory\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = ObQueryNameString(FileObject->DeviceObject, oni, len, &len);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ObQueryNameString 2 returned %08x\n", Status);
|
||||
ExFreePool(oni);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data = ExAllocatePoolWithTag(PagedPool, fcb->inode_item.st_size, ALLOC_TAG);
|
||||
if (!data) {
|
||||
ERR("out of memory\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = read_file(fcb->Vcb, fcb->subvol, fcb->inode, data, 0, fcb->inode_item.st_size, NULL);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_file returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; i < fcb->inode_item.st_size; i++) {
|
||||
if (data[i] == '/')
|
||||
data[i] = '\\';
|
||||
}
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, (char*)data, fcb->inode_item.st_size);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
utf16 = ExAllocatePoolWithTag(PagedPool, stringlen, ALLOC_TAG);
|
||||
if (!utf16) {
|
||||
ERR("out of memory\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(utf16, stringlen, &stringlen, (char*)data, fcb->inode_item.st_size);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
|
||||
ExFreePool(utf16);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (utf16[0] == '\\') { // absolute path
|
||||
abspath.MaximumLength = abspath.Length = stringlen;
|
||||
abspath.Buffer = utf16;
|
||||
} else { // relative path
|
||||
abspath.MaximumLength = fcb->par->full_filename.Length + sizeof(WCHAR) + stringlen;
|
||||
abspath.Buffer = ExAllocatePoolWithTag(PagedPool, abspath.MaximumLength, ALLOC_TAG);
|
||||
if (!abspath.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(utf16);
|
||||
goto end;
|
||||
}
|
||||
|
||||
RtlCopyMemory(abspath.Buffer, fcb->par->full_filename.Buffer, fcb->par->full_filename.Length);
|
||||
abspath.Length = fcb->par->full_filename.Length;
|
||||
|
||||
if (fcb->par->par) {
|
||||
abspath.Buffer[abspath.Length / sizeof(WCHAR)] = '\\';
|
||||
abspath.Length += sizeof(WCHAR);
|
||||
}
|
||||
|
||||
RtlCopyMemory(&abspath.Buffer[abspath.Length / sizeof(WCHAR)], utf16, stringlen);
|
||||
abspath.Length += stringlen;
|
||||
|
||||
ExFreePool(utf16);
|
||||
}
|
||||
|
||||
Status = FsRtlRemoveDotsFromPath(abspath.Buffer, abspath.Length, &newlen);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("FsRtlRemoveDotsFromPath returned %08x\n", Status);
|
||||
ExFreePool(abspath.Buffer);
|
||||
goto end;
|
||||
}
|
||||
|
||||
abspath.Length = newlen;
|
||||
|
||||
TRACE("abspath = %.*S\n", abspath.Length / sizeof(WCHAR), abspath.Buffer);
|
||||
|
||||
TRACE("filename was %.*S\n", FileObject->FileName.Length / sizeof(WCHAR), FileObject->FileName.Buffer);
|
||||
|
||||
if (FileObject->FileName.MaximumLength < oni->Name.Length + abspath.Length) {
|
||||
ExFreePool(FileObject->FileName.Buffer);
|
||||
FileObject->FileName.MaximumLength = oni->Name.Length + abspath.Length;
|
||||
FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.MaximumLength, ALLOC_TAG);
|
||||
|
||||
if (!FileObject->FileName.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
ExFreePool(abspath.Buffer);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
RtlCopyMemory(FileObject->FileName.Buffer, oni->Name.Buffer, oni->Name.Length);
|
||||
RtlCopyMemory(&FileObject->FileName.Buffer[oni->Name.Length / sizeof(WCHAR)], abspath.Buffer, abspath.Length);
|
||||
FileObject->FileName.Length = oni->Name.Length + abspath.Length;
|
||||
|
||||
TRACE("filename now %.*S\n", FileObject->FileName.Length / sizeof(WCHAR), FileObject->FileName.Buffer);
|
||||
|
||||
ExFreePool(abspath.Buffer);
|
||||
|
||||
success = TRUE;
|
||||
end:
|
||||
ExFreePool(data);
|
||||
ExFreePool(oni);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, DWORD* retlen) {
|
||||
USHORT subnamelen, printnamelen, i;
|
||||
ULONG stringlen;
|
||||
|
@ -168,81 +26,118 @@ NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
|||
char* data;
|
||||
NTSTATUS Status;
|
||||
|
||||
// FIXME - check permissions
|
||||
|
||||
TRACE("(%p, %p, %p, %x, %p)\n", DeviceObject, FileObject, buffer, buflen, retlen);
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
if (fcb->type != BTRFS_TYPE_SYMLINK) {
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data = ExAllocatePoolWithTag(PagedPool, fcb->inode_item.st_size, ALLOC_TAG);
|
||||
if (!data) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_file returned %08x\n", Status);
|
||||
ExFreePool(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, data, fcb->inode_item.st_size);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
|
||||
ExFreePool(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
subnamelen = stringlen;
|
||||
printnamelen = stringlen;
|
||||
|
||||
reqlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + subnamelen + printnamelen;
|
||||
|
||||
if (buflen < reqlen) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rdb->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||
rdb->ReparseDataLength = reqlen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer);
|
||||
rdb->Reserved = 0;
|
||||
|
||||
rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
|
||||
rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = subnamelen;
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset = subnamelen;
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameLength = printnamelen;
|
||||
rdb->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
|
||||
stringlen, &stringlen, data, fcb->inode_item.st_size);
|
||||
if (fcb->type == BTRFS_TYPE_SYMLINK) {
|
||||
data = ExAllocatePoolWithTag(PagedPool, fcb->inode_item.st_size, ALLOC_TAG);
|
||||
if (!data) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_file returned %08x\n", Status);
|
||||
ExFreePool(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, data, fcb->inode_item.st_size);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
|
||||
ExFreePool(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
subnamelen = stringlen;
|
||||
printnamelen = stringlen;
|
||||
|
||||
reqlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + subnamelen + printnamelen;
|
||||
|
||||
if (buflen < reqlen) {
|
||||
Status = STATUS_BUFFER_OVERFLOW;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rdb->ReparseTag = IO_REPARSE_TAG_SYMLINK;
|
||||
rdb->ReparseDataLength = reqlen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer);
|
||||
rdb->Reserved = 0;
|
||||
|
||||
rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
|
||||
rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = subnamelen;
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameOffset = subnamelen;
|
||||
rdb->SymbolicLinkReparseBuffer.PrintNameLength = printnamelen;
|
||||
rdb->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
|
||||
stringlen, &stringlen, data, fcb->inode_item.st_size);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
|
||||
ExFreePool(data);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; i < stringlen / sizeof(WCHAR); i++) {
|
||||
if (rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] == '/')
|
||||
rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] = '\\';
|
||||
}
|
||||
|
||||
RtlCopyMemory(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)],
|
||||
&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
|
||||
rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
||||
|
||||
*retlen = reqlen;
|
||||
|
||||
ExFreePool(data);
|
||||
goto end;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (buflen > 0) {
|
||||
*retlen = min(buflen, datalen);
|
||||
RtlCopyMemory(buffer, data, *retlen);
|
||||
} else
|
||||
*retlen = 0;
|
||||
|
||||
ExFreePool(data);
|
||||
} else
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
} else {
|
||||
Status = STATUS_NOT_A_REPARSE_POINT;
|
||||
}
|
||||
|
||||
for (i = 0; i < stringlen / sizeof(WCHAR); i++) {
|
||||
if (rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] == '/')
|
||||
rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] = '\\';
|
||||
}
|
||||
|
||||
RtlCopyMemory(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)],
|
||||
&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
|
||||
rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
|
||||
|
||||
*retlen = reqlen;
|
||||
|
||||
ExFreePool(data);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
|
@ -278,7 +173,6 @@ static NTSTATUS change_file_type(device_extension* Vcb, UINT64 inode, root* subv
|
|||
|
||||
if (!di) {
|
||||
ERR("out of memory\n");
|
||||
free_traverse_ptr(&tp);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
|
@ -314,8 +208,6 @@ static NTSTATUS change_file_type(device_extension* Vcb, UINT64 inode, root* subv
|
|||
WARN("search for DIR_ITEM by crc32 failed\n");
|
||||
}
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
|
||||
searchkey.obj_id = parinode;
|
||||
searchkey.obj_type = TYPE_DIR_INDEX;
|
||||
searchkey.offset = index;
|
||||
|
@ -334,7 +226,6 @@ static NTSTATUS change_file_type(device_extension* Vcb, UINT64 inode, root* subv
|
|||
DIR_ITEM* di2 = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
|
||||
if (!di2) {
|
||||
ERR("out of memory\n");
|
||||
free_traverse_ptr(&tp);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
|
@ -346,85 +237,24 @@ static NTSTATUS change_file_type(device_extension* Vcb, UINT64 inode, root* subv
|
|||
}
|
||||
}
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
void* buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
fcb* fcb;
|
||||
ULONG tag, minlen;
|
||||
static NTSTATUS set_symlink(PIRP Irp, fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, LIST_ENTRY* rollback) {
|
||||
NTSTATUS Status;
|
||||
ULONG minlen;
|
||||
UNICODE_STRING subname;
|
||||
ANSI_STRING target;
|
||||
REPARSE_DATA_BUFFER* rdb = buffer;
|
||||
KEY searchkey;
|
||||
traverse_ptr tp, next_tp;
|
||||
BOOL b;
|
||||
LARGE_INTEGER offset;
|
||||
USHORT i;
|
||||
LIST_ENTRY rollback;
|
||||
|
||||
// FIXME - send notification if this succeeds? The attributes will have changed.
|
||||
|
||||
TRACE("(%p, %p)\n", DeviceObject, Irp);
|
||||
|
||||
InitializeListHead(&rollback);
|
||||
|
||||
if (!FileObject) {
|
||||
ERR("FileObject was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
fcb = FileObject->FsContext;
|
||||
|
||||
ERR("filename: %.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, TRUE);
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_SYMLINK) {
|
||||
WARN("tried to set a reparse point on an existing symlink\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!fcb->utf8.Buffer) {
|
||||
ERR("error - utf8 on FCB not set\n");
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// FIXME - die if not file
|
||||
// FIXME - die if ADS
|
||||
|
||||
if (buflen < sizeof(ULONG)) {
|
||||
WARN("buffer was not long enough to hold tag\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
RtlCopyMemory(&tag, buffer, sizeof(ULONG));
|
||||
|
||||
if (tag != IO_REPARSE_TAG_SYMLINK) {
|
||||
FIXME("FIXME: handle arbitrary reparse tags (%08x)\n", tag);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
minlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + sizeof(WCHAR);
|
||||
if (buflen < minlen) {
|
||||
WARN("buffer was less than minimum length (%u < %u)\n", buflen, minlen);
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE)) {
|
||||
FIXME("FIXME: support non-relative symlinks\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
subname.Buffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)];
|
||||
|
@ -441,7 +271,7 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
goto end;
|
||||
return Status;
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -464,11 +294,11 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
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);
|
||||
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);
|
||||
goto end;
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (size > sizeof(INODE_REF) - 1 + ir->n) {
|
||||
|
@ -483,15 +313,12 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
b = find_next_item(fcb->Vcb, &tp, &next_tp, FALSE);
|
||||
if (b) {
|
||||
free_traverse_ptr(&tp);
|
||||
tp = next_tp;
|
||||
|
||||
b = tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_REF;
|
||||
}
|
||||
} while (b);
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
|
||||
if (fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF) {
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_INODE_EXTREF;
|
||||
|
@ -500,7 +327,7 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
Status = find_item(fcb->Vcb, fcb->subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
goto end;
|
||||
return Status;
|
||||
}
|
||||
|
||||
do {
|
||||
|
@ -523,11 +350,11 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
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);
|
||||
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);
|
||||
goto end;
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (size > sizeof(INODE_EXTREF) - 1 + ier->n) {
|
||||
|
@ -542,42 +369,39 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
|
||||
b = find_next_item(fcb->Vcb, &tp, &next_tp, FALSE);
|
||||
if (b) {
|
||||
free_traverse_ptr(&tp);
|
||||
tp = next_tp;
|
||||
|
||||
b = tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_EXTREF;
|
||||
}
|
||||
} while (b);
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
}
|
||||
|
||||
fcb->inode_item.st_mode |= __S_IFLNK;
|
||||
|
||||
Status = truncate_file(fcb, 0, &rollback);
|
||||
Status = truncate_file(fcb, 0, rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("truncate_file returned %08x\n", Status);
|
||||
goto end;
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = RtlUnicodeToUTF8N(NULL, 0, (PULONG)&target.Length, subname.Buffer, subname.Length);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUnicodeToUTF8N 3 failed with error %08x\n", Status);
|
||||
goto end;
|
||||
return Status;
|
||||
}
|
||||
|
||||
target.MaximumLength = target.Length;
|
||||
target.Buffer = ExAllocatePoolWithTag(PagedPool, target.MaximumLength, ALLOC_TAG);
|
||||
if (!target.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto end;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
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);
|
||||
goto end;
|
||||
ExFreePool(target.Buffer);
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < target.Length; i++) {
|
||||
|
@ -586,10 +410,427 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
|||
}
|
||||
|
||||
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(fcb->Vcb, Irp, offset, target.Buffer, (ULONG*)&target.Length, Irp->Flags & IRP_PAGING_IO, Irp->Flags & IRP_NOCACHE, 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);
|
||||
|
||||
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;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
void* buffer = Irp->AssociatedIrp.SystemBuffer;
|
||||
REPARSE_DATA_BUFFER* rdb = buffer;
|
||||
DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
fcb* fcb;
|
||||
ULONG tag;
|
||||
LIST_ENTRY rollback;
|
||||
|
||||
// FIXME - send notification if this succeeds? The attributes will have changed.
|
||||
// FIXME - check permissions
|
||||
|
||||
TRACE("(%p, %p)\n", DeviceObject, Irp);
|
||||
|
||||
InitializeListHead(&rollback);
|
||||
|
||||
if (!FileObject) {
|
||||
ERR("FileObject was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
fcb = FileObject->FsContext;
|
||||
|
||||
TRACE("%S\n", file_desc(FileObject));
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, TRUE);
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_SYMLINK) {
|
||||
WARN("tried to set a reparse point on an existing symlink\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// FIXME - fail if we already have the attribute FILE_ATTRIBUTE_REPARSE_POINT
|
||||
|
||||
// FIXME - die if not file or directory
|
||||
// FIXME - die if ADS
|
||||
|
||||
if (buflen < sizeof(ULONG)) {
|
||||
WARN("buffer was not long enough to hold tag\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
LARGE_INTEGER offset;
|
||||
char val[64];
|
||||
|
||||
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);
|
||||
goto end;
|
||||
}
|
||||
} else { // otherwise, store as file data
|
||||
Status = truncate_file(fcb, 0, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("truncate_file returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
offset.QuadPart = 0;
|
||||
|
||||
Status = write_file2(fcb->Vcb, Irp, offset, buffer, &buflen, Irp->Flags & IRP_PAGING_IO, Irp->Flags & IRP_NOCACHE, &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;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = consider_write(fcb->Vcb);
|
||||
|
||||
end:
|
||||
if (NT_SUCCESS(Status))
|
||||
clear_rollback(&rollback);
|
||||
else
|
||||
do_rollback(fcb->Vcb, &rollback);
|
||||
|
||||
release_tree_lock(fcb->Vcb, TRUE);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
REPARSE_DATA_BUFFER* rdb = Irp->AssociatedIrp.SystemBuffer;
|
||||
DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||||
NTSTATUS Status;
|
||||
fcb* fcb;
|
||||
ccb* ccb;
|
||||
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);
|
||||
|
||||
InitializeListHead(&rollback);
|
||||
|
||||
if (!FileObject) {
|
||||
ERR("FileObject was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
fcb = FileObject->FsContext;
|
||||
ccb = FileObject->FsContext2;
|
||||
fileref = ccb ? ccb->fileref : NULL;
|
||||
|
||||
TRACE("%S\n", file_desc(FileObject));
|
||||
|
||||
if (!fileref) {
|
||||
ERR("fileref was NULL\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) {
|
||||
ERR("buffer was too short\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (rdb->ReparseDataLength > 0) {
|
||||
WARN("rdb->ReparseDataLength was not zero\n");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, TRUE);
|
||||
|
||||
if (fcb->ads) {
|
||||
WARN("tried to delete reparse point on ADS\n");
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (fcb->type == BTRFS_TYPE_SYMLINK) {
|
||||
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;
|
||||
}
|
||||
} 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?
|
||||
|
||||
Status = truncate_file(fcb, 0, &rollback);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("truncate_file returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 (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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
|
||||
fcb->subvol->root_item.ctime = now;
|
||||
} else {
|
||||
ERR("unsupported file type %u\n", fcb->type);
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
Status = consider_write(fcb->Vcb);
|
||||
|
||||
|
|
|
@ -281,7 +281,7 @@ static void uid_to_sid(UINT32 uid, PSID* sid) {
|
|||
*sid = sh;
|
||||
}
|
||||
|
||||
static UINT32 sid_to_uid(PSID sid) {
|
||||
UINT32 sid_to_uid(PSID sid) {
|
||||
LIST_ENTRY* le;
|
||||
uid_map* um;
|
||||
sid_header* sh = sid;
|
||||
|
@ -646,7 +646,7 @@ static BOOL get_sd_from_xattr(fcb* fcb) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void fcb_get_sd(fcb* fcb) {
|
||||
void fcb_get_sd(fcb* fcb, struct _fcb* parent) {
|
||||
NTSTATUS Status;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
ULONG buflen;
|
||||
|
@ -694,10 +694,10 @@ void fcb_get_sd(fcb* fcb) {
|
|||
}
|
||||
// }
|
||||
|
||||
if (!fcb->par)
|
||||
if (!parent)
|
||||
acl = load_default_acl();
|
||||
else
|
||||
acl = inherit_acl(fcb->par->sd, fcb->type != BTRFS_TYPE_DIRECTORY);
|
||||
acl = inherit_acl(parent->sd, fcb->type != BTRFS_TYPE_DIRECTORY);
|
||||
|
||||
if (!acl) {
|
||||
ERR("out of memory\n");
|
||||
|
@ -758,9 +758,17 @@ end:
|
|||
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;
|
||||
ccb* ccb = FileObject->FsContext2;
|
||||
file_ref* fileref = ccb ? ccb->fileref : NULL;
|
||||
|
||||
if (fcb->ads)
|
||||
fcb = fcb->par;
|
||||
if (fcb->ads) {
|
||||
if (fileref && fileref->parent)
|
||||
fcb = fileref->parent->fcb;
|
||||
else {
|
||||
ERR("could not get parent fcb for stream\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// TRACE("buflen = %u, fcb->sdlen = %u\n", *buflen, fcb->sdlen);
|
||||
|
||||
|
@ -846,6 +854,8 @@ NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|||
static NTSTATUS STDCALL set_file_security(device_extension* Vcb, PFILE_OBJECT FileObject, SECURITY_DESCRIPTOR* sd, SECURITY_INFORMATION flags) {
|
||||
NTSTATUS Status;
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
ccb* ccb = FileObject->FsContext2;
|
||||
file_ref* fileref = ccb ? ccb->fileref : NULL;
|
||||
SECURITY_DESCRIPTOR* oldsd;
|
||||
INODE_ITEM* ii;
|
||||
KEY searchkey;
|
||||
|
@ -863,8 +873,14 @@ static NTSTATUS STDCALL set_file_security(device_extension* Vcb, PFILE_OBJECT Fi
|
|||
|
||||
acquire_tree_lock(Vcb, TRUE);
|
||||
|
||||
if (fcb->ads)
|
||||
fcb = fcb->par;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY) {
|
||||
Status = STATUS_ACCESS_DENIED;
|
||||
|
@ -895,12 +911,10 @@ static NTSTATUS STDCALL set_file_security(device_extension* Vcb, PFILE_OBJECT Fi
|
|||
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;
|
||||
free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
delete_tree_item(Vcb, &tp, &rollback);
|
||||
free_traverse_ptr(&tp);
|
||||
|
||||
KeQuerySystemTime(&time);
|
||||
win_time_to_unix(time, &now);
|
||||
|
@ -1009,12 +1023,12 @@ NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
|
|||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, ACCESS_STATE* as) {
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* fileref, ACCESS_STATE* as) {
|
||||
NTSTATUS Status;
|
||||
PSID owner;
|
||||
BOOLEAN defaulted;
|
||||
|
||||
Status = SeAssignSecurity(fcb->par ? fcb->par->sd : NULL, as->SecurityDescriptor, (void**)&fcb->sd, fcb->type == BTRFS_TYPE_DIRECTORY,
|
||||
Status = SeAssignSecurity((fileref && fileref->parent) ? fileref->parent->fcb->sd : NULL, as->SecurityDescriptor, (void**)&fcb->sd, fcb->type == BTRFS_TYPE_DIRECTORY,
|
||||
&as->SubjectSecurityContext, IoGetFileObjectGenericMapping(), PagedPool);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
|
|
|
@ -105,7 +105,7 @@ end:
|
|||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL read_tree(device_extension* Vcb, UINT64 addr, UINT8* buf) {
|
||||
NTSTATUS STDCALL read_tree(device_extension* Vcb, UINT64 addr, UINT8* buf) {
|
||||
CHUNK_ITEM* ci;
|
||||
CHUNK_ITEM_STRIPE* cis;
|
||||
read_tree_context* context;
|
||||
|
@ -277,6 +277,17 @@ static NTSTATUS STDCALL read_tree(device_extension* Vcb, UINT64 addr, UINT8* buf
|
|||
|
||||
// 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++) {
|
||||
|
@ -385,7 +396,6 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
RtlCopyMemory(&t->header, th, sizeof(tree_header));
|
||||
// t->address = addr;
|
||||
// t->level = th->level;
|
||||
t->refcount = 1;
|
||||
t->has_address = TRUE;
|
||||
t->Vcb = Vcb;
|
||||
t->parent = NULL;
|
||||
|
@ -395,13 +405,7 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
t->size = 0;
|
||||
t->new_address = 0;
|
||||
t->has_new_address = FALSE;
|
||||
#ifdef DEBUG_TREE_REFCOUNTS
|
||||
#ifdef DEBUG_LONG_MESSAGES
|
||||
_debug_message(func, file, line, "loaded tree %p (%llx)\n", t, addr);
|
||||
#else
|
||||
_debug_message(func, "loaded tree %p (%llx)\n", t, addr);
|
||||
#endif
|
||||
#endif
|
||||
t->write = FALSE;
|
||||
|
||||
c = get_chunk_from_address(Vcb, addr);
|
||||
|
||||
|
@ -494,85 +498,56 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
|
|||
}
|
||||
|
||||
static tree* free_tree2(tree* t, const char* func, const char* file, unsigned int line) {
|
||||
LONG rc;
|
||||
LIST_ENTRY* le;
|
||||
tree_data* td;
|
||||
tree* par;
|
||||
|
||||
#ifdef DEBUG_TREE_REFCOUNTS
|
||||
TRACE("(%p)\n", t);
|
||||
#endif
|
||||
root* r = t->root;
|
||||
|
||||
par = t->parent;
|
||||
|
||||
// if (par) ExAcquireResourceExclusiveLite(&par->nonpaged->load_tree_lock, TRUE);
|
||||
|
||||
rc = InterlockedDecrement(&t->refcount);
|
||||
if (r && r->treeholder.tree != t)
|
||||
r = NULL;
|
||||
|
||||
#ifdef DEBUG_TREE_REFCOUNTS
|
||||
#ifdef DEBUG_LONG_MESSAGES
|
||||
_debug_message(func, file, line, "tree %p: refcount decreased to %i (free_tree2)\n", t, rc);
|
||||
#else
|
||||
_debug_message(func, "tree %p: refcount decreased to %i (free_tree2)\n", t, rc);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (rc < 0) {
|
||||
ERR("error - negative refcount (%i)\n", rc);
|
||||
int3;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
root* r = t->root;
|
||||
if (r && r->treeholder.tree != t)
|
||||
r = NULL;
|
||||
|
||||
// if (r) {
|
||||
// FsRtlEnterFileSystem();
|
||||
// ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
|
||||
// }
|
||||
|
||||
if (par) {
|
||||
if (t->paritem)
|
||||
t->paritem->treeholder.tree = NULL;
|
||||
|
||||
if (par) {
|
||||
if (t->paritem)
|
||||
t->paritem->treeholder.tree = NULL;
|
||||
|
||||
// ExReleaseResourceLite(&par->nonpaged->load_tree_lock);
|
||||
}
|
||||
|
||||
if (t->parent)
|
||||
t->parent = free_tree2(t->parent, func, file, line);
|
||||
|
||||
// ExDeleteResourceLite(&t->nonpaged->load_tree_lock);
|
||||
|
||||
// ExFreePool(t->nonpaged);
|
||||
|
||||
while (!IsListEmpty(&t->itemlist)) {
|
||||
le = RemoveHeadList(&t->itemlist);
|
||||
td = CONTAINING_RECORD(le, tree_data, list_entry);
|
||||
|
||||
if (t->header.level == 0 && td->data)
|
||||
ExFreePool(td->data);
|
||||
|
||||
ExFreePool(td);
|
||||
}
|
||||
|
||||
InterlockedDecrement(&t->Vcb->open_trees);
|
||||
RemoveEntryList(&t->list_entry);
|
||||
|
||||
if (r) {
|
||||
r->treeholder.tree = NULL;
|
||||
// ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
|
||||
// FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
ExFreePool(t);
|
||||
|
||||
return NULL;
|
||||
} else {
|
||||
// if (par) ExReleaseResourceLite(&par->nonpaged->load_tree_lock);
|
||||
}
|
||||
|
||||
return t;
|
||||
// ExDeleteResourceLite(&t->nonpaged->load_tree_lock);
|
||||
|
||||
// ExFreePool(t->nonpaged);
|
||||
|
||||
while (!IsListEmpty(&t->itemlist)) {
|
||||
le = RemoveHeadList(&t->itemlist);
|
||||
td = CONTAINING_RECORD(le, tree_data, list_entry);
|
||||
|
||||
if (t->header.level == 0 && td->data)
|
||||
ExFreePool(td->data);
|
||||
|
||||
ExFreePool(td);
|
||||
}
|
||||
|
||||
InterlockedDecrement(&t->Vcb->open_trees);
|
||||
RemoveEntryList(&t->list_entry);
|
||||
|
||||
if (r) {
|
||||
r->treeholder.tree = NULL;
|
||||
// ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
|
||||
// FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
ExFreePool(t);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -623,11 +598,8 @@ NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r,
|
|||
th->tree->paritem = td;
|
||||
|
||||
ret = TRUE;
|
||||
} else {
|
||||
_increase_tree_rc(th->tree, func, file, line);
|
||||
|
||||
} else
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
// KeReleaseSpinLock(&thnp->spin_lock, irql);
|
||||
|
||||
|
@ -726,13 +698,11 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
|
|||
|
||||
oldtp.tree = t;
|
||||
oldtp.item = td;
|
||||
_increase_tree_rc(t, func, file, line);
|
||||
|
||||
while (_find_prev_item(Vcb, &oldtp, tp, TRUE, func, file, line)) {
|
||||
if (!tp->item->ignore)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
free_traverse_ptr(&oldtp);
|
||||
oldtp = *tp;
|
||||
}
|
||||
|
||||
|
@ -740,23 +710,18 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
|
|||
|
||||
oldtp.tree = t;
|
||||
oldtp.item = td;
|
||||
_increase_tree_rc(t, func, file, line);
|
||||
|
||||
while (_find_next_item(Vcb, &oldtp, tp, TRUE, func, file, line)) {
|
||||
if (!tp->item->ignore)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
free_traverse_ptr(&oldtp);
|
||||
oldtp = *tp;
|
||||
}
|
||||
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
} else {
|
||||
tp->tree = t;
|
||||
_increase_tree_rc(t, func, file, line);
|
||||
tp->item = td;
|
||||
|
||||
add_to_tree_cache(Vcb, t, FALSE);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -780,14 +745,8 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
|
|||
return Status;
|
||||
}
|
||||
|
||||
if (loaded)
|
||||
_increase_tree_rc(t, func, file, line);
|
||||
|
||||
Status = find_item_in_tree(Vcb, td->treeholder.tree, tp, searchkey, ignore, func, file, line);
|
||||
|
||||
td->treeholder.tree = _free_tree(td->treeholder.tree, func, file, line);
|
||||
TRACE("tree now %p\n", td->treeholder.tree);
|
||||
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
@ -799,18 +758,18 @@ NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, co
|
|||
|
||||
TRACE("(%p, %p, %p, %p)\n", Vcb, r, tp, searchkey);
|
||||
|
||||
Status = _do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, func, file, line);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("do_load_tree returned %08x\n", Status);
|
||||
return Status;
|
||||
if (!r->treeholder.tree) {
|
||||
Status = _do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, func, file, line);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("do_load_tree returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
Status = find_item_in_tree(Vcb, r->treeholder.tree, tp, searchkey, ignore, func, file, line);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("find_item_in_tree returned %08x\n", Status);
|
||||
}
|
||||
|
||||
_free_tree(r->treeholder.tree, func, file, line);
|
||||
|
||||
// #ifdef DEBUG_PARANOID
|
||||
// if (b && !ignore && tp->item->ignore) {
|
||||
|
@ -822,12 +781,6 @@ NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, co
|
|||
return Status;
|
||||
}
|
||||
|
||||
void STDCALL _free_traverse_ptr(traverse_ptr* tp, const char* func, const char* file, unsigned int line) {
|
||||
if (tp->tree) {
|
||||
tp->tree = free_tree2(tp->tree, func, file, 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) {
|
||||
tree* t;
|
||||
tree_data *td, *next;
|
||||
|
@ -843,7 +796,6 @@ BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, trav
|
|||
|
||||
if (next) {
|
||||
next_tp->tree = tp->tree;
|
||||
_increase_tree_rc(next_tp->tree, func, file, line);
|
||||
next_tp->item = next;
|
||||
|
||||
#ifdef DEBUG_PARANOID
|
||||
|
@ -879,9 +831,6 @@ BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, trav
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (loaded)
|
||||
_increase_tree_rc(t->parent, func, file, line);
|
||||
|
||||
t = td->treeholder.tree;
|
||||
|
||||
while (t->header.level != 0) {
|
||||
|
@ -906,21 +855,16 @@ BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, trav
|
|||
BOOL b;
|
||||
|
||||
while ((b = _find_next_item(Vcb, next_tp, &ntp2, TRUE, func, file, line))) {
|
||||
_free_traverse_ptr(next_tp, func, file, line);
|
||||
*next_tp = ntp2;
|
||||
|
||||
if (!next_tp->item->ignore)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!b) {
|
||||
_free_traverse_ptr(next_tp, func, file, line);
|
||||
if (!b)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
add_to_tree_cache(Vcb, t, FALSE);
|
||||
|
||||
#ifdef DEBUG_PARANOID
|
||||
if (!ignore && next_tp->item->ignore) {
|
||||
ERR("error - returning ignored item\n");
|
||||
|
@ -949,7 +893,6 @@ BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, trav
|
|||
// FIXME - support ignore flag
|
||||
if (prev_item(tp->tree, tp->item)) {
|
||||
prev_tp->tree = tp->tree;
|
||||
_increase_tree_rc(prev_tp->tree, func, file, line);
|
||||
prev_tp->item = prev_item(tp->tree, tp->item);
|
||||
|
||||
return TRUE;
|
||||
|
@ -974,9 +917,6 @@ BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, trav
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (loaded)
|
||||
_increase_tree_rc(t->parent, func, file, line);
|
||||
|
||||
t = td->treeholder.tree;
|
||||
|
||||
while (t->header.level != 0) {
|
||||
|
@ -993,8 +933,6 @@ BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, trav
|
|||
t = li->treeholder.tree;
|
||||
}
|
||||
|
||||
add_to_tree_cache(Vcb, t, FALSE);
|
||||
|
||||
prev_tp->tree = t;
|
||||
prev_tp->item = last_item(t);
|
||||
|
||||
|
@ -1013,74 +951,54 @@ BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, trav
|
|||
// ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
|
||||
// }
|
||||
|
||||
void STDCALL free_tree_cache(LIST_ENTRY* tc) {
|
||||
void free_trees_root(device_extension* Vcb, root* r) {
|
||||
LIST_ENTRY* le;
|
||||
tree_cache* tc2;
|
||||
root* r;
|
||||
|
||||
while (tc->Flink != tc) {
|
||||
le = tc->Flink;
|
||||
tc2 = CONTAINING_RECORD(le, tree_cache, list_entry);
|
||||
r = tc2->tree->root;
|
||||
UINT8 level;
|
||||
|
||||
for (level = 0; level <= 255; level++) {
|
||||
BOOL empty = TRUE;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
|
||||
le = Vcb->trees.Flink;
|
||||
|
||||
while (le != tc) {
|
||||
while (le != &Vcb->trees) {
|
||||
LIST_ENTRY* nextle = le->Flink;
|
||||
tc2 = CONTAINING_RECORD(le, tree_cache, list_entry);
|
||||
tree* t = CONTAINING_RECORD(le, tree, list_entry);
|
||||
|
||||
if (tc2->tree->root == r) {
|
||||
tree* nt;
|
||||
BOOL top = !tc2->tree->paritem;
|
||||
if (t->root == r && t->header.level == level) {
|
||||
BOOL top = !t->paritem;
|
||||
|
||||
nt = free_tree2(tc2->tree, funcname, __FILE__, __LINE__);
|
||||
if (top && !nt && r->treeholder.tree == tc2->tree)
|
||||
empty = FALSE;
|
||||
|
||||
free_tree2(t, funcname, __FILE__, __LINE__);
|
||||
if (top && r->treeholder.tree == t)
|
||||
r->treeholder.tree = NULL;
|
||||
|
||||
RemoveEntryList(&tc2->list_entry);
|
||||
ExFreePool(tc2);
|
||||
if (IsListEmpty(&Vcb->trees))
|
||||
return;
|
||||
}
|
||||
|
||||
le = nextle;
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
|
||||
if (empty)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void STDCALL add_to_tree_cache(device_extension* Vcb, tree* t, BOOL write) {
|
||||
LIST_ENTRY* le;
|
||||
tree_cache* tc2;
|
||||
|
||||
le = Vcb->tree_cache.Flink;
|
||||
while (le != &Vcb->tree_cache) {
|
||||
tc2 = CONTAINING_RECORD(le, tree_cache, list_entry);
|
||||
|
||||
if (tc2->tree == t) {
|
||||
if (write && !tc2->write) {
|
||||
Vcb->write_trees++;
|
||||
tc2->write = TRUE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
tc2 = ExAllocatePoolWithTag(PagedPool, sizeof(tree_cache), ALLOC_TAG);
|
||||
if (!tc2) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TRACE("adding %p to tree cache\n", t);
|
||||
|
||||
tc2->tree = t;
|
||||
tc2->write = write;
|
||||
increase_tree_rc(t);
|
||||
InsertTailList(&Vcb->tree_cache, &tc2->list_entry);
|
||||
void STDCALL free_trees(device_extension* Vcb) {
|
||||
tree* t;
|
||||
root* r;
|
||||
|
||||
// print_trees(tc);
|
||||
while (!IsListEmpty(&Vcb->trees)) {
|
||||
t = CONTAINING_RECORD(Vcb->trees.Flink, tree, list_entry);
|
||||
r = t->root;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&r->nonpaged->load_tree_lock, TRUE);
|
||||
|
||||
free_trees_root(Vcb, r);
|
||||
|
||||
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_rollback(LIST_ENTRY* rollback, enum rollback_type type, void* ptr) {
|
||||
|
@ -1152,7 +1070,6 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
|
|||
|
||||
if (cmp == 0 && !tp.item->ignore) { // FIXME - look for all items of the same key to make sure none are non-ignored
|
||||
ERR("error: key (%llx,%x,%llx) already present\n", obj_id, obj_type, offset);
|
||||
free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
|
@ -1161,7 +1078,6 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
|
|||
td = ExAllocatePoolWithTag(PagedPool, sizeof(tree_data), ALLOC_TAG);
|
||||
if (!td) {
|
||||
ERR("out of memory\n");
|
||||
free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1205,11 +1121,12 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
|
|||
// ERR("tree %p, num_items now %x\n", tp.tree, tp.tree->header.num_items);
|
||||
// ERR("size now %x\n", tp.tree->size);
|
||||
|
||||
add_to_tree_cache(Vcb, tp.tree, TRUE);
|
||||
if (!tp.tree->write) {
|
||||
tp.tree->write = TRUE;
|
||||
Vcb->write_trees++;
|
||||
}
|
||||
|
||||
if (!ptp)
|
||||
free_traverse_ptr(&tp);
|
||||
else
|
||||
if (ptp)
|
||||
*ptp = tp;
|
||||
|
||||
t = tp.tree;
|
||||
|
@ -1276,7 +1193,10 @@ void STDCALL delete_tree_item(device_extension* Vcb, traverse_ptr* tp, LIST_ENTR
|
|||
|
||||
tp->item->ignore = TRUE;
|
||||
|
||||
add_to_tree_cache(Vcb, tp->tree, TRUE);
|
||||
if (!tp->tree->write) {
|
||||
tp->tree->write = TRUE;
|
||||
Vcb->write_trees++;
|
||||
}
|
||||
|
||||
tp->tree->header.num_items--;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue