2017-09-08 08:02:43 +00:00
/* Copyright (c) Mark Harmstone 2016-17
*
2016-03-23 20:35:05 +00:00
* This file is part of WinBtrfs .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* 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 .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* 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 .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs . If not , see < http : //www.gnu.org/licenses/>. */
# ifdef _DEBUG
# define DEBUG
# endif
# include "btrfs_drv.h"
# ifndef __REACTOS__
# ifndef _MSC_VER
# include <cpuid.h>
# else
# include <intrin.h>
# endif
# endif
2016-10-29 17:05:10 +00:00
# include <ntddscsi.h>
2016-03-23 20:35:05 +00:00
# include "btrfs.h"
2016-10-29 17:05:10 +00:00
# include <ata.h>
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
# ifndef _MSC_VER
# include <initguid.h>
# include <ntddstor.h>
# undef INITGUID
# endif
# include <ntdddisk.h>
# include <ntddvol.h>
# ifdef _MSC_VER
# include <initguid.h>
# include <ntddstor.h>
# undef INITGUID
# endif
2016-09-04 15:27:46 +00:00
# define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \
2016-10-29 17:05:10 +00:00
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \
BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES )
2017-09-08 08:02:43 +00:00
# define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)
2016-03-23 20:35:05 +00:00
static WCHAR device_name [ ] = { ' \\ ' , ' B ' , ' t ' , ' r ' , ' f ' , ' s ' , 0 } ;
static WCHAR dosdevice_name [ ] = { ' \\ ' , ' D ' , ' o ' , ' s ' , ' D ' , ' e ' , ' v ' , ' i ' , ' c ' , ' e ' , ' s ' , ' \\ ' , ' B ' , ' t ' , ' r ' , ' f ' , ' s ' , 0 } ;
2017-09-08 08:02:43 +00:00
DEFINE_GUID ( BtrfsBusInterface , 0x4d414874 , 0x6865 , 0x6761 , 0x6d , 0x65 , 0x83 , 0x69 , 0x17 , 0x9a , 0x7d , 0x1d ) ;
2016-03-23 20:35:05 +00:00
PDRIVER_OBJECT drvobj ;
2017-09-08 08:02:43 +00:00
PDEVICE_OBJECT master_devobj ;
2016-03-23 20:35:05 +00:00
# ifndef __REACTOS__
2016-10-29 17:05:10 +00:00
BOOL have_sse42 = FALSE , have_sse2 = FALSE ;
2016-03-23 20:35:05 +00:00
# endif
UINT64 num_reads = 0 ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY uid_map_list , gid_map_list ;
2016-03-23 20:35:05 +00:00
LIST_ENTRY VcbList ;
ERESOURCE global_loading_lock ;
UINT32 debug_log_level = 0 ;
2016-09-04 15:27:46 +00:00
UINT32 mount_compress = 0 ;
UINT32 mount_compress_force = 0 ;
UINT32 mount_compress_type = 0 ;
UINT32 mount_zlib_level = 3 ;
UINT32 mount_flush_interval = 30 ;
UINT32 mount_max_inline = 2048 ;
2017-01-01 17:12:12 +00:00
UINT32 mount_skip_balance = 0 ;
2017-09-08 08:02:43 +00:00
UINT32 mount_no_barrier = 0 ;
UINT32 mount_no_trim = 0 ;
UINT32 mount_clear_cache = 0 ;
UINT32 mount_allow_degraded = 0 ;
UINT32 mount_readonly = 0 ;
UINT32 no_pnp = 0 ;
2016-03-23 20:35:05 +00:00
BOOL log_started = FALSE ;
2016-07-27 19:24:26 +00:00
UNICODE_STRING log_device , log_file , registry_path ;
2017-09-08 08:02:43 +00:00
tPsUpdateDiskCounters fPsUpdateDiskCounters ;
tCcCopyReadEx fCcCopyReadEx ;
tCcCopyWriteEx fCcCopyWriteEx ;
tCcSetAdditionalCacheAttributesEx fCcSetAdditionalCacheAttributesEx ;
tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters ;
2017-01-01 17:12:12 +00:00
BOOL diskacc = FALSE ;
2017-09-08 08:02:43 +00:00
void * notification_entry = NULL , * notification_entry2 = NULL , * notification_entry3 = NULL ;
ERESOURCE pdo_list_lock , mapping_lock ;
LIST_ENTRY pdo_list ;
BOOL finished_probing = FALSE ;
HANDLE degraded_wait_handle = NULL , mountmgr_thread_handle = NULL ;
BOOL degraded_wait = TRUE ;
KEVENT mountmgr_thread_event ;
BOOL shutting_down = FALSE ;
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
PFILE_OBJECT comfo = NULL ;
PDEVICE_OBJECT comdo = NULL ;
HANDLE log_handle = NULL ;
2017-09-08 08:02:43 +00:00
ERESOURCE log_lock ;
HANDLE serial_thread_handle = NULL ;
static void init_serial ( BOOL first_time ) ;
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
static NTSTATUS close_file ( _In_ PFILE_OBJECT FileObject , _In_ PIRP Irp ) ;
2016-03-23 20:35:05 +00:00
typedef struct {
KEVENT Event ;
IO_STATUS_BLOCK iosb ;
} read_context ;
# ifdef _DEBUG
2017-09-08 08:02:43 +00:00
_Function_class_ ( IO_COMPLETION_ROUTINE )
static NTSTATUS dbg_completion ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp , _In_ PVOID conptr ) {
2016-03-23 20:35:05 +00:00
read_context * context = conptr ;
2017-09-08 08:02:43 +00:00
UNUSED ( DeviceObject ) ;
2016-03-23 20:35:05 +00:00
context - > iosb = Irp - > IoStatus ;
KeSetEvent ( & context - > Event , 0 , FALSE ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_MORE_PROCESSING_REQUIRED ;
}
# ifdef DEBUG_LONG_MESSAGES
2017-09-08 08:02:43 +00:00
void _debug_message ( _In_ const char * func , _In_ const char * file , _In_ unsigned int line , _In_ char * s , . . . ) {
2016-03-23 20:35:05 +00:00
# else
2017-09-08 08:02:43 +00:00
void _debug_message ( _In_ const char * func , _In_ char * s , . . . ) {
2016-03-23 20:35:05 +00:00
# endif
LARGE_INTEGER offset ;
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
PIRP Irp ;
va_list ap ;
2017-09-08 08:02:43 +00:00
char * buf2 , * buf ;
read_context context ;
2016-03-23 20:35:05 +00:00
UINT32 length ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
buf2 = ExAllocatePoolWithTag ( NonPagedPool , 1024 , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! buf2 ) {
DbgPrint ( " Couldn't allocate buffer in debug_message \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_LONG_MESSAGES
2017-09-08 08:02:43 +00:00
sprintf ( buf2 , " %p:%s:%s:%u: " , PsGetCurrentThread ( ) , func , file , line ) ;
2016-03-23 20:35:05 +00:00
# else
2017-09-08 08:02:43 +00:00
sprintf ( buf2 , " %p:%s: " , PsGetCurrentThread ( ) , func ) ;
2016-03-23 20:35:05 +00:00
# endif
buf = & buf2 [ strlen ( buf2 ) ] ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
va_start ( ap , s ) ;
vsprintf ( buf , s , ap ) ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceSharedLite ( & log_lock , TRUE ) ;
2016-03-23 20:35:05 +00:00
if ( ! log_started | | ( log_device . Length = = 0 & & log_file . Length = = 0 ) ) {
DbgPrint ( buf2 ) ;
} else if ( log_device . Length > 0 ) {
if ( ! comdo ) {
DbgPrint ( " comdo is NULL :-( \n " ) ;
DbgPrint ( buf2 ) ;
goto exit2 ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
length = ( UINT32 ) strlen ( buf2 ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
offset . u . LowPart = 0 ;
offset . u . HighPart = 0 ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( & context , sizeof ( read_context ) ) ;
KeInitializeEvent ( & context . Event , NotificationEvent , FALSE ) ;
2016-03-23 20:35:05 +00:00
Irp = IoAllocateIrp ( comdo - > StackSize , FALSE ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! Irp ) {
DbgPrint ( " IoAllocateIrp failed \n " ) ;
goto exit2 ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IrpSp = IoGetNextIrpStackLocation ( Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_WRITE ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( comdo - > Flags & DO_BUFFERED_IO ) {
Irp - > AssociatedIrp . SystemBuffer = buf2 ;
Irp - > Flags = IRP_BUFFERED_IO ;
} else if ( comdo - > Flags & DO_DIRECT_IO ) {
Irp - > MdlAddress = IoAllocateMdl ( buf2 , length , FALSE , FALSE , NULL ) ;
if ( ! Irp - > MdlAddress ) {
DbgPrint ( " IoAllocateMdl failed \n " ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
MmBuildMdlForNonPagedPool ( Irp - > MdlAddress ) ;
2016-03-23 20:35:05 +00:00
} else {
Irp - > UserBuffer = buf2 ;
}
IrpSp - > Parameters . Write . Length = length ;
IrpSp - > Parameters . Write . ByteOffset = offset ;
2017-09-08 08:02:43 +00:00
Irp - > UserIosb = & context . iosb ;
Irp - > UserEvent = & context . Event ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
IoSetCompletionRoutine ( Irp , dbg_completion , & context , TRUE , TRUE , TRUE ) ;
2016-03-23 20:35:05 +00:00
Status = IoCallDriver ( comdo , Irp ) ;
if ( Status = = STATUS_PENDING ) {
2017-09-08 08:02:43 +00:00
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , FALSE , NULL ) ;
Status = context . iosb . Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
if ( comdo - > Flags & DO_DIRECT_IO )
2016-03-23 20:35:05 +00:00
IoFreeMdl ( Irp - > MdlAddress ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
DbgPrint ( " failed to write to COM1 - error %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit :
IoFreeIrp ( Irp ) ;
} else if ( log_handle ! = NULL ) {
IO_STATUS_BLOCK iosb ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
length = ( UINT32 ) strlen ( buf2 ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwWriteFile ( log_handle , NULL , NULL , NULL , & iosb , buf2 , length , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
DbgPrint ( " failed to write to file - error %08x \n " , Status ) ;
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit2 :
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & log_lock ) ;
2016-03-23 20:35:05 +00:00
va_end ( ap ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( buf2 )
ExFreePool ( buf2 ) ;
}
# endif
2017-09-08 08:02:43 +00:00
BOOL is_top_level ( _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
if ( ! IoGetTopLevelIrp ( ) ) {
IoSetTopLevelIrp ( Irp ) ;
return TRUE ;
}
return FALSE ;
}
2017-09-08 08:02:43 +00:00
_Function_class_ ( DRIVER_UNLOAD )
# ifdef __REACTOS__
static void NTAPI DriverUnload ( _In_ PDRIVER_OBJECT DriverObject ) {
# else
static void DriverUnload ( _In_ PDRIVER_OBJECT DriverObject ) {
# endif
2016-03-23 20:35:05 +00:00
UNICODE_STRING dosdevice_nameW ;
ERR ( " DriverUnload \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
free_cache ( ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoUnregisterFileSystem ( DriverObject - > DeviceObject ) ;
2017-09-08 08:02:43 +00:00
if ( notification_entry2 )
# ifdef __REACTOS__
IoUnregisterPlugPlayNotification ( notification_entry2 ) ;
# else
IoUnregisterPlugPlayNotificationEx ( notification_entry2 ) ;
# endif
if ( notification_entry3 )
# ifdef __REACTOS__
IoUnregisterPlugPlayNotification ( notification_entry3 ) ;
# else
IoUnregisterPlugPlayNotificationEx ( notification_entry3 ) ;
# endif
2017-01-01 17:12:12 +00:00
if ( notification_entry )
# ifdef __REACTOS__
IoUnregisterPlugPlayNotification ( notification_entry ) ;
# else
IoUnregisterPlugPlayNotificationEx ( notification_entry ) ;
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
dosdevice_nameW . Buffer = dosdevice_name ;
dosdevice_nameW . Length = dosdevice_nameW . MaximumLength = ( USHORT ) wcslen ( dosdevice_name ) * sizeof ( WCHAR ) ;
IoDeleteSymbolicLink ( & dosdevice_nameW ) ;
IoDeleteDevice ( DriverObject - > DeviceObject ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( & uid_map_list ) ) {
LIST_ENTRY * le = RemoveHeadList ( & uid_map_list ) ;
uid_map * um = CONTAINING_RECORD ( le , uid_map , listentry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( um - > sid ) ;
ExFreePool ( um ) ;
}
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & gid_map_list ) ) {
gid_map * gm = CONTAINING_RECORD ( RemoveHeadList ( & gid_map_list ) , gid_map , listentry ) ;
ExFreePool ( gm - > sid ) ;
ExFreePool ( gm ) ;
}
2016-03-23 20:35:05 +00:00
// FIXME - free volumes and their devpaths
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
if ( comfo )
ObDereferenceObject ( comfo ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( log_handle )
ZwClose ( log_handle ) ;
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & global_loading_lock ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & pdo_list_lock ) ;
2016-03-23 20:35:05 +00:00
if ( log_device . Buffer )
ExFreePool ( log_device . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( log_file . Buffer )
ExFreePool ( log_file . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( registry_path . Buffer )
ExFreePool ( registry_path . Buffer ) ;
2017-09-08 08:02:43 +00:00
# ifdef _DEBUG
ExDeleteResourceLite ( & log_lock ) ;
# endif
ExDeleteResourceLite ( & mapping_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
static BOOL get_last_inode ( _In_ _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * r , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
KEY searchkey ;
traverse_ptr tp , prev_tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// get last entry
searchkey . obj_id = 0xffffffffffffffff ;
searchkey . obj_type = 0xff ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = find_item ( Vcb , r , & tp , & searchkey , FALSE , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
return FALSE ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( tp . item - > key . obj_type = = TYPE_INODE_ITEM | | ( tp . item - > key . obj_type = = TYPE_ROOT_ITEM & & ! ( tp . item - > key . obj_id & 0x8000000000000000 ) ) ) {
r - > lastinode = tp . item - > key . obj_id ;
TRACE ( " last inode for tree %llx is %llx \n " , r - > id , r - > lastinode ) ;
return TRUE ;
}
2017-09-08 08:02:43 +00:00
while ( find_prev_item ( Vcb , & tp , & prev_tp , Irp ) ) {
2016-03-23 20:35:05 +00:00
tp = prev_tp ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " moving on to %llx,%x,%llx \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( tp . item - > key . obj_type = = TYPE_INODE_ITEM | | ( tp . item - > key . obj_type = = TYPE_ROOT_ITEM & & ! ( tp . item - > key . obj_id & 0x8000000000000000 ) ) ) {
2016-03-23 20:35:05 +00:00
r - > lastinode = tp . item - > key . obj_id ;
TRACE ( " last inode for tree %llx is %llx \n " , r - > id , r - > lastinode ) ;
return TRUE ;
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
r - > lastinode = SUBVOL_ROOT_INODE ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
WARN ( " no INODE_ITEMs in tree %llx \n " , r - > id ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return TRUE ;
}
2017-09-08 08:02:43 +00:00
_Success_ ( return )
static BOOL extract_xattr ( _In_reads_bytes_ ( size ) void * item , _In_ USHORT size , _In_z_ char * name , _Out_ UINT8 * * data , _Out_ UINT16 * datalen ) {
2017-01-01 17:12:12 +00:00
DIR_ITEM * xa = ( DIR_ITEM * ) item ;
USHORT xasize ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( TRUE ) {
if ( size < sizeof ( DIR_ITEM ) | | size < ( sizeof ( DIR_ITEM ) - 1 + xa - > m + xa - > n ) ) {
2017-01-01 17:12:12 +00:00
WARN ( " DIR_ITEM is truncated \n " ) ;
2016-03-23 20:35:05 +00:00
return FALSE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( xa - > n = = strlen ( name ) & & RtlCompareMemory ( name , xa - > name , xa - > n ) = = xa - > n ) {
2017-01-01 17:12:12 +00:00
TRACE ( " found xattr %s \n " , name ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* datalen = xa - > m ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( xa - > m > 0 ) {
* data = ExAllocatePoolWithTag ( PagedPool , xa - > m , ALLOC_TAG ) ;
if ( ! * data ) {
ERR ( " out of memory \n " ) ;
return FALSE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( * data , & xa - > name [ xa - > n ] , xa - > m ) ;
} else
* data = NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
xasize = sizeof ( DIR_ITEM ) - 1 + xa - > m + xa - > n ;
if ( size > xasize ) {
size - = xasize ;
xa = ( DIR_ITEM * ) & xa - > name [ xa - > m + xa - > n ] ;
} else
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " xattr %s not found \n " , name ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return FALSE ;
}
2017-09-08 08:02:43 +00:00
_Success_ ( return )
BOOL get_xattr ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * subvol , _In_ UINT64 inode , _In_z_ char * name , _In_ UINT32 crc32 ,
_Out_ UINT8 * * data , _Out_ UINT16 * datalen , _In_opt_ PIRP Irp ) {
2017-01-01 17:12:12 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " (%p, %llx, %llx, %s, %08x, %p, %p) \n " , Vcb , subvol - > id , inode , name , crc32 , data , datalen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
searchkey . obj_id = inode ;
searchkey . obj_type = TYPE_XATTR_ITEM ;
searchkey . offset = crc32 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = find_item ( Vcb , subvol , & tp , & searchkey , FALSE , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
return FALSE ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
TRACE ( " could not find item (%llx,%x,%llx) \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
return FALSE ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
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 ) ) ;
return FALSE ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return extract_xattr ( tp . item - > data , tp . item - > size , name , data , datalen ) ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_CLOSE )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_close ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2016-03-23 20:35:05 +00:00
BOOL top_level ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " close \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( DeviceObject = = master_devobj ) {
2016-03-23 20:35:05 +00:00
TRACE ( " Closing file system \n " ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto end ;
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_close ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - unmount if called for volume
// FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
2017-09-08 08:02:43 +00:00
Status = close_file ( IrpSp - > FileObject , Irp ) ;
end :
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_DISK_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
FsRtlExitFileSystem ( ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_FLUSH_BUFFERS )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_flush_buffers ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
fcb * fcb = FileObject - > FsContext ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2016-03-23 20:35:05 +00:00
BOOL top_level ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " flush buffers \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_flush_buffers ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
if ( ! fcb ) {
ERR ( " fcb was NULL \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( fcb = = Vcb - > volume_fcb ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
Irp - > IoStatus . Information = 0 ;
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
Irp - > IoStatus . Status = Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
CcFlushCache ( & fcb - > nonpaged - > segment_object , NULL , 0 , & Irp - > IoStatus ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > Header . PagingIoResource ) {
ExAcquireResourceExclusiveLite ( fcb - > Header . PagingIoResource , TRUE ) ;
ExReleaseResourceLite ( fcb - > Header . PagingIoResource ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = Irp - > IoStatus . Status ;
}
2017-09-08 08:02:43 +00:00
end :
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " returning %08x \n " , Status ) ;
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
static void calculate_total_space ( _In_ device_extension * Vcb , _Out_ UINT64 * totalsize , _Out_ UINT64 * freespace ) {
UINT64 nfactor , dfactor , sectors_used ;
2016-10-29 17:05:10 +00:00
if ( Vcb - > data_flags & BLOCK_FLAG_DUPLICATE | | Vcb - > data_flags & BLOCK_FLAG_RAID1 | | Vcb - > data_flags & BLOCK_FLAG_RAID10 ) {
nfactor = 1 ;
dfactor = 2 ;
} else if ( Vcb - > data_flags & BLOCK_FLAG_RAID5 ) {
nfactor = Vcb - > superblock . num_devices - 1 ;
dfactor = Vcb - > superblock . num_devices ;
} else if ( Vcb - > data_flags & BLOCK_FLAG_RAID6 ) {
nfactor = Vcb - > superblock . num_devices - 2 ;
dfactor = Vcb - > superblock . num_devices ;
} else {
nfactor = 1 ;
dfactor = 1 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
sectors_used = Vcb - > superblock . bytes_used / Vcb - > superblock . sector_size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
* totalsize = ( Vcb - > superblock . total_bytes / Vcb - > superblock . sector_size ) * nfactor / dfactor ;
* freespace = sectors_used > * totalsize ? 0 : ( * totalsize - sectors_used ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
# ifndef __REACTOS__
// This function exists because we have to lie about our FS type in certain situations.
// MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match,
// it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working.
// The command mklink refuses to create hard links on anything other than NTFS, so we have to
// blacklist cmd.exe too.
static BOOL lie_about_fs_type ( ) {
NTSTATUS Status ;
PROCESS_BASIC_INFORMATION pbi ;
PPEB peb ;
LIST_ENTRY * le ;
ULONG retlen ;
static WCHAR mpr [ ] = L " MPR.DLL " ;
static WCHAR cmd [ ] = L " CMD.EXE " ;
static WCHAR fsutil [ ] = L " FSUTIL.EXE " ;
UNICODE_STRING mprus , cmdus , fsutilus ;
mprus . Buffer = mpr ;
mprus . Length = mprus . MaximumLength = ( USHORT ) ( wcslen ( mpr ) * sizeof ( WCHAR ) ) ;
cmdus . Buffer = cmd ;
cmdus . Length = cmdus . MaximumLength = ( USHORT ) ( wcslen ( cmd ) * sizeof ( WCHAR ) ) ;
fsutilus . Buffer = fsutil ;
fsutilus . Length = fsutilus . MaximumLength = ( USHORT ) ( wcslen ( fsutil ) * sizeof ( WCHAR ) ) ;
if ( ! PsGetCurrentProcess ( ) )
return FALSE ;
Status = ZwQueryInformationProcess ( NtCurrentProcess ( ) , ProcessBasicInformation , & pbi , sizeof ( pbi ) , & retlen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " ZwQueryInformationProcess returned %08x \n " , Status ) ;
return FALSE ;
}
if ( ! pbi . PebBaseAddress )
return FALSE ;
peb = pbi . PebBaseAddress ;
if ( ! peb - > Ldr )
return FALSE ;
le = peb - > Ldr - > InMemoryOrderModuleList . Flink ;
while ( le ! = & peb - > Ldr - > InMemoryOrderModuleList ) {
LDR_DATA_TABLE_ENTRY * entry = CONTAINING_RECORD ( le , LDR_DATA_TABLE_ENTRY , InMemoryOrderLinks ) ;
BOOL blacklist = FALSE ;
if ( entry - > FullDllName . Length > = mprus . Length ) {
UNICODE_STRING name ;
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - mprus . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = mprus . Length ;
blacklist = FsRtlAreNamesEqual ( & name , & mprus , TRUE , NULL ) ;
}
if ( ! blacklist & & entry - > FullDllName . Length > = cmdus . Length ) {
UNICODE_STRING name ;
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - cmdus . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = cmdus . Length ;
blacklist = FsRtlAreNamesEqual ( & name , & cmdus , TRUE , NULL ) ;
}
if ( ! blacklist & & entry - > FullDllName . Length > = fsutilus . Length ) {
UNICODE_STRING name ;
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - fsutilus . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = fsutilus . Length ;
blacklist = FsRtlAreNamesEqual ( & name , & fsutilus , TRUE , NULL ) ;
}
if ( blacklist ) {
void * * frames ;
ULONG i , num_frames ;
frames = ExAllocatePoolWithTag ( PagedPool , 256 * sizeof ( void * ) , ALLOC_TAG ) ;
if ( ! frames ) {
ERR ( " out of memory \n " ) ;
return FALSE ;
}
num_frames = RtlWalkFrameChain ( frames , 256 , 1 ) ;
for ( i = 0 ; i < num_frames ; i + + ) {
// entry->Reserved3[1] appears to be the image size
if ( frames [ i ] > = entry - > DllBase & & ( ULONG_PTR ) frames [ i ] < = ( ULONG_PTR ) entry - > DllBase + ( ULONG_PTR ) entry - > Reserved3 [ 1 ] ) {
ExFreePool ( frames ) ;
return TRUE ;
}
}
ExFreePool ( frames ) ;
}
le = le - > Flink ;
}
return FALSE ;
}
# endif
_Dispatch_type_ ( IRP_MJ_QUERY_VOLUME_INFORMATION )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_query_volume_information ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
ULONG BytesCopied = 0 ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
BOOL top_level ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " query volume information \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_query_volume_information ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_NOT_IMPLEMENTED ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( IrpSp - > Parameters . QueryVolume . FsInformationClass ) {
case FileFsAttributeInformation :
{
FILE_FS_ATTRIBUTE_INFORMATION * data = Irp - > AssociatedIrp . SystemBuffer ;
BOOL overflow = FALSE ;
2017-09-08 08:02:43 +00:00
# ifndef __REACTOS__
WCHAR * fs_name = ( Irp - > RequestorMode = = UserMode & & lie_about_fs_type ( ) ) ? L " NTFS " : L " Btrfs " ;
ULONG fs_name_len = ( ULONG ) wcslen ( fs_name ) * sizeof ( WCHAR ) ;
# else
WCHAR * fs_name = L " Btrfs " ;
ULONG fs_name_len = 5 * sizeof ( WCHAR ) ;
# endif
2016-03-23 20:35:05 +00:00
ULONG orig_fs_name_len = fs_name_len ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsAttributeInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Parameters . QueryVolume . Length < sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) - sizeof ( WCHAR ) + fs_name_len ) {
if ( IrpSp - > Parameters . QueryVolume . Length > sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) - sizeof ( WCHAR ) )
fs_name_len = IrpSp - > Parameters . QueryVolume . Length - sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) + sizeof ( WCHAR ) ;
else
fs_name_len = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
overflow = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
data - > FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH |
FILE_UNICODE_ON_DISK | FILE_NAMED_STREAMS | FILE_SUPPORTS_HARD_LINKS | FILE_PERSISTENT_ACLS |
2016-10-29 17:05:10 +00:00
FILE_SUPPORTS_REPARSE_POINTS | FILE_SUPPORTS_SPARSE_FILES | FILE_SUPPORTS_OBJECT_IDS |
2017-09-08 08:02:43 +00:00
FILE_SUPPORTS_OPEN_BY_FILE_ID | FILE_SUPPORTS_EXTENDED_ATTRIBUTES | FILE_SUPPORTS_BLOCK_REFCOUNTING ;
2016-03-23 20:35:05 +00:00
if ( Vcb - > readonly )
data - > FileSystemAttributes | = FILE_READ_ONLY_VOLUME ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// should also be FILE_FILE_COMPRESSION when supported
data - > MaximumComponentNameLength = 255 ; // FIXME - check
data - > FileSystemNameLength = orig_fs_name_len ;
RtlCopyMemory ( data - > FileSystemName , fs_name , fs_name_len ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
BytesCopied = sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) - sizeof ( WCHAR ) + fs_name_len ;
Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
break ;
}
case FileFsDeviceInformation :
2016-09-04 15:27:46 +00:00
{
FILE_FS_DEVICE_INFORMATION * ffdi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
TRACE ( " FileFsDeviceInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
ffdi - > DeviceType = FILE_DEVICE_DISK ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
ffdi - > Characteristics = Vcb - > Vpb - > RealDevice - > Characteristics ;
2017-01-01 17:12:12 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > readonly )
ffdi - > Characteristics | = FILE_READ_ONLY_DEVICE ;
else
ffdi - > Characteristics & = ~ FILE_READ_ONLY_DEVICE ;
BytesCopied = sizeof ( FILE_FS_DEVICE_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
}
2016-03-23 20:35:05 +00:00
case FileFsFullSizeInformation :
{
FILE_FS_FULL_SIZE_INFORMATION * ffsi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsFullSizeInformation \n " ) ;
2017-09-08 08:02:43 +00:00
calculate_total_space ( Vcb , ( UINT64 * ) & ffsi - > TotalAllocationUnits . QuadPart , ( UINT64 * ) & ffsi - > ActualAvailableAllocationUnits . QuadPart ) ;
2016-03-23 20:35:05 +00:00
ffsi - > CallerAvailableAllocationUnits . QuadPart = ffsi - > ActualAvailableAllocationUnits . QuadPart ;
ffsi - > SectorsPerAllocationUnit = 1 ;
ffsi - > BytesPerSector = Vcb - > superblock . sector_size ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
BytesCopied = sizeof ( FILE_FS_FULL_SIZE_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileFsObjectIdInformation :
2016-07-27 19:24:26 +00:00
{
FILE_FS_OBJECTID_INFORMATION * ffoi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " FileFsObjectIdInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( ffoi - > ObjectId , & Vcb - > superblock . uuid . uuid [ 0 ] , sizeof ( UCHAR ) * 16 ) ;
RtlZeroMemory ( ffoi - > ExtendedInfo , sizeof ( ffoi - > ExtendedInfo ) ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
BytesCopied = sizeof ( FILE_FS_OBJECTID_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
case FileFsSizeInformation :
{
FILE_FS_SIZE_INFORMATION * ffsi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsSizeInformation \n " ) ;
2017-09-08 08:02:43 +00:00
calculate_total_space ( Vcb , ( UINT64 * ) & ffsi - > TotalAllocationUnits . QuadPart , ( UINT64 * ) & ffsi - > AvailableAllocationUnits . QuadPart ) ;
2016-03-23 20:35:05 +00:00
ffsi - > SectorsPerAllocationUnit = 1 ;
ffsi - > BytesPerSector = Vcb - > superblock . sector_size ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
BytesCopied = sizeof ( FILE_FS_SIZE_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileFsVolumeInformation :
{
FILE_FS_VOLUME_INFORMATION * data = Irp - > AssociatedIrp . SystemBuffer ;
FILE_FS_VOLUME_INFORMATION ffvi ;
BOOL overflow = FALSE ;
ULONG label_len , orig_label_len ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsVolumeInformation \n " ) ;
TRACE ( " max length = %u \n " , IrpSp - > Parameters . QueryVolume . Length ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & label_len , Vcb - > superblock . label , ( ULONG ) strlen ( Vcb - > superblock . label ) ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
break ;
}
2016-03-23 20:35:05 +00:00
orig_label_len = label_len ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Parameters . QueryVolume . Length < sizeof ( FILE_FS_VOLUME_INFORMATION ) - sizeof ( WCHAR ) + label_len ) {
if ( IrpSp - > Parameters . QueryVolume . Length > sizeof ( FILE_FS_VOLUME_INFORMATION ) - sizeof ( WCHAR ) )
label_len = IrpSp - > Parameters . QueryVolume . Length - sizeof ( FILE_FS_VOLUME_INFORMATION ) + sizeof ( WCHAR ) ;
else
label_len = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
overflow = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " label_len = %u \n " , label_len ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ffvi . VolumeCreationTime . QuadPart = 0 ; // FIXME
ffvi . VolumeSerialNumber = Vcb - > superblock . uuid . uuid [ 12 ] < < 24 | Vcb - > superblock . uuid . uuid [ 13 ] < < 16 | Vcb - > superblock . uuid . uuid [ 14 ] < < 8 | Vcb - > superblock . uuid . uuid [ 15 ] ;
ffvi . VolumeLabelLength = orig_label_len ;
ffvi . SupportsObjects = FALSE ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( data , & ffvi , min ( sizeof ( FILE_FS_VOLUME_INFORMATION ) - sizeof ( WCHAR ) , IrpSp - > Parameters . QueryVolume . Length ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( label_len > 0 ) {
ULONG bytecount ;
2017-09-08 08:02:43 +00:00
Status = RtlUTF8ToUnicodeN ( & data - > VolumeLabel [ 0 ] , label_len , & bytecount , Vcb - > superblock . label , ( ULONG ) strlen ( Vcb - > superblock . label ) ) ;
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_BUFFER_TOO_SMALL ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
break ;
}
2016-03-23 20:35:05 +00:00
TRACE ( " label = %.*S \n " , label_len / sizeof ( WCHAR ) , data - > VolumeLabel ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
BytesCopied = sizeof ( FILE_FS_VOLUME_INFORMATION ) - sizeof ( WCHAR ) + label_len ;
Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-30 14:14:27 +00:00
# ifndef __REACTOS__
2016-10-29 17:05:10 +00:00
# ifdef _MSC_VER // not in mingw yet
case FileFsSectorSizeInformation :
{
FILE_FS_SECTOR_SIZE_INFORMATION * data = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
data - > LogicalBytesPerSector = Vcb - > superblock . sector_size ;
data - > PhysicalBytesPerSectorForAtomicity = Vcb - > superblock . sector_size ;
data - > PhysicalBytesPerSectorForPerformance = Vcb - > superblock . sector_size ;
data - > FileSystemEffectivePhysicalBytesPerSectorForAtomicity = Vcb - > superblock . sector_size ;
data - > ByteOffsetForSectorAlignment = 0 ;
data - > ByteOffsetForPartitionAlignment = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
data - > Flags = SSINFO_FLAGS_ALIGNED_DEVICE | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > trim & & ! Vcb - > options . no_trim )
2016-10-29 17:05:10 +00:00
data - > Flags | = SSINFO_FLAGS_TRIM_ENABLED ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
BytesCopied = sizeof ( FILE_FS_SECTOR_SIZE_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
break ;
}
# endif
2016-10-30 14:14:27 +00:00
# endif /* __REACTOS__ */
2016-03-23 20:35:05 +00:00
default :
Status = STATUS_INVALID_PARAMETER ;
2016-07-27 19:24:26 +00:00
WARN ( " unknown FsInformationClass %u \n " , IrpSp - > Parameters . QueryVolume . FsInformationClass ) ;
2016-03-23 20:35:05 +00:00
break ;
}
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_BUFFER_OVERFLOW )
Irp - > IoStatus . Information = 0 ;
else
Irp - > IoStatus . Information = BytesCopied ;
2017-09-08 08:02:43 +00:00
end :
Irp - > IoStatus . Status = Status ;
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_DISK_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " query volume information returning %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
FsRtlExitFileSystem ( ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Function_class_ ( IO_COMPLETION_ROUTINE )
# ifdef __REACTOS__
static NTSTATUS NTAPI read_completion ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp , _In_ PVOID conptr ) {
# else
static NTSTATUS read_completion ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp , _In_ PVOID conptr ) {
# endif
2016-03-23 20:35:05 +00:00
read_context * context = conptr ;
2017-09-08 08:02:43 +00:00
UNUSED ( DeviceObject ) ;
2016-03-23 20:35:05 +00:00
context - > iosb = Irp - > IoStatus ;
KeSetEvent ( & context - > Event , 0 , FALSE ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_MORE_PROCESSING_REQUIRED ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS create_root ( _In_ _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ UINT64 id ,
_Out_ root * * rootptr , _In_ BOOL no_tree , _In_ UINT64 offset , _In_opt_ PIRP Irp ) {
NTSTATUS Status ;
2016-05-05 17:26:47 +00:00
root * r ;
2017-09-08 08:02:43 +00:00
tree * t = NULL ;
2016-05-05 17:26:47 +00:00
ROOT_ITEM * ri ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
r = ExAllocatePoolWithTag ( PagedPool , sizeof ( root ) , ALLOC_TAG ) ;
if ( ! r ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
r - > nonpaged = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( root_nonpaged ) , ALLOC_TAG ) ;
if ( ! r - > nonpaged ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( r ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! no_tree ) {
t = ExAllocatePoolWithTag ( PagedPool , sizeof ( tree ) , ALLOC_TAG ) ;
if ( ! t ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
t - > is_unique = TRUE ;
t - > uniqueness_determined = TRUE ;
t - > buf = NULL ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ri = ExAllocatePoolWithTag ( PagedPool , sizeof ( ROOT_ITEM ) , ALLOC_TAG ) ;
if ( ! ri ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
if ( t )
2016-05-05 17:26:47 +00:00
ExFreePool ( t ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
r - > id = id ;
r - > treeholder . address = 0 ;
r - > treeholder . generation = Vcb - > superblock . generation ;
2017-09-08 08:02:43 +00:00
r - > treeholder . tree = t ;
2016-05-05 17:26:47 +00:00
r - > lastinode = 0 ;
2017-09-08 08:02:43 +00:00
r - > dirty = FALSE ;
r - > received = FALSE ;
r - > reserved = NULL ;
r - > parent = 0 ;
r - > send_ops = 0 ;
2016-05-05 17:26:47 +00:00
RtlZeroMemory ( & r - > root_item , sizeof ( ROOT_ITEM ) ) ;
r - > root_item . num_references = 1 ;
InitializeListHead ( & r - > fcbs ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( ri , & r - > root_item , sizeof ( ROOT_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// We ask here for a traverse_ptr to the item we're inserting, so we can
// copy some of the tree's variables
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > root_root , id , TYPE_ROOT_ITEM , offset , ri , sizeof ( ROOT_ITEM ) , & tp , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " insert_tree_item returned %08x \n " , Status ) ;
2016-05-05 17:26:47 +00:00
ExFreePool ( ri ) ;
2017-09-08 08:02:43 +00:00
if ( t )
2016-05-05 17:26:47 +00:00
ExFreePool ( t ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ExInitializeResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InsertTailList ( & Vcb - > roots , & r - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! no_tree ) {
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( & t - > header , sizeof ( tree_header ) ) ;
2016-05-05 17:26:47 +00:00
t - > header . fs_uuid = tp . tree - > header . fs_uuid ;
t - > header . address = 0 ;
t - > header . flags = HEADER_FLAG_MIXED_BACKREF | 1 ; // 1 == "written"? Why does the Linux driver record this?
t - > header . chunk_tree_uuid = tp . tree - > header . chunk_tree_uuid ;
t - > header . generation = Vcb - > superblock . generation ;
t - > header . tree_id = id ;
t - > header . num_items = 0 ;
t - > header . level = 0 ;
t - > has_address = FALSE ;
t - > size = 0 ;
t - > Vcb = Vcb ;
t - > parent = NULL ;
t - > paritem = NULL ;
t - > root = r ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InitializeListHead ( & t - > itemlist ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
t - > new_address = 0 ;
t - > has_new_address = FALSE ;
2016-10-29 17:05:10 +00:00
t - > updated_extents = FALSE ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InsertTailList ( & Vcb - > trees , & t - > list_entry ) ;
2017-01-01 17:12:12 +00:00
t - > list_entry_hash . Flink = NULL ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
t - > write = TRUE ;
2016-07-27 19:24:26 +00:00
Vcb - > need_write = TRUE ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
* rootptr = r ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS set_label ( _In_ device_extension * Vcb , _In_ FILE_FS_LABEL_INFORMATION * ffli ) {
2016-03-23 20:35:05 +00:00
ULONG utf8len ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG vollen , i ;
2016-03-23 20:35:05 +00:00
TRACE ( " label = %.*S \n " , ffli - > VolumeLabelLength / sizeof ( WCHAR ) , ffli - > VolumeLabel ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
vollen = ffli - > VolumeLabelLength ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
for ( i = 0 ; i < ffli - > VolumeLabelLength / sizeof ( WCHAR ) ; i + + ) {
if ( ffli - > VolumeLabel [ i ] = = 0 ) {
vollen = i * sizeof ( WCHAR ) ;
break ;
} else if ( ffli - > VolumeLabel [ i ] = = ' / ' | | ffli - > VolumeLabel [ i ] = = ' \\ ' ) {
Status = STATUS_INVALID_VOLUME_LABEL ;
goto end ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( vollen = = 0 ) {
utf8len = 0 ;
} else {
Status = RtlUnicodeToUTF8N ( NULL , 0 , & utf8len , ffli - > VolumeLabel , vollen ) ;
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( utf8len > MAX_LABEL_SIZE ) {
Status = STATUS_INVALID_VOLUME_LABEL ;
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( utf8len > 0 ) {
Status = RtlUnicodeToUTF8N ( ( PCHAR ) & Vcb - > superblock . label , MAX_LABEL_SIZE , & utf8len , ffli - > VolumeLabel , vollen ) ;
if ( ! NT_SUCCESS ( Status ) )
goto release ;
} else
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( utf8len < MAX_LABEL_SIZE )
RtlZeroMemory ( Vcb - > superblock . label + utf8len , MAX_LABEL_SIZE - utf8len ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Vcb - > need_write = TRUE ;
2017-09-08 08:02:43 +00:00
release :
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
end :
TRACE ( " returning %08x \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_SET_VOLUME_INFORMATION )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_set_volume_information ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
NTSTATUS Status ;
BOOL top_level ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " set volume information \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_set_volume_information ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_NOT_IMPLEMENTED ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( Vcb - > readonly ) {
Status = STATUS_MEDIA_WRITE_PROTECTED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > removing | | Vcb - > locked ) {
2016-05-05 17:26:47 +00:00
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( IrpSp - > Parameters . SetVolume . FsInformationClass ) {
case FileFsControlInformation :
FIXME ( " STUB: FileFsControlInformation \n " ) ;
break ;
case FileFsLabelInformation :
TRACE ( " FileFsLabelInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = set_label ( Vcb , Irp - > AssociatedIrp . SystemBuffer ) ;
break ;
case FileFsObjectIdInformation :
FIXME ( " STUB: FileFsObjectIdInformation \n " ) ;
break ;
default :
WARN ( " Unrecognized FsInformationClass 0x%x \n " , IrpSp - > Parameters . SetVolume . FsInformationClass ) ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
end :
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
static WCHAR * file_desc_fcb ( _In_ fcb * fcb ) {
2016-05-05 17:26:47 +00:00
char s [ 60 ] ;
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-05-05 17:26:47 +00:00
UNICODE_STRING us ;
ANSI_STRING as ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > debug_desc )
return fcb - > debug_desc ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb = = fcb - > Vcb - > volume_fcb )
return L " volume FCB " ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
fcb - > debug_desc = ExAllocatePoolWithTag ( PagedPool , 60 * sizeof ( WCHAR ) , ALLOC_TAG ) ;
if ( ! fcb - > debug_desc )
return L " (memory error) " ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// I know this is pretty hackish...
// GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf
// without the CRT, which breaks drivers.
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
sprintf ( s , " subvol %x, inode %x " , ( UINT32 ) fcb - > subvol - > id , ( UINT32 ) fcb - > inode ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
as . Buffer = s ;
2017-09-08 08:02:43 +00:00
as . Length = as . MaximumLength = ( USHORT ) strlen ( s ) ;
2016-05-05 17:26:47 +00:00
us . Buffer = fcb - > debug_desc ;
us . MaximumLength = 60 * sizeof ( WCHAR ) ;
us . Length = 0 ;
2017-09-08 08:02:43 +00:00
Status = RtlAnsiStringToUnicodeString ( & us , & as , FALSE ) ;
if ( ! NT_SUCCESS ( Status ) )
return L " (RtlAnsiStringToUnicodeString error) " ;
2016-05-05 17:26:47 +00:00
us . Buffer [ us . Length / sizeof ( WCHAR ) ] = 0 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return fcb - > debug_desc ;
}
2017-09-08 08:02:43 +00:00
WCHAR * file_desc_fileref ( _In_ file_ref * fileref ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
UNICODE_STRING fn ;
2017-09-08 08:02:43 +00:00
ULONG reqlen ;
2016-05-05 17:26:47 +00:00
if ( fileref - > debug_desc )
return fileref - > debug_desc ;
2017-09-08 08:02:43 +00:00
fn . Length = fn . MaximumLength = 0 ;
Status = fileref_get_filename ( fileref , & fn , NULL , & reqlen ) ;
if ( Status ! = STATUS_BUFFER_OVERFLOW )
2016-07-27 19:24:26 +00:00
return L " ERROR " ;
2017-09-08 08:02:43 +00:00
if ( reqlen > 0xffff - sizeof ( WCHAR ) )
return L " (too long) " ;
fileref - > debug_desc = ExAllocatePoolWithTag ( PagedPool , reqlen + sizeof ( WCHAR ) , ALLOC_TAG ) ;
if ( ! fileref - > debug_desc )
2016-05-05 17:26:47 +00:00
return L " (memory error) " ;
2017-09-08 08:02:43 +00:00
fn . Buffer = fileref - > debug_desc ;
fn . Length = 0 ;
fn . MaximumLength = ( USHORT ) ( reqlen + sizeof ( WCHAR ) ) ;
Status = fileref_get_filename ( fileref , & fn , NULL , & reqlen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ExFreePool ( fileref - > debug_desc ) ;
fileref - > debug_desc = NULL ;
return L " ERROR " ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > debug_desc [ fn . Length / sizeof ( WCHAR ) ] = 0 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return fileref - > debug_desc ;
}
2017-09-08 08:02:43 +00:00
_Ret_z_
WCHAR * file_desc ( _In_ PFILE_OBJECT FileObject ) {
2016-05-05 17:26:47 +00:00
fcb * fcb = FileObject - > FsContext ;
ccb * ccb = FileObject - > FsContext2 ;
file_ref * fileref = ccb ? ccb - > fileref : NULL ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fileref )
return file_desc_fileref ( fileref ) ;
else
return file_desc_fcb ( fcb ) ;
}
2017-09-08 08:02:43 +00:00
void send_notification_fileref ( _In_ file_ref * fileref , _In_ ULONG filter_match , _In_ ULONG action , _In_opt_ PUNICODE_STRING stream ) {
2016-07-27 19:24:26 +00:00
UNICODE_STRING fn ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG reqlen ;
2016-07-27 19:24:26 +00:00
USHORT name_offset ;
2016-05-05 17:26:47 +00:00
fcb * fcb = fileref - > fcb ;
2017-09-08 08:02:43 +00:00
fn . Length = fn . MaximumLength = 0 ;
Status = fileref_get_filename ( fileref , & fn , NULL , & reqlen ) ;
if ( Status ! = STATUS_BUFFER_OVERFLOW ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
return ;
}
if ( reqlen > 0xffff ) {
WARN ( " reqlen was too long for FsRtlNotifyFilterReportChange \n " ) ;
return ;
}
fn . Buffer = ExAllocatePoolWithTag ( PagedPool , reqlen , ALLOC_TAG ) ;
if ( ! fn . Buffer ) {
ERR ( " out of memory \n " ) ;
return ;
}
fn . MaximumLength = ( USHORT ) reqlen ;
fn . Length = 0 ;
Status = fileref_get_filename ( fileref , & fn , & name_offset , & reqlen ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( fn . Buffer ) ;
2016-07-27 19:24:26 +00:00
return ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
FsRtlNotifyFilterReportChange ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ( PSTRING ) & fn , name_offset ,
2017-09-08 08:02:43 +00:00
( PSTRING ) stream , NULL , filter_match , action , NULL , NULL ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( fn . Buffer ) ;
}
2017-09-08 08:02:43 +00:00
void send_notification_fcb ( _In_ file_ref * fileref , _In_ ULONG filter_match , _In_ ULONG action , _In_opt_ PUNICODE_STRING stream ) {
2016-07-27 19:24:26 +00:00
fcb * fcb = fileref - > fcb ;
LIST_ENTRY * le ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// no point looking for hardlinks if st_nlink == 1
if ( fileref - > fcb - > inode_item . st_nlink = = 1 ) {
2017-09-08 08:02:43 +00:00
send_notification_fileref ( fileref , filter_match , action , stream ) ;
2016-07-27 19:24:26 +00:00
return ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > fcb_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = fcb - > hardlinks . Flink ;
while ( le ! = & fcb - > hardlinks ) {
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
file_ref * parfr ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = open_fileref_by_inode ( fcb - > Vcb , fcb - > subvol , hl - > parent , & parfr , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2016-07-27 19:24:26 +00:00
ERR ( " open_fileref_by_inode returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
else if ( ! parfr - > deleted ) {
UNICODE_STRING fn ;
ULONG pathlen ;
fn . Length = fn . MaximumLength = 0 ;
Status = fileref_get_filename ( parfr , & fn , NULL , & pathlen ) ;
if ( Status ! = STATUS_BUFFER_OVERFLOW ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
free_fileref ( fcb - > Vcb , parfr ) ;
break ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( parfr ! = fcb - > Vcb - > root_fileref )
pathlen + = sizeof ( WCHAR ) ;
if ( pathlen + hl - > name . Length > 0xffff ) {
WARN ( " pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange \n " ) ;
free_fileref ( fcb - > Vcb , parfr ) ;
break ;
}
fn . MaximumLength = ( USHORT ) ( pathlen + hl - > name . Length ) ;
fn . Buffer = ExAllocatePoolWithTag ( PagedPool , fn . MaximumLength , ALLOC_TAG ) ;
if ( ! fn . Buffer ) {
ERR ( " out of memory \n " ) ;
free_fileref ( fcb - > Vcb , parfr ) ;
break ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
Status = fileref_get_filename ( parfr , & fn , NULL , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
free_fileref ( fcb - > Vcb , parfr ) ;
ExFreePool ( fn . Buffer ) ;
break ;
}
if ( parfr ! = fcb - > Vcb - > root_fileref ) {
fn . Buffer [ ( pathlen / sizeof ( WCHAR ) ) - 1 ] = ' \\ ' ;
fn . Length + = sizeof ( WCHAR ) ;
}
RtlCopyMemory ( & fn . Buffer [ pathlen / sizeof ( WCHAR ) ] , hl - > name . Buffer , hl - > name . Length ) ;
fn . Length + = hl - > name . Length ;
FsRtlNotifyFilterReportChange ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ( PSTRING ) & fn , ( USHORT ) pathlen ,
( PSTRING ) stream , NULL , filter_match , action , NULL , NULL ) ;
ExFreePool ( fn . Buffer ) ;
free_fileref ( fcb - > Vcb , parfr ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fcb_lock ) ;
}
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
void mark_fcb_dirty ( _In_ fcb * fcb ) {
2016-07-27 19:24:26 +00:00
if ( ! fcb - > dirty ) {
# ifdef DEBUG_FCB_REFCOUNTS
LONG rc ;
# endif
fcb - > dirty = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
rc = InterlockedIncrement ( & fcb - > refcount ) ;
WARN ( " fcb %p: refcount now %i \n " , fcb , rc ) ;
# else
InterlockedIncrement ( & fcb - > refcount ) ;
# endif
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > dirty_fcbs_lock , TRUE ) ;
InsertTailList ( & fcb - > Vcb - > dirty_fcbs , & fcb - > list_entry_dirty ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > dirty_fcbs_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > Vcb - > need_write = TRUE ;
}
2017-09-08 08:02:43 +00:00
void mark_fileref_dirty ( _In_ file_ref * fileref ) {
2016-07-27 19:24:26 +00:00
if ( ! fileref - > dirty ) {
fileref - > dirty = TRUE ;
increase_fileref_refcount ( fileref ) ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & fileref - > fcb - > Vcb - > dirty_filerefs_lock , TRUE ) ;
InsertTailList ( & fileref - > fcb - > Vcb - > dirty_filerefs , & fileref - > list_entry_dirty ) ;
ExReleaseResourceLite ( & fileref - > fcb - > Vcb - > dirty_filerefs_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > fcb - > Vcb - > need_write = TRUE ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
void _free_fcb ( _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) _In_ device_extension * Vcb , _Inout_ fcb * fcb , _In_ const char * func ) {
# else
void free_fcb ( _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) _In_ device_extension * Vcb , _Inout_ fcb * fcb ) {
# endif
2016-05-05 17:26:47 +00:00
LONG rc ;
2016-03-23 20:35:05 +00:00
rc = InterlockedDecrement ( & fcb - > refcount ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
# ifdef DEBUG_LONG_MESSAGES
2017-09-08 08:02:43 +00:00
ERR ( " fcb %p: refcount now %i (subvol %llx, inode %llx) \n " , fcb , rc , fcb - > subvol ? fcb - > subvol - > id : 0 , fcb - > inode ) ;
2016-03-23 20:35:05 +00:00
# else
2017-09-08 08:02:43 +00:00
ERR ( " fcb %p: refcount now %i (subvol %llx, inode %llx) \n " , fcb , rc , fcb - > subvol ? fcb - > subvol - > id : 0 , fcb - > inode ) ;
2016-03-23 20:35:05 +00:00
# endif
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( rc > 0 )
return ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > list_entry . Flink )
RemoveEntryList ( & fcb - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > list_entry_all . Flink )
RemoveEntryList ( & fcb - > list_entry_all ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & fcb - > nonpaged - > resource ) ;
ExDeleteResourceLite ( & fcb - > nonpaged - > paging_resource ) ;
2017-01-01 17:12:12 +00:00
ExDeleteResourceLite ( & fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
ExFreeToNPagedLookasideList ( & Vcb - > fcb_np_lookaside , fcb - > nonpaged ) ;
2016-03-23 20:35:05 +00:00
if ( fcb - > sd )
ExFreePool ( fcb - > sd ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > adsxattr . Buffer )
ExFreePool ( fcb - > adsxattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > reparse_xattr . Buffer )
ExFreePool ( fcb - > reparse_xattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > ea_xattr . Buffer )
ExFreePool ( fcb - > ea_xattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > adsdata . Buffer )
ExFreePool ( fcb - > adsdata . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > debug_desc )
ExFreePool ( fcb - > debug_desc ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( ! IsListEmpty ( & fcb - > extents ) ) {
LIST_ENTRY * le = RemoveHeadList ( & fcb - > extents ) ;
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ext - > csum )
ExFreePool ( ext - > csum ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExFreePool ( ext ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( ! IsListEmpty ( & fcb - > hardlinks ) ) {
LIST_ENTRY * le = RemoveHeadList ( & fcb - > hardlinks ) ;
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( hl - > name . Buffer )
ExFreePool ( hl - > name . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( hl - > utf8 . Buffer )
ExFreePool ( hl - > utf8 . Buffer ) ;
ExFreePool ( hl ) ;
}
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & fcb - > xattrs ) ) {
xattr * xa = CONTAINING_RECORD ( RemoveHeadList ( & fcb - > xattrs ) , xattr , list_entry ) ;
ExFreePool ( xa ) ;
}
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & fcb - > dir_children_index ) ) {
LIST_ENTRY * le = RemoveHeadList ( & fcb - > dir_children_index ) ;
dir_child * dc = CONTAINING_RECORD ( le , dir_child , list_entry_index ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc - > name_uc . Buffer ) ;
ExFreePool ( dc ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > hash_ptrs )
ExFreePool ( fcb - > hash_ptrs ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > hash_ptrs_uc )
ExFreePool ( fcb - > hash_ptrs_uc ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
FsRtlUninitializeFileLock ( & fcb - > lock ) ;
2017-09-08 08:02:43 +00:00
if ( fcb - > pool_type = = NonPagedPool )
ExFreePool ( fcb ) ;
else
ExFreeToPagedLookasideList ( & Vcb - > fcb_lookaside , fcb ) ;
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
# ifdef DEBUG_LONG_MESSAGES
2016-05-05 17:26:47 +00:00
_debug_message ( func , file , line , " freeing fcb %p \n " , fcb ) ;
# else
_debug_message ( func , " freeing fcb %p \n " , fcb ) ;
# endif
# endif
}
2017-09-08 08:02:43 +00:00
void free_fileref ( _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) _In_ device_extension * Vcb , _Inout_ file_ref * fr ) {
2016-05-05 17:26:47 +00:00
LONG rc ;
rc = InterlockedDecrement ( & fr - > refcount ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2017-09-08 08:02:43 +00:00
ERR ( " fileref %p: refcount now %i \n " , fr , rc ) ;
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
# ifdef _DEBUG
if ( rc < 0 ) {
ERR ( " fileref %p: refcount now %i \n " , fr , rc ) ;
int3 ;
}
# endif
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( rc > 0 )
return ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fr - > parent )
ExAcquireResourceExclusiveLite ( & fr - > parent - > nonpaged - > children_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - do we need a file_ref lock?
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - do delete if needed
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fr - > debug_desc )
ExFreePool ( fr - > debug_desc ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExDeleteResourceLite ( & fr - > nonpaged - > children_lock ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & fr - > nonpaged - > fileref_lock ) ;
ExFreeToNPagedLookasideList ( & Vcb - > fileref_np_lookaside , fr - > nonpaged ) ;
2016-05-05 17:26:47 +00:00
// FIXME - throw error if children not empty
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fr - > fcb - > fileref = = fr )
fr - > fcb - > fileref = NULL ;
2017-09-08 08:02:43 +00:00
if ( fr - > dc ) {
if ( fr - > fcb - > ads )
fr - > dc - > size = fr - > fcb - > adsdata . Length ;
2017-01-01 17:12:12 +00:00
fr - > dc - > fileref = NULL ;
2017-09-08 08:02:43 +00:00
}
2017-01-01 17:12:12 +00:00
2016-05-05 17:26:47 +00:00
if ( fr - > list_entry . Flink )
RemoveEntryList ( & fr - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fr - > parent ) {
ExReleaseResourceLite ( & fr - > parent - > nonpaged - > children_lock ) ;
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , fr - > parent ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fr - > fcb ) ;
ExFreeToPagedLookasideList ( & Vcb - > fileref_lookaside , fr ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS close_file ( _In_ PFILE_OBJECT FileObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
fcb * fcb ;
ccb * ccb ;
2016-05-05 17:26:47 +00:00
file_ref * fileref = NULL ;
2016-10-29 17:05:10 +00:00
LONG open_files ;
2017-09-08 08:02:43 +00:00
device_extension * Vcb ;
UNUSED ( Irp ) ;
2016-03-23 20:35:05 +00:00
TRACE ( " FileObject = %p \n " , FileObject ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fcb = FileObject - > FsContext ;
if ( ! fcb ) {
TRACE ( " FCB was NULL, returning success \n " ) ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
open_files = InterlockedDecrement ( & fcb - > Vcb - > open_files ) ;
2016-03-23 20:35:05 +00:00
ccb = FileObject - > FsContext2 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " close called for %S (fcb == %p) \n " , file_desc ( FileObject ) , fcb ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - make sure notification gets sent if file is being deleted
2017-09-08 08:02:43 +00:00
if ( ccb ) {
2016-03-23 20:35:05 +00:00
if ( ccb - > query_string . Buffer )
RtlFreeUnicodeString ( & ccb - > query_string ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ccb - > filename . Buffer )
ExFreePool ( ccb - > filename . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - use refcounts for fileref
fileref = ccb - > fileref ;
2017-09-08 08:02:43 +00:00
if ( fcb - > Vcb - > running_sends > 0 ) {
BOOL send_cancelled = FALSE ;
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > send_load_lock , TRUE ) ;
if ( ccb - > send ) {
ccb - > send - > cancelling = TRUE ;
send_cancelled = TRUE ;
KeSetEvent ( & ccb - > send - > cleared_event , 0 , FALSE ) ;
}
ExReleaseResourceLite ( & fcb - > Vcb - > send_load_lock ) ;
if ( send_cancelled ) {
while ( ccb - > send ) {
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > send_load_lock , TRUE ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > send_load_lock ) ;
}
}
}
ExFreePool ( ccb ) ;
}
CcUninitializeCacheMap ( FileObject , NULL , NULL ) ;
if ( open_files = = 0 & & fcb - > Vcb - > removing ) {
uninit ( fcb - > Vcb , FALSE ) ;
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
if ( ! ( fcb - > Vcb - > Vpb - > Flags & VPB_MOUNTED ) )
2016-09-04 15:27:46 +00:00
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
Vcb = fcb - > Vcb ;
2016-05-05 17:26:47 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fileref )
2017-09-08 08:02:43 +00:00
free_fileref ( fcb - > Vcb , fileref ) ;
2016-05-05 17:26:47 +00:00
else
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2016-05-05 17:26:47 +00:00
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
void uninit ( _In_ device_extension * Vcb , _In_ BOOL flush ) {
2016-03-23 20:35:05 +00:00
UINT64 i ;
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
LIST_ENTRY * le ;
LARGE_INTEGER time ;
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > removing ) {
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , TRUE ) ;
Vcb - > removing = TRUE ;
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
}
2016-07-27 19:24:26 +00:00
RemoveEntryList ( & Vcb - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > balance . thread ) {
Vcb - > balance . paused = FALSE ;
Vcb - > balance . stopping = TRUE ;
KeSetEvent ( & Vcb - > balance . event , 0 , FALSE ) ;
KeWaitForSingleObject ( & Vcb - > balance . finished , Executive , KernelMode , FALSE , NULL ) ;
}
2017-09-08 08:02:43 +00:00
if ( Vcb - > scrub . thread ) {
Vcb - > scrub . paused = FALSE ;
Vcb - > scrub . stopping = TRUE ;
KeSetEvent ( & Vcb - > scrub . event , 0 , FALSE ) ;
KeWaitForSingleObject ( & Vcb - > scrub . finished , Executive , KernelMode , FALSE , NULL ) ;
}
if ( Vcb - > running_sends ! = 0 ) {
BOOL send_cancelled = FALSE ;
ExAcquireResourceExclusiveLite ( & Vcb - > send_load_lock , TRUE ) ;
le = Vcb - > send_ops . Flink ;
while ( le ! = & Vcb - > send_ops ) {
send_info * send = CONTAINING_RECORD ( le , send_info , list_entry ) ;
if ( ! send - > cancelling ) {
send - > cancelling = TRUE ;
send_cancelled = TRUE ;
send - > ccb = NULL ;
KeSetEvent ( & send - > cleared_event , 0 , FALSE ) ;
}
le = le - > Flink ;
}
ExReleaseResourceLite ( & Vcb - > send_load_lock ) ;
if ( send_cancelled ) {
while ( Vcb - > running_sends ! = 0 ) {
ExAcquireResourceExclusiveLite ( & Vcb - > send_load_lock , TRUE ) ;
ExReleaseResourceLite ( & Vcb - > send_load_lock ) ;
}
}
}
2016-07-27 19:24:26 +00:00
Status = registry_mark_volume_unmounted ( & Vcb - > superblock . uuid ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_TOO_LATE )
2016-07-27 19:24:26 +00:00
WARN ( " registry_mark_volume_unmounted returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( flush ) {
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , TRUE ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
if ( Vcb - > need_write & & ! Vcb - > readonly ) {
Status = do_write ( Vcb , NULL ) ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " do_write returned %08x \n " , Status ) ;
}
2016-05-05 17:26:47 +00:00
free_trees ( Vcb ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
for ( i = 0 ; i < Vcb - > calcthreads . num_threads ; i + + ) {
Vcb - > calcthreads . threads [ i ] . quit = TRUE ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
KeSetEvent ( & Vcb - > calcthreads . event , 0 , FALSE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
for ( i = 0 ; i < Vcb - > calcthreads . num_threads ; i + + ) {
KeWaitForSingleObject ( & Vcb - > calcthreads . threads [ i ] . finished , Executive , KernelMode , FALSE , NULL ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ZwClose ( Vcb - > calcthreads . threads [ i ] . handle ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExDeleteResourceLite ( & Vcb - > calcthreads . lock ) ;
ExFreePool ( Vcb - > calcthreads . threads ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
time . QuadPart = 0 ;
KeSetTimer ( & Vcb - > flush_thread_timer , time , NULL ) ; // trigger the timer early
KeWaitForSingleObject ( & Vcb - > flush_thread_finished , Executive , KernelMode , FALSE , NULL ) ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
free_fcb ( Vcb , Vcb - > volume_fcb ) ;
free_fcb ( Vcb , Vcb - > dummy_fcb ) ;
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
2016-07-27 19:24:26 +00:00
if ( Vcb - > root_file )
ObDereferenceObject ( Vcb - > root_file ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
chunk * c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( c - > cache ) {
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
free_fcb ( Vcb , c - > cache ) ;
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
2016-07-27 19:24:26 +00:00
c - > cache = NULL ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
while ( ! IsListEmpty ( & Vcb - > roots ) ) {
2017-09-08 08:02:43 +00:00
root * r = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > roots ) , root , list_entry ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
ExDeleteResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( & Vcb - > chunks ) ) {
2017-09-08 08:02:43 +00:00
chunk * c = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > chunks ) , chunk , list_entry ) ;
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( & c - > space ) ) {
LIST_ENTRY * le2 = RemoveHeadList ( & c - > space ) ;
2017-09-08 08:02:43 +00:00
space * s = CONTAINING_RECORD ( le2 , space , list_entry ) ;
2016-03-23 20:35:05 +00:00
ExFreePool ( s ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( ! IsListEmpty ( & c - > deleting ) ) {
LIST_ENTRY * le2 = RemoveHeadList ( & c - > deleting ) ;
2017-09-08 08:02:43 +00:00
space * s = CONTAINING_RECORD ( le2 , space , list_entry ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( s ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( c - > devices )
ExFreePool ( c - > devices ) ;
2017-09-08 08:02:43 +00:00
if ( c - > cache ) {
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
free_fcb ( Vcb , c - > cache ) ;
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
}
ExDeleteResourceLite ( & c - > range_locks_lock ) ;
ExDeleteResourceLite ( & c - > partial_stripes_lock ) ;
2016-09-04 15:27:46 +00:00
ExDeleteResourceLite ( & c - > lock ) ;
ExDeleteResourceLite ( & c - > changed_extents_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// FIXME - free any open fcbs?
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & Vcb - > devices ) ) {
2017-09-08 08:02:43 +00:00
device * dev = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > devices ) , device , list_entry ) ;
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & dev - > space ) ) {
LIST_ENTRY * le2 = RemoveHeadList ( & dev - > space ) ;
space * s = CONTAINING_RECORD ( le2 , space , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExFreePool ( s ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( dev ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > scrub . stats_lock , TRUE ) ;
while ( ! IsListEmpty ( & Vcb - > scrub . errors ) ) {
scrub_error * err = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > scrub . errors ) , scrub_error , list_entry ) ;
ExFreePool ( err ) ;
}
ExReleaseResourceLite ( & Vcb - > scrub . stats_lock ) ;
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & Vcb - > fcb_lock ) ;
ExDeleteResourceLite ( & Vcb - > load_lock ) ;
ExDeleteResourceLite ( & Vcb - > tree_lock ) ;
2016-07-27 19:24:26 +00:00
ExDeleteResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_subvols_lock ) ;
ExDeleteResourceLite ( & Vcb - > scrub . stats_lock ) ;
ExDeleteResourceLite ( & Vcb - > send_load_lock ) ;
2016-10-29 17:05:10 +00:00
ExDeletePagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > traverse_ptr_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > batch_item_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeletePagedLookasideList ( & Vcb - > fileref_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > fcb_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > name_bit_lookaside ) ;
2016-10-29 17:05:10 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > range_lock_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > fileref_np_lookaside ) ;
ExDeleteNPagedLookasideList ( & Vcb - > fcb_np_lookaside ) ;
2016-03-23 20:35:05 +00:00
ZwClose ( Vcb - > flush_thread_handle ) ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS delete_fileref ( _In_ file_ref * fileref , _In_ PFILE_OBJECT FileObject , _In_opt_ PIRP Irp , _In_ LIST_ENTRY * rollback ) {
2016-07-27 19:24:26 +00:00
LARGE_INTEGER newlength , time ;
BTRFS_TIME now ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG utf8len = 0 ;
2016-07-27 19:24:26 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
ExAcquireResourceExclusiveLite ( fileref - > fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref - > deleted ) {
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
if ( fileref - > fcb - > subvol - > send_ops > 0 ) {
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
return STATUS_ACCESS_DENIED ;
}
2016-07-27 19:24:26 +00:00
fileref - > deleted = TRUE ;
mark_fileref_dirty ( fileref ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// delete INODE_ITEM (0x1)
TRACE ( " nlink = %u \n " , fileref - > fcb - > inode_item . st_nlink ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! fileref - > fcb - > ads ) {
if ( fileref - > parent - > fcb - > subvol = = fileref - > fcb - > subvol ) {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > fcb ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fileref - > fcb - > inode_item_changed = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref - > fcb - > inode_item . st_nlink > 1 ) {
fileref - > fcb - > inode_item . st_nlink - - ;
fileref - > fcb - > inode_item . transid = fileref - > fcb - > Vcb - > superblock . generation ;
fileref - > fcb - > inode_item . sequence + + ;
fileref - > fcb - > inode_item . st_ctime = now ;
} else {
// excise extents
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref - > fcb - > type ! = BTRFS_TYPE_DIRECTORY & & fileref - > fcb - > inode_item . st_size > 0 ) {
2016-09-04 15:27:46 +00:00
Status = excise_extents ( fileref - > fcb - > Vcb , fileref - > fcb , 0 , sector_align ( fileref - > fcb - > inode_item . st_size , fileref - > fcb - > Vcb - > superblock . sector_size ) , Irp , rollback ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " excise_extents returned %08x \n " , Status ) ;
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > fcb - > Header . AllocationSize . QuadPart = 0 ;
fileref - > fcb - > Header . FileSize . QuadPart = 0 ;
fileref - > fcb - > Header . ValidDataLength . QuadPart = 0 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( FileObject ) {
CC_FILE_SIZES ccfs ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ccfs . AllocationSize = fileref - > fcb - > Header . AllocationSize ;
ccfs . FileSize = fileref - > fcb - > Header . FileSize ;
ccfs . ValidDataLength = fileref - > fcb - > Header . ValidDataLength ;
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
_SEH2_TRY {
CcSetFileSizes ( FileObject , & ccfs ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
} _SEH2_END ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " CcSetFileSizes threw exception %08x \n " , Status ) ;
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
return Status ;
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
fileref - > fcb - > deleted = TRUE ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( fileref - > dc ) {
le = fileref - > fcb - > hardlinks . Flink ;
while ( le ! = & fileref - > fcb - > hardlinks ) {
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
if ( hl - > parent = = fileref - > parent - > fcb - > inode & & hl - > index = = fileref - > dc - > index ) {
RemoveEntryList ( & hl - > list_entry ) ;
if ( hl - > name . Buffer )
ExFreePool ( hl - > name . Buffer ) ;
if ( hl - > utf8 . Buffer )
ExFreePool ( hl - > utf8 . Buffer ) ;
ExFreePool ( hl ) ;
break ;
}
le = le - > Flink ;
2016-07-27 19:24:26 +00:00
}
}
2017-09-08 08:02:43 +00:00
} else if ( fileref - > fcb - > subvol - > parent = = fileref - > parent - > fcb - > subvol - > id ) { // valid subvolume
2016-07-27 19:24:26 +00:00
if ( fileref - > fcb - > subvol - > root_item . num_references > 1 ) {
fileref - > fcb - > subvol - > root_item . num_references - - ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > fcb ) ; // so ROOT_ITEM gets updated
} else {
// FIXME - we need a lock here
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RemoveEntryList ( & fileref - > fcb - > subvol - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InsertTailList ( & fileref - > fcb - > Vcb - > drop_roots , & fileref - > fcb - > subvol - > list_entry ) ;
}
}
} else {
fileref - > fcb - > deleted = TRUE ;
mark_fcb_dirty ( fileref - > fcb ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// remove dir_child from parent
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fileref - > dc ) {
2017-09-08 08:02:43 +00:00
TRACE ( " delete file %.*S \n " , fileref - > dc - > name . Length / sizeof ( WCHAR ) , fileref - > dc - > name . Buffer ) ;
2017-01-01 17:12:12 +00:00
ExAcquireResourceExclusiveLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
RemoveEntryList ( & fileref - > dc - > list_entry_index ) ;
2017-09-08 08:02:43 +00:00
if ( ! fileref - > fcb - > ads )
remove_dir_child_from_hash_lists ( fileref - > parent - > fcb , fileref - > dc ) ;
2017-01-01 17:12:12 +00:00
ExReleaseResourceLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
if ( ! fileref - > oldutf8 . Buffer )
fileref - > oldutf8 = fileref - > dc - > utf8 ;
else
ExFreePool ( fileref - > dc - > utf8 . Buffer ) ;
utf8len = fileref - > dc - > utf8 . Length ;
fileref - > oldindex = fileref - > dc - > index ;
2017-01-01 17:12:12 +00:00
ExFreePool ( fileref - > dc - > name . Buffer ) ;
ExFreePool ( fileref - > dc - > name_uc . Buffer ) ;
ExFreePool ( fileref - > dc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fileref - > dc = NULL ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// update INODE_ITEM of parent
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( fileref - > parent - > fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > parent - > fcb - > inode_item . transid = fileref - > fcb - > Vcb - > superblock . generation ;
fileref - > parent - > fcb - > inode_item . sequence + + ;
fileref - > parent - > fcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
if ( ! fileref - > fcb - > ads ) {
TRACE ( " fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx \n " , fileref - > parent - > fcb - > inode , fileref - > parent - > fcb - > inode_item . st_size ) ;
fileref - > parent - > fcb - > inode_item . st_size - = utf8len * 2 ;
TRACE ( " fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx \n " , fileref - > parent - > fcb - > inode , fileref - > parent - > fcb - > inode_item . st_size ) ;
fileref - > parent - > fcb - > inode_item . st_mtime = now ;
}
2016-07-27 19:24:26 +00:00
2016-10-29 17:05:10 +00:00
fileref - > parent - > fcb - > inode_item_changed = TRUE ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( fileref - > parent - > fcb - > Header . Resource ) ;
if ( ! fileref - > fcb - > ads & & fileref - > parent - > dc )
send_notification_fcb ( fileref - > parent , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > parent - > fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > fcb - > subvol - > root_item . ctransid = fileref - > fcb - > Vcb - > superblock . generation ;
fileref - > fcb - > subvol - > root_item . ctime = now ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
newlength . QuadPart = 0 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( FileObject & & ! CcUninitializeCacheMap ( FileObject , & newlength , NULL ) )
TRACE ( " CcUninitializeCacheMap failed \n " ) ;
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_CLEANUP )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_cleanup ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2017-09-08 08:02:43 +00:00
fcb * fcb = FileObject - > FsContext ;
2016-03-23 20:35:05 +00:00
BOOL top_level ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " cleanup \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_cleanup ( DeviceObject , Irp ) ;
goto exit ;
} else if ( DeviceObject = = master_devobj ) {
2016-03-23 20:35:05 +00:00
TRACE ( " closing file system \n " ) ;
Status = STATUS_SUCCESS ;
goto exit ;
2017-09-08 08:02:43 +00:00
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
if ( FileObject - > Flags & FO_CLEANUP_COMPLETE ) {
TRACE ( " FileObject %p already cleaned up \n " , FileObject ) ;
Status = STATUS_SUCCESS ;
goto exit ;
}
if ( ! fcb ) {
ERR ( " fcb was NULL \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
// We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup
// messages belonging to other devices.
2016-05-05 17:26:47 +00:00
if ( FileObject & & FileObject - > FsContext ) {
2016-03-23 20:35:05 +00:00
LONG oc ;
2016-05-05 17:26:47 +00:00
ccb * ccb ;
file_ref * fileref ;
2017-09-08 08:02:43 +00:00
BOOL locked = TRUE ;
2016-05-05 17:26:47 +00:00
ccb = FileObject - > FsContext2 ;
fileref = ccb ? ccb - > fileref : NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " cleanup called for FileObject %p \n " , FileObject ) ;
2016-10-29 17:05:10 +00:00
TRACE ( " fileref %p (%S), refcount = %u, open_count = %u \n " , fileref , file_desc ( FileObject ) , fileref ? fileref - > refcount : 0 , fileref ? fileref - > open_count : 0 ) ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceSharedLite ( & fcb - > Vcb - > tree_lock , TRUE ) ;
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2016-03-23 20:35:05 +00:00
IoRemoveShareAccess ( FileObject , & fcb - > share_access ) ;
2017-09-08 08:02:43 +00:00
if ( ccb )
FsRtlNotifyCleanup ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ccb ) ;
2016-10-29 17:05:10 +00:00
if ( fileref ) {
oc = InterlockedDecrement ( & fileref - > open_count ) ;
2016-03-26 11:53:07 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2016-10-29 17:05:10 +00:00
ERR ( " fileref %p: open_count now %i \n " , fileref , oc ) ;
2016-03-26 11:53:07 +00:00
# endif
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ccb & & ccb - > options & FILE_DELETE_ON_CLOSE & & fileref )
fileref - > delete_on_close = TRUE ;
2017-09-08 08:02:43 +00:00
if ( fileref & & fileref - > delete_on_close & & fcb - > type = = BTRFS_TYPE_DIRECTORY & & fcb - > inode_item . st_size > 0 & & fcb ! = fcb - > Vcb - > dummy_fcb )
2016-05-05 17:26:47 +00:00
fileref - > delete_on_close = FALSE ;
2017-09-08 08:02:43 +00:00
if ( fcb - > Vcb - > locked & & fcb - > Vcb - > locked_fileobj = = FileObject ) {
2016-07-27 19:24:26 +00:00
TRACE ( " unlocking volume \n " ) ;
2017-09-08 08:02:43 +00:00
do_unlock_volume ( fcb - > Vcb ) ;
2016-07-27 19:24:26 +00:00
FsRtlNotifyVolumeEvent ( FileObject , FSRTL_VOLUME_UNLOCK ) ;
}
2017-09-08 08:02:43 +00:00
if ( ccb & & ccb - > reserving ) {
fcb - > subvol - > reserved = NULL ;
ccb - > reserving = FALSE ;
// FIXME - flush all of subvol's fcbs
}
2016-10-29 17:05:10 +00:00
if ( fileref & & oc = = 0 ) {
2017-09-08 08:02:43 +00:00
if ( ! fcb - > Vcb - > removing ) {
2016-07-27 19:24:26 +00:00
if ( fileref & & fileref - > delete_on_close & & fileref ! = fcb - > Vcb - > root_fileref & & fcb ! = fcb - > Vcb - > volume_fcb ) {
2017-09-08 08:02:43 +00:00
LIST_ENTRY rollback ;
InitializeListHead ( & rollback ) ;
if ( ! fileref - > fcb - > ads | | fileref - > dc ) {
if ( fileref - > fcb - > ads ) {
send_notification_fileref ( fileref - > parent , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME ,
FILE_ACTION_REMOVED , & fileref - > dc - > name ) ;
} else
send_notification_fileref ( fileref , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_REMOVED , NULL ) ;
}
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
locked = FALSE ;
// fcb_lock needs to be acquired before fcb->Header.Resource
2016-10-29 17:05:10 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > fcb_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = delete_fileref ( fileref , FileObject , Irp , & rollback ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
do_rollback ( fcb - > Vcb , & rollback ) ;
2016-10-29 17:05:10 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fcb_lock ) ;
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
goto exit ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fcb_lock ) ;
2017-09-08 08:02:43 +00:00
locked = FALSE ;
clear_rollback ( & rollback ) ;
2016-07-27 19:24:26 +00:00
} else if ( FileObject - > Flags & FO_CACHE_SUPPORTED & & fcb - > nonpaged - > segment_object . DataSectionObject ) {
IO_STATUS_BLOCK iosb ;
CcFlushCache ( FileObject - > SectionObjectPointer , NULL , 0 , & iosb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( iosb . Status ) ) {
ERR ( " CcFlushCache returned %08x \n " , iosb . Status ) ;
}
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
if ( ! ExIsResourceAcquiredSharedLite ( fcb - > Header . PagingIoResource ) ) {
ExAcquireResourceExclusiveLite ( fcb - > Header . PagingIoResource , TRUE ) ;
ExReleaseResourceLite ( fcb - > Header . PagingIoResource ) ;
}
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
CcPurgeCacheSection ( & fcb - > nonpaged - > segment_object , NULL , 0 , FALSE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx) \n " ,
FileObject , fcb , fcb - > Header . AllocationSize . QuadPart , fcb - > Header . FileSize . QuadPart , fcb - > Header . ValidDataLength . QuadPart ) ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-26 11:53:07 +00:00
if ( fcb - > Vcb & & fcb ! = fcb - > Vcb - > volume_fcb )
CcUninitializeCacheMap ( FileObject , NULL , NULL ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
if ( locked )
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
FileObject - > Flags | = FO_CLEANUP_COMPLETE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
exit :
2017-09-08 08:02:43 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
_Success_ ( return )
BOOL get_file_attributes_from_xattr ( _In_reads_bytes_ ( len ) char * val , _In_ UINT16 len , _Out_ ULONG * atts ) {
2017-01-01 17:12:12 +00:00
if ( len > 2 & & val [ 0 ] = = ' 0 ' & & val [ 1 ] = = ' x ' ) {
int i ;
ULONG dosnum = 0 ;
for ( i = 2 ; i < len ; i + + ) {
dosnum * = 0x10 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( val [ i ] > = ' 0 ' & & val [ i ] < = ' 9 ' )
dosnum | = val [ i ] - ' 0 ' ;
else if ( val [ i ] > = ' a ' & & val [ i ] < = ' f ' )
dosnum | = val [ i ] + 10 - ' a ' ;
else if ( val [ i ] > = ' A ' & & val [ i ] < = ' F ' )
dosnum | = val [ i ] + 10 - ' a ' ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " DOSATTRIB: %08x \n " , dosnum ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* atts = dosnum ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return TRUE ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return FALSE ;
}
2017-09-08 08:02:43 +00:00
ULONG get_file_attributes ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * r , _In_ UINT64 inode ,
_In_ UINT8 type , _In_ BOOL dotfile , _In_ BOOL ignore_xa , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
ULONG att ;
char * eaval ;
UINT16 ealen ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! ignore_xa & & get_xattr ( Vcb , r , inode , EA_DOSATTRIB , EA_DOSATTRIB_HASH , ( UINT8 * * ) & eaval , & ealen , Irp ) ) {
2017-01-01 17:12:12 +00:00
ULONG dosnum = 0 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( get_file_attributes_from_xattr ( eaval , ealen , & dosnum ) ) {
ExFreePool ( eaval ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( type = = BTRFS_TYPE_DIRECTORY )
dosnum | = FILE_ATTRIBUTE_DIRECTORY ;
else if ( type = = BTRFS_TYPE_SYMLINK )
dosnum | = FILE_ATTRIBUTE_REPARSE_POINT ;
2017-09-08 08:02:43 +00:00
if ( type ! = BTRFS_TYPE_DIRECTORY )
dosnum & = ~ FILE_ATTRIBUTE_DIRECTORY ;
2017-01-01 17:12:12 +00:00
if ( inode = = SUBVOL_ROOT_INODE ) {
if ( r - > root_item . flags & BTRFS_SUBVOL_READONLY )
dosnum | = FILE_ATTRIBUTE_READONLY ;
else
dosnum & = ~ FILE_ATTRIBUTE_READONLY ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return dosnum ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( eaval ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( type ) {
case BTRFS_TYPE_DIRECTORY :
att = FILE_ATTRIBUTE_DIRECTORY ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_TYPE_SYMLINK :
att = FILE_ATTRIBUTE_REPARSE_POINT ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
default :
att = 0 ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( dotfile ) {
att | = FILE_ATTRIBUTE_HIDDEN ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
att | = FILE_ATTRIBUTE_ARCHIVE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( inode = = SUBVOL_ROOT_INODE ) {
if ( r - > root_item . flags & BTRFS_SUBVOL_READONLY )
att | = FILE_ATTRIBUTE_READONLY ;
else
att & = ~ FILE_ATTRIBUTE_READONLY ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - get READONLY from ii->st_mode
// FIXME - return SYSTEM for block/char devices?
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( att = = 0 )
att = FILE_ATTRIBUTE_NORMAL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return att ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS sync_read_phys ( _In_ PDEVICE_OBJECT DeviceObject , _In_ UINT64 StartingOffset , _In_ ULONG Length ,
_Out_writes_bytes_ ( Length ) PUCHAR Buffer , _In_ BOOL override ) {
IO_STATUS_BLOCK IoStatus ;
2016-03-23 20:35:05 +00:00
LARGE_INTEGER Offset ;
PIRP Irp ;
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
read_context context ;
2016-03-23 20:35:05 +00:00
num_reads + + ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( & context , sizeof ( read_context ) ) ;
KeInitializeEvent ( & context . Event , NotificationEvent , FALSE ) ;
Offset . QuadPart = ( LONGLONG ) StartingOffset ;
2016-03-23 20:35:05 +00:00
Irp = IoAllocateIrp ( DeviceObject - > StackSize , FALSE ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! Irp ) {
ERR ( " IoAllocateIrp failed \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Irp - > Flags | = IRP_NOCACHE ;
2016-03-23 20:35:05 +00:00
IrpSp = IoGetNextIrpStackLocation ( Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_READ ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( override )
IrpSp - > Flags | = SL_OVERRIDE_VERIFY_VOLUME ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( DeviceObject - > Flags & DO_BUFFERED_IO ) {
2017-09-08 08:02:43 +00:00
Irp - > AssociatedIrp . SystemBuffer = ExAllocatePoolWithTag ( NonPagedPool , Length , ALLOC_TAG ) ;
if ( ! Irp - > AssociatedIrp . SystemBuffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
Irp - > Flags | = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION ;
Irp - > UserBuffer = Buffer ;
2016-03-23 20:35:05 +00:00
} else if ( DeviceObject - > Flags & DO_DIRECT_IO ) {
Irp - > MdlAddress = IoAllocateMdl ( Buffer , Length , FALSE , FALSE , NULL ) ;
if ( ! Irp - > MdlAddress ) {
ERR ( " IoAllocateMdl failed \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
_SEH2_TRY {
MmProbeAndLockPages ( Irp - > MdlAddress , KernelMode , IoWriteAccess ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
} _SEH2_END ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " MmProbeAndLockPages threw exception %08x \n " , Status ) ;
IoFreeMdl ( Irp - > MdlAddress ) ;
goto exit ;
}
} else
Irp - > UserBuffer = Buffer ;
IrpSp - > Parameters . Read . Length = Length ;
IrpSp - > Parameters . Read . ByteOffset = Offset ;
Irp - > UserIosb = & IoStatus ;
Irp - > UserEvent = & context . Event ;
IoSetCompletionRoutine ( Irp , read_completion , & context , TRUE , TRUE , TRUE ) ;
2016-03-23 20:35:05 +00:00
Status = IoCallDriver ( DeviceObject , Irp ) ;
if ( Status = = STATUS_PENDING ) {
2017-09-08 08:02:43 +00:00
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , FALSE , NULL ) ;
Status = context . iosb . Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( DeviceObject - > Flags & DO_DIRECT_IO ) {
MmUnlockPages ( Irp - > MdlAddress ) ;
IoFreeMdl ( Irp - > MdlAddress ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit :
IoFreeIrp ( Irp ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS read_superblock ( _In_ device_extension * Vcb , _In_ PDEVICE_OBJECT device , _In_ UINT64 length ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
superblock * sb ;
2017-09-08 08:02:43 +00:00
ULONG i , to_read ;
2016-10-29 17:05:10 +00:00
UINT8 valid_superblocks ;
2017-09-08 08:02:43 +00:00
to_read = device - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , device - > SectorSize ) ;
2016-03-23 20:35:05 +00:00
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
if ( superblock_addrs [ 0 ] + to_read > length ) {
WARN ( " device was too short to have any superblock \n " ) ;
ExFreePool ( sb ) ;
return STATUS_UNRECOGNIZED_VOLUME ;
}
2016-03-23 20:35:05 +00:00
i = 0 ;
2016-10-29 17:05:10 +00:00
valid_superblocks = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( superblock_addrs [ i ] > 0 ) {
2016-10-29 17:05:10 +00:00
UINT32 crc32 ;
2017-09-08 08:02:43 +00:00
if ( i > 0 & & superblock_addrs [ i ] + to_read > length )
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = sync_read_phys ( device , superblock_addrs [ i ] , to_read , ( PUCHAR ) sb , FALSE ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " Failed to read superblock %u: %08x \n " , i , Status ) ;
ExFreePool ( sb ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( sb - > magic ! = BTRFS_MAGIC ) {
if ( i = = 0 ) {
TRACE ( " not a BTRFS volume \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( sb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_UNRECOGNIZED_VOLUME ;
}
} else {
TRACE ( " got superblock %u! \n " , i ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
crc32 = ~ calc_crc32c ( 0xffffffff , ( UINT8 * ) & sb - > uuid , ( ULONG ) sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( crc32 ! = * ( ( UINT32 * ) sb - > checksum ) )
WARN ( " crc32 was %08x, expected %08x \n " , crc32 , * ( ( UINT32 * ) sb - > checksum ) ) ;
2017-09-08 08:02:43 +00:00
else if ( sb - > sector_size = = 0 )
WARN ( " superblock sector size was 0 \n " ) ;
else if ( sb - > node_size < sizeof ( tree_header ) + sizeof ( internal_node ) | | sb - > node_size > 0x10000 )
WARN ( " invalid node size %x \n " , sb - > node_size ) ;
else if ( ( sb - > node_size % sb - > sector_size ) ! = 0 )
WARN ( " node size %x was not a multiple of sector_size %x \n " , sb - > node_size , sb - > sector_size ) ;
2017-01-01 17:12:12 +00:00
else if ( valid_superblocks = = 0 | | sb - > generation > Vcb - > superblock . generation ) {
RtlCopyMemory ( & Vcb - > superblock , sb , sizeof ( superblock ) ) ;
valid_superblocks + + ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
i + + ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( sb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( valid_superblocks = = 0 ) {
ERR ( " could not find any valid superblocks \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " label is %s \n " , Vcb - > superblock . label ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS dev_ioctl ( _In_ PDEVICE_OBJECT DeviceObject , _In_ ULONG ControlCode , _In_reads_bytes_opt_ ( InputBufferSize ) PVOID InputBuffer , _In_ ULONG InputBufferSize ,
_Out_writes_bytes_opt_ ( OutputBufferSize ) PVOID OutputBuffer , _In_ ULONG OutputBufferSize , _In_ BOOLEAN Override , _Out_opt_ IO_STATUS_BLOCK * iosb ) {
2016-03-23 20:35:05 +00:00
PIRP Irp ;
KEVENT Event ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
PIO_STACK_LOCATION IrpSp ;
2016-03-23 20:35:05 +00:00
IO_STATUS_BLOCK IoStatus ;
KeInitializeEvent ( & Event , NotificationEvent , FALSE ) ;
Irp = IoBuildDeviceIoControlRequest ( ControlCode ,
DeviceObject ,
InputBuffer ,
InputBufferSize ,
OutputBuffer ,
OutputBufferSize ,
FALSE ,
& Event ,
& IoStatus ) ;
if ( ! Irp ) return STATUS_INSUFFICIENT_RESOURCES ;
if ( Override ) {
2017-09-08 08:02:43 +00:00
IrpSp = IoGetNextIrpStackLocation ( Irp ) ;
IrpSp - > Flags | = SL_OVERRIDE_VERIFY_VOLUME ;
2016-03-23 20:35:05 +00:00
}
Status = IoCallDriver ( DeviceObject , Irp ) ;
if ( Status = = STATUS_PENDING ) {
KeWaitForSingleObject ( & Event , Executive , KernelMode , FALSE , NULL ) ;
Status = IoStatus . Status ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( iosb )
* iosb = IoStatus ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Requires_exclusive_lock_held_ ( Vcb - > tree_lock )
static NTSTATUS add_root ( _Inout_ device_extension * Vcb , _In_ UINT64 id , _In_ UINT64 addr ,
_In_ UINT64 generation , _In_opt_ traverse_ptr * tp ) {
2016-03-23 20:35:05 +00:00
root * r = ExAllocatePoolWithTag ( PagedPool , sizeof ( root ) , ALLOC_TAG ) ;
if ( ! r ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
r - > id = id ;
2017-09-08 08:02:43 +00:00
r - > dirty = FALSE ;
r - > received = FALSE ;
r - > reserved = NULL ;
2016-03-23 20:35:05 +00:00
r - > treeholder . address = addr ;
r - > treeholder . tree = NULL ;
2017-09-08 08:02:43 +00:00
r - > treeholder . generation = generation ;
r - > parent = 0 ;
r - > send_ops = 0 ;
2016-05-05 17:26:47 +00:00
InitializeListHead ( & r - > fcbs ) ;
2016-03-23 20:35:05 +00:00
r - > nonpaged = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( root_nonpaged ) , ALLOC_TAG ) ;
if ( ! r - > nonpaged ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( r ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
r - > lastinode = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp ) {
RtlCopyMemory ( & r - > root_item , tp - > item - > data , min ( sizeof ( ROOT_ITEM ) , tp - > item - > size ) ) ;
if ( tp - > item - > size < sizeof ( ROOT_ITEM ) )
RtlZeroMemory ( ( ( UINT8 * ) & r - > root_item ) + tp - > item - > size , sizeof ( ROOT_ITEM ) - tp - > item - > size ) ;
2017-09-08 08:02:43 +00:00
} else
RtlZeroMemory ( & r - > root_item , sizeof ( ROOT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
if ( ! Vcb - > readonly & & ( r - > id = = BTRFS_ROOT_ROOT | | r - > id = = BTRFS_ROOT_FSTREE | | ( r - > id > = 0x100 & & ! ( r - > id & 0xf000000000000000 ) ) ) ) { // FS tree root
// FIXME - don't call this if subvol is readonly (though we will have to if we ever toggle this flag)
get_last_inode ( Vcb , r , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( r - > id = = BTRFS_ROOT_ROOT & & r - > lastinode < 0x100 )
r - > lastinode = 0x100 ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InsertTailList ( & Vcb - > roots , & r - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( r - > id ) {
case BTRFS_ROOT_ROOT :
Vcb - > root_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_EXTENT :
Vcb - > extent_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_CHUNK :
Vcb - > chunk_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_DEVTREE :
Vcb - > dev_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_CHECKSUM :
Vcb - > checksum_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
case BTRFS_ROOT_UUID :
Vcb - > uuid_root = r ;
break ;
2017-09-08 08:02:43 +00:00
case BTRFS_ROOT_FREE_SPACE :
Vcb - > space_root = r ;
break ;
2016-10-29 17:05:10 +00:00
case BTRFS_ROOT_DATA_RELOC :
Vcb - > data_reloc_root = r ;
2017-09-08 08:02:43 +00:00
break ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS look_for_roots ( _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) _In_ device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
traverse_ptr tp , next_tp ;
KEY searchkey ;
BOOL b ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_id = 0 ;
searchkey . obj_type = 0 ;
searchkey . offset = 0 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , FALSE , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2017-09-08 08:02:43 +00:00
ERR ( " error - find_item returned %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
do {
TRACE ( " (%llx,%x,%llx) \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > key . obj_type = = TYPE_ROOT_ITEM ) {
ROOT_ITEM * ri = ( ROOT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > size < offsetof ( ROOT_ITEM , byte_limit ) ) {
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 , offsetof ( ROOT_ITEM , byte_limit ) ) ;
} else {
TRACE ( " root %llx - address %llx \n " , tp . item - > key . obj_id , ri - > block_number ) ;
2017-09-08 08:02:43 +00:00
Status = add_root ( Vcb , tp . item - > key . obj_id , ri - > block_number , ri - > generation , & tp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " add_root returned %08x \n " , Status ) ;
return Status ;
}
}
2017-09-08 08:02:43 +00:00
} else if ( tp . item - > key . obj_type = = TYPE_ROOT_BACKREF & & ! IsListEmpty ( & Vcb - > roots ) ) {
root * lastroot = CONTAINING_RECORD ( Vcb - > roots . Blink , root , list_entry ) ;
if ( lastroot - > id = = tp . item - > key . obj_id )
lastroot - > parent = tp . item - > key . offset ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , FALSE , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( b )
2016-03-23 20:35:05 +00:00
tp = next_tp ;
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! Vcb - > readonly & & ! Vcb - > data_reloc_root ) {
root * reloc_root ;
INODE_ITEM * ii ;
2017-09-08 08:02:43 +00:00
UINT16 irlen ;
2016-10-29 17:05:10 +00:00
INODE_REF * ir ;
LARGE_INTEGER time ;
BTRFS_TIME now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
WARN ( " data reloc root doesn't exist, creating it \n " ) ;
2017-09-08 08:02:43 +00:00
Status = create_root ( Vcb , BTRFS_ROOT_DATA_RELOC , & reloc_root , FALSE , 0 , Irp ) ;
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " create_root returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
reloc_root - > root_item . inode . generation = 1 ;
reloc_root - > root_item . inode . st_size = 3 ;
reloc_root - > root_item . inode . st_blocks = Vcb - > superblock . node_size ;
reloc_root - > root_item . inode . st_nlink = 1 ;
reloc_root - > root_item . inode . st_mode = 040755 ;
reloc_root - > root_item . inode . flags = 0xffffffff80000000 ;
reloc_root - > root_item . objid = SUBVOL_ROOT_INODE ;
reloc_root - > root_item . bytes_used = Vcb - > superblock . node_size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ii = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_ITEM ) , ALLOC_TAG ) ;
if ( ! ii ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlZeroMemory ( ii , sizeof ( INODE_ITEM ) ) ;
ii - > generation = Vcb - > superblock . generation ;
ii - > st_blocks = Vcb - > superblock . node_size ;
ii - > st_nlink = 1 ;
ii - > st_mode = 040755 ;
ii - > st_atime = now ;
ii - > st_ctime = now ;
ii - > st_mtime = now ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , reloc_root , SUBVOL_ROOT_INODE , TYPE_INODE_ITEM , 0 , ii , sizeof ( INODE_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " insert_tree_item returned %08x \n " , Status ) ;
ExFreePool ( ii ) ;
return Status ;
}
irlen = ( UINT16 ) offsetof ( INODE_REF , name [ 0 ] ) + 2 ;
2016-10-29 17:05:10 +00:00
ir = ExAllocatePoolWithTag ( PagedPool , irlen , ALLOC_TAG ) ;
if ( ! ir ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ir - > index = 0 ;
ir - > n = 2 ;
ir - > name [ 0 ] = ' . ' ;
ir - > name [ 1 ] = ' . ' ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , reloc_root , SUBVOL_ROOT_INODE , TYPE_INODE_REF , SUBVOL_ROOT_INODE , ir , irlen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " insert_tree_item returned %08x \n " , Status ) ;
ExFreePool ( ir ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
Vcb - > data_reloc_root = reloc_root ;
Vcb - > need_write = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS find_disk_holes ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ device * dev , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
KEY searchkey ;
traverse_ptr tp , next_tp ;
BOOL b ;
UINT64 lastaddr ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InitializeListHead ( & dev - > space ) ;
2017-09-08 08:02:43 +00:00
searchkey . obj_id = 0 ;
searchkey . obj_type = TYPE_DEV_STATS ;
searchkey . offset = dev - > devitem . dev_id ;
Status = find_item ( Vcb , Vcb - > dev_root , & tp , & searchkey , FALSE , Irp ) ;
if ( NT_SUCCESS ( Status ) & & ! keycmp ( tp . item - > key , searchkey ) )
RtlCopyMemory ( dev - > stats , tp . item - > data , min ( sizeof ( UINT64 ) * 5 , tp . item - > size ) ) ;
2016-03-23 20:35:05 +00:00
searchkey . obj_id = dev - > devitem . dev_id ;
searchkey . obj_type = TYPE_DEV_EXTENT ;
searchkey . offset = 0 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = find_item ( Vcb , Vcb - > dev_root , & tp , & searchkey , FALSE , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2017-09-08 08:02:43 +00:00
ERR ( " error - find_item returned %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
lastaddr = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
do {
if ( tp . item - > key . obj_id = = dev - > devitem . dev_id & & tp . item - > key . obj_type = = TYPE_DEV_EXTENT ) {
if ( tp . item - > size > = sizeof ( DEV_EXTENT ) ) {
DEV_EXTENT * de = ( DEV_EXTENT * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > key . offset > lastaddr ) {
2016-07-27 19:24:26 +00:00
Status = add_space_entry ( & dev - > space , NULL , lastaddr , tp . item - > key . offset - lastaddr ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " add_space_entry returned %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
}
lastaddr = tp . item - > key . offset + de - > length ;
} else {
ERR ( " (%llx,%x,%llx) was %u bytes, expected %u \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DEV_EXTENT ) ) ;
}
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , FALSE , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( b ) {
tp = next_tp ;
if ( tp . item - > key . obj_id > searchkey . obj_id | | tp . item - > key . obj_type > searchkey . obj_type )
break ;
}
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( lastaddr < dev - > devitem . num_bytes ) {
2016-07-27 19:24:26 +00:00
Status = add_space_entry ( & dev - > space , NULL , lastaddr , dev - > devitem . num_bytes - lastaddr ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " add_space_entry returned %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// The Linux driver doesn't like to allocate chunks within the first megabyte of a device.
2017-09-08 08:02:43 +00:00
space_list_subtract2 ( & dev - > space , NULL , 0 , 0x100000 , NULL , NULL ) ;
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static void add_device_to_list ( _In_ device_extension * Vcb , _In_ device * dev ) {
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( le ! = & Vcb - > devices ) {
device * dev2 = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev2 - > devitem . dev_id > dev - > devitem . dev_id ) {
InsertHeadList ( le - > Blink , & dev - > list_entry ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertTailList ( & Vcb - > devices , & dev - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
_Ret_maybenull_
device * find_device_from_uuid ( _In_ device_extension * Vcb , _In_ BTRFS_UUID * uuid ) {
volume_device_extension * vde ;
pdo_device_extension * pdode ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x \n " , dev - > devitem . dev_id ,
dev - > devitem . device_uuid . uuid [ 0 ] , dev - > devitem . device_uuid . uuid [ 1 ] , dev - > devitem . device_uuid . uuid [ 2 ] , dev - > devitem . device_uuid . uuid [ 3 ] , dev - > devitem . device_uuid . uuid [ 4 ] , dev - > devitem . device_uuid . uuid [ 5 ] , dev - > devitem . device_uuid . uuid [ 6 ] , dev - > devitem . device_uuid . uuid [ 7 ] ,
dev - > devitem . device_uuid . uuid [ 8 ] , dev - > devitem . device_uuid . uuid [ 9 ] , dev - > devitem . device_uuid . uuid [ 10 ] , dev - > devitem . device_uuid . uuid [ 11 ] , dev - > devitem . device_uuid . uuid [ 12 ] , dev - > devitem . device_uuid . uuid [ 13 ] , dev - > devitem . device_uuid . uuid [ 14 ] , dev - > devitem . device_uuid . uuid [ 15 ] ) ;
2017-09-08 08:02:43 +00:00
if ( RtlCompareMemory ( & dev - > devitem . device_uuid , uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
2017-01-01 17:12:12 +00:00
TRACE ( " returning device %llx \n " , dev - > devitem . dev_id ) ;
return dev ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
vde = Vcb - > vde ;
if ( ! vde )
goto end ;
pdode = vde - > pdode ;
ExAcquireResourceSharedLite ( & pdode - > child_lock , TRUE ) ;
if ( Vcb - > devices_loaded < Vcb - > superblock . num_devices ) {
le = pdode - > children . Flink ;
while ( le ! = & pdode - > children ) {
volume_child * vc = CONTAINING_RECORD ( le , volume_child , list_entry ) ;
if ( RtlCompareMemory ( uuid , & vc - > uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
2017-01-01 17:12:12 +00:00
device * dev ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-01-01 17:12:12 +00:00
ERR ( " out of memory \n " ) ;
return NULL ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( dev , sizeof ( device ) ) ;
2017-09-08 08:02:43 +00:00
dev - > devobj = vc - > devobj ;
2017-01-01 17:12:12 +00:00
dev - > devitem . device_uuid = * uuid ;
2017-09-08 08:02:43 +00:00
dev - > devitem . dev_id = vc - > devid ;
dev - > devitem . num_bytes = vc - > size ;
dev - > seeding = vc - > seeding ;
2017-01-01 17:12:12 +00:00
dev - > readonly = dev - > seeding ;
dev - > reloc = FALSE ;
dev - > removable = FALSE ;
2017-09-08 08:02:43 +00:00
dev - > disk_num = vc - > disk_num ;
dev - > part_num = vc - > part_num ;
dev - > num_trim_entries = 0 ;
InitializeListHead ( & dev - > trim_list ) ;
2017-01-01 17:12:12 +00:00
add_device_to_list ( Vcb , dev ) ;
2016-07-27 19:24:26 +00:00
Vcb - > devices_loaded + + ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-01-01 17:12:12 +00:00
return dev ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
end :
2016-03-23 20:35:05 +00:00
WARN ( " could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x \n " ,
uuid - > uuid [ 0 ] , uuid - > uuid [ 1 ] , uuid - > uuid [ 2 ] , uuid - > uuid [ 3 ] , uuid - > uuid [ 4 ] , uuid - > uuid [ 5 ] , uuid - > uuid [ 6 ] , uuid - > uuid [ 7 ] ,
uuid - > uuid [ 8 ] , uuid - > uuid [ 9 ] , uuid - > uuid [ 10 ] , uuid - > uuid [ 11 ] , uuid - > uuid [ 12 ] , uuid - > uuid [ 13 ] , uuid - > uuid [ 14 ] , uuid - > uuid [ 15 ] ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return NULL ;
}
2017-09-08 08:02:43 +00:00
static BOOL is_device_removable ( _In_ PDEVICE_OBJECT devobj ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
STORAGE_HOTPLUG_INFO shi ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = dev_ioctl ( devobj , IOCTL_STORAGE_GET_HOTPLUG_INFO , NULL , 0 , & shi , sizeof ( STORAGE_HOTPLUG_INFO ) , TRUE , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " dev_ioctl returned %08x \n " , Status ) ;
return FALSE ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return shi . MediaRemovable ! = 0 ? TRUE : FALSE ;
}
2017-09-08 08:02:43 +00:00
static ULONG get_device_change_count ( _In_ PDEVICE_OBJECT devobj ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
ULONG cc ;
IO_STATUS_BLOCK iosb ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = dev_ioctl ( devobj , IOCTL_STORAGE_CHECK_VERIFY , NULL , 0 , & cc , sizeof ( ULONG ) , TRUE , & iosb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " dev_ioctl returned %08x \n " , Status ) ;
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( iosb . Information < sizeof ( ULONG ) ) {
ERR ( " iosb.Information was too short \n " ) ;
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return cc ;
}
2017-09-08 08:02:43 +00:00
void init_device ( _In_ device_extension * Vcb , _Inout_ device * dev , _In_ BOOL get_nums ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
ULONG aptelen ;
ATA_PASS_THROUGH_EX * apte ;
2017-09-08 08:02:43 +00:00
STORAGE_PROPERTY_QUERY spq ;
DEVICE_TRIM_DESCRIPTOR dtd ;
2016-07-27 19:24:26 +00:00
dev - > removable = is_device_removable ( dev - > devobj ) ;
dev - > change_count = dev - > removable ? get_device_change_count ( dev - > devobj ) : 0 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( get_nums ) {
STORAGE_DEVICE_NUMBER sdn ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = dev_ioctl ( dev - > devobj , IOCTL_STORAGE_GET_DEVICE_NUMBER , NULL , 0 ,
& sdn , sizeof ( STORAGE_DEVICE_NUMBER ) , TRUE , NULL ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
WARN ( " IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
dev - > disk_num = 0xffffffff ;
dev - > part_num = 0xffffffff ;
2017-01-01 17:12:12 +00:00
} else {
dev - > disk_num = sdn . DeviceNumber ;
dev - > part_num = sdn . PartitionNumber ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
dev - > trim = FALSE ;
dev - > readonly = dev - > seeding ;
2017-01-01 17:12:12 +00:00
dev - > reloc = FALSE ;
2017-09-08 08:02:43 +00:00
dev - > num_trim_entries = 0 ;
dev - > stats_changed = FALSE ;
InitializeListHead ( & dev - > trim_list ) ;
2016-10-29 17:05:10 +00:00
if ( ! dev - > readonly ) {
Status = dev_ioctl ( dev - > devobj , IOCTL_DISK_IS_WRITABLE , NULL , 0 ,
NULL , 0 , TRUE , NULL ) ;
if ( Status = = STATUS_MEDIA_WRITE_PROTECTED )
dev - > readonly = TRUE ;
}
aptelen = sizeof ( ATA_PASS_THROUGH_EX ) + 512 ;
apte = ExAllocatePoolWithTag ( NonPagedPool , aptelen , ALLOC_TAG ) ;
if ( ! apte ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlZeroMemory ( apte , aptelen ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
apte - > Length = sizeof ( ATA_PASS_THROUGH_EX ) ;
apte - > AtaFlags = ATA_FLAGS_DATA_IN ;
apte - > DataTransferLength = aptelen - sizeof ( ATA_PASS_THROUGH_EX ) ;
apte - > TimeOutValue = 3 ;
apte - > DataBufferOffset = apte - > Length ;
2017-09-08 08:02:43 +00:00
apte - > CurrentTaskFile [ 6 ] = IDE_COMMAND_IDENTIFY ;
2016-10-29 17:05:10 +00:00
Status = dev_ioctl ( dev - > devobj , IOCTL_ATA_PASS_THROUGH , apte , aptelen ,
apte , aptelen , TRUE , NULL ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) )
TRACE ( " IOCTL_ATA_PASS_THROUGH returned %08x for IDENTIFY DEVICE \n " , Status ) ;
else {
2017-09-08 08:02:43 +00:00
IDENTIFY_DEVICE_DATA * idd = ( IDENTIFY_DEVICE_DATA * ) ( ( UINT8 * ) apte + sizeof ( ATA_PASS_THROUGH_EX ) ) ;
if ( idd - > CommandSetSupport . FlushCache ) {
dev - > can_flush = TRUE ;
TRACE ( " FLUSH CACHE supported \n " ) ;
} else
TRACE ( " FLUSH CACHE not supported \n " ) ;
}
ExFreePool ( apte ) ;
spq . PropertyId = StorageDeviceTrimProperty ;
spq . QueryType = PropertyStandardQuery ;
spq . AdditionalParameters [ 0 ] = 0 ;
Status = dev_ioctl ( dev - > devobj , IOCTL_STORAGE_QUERY_PROPERTY , & spq , sizeof ( STORAGE_PROPERTY_QUERY ) ,
& dtd , sizeof ( DEVICE_TRIM_DESCRIPTOR ) , TRUE , NULL ) ;
if ( NT_SUCCESS ( Status ) ) {
if ( dtd . TrimEnabled ) {
2016-10-29 17:05:10 +00:00
dev - > trim = TRUE ;
Vcb - > trim = TRUE ;
TRACE ( " TRIM supported \n " ) ;
} else
TRACE ( " TRIM not supported \n " ) ;
}
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( dev - > stats , sizeof ( UINT64 ) * 5 ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS load_chunk_root ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
traverse_ptr tp , next_tp ;
KEY searchkey ;
BOOL b ;
chunk * c ;
NTSTATUS Status ;
searchkey . obj_id = 0 ;
searchkey . obj_type = 0 ;
searchkey . offset = 0 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Vcb - > data_flags = 0 ;
2017-01-01 17:12:12 +00:00
Vcb - > metadata_flags = 0 ;
Vcb - > system_flags = 0 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = find_item ( Vcb , Vcb - > chunk_root , & tp , & searchkey , FALSE , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
do {
TRACE ( " (%llx,%x,%llx) \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( tp . item - > key . obj_id = = 1 & & tp . item - > key . obj_type = = TYPE_DEV_ITEM ) {
if ( tp . item - > size < sizeof ( DEV_ITEM ) ) {
ERR ( " (%llx,%x,%llx) was %u bytes, expected %u \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DEV_ITEM ) ) ;
} else {
DEV_ITEM * di = ( DEV_ITEM * ) tp . item - > data ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2016-07-27 19:24:26 +00:00
BOOL done = FALSE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev - > devobj & & RtlCompareMemory ( & dev - > devitem . device_uuid , & di - > device_uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
RtlCopyMemory ( & dev - > devitem , tp . item - > data , min ( tp . item - > size , sizeof ( DEV_ITEM ) ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( le ! = Vcb - > devices . Flink )
2017-09-08 08:02:43 +00:00
init_device ( Vcb , dev , TRUE ) ;
2016-07-27 19:24:26 +00:00
done = TRUE ;
break ;
}
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( ! done & & Vcb - > vde ) {
volume_device_extension * vde = Vcb - > vde ;
pdo_device_extension * pdode = vde - > pdode ;
ExAcquireResourceSharedLite ( & pdode - > child_lock , TRUE ) ;
if ( Vcb - > devices_loaded < Vcb - > superblock . num_devices ) {
le = pdode - > children . Flink ;
while ( le ! = & pdode - > children ) {
volume_child * vc = CONTAINING_RECORD ( le , volume_child , list_entry ) ;
if ( RtlCompareMemory ( & di - > device_uuid , & vc - > uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
2017-01-01 17:12:12 +00:00
device * dev ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-01-01 17:12:12 +00:00
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( dev , sizeof ( device ) ) ;
2017-09-08 08:02:43 +00:00
dev - > devobj = vc - > devobj ;
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( & dev - > devitem , di , min ( tp . item - > size , sizeof ( DEV_ITEM ) ) ) ;
2017-09-08 08:02:43 +00:00
dev - > seeding = vc - > seeding ;
init_device ( Vcb , dev , FALSE ) ;
2017-01-01 17:12:12 +00:00
2017-09-08 08:02:43 +00:00
if ( dev - > devitem . num_bytes > vc - > size ) {
WARN ( " device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx \n " , tp . item - > key . offset ,
dev - > devitem . num_bytes , vc - > size ) ;
dev - > devitem . num_bytes = vc - > size ;
}
dev - > disk_num = vc - > disk_num ;
dev - > part_num = vc - > part_num ;
2017-01-01 17:12:12 +00:00
add_device_to_list ( Vcb , dev ) ;
2016-07-27 19:24:26 +00:00
Vcb - > devices_loaded + + ;
done = TRUE ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! done ) {
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > options . allow_degraded ) {
ERR ( " volume not found: device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x \n " , tp . item - > key . offset ,
di - > device_uuid . uuid [ 0 ] , di - > device_uuid . uuid [ 1 ] , di - > device_uuid . uuid [ 2 ] , di - > device_uuid . uuid [ 3 ] , di - > device_uuid . uuid [ 4 ] , di - > device_uuid . uuid [ 5 ] , di - > device_uuid . uuid [ 6 ] , di - > device_uuid . uuid [ 7 ] ,
di - > device_uuid . uuid [ 8 ] , di - > device_uuid . uuid [ 9 ] , di - > device_uuid . uuid [ 10 ] , di - > device_uuid . uuid [ 11 ] , di - > device_uuid . uuid [ 12 ] , di - > device_uuid . uuid [ 13 ] , di - > device_uuid . uuid [ 14 ] , di - > device_uuid . uuid [ 15 ] ) ;
} else {
device * dev ;
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
ExReleaseResourceLite ( & pdode - > child_lock ) ;
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlZeroMemory ( dev , sizeof ( device ) ) ;
// Missing device, so we keep dev->devobj as NULL
RtlCopyMemory ( & dev - > devitem , di , min ( tp . item - > size , sizeof ( DEV_ITEM ) ) ) ;
InitializeListHead ( & dev - > trim_list ) ;
add_device_to_list ( Vcb , dev ) ;
Vcb - > devices_loaded + + ;
}
2016-07-27 19:24:26 +00:00
}
} else
ERR ( " unexpected device %llx found \n " , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2016-07-27 19:24:26 +00:00
}
}
2016-03-23 20:35:05 +00:00
} else if ( tp . item - > key . obj_type = = TYPE_CHUNK_ITEM ) {
if ( tp . item - > size < sizeof ( CHUNK_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 ( CHUNK_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
} else {
2016-09-04 15:27:46 +00:00
c = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( chunk ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! c ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
c - > size = tp . item - > size ;
c - > offset = tp . item - > key . offset ;
c - > used = c - > oldused = 0 ;
2017-09-08 08:02:43 +00:00
c - > cache = c - > old_cache = NULL ;
2016-07-27 19:24:26 +00:00
c - > created = FALSE ;
2016-10-29 17:05:10 +00:00
c - > readonly = FALSE ;
2017-01-01 17:12:12 +00:00
c - > reloc = FALSE ;
2017-09-08 08:02:43 +00:00
c - > cache_loaded = FALSE ;
c - > changed = FALSE ;
c - > space_changed = FALSE ;
c - > balance_num = 0 ;
2016-09-04 15:27:46 +00:00
c - > chunk_item = ExAllocatePoolWithTag ( NonPagedPool , tp . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! c - > chunk_item ) {
ERR ( " out of memory \n " ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( c ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( c - > chunk_item , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_DATA & & c - > chunk_item - > type > Vcb - > data_flags )
Vcb - > data_flags = c - > chunk_item - > type ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_METADATA & & c - > chunk_item - > type > Vcb - > metadata_flags )
Vcb - > metadata_flags = c - > chunk_item - > type ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_SYSTEM & & c - > chunk_item - > type > Vcb - > system_flags )
Vcb - > system_flags = c - > chunk_item - > type ;
2017-09-08 08:02:43 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_RAID10 ) {
if ( c - > chunk_item - > sub_stripes = = 0 | | c - > chunk_item - > sub_stripes > c - > chunk_item - > num_stripes ) {
ERR ( " chunk %llx: invalid stripes (num_stripes %u, sub_stripes %u) \n " , c - > offset , c - > chunk_item - > num_stripes , c - > chunk_item - > sub_stripes ) ;
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
return STATUS_INTERNAL_ERROR ;
}
}
2016-03-23 20:35:05 +00:00
if ( c - > chunk_item - > num_stripes > 0 ) {
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & c - > chunk_item [ 1 ] ;
2017-01-01 17:12:12 +00:00
UINT16 i ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
c - > devices = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device * ) * c - > chunk_item - > num_stripes , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! c - > devices ) {
ERR ( " out of memory \n " ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( c - > chunk_item ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( c ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
c - > devices [ i ] = find_device_from_uuid ( Vcb , & cis [ i ] . dev_uuid ) ;
TRACE ( " device %llu = %p \n " , i , c - > devices [ i ] ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! c - > devices [ i ] ) {
ERR ( " missing device \n " ) ;
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c - > devices [ i ] - > readonly )
c - > readonly = TRUE ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
} else {
ERR ( " chunk %llx: number of stripes is 0 \n " , c - > offset ) ;
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
return STATUS_INTERNAL_ERROR ;
}
2016-09-04 15:27:46 +00:00
ExInitializeResourceLite ( & c - > lock ) ;
ExInitializeResourceLite ( & c - > changed_extents_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeListHead ( & c - > space ) ;
2016-07-27 19:24:26 +00:00
InitializeListHead ( & c - > space_size ) ;
InitializeListHead ( & c - > deleting ) ;
InitializeListHead ( & c - > changed_extents ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & c - > range_locks ) ;
2017-09-08 08:02:43 +00:00
ExInitializeResourceLite ( & c - > range_locks_lock ) ;
2016-10-29 17:05:10 +00:00
KeInitializeEvent ( & c - > range_locks_event , NotificationEvent , FALSE ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & c - > partial_stripes ) ;
ExInitializeResourceLite ( & c - > partial_stripes_lock ) ;
2017-01-01 17:12:12 +00:00
c - > last_alloc_set = FALSE ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
c - > last_stripe = 0 ;
2016-03-23 20:35:05 +00:00
InsertTailList ( & Vcb - > chunks , & c - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c - > list_entry_balance . Flink = NULL ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , FALSE , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( b )
2016-03-23 20:35:05 +00:00
tp = next_tp ;
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Vcb - > log_to_phys_loaded = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > data_flags = = 0 )
Vcb - > data_flags = BLOCK_FLAG_DATA | ( Vcb - > superblock . num_devices > 1 ? BLOCK_FLAG_RAID0 : 0 ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > metadata_flags = = 0 )
Vcb - > metadata_flags = BLOCK_FLAG_METADATA | ( Vcb - > superblock . num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > system_flags = = 0 )
Vcb - > system_flags = BLOCK_FLAG_SYSTEM | ( Vcb - > superblock . num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS ) {
Vcb - > metadata_flags | = BLOCK_FLAG_DATA ;
Vcb - > data_flags = Vcb - > metadata_flags ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
void protect_superblocks ( _Inout_ chunk * c ) {
2016-07-27 19:24:26 +00:00
UINT16 i = 0 , j ;
2016-05-05 17:26:47 +00:00
UINT64 off_start , off_end ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// The Linux driver also protects all the space before the first superblock.
2017-09-08 08:02:43 +00:00
// I realize this confuses physical and logical addresses, but this is what btrfs-progs does -
2016-07-27 19:24:26 +00:00
// evidently Linux assumes the chunk at 0 is always SINGLE.
if ( c - > offset < superblock_addrs [ 0 ] )
2017-09-08 08:02:43 +00:00
space_list_subtract ( c , FALSE , c - > offset , superblock_addrs [ 0 ] - c - > offset , NULL ) ;
2016-03-23 20:35:05 +00:00
while ( superblock_addrs [ i ] ! = 0 ) {
CHUNK_ITEM * ci = c - > chunk_item ;
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & ci [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ci - > type & BLOCK_FLAG_RAID0 | | ci - > type & BLOCK_FLAG_RAID10 ) {
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
2017-09-08 08:02:43 +00:00
UINT16 sub_stripes = max ( ci - > sub_stripes , 1 ) ;
2016-07-27 19:24:26 +00:00
if ( cis [ j ] . offset + ( ci - > size * ci - > num_stripes / sub_stripes ) > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
# ifdef _DEBUG
UINT64 startoff ;
UINT16 startoffstripe ;
# endif
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " cut out superblock in chunk %llx \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
off_start = superblock_addrs [ i ] - cis [ j ] . offset ;
off_start - = off_start % ci - > stripe_length ;
off_start * = ci - > num_stripes / sub_stripes ;
off_start + = ( j / sub_stripes ) * ci - > stripe_length ;
off_end = off_start + ci - > stripe_length ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
# ifdef _DEBUG
get_raid0_offset ( off_start , ci - > stripe_length , ci - > num_stripes / sub_stripes , & startoff , & startoffstripe ) ;
TRACE ( " j = %u, startoffstripe = %u \n " , j , startoffstripe ) ;
TRACE ( " startoff = %llx, superblock = %llx \n " , startoff + cis [ j ] . offset , superblock_addrs [ i ] ) ;
# endif
2017-09-08 08:02:43 +00:00
space_list_subtract ( c , FALSE , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-10-29 17:05:10 +00:00
}
}
} else if ( ci - > type & BLOCK_FLAG_RAID5 ) {
2017-09-08 08:02:43 +00:00
UINT64 stripe_size = ci - > size / ( ci - > num_stripes - 1 ) ;
2016-10-29 17:05:10 +00:00
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
if ( cis [ j ] . offset + stripe_size > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
TRACE ( " cut out superblock in chunk %llx \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
off_start = superblock_addrs [ i ] - cis [ j ] . offset ;
2017-09-08 08:02:43 +00:00
off_start - = off_start % ci - > stripe_length ;
2016-10-29 17:05:10 +00:00
off_start * = ci - > num_stripes - 1 ;
2017-09-08 08:02:43 +00:00
off_end = sector_align ( superblock_addrs [ i ] - cis [ j ] . offset + sizeof ( superblock ) , ci - > stripe_length ) ;
off_end * = ci - > num_stripes - 1 ;
2016-10-29 17:05:10 +00:00
TRACE ( " cutting out %llx, size %llx \n " , c - > offset + off_start , off_end - off_start ) ;
2017-09-08 08:02:43 +00:00
space_list_subtract ( c , FALSE , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-10-29 17:05:10 +00:00
}
}
} else if ( ci - > type & BLOCK_FLAG_RAID6 ) {
2017-09-08 08:02:43 +00:00
UINT64 stripe_size = ci - > size / ( ci - > num_stripes - 2 ) ;
2016-10-29 17:05:10 +00:00
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
if ( cis [ j ] . offset + stripe_size > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
TRACE ( " cut out superblock in chunk %llx \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
off_start = superblock_addrs [ i ] - cis [ j ] . offset ;
2017-09-08 08:02:43 +00:00
off_start - = off_start % ci - > stripe_length ;
2016-10-29 17:05:10 +00:00
off_start * = ci - > num_stripes - 2 ;
2017-09-08 08:02:43 +00:00
off_end = sector_align ( superblock_addrs [ i ] - cis [ j ] . offset + sizeof ( superblock ) , ci - > stripe_length ) ;
off_end * = ci - > num_stripes - 2 ;
2016-10-29 17:05:10 +00:00
TRACE ( " cutting out %llx, size %llx \n " , c - > offset + off_start , off_end - off_start ) ;
2017-09-08 08:02:43 +00:00
space_list_subtract ( c , FALSE , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-07-27 19:24:26 +00:00
}
}
} else { // SINGLE, DUPLICATE, RAID1
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
if ( cis [ j ] . offset + ci - > size > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
TRACE ( " cut out superblock in chunk %llx \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// The Linux driver protects the whole stripe in which the superblock lives
off_start = ( ( superblock_addrs [ i ] - cis [ j ] . offset ) / c - > chunk_item - > stripe_length ) * c - > chunk_item - > stripe_length ;
off_end = sector_align ( superblock_addrs [ i ] - cis [ j ] . offset + sizeof ( superblock ) , c - > chunk_item - > stripe_length ) ;
2017-09-08 08:02:43 +00:00
space_list_subtract ( c , FALSE , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
i + + ;
}
}
2017-09-08 08:02:43 +00:00
NTSTATUS find_chunk_usage ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
LIST_ENTRY * le = Vcb - > chunks . Flink ;
chunk * c ;
KEY searchkey ;
traverse_ptr tp ;
BLOCK_GROUP_ITEM * bgi ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_type = TYPE_BLOCK_GROUP_ITEM ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( le ! = & Vcb - > chunks ) {
c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_id = c - > offset ;
searchkey . offset = c - > chunk_item - > size ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , FALSE , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( searchkey , tp . item - > key ) ) {
2016-03-23 20:35:05 +00:00
if ( tp . item - > size > = sizeof ( BLOCK_GROUP_ITEM ) ) {
bgi = ( BLOCK_GROUP_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
c - > used = c - > oldused = bgi - > used ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " chunk %llx has %llx bytes used \n " , c - > offset , c - > used ) ;
} else {
ERR ( " (%llx;%llx,%x,%llx) is %u bytes, expected %u \n " ,
Vcb - > extent_root - > id , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( BLOCK_GROUP_ITEM ) ) ;
}
}
2016-10-29 17:05:10 +00:00
2016-03-23 20:35:05 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
Vcb - > chunk_usage_found = TRUE ;
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS load_sys_chunks ( _In_ device_extension * Vcb ) {
2016-03-23 20:35:05 +00:00
KEY key ;
ULONG n = Vcb - > superblock . n ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( n > 0 ) {
if ( n > sizeof ( KEY ) ) {
RtlCopyMemory ( & key , & Vcb - > superblock . sys_chunk_array [ Vcb - > superblock . n - n ] , sizeof ( KEY ) ) ;
n - = sizeof ( KEY ) ;
} else
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " bootstrap: %llx,%x,%llx \n " , key . obj_id , key . obj_type , key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( key . obj_type = = TYPE_CHUNK_ITEM ) {
CHUNK_ITEM * ci ;
2017-09-08 08:02:43 +00:00
USHORT cisize ;
2016-03-23 20:35:05 +00:00
sys_chunk * sc ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( n < sizeof ( CHUNK_ITEM ) )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ci = ( CHUNK_ITEM * ) & Vcb - > superblock . sys_chunk_array [ Vcb - > superblock . n - n ] ;
cisize = sizeof ( CHUNK_ITEM ) + ( ci - > num_stripes * sizeof ( CHUNK_ITEM_STRIPE ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( n < cisize )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
sc = ExAllocatePoolWithTag ( PagedPool , sizeof ( sys_chunk ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! sc ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
sc - > key = key ;
sc - > size = cisize ;
sc - > data = ExAllocatePoolWithTag ( PagedPool , sc - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! sc - > data ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( sc ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( sc - > data , ci , sc - > size ) ;
InsertTailList ( & Vcb - > sys_chunks , & sc - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
n - = cisize ;
} else {
ERR ( " unexpected item %llx,%x,%llx in bootstrap \n " , key . obj_id , key . obj_type , key . offset ) ;
return STATUS_INTERNAL_ERROR ;
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
_Ret_maybenull_
static root * find_default_subvol ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-05-05 17:26:47 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
static char fn [ ] = " default " ;
2016-03-23 20:35:05 +00:00
static UINT32 crc32 = 0x8dbfc2d2 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > options . subvol_id ! = 0 ) {
le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( r - > id = = Vcb - > options . subvol_id )
return r ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
DIR_ITEM * di ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
searchkey . obj_id = Vcb - > superblock . root_dir_objectid ;
searchkey . obj_type = TYPE_DIR_ITEM ;
searchkey . offset = crc32 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , FALSE , Irp ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " could not find (%llx,%x,%llx) in root tree \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
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 ) ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
di = ( DIR_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( tp . item - > size < sizeof ( DIR_ITEM ) - 1 + di - > n ) {
ERR ( " (%llx,%x,%llx) was %u bytes, expected %u \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DIR_ITEM ) - 1 + di - > n ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( di - > n ! = strlen ( fn ) | | RtlCompareMemory ( di - > name , fn , di - > n ) ! = di - > n ) {
ERR ( " root DIR_ITEM had same CRC32, but was not \" default \" \n " ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( di - > key . obj_type ! = TYPE_ROOT_ITEM ) {
ERR ( " default root has key (%llx,%x,%llx), expected subvolume \n " , di - > key . obj_id , di - > key . obj_type , di - > key . offset ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( r - > id = = di - > key . obj_id )
return r ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ERR ( " could not find root %llx, using default instead \n " , di - > key . obj_id ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
end :
2016-05-05 17:26:47 +00:00
le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( r - > id = = BTRFS_ROOT_FSTREE )
return r ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return NULL ;
}
2017-09-08 08:02:43 +00:00
void init_file_cache ( _In_ PFILE_OBJECT FileObject , _In_ CC_FILE_SIZES * ccfs ) {
2017-01-01 17:12:12 +00:00
TRACE ( " (%p, %p) \n " , FileObject , ccfs ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
CcInitializeCacheMap ( FileObject , ccfs , FALSE , cache_callbacks , FileObject ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( diskacc )
2017-09-08 08:02:43 +00:00
fCcSetAdditionalCacheAttributesEx ( FileObject , CC_ENABLE_DISK_IO_ACCOUNTING ) ;
2017-01-01 17:12:12 +00:00
CcSetReadAheadGranularity ( FileObject , READ_AHEAD_GRANULARITY ) ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS create_calc_threads ( _In_ PDEVICE_OBJECT DeviceObject ) {
2017-01-01 17:12:12 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
ULONG i ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Vcb - > calcthreads . num_threads = KeQueryActiveProcessorCount ( NULL ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Vcb - > calcthreads . threads = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( drv_calc_thread ) * Vcb - > calcthreads . num_threads , ALLOC_TAG ) ;
if ( ! Vcb - > calcthreads . threads ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InitializeListHead ( & Vcb - > calcthreads . job_list ) ;
ExInitializeResourceLite ( & Vcb - > calcthreads . lock ) ;
KeInitializeEvent ( & Vcb - > calcthreads . event , NotificationEvent , FALSE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( Vcb - > calcthreads . threads , sizeof ( drv_calc_thread ) * Vcb - > calcthreads . num_threads ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
for ( i = 0 ; i < Vcb - > calcthreads . num_threads ; i + + ) {
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Vcb - > calcthreads . threads [ i ] . DeviceObject = DeviceObject ;
KeInitializeEvent ( & Vcb - > calcthreads . threads [ i ] . finished , NotificationEvent , FALSE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = PsCreateSystemThread ( & Vcb - > calcthreads . threads [ i ] . handle , 0 , NULL , NULL , NULL , calc_thread , & Vcb - > calcthreads . threads [ i ] ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ULONG j ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ERR ( " PsCreateSystemThread returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
for ( j = 0 ; j < i ; j + + ) {
Vcb - > calcthreads . threads [ i ] . quit = TRUE ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
KeSetEvent ( & Vcb - > calcthreads . event , 0 , FALSE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static BOOL is_btrfs_volume ( _In_ PDEVICE_OBJECT DeviceObject ) {
NTSTATUS Status ;
MOUNTDEV_NAME mdn , * mdn2 ;
ULONG mdnsize ;
Status = dev_ioctl ( DeviceObject , IOCTL_MOUNTDEV_QUERY_DEVICE_NAME , NULL , 0 , & mdn , sizeof ( MOUNTDEV_NAME ) , TRUE , NULL ) ;
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_BUFFER_OVERFLOW ) {
ERR ( " IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x \n " , Status ) ;
return FALSE ;
}
mdnsize = ( ULONG ) offsetof ( MOUNTDEV_NAME , Name [ 0 ] ) + mdn . NameLength ;
mdn2 = ExAllocatePoolWithTag ( PagedPool , mdnsize , ALLOC_TAG ) ;
if ( ! mdn2 ) {
ERR ( " out of memory \n " ) ;
return FALSE ;
}
Status = dev_ioctl ( DeviceObject , IOCTL_MOUNTDEV_QUERY_DEVICE_NAME , NULL , 0 , mdn2 , mdnsize , TRUE , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x \n " , Status ) ;
ExFreePool ( mdn2 ) ;
return FALSE ;
}
if ( mdn2 - > NameLength > wcslen ( BTRFS_VOLUME_PREFIX ) * sizeof ( WCHAR ) & &
RtlCompareMemory ( mdn2 - > Name , BTRFS_VOLUME_PREFIX , wcslen ( BTRFS_VOLUME_PREFIX ) * sizeof ( WCHAR ) ) = = wcslen ( BTRFS_VOLUME_PREFIX ) * sizeof ( WCHAR ) ) {
ExFreePool ( mdn2 ) ;
return TRUE ;
}
ExFreePool ( mdn2 ) ;
return FALSE ;
}
static NTSTATUS get_device_pnp_name_guid ( _In_ PDEVICE_OBJECT DeviceObject , _Out_ PUNICODE_STRING pnp_name , _In_ const GUID * guid ) {
NTSTATUS Status ;
WCHAR * list = NULL , * s ;
Status = IoGetDeviceInterfaces ( ( PVOID ) guid , NULL , 0 , & list ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoGetDeviceInterfaces returned %08x \n " , Status ) ;
return Status ;
}
s = list ;
while ( s [ 0 ] ! = 0 ) {
PFILE_OBJECT FileObject ;
PDEVICE_OBJECT devobj ;
UNICODE_STRING name ;
name . Length = name . MaximumLength = ( USHORT ) wcslen ( s ) * sizeof ( WCHAR ) ;
name . Buffer = s ;
if ( NT_SUCCESS ( IoGetDeviceObjectPointer ( & name , FILE_READ_ATTRIBUTES , & FileObject , & devobj ) ) ) {
if ( DeviceObject = = devobj | | DeviceObject = = FileObject - > DeviceObject ) {
ObDereferenceObject ( FileObject ) ;
pnp_name - > Buffer = ExAllocatePoolWithTag ( PagedPool , name . Length , ALLOC_TAG ) ;
if ( ! pnp_name - > Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
RtlCopyMemory ( pnp_name - > Buffer , name . Buffer , name . Length ) ;
pnp_name - > Length = pnp_name - > MaximumLength = name . Length ;
Status = STATUS_SUCCESS ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
ObDereferenceObject ( FileObject ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
s = & s [ wcslen ( s ) + 1 ] ;
}
pnp_name - > Length = pnp_name - > MaximumLength = 0 ;
pnp_name - > Buffer = 0 ;
Status = STATUS_NOT_FOUND ;
end :
if ( list )
ExFreePool ( list ) ;
return Status ;
}
NTSTATUS get_device_pnp_name ( _In_ PDEVICE_OBJECT DeviceObject , _Out_ PUNICODE_STRING pnp_name , _Out_ const GUID * * guid ) {
NTSTATUS Status ;
Status = get_device_pnp_name_guid ( DeviceObject , pnp_name , & GUID_DEVINTERFACE_VOLUME ) ;
if ( NT_SUCCESS ( Status ) ) {
* guid = & GUID_DEVINTERFACE_VOLUME ;
return Status ;
}
Status = get_device_pnp_name_guid ( DeviceObject , pnp_name , & GUID_DEVINTERFACE_HIDDEN_VOLUME ) ;
if ( NT_SUCCESS ( Status ) ) {
* guid = & GUID_DEVINTERFACE_HIDDEN_VOLUME ;
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
Status = get_device_pnp_name_guid ( DeviceObject , pnp_name , & GUID_DEVINTERFACE_DISK ) ;
if ( NT_SUCCESS ( Status ) ) {
* guid = & GUID_DEVINTERFACE_DISK ;
return Status ;
}
return STATUS_NOT_FOUND ;
}
_Success_ ( return > = 0 )
static NTSTATUS check_mount_device ( _In_ PDEVICE_OBJECT DeviceObject , _Out_ BOOL * no_pnp ) {
NTSTATUS Status ;
ULONG to_read ;
superblock * sb ;
UINT32 crc32 ;
UNICODE_STRING pnp_name ;
const GUID * guid ;
to_read = DeviceObject - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , DeviceObject - > SectorSize ) ;
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
Status = sync_read_phys ( DeviceObject , superblock_addrs [ 0 ] , to_read , ( PUCHAR ) sb , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " sync_read_phys returned %08x \n " , Status ) ;
goto end ;
}
if ( sb - > magic ! = BTRFS_MAGIC ) {
Status = STATUS_SUCCESS ;
goto end ;
}
crc32 = ~ calc_crc32c ( 0xffffffff , ( UINT8 * ) & sb - > uuid , ( ULONG ) sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
if ( crc32 ! = * ( ( UINT32 * ) sb - > checksum ) ) {
WARN ( " crc32 was %08x, expected %08x \n " , crc32 , * ( ( UINT32 * ) sb - > checksum ) ) ;
Status = STATUS_SUCCESS ;
goto end ;
}
DeviceObject - > Flags & = ~ DO_VERIFY_VOLUME ;
pnp_name . Buffer = NULL ;
Status = get_device_pnp_name ( DeviceObject , & pnp_name , & guid ) ;
if ( ! NT_SUCCESS ( Status ) ) {
WARN ( " get_device_pnp_name returned %08x \n " , Status ) ;
pnp_name . Length = 0 ;
}
if ( pnp_name . Length = = 0 )
* no_pnp = TRUE ;
else {
* no_pnp = FALSE ;
volume_arrival ( drvobj , & pnp_name ) ;
}
if ( pnp_name . Buffer )
ExFreePool ( pnp_name . Buffer ) ;
Status = STATUS_SUCCESS ;
end :
ExFreePool ( sb ) ;
return Status ;
}
static BOOL still_has_superblock ( _In_ PDEVICE_OBJECT device ) {
NTSTATUS Status ;
ULONG to_read ;
superblock * sb ;
PDEVICE_OBJECT device2 ;
if ( ! device )
return FALSE ;
to_read = device - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , device - > SectorSize ) ;
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return FALSE ;
}
Status = sync_read_phys ( device , superblock_addrs [ 0 ] , to_read , ( PUCHAR ) sb , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " Failed to read superblock: %08x \n " , Status ) ;
ExFreePool ( sb ) ;
return FALSE ;
}
if ( sb - > magic ! = BTRFS_MAGIC ) {
TRACE ( " not a BTRFS volume \n " ) ;
ExFreePool ( sb ) ;
return FALSE ;
} else {
UINT32 crc32 = ~ calc_crc32c ( 0xffffffff , ( UINT8 * ) & sb - > uuid , ( ULONG ) sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
if ( crc32 ! = * ( ( UINT32 * ) sb - > checksum ) ) {
WARN ( " crc32 was %08x, expected %08x \n " , crc32 , * ( ( UINT32 * ) sb - > checksum ) ) ;
ExFreePool ( sb ) ;
return FALSE ;
}
}
device2 = device ;
do {
device2 - > Flags & = ~ DO_VERIFY_VOLUME ;
device2 = IoGetLowerDeviceObject ( device2 ) ;
} while ( device2 ) ;
ExFreePool ( sb ) ;
2016-07-27 19:24:26 +00:00
return TRUE ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS mount_vol ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2017-01-01 17:12:12 +00:00
PIO_STACK_LOCATION IrpSp ;
2016-03-23 20:35:05 +00:00
PDEVICE_OBJECT NewDeviceObject = NULL ;
2017-09-08 08:02:43 +00:00
PDEVICE_OBJECT DeviceToMount , readobj ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
device_extension * Vcb = NULL ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le , batchlist ;
2016-03-23 20:35:05 +00:00
KEY searchkey ;
traverse_ptr tp ;
2016-05-05 17:26:47 +00:00
fcb * root_fcb = NULL ;
2016-07-27 19:24:26 +00:00
ccb * root_ccb = NULL ;
2016-10-29 17:05:10 +00:00
BOOL init_lookaside = FALSE ;
2017-01-01 17:12:12 +00:00
device * dev ;
2017-09-08 08:02:43 +00:00
volume_device_extension * vde = NULL ;
pdo_device_extension * pdode = NULL ;
volume_child * vc ;
BOOL no_pnp = FALSE ;
UINT64 readobjsize ;
2017-01-01 17:12:12 +00:00
TRACE ( " (%p, %p) \n " , DeviceObject , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( DeviceObject ! = master_devobj ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_INVALID_DEVICE_REQUEST ;
goto exit ;
}
2017-01-01 17:12:12 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
DeviceToMount = IrpSp - > Parameters . MountVolume . DeviceObject ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
if ( ! is_btrfs_volume ( DeviceToMount ) ) {
Status = check_mount_device ( DeviceToMount , & no_pnp ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " check_mount_device returned %08x \n " , Status ) ;
if ( ! no_pnp ) {
Status = STATUS_UNRECOGNIZED_VOLUME ;
goto exit2 ;
}
} else {
PDEVICE_OBJECT pdo ;
pdo = DeviceToMount ;
while ( IoGetLowerDeviceObject ( pdo ) ) {
pdo = IoGetLowerDeviceObject ( pdo ) ;
}
ExAcquireResourceSharedLite ( & pdo_list_lock , TRUE ) ;
le = pdo_list . Flink ;
while ( le ! = & pdo_list ) {
pdo_device_extension * pdode = CONTAINING_RECORD ( le , pdo_device_extension , list_entry ) ;
if ( pdode - > pdo = = pdo ) {
vde = pdode - > vde ;
break ;
}
le = le - > Flink ;
}
ExReleaseResourceLite ( & pdo_list_lock ) ;
if ( ! vde | | vde - > type ! = VCB_TYPE_VOLUME ) {
vde = NULL ;
Status = STATUS_UNRECOGNIZED_VOLUME ;
goto exit2 ;
}
}
if ( vde ) {
pdode = vde - > pdode ;
ExAcquireResourceExclusiveLite ( & pdode - > child_lock , TRUE ) ;
le = pdode - > children . Flink ;
while ( le ! = & pdode - > children ) {
LIST_ENTRY * le2 = le - > Flink ;
vc = CONTAINING_RECORD ( pdode - > children . Flink , volume_child , list_entry ) ;
if ( ! still_has_superblock ( vc - > devobj ) ) {
remove_volume_child ( vde , vc , FALSE ) ;
if ( pdode - > num_children = = 0 ) {
ERR ( " error - number of devices is zero \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit2 ;
}
Status = STATUS_DEVICE_NOT_READY ;
goto exit2 ;
}
le = le2 ;
}
if ( pdode - > num_children = = 0 | | pdode - > children_loaded = = 0 ) {
ERR ( " error - number of devices is zero \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
ExConvertExclusiveToSharedLite ( & pdode - > child_lock ) ;
vc = CONTAINING_RECORD ( pdode - > children . Flink , volume_child , list_entry ) ;
readobj = vc - > devobj ;
readobjsize = vc - > size ;
vde - > device - > Characteristics & = ~ FILE_DEVICE_SECURE_OPEN ;
} else {
GET_LENGTH_INFORMATION gli ;
vc = NULL ;
readobj = DeviceToMount ;
Status = dev_ioctl ( readobj , IOCTL_DISK_GET_LENGTH_INFO , NULL , 0 ,
& gli , sizeof ( gli ) , TRUE , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error reading length information: %08x \n " , Status ) ;
goto exit ;
}
readobjsize = gli . Length . QuadPart ;
2016-03-23 20:35:05 +00:00
}
2017-01-01 17:12:12 +00:00
Status = IoCreateDevice ( drvobj , sizeof ( device_extension ) , NULL , FILE_DEVICE_DISK_FILE_SYSTEM , 0 , FALSE , & NewDeviceObject ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoCreateDevice returned %08x \n " , Status ) ;
Status = STATUS_UNRECOGNIZED_VOLUME ;
2016-03-23 20:35:05 +00:00
goto exit ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
NewDeviceObject - > Flags | = DO_DIRECT_IO ;
2017-09-08 08:02:43 +00:00
// Some programs seem to expect that the sector size will be 512, for
// FILE_NO_INTERMEDIATE_BUFFERING and the like.
NewDeviceObject - > SectorSize = min ( DeviceToMount - > SectorSize , 512 ) ;
2016-03-23 20:35:05 +00:00
Vcb = ( PVOID ) NewDeviceObject - > DeviceExtension ;
RtlZeroMemory ( Vcb , sizeof ( device_extension ) ) ;
2017-09-08 08:02:43 +00:00
Vcb - > type = VCB_TYPE_FS ;
Vcb - > vde = vde ;
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & Vcb - > tree_lock ) ;
2016-07-27 19:24:26 +00:00
Vcb - > need_write = FALSE ;
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & Vcb - > fcb_lock ) ;
2016-07-27 19:24:26 +00:00
ExInitializeResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
ExInitializeResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
ExInitializeResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
ExInitializeResourceLite ( & Vcb - > dirty_subvols_lock ) ;
ExInitializeResourceLite ( & Vcb - > scrub . stats_lock ) ;
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & Vcb - > load_lock ) ;
ExAcquireResourceExclusiveLite ( & Vcb - > load_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , TRUE ) ;
2016-03-23 20:35:05 +00:00
DeviceToMount - > Flags | = DO_DIRECT_IO ;
2017-09-08 08:02:43 +00:00
Status = read_superblock ( Vcb , readobj , readobjsize ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2017-09-08 08:02:43 +00:00
if ( ! IoIsErrorUserInduced ( Status ) )
Status = STATUS_UNRECOGNIZED_VOLUME ;
else if ( Irp - > Tail . Overlay . Thread )
IoSetHardErrorOrVerifyDevice ( Irp , readobj ) ;
goto exit ;
}
if ( ! vde & & Vcb - > superblock . num_devices > 1 ) {
ERR ( " cannot mount multi-device FS with non-PNP device \n " ) ;
2016-03-23 20:35:05 +00:00
Status = STATUS_UNRECOGNIZED_VOLUME ;
goto exit ;
}
2016-09-04 15:27:46 +00:00
Status = registry_load_volume_options ( Vcb ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " registry_load_volume_options returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
if ( pdode & & pdode - > children_loaded < pdode - > num_children & & ( ! Vcb - > options . allow_degraded | | ! finished_probing | | degraded_wait ) ) {
ERR ( " could not mount as %u device(s) missing \n " , pdode - > num_children - pdode - > children_loaded ) ;
Status = STATUS_DEVICE_NOT_READY ;
goto exit ;
}
2016-07-27 19:24:26 +00:00
if ( Vcb - > options . ignore ) {
TRACE ( " ignoring volume \n " ) ;
Status = STATUS_UNRECOGNIZED_VOLUME ;
goto exit ;
}
2016-03-23 20:35:05 +00:00
if ( Vcb - > superblock . incompat_flags & ~ INCOMPAT_SUPPORTED ) {
WARN ( " cannot mount because of unsupported incompat flags (%llx) \n " , Vcb - > superblock . incompat_flags & ~ INCOMPAT_SUPPORTED ) ;
Status = STATUS_UNRECOGNIZED_VOLUME ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Vcb - > readonly = FALSE ;
if ( Vcb - > superblock . compat_ro_flags & ~ COMPAT_RO_SUPPORTED ) {
WARN ( " mounting read-only because of unsupported flags (%llx) \n " , Vcb - > superblock . compat_ro_flags & ~ COMPAT_RO_SUPPORTED ) ;
Vcb - > readonly = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > options . readonly )
Vcb - > readonly = TRUE ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Vcb - > superblock . generation + + ;
Vcb - > superblock . incompat_flags | = BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InitializeListHead ( & Vcb - > devices ) ;
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
2016-03-23 20:35:05 +00:00
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
dev - > devobj = readobj ;
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( & dev - > devitem , & Vcb - > superblock . dev_item , sizeof ( DEV_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
if ( dev - > devitem . num_bytes > readobjsize ) {
WARN ( " device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx \n " , dev - > devitem . dev_id ,
dev - > devitem . num_bytes , readobjsize ) ;
dev - > devitem . num_bytes = readobjsize ;
}
2017-01-01 17:12:12 +00:00
dev - > seeding = Vcb - > superblock . flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE ;
2017-09-08 08:02:43 +00:00
init_device ( Vcb , dev , TRUE ) ;
2017-01-01 17:12:12 +00:00
InsertTailList ( & Vcb - > devices , & dev - > list_entry ) ;
2016-07-27 19:24:26 +00:00
Vcb - > devices_loaded = 1 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( DeviceToMount - > Flags & DO_SYSTEM_BOOT_PARTITION )
Vcb - > disallow_dismount = TRUE ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " DeviceToMount = %p \n " , DeviceToMount ) ;
2017-01-01 17:12:12 +00:00
TRACE ( " IrpSp->Parameters.MountVolume.Vpb = %p \n " , IrpSp - > Parameters . MountVolume . Vpb ) ;
2016-03-23 20:35:05 +00:00
NewDeviceObject - > StackSize = DeviceToMount - > StackSize + 1 ;
NewDeviceObject - > Flags & = ~ DO_DEVICE_INITIALIZING ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InitializeListHead ( & Vcb - > roots ) ;
InitializeListHead ( & Vcb - > drop_roots ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Vcb - > log_to_phys_loaded = FALSE ;
2017-09-08 08:02:43 +00:00
add_root ( Vcb , BTRFS_ROOT_CHUNK , Vcb - > superblock . chunk_tree_addr , Vcb - > superblock . chunk_root_generation , NULL ) ;
2016-03-23 20:35:05 +00:00
if ( ! Vcb - > chunk_root ) {
ERR ( " Could not load chunk root. \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeListHead ( & Vcb - > sys_chunks ) ;
Status = load_sys_chunks ( Vcb ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " load_sys_chunks returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeListHead ( & Vcb - > chunks ) ;
InitializeListHead ( & Vcb - > trees ) ;
2017-01-01 17:12:12 +00:00
InitializeListHead ( & Vcb - > trees_hash ) ;
2016-07-27 19:24:26 +00:00
InitializeListHead ( & Vcb - > all_fcbs ) ;
InitializeListHead ( & Vcb - > dirty_fcbs ) ;
InitializeListHead ( & Vcb - > dirty_filerefs ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & Vcb - > dirty_subvols ) ;
InitializeListHead ( & Vcb - > send_ops ) ;
2016-03-23 20:35:05 +00:00
InitializeListHead ( & Vcb - > DirNotifyList ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & Vcb - > scrub . errors ) ;
2016-03-23 20:35:05 +00:00
FsRtlNotifyInitializeSync ( & Vcb - > NotifySync ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExInitializePagedLookasideList ( & Vcb - > tree_data_lookaside , NULL , NULL , 0 , sizeof ( tree_data ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > traverse_ptr_lookaside , NULL , NULL , 0 , sizeof ( traverse_ptr ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > batch_item_lookaside , NULL , NULL , 0 , sizeof ( batch_item ) , ALLOC_TAG , 0 ) ;
2017-09-08 08:02:43 +00:00
ExInitializePagedLookasideList ( & Vcb - > fileref_lookaside , NULL , NULL , 0 , sizeof ( file_ref ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > fcb_lookaside , NULL , NULL , 0 , sizeof ( fcb ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > name_bit_lookaside , NULL , NULL , 0 , sizeof ( name_bit ) , ALLOC_TAG , 0 ) ;
2016-10-29 17:05:10 +00:00
ExInitializeNPagedLookasideList ( & Vcb - > range_lock_lookaside , NULL , NULL , 0 , sizeof ( range_lock ) , ALLOC_TAG , 0 ) ;
2017-09-08 08:02:43 +00:00
ExInitializeNPagedLookasideList ( & Vcb - > fileref_np_lookaside , NULL , NULL , 0 , sizeof ( file_ref_nonpaged ) , ALLOC_TAG , 0 ) ;
ExInitializeNPagedLookasideList ( & Vcb - > fcb_np_lookaside , NULL , NULL , 0 , sizeof ( fcb_nonpaged ) , ALLOC_TAG , 0 ) ;
2016-10-29 17:05:10 +00:00
init_lookaside = TRUE ;
2017-09-08 08:02:43 +00:00
Vcb - > Vpb = IrpSp - > Parameters . MountVolume . Vpb ;
2016-09-04 15:27:46 +00:00
Status = load_chunk_root ( Vcb , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " load_chunk_root returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > superblock . num_devices > 1 ) {
2017-09-08 08:02:43 +00:00
if ( Vcb - > devices_loaded < Vcb - > superblock . num_devices & & ( ! Vcb - > options . allow_degraded | | ! finished_probing ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " could not mount as %u device(s) missing \n " , Vcb - > superblock . num_devices - Vcb - > devices_loaded ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
IoRaiseInformationalHardError ( IO_ERR_INTERNAL_ERROR , NULL , NULL ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev - > readonly & & ! Vcb - > readonly ) {
2016-10-29 17:05:10 +00:00
Vcb - > readonly = TRUE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev2 = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev2 - > readonly & & ! dev2 - > seeding )
2016-10-29 17:05:10 +00:00
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! dev2 - > readonly ) {
2016-10-29 17:05:10 +00:00
Vcb - > readonly = FALSE ;
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > readonly )
WARN ( " setting volume to readonly \n " ) ;
}
} else {
2017-01-01 17:12:12 +00:00
if ( dev - > readonly ) {
2016-10-29 17:05:10 +00:00
WARN ( " setting volume to readonly as device is readonly \n " ) ;
Vcb - > readonly = TRUE ;
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
add_root ( Vcb , BTRFS_ROOT_ROOT , Vcb - > superblock . root_tree_addr , Vcb - > superblock . generation - 1 , NULL ) ;
2016-03-23 20:35:05 +00:00
if ( ! Vcb - > root_root ) {
ERR ( " Could not load root of roots. \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = look_for_roots ( Vcb , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " look_for_roots returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > readonly ) {
Status = find_chunk_usage ( Vcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " find_chunk_usage returned %08x \n " , Status ) ;
goto exit ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & batchlist ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// We've already increased the generation by one
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > readonly & & (
Vcb - > options . clear_cache | |
( ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE ) & & Vcb - > superblock . generation - 1 ! = Vcb - > superblock . cache_generation ) | |
( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE & & ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID ) ) ) ) {
if ( Vcb - > options . clear_cache )
WARN ( " ClearCache option was set, clearing cache... \n " ) ;
else if ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE & & ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID ) )
WARN ( " clearing free-space tree created by buggy Linux driver \n " ) ;
else
WARN ( " generation was %llx, free-space cache generation was %llx; clearing cache... \n " , Vcb - > superblock . generation - 1 , Vcb - > superblock . cache_generation ) ;
2016-10-29 17:05:10 +00:00
Status = clear_free_space_cache ( Vcb , & batchlist , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " clear_free_space_cache returned %08x \n " , Status ) ;
2016-10-29 17:05:10 +00:00
clear_batch_list ( Vcb , & batchlist ) ;
2016-05-05 17:26:47 +00:00
goto exit ;
}
}
2017-09-08 08:02:43 +00:00
Status = commit_batch_list ( Vcb , & batchlist , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " commit_batch_list returned %08x \n " , Status ) ;
goto exit ;
}
Vcb - > volume_fcb = create_fcb ( Vcb , NonPagedPool ) ;
2016-03-23 20:35:05 +00:00
if ( ! Vcb - > volume_fcb ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Vcb - > volume_fcb - > Vcb = Vcb ;
Vcb - > volume_fcb - > sd = NULL ;
2017-09-08 08:02:43 +00:00
Vcb - > dummy_fcb = create_fcb ( Vcb , NonPagedPool ) ;
if ( ! Vcb - > dummy_fcb ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
Vcb - > dummy_fcb - > Vcb = Vcb ;
Vcb - > dummy_fcb - > type = BTRFS_TYPE_DIRECTORY ;
Vcb - > dummy_fcb - > inode = 2 ;
Vcb - > dummy_fcb - > subvol = Vcb - > root_root ;
Vcb - > dummy_fcb - > atts = FILE_ATTRIBUTE_DIRECTORY ;
Vcb - > dummy_fcb - > inode_item . st_nlink = 1 ;
Vcb - > dummy_fcb - > inode_item . st_mode = __S_IFDIR ;
Vcb - > dummy_fcb - > hash_ptrs = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! Vcb - > dummy_fcb - > hash_ptrs ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
RtlZeroMemory ( Vcb - > dummy_fcb - > hash_ptrs , sizeof ( LIST_ENTRY * ) * 256 ) ;
Vcb - > dummy_fcb - > hash_ptrs_uc = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! Vcb - > dummy_fcb - > hash_ptrs_uc ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
RtlZeroMemory ( Vcb - > dummy_fcb - > hash_ptrs_uc , sizeof ( LIST_ENTRY * ) * 256 ) ;
root_fcb = create_fcb ( Vcb , NonPagedPool ) ;
2016-05-05 17:26:47 +00:00
if ( ! root_fcb ) {
2016-03-23 20:35:05 +00:00
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
root_fcb - > Vcb = Vcb ;
root_fcb - > inode = SUBVOL_ROOT_INODE ;
root_fcb - > type = BTRFS_TYPE_DIRECTORY ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
WARN ( " volume FCB = %p \n " , Vcb - > volume_fcb ) ;
2016-05-05 17:26:47 +00:00
WARN ( " root FCB = %p \n " , root_fcb ) ;
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
root_fcb - > subvol = find_default_subvol ( Vcb , Irp ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
if ( ! root_fcb - > subvol ) {
2016-03-23 20:35:05 +00:00
ERR ( " could not find top subvol \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
Status = load_dir_children ( Vcb , root_fcb , TRUE , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " load_dir_children returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
searchkey . obj_id = root_fcb - > inode ;
2016-03-23 20:35:05 +00:00
searchkey . obj_type = TYPE_INODE_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = find_item ( Vcb , root_fcb - > subvol , & tp , & searchkey , FALSE , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
ERR ( " couldn't find INODE_ITEM for root directory \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > size > 0 )
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( & root_fcb - > inode_item , tp . item - > data , min ( sizeof ( INODE_ITEM ) , tp . item - > size ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fcb_get_sd ( root_fcb , NULL , TRUE , Irp ) ;
2017-09-08 08:02:43 +00:00
root_fcb - > atts = get_file_attributes ( Vcb , root_fcb - > subvol , root_fcb - > inode , root_fcb - > type , FALSE , FALSE , Irp ) ;
Vcb - > root_fileref = create_fileref ( Vcb ) ;
2016-05-05 17:26:47 +00:00
if ( ! Vcb - > root_fileref ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Vcb - > root_fileref - > fcb = root_fcb ;
InsertTailList ( & root_fcb - > subvol - > fcbs , & root_fcb - > list_entry ) ;
2016-07-27 19:24:26 +00:00
InsertTailList ( & Vcb - > all_fcbs , & root_fcb - > list_entry_all ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
root_fcb - > fileref = Vcb - > root_fileref ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
root_ccb = ExAllocatePoolWithTag ( PagedPool , sizeof ( ccb ) , ALLOC_TAG ) ;
if ( ! root_ccb ) {
2016-05-05 17:26:47 +00:00
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Vcb - > root_file = IoCreateStreamFileObject ( NULL , DeviceToMount ) ;
Vcb - > root_file - > FsContext = root_fcb ;
2016-07-27 19:32:05 +00:00
Vcb - > root_file - > SectionObjectPointer = & root_fcb - > nonpaged - > segment_object ;
Vcb - > root_file - > Vpb = DeviceObject - > Vpb ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlZeroMemory ( root_ccb , sizeof ( ccb ) ) ;
root_ccb - > NodeType = BTRFS_NODE_TYPE_CCB ;
root_ccb - > NodeSize = sizeof ( ccb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:32:05 +00:00
Vcb - > root_file - > FsContext2 = root_ccb ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:32:05 +00:00
_SEH2_TRY {
CcInitializeCacheMap ( Vcb - > root_file , ( PCC_FILE_SIZES ) ( & root_fcb - > Header . AllocationSize ) , FALSE , cache_callbacks , Vcb - > root_file ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
goto exit ;
} _SEH2_END ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev2 = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = find_disk_holes ( Vcb , dev2 , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " find_disk_holes returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
NewDeviceObject - > Vpb = IrpSp - > Parameters . MountVolume . Vpb ;
IrpSp - > Parameters . MountVolume . Vpb - > DeviceObject = NewDeviceObject ;
IrpSp - > Parameters . MountVolume . Vpb - > Flags | = VPB_MOUNTED ;
2016-03-23 20:35:05 +00:00
NewDeviceObject - > Vpb - > VolumeLabelLength = 4 ; // FIXME
NewDeviceObject - > Vpb - > VolumeLabel [ 0 ] = ' ? ' ;
NewDeviceObject - > Vpb - > VolumeLabel [ 1 ] = 0 ;
NewDeviceObject - > Vpb - > ReferenceCount + + ; // FIXME - should we deref this at any point?
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
KeInitializeEvent ( & Vcb - > flush_thread_finished , NotificationEvent , FALSE ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = PsCreateSystemThread ( & Vcb - > flush_thread_handle , 0 , NULL , NULL , NULL , flush_thread , NewDeviceObject ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " PsCreateSystemThread returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = create_calc_threads ( NewDeviceObject ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " create_calc_threads returned %08x \n " , Status ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = registry_mark_volume_mounted ( & Vcb - > superblock . uuid ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " registry_mark_volume_mounted returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = look_for_balance_item ( Vcb ) ;
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_NOT_FOUND )
WARN ( " look_for_balance_item returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
if ( vde )
vde - > mounted_device = NewDeviceObject ;
ExInitializeResourceLite ( & Vcb - > send_load_lock ) ;
2016-03-23 20:35:05 +00:00
exit :
2017-09-08 08:02:43 +00:00
if ( pdode )
ExReleaseResourceLite ( & pdode - > child_lock ) ;
exit2 :
2016-03-23 20:35:05 +00:00
if ( Vcb ) {
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
ExReleaseResourceLite ( & Vcb - > load_lock ) ;
}
if ( ! NT_SUCCESS ( Status ) ) {
if ( Vcb ) {
2016-10-29 17:05:10 +00:00
if ( init_lookaside ) {
ExDeletePagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > traverse_ptr_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > batch_item_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeletePagedLookasideList ( & Vcb - > fileref_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > fcb_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > name_bit_lookaside ) ;
2016-10-29 17:05:10 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > range_lock_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > fileref_np_lookaside ) ;
ExDeleteNPagedLookasideList ( & Vcb - > fcb_np_lookaside ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > root_file )
ObDereferenceObject ( Vcb - > root_file ) ;
2017-09-08 08:02:43 +00:00
else if ( Vcb - > root_fileref ) {
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
free_fileref ( Vcb , Vcb - > root_fileref ) ;
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
} else if ( root_fcb ) {
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
free_fcb ( Vcb , root_fcb ) ;
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
}
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
if ( Vcb - > volume_fcb ) {
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
free_fcb ( Vcb , Vcb - > volume_fcb ) ;
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
}
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & Vcb - > tree_lock ) ;
ExDeleteResourceLite ( & Vcb - > load_lock ) ;
ExDeleteResourceLite ( & Vcb - > fcb_lock ) ;
2016-07-27 19:24:26 +00:00
ExDeleteResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_subvols_lock ) ;
ExDeleteResourceLite ( & Vcb - > scrub . stats_lock ) ;
2016-03-23 20:35:05 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > devices . Flink ) {
while ( ! IsListEmpty ( & Vcb - > devices ) ) {
2017-09-08 08:02:43 +00:00
device * dev2 = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > devices ) , device , list_entry ) ;
ExFreePool ( dev2 ) ;
2017-01-01 17:12:12 +00:00
}
}
2016-03-23 20:35:05 +00:00
}
if ( NewDeviceObject )
IoDeleteDevice ( NewDeviceObject ) ;
2017-01-01 17:12:12 +00:00
} else {
ExAcquireResourceExclusiveLite ( & global_loading_lock , TRUE ) ;
InsertTailList ( & VcbList , & Vcb - > list_entry ) ;
ExReleaseResourceLite ( & global_loading_lock ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
FsRtlNotifyVolumeEvent ( Vcb - > root_file , FSRTL_VOLUME_MOUNT ) ;
2017-01-01 17:12:12 +00:00
}
2016-03-23 20:35:05 +00:00
TRACE ( " mount_vol done (status: %lx) \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS verify_device ( _In_ device_extension * Vcb , _Inout_ device * dev ) {
2016-09-04 15:27:46 +00:00
NTSTATUS Status ;
superblock * sb ;
UINT32 crc32 ;
2017-09-08 08:02:43 +00:00
ULONG to_read , cc ;
if ( ! dev - > devobj )
2016-09-04 15:27:46 +00:00
return STATUS_WRONG_VOLUME ;
2017-09-08 08:02:43 +00:00
if ( dev - > removable ) {
IO_STATUS_BLOCK iosb ;
Status = dev_ioctl ( dev - > devobj , IOCTL_STORAGE_CHECK_VERIFY , NULL , 0 , & cc , sizeof ( ULONG ) , TRUE , & iosb ) ;
if ( IoIsErrorUserInduced ( Status ) ) {
ERR ( " IOCTL_STORAGE_CHECK_VERIFY returned %08x (user-induced) \n " , Status ) ;
if ( Vcb - > vde ) {
pdo_device_extension * pdode = Vcb - > vde - > pdode ;
LIST_ENTRY * le2 ;
BOOL changed = FALSE ;
ExAcquireResourceExclusiveLite ( & pdode - > child_lock , TRUE ) ;
le2 = pdode - > children . Flink ;
while ( le2 ! = & pdode - > children ) {
volume_child * vc = CONTAINING_RECORD ( le2 , volume_child , list_entry ) ;
if ( vc - > devobj = = dev - > devobj ) {
TRACE ( " removing device \n " ) ;
remove_volume_child ( Vcb - > vde , vc , TRUE ) ;
changed = TRUE ;
break ;
}
le2 = le2 - > Flink ;
}
if ( ! changed )
ExReleaseResourceLite ( & pdode - > child_lock ) ;
}
} else if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IOCTL_STORAGE_CHECK_VERIFY returned %08x \n " , Status ) ;
return Status ;
} else if ( iosb . Information < sizeof ( ULONG ) ) {
ERR ( " iosb.Information was too short \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
dev - > change_count = cc ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
to_read = dev - > devobj - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , dev - > devobj - > SectorSize ) ;
2016-09-04 15:27:46 +00:00
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
Status = sync_read_phys ( dev - > devobj , superblock_addrs [ 0 ] , to_read , ( PUCHAR ) sb , TRUE ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " Failed to read superblock: %08x \n " , Status ) ;
ExFreePool ( sb ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( sb - > magic ! = BTRFS_MAGIC ) {
ERR ( " not a BTRFS volume \n " ) ;
ExFreePool ( sb ) ;
return STATUS_WRONG_VOLUME ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
crc32 = ~ calc_crc32c ( 0xffffffff , ( UINT8 * ) & sb - > uuid , ( ULONG ) sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
TRACE ( " crc32 was %08x, expected %08x \n " , crc32 , * ( ( UINT32 * ) sb - > checksum ) ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( crc32 ! = * ( ( UINT32 * ) sb - > checksum ) ) {
2017-09-08 08:02:43 +00:00
ERR ( " checksum error \n " ) ;
ExFreePool ( sb ) ;
return STATUS_WRONG_VOLUME ;
}
if ( RtlCompareMemory ( & sb - > uuid , & Vcb - > superblock . uuid , sizeof ( BTRFS_UUID ) ) ! = sizeof ( BTRFS_UUID ) ) {
2016-09-04 15:27:46 +00:00
ERR ( " different UUIDs \n " ) ;
ExFreePool ( sb ) ;
return STATUS_WRONG_VOLUME ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
ExFreePool ( sb ) ;
2017-09-08 08:02:43 +00:00
dev - > devobj - > Flags & = ~ DO_VERIFY_VOLUME ;
return STATUS_SUCCESS ;
}
static NTSTATUS verify_volume ( _In_ PDEVICE_OBJECT devobj ) {
device_extension * Vcb = devobj - > DeviceExtension ;
NTSTATUS Status ;
LIST_ENTRY * le ;
UINT64 failed_devices = 0 ;
BOOL locked = FALSE , remove = FALSE ;
if ( ! ( Vcb - > Vpb - > Flags & VPB_MOUNTED ) )
return STATUS_WRONG_VOLUME ;
if ( ! ExIsResourceAcquiredExclusive ( & Vcb - > tree_lock ) ) {
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , TRUE ) ;
locked = TRUE ;
}
if ( Vcb - > removing ) {
if ( locked ) ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
return STATUS_WRONG_VOLUME ;
}
InterlockedIncrement ( & Vcb - > open_files ) ; // so pnp_surprise_removal doesn't uninit the device while we're still using it
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
Status = verify_device ( Vcb , dev ) ;
if ( ! NT_SUCCESS ( Status ) ) {
failed_devices + + ;
if ( dev - > devobj & & Vcb - > options . allow_degraded )
dev - > devobj = NULL ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
InterlockedDecrement ( & Vcb - > open_files ) ;
if ( Vcb - > removing & & Vcb - > open_files = = 0 )
remove = TRUE ;
if ( locked )
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
if ( remove ) {
uninit ( Vcb , FALSE ) ;
return Status ;
}
if ( failed_devices = = 0 | | ( Vcb - > options . allow_degraded & & failed_devices < Vcb - > superblock . num_devices ) ) {
Vcb - > Vpb - > RealDevice - > Flags & = ~ DO_VERIFY_VOLUME ;
return STATUS_SUCCESS ;
}
return Status ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_FILE_SYSTEM_CONTROL )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_file_system_control ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp ;
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2016-03-23 20:35:05 +00:00
BOOL top_level ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " file system control \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_file_system_control ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | ( Vcb - > type ! = VCB_TYPE_FS & & Vcb - > type ! = VCB_TYPE_CONTROL ) ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = STATUS_NOT_IMPLEMENTED ;
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( IrpSp - > MinorFunction ) {
case IRP_MN_MOUNT_VOLUME :
TRACE ( " IRP_MN_MOUNT_VOLUME \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = mount_vol ( DeviceObject , Irp ) ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case IRP_MN_KERNEL_CALL :
TRACE ( " IRP_MN_KERNEL_CALL \n " ) ;
2017-09-08 08:02:43 +00:00
Status = fsctl_request ( DeviceObject , & Irp , IrpSp - > Parameters . FileSystemControl . FsControlCode ) ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case IRP_MN_USER_FS_REQUEST :
TRACE ( " IRP_MN_USER_FS_REQUEST \n " ) ;
2017-09-08 08:02:43 +00:00
Status = fsctl_request ( DeviceObject , & Irp , IrpSp - > Parameters . FileSystemControl . FsControlCode ) ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case IRP_MN_VERIFY_VOLUME :
2016-09-04 15:27:46 +00:00
TRACE ( " IRP_MN_VERIFY_VOLUME \n " ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = verify_volume ( DeviceObject ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) & & Vcb - > Vpb - > Flags & VPB_MOUNTED ) {
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , TRUE ) ;
Vcb - > removing = TRUE ;
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
default :
break ;
}
2017-09-08 08:02:43 +00:00
end :
TRACE ( " returning %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
if ( Irp ) {
Irp - > IoStatus . Status = Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
}
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
2016-07-27 19:24:26 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_LOCK_CONTROL )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_lock_control ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
fcb * fcb = IrpSp - > FileObject - > FsContext ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2016-03-23 20:35:05 +00:00
BOOL top_level ;
FsRtlEnterFileSystem ( ) ;
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_lock_control ( DeviceObject , Irp ) ;
Irp - > IoStatus . Status = Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2016-07-27 19:24:26 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " lock control \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = FsRtlProcessFileLock ( & fcb - > lock , Irp , NULL ) ;
2016-05-05 17:26:47 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
exit :
2017-09-08 08:02:43 +00:00
TRACE ( " returning %08x \n " , Status ) ;
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_SHUTDOWN )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_shutdown ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
BOOL top_level ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
FsRtlEnterFileSystem ( ) ;
TRACE ( " shutdown \n " ) ;
top_level = is_top_level ( Irp ) ;
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_shutdown ( DeviceObject , Irp ) ;
goto end ;
}
Status = STATUS_SUCCESS ;
shutting_down = TRUE ;
KeSetEvent ( & mountmgr_thread_event , 0 , FALSE ) ;
while ( ! IsListEmpty ( & VcbList ) ) {
Vcb = CONTAINING_RECORD ( VcbList . Flink , device_extension , list_entry ) ;
TRACE ( " shutting down Vcb %p \n " , Vcb ) ;
uninit ( Vcb , TRUE ) ;
}
# ifdef _DEBUG
if ( comfo ) {
ObDereferenceObject ( comfo ) ;
comdo = NULL ;
comfo = NULL ;
}
# endif
end :
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
if ( top_level )
IoSetTopLevelIrp ( NULL ) ;
FsRtlExitFileSystem ( ) ;
2016-07-27 19:24:26 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_POWER )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_power ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2016-03-23 20:35:05 +00:00
BOOL top_level ;
2017-09-08 08:02:43 +00:00
FsRtlEnterFileSystem ( ) ;
top_level = is_top_level ( Irp ) ;
Irp - > IoStatus . Information = 0 ;
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_power ( DeviceObject , Irp ) ;
Irp - > IoStatus . Status = Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
goto exit ;
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_FS ) {
IoSkipCurrentIrpStackLocation ( Irp ) ;
Status = IoCallDriver ( Vcb - > Vpb - > RealDevice , Irp ) ;
goto exit ;
}
Status = STATUS_INVALID_DEVICE_REQUEST ;
Irp - > IoStatus . Status = Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
exit :
if ( top_level )
IoSetTopLevelIrp ( NULL ) ;
FsRtlExitFileSystem ( ) ;
return Status ;
}
_Dispatch_type_ ( IRP_MJ_SYSTEM_CONTROL )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS drv_system_control ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
NTSTATUS Status ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2017-09-08 08:02:43 +00:00
BOOL top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
Irp - > IoStatus . Information = 0 ;
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
volume_device_extension * vde = DeviceObject - > DeviceExtension ;
IoSkipCurrentIrpStackLocation ( Irp ) ;
Status = IoCallDriver ( vde - > pdo , Irp ) ;
2016-07-27 19:24:26 +00:00
goto exit ;
2017-09-08 08:02:43 +00:00
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_FS ) {
IoSkipCurrentIrpStackLocation ( Irp ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
Status = IoCallDriver ( Vcb - > Vpb - > RealDevice , Irp ) ;
goto exit ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
Status = Irp - > IoStatus . Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2016-07-27 19:24:26 +00:00
exit :
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
BOOL is_file_name_valid ( _In_ PUNICODE_STRING us , _In_ BOOL posix ) {
2016-05-05 17:26:47 +00:00
ULONG i ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( us - > Length < sizeof ( WCHAR ) )
return FALSE ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( us - > Length > 255 * sizeof ( WCHAR ) )
return FALSE ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
for ( i = 0 ; i < us - > Length / sizeof ( WCHAR ) ; i + + ) {
2017-09-08 08:02:43 +00:00
if ( us - > Buffer [ i ] = = ' / ' | | us - > Buffer [ i ] = = 0 | |
( ! posix & & ( us - > Buffer [ i ] = = ' < ' | | us - > Buffer [ i ] = = ' > ' | | us - > Buffer [ i ] = = ' : ' | | us - > Buffer [ i ] = = ' " ' | |
us - > Buffer [ i ] = = ' | ' | | us - > Buffer [ i ] = = ' ? ' | | us - > Buffer [ i ] = = ' * ' | | ( us - > Buffer [ i ] > = 1 & & us - > Buffer [ i ] < = 31 ) ) ) )
2016-05-05 17:26:47 +00:00
return FALSE ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( us - > Buffer [ 0 ] = = ' . ' & & ( us - > Length = = sizeof ( WCHAR ) | | ( us - > Length = = 2 * sizeof ( WCHAR ) & & us - > Buffer [ 1 ] = = ' . ' ) ) )
return FALSE ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return TRUE ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
void chunk_lock_range ( _In_ device_extension * Vcb , _In_ chunk * c , _In_ UINT64 start , _In_ UINT64 length ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
BOOL locked ;
range_lock * rl ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rl = ExAllocateFromNPagedLookasideList ( & Vcb - > range_lock_lookaside ) ;
if ( ! rl ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rl - > start = start ;
rl - > length = length ;
rl - > thread = PsGetCurrentThread ( ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( TRUE ) {
locked = FALSE ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & c - > range_locks_lock , TRUE ) ;
2016-10-29 17:05:10 +00:00
le = c - > range_locks . Flink ;
while ( le ! = & c - > range_locks ) {
range_lock * rl2 = CONTAINING_RECORD ( le , range_lock , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rl2 - > start < start + length & & rl2 - > start + rl2 - > length > start & & rl2 - > thread ! = PsGetCurrentThread ( ) ) {
locked = TRUE ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! locked ) {
InsertTailList ( & c - > range_locks , & rl - > list_entry ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > range_locks_lock ) ;
2016-10-29 17:05:10 +00:00
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
KeClearEvent ( & c - > range_locks_event ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > range_locks_lock ) ;
2016-10-29 17:05:10 +00:00
KeWaitForSingleObject ( & c - > range_locks_event , UserRequest , KernelMode , FALSE , NULL ) ;
}
}
2017-09-08 08:02:43 +00:00
void chunk_unlock_range ( _In_ device_extension * Vcb , _In_ chunk * c , _In_ UINT64 start , _In_ UINT64 length ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & c - > range_locks_lock , TRUE ) ;
2016-10-29 17:05:10 +00:00
le = c - > range_locks . Flink ;
while ( le ! = & c - > range_locks ) {
range_lock * rl = CONTAINING_RECORD ( le , range_lock , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rl - > start = = start & & rl - > length = = length ) {
RemoveEntryList ( & rl - > list_entry ) ;
ExFreeToNPagedLookasideList ( & Vcb - > range_lock_lookaside , rl ) ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
KeSetEvent ( & c - > range_locks_event , 0 , FALSE ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > range_locks_lock ) ;
}
void log_device_error ( _In_ device_extension * Vcb , _Inout_ device * dev , _In_ int error ) {
dev - > stats [ error ] + + ;
dev - > stats_changed = TRUE ;
Vcb - > stats_changed = TRUE ;
2016-10-29 17:05:10 +00:00
}
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
2017-09-08 08:02:43 +00:00
_Function_class_ ( KSTART_ROUTINE )
static void serial_thread ( void * context ) {
LARGE_INTEGER due_time ;
KTIMER timer ;
UNUSED ( context ) ;
KeInitializeTimer ( & timer ) ;
due_time . QuadPart = ( UINT64 ) - 10000000 ;
KeSetTimer ( & timer , due_time , NULL ) ;
while ( TRUE ) {
KeWaitForSingleObject ( & timer , Executive , KernelMode , FALSE , NULL ) ;
init_serial ( FALSE ) ;
if ( comdo )
break ;
KeSetTimer ( & timer , due_time , NULL ) ;
}
KeCancelTimer ( & timer ) ;
PsTerminateSystemThread ( STATUS_SUCCESS ) ;
serial_thread_handle = NULL ;
}
static void init_serial ( BOOL first_time ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = IoGetDeviceObjectPointer ( & log_device , FILE_WRITE_DATA , & comfo , & comdo ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoGetDeviceObjectPointer returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( first_time ) {
NTSTATUS Status ;
Status = PsCreateSystemThread ( & serial_thread_handle , 0 , NULL , NULL , NULL , serial_thread , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " PsCreateSystemThread returned %08x \n " , Status ) ;
return ;
}
}
2016-03-23 20:35:05 +00:00
}
}
# endif
# ifndef __REACTOS__
2017-09-08 08:02:43 +00:00
static void check_cpu ( ) {
2016-03-23 20:35:05 +00:00
unsigned int cpuInfo [ 4 ] ;
# ifndef _MSC_VER
__get_cpuid ( 1 , & cpuInfo [ 0 ] , & cpuInfo [ 1 ] , & cpuInfo [ 2 ] , & cpuInfo [ 3 ] ) ;
have_sse42 = cpuInfo [ 2 ] & bit_SSE4_2 ;
2016-10-29 17:05:10 +00:00
have_sse2 = cpuInfo [ 3 ] & bit_SSE2 ;
2016-03-23 20:35:05 +00:00
# else
__cpuid ( cpuInfo , 1 ) ;
have_sse42 = cpuInfo [ 2 ] & ( 1 < < 20 ) ;
2016-10-29 17:05:10 +00:00
have_sse2 = cpuInfo [ 3 ] & ( 1 < < 26 ) ;
2016-03-23 20:35:05 +00:00
# endif
if ( have_sse42 )
TRACE ( " SSE4.2 is supported \n " ) ;
else
TRACE ( " SSE4.2 not supported \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( have_sse2 )
TRACE ( " SSE2 is supported \n " ) ;
else
TRACE ( " SSE2 is not supported \n " ) ;
2016-03-23 20:35:05 +00:00
}
# endif
# ifdef _DEBUG
static void init_logging ( ) {
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & log_lock , TRUE ) ;
2016-03-23 20:35:05 +00:00
if ( log_device . Length > 0 )
2017-09-08 08:02:43 +00:00
init_serial ( TRUE ) ;
2016-03-23 20:35:05 +00:00
else if ( log_file . Length > 0 ) {
NTSTATUS Status ;
OBJECT_ATTRIBUTES oa ;
IO_STATUS_BLOCK iosb ;
char * dateline ;
LARGE_INTEGER time ;
TIME_FIELDS tf ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeObjectAttributes ( & oa , & log_file , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwCreateFile ( & log_handle , FILE_WRITE_DATA , & oa , & iosb , NULL , FILE_ATTRIBUTE_NORMAL , FILE_SHARE_READ ,
FILE_OPEN_IF , FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_ALERT , NULL , 0 ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " ZwCreateFile returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( iosb . Information = = FILE_OPENED ) { // already exists
FILE_STANDARD_INFORMATION fsi ;
FILE_POSITION_INFORMATION fpi ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
static char delim [ ] = " \n --- \n " ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// move to end of file
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwQueryInformationFile ( log_handle , & iosb , & fsi , sizeof ( FILE_STANDARD_INFORMATION ) , FileStandardInformation ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " ZwQueryInformationFile returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fpi . CurrentByteOffset = fsi . EndOfFile ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwSetInformationFile ( log_handle , & iosb , & fpi , sizeof ( FILE_POSITION_INFORMATION ) , FilePositionInformation ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " ZwSetInformationFile returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
Status = ZwWriteFile ( log_handle , NULL , NULL , NULL , & iosb , delim , ( ULONG ) strlen ( delim ) , NULL , NULL ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " ZwWriteFile returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
dateline = ExAllocatePoolWithTag ( PagedPool , 256 , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! dateline ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
KeQuerySystemTime ( & time ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlTimeToTimeFields ( & time , & tf ) ;
2017-09-08 08:02:43 +00:00
sprintf ( dateline , " Starting logging at %04i-%02i-%02i %02i:%02i:%02i \n " , tf . Year , tf . Month , tf . Day , tf . Hour , tf . Minute , tf . Second ) ;
Status = ZwWriteFile ( log_handle , NULL , NULL , NULL , & iosb , dateline , ( ULONG ) strlen ( dateline ) , NULL , NULL ) ;
ExFreePool ( dateline ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " ZwWriteFile returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
end :
ExReleaseResourceLite ( & log_lock ) ;
}
# endif
_Function_class_ ( KSTART_ROUTINE )
# ifdef __REACTOS__
static void NTAPI degraded_wait_thread ( _In_ void * context ) {
# else
static void degraded_wait_thread ( _In_ void * context ) {
# endif
KTIMER timer ;
LARGE_INTEGER delay ;
UNUSED ( context ) ;
KeInitializeTimer ( & timer ) ;
delay . QuadPart = - 30000000 ; // wait three seconds
KeSetTimer ( & timer , delay , NULL ) ;
KeWaitForSingleObject ( & timer , Executive , KernelMode , FALSE , NULL ) ;
TRACE ( " timer expired \n " ) ;
degraded_wait = FALSE ;
ZwClose ( degraded_wait_handle ) ;
degraded_wait_handle = NULL ;
PsTerminateSystemThread ( STATUS_SUCCESS ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
# ifdef __REACTOS__
NTSTATUS NTAPI AddDevice ( PDRIVER_OBJECT DriverObject , PDEVICE_OBJECT PhysicalDeviceObject ) {
# else
NTSTATUS AddDevice ( PDRIVER_OBJECT DriverObject , PDEVICE_OBJECT PhysicalDeviceObject ) {
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le ;
NTSTATUS Status ;
UNICODE_STRING volname ;
ULONG i , j ;
pdo_device_extension * pdode = NULL ;
PDEVICE_OBJECT voldev ;
volume_device_extension * vde ;
TRACE ( " (%p, %p) \n " , DriverObject , PhysicalDeviceObject ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
ExAcquireResourceSharedLite ( & pdo_list_lock , TRUE ) ;
le = pdo_list . Flink ;
while ( le ! = & pdo_list ) {
pdo_device_extension * pdode2 = CONTAINING_RECORD ( le , pdo_device_extension , list_entry ) ;
if ( pdode2 - > pdo = = PhysicalDeviceObject ) {
pdode = pdode2 ;
break ;
}
le = le - > Flink ;
}
if ( ! pdode ) {
WARN ( " unrecognized PDO %p \n " , PhysicalDeviceObject ) ;
Status = STATUS_NOT_SUPPORTED ;
goto end ;
}
ExAcquireResourceSharedLite ( & pdode - > child_lock , TRUE ) ;
volname . Length = volname . MaximumLength = ( USHORT ) ( ( wcslen ( BTRFS_VOLUME_PREFIX ) + 36 + 1 ) * sizeof ( WCHAR ) ) ;
volname . Buffer = ExAllocatePoolWithTag ( PagedPool , volname . MaximumLength , ALLOC_TAG ) ; // FIXME - when do we free this?
if ( ! volname . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end2 ;
}
RtlCopyMemory ( volname . Buffer , BTRFS_VOLUME_PREFIX , wcslen ( BTRFS_VOLUME_PREFIX ) * sizeof ( WCHAR ) ) ;
j = ( ULONG ) wcslen ( BTRFS_VOLUME_PREFIX ) ;
for ( i = 0 ; i < 16 ; i + + ) {
volname . Buffer [ j ] = hex_digit ( pdode - > uuid . uuid [ i ] > > 4 ) ; j + + ;
volname . Buffer [ j ] = hex_digit ( pdode - > uuid . uuid [ i ] & 0xf ) ; j + + ;
if ( i = = 3 | | i = = 5 | | i = = 7 | | i = = 9 ) {
volname . Buffer [ j ] = ' - ' ;
j + + ;
}
}
volname . Buffer [ j ] = ' } ' ;
Status = IoCreateDevice ( drvobj , sizeof ( volume_device_extension ) , & volname , FILE_DEVICE_DISK ,
RtlIsNtDdiVersionAvailable ( NTDDI_WIN8 ) ? FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL : 0 , FALSE , & voldev ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoCreateDevice returned %08x \n " , Status ) ;
goto end2 ;
}
voldev - > SectorSize = PhysicalDeviceObject - > SectorSize ;
voldev - > Flags | = DO_DIRECT_IO ;
vde = voldev - > DeviceExtension ;
vde - > type = VCB_TYPE_VOLUME ;
vde - > name = volname ;
vde - > device = voldev ;
vde - > mounted_device = NULL ;
vde - > pdo = PhysicalDeviceObject ;
vde - > pdode = pdode ;
vde - > removing = FALSE ;
vde - > open_count = 0 ;
Status = IoRegisterDeviceInterface ( PhysicalDeviceObject , & GUID_DEVINTERFACE_VOLUME , NULL , & vde - > bus_name ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " IoRegisterDeviceInterface returned %08x \n " , Status ) ;
vde - > attached_device = IoAttachDeviceToDeviceStack ( voldev , PhysicalDeviceObject ) ;
pdode - > vde = vde ;
if ( pdode - > removable )
voldev - > Characteristics | = FILE_REMOVABLE_MEDIA ;
voldev - > Flags & = ~ DO_DEVICE_INITIALIZING ;
Status = IoSetDeviceInterfaceState ( & vde - > bus_name , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " IoSetDeviceInterfaceState returned %08x \n " , Status ) ;
Status = STATUS_SUCCESS ;
end2 :
ExReleaseResourceLite ( & pdode - > child_lock ) ;
end :
ExReleaseResourceLite ( & pdo_list_lock ) ;
return Status ;
}
_Function_class_ ( DRIVER_INITIALIZE )
# ifdef __REACTOS__
NTSTATUS NTAPI DriverEntry ( _In_ PDRIVER_OBJECT DriverObject , _In_ PUNICODE_STRING RegistryPath ) {
# else
NTSTATUS DriverEntry ( _In_ PDRIVER_OBJECT DriverObject , _In_ PUNICODE_STRING RegistryPath ) {
# endif
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PDEVICE_OBJECT DeviceObject ;
UNICODE_STRING device_nameW ;
UNICODE_STRING dosdevice_nameW ;
2017-01-01 17:12:12 +00:00
control_device_extension * cde ;
2017-09-08 08:02:43 +00:00
HANDLE regh ;
OBJECT_ATTRIBUTES oa ;
ULONG dispos ;
2016-03-23 20:35:05 +00:00
InitializeListHead ( & uid_map_list ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & gid_map_list ) ;
# ifdef _DEBUG
ExInitializeResourceLite ( & log_lock ) ;
# endif
ExInitializeResourceLite ( & mapping_lock ) ;
2016-03-23 20:35:05 +00:00
log_device . Buffer = NULL ;
log_device . Length = log_device . MaximumLength = 0 ;
log_file . Buffer = NULL ;
log_file . Length = log_file . MaximumLength = 0 ;
2016-07-27 19:24:26 +00:00
registry_path . Length = registry_path . MaximumLength = RegistryPath - > Length ;
registry_path . Buffer = ExAllocatePoolWithTag ( PagedPool , registry_path . Length , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! registry_path . Buffer ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( registry_path . Buffer , RegistryPath - > Buffer , registry_path . Length ) ;
2017-09-08 08:02:43 +00:00
read_registry ( & registry_path , FALSE ) ;
# ifdef _DEBUG
if ( debug_log_level > 0 )
init_logging ( ) ;
log_started = TRUE ;
# endif
TRACE ( " DriverEntry \n " ) ;
2016-03-23 20:35:05 +00:00
# ifndef __REACTOS__
check_cpu ( ) ;
# endif
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( RtlIsNtDdiVersionAvailable ( NTDDI_WIN8 ) ) {
UNICODE_STRING name ;
2017-09-08 08:02:43 +00:00
tPsIsDiskCountersEnabled fPsIsDiskCountersEnabled ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " PsIsDiskCountersEnabled " ) ;
2017-09-08 08:02:43 +00:00
fPsIsDiskCountersEnabled = ( tPsIsDiskCountersEnabled ) MmGetSystemRoutineAddress ( & name ) ;
if ( fPsIsDiskCountersEnabled ) {
diskacc = fPsIsDiskCountersEnabled ( ) ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " PsUpdateDiskCounters " ) ;
2017-09-08 08:02:43 +00:00
fPsUpdateDiskCounters = ( tPsUpdateDiskCounters ) MmGetSystemRoutineAddress ( & name ) ;
if ( ! fPsUpdateDiskCounters )
2017-01-01 17:12:12 +00:00
diskacc = FALSE ;
2017-09-08 08:02:43 +00:00
RtlInitUnicodeString ( & name , L " FsRtlUpdateDiskCounters " ) ;
fFsRtlUpdateDiskCounters = ( tFsRtlUpdateDiskCounters ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " CcCopyReadEx " ) ;
2017-09-08 08:02:43 +00:00
fCcCopyReadEx = ( tCcCopyReadEx ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " CcCopyWriteEx " ) ;
2017-09-08 08:02:43 +00:00
fCcCopyWriteEx = ( tCcCopyWriteEx ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " CcSetAdditionalCacheAttributesEx " ) ;
2017-09-08 08:02:43 +00:00
fCcSetAdditionalCacheAttributesEx = ( tCcSetAdditionalCacheAttributesEx ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
} else {
2017-09-08 08:02:43 +00:00
fPsUpdateDiskCounters = NULL ;
fCcCopyReadEx = NULL ;
fCcCopyWriteEx = NULL ;
fCcSetAdditionalCacheAttributesEx = NULL ;
fFsRtlUpdateDiskCounters = NULL ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
drvobj = DriverObject ;
DriverObject - > DriverUnload = DriverUnload ;
2017-09-08 08:02:43 +00:00
DriverObject - > DriverExtension - > AddDevice = AddDevice ;
2016-03-23 20:35:05 +00:00
DriverObject - > MajorFunction [ IRP_MJ_CREATE ] = ( PDRIVER_DISPATCH ) drv_create ;
DriverObject - > MajorFunction [ IRP_MJ_CLOSE ] = ( PDRIVER_DISPATCH ) drv_close ;
DriverObject - > MajorFunction [ IRP_MJ_READ ] = ( PDRIVER_DISPATCH ) drv_read ;
DriverObject - > MajorFunction [ IRP_MJ_WRITE ] = ( PDRIVER_DISPATCH ) drv_write ;
DriverObject - > MajorFunction [ IRP_MJ_QUERY_INFORMATION ] = ( PDRIVER_DISPATCH ) drv_query_information ;
DriverObject - > MajorFunction [ IRP_MJ_SET_INFORMATION ] = ( PDRIVER_DISPATCH ) drv_set_information ;
DriverObject - > MajorFunction [ IRP_MJ_QUERY_EA ] = ( PDRIVER_DISPATCH ) drv_query_ea ;
DriverObject - > MajorFunction [ IRP_MJ_SET_EA ] = ( PDRIVER_DISPATCH ) drv_set_ea ;
DriverObject - > MajorFunction [ IRP_MJ_FLUSH_BUFFERS ] = ( PDRIVER_DISPATCH ) drv_flush_buffers ;
DriverObject - > MajorFunction [ IRP_MJ_QUERY_VOLUME_INFORMATION ] = ( PDRIVER_DISPATCH ) drv_query_volume_information ;
DriverObject - > MajorFunction [ IRP_MJ_SET_VOLUME_INFORMATION ] = ( PDRIVER_DISPATCH ) drv_set_volume_information ;
DriverObject - > MajorFunction [ IRP_MJ_DIRECTORY_CONTROL ] = ( PDRIVER_DISPATCH ) drv_directory_control ;
DriverObject - > MajorFunction [ IRP_MJ_FILE_SYSTEM_CONTROL ] = ( PDRIVER_DISPATCH ) drv_file_system_control ;
DriverObject - > MajorFunction [ IRP_MJ_DEVICE_CONTROL ] = ( PDRIVER_DISPATCH ) drv_device_control ;
DriverObject - > MajorFunction [ IRP_MJ_SHUTDOWN ] = ( PDRIVER_DISPATCH ) drv_shutdown ;
2017-09-08 08:02:43 +00:00
DriverObject - > MajorFunction [ IRP_MJ_LOCK_CONTROL ] = ( PDRIVER_DISPATCH ) drv_lock_control ;
DriverObject - > MajorFunction [ IRP_MJ_CLEANUP ] = ( PDRIVER_DISPATCH ) drv_cleanup ;
2016-03-23 20:35:05 +00:00
DriverObject - > MajorFunction [ IRP_MJ_QUERY_SECURITY ] = ( PDRIVER_DISPATCH ) drv_query_security ;
DriverObject - > MajorFunction [ IRP_MJ_SET_SECURITY ] = ( PDRIVER_DISPATCH ) drv_set_security ;
2017-09-08 08:02:43 +00:00
DriverObject - > MajorFunction [ IRP_MJ_POWER ] = ( PDRIVER_DISPATCH ) drv_power ;
DriverObject - > MajorFunction [ IRP_MJ_SYSTEM_CONTROL ] = ( PDRIVER_DISPATCH ) drv_system_control ;
DriverObject - > MajorFunction [ IRP_MJ_PNP ] = ( PDRIVER_DISPATCH ) drv_pnp ;
2016-03-23 20:35:05 +00:00
init_fast_io_dispatch ( & DriverObject - > FastIoDispatch ) ;
device_nameW . Buffer = device_name ;
device_nameW . Length = device_nameW . MaximumLength = ( USHORT ) wcslen ( device_name ) * sizeof ( WCHAR ) ;
dosdevice_nameW . Buffer = dosdevice_name ;
dosdevice_nameW . Length = dosdevice_nameW . MaximumLength = ( USHORT ) wcslen ( dosdevice_name ) * sizeof ( WCHAR ) ;
2017-01-01 17:12:12 +00:00
Status = IoCreateDevice ( DriverObject , sizeof ( control_device_extension ) , & device_nameW , FILE_DEVICE_DISK_FILE_SYSTEM ,
FILE_DEVICE_SECURE_OPEN , FALSE , & DeviceObject ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoCreateDevice returned %08x \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
master_devobj = DeviceObject ;
cde = ( control_device_extension * ) master_devobj - > DeviceExtension ;
RtlZeroMemory ( cde , sizeof ( control_device_extension ) ) ;
2017-01-01 17:12:12 +00:00
cde - > type = VCB_TYPE_CONTROL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
DeviceObject - > Flags & = ~ DO_DEVICE_INITIALIZING ;
Status = IoCreateSymbolicLink ( & dosdevice_nameW , & device_nameW ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoCreateSymbolicLink returned %08x \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = init_cache ( ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " init_cache returned %08x \n " , Status ) ;
return Status ;
}
InitializeListHead ( & VcbList ) ;
ExInitializeResourceLite ( & global_loading_lock ) ;
2017-09-08 08:02:43 +00:00
ExInitializeResourceLite ( & pdo_list_lock ) ;
InitializeListHead ( & pdo_list ) ;
InitializeObjectAttributes ( & oa , RegistryPath , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE , NULL , NULL ) ;
Status = ZwCreateKey ( & regh , KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY , & oa , 0 , NULL , REG_OPTION_NON_VOLATILE , & dispos ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " ZwCreateKey returned %08x \n " , Status ) ;
return Status ;
}
watch_registry ( regh ) ;
Status = IoReportDetectedDevice ( drvobj , InterfaceTypeUndefined , 0xFFFFFFFF , 0xFFFFFFFF ,
NULL , NULL , 0 , & cde - > buspdo ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoReportDetectedDevice returned %08x \n " , Status ) ;
return Status ;
}
Status = IoRegisterDeviceInterface ( cde - > buspdo , & BtrfsBusInterface , NULL , & cde - > bus_name ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " IoRegisterDeviceInterface returned %08x \n " , Status ) ;
cde - > attached_device = IoAttachDeviceToDeviceStack ( DeviceObject , cde - > buspdo ) ;
Status = IoSetDeviceInterfaceState ( & cde - > bus_name , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " IoSetDeviceInterfaceState returned %08x \n " , Status ) ;
DeviceObject - > Flags & = ~ DO_DEVICE_INITIALIZING ;
IoInvalidateDeviceRelations ( cde - > buspdo , BusRelations ) ;
Status = PsCreateSystemThread ( & degraded_wait_handle , 0 , NULL , NULL , NULL , degraded_wait_thread , NULL ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " PsCreateSystemThread returned %08x \n " , Status ) ;
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange , PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES ,
( PVOID ) & GUID_DEVINTERFACE_VOLUME , DriverObject , volume_notification , DriverObject , & notification_entry2 ) ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " IoRegisterPlugPlayNotification returned %08x \n " , Status ) ;
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange , PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES ,
( PVOID ) & GUID_DEVINTERFACE_HIDDEN_VOLUME , DriverObject , volume_notification , DriverObject , & notification_entry3 ) ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " IoRegisterPlugPlayNotification returned %08x \n " , Status ) ;
2017-01-01 17:12:12 +00:00
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange , PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES ,
( PVOID ) & GUID_DEVINTERFACE_DISK , DriverObject , pnp_notification , DriverObject , & notification_entry ) ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " IoRegisterPlugPlayNotification returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
finished_probing = TRUE ;
KeInitializeEvent ( & mountmgr_thread_event , NotificationEvent , FALSE ) ;
2017-09-14 09:04:32 +00:00
# ifndef __REACTOS__
2017-09-08 08:02:43 +00:00
Status = PsCreateSystemThread ( & mountmgr_thread_handle , 0 , NULL , NULL , NULL , mountmgr_thread , NULL ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " PsCreateSystemThread returned %08x \n " , Status ) ;
2017-09-14 09:04:32 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoRegisterFileSystem ( DeviceObject ) ;
return STATUS_SUCCESS ;
}