mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[BTRFS]
Import the WinBtrfs 0.2 driver from https://github.com/maharmstone/btrfs. Based on the initial work from Peter Hater, with various modification and patches sent upstream (yay, yet another collaboration :-)). This driver is in its earlies, so expect crashes, issues, and so on. We'll keep it updated to get rid of these issues. For now, it reads really well from a btrfs volume! CORE-10892 svn path=/trunk/; revision=71037
This commit is contained in:
parent
bd24dc4921
commit
d6b45221ca
22 changed files with 23580 additions and 0 deletions
|
@ -1,4 +1,5 @@
|
|||
|
||||
add_subdirectory(btrfs)
|
||||
add_subdirectory(cdfs)
|
||||
add_subdirectory(ext2)
|
||||
add_subdirectory(fastfat)
|
||||
|
|
37
reactos/drivers/filesystems/btrfs/CMakeLists.txt
Normal file
37
reactos/drivers/filesystems/btrfs/CMakeLists.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
include_directories(${REACTOS_SOURCE_DIR}/include/reactos/drivers
|
||||
inc)
|
||||
|
||||
list(APPEND SOURCE
|
||||
btrfs.c
|
||||
cache.c
|
||||
crc32c.c
|
||||
create.c
|
||||
dirctrl.c
|
||||
fastio.c
|
||||
fileinfo.c
|
||||
flushthread.c
|
||||
fsctl.c
|
||||
read.c
|
||||
reparse.c
|
||||
search.c
|
||||
security.c
|
||||
treefuncs.c
|
||||
write.c
|
||||
btrfs_drv.h)
|
||||
|
||||
add_library(btrfs SHARED ${SOURCE} btrfs.rc)
|
||||
|
||||
if(NOT MSVC)
|
||||
replace_compile_flags("-Werror" " ")
|
||||
else()
|
||||
replace_compile_flags("/we\"4189\"" " ")
|
||||
endif()
|
||||
|
||||
add_definitions(-D__KERNEL__)
|
||||
set_module_type(btrfs kernelmodedriver)
|
||||
target_link_libraries(btrfs ntoskrnl_vista)
|
||||
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)
|
||||
|
4363
reactos/drivers/filesystems/btrfs/btrfs.c
Normal file
4363
reactos/drivers/filesystems/btrfs/btrfs.c
Normal file
File diff suppressed because it is too large
Load diff
403
reactos/drivers/filesystems/btrfs/btrfs.h
Normal file
403
reactos/drivers/filesystems/btrfs/btrfs.h
Normal file
|
@ -0,0 +1,403 @@
|
|||
/* btrfs.h
|
||||
* Generic btrfs header file. Thanks to whoever it was who wrote
|
||||
* https://btrfs.wiki.kernel.org/index.php/On-disk_Format - you saved me a lot of time!
|
||||
*
|
||||
* I release this file, and this file only, into the public domain - do whatever
|
||||
* you want with it. You don't have to, but I'd appreciate if you let me know if you
|
||||
* use it anything cool - mark@harmstone.com. */
|
||||
|
||||
#ifndef BTRFS_H_DEFINED
|
||||
#define BTRFS_H_DEFINED
|
||||
|
||||
static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4000000000000, 0 };
|
||||
|
||||
#define BTRFS_MAGIC 0x4d5f53665248425f
|
||||
#define MAX_LABEL_SIZE 0x100
|
||||
#define SUBVOL_ROOT_INODE 0x100
|
||||
|
||||
#define TYPE_INODE_ITEM 0x01
|
||||
#define TYPE_INODE_REF 0x0C
|
||||
#define TYPE_INODE_EXTREF 0x0D
|
||||
#define TYPE_XATTR_ITEM 0x18
|
||||
#define TYPE_DIR_ITEM 0x54
|
||||
#define TYPE_DIR_INDEX 0x60
|
||||
#define TYPE_EXTENT_DATA 0x6C
|
||||
#define TYPE_EXTENT_CSUM 0x80
|
||||
#define TYPE_ROOT_ITEM 0x84
|
||||
#define TYPE_ROOT_BACKREF 0x90
|
||||
#define TYPE_ROOT_REF 0x9C
|
||||
#define TYPE_EXTENT_ITEM 0xA8
|
||||
#define TYPE_METADATA_ITEM 0xA9
|
||||
#define TYPE_TREE_BLOCK_REF 0xB0
|
||||
#define TYPE_EXTENT_DATA_REF 0xB2
|
||||
#define TYPE_EXTENT_REF_V0 0xB4
|
||||
#define TYPE_SHARED_BLOCK_REF 0xB6
|
||||
#define TYPE_SHARED_DATA_REF 0xB8
|
||||
#define TYPE_BLOCK_GROUP_ITEM 0xC0
|
||||
#define TYPE_DEV_EXTENT 0xCC
|
||||
#define TYPE_DEV_ITEM 0xD8
|
||||
#define TYPE_CHUNK_ITEM 0xE4
|
||||
|
||||
#define BTRFS_ROOT_ROOT 1
|
||||
#define BTRFS_ROOT_EXTENT 2
|
||||
#define BTRFS_ROOT_CHUNK 3
|
||||
#define BTRFS_ROOT_DEVTREE 4
|
||||
#define BTRFS_ROOT_FSTREE 5
|
||||
#define BTRFS_ROOT_CHECKSUM 7
|
||||
|
||||
#define BTRFS_COMPRESSION_NONE 0
|
||||
#define BTRFS_COMPRESSION_ZLIB 1
|
||||
#define BTRFS_COMPRESSION_LZO 2
|
||||
|
||||
#define BTRFS_ENCRYPTION_NONE 0
|
||||
|
||||
#define BTRFS_ENCODING_NONE 0
|
||||
|
||||
#define EXTENT_TYPE_INLINE 0
|
||||
#define EXTENT_TYPE_REGULAR 1
|
||||
#define EXTENT_TYPE_PREALLOC 2
|
||||
|
||||
#define BLOCK_FLAG_DATA 0x001
|
||||
#define BLOCK_FLAG_SYSTEM 0x002
|
||||
#define BLOCK_FLAG_METADATA 0x004
|
||||
#define BLOCK_FLAG_RAID0 0x008
|
||||
#define BLOCK_FLAG_RAID1 0x010
|
||||
#define BLOCK_FLAG_DUPLICATE 0x020
|
||||
#define BLOCK_FLAG_RAID10 0x040
|
||||
#define BLOCK_FLAG_RAID5 0x080
|
||||
#define BLOCK_FLAG_RAID6 0x100
|
||||
|
||||
#define FREE_SPACE_CACHE_ID 0xFFFFFFFFFFFFFFF5
|
||||
#define EXTENT_CSUM_ID 0xFFFFFFFFFFFFFFF6
|
||||
|
||||
#define BTRFS_INODE_NODATASUM 0x001
|
||||
#define BTRFS_INODE_NODATACOW 0x002
|
||||
#define BTRFS_INODE_READONLY 0x004
|
||||
#define BTRFS_INODE_NOCOMPRESS 0x008
|
||||
#define BTRFS_INODE_PREALLOC 0x010
|
||||
#define BTRFS_INODE_SYNC 0x020
|
||||
#define BTRFS_INODE_IMMUTABLE 0x040
|
||||
#define BTRFS_INODE_APPEND 0x080
|
||||
#define BTRFS_INODE_NODUMP 0x100
|
||||
#define BTRFS_INODE_NOATIME 0x200
|
||||
#define BTRFS_INODE_DIRSYNC 0x400
|
||||
#define BTRFS_INODE_COMPRESS 0x800
|
||||
|
||||
#define BTRFS_SUBVOL_READONLY 0x1
|
||||
|
||||
#define BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE 0x1
|
||||
|
||||
#define BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF 0x0001
|
||||
#define BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL 0x0002
|
||||
#define BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS 0x0004
|
||||
#define BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO 0x0008
|
||||
#define BTRFS_INCOMPAT_FLAGS_COMPRESS_LZOV2 0x0010
|
||||
#define BTRFS_INCOMPAT_FLAGS_BIG_METADATA 0x0020
|
||||
#define BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF 0x0040
|
||||
#define BTRFS_INCOMPAT_FLAGS_RAID56 0x0080
|
||||
#define BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA 0x0100
|
||||
#define BTRFS_INCOMPAT_FLAGS_NO_HOLES 0x0200
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
UINT8 uuid[16];
|
||||
} BTRFS_UUID;
|
||||
|
||||
typedef struct {
|
||||
UINT64 obj_id;
|
||||
UINT8 obj_type;
|
||||
UINT64 offset;
|
||||
} KEY;
|
||||
|
||||
#define HEADER_FLAG_MIXED_BACKREF 0x100000000000000
|
||||
#define HEADER_FLAG_SHARED_BACKREF 0x000000000000002
|
||||
|
||||
typedef struct {
|
||||
UINT8 csum[32];
|
||||
BTRFS_UUID fs_uuid;
|
||||
UINT64 address;
|
||||
UINT64 flags;
|
||||
BTRFS_UUID chunk_tree_uuid;
|
||||
UINT64 generation;
|
||||
UINT64 tree_id;
|
||||
UINT32 num_items;
|
||||
UINT8 level;
|
||||
} tree_header;
|
||||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
UINT32 offset;
|
||||
UINT32 size;
|
||||
} leaf_node;
|
||||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
UINT64 address;
|
||||
UINT64 generation;
|
||||
} internal_node;
|
||||
|
||||
typedef struct {
|
||||
UINT64 dev_id;
|
||||
UINT64 num_bytes;
|
||||
UINT64 bytes_used;
|
||||
UINT32 optimal_io_align;
|
||||
UINT32 optimal_io_width;
|
||||
UINT32 minimal_io_size;
|
||||
UINT64 type;
|
||||
UINT64 generation;
|
||||
UINT64 start_offset;
|
||||
UINT32 dev_group;
|
||||
UINT8 seek_speed;
|
||||
UINT8 bandwidth;
|
||||
BTRFS_UUID device_uuid;
|
||||
BTRFS_UUID fs_uuid;
|
||||
} DEV_ITEM;
|
||||
|
||||
#define SYS_CHUNK_ARRAY_SIZE 0x800
|
||||
|
||||
typedef struct {
|
||||
UINT8 checksum[32];
|
||||
BTRFS_UUID uuid;
|
||||
UINT64 sb_phys_addr;
|
||||
UINT64 flags;
|
||||
UINT64 magic;
|
||||
UINT64 generation;
|
||||
UINT64 root_tree_addr;
|
||||
UINT64 chunk_tree_addr;
|
||||
UINT64 log_tree_addr;
|
||||
UINT64 log_root_transid;
|
||||
UINT64 total_bytes;
|
||||
UINT64 bytes_used;
|
||||
UINT64 root_dir_objectid;
|
||||
UINT64 num_devices;
|
||||
UINT32 sector_size;
|
||||
UINT32 node_size;
|
||||
UINT32 leaf_size;
|
||||
UINT32 stripe_size;
|
||||
UINT32 n;
|
||||
UINT64 chunk_root_generation;
|
||||
UINT64 compat_flags;
|
||||
UINT64 compat_ro_flags;
|
||||
UINT64 incompat_flags;
|
||||
UINT16 csum_type;
|
||||
UINT8 root_level;
|
||||
UINT8 chunk_root_level;
|
||||
UINT8 log_root_level;
|
||||
DEV_ITEM dev_item;
|
||||
char label[MAX_LABEL_SIZE];
|
||||
UINT64 cache_generation;
|
||||
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;
|
||||
|
||||
#define BTRFS_TYPE_UNKNOWN 0
|
||||
#define BTRFS_TYPE_FILE 1
|
||||
#define BTRFS_TYPE_DIRECTORY 2
|
||||
#define BTRFS_TYPE_CHARDEV 3
|
||||
#define BTRFS_TYPE_BLOCKDEV 4
|
||||
#define BTRFS_TYPE_FIFO 5
|
||||
#define BTRFS_TYPE_SOCKET 6
|
||||
#define BTRFS_TYPE_SYMLINK 7
|
||||
#define BTRFS_TYPE_EA 8
|
||||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
UINT64 transid;
|
||||
UINT16 m;
|
||||
UINT16 n;
|
||||
UINT8 type;
|
||||
char name[1];
|
||||
} DIR_ITEM;
|
||||
|
||||
typedef struct {
|
||||
UINT64 seconds;
|
||||
UINT32 nanoseconds;
|
||||
} BTRFS_TIME;
|
||||
|
||||
typedef struct {
|
||||
UINT64 generation;
|
||||
UINT64 transid;
|
||||
UINT64 st_size;
|
||||
UINT64 st_blocks;
|
||||
UINT64 block_group;
|
||||
UINT32 st_nlink;
|
||||
UINT32 st_uid;
|
||||
UINT32 st_gid;
|
||||
UINT32 st_mode;
|
||||
UINT64 st_rdev;
|
||||
UINT64 flags;
|
||||
UINT64 sequence;
|
||||
UINT8 reserved[32];
|
||||
BTRFS_TIME st_atime;
|
||||
BTRFS_TIME st_ctime;
|
||||
BTRFS_TIME st_mtime;
|
||||
BTRFS_TIME otime;
|
||||
} INODE_ITEM;
|
||||
|
||||
typedef struct {
|
||||
INODE_ITEM inode;
|
||||
UINT64 generation;
|
||||
UINT64 objid;
|
||||
UINT64 block_number;
|
||||
UINT64 byte_limit;
|
||||
UINT64 bytes_used;
|
||||
UINT64 last_snapshot_generation;
|
||||
UINT64 flags;
|
||||
UINT32 num_references;
|
||||
KEY drop_progress;
|
||||
UINT8 drop_level;
|
||||
UINT8 root_level;
|
||||
UINT64 generation2;
|
||||
BTRFS_UUID uuid;
|
||||
BTRFS_UUID parent_uuid;
|
||||
BTRFS_UUID received_uuid;
|
||||
UINT64 ctransid;
|
||||
UINT64 otransid;
|
||||
UINT64 stransid;
|
||||
UINT64 rtransid;
|
||||
BTRFS_TIME ctime;
|
||||
BTRFS_TIME otime;
|
||||
BTRFS_TIME stime;
|
||||
BTRFS_TIME rtime;
|
||||
UINT64 reserved[8];
|
||||
} ROOT_ITEM;
|
||||
|
||||
typedef struct {
|
||||
UINT64 size;
|
||||
UINT64 root_id;
|
||||
UINT64 stripe_length;
|
||||
UINT64 type;
|
||||
UINT32 opt_io_alignment;
|
||||
UINT32 opt_io_width;
|
||||
UINT32 sector_size;
|
||||
UINT16 num_stripes;
|
||||
UINT16 sub_stripes;
|
||||
} CHUNK_ITEM;
|
||||
|
||||
typedef struct {
|
||||
UINT64 dev_id;
|
||||
UINT64 offset;
|
||||
BTRFS_UUID dev_uuid;
|
||||
} CHUNK_ITEM_STRIPE;
|
||||
|
||||
typedef struct {
|
||||
UINT64 generation;
|
||||
UINT64 decoded_size;
|
||||
UINT8 compression;
|
||||
UINT8 encryption;
|
||||
UINT16 encoding;
|
||||
UINT8 type;
|
||||
UINT8 data[1];
|
||||
} EXTENT_DATA;
|
||||
|
||||
typedef struct {
|
||||
UINT64 address;
|
||||
UINT64 size;
|
||||
UINT64 offset;
|
||||
UINT64 num_bytes;
|
||||
} EXTENT_DATA2;
|
||||
|
||||
typedef struct {
|
||||
UINT64 index;
|
||||
UINT16 n;
|
||||
char name[1];
|
||||
} INODE_REF;
|
||||
|
||||
typedef struct {
|
||||
UINT64 dir;
|
||||
UINT64 index;
|
||||
UINT16 n;
|
||||
char name[1];
|
||||
} INODE_EXTREF;
|
||||
|
||||
#define EXTENT_ITEM_DATA 0x001
|
||||
#define EXTENT_ITEM_TREE_BLOCK 0x002
|
||||
#define EXTENT_ITEM_SHARED_BACKREFS 0x100
|
||||
|
||||
typedef struct {
|
||||
UINT64 refcount;
|
||||
UINT64 generation;
|
||||
UINT64 flags;
|
||||
} EXTENT_ITEM;
|
||||
|
||||
typedef struct {
|
||||
UINT32 refcount;
|
||||
} EXTENT_ITEM_V0;
|
||||
|
||||
typedef struct {
|
||||
EXTENT_ITEM extent_item;
|
||||
KEY firstitem;
|
||||
UINT8 level;
|
||||
} EXTENT_ITEM_TREE;
|
||||
|
||||
typedef struct {
|
||||
UINT64 offset;
|
||||
} TREE_BLOCK_REF;
|
||||
|
||||
typedef struct {
|
||||
UINT64 root;
|
||||
UINT64 objid;
|
||||
UINT64 offset;
|
||||
UINT32 count;
|
||||
} EXTENT_DATA_REF;
|
||||
|
||||
typedef struct {
|
||||
UINT64 used;
|
||||
UINT64 chunk_tree;
|
||||
UINT64 flags;
|
||||
} BLOCK_GROUP_ITEM;
|
||||
|
||||
typedef struct {
|
||||
UINT64 root;
|
||||
UINT64 gen;
|
||||
UINT64 objid;
|
||||
UINT64 count;
|
||||
} EXTENT_REF_V0;
|
||||
|
||||
typedef struct {
|
||||
UINT64 offset;
|
||||
} SHARED_BLOCK_REF;
|
||||
|
||||
typedef struct {
|
||||
UINT64 offset;
|
||||
UINT32 count;
|
||||
} SHARED_DATA_REF;
|
||||
|
||||
#define FREE_SPACE_EXTENT 1
|
||||
#define FREE_SPACE_BITMAP 2
|
||||
|
||||
typedef struct {
|
||||
UINT64 offset;
|
||||
UINT64 size;
|
||||
UINT8 type;
|
||||
} FREE_SPACE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
UINT64 generation;
|
||||
UINT64 num_entries;
|
||||
UINT64 num_bitmaps;
|
||||
} FREE_SPACE_ITEM;
|
||||
|
||||
typedef struct {
|
||||
UINT64 dir;
|
||||
UINT64 index;
|
||||
UINT16 n;
|
||||
char name[1];
|
||||
} ROOT_REF;
|
||||
|
||||
typedef struct {
|
||||
UINT64 chunktree;
|
||||
UINT64 objid;
|
||||
UINT64 address;
|
||||
UINT64 length;
|
||||
BTRFS_UUID chunktree_uuid;
|
||||
} DEV_EXTENT;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
101
reactos/drivers/filesystems/btrfs/btrfs.rc
Normal file
101
reactos/drivers/filesystems/btrfs/btrfs.rc
Normal file
|
@ -0,0 +1,101 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.K.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x1L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "080904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "WinBtrfs"
|
||||
VALUE "FileVersion", "0.2"
|
||||
VALUE "InternalName", "btrfs"
|
||||
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016"
|
||||
VALUE "OriginalFilename", "btrfs.sys"
|
||||
VALUE "ProductName", "WinBtrfs"
|
||||
VALUE "ProductVersion", "0.2"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x809, 1200
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (U.K.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
644
reactos/drivers/filesystems/btrfs/btrfs_drv.h
Normal file
644
reactos/drivers/filesystems/btrfs/btrfs_drv.h
Normal file
|
@ -0,0 +1,644 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef BTRFS_DRV_H_DEFINED
|
||||
#define BTRFS_DRV_H_DEFINED
|
||||
|
||||
#ifndef __REACTOS__
|
||||
#undef _WIN32_WINNT
|
||||
#undef NTDDI_VERSION
|
||||
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#define NTDDI_VERSION 0x06010000 // Win 7
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif /* __REACTOS__ */
|
||||
|
||||
#include <ntifs.h>
|
||||
#include <ntddk.h>
|
||||
#ifdef __REACTOS__
|
||||
#include <ntdddisk.h>
|
||||
#endif /* __REACTOS__ */
|
||||
#include <mountmgr.h>
|
||||
#ifdef __REACTOS__
|
||||
#include <rtlfuncs.h>
|
||||
#include <iotypes.h>
|
||||
#endif /* __REACTOS__ */
|
||||
//#include <windows.h>
|
||||
#include <windef.h>
|
||||
#include <wdm.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include "btrfs.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
// #define DEBUG_TREE_REFCOUNTS
|
||||
// #define DEBUG_FCB_REFCOUNTS
|
||||
// #define DEBUG_LONG_MESSAGES
|
||||
#define DEBUG_PARANOID
|
||||
#endif
|
||||
|
||||
#define BTRFS_NODE_TYPE_CCB 0x2295
|
||||
#define BTRFS_NODE_TYPE_FCB 0x2296
|
||||
|
||||
#define ALLOC_TAG 0x7442484D //'MHBt'
|
||||
|
||||
#define STDCALL __stdcall
|
||||
|
||||
#define UID_NOBODY 65534
|
||||
#define GID_NOBODY 65534
|
||||
|
||||
#define EA_NTACL "security.NTACL"
|
||||
#define EA_NTACL_HASH 0x45922146
|
||||
|
||||
#define EA_DOSATTRIB "user.DOSATTRIB"
|
||||
#define EA_DOSATTRIB_HASH 0x914f9939
|
||||
|
||||
#define READ_AHEAD_GRANULARITY 0x10000 // 64 KB
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define try __try
|
||||
#define except __except
|
||||
#define finally __finally
|
||||
#else
|
||||
#define try if (1)
|
||||
#define except(x) if (0 && (x))
|
||||
#define finally if (1)
|
||||
#endif
|
||||
|
||||
// #pragma pack(push, 1)
|
||||
|
||||
struct device_extension;
|
||||
|
||||
typedef struct {
|
||||
PDEVICE_OBJECT devobj;
|
||||
BTRFS_UUID fsuuid;
|
||||
BTRFS_UUID devuuid;
|
||||
UINT64 devnum;
|
||||
UNICODE_STRING devpath;
|
||||
BOOL processed;
|
||||
LIST_ENTRY list_entry;
|
||||
} volume;
|
||||
|
||||
typedef struct _fcb_nonpaged {
|
||||
FAST_MUTEX HeaderMutex;
|
||||
SECTION_OBJECT_POINTERS segment_object;
|
||||
ERESOURCE resource;
|
||||
ERESOURCE paging_resource;
|
||||
} fcb_nonpaged;
|
||||
|
||||
struct _root;
|
||||
|
||||
typedef struct _fcb {
|
||||
FSRTL_ADVANCED_FCB_HEADER Header;
|
||||
struct _fcb_nonpaged* nonpaged;
|
||||
LONG refcount;
|
||||
LONG open_count;
|
||||
UNICODE_STRING filepart;
|
||||
ANSI_STRING utf8;
|
||||
struct _device_extension* Vcb;
|
||||
struct _fcb* par;
|
||||
struct _fcb* prev;
|
||||
struct _fcb* next;
|
||||
struct _root* subvol;
|
||||
LIST_ENTRY children;
|
||||
UINT64 inode;
|
||||
UINT8 type;
|
||||
BOOL delete_on_close;
|
||||
INODE_ITEM inode_item;
|
||||
UNICODE_STRING full_filename;
|
||||
ULONG name_offset;
|
||||
SECURITY_DESCRIPTOR* sd;
|
||||
FILE_LOCK lock;
|
||||
BOOL deleted;
|
||||
PKTHREAD lazy_writer_thread;
|
||||
ULONG atts;
|
||||
SHARE_ACCESS share_access;
|
||||
|
||||
BOOL ads;
|
||||
UINT32 adssize;
|
||||
UINT32 adshash;
|
||||
ANSI_STRING adsxattr;
|
||||
|
||||
LIST_ENTRY list_entry;
|
||||
} fcb;
|
||||
|
||||
typedef struct _ccb {
|
||||
USHORT NodeType;
|
||||
CSHORT NodeSize;
|
||||
ULONG disposition;
|
||||
ULONG options;
|
||||
UINT64 query_dir_offset;
|
||||
// char* query_string;
|
||||
UNICODE_STRING query_string;
|
||||
BOOL has_wildcard;
|
||||
BOOL specific_file;
|
||||
} ccb;
|
||||
|
||||
// typedef struct _log_to_phys {
|
||||
// UINT64 address;
|
||||
// UINT64 size;
|
||||
// UINT64 physaddr;
|
||||
// UINT32 sector_size;
|
||||
// struct _log_to_phys* next;
|
||||
// } log_to_phys;
|
||||
|
||||
struct _device_extension;
|
||||
|
||||
// enum tree_holder_status {
|
||||
// tree_holder_unloaded,
|
||||
// tree_holder_loading,
|
||||
// tree_holder_loaded,
|
||||
// tree_holder_unloading
|
||||
// };
|
||||
|
||||
// typedef struct {
|
||||
// enum tree_holder_status status;
|
||||
// KSPIN_LOCK spin_lock;
|
||||
// ERESOURCE lock;
|
||||
// } tree_holder_nonpaged;
|
||||
|
||||
typedef struct {
|
||||
UINT64 address;
|
||||
UINT64 generation;
|
||||
struct _tree* tree;
|
||||
// tree_holder_nonpaged* nonpaged;
|
||||
} tree_holder;
|
||||
|
||||
typedef struct _tree_data {
|
||||
KEY key;
|
||||
LIST_ENTRY list_entry;
|
||||
BOOL ignore;
|
||||
BOOL inserted;
|
||||
|
||||
union {
|
||||
tree_holder treeholder;
|
||||
|
||||
struct {
|
||||
UINT32 size;
|
||||
UINT8* data;
|
||||
};
|
||||
};
|
||||
} tree_data;
|
||||
|
||||
// typedef struct _tree_nonpaged {
|
||||
// ERESOURCE load_tree_lock;
|
||||
// } tree_nonpaged;
|
||||
|
||||
typedef struct _tree {
|
||||
// UINT64 address;
|
||||
// UINT8 level;
|
||||
tree_header header;
|
||||
LONG refcount;
|
||||
UINT32 size;
|
||||
struct _device_extension* Vcb;
|
||||
struct _tree* parent;
|
||||
tree_data* paritem;
|
||||
struct _root* root;
|
||||
// tree_nonpaged* nonpaged;
|
||||
LIST_ENTRY itemlist;
|
||||
LIST_ENTRY list_entry;
|
||||
UINT64 new_address;
|
||||
UINT64 flags;
|
||||
} tree;
|
||||
|
||||
typedef struct {
|
||||
// KSPIN_LOCK load_tree_lock;
|
||||
ERESOURCE load_tree_lock;
|
||||
} root_nonpaged;
|
||||
|
||||
typedef struct _root {
|
||||
UINT64 id;
|
||||
tree_holder treeholder;
|
||||
root_nonpaged* nonpaged;
|
||||
UINT64 lastinode;
|
||||
ROOT_ITEM root_item;
|
||||
|
||||
struct _root* prev;
|
||||
struct _root* next;
|
||||
} root;
|
||||
|
||||
typedef struct {
|
||||
tree* tree;
|
||||
tree_data* item;
|
||||
} traverse_ptr;
|
||||
|
||||
typedef struct _tree_cache {
|
||||
tree* tree;
|
||||
BOOL write;
|
||||
LIST_ENTRY list_entry;
|
||||
} tree_cache;
|
||||
|
||||
typedef struct _root_cache {
|
||||
root* root;
|
||||
struct _root_cache* next;
|
||||
} root_cache;
|
||||
|
||||
#define SPACE_TYPE_FREE 0
|
||||
#define SPACE_TYPE_USED 1
|
||||
#define SPACE_TYPE_DELETING 2
|
||||
#define SPACE_TYPE_WRITING 3
|
||||
|
||||
typedef struct {
|
||||
UINT64 offset;
|
||||
UINT64 size;
|
||||
UINT8 type;
|
||||
LIST_ENTRY list_entry;
|
||||
} space;
|
||||
|
||||
typedef struct {
|
||||
UINT64 address;
|
||||
UINT64 size;
|
||||
BOOL provisional;
|
||||
LIST_ENTRY listentry;
|
||||
} disk_hole;
|
||||
|
||||
typedef struct {
|
||||
PDEVICE_OBJECT devobj;
|
||||
DEV_ITEM devitem;
|
||||
LIST_ENTRY disk_holes;
|
||||
} device;
|
||||
|
||||
typedef struct {
|
||||
CHUNK_ITEM* chunk_item;
|
||||
UINT32 size;
|
||||
UINT64 offset;
|
||||
UINT64 used;
|
||||
UINT32 oldused;
|
||||
BOOL space_changed;
|
||||
device** devices;
|
||||
LIST_ENTRY space;
|
||||
LIST_ENTRY list_entry;
|
||||
} chunk;
|
||||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
void* data;
|
||||
USHORT size;
|
||||
LIST_ENTRY list_entry;
|
||||
} sys_chunk;
|
||||
|
||||
typedef struct _device_extension {
|
||||
device* devices;
|
||||
// DISK_GEOMETRY geometry;
|
||||
UINT64 length;
|
||||
superblock superblock;
|
||||
// WCHAR label[MAX_LABEL_SIZE];
|
||||
BOOL readonly;
|
||||
fcb* fcbs;
|
||||
fcb* volume_fcb;
|
||||
fcb* root_fcb;
|
||||
ERESOURCE DirResource;
|
||||
KSPIN_LOCK FcbListLock;
|
||||
ERESOURCE fcb_lock;
|
||||
ERESOURCE load_lock;
|
||||
ERESOURCE tree_lock;
|
||||
PNOTIFY_SYNC NotifySync;
|
||||
LIST_ENTRY DirNotifyList;
|
||||
LONG tree_lock_counter;
|
||||
LONG open_trees;
|
||||
ULONG write_trees;
|
||||
// ERESOURCE LogToPhysLock;
|
||||
// UINT64 chunk_root_phys_addr;
|
||||
UINT64 root_tree_phys_addr;
|
||||
// log_to_phys* log_to_phys;
|
||||
root* roots;
|
||||
root* chunk_root;
|
||||
root* root_root;
|
||||
root* extent_root;
|
||||
root* checksum_root;
|
||||
root* dev_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;
|
||||
|
||||
typedef struct {
|
||||
LIST_ENTRY listentry;
|
||||
PSID sid;
|
||||
UINT32 uid;
|
||||
} uid_map;
|
||||
|
||||
// #pragma pack(pop)
|
||||
|
||||
static __inline void init_tree_holder(tree_holder* th) {
|
||||
// th->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_holder_nonpaged), ALLOC_TAG);
|
||||
// KeInitializeSpinLock(&th->nonpaged->spin_lock);
|
||||
// ExInitializeResourceLite(&th->nonpaged->lock); // FIXME - delete this later
|
||||
}
|
||||
|
||||
static __inline void* map_user_buffer(PIRP Irp) {
|
||||
if (!Irp->MdlAddress) {
|
||||
return Irp->UserBuffer;
|
||||
} else {
|
||||
return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline UINT64 unix_time_to_win(BTRFS_TIME* t) {
|
||||
return (t->seconds * 10000000) + (t->nanoseconds / 100) + 116444736000000000;
|
||||
}
|
||||
|
||||
static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) {
|
||||
ULONGLONG l = t.QuadPart - 116444736000000000;
|
||||
|
||||
out->seconds = l / 10000000;
|
||||
out->nanoseconds = (l % 10000000) * 100;
|
||||
}
|
||||
|
||||
// in btrfs.c
|
||||
device* find_device_from_uuid(device_extension* Vcb, BTRFS_UUID* uuid);
|
||||
ULONG sector_align( ULONG NumberToBeAligned, ULONG Alignment );
|
||||
int keycmp(const KEY* key1, const KEY* key2);
|
||||
ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa);
|
||||
BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen);
|
||||
NTSTATUS STDCALL set_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8* data, UINT16 datalen, LIST_ENTRY* rollback);
|
||||
BOOL STDCALL delete_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, LIST_ENTRY* rollback);
|
||||
void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line);
|
||||
BOOL STDCALL get_last_inode(device_extension* Vcb, root* r);
|
||||
NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, LIST_ENTRY* rollback);
|
||||
NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, LIST_ENTRY* rollback);
|
||||
UINT64 find_next_dir_index(device_extension* Vcb, root* subvol, UINT64 inode);
|
||||
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, UINT64* index, LIST_ENTRY* rollback);
|
||||
NTSTATUS delete_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback);
|
||||
fcb* create_fcb();
|
||||
void protect_superblocks(device_extension* Vcb, chunk* c);
|
||||
BOOL is_top_level(PIRP Irp);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define funcname __FUNCTION__
|
||||
#else
|
||||
#define funcname __func__
|
||||
#endif
|
||||
|
||||
// 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__)
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#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__)
|
||||
|
||||
void STDCALL _debug_message(const char* func, UINT8 priority, 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__)
|
||||
|
||||
void STDCALL _debug_message(const char* func, UINT8 priority, char* s, ...);
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define TRACE(s, ...)
|
||||
#define WARN(s, ...)
|
||||
#ifndef __REACTOS__
|
||||
#define FIXME(s, ...) DbgPrint("Btrfs FIXME : " funcname " : " s, ##__VA_ARGS__)
|
||||
#define ERR(s, ...) DbgPrint("Btrfs ERR : " funcname " : " s, ##__VA_ARGS__)
|
||||
#else
|
||||
#define FIXME(s, ...) DbgPrint("Btrfs FIXME : %s : " s, funcname, ##__VA_ARGS__)
|
||||
#define ERR(s, ...) DbgPrint("Btrfs ERR : %s : " s, funcname, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// in fastio.c
|
||||
void STDCALL init_fast_io_dispatch(FAST_IO_DISPATCH** fiod);
|
||||
|
||||
// in crc32c.c
|
||||
UINT32 STDCALL calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen);
|
||||
|
||||
// in treefuncs.c
|
||||
NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, const char* func, const char* file, unsigned int line);
|
||||
BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, const char* func, const char* file, unsigned int line);
|
||||
BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, const char* func, const char* file, unsigned int line);
|
||||
void STDCALL _free_traverse_ptr(traverse_ptr* tp, const char* func, const char* file, unsigned int line);
|
||||
void STDCALL free_tree_cache(LIST_ENTRY* tc);
|
||||
BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset, void* data, UINT32 size, traverse_ptr* ptp, LIST_ENTRY* rollback);
|
||||
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);
|
||||
|
||||
#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
|
||||
void STDCALL look_for_vols(LIST_ENTRY* volumes);
|
||||
|
||||
// in cache.c
|
||||
NTSTATUS STDCALL init_cache();
|
||||
void STDCALL free_cache();
|
||||
extern CACHE_MANAGER_CALLBACKS* cache_callbacks;
|
||||
|
||||
// in write.c
|
||||
NTSTATUS STDCALL do_write(device_extension* Vcb, LIST_ENTRY* rollback);
|
||||
NTSTATUS write_file(PDEVICE_OBJECT DeviceObject, PIRP Irp);
|
||||
NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, BOOL paging_io, BOOL no_cache, LIST_ENTRY* rollback);
|
||||
NTSTATUS truncate_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback);
|
||||
NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback);
|
||||
NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
void update_checksum_tree(device_extension* Vcb, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
NTSTATUS insert_sparse_extent(device_extension* Vcb, root* r, UINT64 inode, UINT64 start, UINT64 length, LIST_ENTRY* rollback);
|
||||
NTSTATUS STDCALL add_extent_ref(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode, UINT64 offset, LIST_ENTRY* rollback);
|
||||
NTSTATUS STDCALL remove_extent_ref(device_extension* Vcb, UINT64 address, UINT64 size, root* subvol, UINT64 inode, UINT64 offset, LIST_ENTRY* changed_sector_list, LIST_ENTRY* rollback);
|
||||
void print_trees(LIST_ENTRY* tc);
|
||||
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);
|
||||
|
||||
// in dirctrl.c
|
||||
NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
|
||||
// in security.c
|
||||
NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
|
||||
void fcb_get_sd(fcb* fcb);
|
||||
// UINT32 STDCALL get_uid();
|
||||
void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid);
|
||||
NTSTATUS fcb_get_new_sd(fcb* fcb, 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// in fsctl.c
|
||||
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user);
|
||||
|
||||
// in flushthread.c
|
||||
void STDCALL flush_thread(void* context);
|
||||
|
||||
// in read.c
|
||||
NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp);
|
||||
NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr);
|
||||
|
||||
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);
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY* before) {
|
||||
item->Flink = before->Flink;
|
||||
before->Flink = item;
|
||||
item->Blink = before;
|
||||
|
||||
if (item->Flink != head)
|
||||
item->Flink->Blink = item;
|
||||
else
|
||||
head->Blink = item;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// #define int3 __asm { int 3 }
|
||||
#define int3 __debugbreak()
|
||||
#else
|
||||
#define int3 asm("int3;")
|
||||
#endif
|
||||
|
||||
#define acquire_tree_lock(Vcb, exclusive) {\
|
||||
LONG ref = InterlockedIncrement(&Vcb->tree_lock_counter); \
|
||||
ref = ref; \
|
||||
if (exclusive) { \
|
||||
TRACE("getting tree_lock (exclusive) %u->%u\n", ref-1, ref); \
|
||||
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); \
|
||||
TRACE("open tree count = %i\n", Vcb->open_trees); \
|
||||
} else { \
|
||||
TRACE("getting tree_lock %u->%u\n", ref-1, ref); \
|
||||
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); \
|
||||
} \
|
||||
}
|
||||
|
||||
// if (Vcb->open_trees > 0) { ERR("open tree count = %i\n", Vcb->open_trees); print_open_trees(Vcb); int3; }
|
||||
// else TRACE("open tree count = %i\n", Vcb->open_trees);
|
||||
|
||||
// FIXME - find a way to catch unfreed trees again
|
||||
|
||||
#define release_tree_lock(Vcb, exclusive) {\
|
||||
LONG ref = InterlockedDecrement(&Vcb->tree_lock_counter); \
|
||||
ref = ref; \
|
||||
TRACE("releasing tree_lock %u->%u\n", ref+1, ref); \
|
||||
if (exclusive) {\
|
||||
TRACE("open tree count = %i\n", Vcb->open_trees); \
|
||||
} \
|
||||
ExReleaseResourceLite(&Vcb->tree_lock); \
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TREE_REFCOUNTS
|
||||
#ifdef DEBUG_LONG_MESSAGES
|
||||
#define _increase_tree_rc(t, func, file, line) { \
|
||||
LONG rc = InterlockedIncrement(&t->refcount); \
|
||||
_debug_message(func, file, line, "tree %p: refcount increased to %i (increase_tree_rc)\n", t, rc); \
|
||||
}
|
||||
#else
|
||||
#define _increase_tree_rc(t, func, file, line) { \
|
||||
LONG rc = InterlockedIncrement(&t->refcount); \
|
||||
_debug_message(func, "tree %p: refcount increased to %i (increase_tree_rc)\n", t, rc); \
|
||||
}
|
||||
#endif
|
||||
#define increase_tree_rc(t) _increase_tree_rc(t, funcname, __FILE__, __LINE__)
|
||||
#else
|
||||
#define increase_tree_rc(t) InterlockedIncrement(&t->refcount);
|
||||
#define _increase_tree_rc(t, func, file, line) increase_tree_rc(t)
|
||||
#endif
|
||||
|
||||
// from sys/stat.h
|
||||
#define __S_IFMT 0170000 /* These bits determine file type. */
|
||||
#define __S_IFDIR 0040000 /* Directory. */
|
||||
#define __S_IFCHR 0020000 /* Character device. */
|
||||
#define __S_IFBLK 0060000 /* Block device. */
|
||||
#define __S_IFREG 0100000 /* Regular file. */
|
||||
#define __S_IFIFO 0010000 /* FIFO. */
|
||||
#define __S_IFLNK 0120000 /* Symbolic link. */
|
||||
#define __S_IFSOCK 0140000 /* Socket. */
|
||||
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
|
||||
#endif
|
||||
|
||||
#ifndef S_IXUSR
|
||||
#define S_IXUSR 0000100
|
||||
#endif
|
||||
|
||||
#ifdef __REACTOS__
|
||||
#define S_IFDIR __S_IFDIR
|
||||
#define S_IFREG __S_IFREG
|
||||
#endif /* __REACTOS__ */
|
||||
|
||||
#ifndef S_IXGRP
|
||||
#define S_IXGRP (S_IXUSR >> 3)
|
||||
#endif
|
||||
|
||||
#ifndef S_IXOTH
|
||||
#define S_IXOTH (S_IXGRP >> 3)
|
||||
#endif
|
||||
|
||||
#if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7)
|
||||
NTSTATUS WINAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
|
||||
ULONG *utf8_bytes_written,
|
||||
const WCHAR *uni_src, ULONG uni_bytes);
|
||||
NTSTATUS WINAPI RtlUTF8ToUnicodeN(WCHAR *uni_dest, ULONG uni_bytes_max,
|
||||
ULONG *uni_bytes_written,
|
||||
const CHAR *utf8_src, ULONG utf8_bytes);
|
||||
#endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */
|
||||
#if defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_VISTA)
|
||||
NTSTATUS NTAPI FsRtlRemoveDotsFromPath(PWSTR OriginalString,
|
||||
USHORT PathLength, USHORT *NewLength);
|
||||
#endif /* defined(__REACTOS__) && (NTDDI_VERSION < NTDDI_WIN7) */
|
||||
|
||||
#endif
|
76
reactos/drivers/filesystems/btrfs/cache.c
Normal file
76
reactos/drivers/filesystems/btrfs/cache.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "btrfs_drv.h"
|
||||
#include <wdm.h>
|
||||
|
||||
CACHE_MANAGER_CALLBACKS* cache_callbacks;
|
||||
|
||||
static BOOLEAN STDCALL acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) {
|
||||
PFILE_OBJECT FileObject = Context;
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
|
||||
TRACE("(%p, %u)\n", Context, Wait);
|
||||
|
||||
if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE)
|
||||
return FALSE;
|
||||
|
||||
fcb->lazy_writer_thread = KeGetCurrentThread();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void STDCALL release_from_lazy_write(PVOID Context) {
|
||||
PFILE_OBJECT FileObject = Context;
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
|
||||
TRACE("(%p)\n", Context);
|
||||
|
||||
if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE)
|
||||
return;
|
||||
|
||||
fcb->lazy_writer_thread = NULL;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL acquire_for_read_ahead(PVOID Context, BOOLEAN Wait) {
|
||||
TRACE("(%p, %u)\n", Context, Wait);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void STDCALL release_from_read_ahead(PVOID Context) {
|
||||
TRACE("(%p)\n", Context);
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL init_cache() {
|
||||
cache_callbacks = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_MANAGER_CALLBACKS), ALLOC_TAG);
|
||||
if (!cache_callbacks) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
cache_callbacks->AcquireForLazyWrite = acquire_for_lazy_write;
|
||||
cache_callbacks->ReleaseFromLazyWrite = release_from_lazy_write;
|
||||
cache_callbacks->AcquireForReadAhead = acquire_for_read_ahead;
|
||||
cache_callbacks->ReleaseFromReadAhead = release_from_read_ahead;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void STDCALL free_cache() {
|
||||
ExFreePool(cache_callbacks);
|
||||
}
|
108
reactos/drivers/filesystems/btrfs/crc32c.c
Normal file
108
reactos/drivers/filesystems/btrfs/crc32c.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <windef.h>
|
||||
#ifndef __REACTOS__
|
||||
#include <smmintrin.h>
|
||||
|
||||
extern BOOL have_sse42;
|
||||
#endif /* __REACTOS__ */
|
||||
|
||||
static const UINT32 crctable[] = {
|
||||
0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
|
||||
0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
|
||||
0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
|
||||
0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
|
||||
0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
|
||||
0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
|
||||
0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
|
||||
0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
|
||||
0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
|
||||
0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
|
||||
0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
|
||||
0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
|
||||
0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
|
||||
0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
|
||||
0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
|
||||
0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
|
||||
0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
|
||||
0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
|
||||
0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
|
||||
0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
|
||||
0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
|
||||
0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
|
||||
0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
|
||||
0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
|
||||
0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
|
||||
0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
|
||||
0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
|
||||
0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
|
||||
0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
|
||||
0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
|
||||
0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
|
||||
0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
|
||||
};
|
||||
|
||||
#ifndef __REACTOS__
|
||||
// HW code taken from https://github.com/rurban/smhasher/blob/master/crc32_hw.c
|
||||
#define ALIGN_SIZE 0x08UL
|
||||
#define ALIGN_MASK (ALIGN_SIZE - 1)
|
||||
#define CALC_CRC(op, crc, type, buf, len) \
|
||||
do { \
|
||||
for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \
|
||||
(crc) = op((crc), *(type *) (buf)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static UINT32 crc32c_hw(const void *input, int len, UINT32 crc) {
|
||||
const char* buf = (const char*)input;
|
||||
|
||||
for (; (len > 0) && ((size_t)buf & ALIGN_MASK); len--, buf++) {
|
||||
crc = _mm_crc32_u8(crc, *buf);
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
CALC_CRC(_mm_crc32_u64, crc, UINT64, buf, len);
|
||||
#endif
|
||||
CALC_CRC(_mm_crc32_u32, crc, UINT32, buf, len);
|
||||
CALC_CRC(_mm_crc32_u16, crc, UINT16, buf, len);
|
||||
CALC_CRC(_mm_crc32_u8, crc, UINT8, buf, len);
|
||||
|
||||
return crc;
|
||||
}
|
||||
#endif
|
||||
|
||||
UINT32 __stdcall calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen) {
|
||||
UINT32 rem;
|
||||
ULONG i;
|
||||
|
||||
#ifndef __REACTOS__
|
||||
if (have_sse42) {
|
||||
return crc32c_hw(msg, msglen, seed);
|
||||
} else {
|
||||
#endif
|
||||
rem = seed;
|
||||
|
||||
for (i = 0; i < msglen; i++) {
|
||||
rem = crctable[(rem ^ msg[i]) & 0xff] ^ (rem >> 8);
|
||||
}
|
||||
#ifndef __REACTOS__
|
||||
}
|
||||
#endif
|
||||
|
||||
return rem;
|
||||
}
|
2396
reactos/drivers/filesystems/btrfs/create.c
Normal file
2396
reactos/drivers/filesystems/btrfs/create.c
Normal file
File diff suppressed because it is too large
Load diff
879
reactos/drivers/filesystems/btrfs/dirctrl.c
Normal file
879
reactos/drivers/filesystems/btrfs/dirctrl.c
Normal file
|
@ -0,0 +1,879 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
enum DirEntryType {
|
||||
DirEntryType_File,
|
||||
DirEntryType_Self,
|
||||
DirEntryType_Parent
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
KEY key;
|
||||
char* name;
|
||||
ULONG namelen;
|
||||
UINT8 type;
|
||||
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) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
UINT32 needed;
|
||||
UINT64 inode;
|
||||
INODE_ITEM ii;
|
||||
NTSTATUS Status;
|
||||
ULONG stringlen;
|
||||
BOOL dotfile;
|
||||
|
||||
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;
|
||||
|
||||
if (!r) {
|
||||
ERR("could not find root %llx\n", de->key.obj_id);
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
inode = SUBVOL_ROOT_INODE;
|
||||
} else {
|
||||
inode = de->key.obj_id;
|
||||
}
|
||||
|
||||
if (IrpSp->Parameters.QueryDirectory.FileInformationClass != FileNamesInformation) { // FIXME - object ID and reparse point classes too?
|
||||
switch (de->dir_entry_type) {
|
||||
case DirEntryType_File:
|
||||
{
|
||||
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 (c->subvol == r && c->inode == inode) {
|
||||
ii = c->inode_item;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
KEY searchkey;
|
||||
traverse_ptr tp;
|
||||
|
||||
searchkey.obj_id = inode;
|
||||
searchkey.obj_type = TYPE_INODE_ITEM;
|
||||
searchkey.offset = 0xffffffffffffffff;
|
||||
|
||||
Status = find_item(fcb->Vcb, r, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
RtlZeroMemory(&ii, sizeof(INODE_ITEM));
|
||||
|
||||
if (tp.item->size > 0)
|
||||
RtlCopyMemory(&ii, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DirEntryType_Self:
|
||||
ii = fcb->inode_item;
|
||||
r = fcb->subvol;
|
||||
inode = fcb->inode;
|
||||
break;
|
||||
|
||||
case DirEntryType_Parent:
|
||||
ii = fcb->par->inode_item;
|
||||
r = fcb->par->subvol;
|
||||
inode = fcb->par->inode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FICs which return the filename
|
||||
if (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation ||
|
||||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileDirectoryInformation ||
|
||||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileFullDirectoryInformation ||
|
||||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation ||
|
||||
IrpSp->Parameters.QueryDirectory.FileInformationClass == FileNamesInformation) {
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de->name, de->namelen);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
dotfile = de->name[0] == '.' && (de->name[1] != '.' || de->name[2] != 0) && (de->name[1] != 0);
|
||||
|
||||
switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
|
||||
case FileBothDirectoryInformation:
|
||||
{
|
||||
FILE_BOTH_DIR_INFORMATION* fbdi = buf;
|
||||
|
||||
TRACE("FileBothDirectoryInformation\n");
|
||||
|
||||
needed = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
fbdi->NextEntryOffset = 0;
|
||||
fbdi->FileIndex = 0;
|
||||
fbdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
|
||||
fbdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
|
||||
fbdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
|
||||
fbdi->ChangeTime.QuadPart = 0;
|
||||
fbdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
|
||||
fbdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
|
||||
fbdi->FileAttributes = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
fbdi->FileNameLength = stringlen;
|
||||
fbdi->EaSize = de->type == BTRFS_TYPE_SYMLINK ? IO_REPARSE_TAG_SYMLINK : 0;
|
||||
fbdi->ShortNameLength = 0;
|
||||
// fibdi->ShortName[12];
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(fbdi->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
*len -= needed;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case FileDirectoryInformation:
|
||||
{
|
||||
FILE_DIRECTORY_INFORMATION* fdi = buf;
|
||||
|
||||
TRACE("FileDirectoryInformation\n");
|
||||
|
||||
needed = sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
fdi->NextEntryOffset = 0;
|
||||
fdi->FileIndex = 0;
|
||||
fdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
|
||||
fdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
|
||||
fdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
|
||||
fdi->ChangeTime.QuadPart = 0;
|
||||
fdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
|
||||
fdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
|
||||
fdi->FileAttributes = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
fdi->FileNameLength = stringlen;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(fdi->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
*len -= needed;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case FileFullDirectoryInformation:
|
||||
{
|
||||
FILE_FULL_DIR_INFORMATION* ffdi = buf;
|
||||
|
||||
TRACE("FileFullDirectoryInformation\n");
|
||||
|
||||
needed = sizeof(FILE_FULL_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
ffdi->NextEntryOffset = 0;
|
||||
ffdi->FileIndex = 0;
|
||||
ffdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
|
||||
ffdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
|
||||
ffdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
|
||||
ffdi->ChangeTime.QuadPart = 0;
|
||||
ffdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
|
||||
ffdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
|
||||
ffdi->FileAttributes = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
ffdi->FileNameLength = stringlen;
|
||||
ffdi->EaSize = de->type == BTRFS_TYPE_SYMLINK ? IO_REPARSE_TAG_SYMLINK : 0;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(ffdi->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
*len -= needed;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case FileIdBothDirectoryInformation:
|
||||
{
|
||||
FILE_ID_BOTH_DIR_INFORMATION* fibdi = buf;
|
||||
|
||||
TRACE("FileIdBothDirectoryInformation\n");
|
||||
|
||||
needed = sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
// if (!buf)
|
||||
// return STATUS_INVALID_POINTER;
|
||||
|
||||
fibdi->NextEntryOffset = 0;
|
||||
fibdi->FileIndex = 0;
|
||||
fibdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
|
||||
fibdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
|
||||
fibdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
|
||||
fibdi->ChangeTime.QuadPart = 0;
|
||||
fibdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
|
||||
fibdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
|
||||
fibdi->FileAttributes = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
|
||||
fibdi->FileNameLength = stringlen;
|
||||
fibdi->EaSize = de->type == BTRFS_TYPE_SYMLINK ? IO_REPARSE_TAG_SYMLINK : 0;
|
||||
fibdi->ShortNameLength = 0;
|
||||
// fibdi->ShortName[12];
|
||||
fibdi->FileId.QuadPart = inode;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(fibdi->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
*len -= needed;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case FileIdFullDirectoryInformation:
|
||||
FIXME("STUB: FileIdFullDirectoryInformation\n");
|
||||
break;
|
||||
|
||||
case FileNamesInformation:
|
||||
{
|
||||
FILE_NAMES_INFORMATION* fni = buf;
|
||||
|
||||
TRACE("FileNamesInformation\n");
|
||||
|
||||
needed = sizeof(FILE_NAMES_INFORMATION) - sizeof(WCHAR) + stringlen;
|
||||
|
||||
if (needed > *len) {
|
||||
WARN("buffer overflow - %u > %u\n", needed, *len);
|
||||
return STATUS_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
fni->NextEntryOffset = 0;
|
||||
fni->FileIndex = 0;
|
||||
fni->FileNameLength = stringlen;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(fni->FileName, stringlen, &stringlen, de->name, de->namelen);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
*len -= needed;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
case FileObjectIdInformation:
|
||||
FIXME("STUB: FileObjectIdInformation\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
case FileQuotaInformation:
|
||||
FIXME("STUB: FileQuotaInformation\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
case FileReparsePointInformation:
|
||||
FIXME("STUB: FileReparsePointInformation\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
|
||||
default:
|
||||
WARN("Unknown FileInformationClass %u\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL next_dir_entry(fcb* fcb, 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 (*offset == 0) {
|
||||
de->key.obj_id = fcb->inode;
|
||||
de->key.obj_type = TYPE_INODE_ITEM;
|
||||
de->key.offset = 0;
|
||||
de->dir_entry_type = DirEntryType_Self;
|
||||
de->name = ".";
|
||||
de->namelen = 1;
|
||||
de->type = BTRFS_TYPE_DIRECTORY;
|
||||
|
||||
*offset = 1;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else if (*offset == 1) {
|
||||
de->key.obj_id = fcb->par->inode;
|
||||
de->key.obj_type = TYPE_INODE_ITEM;
|
||||
de->key.offset = 0;
|
||||
de->dir_entry_type = DirEntryType_Parent;
|
||||
de->name = "..";
|
||||
de->namelen = 2;
|
||||
de->type = BTRFS_TYPE_DIRECTORY;
|
||||
|
||||
*offset = 2;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tp->tree) {
|
||||
searchkey.obj_id = fcb->inode;
|
||||
searchkey.obj_type = TYPE_DIR_INDEX;
|
||||
searchkey.offset = *offset;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
TRACE("found item %llx,%x,%llx\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
|
||||
|
||||
if (keycmp(&tp->item->key, &searchkey) == -1) {
|
||||
if (find_next_item(fcb->Vcb, tp, &next_tp, FALSE)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*offset = tp->item->key.offset + 1;
|
||||
|
||||
di = (DIR_ITEM*)tp->item->data;
|
||||
|
||||
if (tp->item->size < sizeof(DIR_ITEM) || tp->item->size < sizeof(DIR_ITEM) - 1 + di->m + di->n) {
|
||||
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, tp->item->size, sizeof(DIR_ITEM));
|
||||
|
||||
free_traverse_ptr(tp);
|
||||
tp->tree = NULL;
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
de->key = di->key;
|
||||
de->name = di->name;
|
||||
de->namelen = di->n;
|
||||
de->type = di->type;
|
||||
de->dir_entry_type = DirEntryType_File;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else {
|
||||
if (find_next_item(fcb->Vcb, tp, &next_tp, FALSE)) {
|
||||
if (next_tp.item->key.obj_type == TYPE_DIR_INDEX && next_tp.item->key.obj_id == tp->item->key.obj_id) {
|
||||
free_traverse_ptr(tp);
|
||||
*tp = next_tp;
|
||||
|
||||
*offset = tp->item->key.offset + 1;
|
||||
|
||||
di = (DIR_ITEM*)tp->item->data;
|
||||
|
||||
if (tp->item->size < sizeof(DIR_ITEM) || tp->item->size < sizeof(DIR_ITEM) - 1 + di->m + di->n) {
|
||||
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, tp->item->size, sizeof(DIR_ITEM));
|
||||
|
||||
free_traverse_ptr(&next_tp);
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
de->key = di->key;
|
||||
de->name = di->name;
|
||||
de->namelen = di->n;
|
||||
de->type = di->type;
|
||||
de->dir_entry_type = DirEntryType_File;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
} else {
|
||||
free_traverse_ptr(&next_tp);
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
} else
|
||||
return STATUS_NO_MORE_FILES;
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
NTSTATUS Status, status2;
|
||||
fcb* fcb;
|
||||
ccb* ccb;
|
||||
void* buf;
|
||||
UINT8 *curitem, *lastitem;
|
||||
LONG length;
|
||||
ULONG count;
|
||||
BOOL has_wildcard = FALSE, specific_file = FALSE;
|
||||
// UINT64 num_reads_orig;
|
||||
traverse_ptr tp;
|
||||
dir_entry de;
|
||||
|
||||
TRACE("query directory\n");
|
||||
|
||||
// get_uid(); // TESTING
|
||||
|
||||
// num_reads_orig = num_reads;
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
fcb = IrpSp->FileObject->FsContext;
|
||||
ccb = IrpSp->FileObject->FsContext2;
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
TRACE("%.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
|
||||
|
||||
if (IrpSp->Flags == 0) {
|
||||
TRACE("QD flags: (none)\n");
|
||||
} else {
|
||||
ULONG flags = IrpSp->Flags;
|
||||
|
||||
TRACE("QD flags:\n");
|
||||
|
||||
if (flags & SL_INDEX_SPECIFIED) {
|
||||
TRACE(" SL_INDEX_SPECIFIED\n");
|
||||
flags &= ~SL_INDEX_SPECIFIED;
|
||||
}
|
||||
|
||||
if (flags & SL_RESTART_SCAN) {
|
||||
TRACE(" SL_RESTART_SCAN\n");
|
||||
flags &= ~SL_RESTART_SCAN;
|
||||
}
|
||||
|
||||
if (flags & SL_RETURN_SINGLE_ENTRY) {
|
||||
TRACE(" SL_RETURN_SINGLE_ENTRY\n");
|
||||
flags &= ~SL_RETURN_SINGLE_ENTRY;
|
||||
}
|
||||
|
||||
if (flags != 0)
|
||||
TRACE(" unknown flags: %u\n", flags);
|
||||
}
|
||||
|
||||
if (IrpSp->Flags & SL_RESTART_SCAN) {
|
||||
ccb->query_dir_offset = 0;
|
||||
|
||||
if (ccb->query_string.Buffer) {
|
||||
RtlFreeUnicodeString(&ccb->query_string);
|
||||
ccb->query_string.Buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (IrpSp->Parameters.QueryDirectory.FileName) {
|
||||
// int i;
|
||||
// WCHAR* us;
|
||||
|
||||
TRACE("QD filename: %.*S\n", IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR), IrpSp->Parameters.QueryDirectory.FileName->Buffer);
|
||||
|
||||
// if (IrpSp->Parameters.QueryDirectory.FileName->Length > 1 || IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != '*') {
|
||||
// specific_file = TRUE;
|
||||
// for (i = 0; i < IrpSp->Parameters.QueryDirectory.FileName->Length; i++) {
|
||||
// if (IrpSp->Parameters.QueryDirectory.FileName->Buffer[i] == '?' || IrpSp->Parameters.QueryDirectory.FileName->Buffer[i] == '*') {
|
||||
// has_wildcard = TRUE;
|
||||
// specific_file = FALSE;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
has_wildcard = TRUE;
|
||||
|
||||
if (ccb->query_string.Buffer)
|
||||
RtlFreeUnicodeString(&ccb->query_string);
|
||||
|
||||
// us = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length + sizeof(WCHAR), ALLOC_TAG);
|
||||
// RtlCopyMemory(us, IrpSp->Parameters.QueryDirectory.FileName->Buffer, IrpSp->Parameters.QueryDirectory.FileName->Length);
|
||||
// us[IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR)] = 0;
|
||||
|
||||
// ccb->query_string = ExAllocatePoolWithTag(NonPagedPool, utf16_to_utf8_len(us), ALLOC_TAG);
|
||||
// utf16_to_utf8(us, ccb->query_string);
|
||||
|
||||
// ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG);
|
||||
// RtlCopyMemory(ccb->query_string.Buffer, IrpSp->Parameters.QueryDirectory.FileName->Buffer,
|
||||
// IrpSp->Parameters.QueryDirectory.FileName->Length);
|
||||
// ccb->query_string.Length = IrpSp->Parameters.QueryDirectory.FileName->Length;
|
||||
// ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length;
|
||||
RtlUpcaseUnicodeString(&ccb->query_string, IrpSp->Parameters.QueryDirectory.FileName, TRUE);
|
||||
|
||||
ccb->has_wildcard = has_wildcard;
|
||||
ccb->specific_file = specific_file;
|
||||
|
||||
// ExFreePool(us);
|
||||
} else {
|
||||
has_wildcard = ccb->has_wildcard;
|
||||
specific_file = ccb->specific_file;
|
||||
}
|
||||
|
||||
if (ccb->query_string.Buffer) {
|
||||
TRACE("query string = %.*S\n", ccb->query_string.Length / sizeof(WCHAR), ccb->query_string.Buffer);
|
||||
}
|
||||
|
||||
tp.tree = NULL;
|
||||
Status = next_dir_entry(fcb, &ccb->query_dir_offset, &de, &tp);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
if (Status == STATUS_NO_MORE_FILES && IrpSp->Flags & SL_RETURN_SINGLE_ENTRY)
|
||||
Status = STATUS_NO_SUCH_FILE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// FIXME - make this work
|
||||
// if (specific_file) {
|
||||
// UINT64 filesubvol, fileinode;
|
||||
// WCHAR* us;
|
||||
//
|
||||
// us = ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length + sizeof(WCHAR), ALLOC_TAG);
|
||||
// RtlCopyMemory(us, IrpSp->Parameters.QueryDirectory.FileName->Buffer, IrpSp->Parameters.QueryDirectory.FileName->Length);
|
||||
// us[IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR)] = 0;
|
||||
//
|
||||
// if (!find_file_in_dir(fcb->Vcb, us, fcb->subvolume, fcb->inode, &filesubvol, &fileinode)) {
|
||||
// ExFreePool(us);
|
||||
// return STATUS_NO_MORE_FILES;
|
||||
// }
|
||||
//
|
||||
// ExFreePool(us);
|
||||
// }
|
||||
|
||||
buf = map_user_buffer(Irp);
|
||||
|
||||
if (Irp->MdlAddress && !buf) {
|
||||
ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
length = IrpSp->Parameters.QueryDirectory.Length;
|
||||
|
||||
// if (specific_file) {
|
||||
if (has_wildcard) {
|
||||
WCHAR* uni_fn;
|
||||
ULONG stringlen;
|
||||
UNICODE_STRING di_uni_fn;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de.name, de.namelen);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
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;
|
||||
}
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(uni_fn, stringlen, &stringlen, de.name, de.namelen);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
goto end;
|
||||
}
|
||||
|
||||
di_uni_fn.Length = di_uni_fn.MaximumLength = stringlen;
|
||||
di_uni_fn.Buffer = uni_fn;
|
||||
|
||||
while (!FsRtlIsNameInExpression(&ccb->query_string, &di_uni_fn, TRUE, NULL)) {
|
||||
Status = next_dir_entry(fcb, &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;
|
||||
}
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(uni_fn, stringlen, &stringlen, de.name, de.namelen);
|
||||
|
||||
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)
|
||||
Status = STATUS_NO_SUCH_FILE;
|
||||
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(uni_fn);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
count = 0;
|
||||
if (NT_SUCCESS(Status) && !(IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) && !specific_file) {
|
||||
lastitem = (UINT8*)buf;
|
||||
|
||||
while (length > 0) {
|
||||
switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) {
|
||||
case FileBothDirectoryInformation:
|
||||
case FileDirectoryInformation:
|
||||
case FileIdBothDirectoryInformation:
|
||||
case FileFullDirectoryInformation:
|
||||
length -= length % 8;
|
||||
break;
|
||||
|
||||
case FileNamesInformation:
|
||||
length -= length % 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN("unhandled file information class %u\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
|
||||
break;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
WCHAR* uni_fn = NULL;
|
||||
UNICODE_STRING di_uni_fn;
|
||||
|
||||
Status = next_dir_entry(fcb, &ccb->query_dir_offset, &de, &tp);
|
||||
if (NT_SUCCESS(Status)) {
|
||||
if (has_wildcard) {
|
||||
ULONG stringlen;
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, de.name, de.namelen);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("RtlUTF8ToUnicodeN returned %08x\n", Status);
|
||||
if (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;
|
||||
}
|
||||
|
||||
Status = RtlUTF8ToUnicodeN(uni_fn, stringlen, &stringlen, de.name, de.namelen);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!has_wildcard || FsRtlIsNameInExpression(&ccb->query_string, &di_uni_fn, TRUE, NULL)) {
|
||||
curitem = (UINT8*)buf + IrpSp->Parameters.QueryDirectory.Length - length;
|
||||
count++;
|
||||
|
||||
TRACE("file(%u) %u = %.*s\n", count, curitem - (UINT8*)buf, de.namelen, de.name);
|
||||
TRACE("offset = %u\n", ccb->query_dir_offset - 1);
|
||||
|
||||
status2 = query_dir_item(fcb, curitem, &length, Irp, &de, fcb->subvol);
|
||||
|
||||
if (NT_SUCCESS(status2)) {
|
||||
ULONG* lastoffset = (ULONG*)lastitem;
|
||||
|
||||
*lastoffset = (ULONG)(curitem - lastitem);
|
||||
|
||||
lastitem = curitem;
|
||||
} else {
|
||||
if (uni_fn) ExFreePool(uni_fn);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uni_fn) {
|
||||
ExFreePool(uni_fn);
|
||||
uni_fn = NULL;
|
||||
}
|
||||
} else {
|
||||
if (Status == STATUS_NO_MORE_FILES)
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
break;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Irp->IoStatus.Information = IrpSp->Parameters.QueryDirectory.Length - length;
|
||||
|
||||
if (tp.tree) free_traverse_ptr(&tp);
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
// TRACE("query directory performed %u reads\n", (UINT32)(num_reads-num_reads_orig));
|
||||
TRACE("returning %08x\n", Status);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
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;
|
||||
NTSTATUS Status;
|
||||
// WCHAR fn[MAX_PATH];
|
||||
|
||||
TRACE("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
if (fcb->type != BTRFS_TYPE_DIRECTORY) {
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// FIXME - raise exception if FCB marked for deletion?
|
||||
|
||||
TRACE("%.*S\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer);
|
||||
|
||||
FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext2, (PSTRING)&fcb->full_filename,
|
||||
IrpSp->Flags & SL_WATCH_TREE, FALSE, IrpSp->Parameters.NotifyDirectory.CompletionFilter, Irp, NULL, NULL);
|
||||
|
||||
Status = STATUS_PENDING;
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
NTSTATUS Status;
|
||||
ULONG func;
|
||||
BOOL top_level;
|
||||
|
||||
TRACE("directory control\n");
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
top_level = is_top_level(Irp);
|
||||
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
func = IrpSp->MinorFunction;
|
||||
|
||||
switch (func) {
|
||||
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
|
||||
Status = notify_change_directory(DeviceObject->DeviceExtension, Irp);
|
||||
break;
|
||||
|
||||
case IRP_MN_QUERY_DIRECTORY:
|
||||
Status = query_directory(DeviceObject, Irp);
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN("unknown minor %u\n", func);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
Irp->IoStatus.Status = Status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (func != IRP_MN_NOTIFY_CHANGE_DIRECTORY || Status != STATUS_PENDING) {
|
||||
Irp->IoStatus.Status = Status;
|
||||
IoCompleteRequest( Irp, IO_DISK_INCREMENT );
|
||||
}
|
||||
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
return Status;
|
||||
}
|
182
reactos/drivers/filesystems/btrfs/fastio.c
Normal file
182
reactos/drivers/filesystems/btrfs/fastio.c
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <ntifs.h>
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
FAST_IO_DISPATCH FastIoDispatch;
|
||||
|
||||
static void STDCALL acquire_file_for_create_section(PFILE_OBJECT FileObject) {
|
||||
TRACE("STUB: acquire_file_for_create_section\n");
|
||||
}
|
||||
|
||||
static void STDCALL release_file_for_create_section(PFILE_OBJECT FileObject) {
|
||||
TRACE("STUB: release_file_for_create_section\n");
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_BASIC_INFORMATION buf,
|
||||
PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
|
||||
|
||||
TRACE("STUB: fast_query_basic_info\n");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_query_standard_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_STANDARD_INFORMATION buf,
|
||||
PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
|
||||
|
||||
TRACE("STUB: fast_query_standard_info\n");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_query_open(PIRP Irp, PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, PDEVICE_OBJECT DeviceObject) {
|
||||
TRACE("STUB: fast_io_query_open\n");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_check_if_possible(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait,
|
||||
ULONG LockKey, BOOLEAN CheckForReadOperation, PIO_STATUS_BLOCK IoStatus,
|
||||
PDEVICE_OBJECT DeviceObject) {
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
LARGE_INTEGER len2;
|
||||
|
||||
TRACE("(%p, %llx, %x, %x, %x, %x, %p, %p)\n", FileObject, FileOffset->QuadPart, Length, Wait, LockKey, CheckForReadOperation, IoStatus, DeviceObject);
|
||||
|
||||
len2.QuadPart = Length;
|
||||
|
||||
if (CheckForReadOperation) {
|
||||
if (FsRtlFastCheckLockForRead(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess()))
|
||||
return TRUE;
|
||||
} else {
|
||||
if (!fcb->Vcb->readonly && !(fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY) && FsRtlFastCheckLockForWrite(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess()))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_lock(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, BOOLEAN FailImmediately, BOOLEAN ExclusiveLock, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_lock\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_unlock_single(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_unlock_single\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_unlock_all(PFILE_OBJECT FileObject, PEPROCESS ProcessId, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_unlock_all\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_unlock_all_by_key(PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_unlock_all_by_key\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_device_control(PFILE_OBJECT FileObject, BOOLEAN Wait, PVOID InputBuffer OPTIONAL, ULONG InputBufferLength, PVOID OutputBuffer OPTIONAL, ULONG OutputBufferLength, ULONG IoControlCode, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_device_control\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static VOID STDCALL fast_io_detach_device(PDEVICE_OBJECT SourceDevice, PDEVICE_OBJECT TargetDevice){
|
||||
TRACE("STUB: fast_io_detach_device\n");
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_query_network_open_info(PFILE_OBJECT FileObject, BOOLEAN Wait, struct _FILE_NETWORK_OPEN_INFORMATION *Buffer, struct _IO_STATUS_BLOCK *IoStatus, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_query_network_open_info\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset, struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_acquire_for_mod_write\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_read_compressed(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PVOID Buffer, PMDL *MdlChain, PIO_STATUS_BLOCK IoStatus, struct _COMPRESSED_DATA_INFO *CompressedDataInfo, ULONG CompressedDataInfoLength, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_read_compressed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_write_compressed(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PVOID Buffer, PMDL *MdlChain, PIO_STATUS_BLOCK IoStatus, struct _COMPRESSED_DATA_INFO *CompressedDataInfo, ULONG CompressedDataInfoLength, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_write_compressed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_mdl_read_complete_compressed(PFILE_OBJECT FileObject, PMDL MdlChain, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_mdl_read_complete_compressed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOLEAN STDCALL fast_io_mdl_write_complete_compressed(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL MdlChain, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_mdl_write_complete_compressed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE *ResourceToRelease, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_release_for_mod_write\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_acquire_for_ccflush\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject){
|
||||
TRACE("STUB: fast_io_release_for_ccflush\n");
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
|
||||
RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch));
|
||||
|
||||
FastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
|
||||
|
||||
FastIoDispatch.FastIoCheckIfPossible = fast_io_check_if_possible;
|
||||
FastIoDispatch.FastIoRead = FsRtlCopyRead;
|
||||
FastIoDispatch.FastIoWrite = FsRtlCopyWrite;
|
||||
FastIoDispatch.FastIoQueryBasicInfo = fast_query_basic_info;
|
||||
FastIoDispatch.FastIoQueryStandardInfo = fast_query_standard_info;
|
||||
FastIoDispatch.FastIoLock = fast_io_lock;
|
||||
FastIoDispatch.FastIoUnlockSingle = fast_io_unlock_single;
|
||||
FastIoDispatch.FastIoUnlockAll = fast_io_unlock_all;
|
||||
FastIoDispatch.FastIoUnlockAllByKey = fast_io_unlock_all_by_key;
|
||||
FastIoDispatch.FastIoDeviceControl = fast_io_device_control;
|
||||
FastIoDispatch.AcquireFileForNtCreateSection = acquire_file_for_create_section;
|
||||
FastIoDispatch.ReleaseFileForNtCreateSection = release_file_for_create_section;
|
||||
FastIoDispatch.FastIoDetachDevice = fast_io_detach_device;
|
||||
FastIoDispatch.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info;
|
||||
FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write;
|
||||
FastIoDispatch.MdlRead = FsRtlMdlReadDev;
|
||||
FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
|
||||
FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
|
||||
FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
|
||||
FastIoDispatch.FastIoReadCompressed = fast_io_read_compressed;
|
||||
FastIoDispatch.FastIoWriteCompressed = fast_io_write_compressed;
|
||||
FastIoDispatch.MdlReadCompleteCompressed = fast_io_mdl_read_complete_compressed;
|
||||
FastIoDispatch.MdlWriteCompleteCompressed = fast_io_mdl_write_complete_compressed;
|
||||
FastIoDispatch.FastIoQueryOpen = fast_io_query_open;
|
||||
FastIoDispatch.ReleaseForModWrite = fast_io_release_for_mod_write;
|
||||
FastIoDispatch.AcquireForCcFlush = fast_io_acquire_for_ccflush;
|
||||
FastIoDispatch.ReleaseForCcFlush = fast_io_release_for_ccflush;
|
||||
|
||||
*fiod = &FastIoDispatch;
|
||||
}
|
2944
reactos/drivers/filesystems/btrfs/fileinfo.c
Normal file
2944
reactos/drivers/filesystems/btrfs/fileinfo.c
Normal file
File diff suppressed because it is too large
Load diff
63
reactos/drivers/filesystems/btrfs/flushthread.c
Normal file
63
reactos/drivers/filesystems/btrfs/flushthread.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
#define INTERVAL 15000 // in milliseconds
|
||||
|
||||
static void do_flush(device_extension* Vcb) {
|
||||
LIST_ENTRY rollback;
|
||||
|
||||
InitializeListHead(&rollback);
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
acquire_tree_lock(Vcb, TRUE);
|
||||
|
||||
if (Vcb->write_trees > 0)
|
||||
do_write(Vcb, &rollback);
|
||||
|
||||
free_tree_cache(&Vcb->tree_cache);
|
||||
|
||||
clear_rollback(&rollback);
|
||||
|
||||
release_tree_lock(Vcb, TRUE);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
}
|
||||
|
||||
void STDCALL flush_thread(void* context) {
|
||||
device_extension* Vcb = context;
|
||||
LARGE_INTEGER due_time;
|
||||
|
||||
KeInitializeTimer(&Vcb->flush_thread_timer);
|
||||
|
||||
due_time.QuadPart = -INTERVAL * 10000;
|
||||
|
||||
KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
|
||||
|
||||
while (TRUE) {
|
||||
KeWaitForSingleObject(&Vcb->flush_thread_timer, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
do_flush(Vcb);
|
||||
|
||||
KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);
|
||||
}
|
||||
|
||||
KeCancelTimer(&Vcb->flush_thread_timer);
|
||||
PsTerminateSystemThread(STATUS_SUCCESS);
|
||||
}
|
510
reactos/drivers/filesystems/btrfs/fsctl.c
Normal file
510
reactos/drivers/filesystems/btrfs/fsctl.c
Normal file
|
@ -0,0 +1,510 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
#ifndef FSCTL_CSV_CONTROL
|
||||
#define FSCTL_CSV_CONTROL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 181, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#endif
|
||||
|
||||
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user) {
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
NTSTATUS Status;
|
||||
|
||||
switch (type) {
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
||||
WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
||||
WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_REQUEST_BATCH_OPLOCK:
|
||||
WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
||||
WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
||||
WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
||||
WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_LOCK_VOLUME:
|
||||
WARN("STUB: FSCTL_LOCK_VOLUME\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_UNLOCK_VOLUME:
|
||||
WARN("STUB: FSCTL_UNLOCK_VOLUME\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_DISMOUNT_VOLUME:
|
||||
WARN("STUB: FSCTL_DISMOUNT_VOLUME\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_IS_VOLUME_MOUNTED:
|
||||
WARN("STUB: FSCTL_IS_VOLUME_MOUNTED\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_IS_PATHNAME_VALID:
|
||||
WARN("STUB: FSCTL_IS_PATHNAME_VALID\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_MARK_VOLUME_DIRTY:
|
||||
WARN("STUB: FSCTL_MARK_VOLUME_DIRTY\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_QUERY_RETRIEVAL_POINTERS:
|
||||
WARN("STUB: FSCTL_QUERY_RETRIEVAL_POINTERS\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_GET_COMPRESSION:
|
||||
WARN("STUB: FSCTL_GET_COMPRESSION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_COMPRESSION:
|
||||
WARN("STUB: FSCTL_SET_COMPRESSION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_BOOTLOADER_ACCESSED:
|
||||
WARN("STUB: FSCTL_SET_BOOTLOADER_ACCESSED\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
||||
WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_INVALIDATE_VOLUMES:
|
||||
WARN("STUB: FSCTL_INVALIDATE_VOLUMES\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_QUERY_FAT_BPB:
|
||||
WARN("STUB: FSCTL_QUERY_FAT_BPB\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_REQUEST_FILTER_OPLOCK:
|
||||
WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_FILESYSTEM_GET_STATISTICS:
|
||||
WARN("STUB: FSCTL_FILESYSTEM_GET_STATISTICS\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_GET_NTFS_VOLUME_DATA:
|
||||
WARN("STUB: FSCTL_GET_NTFS_VOLUME_DATA\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_GET_NTFS_FILE_RECORD:
|
||||
WARN("STUB: FSCTL_GET_NTFS_FILE_RECORD\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_GET_VOLUME_BITMAP:
|
||||
WARN("STUB: FSCTL_GET_VOLUME_BITMAP\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_GET_RETRIEVAL_POINTERS:
|
||||
WARN("STUB: FSCTL_GET_RETRIEVAL_POINTERS\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_MOVE_FILE:
|
||||
WARN("STUB: FSCTL_MOVE_FILE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_IS_VOLUME_DIRTY:
|
||||
WARN("STUB: FSCTL_IS_VOLUME_DIRTY\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_ALLOW_EXTENDED_DASD_IO:
|
||||
WARN("STUB: FSCTL_ALLOW_EXTENDED_DASD_IO\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_FIND_FILES_BY_SID:
|
||||
WARN("STUB: FSCTL_FIND_FILES_BY_SID\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_OBJECT_ID:
|
||||
WARN("STUB: FSCTL_SET_OBJECT_ID\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_GET_OBJECT_ID:
|
||||
WARN("STUB: FSCTL_GET_OBJECT_ID\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_DELETE_OBJECT_ID:
|
||||
WARN("STUB: FSCTL_DELETE_OBJECT_ID\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_REPARSE_POINT:
|
||||
Status = set_reparse_point(DeviceObject, Irp);
|
||||
break;
|
||||
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
Status = get_reparse_point(DeviceObject, IrpSp->FileObject, Irp->AssociatedIrp.SystemBuffer,
|
||||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength, &Irp->IoStatus.Information);
|
||||
break;
|
||||
|
||||
case FSCTL_DELETE_REPARSE_POINT:
|
||||
WARN("STUB: FSCTL_DELETE_REPARSE_POINT\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_ENUM_USN_DATA:
|
||||
WARN("STUB: FSCTL_ENUM_USN_DATA\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SECURITY_ID_CHECK:
|
||||
WARN("STUB: FSCTL_SECURITY_ID_CHECK\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_READ_USN_JOURNAL:
|
||||
WARN("STUB: FSCTL_READ_USN_JOURNAL\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_OBJECT_ID_EXTENDED:
|
||||
WARN("STUB: FSCTL_SET_OBJECT_ID_EXTENDED\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_CREATE_OR_GET_OBJECT_ID:
|
||||
WARN("STUB: FSCTL_CREATE_OR_GET_OBJECT_ID\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_SPARSE:
|
||||
WARN("STUB: FSCTL_SET_SPARSE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_ZERO_DATA:
|
||||
WARN("STUB: FSCTL_SET_ZERO_DATA\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_QUERY_ALLOCATED_RANGES:
|
||||
WARN("STUB: FSCTL_QUERY_ALLOCATED_RANGES\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_ENABLE_UPGRADE:
|
||||
WARN("STUB: FSCTL_ENABLE_UPGRADE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_ENCRYPTION:
|
||||
WARN("STUB: FSCTL_SET_ENCRYPTION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_ENCRYPTION_FSCTL_IO:
|
||||
WARN("STUB: FSCTL_ENCRYPTION_FSCTL_IO\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_WRITE_RAW_ENCRYPTED:
|
||||
WARN("STUB: FSCTL_WRITE_RAW_ENCRYPTED\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_READ_RAW_ENCRYPTED:
|
||||
WARN("STUB: FSCTL_READ_RAW_ENCRYPTED\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_CREATE_USN_JOURNAL:
|
||||
WARN("STUB: FSCTL_CREATE_USN_JOURNAL\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_READ_FILE_USN_DATA:
|
||||
WARN("STUB: FSCTL_READ_FILE_USN_DATA\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_WRITE_USN_CLOSE_RECORD:
|
||||
WARN("STUB: FSCTL_WRITE_USN_CLOSE_RECORD\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_EXTEND_VOLUME:
|
||||
WARN("STUB: FSCTL_EXTEND_VOLUME\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_QUERY_USN_JOURNAL:
|
||||
WARN("STUB: FSCTL_QUERY_USN_JOURNAL\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_DELETE_USN_JOURNAL:
|
||||
WARN("STUB: FSCTL_DELETE_USN_JOURNAL\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_MARK_HANDLE:
|
||||
WARN("STUB: FSCTL_MARK_HANDLE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SIS_COPYFILE:
|
||||
WARN("STUB: FSCTL_SIS_COPYFILE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SIS_LINK_FILES:
|
||||
WARN("STUB: FSCTL_SIS_LINK_FILES\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_RECALL_FILE:
|
||||
WARN("STUB: FSCTL_RECALL_FILE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_READ_FROM_PLEX:
|
||||
WARN("STUB: FSCTL_READ_FROM_PLEX\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_FILE_PREFETCH:
|
||||
WARN("STUB: FSCTL_FILE_PREFETCH\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
#if WIN32_WINNT >= 0x0600
|
||||
case FSCTL_MAKE_MEDIA_COMPATIBLE:
|
||||
WARN("STUB: FSCTL_MAKE_MEDIA_COMPATIBLE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_DEFECT_MANAGEMENT:
|
||||
WARN("STUB: FSCTL_SET_DEFECT_MANAGEMENT\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_QUERY_SPARING_INFO:
|
||||
WARN("STUB: FSCTL_QUERY_SPARING_INFO\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_QUERY_ON_DISK_VOLUME_INFO:
|
||||
WARN("STUB: FSCTL_QUERY_ON_DISK_VOLUME_INFO\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_VOLUME_COMPRESSION_STATE:
|
||||
WARN("STUB: FSCTL_SET_VOLUME_COMPRESSION_STATE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_MODIFY_RM:
|
||||
WARN("STUB: FSCTL_TXFS_MODIFY_RM\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_QUERY_RM_INFORMATION:
|
||||
WARN("STUB: FSCTL_TXFS_QUERY_RM_INFORMATION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_ROLLFORWARD_REDO:
|
||||
WARN("STUB: FSCTL_TXFS_ROLLFORWARD_REDO\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_ROLLFORWARD_UNDO:
|
||||
WARN("STUB: FSCTL_TXFS_ROLLFORWARD_UNDO\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_START_RM:
|
||||
WARN("STUB: FSCTL_TXFS_START_RM\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_SHUTDOWN_RM:
|
||||
WARN("STUB: FSCTL_TXFS_SHUTDOWN_RM\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_READ_BACKUP_INFORMATION:
|
||||
WARN("STUB: FSCTL_TXFS_READ_BACKUP_INFORMATION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_WRITE_BACKUP_INFORMATION:
|
||||
WARN("STUB: FSCTL_TXFS_WRITE_BACKUP_INFORMATION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_CREATE_SECONDARY_RM:
|
||||
WARN("STUB: FSCTL_TXFS_CREATE_SECONDARY_RM\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_GET_METADATA_INFO:
|
||||
WARN("STUB: FSCTL_TXFS_GET_METADATA_INFO\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_GET_TRANSACTED_VERSION:
|
||||
WARN("STUB: FSCTL_TXFS_GET_TRANSACTED_VERSION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_SAVEPOINT_INFORMATION:
|
||||
WARN("STUB: FSCTL_TXFS_SAVEPOINT_INFORMATION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_CREATE_MINIVERSION:
|
||||
WARN("STUB: FSCTL_TXFS_CREATE_MINIVERSION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_TRANSACTION_ACTIVE:
|
||||
WARN("STUB: FSCTL_TXFS_TRANSACTION_ACTIVE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_ZERO_ON_DEALLOCATION:
|
||||
WARN("STUB: FSCTL_SET_ZERO_ON_DEALLOCATION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_REPAIR:
|
||||
WARN("STUB: FSCTL_SET_REPAIR\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_GET_REPAIR:
|
||||
WARN("STUB: FSCTL_GET_REPAIR\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_WAIT_FOR_REPAIR:
|
||||
WARN("STUB: FSCTL_WAIT_FOR_REPAIR\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_INITIATE_REPAIR:
|
||||
WARN("STUB: FSCTL_INITIATE_REPAIR\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_CSC_INTERNAL:
|
||||
WARN("STUB: FSCTL_CSC_INTERNAL\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SHRINK_VOLUME:
|
||||
WARN("STUB: FSCTL_SHRINK_VOLUME\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_SET_SHORT_NAME_BEHAVIOR:
|
||||
WARN("STUB: FSCTL_SET_SHORT_NAME_BEHAVIOR\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_DFSR_SET_GHOST_HANDLE_STATE:
|
||||
WARN("STUB: FSCTL_DFSR_SET_GHOST_HANDLE_STATE\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES:
|
||||
WARN("STUB: FSCTL_TXFS_LIST_TRANSACTION_LOCKED_FILES\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_LIST_TRANSACTIONS:
|
||||
WARN("STUB: FSCTL_TXFS_LIST_TRANSACTIONS\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_QUERY_PAGEFILE_ENCRYPTION:
|
||||
WARN("STUB: FSCTL_QUERY_PAGEFILE_ENCRYPTION\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_RESET_VOLUME_ALLOCATION_HINTS:
|
||||
WARN("STUB: FSCTL_RESET_VOLUME_ALLOCATION_HINTS\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_TXFS_READ_BACKUP_INFORMATION2:
|
||||
WARN("STUB: FSCTL_TXFS_READ_BACKUP_INFORMATION2\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
|
||||
case FSCTL_CSV_CONTROL:
|
||||
WARN("STUB: FSCTL_CSV_CONTROL\n");
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
WARN("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n",
|
||||
IrpSp->Parameters.FileSystemControl.FsControlCode, (IrpSp->Parameters.FileSystemControl.FsControlCode & 0xff0000) >> 16,
|
||||
(IrpSp->Parameters.FileSystemControl.FsControlCode & 0xc000) >> 14, (IrpSp->Parameters.FileSystemControl.FsControlCode & 0x3ffc) >> 2,
|
||||
IrpSp->Parameters.FileSystemControl.FsControlCode & 0x3);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
231
reactos/drivers/filesystems/btrfs/loader.c
Normal file
231
reactos/drivers/filesystems/btrfs/loader.c
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
723
reactos/drivers/filesystems/btrfs/read.c
Normal file
723
reactos/drivers/filesystems/btrfs/read.c
Normal file
|
@ -0,0 +1,723 @@
|
|||
#include "btrfs_drv.h"
|
||||
|
||||
enum read_data_status {
|
||||
ReadDataStatus_Pending,
|
||||
ReadDataStatus_Success,
|
||||
ReadDataStatus_Cancelling,
|
||||
ReadDataStatus_Cancelled,
|
||||
ReadDataStatus_Error,
|
||||
ReadDataStatus_CRCError,
|
||||
ReadDataStatus_MissingDevice
|
||||
};
|
||||
|
||||
struct read_data_context;
|
||||
|
||||
typedef struct {
|
||||
struct read_data_context* context;
|
||||
UINT8* buf;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
enum read_data_status status;
|
||||
} read_data_stripe;
|
||||
|
||||
typedef struct {
|
||||
KEVENT Event;
|
||||
NTSTATUS Status;
|
||||
chunk* c;
|
||||
UINT32 buflen;
|
||||
UINT64 num_stripes;
|
||||
UINT64 type;
|
||||
read_data_stripe* stripes;
|
||||
} read_data_context;
|
||||
|
||||
static NTSTATUS STDCALL read_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
|
||||
read_data_stripe* stripe = conptr;
|
||||
read_data_context* context = (read_data_context*)stripe->context;
|
||||
UINT64 i;
|
||||
BOOL complete;
|
||||
|
||||
if (stripe->status == ReadDataStatus_Cancelling) {
|
||||
stripe->status = ReadDataStatus_Cancelled;
|
||||
goto end;
|
||||
}
|
||||
|
||||
stripe->iosb = Irp->IoStatus;
|
||||
|
||||
if (NT_SUCCESS(Irp->IoStatus.Status)) {
|
||||
// FIXME - calculate and compare checksum
|
||||
|
||||
stripe->status = ReadDataStatus_Success;
|
||||
|
||||
for (i = 0; i < context->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadDataStatus_Pending) {
|
||||
context->stripes[i].status = ReadDataStatus_Cancelling;
|
||||
IoCancelIrp(context->stripes[i].Irp);
|
||||
}
|
||||
}
|
||||
|
||||
goto end;
|
||||
} else {
|
||||
stripe->status = ReadDataStatus_Error;
|
||||
}
|
||||
|
||||
end:
|
||||
complete = TRUE;
|
||||
|
||||
for (i = 0; i < context->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadDataStatus_Pending || context->stripes[i].status == ReadDataStatus_Cancelling) {
|
||||
complete = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (complete)
|
||||
KeSetEvent(&context->Event, 0, FALSE);
|
||||
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL read_data(device_extension* Vcb, UINT64 addr, UINT32 length, UINT8* buf) {
|
||||
CHUNK_ITEM* ci;
|
||||
CHUNK_ITEM_STRIPE* cis;
|
||||
read_data_context* context;
|
||||
UINT64 i/*, type*/, offset;
|
||||
NTSTATUS Status;
|
||||
device** devices;
|
||||
|
||||
// FIXME - make this work with RAID
|
||||
|
||||
if (Vcb->log_to_phys_loaded) {
|
||||
chunk* c = get_chunk_from_address(Vcb, addr);
|
||||
|
||||
if (!c) {
|
||||
ERR("get_chunk_from_address failed\n");
|
||||
return STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ci = c->chunk_item;
|
||||
offset = c->offset;
|
||||
devices = c->devices;
|
||||
}
|
||||
|
||||
// if (ci->type & BLOCK_FLAG_DUPLICATE) {
|
||||
// type = BLOCK_FLAG_DUPLICATE;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID0) {
|
||||
// FIXME("RAID0 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID1) {
|
||||
// FIXME("RAID1 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID10) {
|
||||
// FIXME("RAID10 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID5) {
|
||||
// FIXME("RAID5 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else if (ci->type & BLOCK_FLAG_RAID6) {
|
||||
// FIXME("RAID6 not yet supported\n");
|
||||
// return STATUS_NOT_IMPLEMENTED;
|
||||
// } else { // SINGLE
|
||||
// type = 0;
|
||||
// }
|
||||
|
||||
cis = (CHUNK_ITEM_STRIPE*)&ci[1];
|
||||
|
||||
context = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_data_context), ALLOC_TAG);
|
||||
if (!context) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(context, sizeof(read_data_context));
|
||||
KeInitializeEvent(&context->Event, NotificationEvent, FALSE);
|
||||
|
||||
context->stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_data_stripe) * ci->num_stripes, ALLOC_TAG);
|
||||
if (!context->stripes) {
|
||||
ERR("out of memory\n");
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlZeroMemory(context->stripes, sizeof(read_data_stripe) * ci->num_stripes);
|
||||
|
||||
context->buflen = length;
|
||||
context->num_stripes = ci->num_stripes;
|
||||
// context->type = type;
|
||||
|
||||
// FIXME - for RAID, check beforehand whether there's enough devices to satisfy request
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
if (!devices[i]) {
|
||||
context->stripes[i].status = ReadDataStatus_MissingDevice;
|
||||
context->stripes[i].buf = NULL;
|
||||
} else {
|
||||
context->stripes[i].context = (struct read_data_context*)context;
|
||||
context->stripes[i].buf = ExAllocatePoolWithTag(NonPagedPool, length, ALLOC_TAG);
|
||||
|
||||
if (!context->stripes[i].buf) {
|
||||
ERR("out of memory\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
context->stripes[i].Irp = IoAllocateIrp(devices[i]->devobj->StackSize, FALSE);
|
||||
|
||||
if (!context->stripes[i].Irp) {
|
||||
ERR("IoAllocateIrp failed\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
IrpSp = IoGetNextIrpStackLocation(context->stripes[i].Irp);
|
||||
IrpSp->MajorFunction = IRP_MJ_READ;
|
||||
|
||||
if (devices[i]->devobj->Flags & DO_BUFFERED_IO) {
|
||||
FIXME("FIXME - buffered IO\n");
|
||||
} else if (devices[i]->devobj->Flags & DO_DIRECT_IO) {
|
||||
context->stripes[i].Irp->MdlAddress = IoAllocateMdl(context->stripes[i].buf, length, FALSE, FALSE, NULL);
|
||||
if (!context->stripes[i].Irp->MdlAddress) {
|
||||
ERR("IoAllocateMdl failed\n");
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
MmProbeAndLockPages(context->stripes[i].Irp->MdlAddress, KernelMode, IoWriteAccess);
|
||||
} else {
|
||||
context->stripes[i].Irp->UserBuffer = context->stripes[i].buf;
|
||||
}
|
||||
|
||||
IrpSp->Parameters.Read.Length = length;
|
||||
IrpSp->Parameters.Read.ByteOffset.QuadPart = addr - offset + cis[i].offset;
|
||||
|
||||
context->stripes[i].Irp->UserIosb = &context->stripes[i].iosb;
|
||||
|
||||
IoSetCompletionRoutine(context->stripes[i].Irp, read_data_completion, &context->stripes[i], TRUE, TRUE, TRUE);
|
||||
|
||||
context->stripes[i].status = ReadDataStatus_Pending;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status != ReadDataStatus_MissingDevice) {
|
||||
IoCallDriver(devices[i]->devobj, context->stripes[i].Irp);
|
||||
}
|
||||
}
|
||||
|
||||
KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
// FIXME - if checksum error, write good data over bad
|
||||
|
||||
// check if any of the stripes succeeded
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadDataStatus_Success) {
|
||||
RtlCopyMemory(buf, context->stripes[i].buf, length);
|
||||
Status = STATUS_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// if not, see if we got a checksum error
|
||||
|
||||
// for (i = 0; i < ci->num_stripes; i++) {
|
||||
// if (context->stripes[i].status == ReadDataStatus_CRCError) {
|
||||
// WARN("stripe %llu had a checksum error\n", i);
|
||||
//
|
||||
// Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
|
||||
// goto exit;
|
||||
// }
|
||||
// }
|
||||
|
||||
// failing that, return the first error we encountered
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].status == ReadDataStatus_Error) {
|
||||
Status = context->stripes[i].iosb.Status;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// if we somehow get here, return STATUS_INTERNAL_ERROR
|
||||
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
|
||||
exit:
|
||||
|
||||
for (i = 0; i < ci->num_stripes; i++) {
|
||||
if (context->stripes[i].Irp) {
|
||||
if (devices[i]->devobj->Flags & DO_DIRECT_IO) {
|
||||
MmUnlockPages(context->stripes[i].Irp->MdlAddress);
|
||||
IoFreeMdl(context->stripes[i].Irp->MdlAddress);
|
||||
}
|
||||
IoFreeIrp(context->stripes[i].Irp);
|
||||
}
|
||||
|
||||
if (context->stripes[i].buf)
|
||||
ExFreePool(context->stripes[i].buf);
|
||||
}
|
||||
|
||||
ExFreePool(context->stripes);
|
||||
ExFreePool(context);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS STDCALL read_stream(fcb* fcb, UINT8* data, UINT64 start, ULONG length, ULONG* pbr) {
|
||||
UINT8* xattrdata;
|
||||
UINT16 xattrlen;
|
||||
ULONG readlen;
|
||||
NTSTATUS Status;
|
||||
|
||||
TRACE("(%p, %p, %llx, %llx, %p)\n", fcb, data, start, length, pbr);
|
||||
|
||||
if (pbr) *pbr = 0;
|
||||
|
||||
if (!get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, fcb->adsxattr.Buffer, fcb->adshash, &xattrdata, &xattrlen)) {
|
||||
ERR("get_xattr failed\n");
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (start >= xattrlen) {
|
||||
TRACE("tried to read beyond end of stream\n");
|
||||
Status = STATUS_END_OF_FILE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
WARN("tried to read zero bytes\n");
|
||||
Status = STATUS_SUCCESS;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (start + length < xattrlen)
|
||||
readlen = length;
|
||||
else
|
||||
readlen = (ULONG)xattrlen - (ULONG)start;
|
||||
|
||||
RtlCopyMemory(data + start, xattrdata, readlen);
|
||||
|
||||
if (pbr) *pbr = readlen;
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
ExFreePool(xattrdata);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UINT8* data, UINT64 start, UINT64 length, ULONG* pbr) {
|
||||
KEY searchkey;
|
||||
NTSTATUS Status;
|
||||
traverse_ptr tp, next_tp;
|
||||
EXTENT_DATA* ed;
|
||||
UINT64 bytes_read = 0;
|
||||
|
||||
TRACE("(%p, %llx, %llx, %p, %llx, %llx, %p)\n", Vcb, subvol->id, inode, data, start, length, pbr);
|
||||
|
||||
if (pbr)
|
||||
*pbr = 0;
|
||||
|
||||
searchkey.obj_id = inode;
|
||||
searchkey.obj_type = TYPE_EXTENT_DATA;
|
||||
searchkey.offset = start;
|
||||
|
||||
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (tp.item->key.offset > start) {
|
||||
ERR("first EXTENT_DATA was after offset\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_INTERNAL_ERROR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// while (TRUE) {
|
||||
// BOOL foundnext = find_next_item(Vcb, &tp, &next_tp, NULL, FALSE);
|
||||
//
|
||||
// if (!foundnext || next_tp.item->key.obj_id != inode ||
|
||||
// next_tp.item->key.obj_type != TYPE_EXTENT_DATA || next_tp.item->key.offset > start) {
|
||||
// if (foundnext)
|
||||
// free_traverse_ptr(&next_tp);
|
||||
//
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// free_traverse_ptr(&tp);
|
||||
// tp = next_tp;
|
||||
// }
|
||||
|
||||
do {
|
||||
ed = (EXTENT_DATA*)tp.item->data;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (tp.item->key.offset + ed->decoded_size < 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;
|
||||
}
|
||||
|
||||
switch (ed->type) {
|
||||
case EXTENT_TYPE_INLINE:
|
||||
{
|
||||
UINT64 off = start + bytes_read - tp.item->key.offset;
|
||||
UINT64 read;
|
||||
|
||||
read = ed->decoded_size - off;
|
||||
if (read > length) read = length;
|
||||
|
||||
RtlCopyMemory(data + bytes_read, &ed->data[off], read);
|
||||
|
||||
bytes_read += read;
|
||||
length -= read;
|
||||
break;
|
||||
}
|
||||
|
||||
case EXTENT_TYPE_REGULAR:
|
||||
{
|
||||
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
|
||||
UINT64 off = start + bytes_read - tp.item->key.offset;
|
||||
UINT32 to_read, read;
|
||||
UINT8* buf;
|
||||
|
||||
read = ed->decoded_size - off;
|
||||
if (read > length) read = length;
|
||||
|
||||
if (ed2->address == 0) {
|
||||
RtlZeroMemory(data + bytes_read, read);
|
||||
} else {
|
||||
to_read = sector_align(read, Vcb->superblock.sector_size);
|
||||
|
||||
buf = ExAllocatePoolWithTag(PagedPool, to_read, ALLOC_TAG);
|
||||
|
||||
if (!buf) {
|
||||
ERR("out of memory\n");
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// FIXME - load checksums
|
||||
|
||||
Status = read_data(Vcb, ed2->address + ed2->offset + off, to_read, buf);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("read_data returned %08x\n", Status);
|
||||
ExFreePool(buf);
|
||||
free_traverse_ptr(&tp);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RtlCopyMemory(data + bytes_read, buf, read);
|
||||
|
||||
ExFreePool(buf);
|
||||
}
|
||||
|
||||
bytes_read += read;
|
||||
length -= read;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case EXTENT_TYPE_PREALLOC:
|
||||
{
|
||||
UINT64 off = start + bytes_read - tp.item->key.offset;
|
||||
UINT32 read;
|
||||
|
||||
read = ed->decoded_size - off;
|
||||
if (read > length) read = length;
|
||||
|
||||
RtlZeroMemory(data + bytes_read, read);
|
||||
|
||||
bytes_read += read;
|
||||
length -= read;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
WARN("Unsupported extent data type %u\n", ed->type);
|
||||
free_traverse_ptr(&tp);
|
||||
Status = STATUS_NOT_IMPLEMENTED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
BOOL foundnext = find_next_item(Vcb, &tp, &next_tp, FALSE);
|
||||
|
||||
if (!foundnext)
|
||||
break;
|
||||
else if (next_tp.item->key.obj_id != inode ||
|
||||
next_tp.item->key.obj_type != TYPE_EXTENT_DATA ||
|
||||
next_tp.item->key.offset != tp.item->key.offset + ed->decoded_size
|
||||
) {
|
||||
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;
|
||||
|
||||
exit:
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
UINT8* data;
|
||||
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
UINT64 start;
|
||||
ULONG length, bytes_read;
|
||||
NTSTATUS Status;
|
||||
BOOL top_level;
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
top_level = is_top_level(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;
|
||||
|
||||
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;
|
||||
|
||||
if (!fcb || !fcb->Vcb || !fcb->subvol) {
|
||||
Status = STATUS_INTERNAL_ERROR; // FIXME - invalid param error?
|
||||
goto exit;
|
||||
}
|
||||
|
||||
TRACE("file = %.*S (fcb = %p)\n", fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, 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 (!(Irp->Flags & IRP_PAGING_IO) && !FsRtlCheckLockForReadAccess(&fcb->lock, Irp)) {
|
||||
WARN("tried to read locked region\n");
|
||||
Status = STATUS_FILE_LOCK_CONFLICT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (length == 0) {
|
||||
WARN("tried to read zero bytes\n");
|
||||
Status = STATUS_SUCCESS;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (start >= fcb->Header.FileSize.QuadPart) {
|
||||
TRACE("tried to read with offset after file end (%llx >= %llx)\n", start, fcb->Header.FileSize.QuadPart);
|
||||
Status = STATUS_END_OF_FILE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
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)) {
|
||||
BOOL wait;
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
// try {
|
||||
if (!FileObject->PrivateCacheMap) {
|
||||
CC_FILE_SIZES ccfs;
|
||||
|
||||
ccfs.AllocationSize = fcb->Header.AllocationSize;
|
||||
ccfs.FileSize = fcb->Header.FileSize;
|
||||
ccfs.ValidDataLength = fcb->Header.ValidDataLength;
|
||||
|
||||
TRACE("calling CcInitializeCacheMap (%llx, %llx, %llx)\n",
|
||||
ccfs.AllocationSize.QuadPart, ccfs.FileSize.QuadPart, ccfs.ValidDataLength.QuadPart);
|
||||
CcInitializeCacheMap(FileObject, &ccfs, FALSE, cache_callbacks, FileObject);
|
||||
|
||||
CcSetReadAheadGranularity(FileObject, READ_AHEAD_GRANULARITY);
|
||||
}
|
||||
|
||||
// FIXME - uncomment this when async is working
|
||||
// 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;
|
||||
}
|
||||
TRACE("CcCopyRead finished\n");
|
||||
// } except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
// Status = GetExceptionCode();
|
||||
// }
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
Status = Irp->IoStatus.Status;
|
||||
bytes_read = Irp->IoStatus.Information;
|
||||
} else
|
||||
ERR("EXCEPTION - %08x\n", Status);
|
||||
} else {
|
||||
if (!(Irp->Flags & IRP_PAGING_IO) && FileObject->SectionObjectPointer->DataSectionObject) {
|
||||
IO_STATUS_BLOCK iosb;
|
||||
|
||||
CcFlushCache(FileObject->SectionObjectPointer, &IrpSp->Parameters.Read.ByteOffset, length, &iosb);
|
||||
|
||||
if (!NT_SUCCESS(iosb.Status)) {
|
||||
ERR("CcFlushCache returned %08x\n", iosb.Status);
|
||||
Status = iosb.Status;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
acquire_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
if (fcb->ads)
|
||||
Status = read_stream(fcb, data, start, length, &bytes_read);
|
||||
else
|
||||
Status = read_file(fcb->Vcb, fcb->subvol, fcb->inode, data, start, length, &bytes_read);
|
||||
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
TRACE("read %u bytes\n", bytes_read);
|
||||
|
||||
Irp->IoStatus.Information = bytes_read;
|
||||
}
|
||||
|
||||
exit:
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
||||
if (FileObject->Flags & FO_SYNCHRONOUS_IO && !(Irp->Flags & IRP_PAGING_IO))
|
||||
FileObject->CurrentByteOffset.QuadPart = start + (NT_SUCCESS(Status) ? bytes_read : 0);
|
||||
|
||||
TRACE("Irp->IoStatus.Status = %08x\n", Irp->IoStatus.Status);
|
||||
TRACE("Irp->IoStatus.Information = %lu\n", Irp->IoStatus.Information);
|
||||
TRACE("returning %08x\n", Status);
|
||||
|
||||
if (Status != STATUS_PENDING)
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
|
||||
if (top_level)
|
||||
IoSetTopLevelIrp(NULL);
|
||||
|
||||
FsRtlExitFileSystem();
|
||||
|
||||
return Status;
|
||||
}
|
605
reactos/drivers/filesystems/btrfs/reparse.c
Normal file
605
reactos/drivers/filesystems/btrfs/reparse.c
Normal file
|
@ -0,0 +1,605 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
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;
|
||||
DWORD reqlen;
|
||||
REPARSE_DATA_BUFFER* rdb = buffer;
|
||||
fcb* fcb = FileObject->FsContext;
|
||||
char* data;
|
||||
NTSTATUS Status;
|
||||
|
||||
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 (!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);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
end:
|
||||
release_tree_lock(fcb->Vcb, FALSE);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
static NTSTATUS change_file_type(device_extension* Vcb, UINT64 inode, root* subvol, UINT64 parinode, UINT64 index, PANSI_STRING utf8, UINT8 type, LIST_ENTRY* rollback) {
|
||||
KEY searchkey;
|
||||
UINT32 crc32;
|
||||
traverse_ptr tp;
|
||||
NTSTATUS Status;
|
||||
|
||||
crc32 = calc_crc32c(0xfffffffe, (UINT8*)utf8->Buffer, (ULONG)utf8->Length);
|
||||
|
||||
searchkey.obj_id = parinode;
|
||||
searchkey.obj_type = TYPE_DIR_ITEM;
|
||||
searchkey.offset = crc32;
|
||||
|
||||
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!keycmp(&tp.item->key, &searchkey)) {
|
||||
if (tp.item->size < sizeof(DIR_ITEM)) {
|
||||
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
|
||||
} else {
|
||||
DIR_ITEM *di = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG), *di2;
|
||||
BOOL found = FALSE;
|
||||
ULONG len = tp.item->size;
|
||||
|
||||
if (!di) {
|
||||
ERR("out of memory\n");
|
||||
free_traverse_ptr(&tp);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(di, tp.item->data, tp.item->size);
|
||||
|
||||
di2 = di;
|
||||
do {
|
||||
if (len < sizeof(DIR_ITEM) || len < sizeof(DIR_ITEM) - 1 + di2->m + di2->n) {
|
||||
ERR("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
if (di2->n == utf8->Length && RtlCompareMemory(di2->name, utf8->Buffer, utf8->Length) == utf8->Length) {
|
||||
di2->type = type;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > sizeof(DIR_ITEM) - sizeof(char) + di2->m + di2->n) {
|
||||
len -= sizeof(DIR_ITEM) - sizeof(char) + di2->m + di2->n;
|
||||
di2 = (DIR_ITEM*)&di2->name[di2->m + di2->n];
|
||||
} else
|
||||
break;
|
||||
} while (len > 0);
|
||||
|
||||
if (found) {
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, di, tp.item->size, NULL, rollback);
|
||||
} else
|
||||
ExFreePool(di);
|
||||
}
|
||||
} else {
|
||||
WARN("search for DIR_ITEM by crc32 failed\n");
|
||||
}
|
||||
|
||||
free_traverse_ptr(&tp);
|
||||
|
||||
searchkey.obj_id = parinode;
|
||||
searchkey.obj_type = TYPE_DIR_INDEX;
|
||||
searchkey.offset = index;
|
||||
|
||||
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - find_item returned %08x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (!keycmp(&tp.item->key, &searchkey)) {
|
||||
if (tp.item->size < sizeof(DIR_ITEM)) {
|
||||
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
|
||||
} else {
|
||||
DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
|
||||
DIR_ITEM* di2 = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
|
||||
if (!di2) {
|
||||
ERR("out of memory\n");
|
||||
free_traverse_ptr(&tp);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
RtlCopyMemory(di2, di, tp.item->size);
|
||||
di2->type = type;
|
||||
|
||||
delete_tree_item(Vcb, &tp, rollback);
|
||||
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, di2, tp.item->size, NULL, rollback);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
subname.Buffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)];
|
||||
subname.MaximumLength = subname.Length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||
|
||||
ERR("substitute name = %.*S\n", subname.Length / sizeof(WCHAR), subname.Buffer);
|
||||
|
||||
fcb->type = BTRFS_TYPE_SYMLINK;
|
||||
|
||||
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);
|
||||
goto end;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_REF) {
|
||||
if (tp.item->size < sizeof(INODE_REF)) {
|
||||
WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(INODE_REF));
|
||||
} else {
|
||||
INODE_REF* ir;
|
||||
ULONG size = tp.item->size;
|
||||
ANSI_STRING utf8;
|
||||
|
||||
ir = (INODE_REF*)tp.item->data;
|
||||
|
||||
do {
|
||||
if (size < sizeof(INODE_REF) || size < sizeof(INODE_REF) - 1 + ir->n) {
|
||||
WARN("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
utf8.Buffer = ir->name;
|
||||
utf8.Length = utf8.MaximumLength = ir->n;
|
||||
|
||||
Status = change_file_type(fcb->Vcb, fcb->inode, fcb->subvol, tp.item->key.offset, ir->index, &utf8, BTRFS_TYPE_SYMLINK, &rollback);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - change_file_type returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
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);
|
||||
goto end;
|
||||
}
|
||||
|
||||
do {
|
||||
if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_INODE_EXTREF) {
|
||||
if (tp.item->size < sizeof(INODE_EXTREF)) {
|
||||
WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(INODE_EXTREF));
|
||||
} else {
|
||||
INODE_EXTREF* ier;
|
||||
ULONG size = tp.item->size;
|
||||
ANSI_STRING utf8;
|
||||
|
||||
ier = (INODE_EXTREF*)tp.item->data;
|
||||
|
||||
do {
|
||||
if (size < sizeof(INODE_EXTREF) || size < sizeof(INODE_EXTREF) - 1 + ier->n) {
|
||||
WARN("(%llx,%x,%llx) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
|
||||
break;
|
||||
}
|
||||
|
||||
utf8.Buffer = ier->name;
|
||||
utf8.Length = utf8.MaximumLength = ier->n;
|
||||
|
||||
Status = change_file_type(fcb->Vcb, fcb->inode, fcb->subvol, ier->dir, ier->index, &utf8, BTRFS_TYPE_SYMLINK, &rollback);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("error - change_file_type returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("truncate_file returned %08x\n", Status);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (i = 0; i < target.Length; i++) {
|
||||
if (target.Buffer[i] == '\\')
|
||||
target.Buffer[i] = '/';
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ExFreePool(target.Buffer);
|
||||
|
||||
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;
|
||||
}
|
14
reactos/drivers/filesystems/btrfs/resource.h
Normal file
14
reactos/drivers/filesystems/btrfs/resource.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by btrfs.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
332
reactos/drivers/filesystems/btrfs/search.c
Normal file
332
reactos/drivers/filesystems/btrfs/search.c
Normal file
|
@ -0,0 +1,332 @@
|
|||
/* Copyright (c) Mark Harmstone 2016
|
||||
*
|
||||
* This file is part of WinBtrfs.
|
||||
*
|
||||
* WinBtrfs is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public Licence as published by
|
||||
* the Free Software Foundation, either version 3 of the Licence, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* WinBtrfs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public Licence for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public Licence
|
||||
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "btrfs_drv.h"
|
||||
|
||||
#ifndef __REACTOS__
|
||||
#include <ntddk.h>
|
||||
#include <ntifs.h>
|
||||
#include <mountmgr.h>
|
||||
#include <windef.h>
|
||||
#endif
|
||||
|
||||
#include <initguid.h>
|
||||
#ifndef __REACTOS__
|
||||
#include <winioctl.h>
|
||||
#endif
|
||||
#include <wdmguid.h>
|
||||
|
||||
#ifndef __REACTOS__
|
||||
typedef struct _OBJECT_DIRECTORY_INFORMATION {
|
||||
UNICODE_STRING Name;
|
||||
UNICODE_STRING TypeName;
|
||||
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
|
||||
#endif
|
||||
|
||||
#if !defined (_GNU_NTIFS_) || defined(__REACTOS__)
|
||||
NTSTATUS WINAPI ZwQueryDirectoryObject(HANDLE DirectoryHandle, PVOID Buffer, ULONG Length,
|
||||
BOOLEAN ReturnSingleEntry, BOOLEAN RestartScan, PULONG Context,
|
||||
PULONG ReturnLength);
|
||||
#endif
|
||||
|
||||
VOID WINAPI IopNotifyPlugPlayNotification(
|
||||
IN PDEVICE_OBJECT DeviceObject,
|
||||
IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
|
||||
IN LPCGUID Event,
|
||||
IN PVOID EventCategoryData1,
|
||||
IN PVOID EventCategoryData2
|
||||
);
|
||||
|
||||
static const WCHAR devpath[] = {'\\','D','e','v','i','c','e',0};
|
||||
|
||||
static void STDCALL add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
|
||||
ULONG tnsize;
|
||||
MOUNTMGR_TARGET_NAME* tn;
|
||||
KEVENT Event;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
PIRP Irp;
|
||||
NTSTATUS Status;
|
||||
ULONG mmdltsize;
|
||||
MOUNTMGR_DRIVE_LETTER_TARGET* mmdlt;
|
||||
MOUNTMGR_DRIVE_LETTER_INFORMATION mmdli;
|
||||
|
||||
TRACE("found BTRFS volume\n");
|
||||
|
||||
tnsize = sizeof(MOUNTMGR_TARGET_NAME) - sizeof(WCHAR) + us->Length;
|
||||
tn = ExAllocatePoolWithTag(NonPagedPool, tnsize, ALLOC_TAG);
|
||||
if (!tn) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tn->DeviceNameLength = us->Length;
|
||||
RtlCopyMemory(tn->DeviceName, us->Buffer, tn->DeviceNameLength);
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
|
||||
mountmgr, tn, tnsize,
|
||||
NULL, 0, FALSE, &Event, &IoStatusBlock);
|
||||
if (!Irp) {
|
||||
ERR("IoBuildDeviceIoControlRequest failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Status = IoCallDriver(mountmgr, Irp);
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
ERR("IoCallDriver (1) returned %08x\n", Status);
|
||||
|
||||
ExFreePool(tn);
|
||||
|
||||
mmdltsize = sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) - 1 + us->Length;
|
||||
|
||||
mmdlt = ExAllocatePoolWithTag(NonPagedPool, mmdltsize, ALLOC_TAG);
|
||||
if (!mmdlt) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mmdlt->DeviceNameLength = us->Length;
|
||||
RtlCopyMemory(&mmdlt->DeviceName, us->Buffer, us->Length);
|
||||
TRACE("mmdlt = %.*S\n", mmdlt->DeviceNameLength / sizeof(WCHAR), mmdlt->DeviceName);
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
|
||||
mountmgr, mmdlt, mmdltsize,
|
||||
&mmdli, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION), FALSE, &Event, &IoStatusBlock);
|
||||
if (!Irp) {
|
||||
ERR("IoBuildDeviceIoControlRequest failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Status = IoCallDriver(mountmgr, Irp);
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
ERR("IoCallDriver (2) returned %08x\n", Status);
|
||||
else
|
||||
TRACE("DriveLetterWasAssigned = %u, CurrentDriveLetter = %c\n", mmdli.DriveLetterWasAssigned, mmdli.CurrentDriveLetter);
|
||||
|
||||
ExFreePool(mmdlt);
|
||||
}
|
||||
|
||||
static void STDCALL test_vol(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us, LIST_ENTRY* volumes) {
|
||||
KEVENT Event;
|
||||
PIRP Irp;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
NTSTATUS Status;
|
||||
PFILE_OBJECT FileObject;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
LARGE_INTEGER Offset;
|
||||
ULONG toread;
|
||||
UINT8* data;
|
||||
UNICODE_STRING us2;
|
||||
BOOL added_entry = FALSE;
|
||||
|
||||
TRACE("%.*S\n", us->Length / sizeof(WCHAR), us->Buffer);
|
||||
|
||||
us2.Length = ((wcslen(devpath) + 1) * sizeof(WCHAR)) + us->Length;
|
||||
us2.MaximumLength = us2.Length;
|
||||
us2.Buffer = ExAllocatePoolWithTag(PagedPool, us2.Length, ALLOC_TAG);
|
||||
if (!us2.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(us2.Buffer, devpath, wcslen(devpath) * sizeof(WCHAR));
|
||||
us2.Buffer[wcslen(devpath)] = '\\';
|
||||
RtlCopyMemory(&us2.Buffer[wcslen(devpath)+1], us->Buffer, us->Length);
|
||||
|
||||
TRACE("%.*S\n", us2.Length / sizeof(WCHAR), us2.Buffer);
|
||||
|
||||
Status = IoGetDeviceObjectPointer(&us2, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
||||
|
||||
Offset.QuadPart = superblock_addrs[0];
|
||||
|
||||
toread = sector_align(sizeof(superblock), DeviceObject->SectorSize);
|
||||
data = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
|
||||
if (!data) {
|
||||
ERR("out of memory\n");
|
||||
goto deref;
|
||||
}
|
||||
|
||||
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, data, toread, &Offset, &Event, &IoStatusBlock);
|
||||
|
||||
if (!Irp) {
|
||||
ERR("IoBuildSynchronousFsdRequest failed\n");
|
||||
goto deref;
|
||||
}
|
||||
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
|
||||
if (Status == STATUS_PENDING) {
|
||||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||||
Status = IoStatusBlock.Status;
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status) && IoStatusBlock.Information > 0 && ((superblock*)data)->magic == BTRFS_MAGIC) {
|
||||
superblock* sb = (superblock*)data;
|
||||
volume* v = ExAllocatePoolWithTag(PagedPool, sizeof(volume), ALLOC_TAG);
|
||||
if (!v) {
|
||||
ERR("out of memory\n");
|
||||
goto deref;
|
||||
}
|
||||
|
||||
v->devobj = DeviceObject;
|
||||
RtlCopyMemory(&v->fsuuid, &sb->uuid, sizeof(BTRFS_UUID));
|
||||
RtlCopyMemory(&v->devuuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID));
|
||||
v->devnum = sb->dev_item.dev_id;
|
||||
v->devpath = us2;
|
||||
v->processed = FALSE;
|
||||
InsertTailList(volumes, &v->list_entry);
|
||||
|
||||
TRACE("volume found\n");
|
||||
TRACE("FS uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
|
||||
v->fsuuid.uuid[0], v->fsuuid.uuid[1], v->fsuuid.uuid[2], v->fsuuid.uuid[3], v->fsuuid.uuid[4], v->fsuuid.uuid[5], v->fsuuid.uuid[6], v->fsuuid.uuid[7],
|
||||
v->fsuuid.uuid[8], v->fsuuid.uuid[9], v->fsuuid.uuid[10], v->fsuuid.uuid[11], v->fsuuid.uuid[12], v->fsuuid.uuid[13], v->fsuuid.uuid[14], v->fsuuid.uuid[15]);
|
||||
TRACE("device uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
|
||||
v->devuuid.uuid[0], v->devuuid.uuid[1], v->devuuid.uuid[2], v->devuuid.uuid[3], v->devuuid.uuid[4], v->devuuid.uuid[5], v->devuuid.uuid[6], v->devuuid.uuid[7],
|
||||
v->devuuid.uuid[8], v->devuuid.uuid[9], v->devuuid.uuid[10], v->devuuid.uuid[11], v->devuuid.uuid[12], v->devuuid.uuid[13], v->devuuid.uuid[14], v->devuuid.uuid[15]);
|
||||
TRACE("device number %llx\n", v->devnum);
|
||||
|
||||
added_entry = TRUE;
|
||||
}
|
||||
|
||||
deref:
|
||||
ExFreePool(data);
|
||||
ObDereferenceObject(FileObject);
|
||||
|
||||
exit:
|
||||
if (!added_entry)
|
||||
ExFreePool(us2.Buffer);
|
||||
}
|
||||
|
||||
void STDCALL look_for_vols(LIST_ENTRY* volumes) {
|
||||
PFILE_OBJECT FileObject;
|
||||
PDEVICE_OBJECT mountmgr;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
UNICODE_STRING mmdevpath, us;
|
||||
HANDLE h;
|
||||
OBJECT_DIRECTORY_INFORMATION* odi;
|
||||
ULONG odisize;
|
||||
ULONG context;
|
||||
BOOL restart;
|
||||
NTSTATUS Status;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
static const WCHAR hdv[] = {'H','a','r','d','d','i','s','k','V','o','l','u','m','e',0};
|
||||
static const WCHAR device[] = {'D','e','v','i','c','e',0};
|
||||
|
||||
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
|
||||
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr);
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&us, devpath);
|
||||
|
||||
attr.Length = sizeof(attr);
|
||||
attr.RootDirectory = 0;
|
||||
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
||||
attr.ObjectName = &us;
|
||||
attr.SecurityDescriptor = NULL;
|
||||
attr.SecurityQualityOfService = NULL;
|
||||
|
||||
Status = ZwOpenDirectoryObject(&h, DIRECTORY_TRAVERSE, &attr);
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
ERR("ZwOpenDirectoryObject returned %08x\n", Status);
|
||||
return;
|
||||
}
|
||||
|
||||
odisize = sizeof(OBJECT_DIRECTORY_INFORMATION) * 16;
|
||||
odi = ExAllocatePoolWithTag(PagedPool, odisize, ALLOC_TAG);
|
||||
if (!odi) {
|
||||
ERR("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
restart = TRUE;
|
||||
do {
|
||||
Status = ZwQueryDirectoryObject(h, odi, odisize, FALSE, restart, &context, NULL/*&retlen*/);
|
||||
restart = FALSE;
|
||||
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
if (Status != STATUS_NO_MORE_ENTRIES)
|
||||
ERR("ZwQueryDirectoryObject returned %08x\n", Status);
|
||||
} else {
|
||||
OBJECT_DIRECTORY_INFORMATION* odi2 = odi;
|
||||
|
||||
while (odi2->Name.Buffer) {
|
||||
if (odi2->TypeName.Length == wcslen(device) * sizeof(WCHAR) &&
|
||||
RtlCompareMemory(odi2->TypeName.Buffer, device, wcslen(device) * sizeof(WCHAR)) == wcslen(device) * sizeof(WCHAR) &&
|
||||
odi2->Name.Length > wcslen(hdv) * sizeof(WCHAR) &&
|
||||
RtlCompareMemory(odi2->Name.Buffer, hdv, wcslen(hdv) * sizeof(WCHAR)) == wcslen(hdv) * sizeof(WCHAR)) {
|
||||
test_vol(mountmgr, &odi2->Name, volumes);
|
||||
}
|
||||
odi2 = &odi2[1];
|
||||
}
|
||||
}
|
||||
} while (NT_SUCCESS(Status));
|
||||
|
||||
ZwClose(h);
|
||||
|
||||
// FIXME - if Windows has already added the second device of a filesystem itself, delete it
|
||||
|
||||
le = volumes->Flink;
|
||||
while (le != volumes) {
|
||||
volume* v = CONTAINING_RECORD(le, volume, list_entry);
|
||||
|
||||
if (!v->processed) {
|
||||
LIST_ENTRY* le2 = le;
|
||||
volume* mountvol = v;
|
||||
|
||||
while (le2 != volumes) {
|
||||
volume* v2 = CONTAINING_RECORD(le2, volume, list_entry);
|
||||
|
||||
if (RtlCompareMemory(&v2->fsuuid, &v->fsuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
|
||||
v2->processed = TRUE;
|
||||
|
||||
if (v2->devnum < mountvol->devnum)
|
||||
mountvol = v2;
|
||||
}
|
||||
|
||||
le2 = le2->Flink;
|
||||
}
|
||||
|
||||
add_volume(mountmgr, &mountvol->devpath);
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
ObDereferenceObject(FileObject);
|
||||
}
|
1034
reactos/drivers/filesystems/btrfs/security.c
Normal file
1034
reactos/drivers/filesystems/btrfs/security.c
Normal file
File diff suppressed because it is too large
Load diff
1362
reactos/drivers/filesystems/btrfs/treefuncs.c
Normal file
1362
reactos/drivers/filesystems/btrfs/treefuncs.c
Normal file
File diff suppressed because it is too large
Load diff
6572
reactos/drivers/filesystems/btrfs/write.c
Normal file
6572
reactos/drivers/filesystems/btrfs/write.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue