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/>. */
2016-05-09 09:10:13 +00:00
# ifndef __REACTOS__
2016-03-23 20:35:05 +00:00
# include <sys/stat.h>
2016-05-09 09:10:13 +00:00
# endif /* __REACTOS__ */
2016-03-23 20:35:05 +00:00
# include "btrfs_drv.h"
2020-04-23 02:38:57 +00:00
# include "crc32c.h"
2017-09-08 08:02:43 +00:00
# include <ntddstor.h>
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
extern PDEVICE_OBJECT master_devobj ;
2019-09-01 12:53:20 +00:00
extern tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp ;
extern tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter ;
extern tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer ;
2016-03-23 20:35:05 +00:00
2018-12-16 11:03:16 +00:00
static const WCHAR datastring [ ] = L " ::$DATA " ;
2019-11-12 18:32:46 +00:00
static const char root_dir [ ] = " $Root " ;
static const WCHAR root_dir_utf16 [ ] = L " $Root " ;
2018-12-16 11:03:16 +00:00
// Windows 10
# define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
2020-04-23 02:38:57 +00:00
# define ATOMIC_CREATE_ECP_IN_FLAG_OP_FLAGS_SPECIFIED 0x0080
2018-12-16 11:03:16 +00:00
# define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
2020-04-23 02:38:57 +00:00
2018-12-16 11:03:16 +00:00
# define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
2020-04-23 02:38:57 +00:00
# define ATOMIC_CREATE_ECP_OUT_FLAG_OP_FLAGS_HONORED 0x0080
# define ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED 1
# define ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET 1
2022-04-28 19:31:44 +00:00
# ifndef SL_IGNORE_READONLY_ATTRIBUTE
# define SL_IGNORE_READONLY_ATTRIBUTE 0x40 // introduced in Windows 10, not in mingw
# endif
2020-04-23 02:38:57 +00:00
typedef struct _FILE_TIMESTAMPS {
LARGE_INTEGER CreationTime ;
LARGE_INTEGER LastAccessTime ;
LARGE_INTEGER LastWriteTime ;
LARGE_INTEGER ChangeTime ;
} FILE_TIMESTAMPS , * PFILE_TIMESTAMPS ;
2018-12-16 11:03:16 +00:00
typedef struct _ATOMIC_CREATE_ECP_CONTEXT {
USHORT Size ;
USHORT InFlags ;
USHORT OutFlags ;
USHORT ReparseBufferLength ;
PREPARSE_DATA_BUFFER ReparseBuffer ;
LONGLONG FileSize ;
LONGLONG ValidDataLength ;
2020-04-23 02:38:57 +00:00
PFILE_TIMESTAMPS FileTimestamps ;
ULONG FileAttributes ;
ULONG UsnSourceInfo ;
USN Usn ;
ULONG SuppressFileAttributeInheritanceMask ;
ULONG InOpFlags ;
ULONG OutOpFlags ;
ULONG InGenFlags ;
ULONG OutGenFlags ;
ULONG CaseSensitiveFlagsMask ;
ULONG InCaseSensitiveFlags ;
ULONG OutCaseSensitiveFlags ;
2018-12-16 11:03:16 +00:00
} ATOMIC_CREATE_ECP_CONTEXT , * PATOMIC_CREATE_ECP_CONTEXT ;
static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83 , 0x52ac , 0x4104 , { 0xa1 , 0x30 , 0xd1 , 0xec , 0x6a , 0x8c , 0xc8 , 0xe5 } } ;
2020-04-23 02:38:57 +00:00
static const GUID GUID_ECP_QUERY_ON_CREATE = { 0x1aca62e9 , 0xabb4 , 0x4ff2 , { 0xbb , 0x5c , 0x1c , 0x79 , 0x02 , 0x5e , 0x41 , 0x7f } } ;
static const GUID GUID_ECP_CREATE_REDIRECTION = { 0x188d6bd6 , 0xa126 , 0x4fa8 , { 0xbd , 0xf2 , 0x1c , 0xcd , 0xf8 , 0x96 , 0xf3 , 0xe0 } } ;
2016-10-29 17:05:10 +00:00
2022-04-28 19:34:48 +00:00
typedef struct {
device_extension * Vcb ;
ACCESS_MASK granted_access ;
file_ref * fileref ;
2022-04-28 19:37:02 +00:00
NTSTATUS Status ;
KEVENT event ;
2022-04-28 19:34:48 +00:00
} oplock_context ;
2017-09-08 08:02:43 +00:00
fcb * create_fcb ( device_extension * Vcb , POOL_TYPE pool_type ) {
2016-03-23 20:35:05 +00:00
fcb * fcb ;
2017-09-08 08:02:43 +00:00
if ( pool_type = = NonPagedPool ) {
fcb = ExAllocatePoolWithTag ( pool_type , sizeof ( struct _fcb ) , ALLOC_TAG ) ;
if ( ! fcb ) {
ERR ( " out of memory \n " ) ;
return NULL ;
}
} else {
fcb = ExAllocateFromPagedLookasideList ( & Vcb - > fcb_lookaside ) ;
if ( ! fcb ) {
ERR ( " out of memory \n " ) ;
return NULL ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
WARN ( " allocating fcb %p \n " , fcb ) ;
# endif
RtlZeroMemory ( fcb , sizeof ( struct _fcb ) ) ;
2017-09-08 08:02:43 +00:00
fcb - > pool_type = pool_type ;
2016-03-23 20:35:05 +00:00
fcb - > Header . NodeTypeCode = BTRFS_NODE_TYPE_FCB ;
fcb - > Header . NodeByteSize = sizeof ( struct _fcb ) ;
2017-09-08 08:02:43 +00:00
fcb - > nonpaged = ExAllocateFromNPagedLookasideList ( & Vcb - > fcb_np_lookaside ) ;
2016-03-23 20:35:05 +00:00
if ( ! fcb - > nonpaged ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
if ( pool_type = = NonPagedPool )
ExFreePool ( fcb ) ;
else
ExFreeToPagedLookasideList ( & Vcb - > fcb_lookaside , fcb ) ;
2016-03-23 20:35:05 +00:00
return NULL ;
}
RtlZeroMemory ( fcb - > nonpaged , sizeof ( struct _fcb_nonpaged ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & fcb - > nonpaged - > paging_resource ) ;
fcb - > Header . PagingIoResource = & fcb - > nonpaged - > paging_resource ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExInitializeFastMutex ( & fcb - > nonpaged - > HeaderMutex ) ;
FsRtlSetupAdvancedHeader ( & fcb - > Header , & fcb - > nonpaged - > HeaderMutex ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fcb - > refcount = 1 ;
# ifdef DEBUG_FCB_REFCOUNTS
WARN ( " fcb %p: refcount now %i \n " , fcb , fcb - > refcount ) ;
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & fcb - > nonpaged - > resource ) ;
fcb - > Header . Resource = & fcb - > nonpaged - > resource ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExInitializeResourceLite ( & fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlInitializeFileLock ( & fcb - > lock , NULL , NULL ) ;
2019-11-12 18:32:46 +00:00
FsRtlInitializeOplock ( fcb_oplock ( fcb ) ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InitializeListHead ( & fcb - > extents ) ;
InitializeListHead ( & fcb - > hardlinks ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & fcb - > xattrs ) ;
2017-01-01 17:12:12 +00:00
InitializeListHead ( & fcb - > dir_children_index ) ;
InitializeListHead ( & fcb - > dir_children_hash ) ;
InitializeListHead ( & fcb - > dir_children_hash_uc ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return fcb ;
}
2017-09-08 08:02:43 +00:00
file_ref * create_fileref ( device_extension * Vcb ) {
2016-05-05 17:26:47 +00:00
file_ref * fr ;
2017-09-08 08:02:43 +00:00
fr = ExAllocateFromPagedLookasideList ( & Vcb - > fileref_lookaside ) ;
2016-05-05 17:26:47 +00:00
if ( ! fr ) {
ERR ( " out of memory \n " ) ;
return NULL ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlZeroMemory ( fr , sizeof ( file_ref ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fr - > refcount = 1 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
WARN ( " fileref %p: refcount now 1 \n " , fr ) ;
# endif
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InitializeListHead ( & fr - > children ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return fr ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS find_file_in_dir ( PUNICODE_STRING filename , fcb * fcb , root * * subvol , uint64_t * inode , dir_child * * pdc , bool case_sensitive ) {
2017-01-01 17:12:12 +00:00
NTSTATUS Status ;
UNICODE_STRING fnus ;
2019-09-01 12:53:20 +00:00
uint32_t hash ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
uint8_t c ;
bool locked = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! case_sensitive ) {
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & fnus , filename , true ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
} else
fnus = * filename ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:35:05 +00:00
Status = check_file_name_valid ( filename , false , false ) ;
if ( ! NT_SUCCESS ( Status ) )
return Status ;
2019-09-01 12:53:20 +00:00
hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) fnus . Buffer , fnus . Length ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c = hash > > 24 ;
2017-09-08 08:02:43 +00:00
if ( ! ExIsResourceAcquiredSharedLite ( & fcb - > nonpaged - > dir_children_lock ) ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & fcb - > nonpaged - > dir_children_lock , true ) ;
locked = true ;
2017-09-08 08:02:43 +00:00
}
2017-01-01 17:12:12 +00:00
if ( case_sensitive ) {
if ( ! fcb - > hash_ptrs [ c ] ) {
Status = STATUS_OBJECT_NAME_NOT_FOUND ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = fcb - > hash_ptrs [ c ] ;
while ( le ! = & fcb - > dir_children_hash ) {
dir_child * dc = CONTAINING_RECORD ( le , dir_child , list_entry_hash ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc - > hash = = hash ) {
if ( dc - > name . Length = = fnus . Length & & RtlCompareMemory ( dc - > name . Buffer , fnus . Buffer , fnus . Length ) = = fnus . Length ) {
if ( dc - > key . obj_type = = TYPE_ROOT_ITEM ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* subvol = NULL ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = fcb - > Vcb - > roots . Flink ;
while ( le2 ! = & fcb - > Vcb - > roots ) {
root * r2 = CONTAINING_RECORD ( le2 , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( r2 - > id = = dc - > key . obj_id ) {
* subvol = r2 ;
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* inode = SUBVOL_ROOT_INODE ;
} else {
* subvol = fcb - > subvol ;
* inode = dc - > key . obj_id ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* pdc = dc ;
Status = STATUS_SUCCESS ;
goto end ;
}
} else if ( dc - > hash > hash ) {
Status = STATUS_OBJECT_NAME_NOT_FOUND ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
} else {
if ( ! fcb - > hash_ptrs_uc [ c ] ) {
Status = STATUS_OBJECT_NAME_NOT_FOUND ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = fcb - > hash_ptrs_uc [ c ] ;
while ( le ! = & fcb - > dir_children_hash_uc ) {
dir_child * dc = CONTAINING_RECORD ( le , dir_child , list_entry_hash_uc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc - > hash_uc = = hash ) {
if ( dc - > name_uc . Length = = fnus . Length & & RtlCompareMemory ( dc - > name_uc . Buffer , fnus . Buffer , fnus . Length ) = = fnus . Length ) {
if ( dc - > key . obj_type = = TYPE_ROOT_ITEM ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* subvol = NULL ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = fcb - > Vcb - > roots . Flink ;
while ( le2 ! = & fcb - > Vcb - > roots ) {
root * r2 = CONTAINING_RECORD ( le2 , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( r2 - > id = = dc - > key . obj_id ) {
* subvol = r2 ;
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = le2 - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* inode = SUBVOL_ROOT_INODE ;
} else {
* subvol = fcb - > subvol ;
* inode = dc - > key . obj_id ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* pdc = dc ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = STATUS_SUCCESS ;
goto end ;
}
} else if ( dc - > hash_uc > hash ) {
Status = STATUS_OBJECT_NAME_NOT_FOUND ;
goto end ;
}
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
Status = STATUS_OBJECT_NAME_NOT_FOUND ;
2016-05-05 17:26:47 +00:00
2017-01-01 17:12:12 +00:00
end :
2017-09-08 08:02:43 +00:00
if ( locked )
ExReleaseResourceLite ( & fcb - > nonpaged - > dir_children_lock ) ;
2017-01-01 17:12:12 +00:00
if ( ! case_sensitive )
ExFreePool ( fnus . Buffer ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2019-09-01 12:53:20 +00:00
static NTSTATUS split_path ( device_extension * Vcb , PUNICODE_STRING path , LIST_ENTRY * parts , bool * stream ) {
2017-09-08 08:02:43 +00:00
ULONG len , i ;
2019-09-01 12:53:20 +00:00
bool has_stream ;
2016-03-23 20:35:05 +00:00
WCHAR * buf ;
2017-09-08 08:02:43 +00:00
name_bit * nb ;
2019-05-11 09:20:02 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
len = path - > Length / sizeof ( WCHAR ) ;
if ( len > 0 & & ( path - > Buffer [ len - 1 ] = = ' / ' | | path - > Buffer [ len - 1 ] = = ' \\ ' ) )
len - - ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( len = = 0 | | ( path - > Buffer [ len - 1 ] = = ' / ' | | path - > Buffer [ len - 1 ] = = ' \\ ' ) ) {
WARN ( " zero-length filename part \n " ) ;
return STATUS_OBJECT_NAME_INVALID ;
}
2019-09-01 12:53:20 +00:00
has_stream = false ;
2016-03-23 20:35:05 +00:00
for ( i = 0 ; i < len ; i + + ) {
if ( path - > Buffer [ i ] = = ' / ' | | path - > Buffer [ i ] = = ' \\ ' ) {
2019-09-01 12:53:20 +00:00
has_stream = false ;
2016-03-23 20:35:05 +00:00
} else if ( path - > Buffer [ i ] = = ' : ' ) {
2019-09-01 12:53:20 +00:00
has_stream = true ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
buf = path - > Buffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
for ( i = 0 ; i < len ; i + + ) {
if ( path - > Buffer [ i ] = = ' / ' | | path - > Buffer [ i ] = = ' \\ ' ) {
2019-05-11 09:20:02 +00:00
if ( buf [ 0 ] = = ' / ' | | buf [ 0 ] = = ' \\ ' ) {
WARN ( " zero-length filename part \n " ) ;
Status = STATUS_OBJECT_NAME_INVALID ;
goto cleanup ;
}
2017-09-08 08:02:43 +00:00
nb = ExAllocateFromPagedLookasideList ( & Vcb - > name_bit_lookaside ) ;
if ( ! nb ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto cleanup ;
2017-09-08 08:02:43 +00:00
}
nb - > us . Buffer = buf ;
nb - > us . Length = nb - > us . MaximumLength = ( USHORT ) ( & path - > Buffer [ i ] - buf ) * sizeof ( WCHAR ) ;
InsertTailList ( parts , & nb - > list_entry ) ;
2016-03-23 20:35:05 +00:00
buf = & path - > Buffer [ i + 1 ] ;
}
}
2017-09-08 08:02:43 +00:00
nb = ExAllocateFromPagedLookasideList ( & Vcb - > name_bit_lookaside ) ;
if ( ! nb ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto cleanup ;
2017-09-08 08:02:43 +00:00
}
nb - > us . Buffer = buf ;
nb - > us . Length = nb - > us . MaximumLength = ( USHORT ) ( & path - > Buffer [ i ] - buf ) * sizeof ( WCHAR ) ;
InsertTailList ( parts , & nb - > list_entry ) ;
2016-03-23 20:35:05 +00:00
if ( has_stream ) {
2018-12-16 11:03:16 +00:00
static const WCHAR datasuf [ ] = { ' : ' , ' $ ' , ' D ' , ' A ' , ' T ' , ' A ' , 0 } ;
2016-03-23 20:35:05 +00:00
UNICODE_STRING dsus ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
dsus . Buffer = ( WCHAR * ) datasuf ;
dsus . Length = dsus . MaximumLength = sizeof ( datasuf ) - sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
for ( i = 0 ; i < nb - > us . Length / sizeof ( WCHAR ) ; i + + ) {
if ( nb - > us . Buffer [ i ] = = ' : ' ) {
name_bit * nb2 ;
2022-04-28 19:33:48 +00:00
if ( i + 1 = = nb - > us . Length / sizeof ( WCHAR ) ) {
2019-05-11 09:20:02 +00:00
WARN ( " zero-length stream name \n " ) ;
Status = STATUS_OBJECT_NAME_INVALID ;
goto cleanup ;
}
2017-09-08 08:02:43 +00:00
nb2 = ExAllocateFromPagedLookasideList ( & Vcb - > name_bit_lookaside ) ;
if ( ! nb2 ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto cleanup ;
2017-09-08 08:02:43 +00:00
}
nb2 - > us . Buffer = & nb - > us . Buffer [ i + 1 ] ;
2019-09-01 12:53:20 +00:00
nb2 - > us . Length = nb2 - > us . MaximumLength = ( uint16_t ) ( nb - > us . Length - ( i * sizeof ( WCHAR ) ) - sizeof ( WCHAR ) ) ;
2017-09-08 08:02:43 +00:00
InsertTailList ( parts , & nb2 - > list_entry ) ;
2019-09-01 12:53:20 +00:00
nb - > us . Length = ( uint16_t ) i * sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
nb - > us . MaximumLength = nb - > us . Length ;
nb = nb2 ;
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
// FIXME - should comparison be case-insensitive?
// remove :$DATA suffix
2017-09-08 08:02:43 +00:00
if ( nb - > us . Length > = dsus . Length & & RtlCompareMemory ( & nb - > us . Buffer [ ( nb - > us . Length - dsus . Length ) / sizeof ( WCHAR ) ] , dsus . Buffer , dsus . Length ) = = dsus . Length )
nb - > us . Length - = dsus . Length ;
if ( nb - > us . Length = = 0 ) {
RemoveTailList ( parts ) ;
ExFreeToPagedLookasideList ( & Vcb - > name_bit_lookaside , nb ) ;
2019-09-01 12:53:20 +00:00
has_stream = false ;
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 path is just stream name, remove first empty item
if ( has_stream & & path - > Length > = sizeof ( WCHAR ) & & path - > Buffer [ 0 ] = = ' : ' ) {
2017-09-08 08:02:43 +00:00
name_bit * nb1 = CONTAINING_RECORD ( RemoveHeadList ( parts ) , name_bit , list_entry ) ;
ExFreeToPagedLookasideList ( & Vcb - > name_bit_lookaside , nb1 ) ;
2016-03-23 20:35:05 +00:00
}
* stream = has_stream ;
2016-07-27 19:24:26 +00:00
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2019-05-11 09:20:02 +00:00
cleanup :
while ( ! IsListEmpty ( parts ) ) {
nb = CONTAINING_RECORD ( RemoveHeadList ( parts ) , name_bit , list_entry ) ;
ExFreeToPagedLookasideList ( & Vcb - > name_bit_lookaside , nb ) ;
}
return Status ;
2016-03-23 20:35:05 +00:00
}
2016-03-26 11:53:07 +00:00
2020-04-23 02:38:57 +00:00
NTSTATUS load_csum ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , void * csum , uint64_t start , uint64_t length , PIRP Irp ) {
2017-01-01 17:12:12 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp , next_tp ;
2019-09-01 12:53:20 +00:00
uint64_t i , j ;
bool b ;
2020-04-23 02:38:57 +00:00
void * ptr = csum ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
searchkey . obj_id = EXTENT_CSUM_ID ;
searchkey . obj_type = TYPE_EXTENT_CSUM ;
searchkey . offset = start ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > checksum_root , & tp , & searchkey , false , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
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
i = 0 ;
do {
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
ULONG readlen ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( start < tp . item - > key . offset )
j = 0 ;
else
2022-04-28 19:31:44 +00:00
j = ( ( start - tp . item - > key . offset ) > > Vcb - > sector_shift ) + i ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( j * Vcb - > csum_size > tp . item - > size | | tp . item - > key . offset > start + ( i < < Vcb - > sector_shift ) ) {
ERR ( " checksum not found for %I64x \n " , start + ( i < < Vcb - > sector_shift ) ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
readlen = ( ULONG ) min ( ( tp . item - > size / Vcb - > csum_size ) - j , length - i ) ;
RtlCopyMemory ( ptr , tp . item - > data + ( j * Vcb - > csum_size ) , readlen * Vcb - > csum_size ) ;
ptr = ( uint8_t * ) ptr + ( readlen * Vcb - > csum_size ) ;
2017-01-01 17:12:12 +00:00
i + = readlen ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( i = = length )
break ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( b )
tp = next_tp ;
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( i < length ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not read checksums: offset %I64x, length %I64x sectors \n " , start , length ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS load_dir_children ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , fcb * fcb , bool ignore_size , PIRP Irp ) {
2017-01-01 17:12:12 +00:00
KEY searchkey ;
traverse_ptr tp , next_tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG num_children = 0 ;
2019-11-12 18:32:46 +00:00
uint64_t max_index = 2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fcb - > hash_ptrs = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! fcb - > hash_ptrs ) {
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 ( fcb - > hash_ptrs , sizeof ( LIST_ENTRY * ) * 256 ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fcb - > hash_ptrs_uc = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! fcb - > hash_ptrs_uc ) {
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 ( fcb - > hash_ptrs_uc , sizeof ( LIST_ENTRY * ) * 256 ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! ignore_size & & fcb - > inode_item . st_size = = 0 )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
searchkey . obj_id = fcb - > inode ;
searchkey . obj_type = TYPE_DIR_INDEX ;
searchkey . offset = 2 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , fcb - > subvol , & tp , & searchkey , false , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
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
if ( keycmp ( tp . item - > key , searchkey ) = = - 1 ) {
2019-09-01 12:53:20 +00:00
if ( find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ) {
2017-01-01 17:12:12 +00:00
tp = next_tp ;
2019-09-01 12:53:20 +00:00
TRACE ( " moving on to %I64x,%x,%I64x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-01-01 17:12:12 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
DIR_ITEM * di = ( DIR_ITEM * ) tp . item - > data ;
dir_child * dc ;
ULONG utf16len ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( tp . item - > size < sizeof ( DIR_ITEM ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DIR_ITEM ) ) ;
2017-01-01 17:12:12 +00:00
goto cont ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( di - > n = = 0 ) {
2019-09-01 12:53:20 +00:00
WARN ( " (%I64x,%x,%I64x): DIR_ITEM name length is zero \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-01-01 17:12:12 +00:00
goto cont ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & utf16len , di - > name , di - > n ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto cont ;
}
dc = ExAllocatePoolWithTag ( PagedPool , sizeof ( dir_child ) , ALLOC_TAG ) ;
if ( ! dc ) {
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
dc - > key = di - > key ;
dc - > index = tp . item - > key . offset ;
dc - > type = di - > type ;
dc - > fileref = NULL ;
2019-11-12 18:32:46 +00:00
dc - > root_dir = false ;
max_index = dc - > index ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dc - > utf8 . MaximumLength = dc - > utf8 . Length = di - > n ;
dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , di - > n , ALLOC_TAG ) ;
if ( ! dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( dc - > utf8 . Buffer , di - > name , di - > n ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
dc - > name . MaximumLength = dc - > name . Length = ( uint16_t ) utf16len ;
2017-01-01 17:12:12 +00:00
dc - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , dc - > name . MaximumLength , ALLOC_TAG ) ;
if ( ! dc - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( dc - > name . Buffer , utf16len , & utf16len , di - > name , di - > n ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
goto cont ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & dc - > name_uc , & dc - > name , true ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
goto cont ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
dc - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name . Buffer , dc - > name . Length ) ;
dc - > hash_uc = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name_uc . Buffer , dc - > name_uc . Length ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertTailList ( & fcb - > dir_children_index , & dc - > list_entry_index ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
insert_dir_child_into_hash_lists ( fcb , dc ) ;
2017-09-08 08:02:43 +00:00
num_children + + ;
2017-01-01 17:12:12 +00:00
cont :
2019-09-01 12:53:20 +00:00
if ( find_next_item ( Vcb , & tp , & next_tp , false , Irp ) )
2017-01-01 17:12:12 +00:00
tp = next_tp ;
else
break ;
}
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( ! Vcb - > options . no_root_dir & & fcb - > inode = = SUBVOL_ROOT_INODE ) {
root * top_subvol ;
if ( Vcb - > root_fileref & & Vcb - > root_fileref - > fcb )
top_subvol = Vcb - > root_fileref - > fcb - > subvol ;
else
top_subvol = find_default_subvol ( Vcb , NULL ) ;
if ( fcb - > subvol = = top_subvol & & top_subvol - > id ! = BTRFS_ROOT_FSTREE ) {
dir_child * dc = ExAllocatePoolWithTag ( PagedPool , sizeof ( dir_child ) , ALLOC_TAG ) ;
if ( ! dc ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
dc - > key . obj_id = BTRFS_ROOT_FSTREE ;
dc - > key . obj_type = TYPE_ROOT_ITEM ;
dc - > key . offset = 0 ;
dc - > index = max_index + 1 ;
dc - > type = BTRFS_TYPE_DIRECTORY ;
dc - > fileref = NULL ;
dc - > root_dir = true ;
dc - > utf8 . MaximumLength = dc - > utf8 . Length = sizeof ( root_dir ) - sizeof ( char ) ;
dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , sizeof ( root_dir ) - sizeof ( char ) , ALLOC_TAG ) ;
if ( ! dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( dc - > utf8 . Buffer , root_dir , sizeof ( root_dir ) - sizeof ( char ) ) ;
dc - > name . MaximumLength = dc - > name . Length = sizeof ( root_dir_utf16 ) - sizeof ( WCHAR ) ;
dc - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , sizeof ( root_dir_utf16 ) - sizeof ( WCHAR ) , ALLOC_TAG ) ;
if ( ! dc - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( dc - > name . Buffer , root_dir_utf16 , sizeof ( root_dir_utf16 ) - sizeof ( WCHAR ) ) ;
Status = RtlUpcaseUnicodeString ( & dc - > name_uc , & dc - > name , true ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
2019-11-12 18:32:46 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
goto cont ;
}
dc - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name . Buffer , dc - > name . Length ) ;
dc - > hash_uc = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name_uc . Buffer , dc - > name_uc . Length ) ;
InsertTailList ( & fcb - > dir_children_index , & dc - > list_entry_index ) ;
insert_dir_child_into_hash_lists ( fcb , dc ) ;
}
}
2017-01-01 17:12:12 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS open_fcb ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) device_extension * Vcb ,
2019-09-01 12:53:20 +00:00
root * subvol , uint64_t inode , uint8_t type , PANSI_STRING utf8 , bool always_add_hl , fcb * parent , fcb * * pfcb , POOL_TYPE pooltype , PIRP Irp ) {
2016-05-05 17:26:47 +00:00
KEY searchkey ;
2017-01-01 17:12:12 +00:00
traverse_ptr tp , next_tp ;
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
fcb * fcb , * deleted_fcb = NULL ;
2019-09-01 12:53:20 +00:00
bool atts_set = false , sd_set = false , no_data ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * lastle = NULL ;
EXTENT_DATA * ed = NULL ;
2022-04-28 19:33:48 +00:00
uint64_t fcbs_version = 0 ;
2019-09-01 12:53:20 +00:00
uint32_t hash ;
2019-05-11 09:20:02 +00:00
2019-09-01 12:53:20 +00:00
hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) & inode , sizeof ( uint64_t ) ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
acquire_fcb_lock_shared ( Vcb ) ;
if ( subvol - > fcbs_ptrs [ hash > > 24 ] ) {
LIST_ENTRY * le = subvol - > fcbs_ptrs [ hash > > 24 ] ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
while ( le ! = & subvol - > fcbs ) {
fcb = CONTAINING_RECORD ( le , struct _fcb , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > inode = = inode ) {
if ( ! fcb - > ads ) {
2017-09-08 08:02:43 +00:00
if ( fcb - > deleted )
deleted_fcb = fcb ;
else {
2016-05-05 17:26:47 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2017-09-08 08:02:43 +00:00
LONG rc = InterlockedIncrement ( & fcb - > refcount ) ;
2017-01-01 17:12:12 +00:00
2019-09-01 12:53:20 +00:00
WARN ( " fcb %p: refcount now %i (subvol %I64x, inode %I64x) \n " , fcb , rc , fcb - > subvol - > id , fcb - > inode ) ;
2016-05-05 17:26:47 +00:00
# else
2017-09-08 08:02:43 +00:00
InterlockedIncrement ( & fcb - > refcount ) ;
2016-05-05 17:26:47 +00:00
# endif
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
* pfcb = fcb ;
2019-05-11 09:20:02 +00:00
release_fcb_lock ( Vcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
}
2017-01-01 17:12:12 +00:00
}
2019-05-11 09:20:02 +00:00
} else if ( fcb - > hash > hash ) {
2017-09-08 08:02:43 +00:00
if ( deleted_fcb ) {
InterlockedIncrement ( & deleted_fcb - > refcount ) ;
* pfcb = deleted_fcb ;
2019-05-11 09:20:02 +00:00
release_fcb_lock ( Vcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
}
2017-01-01 17:12:12 +00:00
lastle = le - > Blink ;
2019-05-11 09:20:02 +00:00
fcbs_version = subvol - > fcbs_version ;
2017-01-01 17:12:12 +00:00
break ;
2016-05-05 17:26:47 +00:00
}
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
2019-05-11 09:20:02 +00:00
release_fcb_lock ( Vcb ) ;
2017-09-08 08:02:43 +00:00
if ( deleted_fcb ) {
InterlockedIncrement ( & deleted_fcb - > refcount ) ;
* pfcb = deleted_fcb ;
return STATUS_SUCCESS ;
}
fcb = create_fcb ( Vcb , pooltype ) ;
2016-05-05 17:26:47 +00:00
if ( ! fcb ) {
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
fcb - > Vcb = Vcb ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
fcb - > subvol = subvol ;
fcb - > inode = inode ;
2019-05-11 09:20:02 +00:00
fcb - > hash = hash ;
2016-05-05 17:26:47 +00:00
fcb - > type = type ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
searchkey . obj_id = inode ;
searchkey . obj_type = TYPE_INODE_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , subvol , & tp , & searchkey , false , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
2019-09-01 12:53:20 +00:00
WARN ( " couldn't find INODE_ITEM for inode %I64x in subvol %I64x \n " , inode , subvol - > id ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INVALID_PARAMETER ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( tp . item - > size > 0 )
RtlCopyMemory ( & fcb - > inode_item , tp . item - > data , min ( sizeof ( INODE_ITEM ) , tp . item - > size ) ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > type = = 0 ) { // guess the type from the inode mode, if the caller doesn't know already
2017-09-08 08:02:43 +00:00
if ( ( fcb - > inode_item . st_mode & __S_IFDIR ) = = __S_IFDIR )
2016-07-27 19:24:26 +00:00
fcb - > type = BTRFS_TYPE_DIRECTORY ;
2017-09-08 08:02:43 +00:00
else if ( ( fcb - > inode_item . st_mode & __S_IFCHR ) = = __S_IFCHR )
2016-07-27 19:24:26 +00:00
fcb - > type = BTRFS_TYPE_CHARDEV ;
2017-09-08 08:02:43 +00:00
else if ( ( fcb - > inode_item . st_mode & __S_IFBLK ) = = __S_IFBLK )
2016-07-27 19:24:26 +00:00
fcb - > type = BTRFS_TYPE_BLOCKDEV ;
2017-09-08 08:02:43 +00:00
else if ( ( fcb - > inode_item . st_mode & __S_IFIFO ) = = __S_IFIFO )
2017-01-01 17:12:12 +00:00
fcb - > type = BTRFS_TYPE_FIFO ;
2017-09-08 08:02:43 +00:00
else if ( ( fcb - > inode_item . st_mode & __S_IFLNK ) = = __S_IFLNK )
2017-01-01 17:12:12 +00:00
fcb - > type = BTRFS_TYPE_SYMLINK ;
2017-09-08 08:02:43 +00:00
else if ( ( fcb - > inode_item . st_mode & __S_IFSOCK ) = = __S_IFSOCK )
2017-01-01 17:12:12 +00:00
fcb - > type = BTRFS_TYPE_SOCKET ;
else
fcb - > type = BTRFS_TYPE_FILE ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
no_data = fcb - > inode_item . st_size = = 0 | | ( fcb - > type ! = BTRFS_TYPE_FILE & & fcb - > type ! = BTRFS_TYPE_SYMLINK ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
while ( find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ) {
2017-01-01 17:12:12 +00:00
tp = next_tp ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( tp . item - > key . obj_id > inode )
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ( no_data & & tp . item - > key . obj_type > TYPE_XATTR_ITEM ) | | tp . item - > key . obj_type > TYPE_EXTENT_DATA )
break ;
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
if ( ( always_add_hl | | fcb - > inode_item . st_nlink > 1 ) & & tp . item - > key . obj_type = = TYPE_INODE_REF ) {
2017-01-01 17:12:12 +00:00
ULONG len ;
INODE_REF * ir ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
len = tp . item - > size ;
ir = ( INODE_REF * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( len > = sizeof ( INODE_REF ) - 1 ) {
hardlink * hl ;
ULONG stringlen ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl = ExAllocatePoolWithTag ( pooltype , sizeof ( hardlink ) , ALLOC_TAG ) ;
if ( ! hl ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl - > parent = tp . item - > key . offset ;
hl - > index = ir - > index ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl - > utf8 . Length = hl - > utf8 . MaximumLength = ir - > n ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( hl - > utf8 . Length > 0 ) {
hl - > utf8 . Buffer = ExAllocatePoolWithTag ( pooltype , hl - > utf8 . MaximumLength , ALLOC_TAG ) ;
RtlCopyMemory ( hl - > utf8 . Buffer , ir - > name , ir - > n ) ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & stringlen , ir - > name , ir - > n ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( hl ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
hl - > name . Length = hl - > name . MaximumLength = ( uint16_t ) stringlen ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( stringlen = = 0 )
hl - > name . Buffer = NULL ;
else {
hl - > name . Buffer = ExAllocatePoolWithTag ( pooltype , hl - > name . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! hl - > name . Buffer ) {
2016-07-27 19:24:26 +00:00
ERR ( " out of memory \n " ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( hl ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( hl - > name . Buffer , stringlen , & stringlen , ir - > name , ir - > n ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( hl - > name . Buffer ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( hl ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-07-27 19:24:26 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertTailList ( & fcb - > hardlinks , & hl - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
len - = sizeof ( INODE_REF ) - 1 + ir - > n ;
ir = ( INODE_REF * ) & ir - > name [ ir - > n ] ;
}
2019-06-11 10:35:19 +00:00
} else if ( ( always_add_hl | | fcb - > inode_item . st_nlink > 1 ) & & tp . item - > key . obj_type = = TYPE_INODE_EXTREF ) {
2017-01-01 17:12:12 +00:00
ULONG len ;
INODE_EXTREF * ier ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
len = tp . item - > size ;
ier = ( INODE_EXTREF * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( len > = sizeof ( INODE_EXTREF ) - 1 ) {
hardlink * hl ;
ULONG stringlen ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl = ExAllocatePoolWithTag ( pooltype , sizeof ( hardlink ) , ALLOC_TAG ) ;
if ( ! hl ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl - > parent = ier - > dir ;
hl - > index = ier - > index ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl - > utf8 . Length = hl - > utf8 . MaximumLength = ier - > n ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( hl - > utf8 . Length > 0 ) {
hl - > utf8 . Buffer = ExAllocatePoolWithTag ( pooltype , hl - > utf8 . MaximumLength , ALLOC_TAG ) ;
RtlCopyMemory ( hl - > utf8 . Buffer , ier - > name , ier - > n ) ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & stringlen , ier - > name , ier - > n ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( hl ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
hl - > name . Length = hl - > name . MaximumLength = ( uint16_t ) stringlen ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( stringlen = = 0 )
hl - > name . Buffer = NULL ;
else {
hl - > name . Buffer = ExAllocatePoolWithTag ( pooltype , hl - > name . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! hl - > name . Buffer ) {
2016-07-27 19:24:26 +00:00
ERR ( " out of memory \n " ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( hl ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( hl - > name . Buffer , stringlen , & stringlen , ier - > name , ier - > n ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExFreePool ( hl - > name . Buffer ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( hl ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-07-27 19:24:26 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertTailList ( & fcb - > hardlinks , & hl - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
len - = sizeof ( INODE_EXTREF ) - 1 + ier - > n ;
ier = ( INODE_EXTREF * ) & ier - > name [ ier - > n ] ;
}
} else if ( tp . item - > key . obj_type = = TYPE_XATTR_ITEM ) {
2017-09-08 08:02:43 +00:00
ULONG len ;
DIR_ITEM * di ;
2018-12-16 11:03:16 +00:00
static const char xapref [ ] = " user. " ;
2017-09-08 08:02:43 +00:00
if ( tp . item - > size < offsetof ( DIR_ITEM , name [ 0 ] ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , offsetof ( DIR_ITEM , name [ 0 ] ) ) ;
2017-01-01 17:12:12 +00:00
continue ;
}
2017-09-08 08:02:43 +00:00
len = tp . item - > size ;
di = ( DIR_ITEM * ) tp . item - > data ;
do {
if ( len < offsetof ( DIR_ITEM , name [ 0 ] ) + di - > m + di - > n )
break ;
2018-12-16 11:03:16 +00:00
if ( tp . item - > key . offset = = EA_REPARSE_HASH & & di - > n = = sizeof ( EA_REPARSE ) - 1 & & RtlCompareMemory ( EA_REPARSE , di - > name , di - > n ) = = di - > n ) {
2017-09-08 08:02:43 +00:00
if ( di - > m > 0 ) {
fcb - > reparse_xattr . Buffer = ExAllocatePoolWithTag ( PagedPool , di - > m , ALLOC_TAG ) ;
if ( ! fcb - > reparse_xattr . Buffer ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( fcb - > reparse_xattr . Buffer , & di - > name [ di - > n ] , di - > m ) ;
} else
fcb - > reparse_xattr . Buffer = NULL ;
fcb - > reparse_xattr . Length = fcb - > reparse_xattr . MaximumLength = di - > m ;
2018-12-16 11:03:16 +00:00
} else if ( tp . item - > key . offset = = EA_EA_HASH & & di - > n = = sizeof ( EA_EA ) - 1 & & RtlCompareMemory ( EA_EA , di - > name , di - > n ) = = di - > n ) {
2017-09-08 08:02:43 +00:00
if ( di - > m > 0 ) {
ULONG offset ;
Status = IoCheckEaBufferValidity ( ( FILE_FULL_EA_INFORMATION * ) & di - > name [ di - > n ] , di - > m , & offset ) ;
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " IoCheckEaBufferValidity returned %08lx (error at offset %lu) \n " , Status , offset ) ;
2017-09-08 08:02:43 +00:00
else {
FILE_FULL_EA_INFORMATION * eainfo ;
fcb - > ea_xattr . Buffer = ExAllocatePoolWithTag ( PagedPool , di - > m , ALLOC_TAG ) ;
if ( ! fcb - > ea_xattr . Buffer ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( fcb - > ea_xattr . Buffer , & di - > name [ di - > n ] , di - > m ) ;
fcb - > ea_xattr . Length = fcb - > ea_xattr . MaximumLength = di - > m ;
fcb - > ealen = 4 ;
// calculate ealen
eainfo = ( FILE_FULL_EA_INFORMATION * ) & di - > name [ di - > n ] ;
do {
fcb - > ealen + = 5 + eainfo - > EaNameLength + eainfo - > EaValueLength ;
if ( eainfo - > NextEntryOffset = = 0 )
break ;
2019-09-01 12:53:20 +00:00
eainfo = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) eainfo ) + eainfo - > NextEntryOffset ) ;
} while ( true ) ;
2017-09-08 08:02:43 +00:00
}
}
2018-12-16 11:03:16 +00:00
} else if ( tp . item - > key . offset = = EA_DOSATTRIB_HASH & & di - > n = = sizeof ( EA_DOSATTRIB ) - 1 & & RtlCompareMemory ( EA_DOSATTRIB , di - > name , di - > n ) = = di - > n ) {
2017-09-08 08:02:43 +00:00
if ( di - > m > 0 ) {
if ( get_file_attributes_from_xattr ( & di - > name [ di - > n ] , di - > m , & fcb - > atts ) ) {
2019-09-01 12:53:20 +00:00
atts_set = true ;
2017-09-08 08:02:43 +00:00
if ( fcb - > type = = BTRFS_TYPE_DIRECTORY )
fcb - > atts | = FILE_ATTRIBUTE_DIRECTORY ;
else if ( fcb - > type = = BTRFS_TYPE_SYMLINK )
fcb - > atts | = FILE_ATTRIBUTE_REPARSE_POINT ;
if ( fcb - > type ! = BTRFS_TYPE_DIRECTORY )
fcb - > atts & = ~ FILE_ATTRIBUTE_DIRECTORY ;
if ( inode = = SUBVOL_ROOT_INODE ) {
if ( subvol - > root_item . flags & BTRFS_SUBVOL_READONLY )
fcb - > atts | = FILE_ATTRIBUTE_READONLY ;
else
fcb - > atts & = ~ FILE_ATTRIBUTE_READONLY ;
}
}
}
2018-12-16 11:03:16 +00:00
} else if ( tp . item - > key . offset = = EA_NTACL_HASH & & di - > n = = sizeof ( EA_NTACL ) - 1 & & RtlCompareMemory ( EA_NTACL , di - > name , di - > n ) = = di - > n ) {
2017-09-08 08:02:43 +00:00
if ( di - > m > 0 ) {
fcb - > sd = ExAllocatePoolWithTag ( PagedPool , di - > m , ALLOC_TAG ) ;
if ( ! fcb - > sd ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( fcb - > sd , & di - > name [ di - > n ] , di - > m ) ;
// We have to test against our copy rather than the source, as RtlValidRelativeSecurityDescriptor
// will fail if the ACLs aren't 32-bit aligned.
if ( ! RtlValidRelativeSecurityDescriptor ( fcb - > sd , di - > m , 0 ) )
ExFreePool ( fcb - > sd ) ;
else
2019-09-01 12:53:20 +00:00
sd_set = true ;
2017-09-08 08:02:43 +00:00
}
2018-12-16 11:03:16 +00:00
} else if ( tp . item - > key . offset = = EA_PROP_COMPRESSION_HASH & & di - > n = = sizeof ( EA_PROP_COMPRESSION ) - 1 & & RtlCompareMemory ( EA_PROP_COMPRESSION , di - > name , di - > n ) = = di - > n ) {
2017-09-08 08:02:43 +00:00
if ( di - > m > 0 ) {
2018-12-16 11:03:16 +00:00
static const char lzo [ ] = " lzo " ;
static const char zlib [ ] = " zlib " ;
static const char zstd [ ] = " zstd " ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
if ( di - > m = = sizeof ( lzo ) - 1 & & RtlCompareMemory ( & di - > name [ di - > n ] , lzo , di - > m ) = = di - > m )
2017-09-08 08:02:43 +00:00
fcb - > prop_compression = PropCompression_LZO ;
2018-12-16 11:03:16 +00:00
else if ( di - > m = = sizeof ( zlib ) - 1 & & RtlCompareMemory ( & di - > name [ di - > n ] , zlib , di - > m ) = = di - > m )
2017-09-08 08:02:43 +00:00
fcb - > prop_compression = PropCompression_Zlib ;
2018-12-16 11:03:16 +00:00
else if ( di - > m = = sizeof ( zstd ) - 1 & & RtlCompareMemory ( & di - > name [ di - > n ] , zstd , di - > m ) = = di - > m )
fcb - > prop_compression = PropCompression_ZSTD ;
2017-09-08 08:02:43 +00:00
else
fcb - > prop_compression = PropCompression_None ;
}
2019-06-11 10:35:19 +00:00
} else if ( tp . item - > key . offset = = EA_CASE_SENSITIVE_HASH & & di - > n = = sizeof ( EA_CASE_SENSITIVE ) - 1 & & RtlCompareMemory ( EA_CASE_SENSITIVE , di - > name , di - > n ) = = di - > n ) {
if ( di - > m > 0 ) {
fcb - > case_sensitive = di - > m = = 1 & & di - > name [ di - > n ] = = ' 1 ' ;
2019-09-01 12:53:20 +00:00
fcb - > case_sensitive_set = true ;
2019-06-11 10:35:19 +00:00
}
2018-12-16 11:03:16 +00:00
} else if ( di - > n > sizeof ( xapref ) - 1 & & RtlCompareMemory ( xapref , di - > name , sizeof ( xapref ) - 1 ) = = sizeof ( xapref ) - 1 ) {
2017-09-08 08:02:43 +00:00
dir_child * dc ;
ULONG utf16len ;
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & utf16len , & di - > name [ sizeof ( xapref ) - 1 ] , di - > n + 1 - sizeof ( xapref ) ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
dc = ExAllocatePoolWithTag ( PagedPool , sizeof ( dir_child ) , ALLOC_TAG ) ;
if ( ! dc ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( dc , sizeof ( dir_child ) ) ;
2018-12-16 11:03:16 +00:00
dc - > utf8 . MaximumLength = dc - > utf8 . Length = di - > n + 1 - sizeof ( xapref ) ;
2017-09-08 08:02:43 +00:00
dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , dc - > utf8 . MaximumLength , ALLOC_TAG ) ;
if ( ! dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2018-12-16 11:03:16 +00:00
RtlCopyMemory ( dc - > utf8 . Buffer , & di - > name [ sizeof ( xapref ) - 1 ] , dc - > utf8 . Length ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
dc - > name . MaximumLength = dc - > name . Length = ( uint16_t ) utf16len ;
2017-09-08 08:02:43 +00:00
dc - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , dc - > name . MaximumLength , ALLOC_TAG ) ;
if ( ! dc - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( dc - > name . Buffer , utf16len , & utf16len , dc - > utf8 . Buffer , dc - > utf8 . Length ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & dc - > name_uc , & dc - > name , true ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
dc - > size = di - > m ;
InsertTailList ( & fcb - > dir_children_index , & dc - > list_entry_index ) ;
} else {
xattr * xa ;
xa = ExAllocatePoolWithTag ( PagedPool , offsetof ( xattr , data [ 0 ] ) + di - > m + di - > n , ALLOC_TAG ) ;
if ( ! xa ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
xa - > namelen = di - > n ;
xa - > valuelen = di - > m ;
2019-09-01 12:53:20 +00:00
xa - > dirty = false ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( xa - > data , di - > name , di - > m + di - > n ) ;
InsertTailList ( & fcb - > xattrs , & xa - > list_entry ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
len - = ( ULONG ) offsetof ( DIR_ITEM , name [ 0 ] ) + di - > m + di - > n ;
if ( len < offsetof ( DIR_ITEM , name [ 0 ] ) )
break ;
di = ( DIR_ITEM * ) & di - > name [ di - > m + di - > n ] ;
2019-09-01 12:53:20 +00:00
} while ( true ) ;
2017-01-01 17:12:12 +00:00
} else if ( tp . item - > key . obj_type = = TYPE_EXTENT_DATA ) {
extent * ext ;
2019-09-01 12:53:20 +00:00
bool unique = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ed = ( EXTENT_DATA * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( tp . item - > size < sizeof ( EXTENT_DATA ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ,
2017-01-01 17:12:12 +00:00
tp . item - > size , sizeof ( EXTENT_DATA ) ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ed - > type = = EXTENT_TYPE_REGULAR | | ed - > type = = EXTENT_TYPE_PREALLOC ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) & ed - > data [ 0 ] ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( tp . item - > size < sizeof ( EXTENT_DATA ) - 1 + sizeof ( EXTENT_DATA2 ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ,
2017-01-01 17:12:12 +00:00
tp . item - > size , sizeof ( EXTENT_DATA ) - 1 + sizeof ( EXTENT_DATA2 ) ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INTERNAL_ERROR ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( ed2 - > address = = 0 | | ed2 - > size = = 0 ) // sparse
2017-01-01 17:12:12 +00:00
continue ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ed2 - > size ! = 0 & & is_tree_unique ( Vcb , tp . tree , Irp ) )
unique = is_extent_unique ( Vcb , ed2 - > address , ed2 - > size , Irp ) ;
}
2017-09-08 08:02:43 +00:00
ext = ExAllocatePoolWithTag ( pooltype , offsetof ( extent , extent_data ) + tp . item - > size , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! ext ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ext - > offset = tp . item - > key . offset ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( & ext - > extent_data , tp . item - > data , tp . item - > size ) ;
2017-01-01 17:12:12 +00:00
ext - > datalen = tp . item - > size ;
ext - > unique = unique ;
2019-09-01 12:53:20 +00:00
ext - > ignore = false ;
ext - > inserted = false ;
2017-09-08 08:02:43 +00:00
ext - > csum = NULL ;
2017-01-01 17:12:12 +00:00
InsertTailList ( & fcb - > extents , & ext - > list_entry ) ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
2019-09-01 12:53:20 +00:00
Status = load_dir_children ( Vcb , fcb , false , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_dir_children returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return Status ;
2016-07-27 19:24:26 +00:00
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( no_data ) {
fcb - > Header . AllocationSize . QuadPart = 0 ;
fcb - > Header . FileSize . QuadPart = 0 ;
fcb - > Header . ValidDataLength . QuadPart = 0 ;
} else {
if ( ed & & ed - > type = = EXTENT_TYPE_INLINE )
fcb - > Header . AllocationSize . QuadPart = fcb - > inode_item . st_size ;
else
fcb - > Header . AllocationSize . QuadPart = sector_align ( fcb - > inode_item . st_size , fcb - > Vcb - > superblock . sector_size ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fcb - > Header . FileSize . QuadPart = fcb - > inode_item . st_size ;
fcb - > Header . ValidDataLength . QuadPart = fcb - > inode_item . st_size ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! atts_set )
2019-09-01 12:53:20 +00:00
fcb - > atts = get_file_attributes ( Vcb , fcb - > subvol , fcb - > inode , fcb - > type , utf8 & & utf8 - > Buffer [ 0 ] = = ' . ' , true , Irp ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! sd_set )
2019-09-01 12:53:20 +00:00
fcb_get_sd ( fcb , parent , false , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
acquire_fcb_lock_exclusive ( Vcb ) ;
2019-09-01 12:53:20 +00:00
if ( lastle & & subvol - > fcbs_version = = fcbs_version ) {
2019-05-11 09:20:02 +00:00
InsertHeadList ( lastle , & fcb - > list_entry ) ;
2019-09-01 12:53:20 +00:00
if ( ! subvol - > fcbs_ptrs [ hash > > 24 ] | | CONTAINING_RECORD ( subvol - > fcbs_ptrs [ hash > > 24 ] , struct _fcb , list_entry ) - > hash > hash )
subvol - > fcbs_ptrs [ hash > > 24 ] = & fcb - > list_entry ;
} else {
lastle = NULL ;
2019-05-11 09:20:02 +00:00
if ( subvol - > fcbs_ptrs [ hash > > 24 ] ) {
LIST_ENTRY * le = subvol - > fcbs_ptrs [ hash > > 24 ] ;
while ( le ! = & subvol - > fcbs ) {
struct _fcb * fcb2 = CONTAINING_RECORD ( le , struct _fcb , list_entry ) ;
if ( fcb2 - > inode = = inode ) {
if ( ! fcb2 - > ads ) {
if ( fcb2 - > deleted )
deleted_fcb = fcb2 ;
else {
# ifdef DEBUG_FCB_REFCOUNTS
LONG rc = InterlockedIncrement ( & fcb2 - > refcount ) ;
2019-09-01 12:53:20 +00:00
WARN ( " fcb %p: refcount now %i (subvol %I64x, inode %I64x) \n " , fcb2 , rc , fcb2 - > subvol - > id , fcb2 - > inode ) ;
2019-05-11 09:20:02 +00:00
# else
InterlockedIncrement ( & fcb2 - > refcount ) ;
# endif
* pfcb = fcb2 ;
reap_fcb ( fcb ) ;
2019-06-11 10:35:19 +00:00
release_fcb_lock ( Vcb ) ;
2019-05-11 09:20:02 +00:00
return STATUS_SUCCESS ;
}
}
} else if ( fcb2 - > hash > hash ) {
if ( deleted_fcb ) {
InterlockedIncrement ( & deleted_fcb - > refcount ) ;
* pfcb = deleted_fcb ;
reap_fcb ( fcb ) ;
2019-06-11 10:35:19 +00:00
release_fcb_lock ( Vcb ) ;
2019-05-11 09:20:02 +00:00
return STATUS_SUCCESS ;
}
lastle = le - > Blink ;
break ;
}
le = le - > Flink ;
}
}
if ( fcb - > type = = BTRFS_TYPE_DIRECTORY & & fcb - > atts & FILE_ATTRIBUTE_REPARSE_POINT & & fcb - > reparse_xattr . Length = = 0 ) {
fcb - > atts & = ~ FILE_ATTRIBUTE_REPARSE_POINT ;
if ( ! Vcb - > readonly & & ! is_subvol_readonly ( subvol , Irp ) ) {
2019-09-01 12:53:20 +00:00
fcb - > atts_changed = true ;
2019-05-11 09:20:02 +00:00
mark_fcb_dirty ( fcb ) ;
}
}
if ( ! lastle ) {
2019-09-01 12:53:20 +00:00
uint8_t c = hash > > 24 ;
2019-05-11 09:20:02 +00:00
if ( c ! = 0xff ) {
2019-09-01 12:53:20 +00:00
uint8_t d = c + 1 ;
2019-05-11 09:20:02 +00:00
do {
if ( subvol - > fcbs_ptrs [ d ] ) {
lastle = subvol - > fcbs_ptrs [ d ] - > Blink ;
break ;
}
d + + ;
} while ( d ! = 0 ) ;
}
}
if ( lastle ) {
InsertHeadList ( lastle , & fcb - > list_entry ) ;
if ( lastle = = & subvol - > fcbs | | ( CONTAINING_RECORD ( lastle , struct _fcb , list_entry ) - > hash > > 24 ) ! = ( hash > > 24 ) )
subvol - > fcbs_ptrs [ hash > > 24 ] = & fcb - > list_entry ;
} else {
InsertTailList ( & subvol - > fcbs , & fcb - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( fcb - > list_entry . Blink = = & subvol - > fcbs | | ( CONTAINING_RECORD ( fcb - > list_entry . Blink , struct _fcb , list_entry ) - > hash > > 24 ) ! = ( hash > > 24 ) )
subvol - > fcbs_ptrs [ hash > > 24 ] = & fcb - > list_entry ;
2016-05-05 17:26:47 +00:00
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE & & fcb - > subvol - > id = = BTRFS_ROOT_FSTREE & & fcb - > subvol ! = Vcb - > root_fileref - > fcb - > subvol )
2019-11-12 18:32:46 +00:00
fcb - > atts | = FILE_ATTRIBUTE_HIDDEN ;
2019-05-11 09:20:02 +00:00
subvol - > fcbs_version + + ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertTailList ( & Vcb - > all_fcbs , & fcb - > list_entry_all ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
release_fcb_lock ( Vcb ) ;
2017-01-01 17:12:12 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
2016-07-27 19:24:26 +00:00
2016-05-05 17:26:47 +00:00
* pfcb = fcb ;
2019-05-11 09:20:02 +00:00
2016-05-05 17:26:47 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS open_fcb_stream ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) device_extension * Vcb ,
dir_child * dc , fcb * parent , fcb * * pfcb , PIRP Irp ) {
2016-05-05 17:26:47 +00:00
fcb * fcb ;
2019-09-01 12:53:20 +00:00
uint8_t * xattrdata ;
uint16_t xattrlen , overhead ;
2016-09-04 15:27:46 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2018-12-16 11:03:16 +00:00
static const char xapref [ ] = " user. " ;
2017-09-08 08:02:43 +00:00
ANSI_STRING xattr ;
2019-09-01 12:53:20 +00:00
uint32_t crc32 ;
2016-05-05 17:26:47 +00:00
2018-12-16 11:03:16 +00:00
xattr . Length = sizeof ( xapref ) - 1 + dc - > utf8 . Length ;
2017-09-08 08:02:43 +00:00
xattr . MaximumLength = xattr . Length + 1 ;
xattr . Buffer = ExAllocatePoolWithTag ( PagedPool , xattr . MaximumLength , ALLOC_TAG ) ;
if ( ! xattr . Buffer ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
RtlCopyMemory ( xattr . Buffer , xapref , sizeof ( xapref ) - 1 ) ;
RtlCopyMemory ( & xattr . Buffer [ sizeof ( xapref ) - 1 ] , dc - > utf8 . Buffer , dc - > utf8 . Length ) ;
2017-09-08 08:02:43 +00:00
xattr . Buffer [ xattr . Length ] = 0 ;
fcb = create_fcb ( Vcb , PagedPool ) ;
2016-05-05 17:26:47 +00:00
if ( ! fcb ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( xattr . Buffer ) ;
2016-05-05 17:26:47 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
fcb - > Vcb = Vcb ;
2019-09-01 12:53:20 +00:00
crc32 = calc_crc32c ( 0xfffffffe , ( uint8_t * ) xattr . Buffer , xattr . Length ) ;
2017-09-08 08:02:43 +00:00
if ( ! get_xattr ( Vcb , parent - > subvol , parent - > inode , xattr . Buffer , crc32 , & xattrdata , & xattrlen , Irp ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " get_xattr failed \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( xattr . Buffer ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INTERNAL_ERROR ;
}
2016-05-05 17:26:47 +00:00
fcb - > subvol = parent - > subvol ;
fcb - > inode = parent - > inode ;
fcb - > type = parent - > type ;
2019-09-01 12:53:20 +00:00
fcb - > ads = true ;
2017-09-08 08:02:43 +00:00
fcb - > adshash = crc32 ;
fcb - > adsxattr = xattr ;
2016-09-04 15:27:46 +00:00
// find XATTR_ITEM overhead and hence calculate maximum length
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
searchkey . obj_id = parent - > inode ;
searchkey . obj_type = TYPE_XATTR_ITEM ;
2017-09-08 08:02:43 +00:00
searchkey . offset = crc32 ;
2016-09-04 15:27:46 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , parent - > subvol , & tp , & searchkey , false , Irp ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-09-04 15:27:46 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
2016-09-04 15:27:46 +00:00
ERR ( " error - could not find key for xattr \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-09-04 15:27:46 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( tp . item - > size < xattrlen ) {
2019-09-01 12:53:20 +00:00
ERR ( " (%I64x,%x,%I64x) 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 , xattrlen ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2016-09-04 15:27:46 +00:00
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
overhead = tp . item - > size - xattrlen ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
fcb - > adsmaxlen = Vcb - > superblock . node_size - sizeof ( tree_header ) - sizeof ( leaf_node ) - overhead ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > adsdata . Buffer = ( char * ) xattrdata ;
fcb - > adsdata . Length = fcb - > adsdata . MaximumLength = xattrlen ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
2016-07-27 19:24:26 +00:00
fcb - > Header . AllocationSize . QuadPart = xattrlen ;
fcb - > Header . FileSize . QuadPart = xattrlen ;
fcb - > Header . ValidDataLength . QuadPart = xattrlen ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " stream found: size = %x, hash = %08x \n " , xattrlen , fcb - > adshash ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
* pfcb = fcb ;
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
NTSTATUS open_fileref_child ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) _In_ device_extension * Vcb ,
2019-09-01 12:53:20 +00:00
_In_ file_ref * sf , _In_ PUNICODE_STRING name , _In_ bool case_sensitive , _In_ bool lastpart , _In_ bool streampart ,
2017-09-08 08:02:43 +00:00
_In_ POOL_TYPE pooltype , _Out_ file_ref * * psf2 , _In_opt_ PIRP Irp ) {
2017-01-01 17:12:12 +00:00
NTSTATUS Status ;
file_ref * sf2 ;
2017-09-08 08:02:43 +00:00
if ( sf - > fcb = = Vcb - > dummy_fcb )
return STATUS_OBJECT_NAME_NOT_FOUND ;
2017-01-01 17:12:12 +00:00
2017-09-08 08:02:43 +00:00
if ( streampart ) {
2019-09-01 12:53:20 +00:00
bool locked = false ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le ;
UNICODE_STRING name_uc ;
dir_child * dc = NULL ;
fcb * fcb ;
2019-05-11 09:20:02 +00:00
struct _fcb * duff_fcb = NULL ;
file_ref * duff_fr = NULL ;
2017-09-08 08:02:43 +00:00
if ( ! case_sensitive ) {
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & name_uc , name , true ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
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
2017-09-08 08:02:43 +00:00
if ( ! ExIsResourceAcquiredSharedLite ( & sf - > fcb - > nonpaged - > dir_children_lock ) ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & sf - > fcb - > nonpaged - > dir_children_lock , true ) ;
locked = true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
le = sf - > fcb - > dir_children_index . Flink ;
while ( le ! = & sf - > fcb - > dir_children_index ) {
dir_child * dc2 = CONTAINING_RECORD ( le , dir_child , list_entry_index ) ;
if ( dc2 - > index = = 0 ) {
if ( ( case_sensitive & & dc2 - > name . Length = = name - > Length & & RtlCompareMemory ( dc2 - > name . Buffer , name - > Buffer , dc2 - > name . Length ) = = dc2 - > name . Length ) | |
( ! case_sensitive & & dc2 - > name_uc . Length = = name_uc . Length & & RtlCompareMemory ( dc2 - > name_uc . Buffer , name_uc . Buffer , dc2 - > name_uc . Length ) = = dc2 - > name_uc . Length )
) {
dc = dc2 ;
break ;
}
} else
break ;
le = le - > Flink ;
}
2019-05-11 09:20:02 +00:00
if ( ! dc ) {
if ( locked )
ExReleaseResourceLite ( & sf - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! case_sensitive )
ExFreePool ( name_uc . Buffer ) ;
2017-09-08 08:02:43 +00:00
return STATUS_OBJECT_NAME_NOT_FOUND ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
if ( dc - > fileref ) {
2019-05-11 09:20:02 +00:00
if ( locked )
ExReleaseResourceLite ( & sf - > fcb - > nonpaged - > dir_children_lock ) ;
if ( ! case_sensitive )
ExFreePool ( name_uc . Buffer ) ;
2017-09-08 08:02:43 +00:00
increase_fileref_refcount ( dc - > fileref ) ;
* psf2 = dc - > fileref ;
return STATUS_SUCCESS ;
}
2019-05-11 09:20:02 +00:00
if ( locked )
ExReleaseResourceLite ( & sf - > fcb - > nonpaged - > dir_children_lock ) ;
if ( ! case_sensitive )
ExFreePool ( name_uc . Buffer ) ;
2017-09-08 08:02:43 +00:00
Status = open_fcb_stream ( Vcb , dc , sf - > fcb , & fcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fcb_stream returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2019-05-11 09:20:02 +00:00
fcb - > hash = sf - > fcb - > hash ;
acquire_fcb_lock_exclusive ( Vcb ) ;
if ( sf - > fcb - > subvol - > fcbs_ptrs [ fcb - > hash > > 24 ] ) {
2019-09-01 12:53:20 +00:00
le = sf - > fcb - > subvol - > fcbs_ptrs [ fcb - > hash > > 24 ] ;
2019-05-11 09:20:02 +00:00
while ( le ! = & sf - > fcb - > subvol - > fcbs ) {
struct _fcb * fcb2 = CONTAINING_RECORD ( le , struct _fcb , list_entry ) ;
if ( fcb2 - > inode = = fcb - > inode ) {
if ( fcb2 - > ads & & fcb2 - > adshash = = fcb - > adshash ) { // FIXME - handle hash collisions
duff_fcb = fcb ;
fcb = fcb2 ;
break ;
}
} else if ( fcb2 - > hash > fcb - > hash )
break ;
le = le - > Flink ;
}
}
if ( ! duff_fcb ) {
InsertHeadList ( & sf - > fcb - > list_entry , & fcb - > list_entry ) ;
InsertTailList ( & Vcb - > all_fcbs , & fcb - > list_entry_all ) ;
fcb - > subvol - > fcbs_version + + ;
}
release_fcb_lock ( Vcb ) ;
if ( duff_fcb ) {
reap_fcb ( duff_fcb ) ;
InterlockedIncrement ( & fcb - > refcount ) ;
}
2017-09-08 08:02:43 +00:00
sf2 = create_fileref ( Vcb ) ;
if ( ! sf2 ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & sf - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( dc - > fileref ) {
duff_fr = sf2 ;
sf2 = dc - > fileref ;
increase_fileref_refcount ( sf2 ) ;
} else {
sf2 - > fcb = fcb ;
sf2 - > parent = ( struct _file_ref * ) sf ;
sf2 - > dc = dc ;
dc - > fileref = sf2 ;
increase_fileref_refcount ( sf ) ;
InsertTailList ( & sf - > children , & sf2 - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & sf - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( duff_fr )
2022-04-28 19:34:48 +00:00
ExFreeToPagedLookasideList ( & Vcb - > fileref_lookaside , duff_fr ) ;
2017-01-01 17:12:12 +00:00
} else {
root * subvol ;
2019-09-01 12:53:20 +00:00
uint64_t inode ;
2017-01-01 17:12:12 +00:00
dir_child * dc ;
2017-09-08 08:02:43 +00:00
Status = find_file_in_dir ( name , sf - > fcb , & subvol , & inode , & dc , case_sensitive ) ;
2017-01-01 17:12:12 +00:00
if ( Status = = STATUS_OBJECT_NAME_NOT_FOUND ) {
2020-04-23 02:38:57 +00:00
TRACE ( " could not find %.*S \n " , ( int ) ( name - > Length / sizeof ( WCHAR ) ) , name - > Buffer ) ;
2017-01-01 17:12:12 +00:00
return lastpart ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_OBJECT_PATH_NOT_FOUND ;
2022-04-28 19:35:05 +00:00
} else if ( Status = = STATUS_OBJECT_NAME_INVALID ) {
TRACE ( " invalid filename: %.*S \n " , ( int ) ( name - > Length / sizeof ( WCHAR ) ) , name - > Buffer ) ;
return Status ;
2017-01-01 17:12:12 +00:00
} else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_file_in_dir returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
return Status ;
} else {
fcb * fcb ;
2019-05-11 09:20:02 +00:00
file_ref * duff_fr = NULL ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc - > fileref ) {
if ( ! lastpart & & dc - > type ! = BTRFS_TYPE_DIRECTORY ) {
2017-09-08 08:02:43 +00:00
TRACE ( " passed path including file as subdirectory \n " ) ;
2017-01-01 17:12:12 +00:00
return STATUS_OBJECT_PATH_NOT_FOUND ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InterlockedIncrement ( & dc - > fileref - > refcount ) ;
* psf2 = dc - > fileref ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( ! subvol | | ( subvol ! = Vcb - > root_fileref - > fcb - > subvol & & inode = = SUBVOL_ROOT_INODE & & subvol - > parent ! = sf - > fcb - > subvol - > id & & ! dc - > root_dir ) ) {
2017-09-08 08:02:43 +00:00
fcb = Vcb - > dummy_fcb ;
InterlockedIncrement ( & fcb - > refcount ) ;
} else {
2019-09-01 12:53:20 +00:00
Status = open_fcb ( Vcb , subvol , inode , dc - > type , & dc - > utf8 , false , sf - > fcb , & fcb , pooltype , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fcb returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc - > type ! = BTRFS_TYPE_DIRECTORY & & ! lastpart & & ! ( fcb - > atts & FILE_ATTRIBUTE_REPARSE_POINT ) ) {
2017-09-08 08:02:43 +00:00
TRACE ( " passed path including file as subdirectory \n " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_OBJECT_PATH_NOT_FOUND ;
}
2017-09-08 08:02:43 +00:00
sf2 = create_fileref ( Vcb ) ;
2017-01-01 17:12:12 +00:00
if ( ! sf2 ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
sf2 - > fcb = fcb ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & sf - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! dc - > fileref ) {
sf2 - > parent = ( struct _file_ref * ) sf ;
sf2 - > dc = dc ;
dc - > fileref = sf2 ;
InsertTailList ( & sf - > children , & sf2 - > list_entry ) ;
increase_fileref_refcount ( sf ) ;
2022-04-28 19:34:48 +00:00
if ( dc - > type = = BTRFS_TYPE_DIRECTORY )
fcb - > fileref = sf2 ;
2019-05-11 09:20:02 +00:00
} else {
duff_fr = sf2 ;
sf2 = dc - > fileref ;
increase_fileref_refcount ( sf2 ) ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & sf - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( duff_fr )
reap_fileref ( Vcb , duff_fr ) ;
2017-01-01 17:12:12 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* psf2 = sf2 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return STATUS_SUCCESS ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
NTSTATUS open_fileref ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) _In_ device_extension * Vcb , _Out_ file_ref * * pfr ,
2019-09-01 12:53:20 +00:00
_In_ PUNICODE_STRING fnus , _In_opt_ file_ref * related , _In_ bool parent , _Out_opt_ USHORT * parsed , _Out_opt_ ULONG * fn_offset , _In_ POOL_TYPE pooltype ,
_In_ bool case_sensitive , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
UNICODE_STRING fnus2 ;
2016-05-05 17:26:47 +00:00
file_ref * dir , * sf , * sf2 ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY parts ;
2022-04-28 19:33:48 +00:00
bool has_stream = false ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le ;
2017-01-01 17:12:12 +00:00
TRACE ( " (%p, %p, %p, %u, %p) \n " , Vcb , pfr , related , parent , parsed ) ;
2016-09-04 15:27:46 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > removing | | Vcb - > locked )
2016-05-05 17:26:47 +00:00
return STATUS_ACCESS_DENIED ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fnus2 = * fnus ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fnus2 . Length < sizeof ( WCHAR ) & & ! related ) {
2016-03-23 20:35:05 +00:00
ERR ( " error - fnus was too short \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( related & & fnus - > Length = = 0 ) {
2016-07-27 19:24:26 +00:00
increase_fileref_refcount ( related ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
* pfr = related ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( related ) {
dir = related ;
2016-03-23 20:35:05 +00:00
} else {
if ( fnus2 . Buffer [ 0 ] ! = ' \\ ' ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - filename %.*S did not begin with \\ \n " , ( int ) ( fnus2 . Length / sizeof ( WCHAR ) ) , fnus2 . Buffer ) ;
2016-03-23 20:35:05 +00:00
return STATUS_OBJECT_PATH_NOT_FOUND ;
}
2017-09-08 08:02:43 +00:00
2017-10-16 18:05:33 +00:00
// if path starts with two backslashes, ignore one of them
if ( fnus2 . Length > = 2 * sizeof ( WCHAR ) & & fnus2 . Buffer [ 1 ] = = ' \\ ' ) {
fnus2 . Buffer + + ;
fnus2 . Length - = sizeof ( WCHAR ) ;
fnus2 . MaximumLength - = sizeof ( WCHAR ) ;
}
2016-03-23 20:35:05 +00:00
if ( fnus2 . Length = = sizeof ( WCHAR ) ) {
2017-09-08 08:02:43 +00:00
if ( Vcb - > root_fileref - > open_count = = 0 & & ! ( Vcb - > Vpb - > Flags & VPB_MOUNTED ) ) // don't allow root to be opened on unmounted FS
return STATUS_DEVICE_NOT_READY ;
2016-07-27 19:24:26 +00:00
increase_fileref_refcount ( Vcb - > root_fileref ) ;
2016-05-05 17:26:47 +00:00
* pfr = Vcb - > root_fileref ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fn_offset )
* fn_offset = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
2019-05-11 09:20:02 +00:00
} else if ( fnus2 . Length > = 2 * sizeof ( WCHAR ) & & fnus2 . Buffer [ 1 ] = = ' \\ ' )
return STATUS_OBJECT_NAME_INVALID ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
dir = Vcb - > root_fileref ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fnus2 . Buffer + + ;
fnus2 . Length - = sizeof ( WCHAR ) ;
fnus2 . MaximumLength - = sizeof ( WCHAR ) ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( dir - > fcb - > type ! = BTRFS_TYPE_DIRECTORY & & ( fnus - > Length < sizeof ( WCHAR ) | | fnus - > Buffer [ 0 ] ! = ' : ' ) ) {
2019-11-12 18:32:46 +00:00
WARN ( " passed related fileref which isn't a directory (fnus = %.*S) \n " ,
2020-04-23 02:38:57 +00:00
( int ) ( fnus - > Length / sizeof ( WCHAR ) ) , fnus - > Buffer ) ;
2016-03-23 20:35:05 +00:00
return STATUS_OBJECT_PATH_NOT_FOUND ;
}
2017-09-08 08:02:43 +00:00
InitializeListHead ( & parts ) ;
if ( fnus - > Length ! = 0 & &
2018-12-16 11:03:16 +00:00
( fnus - > Length ! = sizeof ( datastring ) - sizeof ( WCHAR ) | | RtlCompareMemory ( fnus - > Buffer , datastring , sizeof ( datastring ) - sizeof ( WCHAR ) ) ! = sizeof ( datastring ) - sizeof ( WCHAR ) ) ) {
2017-09-08 08:02:43 +00:00
Status = split_path ( Vcb , & fnus2 , & parts , & has_stream ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " split_path returned %08lx \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
sf = dir ;
2016-07-27 19:24:26 +00:00
increase_fileref_refcount ( dir ) ;
2017-09-08 08:02:43 +00:00
if ( parent & & ! IsListEmpty ( & parts ) ) {
name_bit * nb ;
nb = CONTAINING_RECORD ( RemoveTailList ( & parts ) , name_bit , list_entry ) ;
2022-04-28 19:35:58 +00:00
ExFreeToPagedLookasideList ( & Vcb - > name_bit_lookaside , nb ) ;
2017-09-08 08:02:43 +00:00
if ( has_stream & & ! IsListEmpty ( & parts ) ) {
nb = CONTAINING_RECORD ( RemoveTailList ( & parts ) , name_bit , list_entry ) ;
2022-04-28 19:35:58 +00:00
ExFreeToPagedLookasideList ( & Vcb - > name_bit_lookaside , nb ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
has_stream = false ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
if ( IsListEmpty ( & parts ) ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
2016-05-05 17:26:47 +00:00
* pfr = dir ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fn_offset )
* fn_offset = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
goto end2 ;
}
2017-09-08 08:02:43 +00:00
le = parts . Flink ;
do {
name_bit * nb = CONTAINING_RECORD ( le , name_bit , list_entry ) ;
2019-09-01 12:53:20 +00:00
bool lastpart = le - > Flink = = & parts | | ( has_stream & & le - > Flink - > Flink = = & parts ) ;
bool streampart = has_stream & & le - > Flink = = & parts ;
bool cs = case_sensitive ;
2019-06-11 10:35:19 +00:00
if ( ! cs ) {
2019-11-12 18:32:46 +00:00
if ( streampart & & sf - > parent )
2019-06-11 10:35:19 +00:00
cs = sf - > parent - > fcb - > case_sensitive ;
else
cs = sf - > fcb - > case_sensitive ;
}
Status = open_fileref_child ( Vcb , sf , & nb - > us , cs , lastpart , streampart , pooltype , & sf2 , Irp ) ;
2019-09-01 12:53:20 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2022-04-28 19:35:05 +00:00
if ( Status = = STATUS_OBJECT_PATH_NOT_FOUND | | Status = = STATUS_OBJECT_NAME_NOT_FOUND | | Status = = STATUS_OBJECT_NAME_INVALID )
2020-04-23 02:38:57 +00:00
TRACE ( " open_fileref_child returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
else
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref_child returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
if ( le - > Flink = = & parts ) { // last entry
if ( fn_offset ) {
if ( has_stream )
nb = CONTAINING_RECORD ( le - > Blink , name_bit , list_entry ) ;
* fn_offset = ( ULONG ) ( nb - > us . Buffer - fnus - > Buffer ) ;
}
2016-03-23 20:35:05 +00:00
break ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( sf2 - > fcb - > atts & FILE_ATTRIBUTE_REPARSE_POINT ) {
Status = STATUS_REPARSE ;
2017-09-08 08:02:43 +00:00
if ( parsed ) {
name_bit * nb2 = CONTAINING_RECORD ( le - > Flink , name_bit , list_entry ) ;
* parsed = ( USHORT ) ( nb2 - > us . Buffer - fnus - > Buffer - 1 ) * sizeof ( WCHAR ) ;
}
2016-05-05 17:26:47 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_fileref ( sf ) ;
2016-03-23 20:35:05 +00:00
sf = sf2 ;
2017-09-08 08:02:43 +00:00
le = le - > Flink ;
} while ( le ! = & parts ) ;
2016-05-05 17:26:47 +00:00
if ( Status ! = STATUS_REPARSE )
Status = STATUS_SUCCESS ;
* pfr = sf2 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
end :
2019-05-11 09:20:02 +00:00
free_fileref ( sf ) ;
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & parts ) ) {
name_bit * nb = CONTAINING_RECORD ( RemoveHeadList ( & parts ) , name_bit , list_entry ) ;
ExFreeToPagedLookasideList ( & Vcb - > name_bit_lookaside , nb ) ;
}
2016-03-23 20:35:05 +00:00
end2 :
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS add_dir_child ( fcb * fcb , uint64_t inode , bool subvol , PANSI_STRING utf8 , PUNICODE_STRING name , uint8_t type , dir_child * * pdc ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2017-01-01 17:12:12 +00:00
dir_child * dc ;
2019-09-01 12:53:20 +00:00
bool locked ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dc = ExAllocatePoolWithTag ( PagedPool , sizeof ( dir_child ) , ALLOC_TAG ) ;
if ( ! dc ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:35:58 +00:00
RtlZeroMemory ( dc , sizeof ( dir_child ) ) ;
2017-01-01 17:12:12 +00:00
dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 - > Length , ALLOC_TAG ) ;
if ( ! dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dc - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , name - > Length , ALLOC_TAG ) ;
if ( ! dc - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dc - > key . obj_id = inode ;
dc - > key . obj_type = subvol ? TYPE_ROOT_ITEM : TYPE_INODE_ITEM ;
2017-09-08 08:02:43 +00:00
dc - > key . offset = subvol ? 0xffffffffffffffff : 0 ;
2017-01-01 17:12:12 +00:00
dc - > type = type ;
dc - > fileref = NULL ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dc - > utf8 . Length = dc - > utf8 . MaximumLength = utf8 - > Length ;
RtlCopyMemory ( dc - > utf8 . Buffer , utf8 - > Buffer , utf8 - > Length ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dc - > name . Length = dc - > name . MaximumLength = name - > Length ;
RtlCopyMemory ( dc - > name . Buffer , name - > Buffer , name - > Length ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & dc - > name_uc , name , true ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
dc - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name . Buffer , dc - > name . Length ) ;
dc - > hash_uc = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name_uc . Buffer , dc - > name_uc . Length ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
locked = ExIsResourceAcquiredExclusive ( & fcb - > nonpaged - > dir_children_lock ) ;
if ( ! locked )
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
if ( IsListEmpty ( & fcb - > dir_children_index ) )
dc - > index = 2 ;
else {
dir_child * dc2 = CONTAINING_RECORD ( fcb - > dir_children_index . Blink , dir_child , list_entry_index ) ;
dc - > index = max ( 2 , dc2 - > index + 1 ) ;
}
2017-01-01 17:12:12 +00:00
InsertTailList ( & fcb - > dir_children_index , & dc - > list_entry_index ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
insert_dir_child_into_hash_lists ( fcb , dc ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! locked )
ExReleaseResourceLite ( & fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* pdc = dc ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
uint32_t inherit_mode ( fcb * parfcb , bool is_dir ) {
uint32_t mode ;
2017-09-08 08:02:43 +00:00
if ( ! parfcb )
return 0755 ;
mode = parfcb - > inode_item . st_mode & ~ S_IFDIR ;
mode & = ~ S_ISVTX ; // clear sticky bit
mode & = ~ S_ISUID ; // clear setuid bit
if ( ! is_dir )
mode & = ~ S_ISGID ; // if not directory, clear setgid bit
return mode ;
}
2018-12-16 11:03:16 +00:00
static NTSTATUS file_create_parse_ea ( fcb * fcb , FILE_FULL_EA_INFORMATION * ea ) {
NTSTATUS Status ;
LIST_ENTRY ealist , * le ;
2019-09-01 12:53:20 +00:00
uint16_t size = 0 ;
2018-12-16 11:03:16 +00:00
char * buf ;
InitializeListHead ( & ealist ) ;
do {
STRING s ;
2019-09-01 12:53:20 +00:00
bool found = false ;
2018-12-16 11:03:16 +00:00
s . Length = s . MaximumLength = ea - > EaNameLength ;
s . Buffer = ea - > EaName ;
RtlUpperString ( & s , & s ) ;
le = ealist . Flink ;
while ( le ! = & ealist ) {
ea_item * item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
if ( item - > name . Length = = s . Length & & RtlCompareMemory ( item - > name . Buffer , s . Buffer , s . Length ) = = s . Length ) {
item - > flags = ea - > Flags ;
item - > value . Length = item - > value . MaximumLength = ea - > EaValueLength ;
item - > value . Buffer = & ea - > EaName [ ea - > EaNameLength + 1 ] ;
2019-09-01 12:53:20 +00:00
found = true ;
2018-12-16 11:03:16 +00:00
break ;
}
le = le - > Flink ;
}
if ( ! found ) {
ea_item * item = ExAllocatePoolWithTag ( PagedPool , sizeof ( ea_item ) , ALLOC_TAG ) ;
if ( ! item ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
item - > name . Length = item - > name . MaximumLength = ea - > EaNameLength ;
item - > name . Buffer = ea - > EaName ;
item - > value . Length = item - > value . MaximumLength = ea - > EaValueLength ;
item - > value . Buffer = & ea - > EaName [ ea - > EaNameLength + 1 ] ;
item - > flags = ea - > Flags ;
InsertTailList ( & ealist , & item - > list_entry ) ;
}
if ( ea - > NextEntryOffset = = 0 )
break ;
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ea ) + ea - > NextEntryOffset ) ;
} while ( true ) ;
2018-12-16 11:03:16 +00:00
// handle LXSS values
le = ealist . Flink ;
while ( le ! = & ealist ) {
LIST_ENTRY * le2 = le - > Flink ;
ea_item * item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
if ( item - > name . Length = = sizeof ( lxuid ) - 1 & & RtlCompareMemory ( item - > name . Buffer , lxuid , item - > name . Length ) = = item - > name . Length ) {
2019-09-01 12:53:20 +00:00
if ( item - > value . Length < sizeof ( uint32_t ) ) {
2018-12-16 11:03:16 +00:00
ERR ( " uid value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & fcb - > inode_item . st_uid , item - > value . Buffer , sizeof ( uint32_t ) ) ;
fcb - > sd_dirty = true ;
fcb - > sd_deleted = false ;
2018-12-16 11:03:16 +00:00
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
} else if ( item - > name . Length = = sizeof ( lxgid ) - 1 & & RtlCompareMemory ( item - > name . Buffer , lxgid , item - > name . Length ) = = item - > name . Length ) {
2019-09-01 12:53:20 +00:00
if ( item - > value . Length < sizeof ( uint32_t ) ) {
2018-12-16 11:03:16 +00:00
ERR ( " gid value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & fcb - > inode_item . st_gid , item - > value . Buffer , sizeof ( uint32_t ) ) ;
2018-12-16 11:03:16 +00:00
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
} else if ( item - > name . Length = = sizeof ( lxmod ) - 1 & & RtlCompareMemory ( item - > name . Buffer , lxmod , item - > name . Length ) = = item - > name . Length ) {
2019-09-01 12:53:20 +00:00
uint32_t allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID ;
uint32_t val ;
2018-12-16 11:03:16 +00:00
2019-09-01 12:53:20 +00:00
if ( item - > value . Length < sizeof ( uint32_t ) ) {
2018-12-16 11:03:16 +00:00
ERR ( " mode value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2022-04-28 19:31:44 +00:00
val = * ( uint32_t * ) item - > value . Buffer ;
2018-12-16 11:03:16 +00:00
fcb - > inode_item . st_mode & = ~ allowed ;
fcb - > inode_item . st_mode | = val & allowed ;
if ( fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
2022-04-28 19:31:44 +00:00
if ( __S_ISTYPE ( val , __S_IFCHR ) ) {
2018-12-16 11:03:16 +00:00
fcb - > type = BTRFS_TYPE_CHARDEV ;
2022-04-28 19:31:44 +00:00
fcb - > inode_item . st_mode & = ~ __S_IFMT ;
fcb - > inode_item . st_mode | = __S_IFCHR ;
} else if ( __S_ISTYPE ( val , __S_IFBLK ) ) {
2018-12-16 11:03:16 +00:00
fcb - > type = BTRFS_TYPE_BLOCKDEV ;
2022-04-28 19:31:44 +00:00
fcb - > inode_item . st_mode & = ~ __S_IFMT ;
fcb - > inode_item . st_mode | = __S_IFBLK ;
} else if ( __S_ISTYPE ( val , __S_IFIFO ) ) {
2018-12-16 11:03:16 +00:00
fcb - > type = BTRFS_TYPE_FIFO ;
2022-04-28 19:31:44 +00:00
fcb - > inode_item . st_mode & = ~ __S_IFMT ;
fcb - > inode_item . st_mode | = __S_IFIFO ;
} else if ( __S_ISTYPE ( val , __S_IFSOCK ) ) {
2018-12-16 11:03:16 +00:00
fcb - > type = BTRFS_TYPE_SOCKET ;
2022-04-28 19:31:44 +00:00
fcb - > inode_item . st_mode & = ~ __S_IFMT ;
fcb - > inode_item . st_mode | = __S_IFSOCK ;
}
2018-12-16 11:03:16 +00:00
}
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
} else if ( item - > name . Length = = sizeof ( lxdev ) - 1 & & RtlCompareMemory ( item - > name . Buffer , lxdev , item - > name . Length ) = = item - > name . Length ) {
2019-09-01 12:53:20 +00:00
uint32_t major , minor ;
2018-12-16 11:03:16 +00:00
2019-09-01 12:53:20 +00:00
if ( item - > value . Length < sizeof ( uint64_t ) ) {
2018-12-16 11:03:16 +00:00
ERR ( " dev value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2019-09-01 12:53:20 +00:00
major = * ( uint32_t * ) item - > value . Buffer ;
minor = * ( uint32_t * ) & item - > value . Buffer [ sizeof ( uint32_t ) ] ;
2018-12-16 11:03:16 +00:00
fcb - > inode_item . st_rdev = ( minor & 0xFFFFF ) | ( ( major & 0xFFFFFFFFFFF ) < < 20 ) ;
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
}
le = le2 ;
}
if ( fcb - > type ! = BTRFS_TYPE_CHARDEV & & fcb - > type ! = BTRFS_TYPE_BLOCKDEV )
fcb - > inode_item . st_rdev = 0 ;
if ( IsListEmpty ( & ealist ) )
return STATUS_SUCCESS ;
le = ealist . Flink ;
while ( le ! = & ealist ) {
ea_item * item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
if ( size % 4 > 0 )
size + = 4 - ( size % 4 ) ;
2019-09-01 12:53:20 +00:00
size + = ( uint16_t ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + item - > name . Length + 1 + item - > value . Length ;
2018-12-16 11:03:16 +00:00
le = le - > Flink ;
}
buf = ExAllocatePoolWithTag ( PagedPool , size , ALLOC_TAG ) ;
if ( ! buf ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
fcb - > ea_xattr . Length = fcb - > ea_xattr . MaximumLength = size ;
fcb - > ea_xattr . Buffer = buf ;
fcb - > ealen = 4 ;
ea = NULL ;
le = ealist . Flink ;
while ( le ! = & ealist ) {
ea_item * item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
if ( ea ) {
ea - > NextEntryOffset = ( ULONG ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + ea - > EaNameLength + ea - > EaValueLength ;
if ( ea - > NextEntryOffset % 4 > 0 )
ea - > NextEntryOffset + = 4 - ( ea - > NextEntryOffset % 4 ) ;
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ea ) + ea - > NextEntryOffset ) ;
2018-12-16 11:03:16 +00:00
} else
ea = ( FILE_FULL_EA_INFORMATION * ) fcb - > ea_xattr . Buffer ;
ea - > NextEntryOffset = 0 ;
ea - > Flags = item - > flags ;
ea - > EaNameLength = ( UCHAR ) item - > name . Length ;
ea - > EaValueLength = item - > value . Length ;
RtlCopyMemory ( ea - > EaName , item - > name . Buffer , item - > name . Length ) ;
ea - > EaName [ item - > name . Length ] = 0 ;
RtlCopyMemory ( & ea - > EaName [ item - > name . Length + 1 ] , item - > value . Buffer , item - > value . Length ) ;
fcb - > ealen + = 5 + item - > name . Length + item - > value . Length ;
le = le - > Flink ;
}
2019-09-01 12:53:20 +00:00
fcb - > ea_changed = true ;
2018-12-16 11:03:16 +00:00
Status = STATUS_SUCCESS ;
end :
while ( ! IsListEmpty ( & ealist ) ) {
ea_item * item = CONTAINING_RECORD ( RemoveHeadList ( & ealist ) , ea_item , list_entry ) ;
ExFreePool ( item ) ;
}
return Status ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS file_create2 ( _In_ PIRP Irp , _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) _In_ device_extension * Vcb , _In_ PUNICODE_STRING fpus ,
_In_ file_ref * parfileref , _In_ ULONG options , _In_reads_bytes_opt_ ( ealen ) FILE_FULL_EA_INFORMATION * ea , _In_ ULONG ealen ,
2019-09-01 12:53:20 +00:00
_Out_ file_ref * * pfr , bool case_sensitive , _In_ LIST_ENTRY * rollback ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
fcb * fcb ;
ULONG utf8len ;
char * utf8 = NULL ;
2019-09-01 12:53:20 +00:00
uint64_t inode ;
uint8_t type ;
2016-03-23 20:35:05 +00:00
LARGE_INTEGER time ;
BTRFS_TIME now ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2016-09-04 15:27:46 +00:00
POOL_TYPE pool_type = IrpSp - > Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool ;
2017-09-08 08:02:43 +00:00
USHORT defda ;
2016-05-05 17:26:47 +00:00
file_ref * fileref ;
2017-01-01 17:12:12 +00:00
dir_child * dc ;
2017-09-08 08:02:43 +00:00
ANSI_STRING utf8as ;
2019-05-11 09:20:02 +00:00
LIST_ENTRY * lastle = NULL ;
file_ref * existing_fileref = NULL ;
2016-05-05 17:26:47 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2016-03-26 11:53:07 +00:00
LONG rc ;
2016-05-05 17:26:47 +00:00
# endif
2017-09-08 08:02:43 +00:00
if ( parfileref - > fcb = = Vcb - > dummy_fcb )
return STATUS_ACCESS_DENIED ;
2017-10-16 18:05:33 +00:00
if ( options & FILE_DIRECTORY_FILE & & IrpSp - > Parameters . Create . FileAttributes & FILE_ATTRIBUTE_TEMPORARY )
return STATUS_INVALID_PARAMETER ;
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , fpus - > Buffer , fpus - > Length ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf16_to_utf8 returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
2017-09-08 08:02:43 +00:00
}
2016-09-04 15:27:46 +00:00
utf8 = ExAllocatePoolWithTag ( pool_type , utf8len + 1 , ALLOC_TAG ) ;
2016-03-23 20:35:05 +00:00
if ( ! utf8 ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( utf8 , utf8len , & utf8len , fpus - > Buffer , fpus - > Length ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf16_to_utf8 returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
ExFreePool ( utf8 ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
utf8 [ utf8len ] = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " create file %.*S \n " , ( int ) ( fpus - > Length / sizeof ( WCHAR ) ) , fpus - > Buffer ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
TRACE ( " parfileref->fcb->inode_item.st_size (inode %I64x) was %I64x \n " , parfileref - > fcb - > inode , parfileref - > fcb - > inode_item . st_size ) ;
2016-05-05 17:26:47 +00:00
parfileref - > fcb - > inode_item . st_size + = utf8len * 2 ;
2019-09-01 12:53:20 +00:00
TRACE ( " parfileref->fcb->inode_item.st_size (inode %I64x) now %I64x \n " , parfileref - > fcb - > inode , parfileref - > fcb - > inode_item . st_size ) ;
2016-05-05 17:26:47 +00:00
parfileref - > fcb - > inode_item . transid = Vcb - > superblock . generation ;
parfileref - > fcb - > inode_item . sequence + + ;
parfileref - > fcb - > inode_item . st_ctime = now ;
parfileref - > fcb - > inode_item . st_mtime = now ;
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
parfileref - > fcb - > inode_item_changed = true ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( parfileref - > fcb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
inode = InterlockedIncrement64 ( & parfileref - > fcb - > subvol - > lastinode ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
type = options & FILE_DIRECTORY_FILE ? BTRFS_TYPE_DIRECTORY : BTRFS_TYPE_FILE ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - link FILE_ATTRIBUTE_READONLY to st_mode
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " requested attributes = %x \n " , IrpSp - > Parameters . Create . FileAttributes ) ;
2017-09-08 08:02:43 +00:00
2017-10-16 18:05:33 +00:00
defda = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( utf8 [ 0 ] = = ' . ' )
defda | = FILE_ATTRIBUTE_HIDDEN ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options & FILE_DIRECTORY_FILE ) {
defda | = FILE_ATTRIBUTE_DIRECTORY ;
IrpSp - > Parameters . Create . FileAttributes | = FILE_ATTRIBUTE_DIRECTORY ;
2017-09-08 08:02:43 +00:00
} else
IrpSp - > Parameters . Create . FileAttributes & = ~ FILE_ATTRIBUTE_DIRECTORY ;
2017-10-16 18:05:33 +00:00
if ( ! ( IrpSp - > Parameters . Create . FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
IrpSp - > Parameters . Create . FileAttributes | = FILE_ATTRIBUTE_ARCHIVE ;
defda | = FILE_ATTRIBUTE_ARCHIVE ;
}
2016-03-23 20:35:05 +00:00
TRACE ( " defda = %x \n " , defda ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Parameters . Create . FileAttributes = = FILE_ATTRIBUTE_NORMAL )
IrpSp - > Parameters . Create . FileAttributes = defda ;
2017-09-08 08:02:43 +00:00
fcb = create_fcb ( Vcb , pool_type ) ;
2016-03-23 20:35:05 +00:00
if ( ! fcb ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( utf8 ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2016-09-04 15:27:46 +00:00
2016-03-23 20:35:05 +00:00
fcb - > Vcb = Vcb ;
2016-09-04 15:27:46 +00:00
2019-09-01 12:53:20 +00:00
if ( IrpSp - > Flags & SL_OPEN_PAGING_FILE )
2016-09-04 15:27:46 +00:00
fcb - > Header . Flags2 | = FSRTL_FLAG2_IS_PAGING_FILE ;
2016-03-23 20:35:05 +00:00
fcb - > inode_item . generation = Vcb - > superblock . generation ;
fcb - > inode_item . transid = Vcb - > superblock . generation ;
fcb - > inode_item . st_size = 0 ;
fcb - > inode_item . st_blocks = 0 ;
fcb - > inode_item . block_group = 0 ;
fcb - > inode_item . st_nlink = 1 ;
fcb - > inode_item . st_gid = GID_NOBODY ; // FIXME?
2017-09-08 08:02:43 +00:00
fcb - > inode_item . st_mode = inherit_mode ( parfileref - > fcb , type = = BTRFS_TYPE_DIRECTORY ) ; // use parent's permissions by default
2016-03-23 20:35:05 +00:00
fcb - > inode_item . st_rdev = 0 ;
fcb - > inode_item . flags = 0 ;
fcb - > inode_item . sequence = 1 ;
fcb - > inode_item . st_atime = now ;
fcb - > inode_item . st_ctime = now ;
fcb - > inode_item . st_mtime = now ;
fcb - > inode_item . otime = now ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( type = = BTRFS_TYPE_DIRECTORY )
fcb - > inode_item . st_mode | = S_IFDIR ;
else {
fcb - > inode_item . st_mode | = S_IFREG ;
fcb - > inode_item . st_mode & = ~ ( S_IXUSR | S_IXGRP | S_IXOTH ) ; // remove executable bit if not directory
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( IrpSp - > Flags & SL_OPEN_PAGING_FILE ) {
fcb - > inode_item . flags = BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM | BTRFS_INODE_NOCOMPRESS ;
} else {
// inherit nodatacow flag from parent directory
2022-09-28 16:08:10 +00:00
if ( parfileref - > fcb - > inode_item . flags & BTRFS_INODE_NODATACOW | | Vcb - > options . nodatacow ) {
2016-09-04 15:27:46 +00:00
fcb - > inode_item . flags | = BTRFS_INODE_NODATACOW ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( type ! = BTRFS_TYPE_DIRECTORY )
fcb - > inode_item . flags | = BTRFS_INODE_NODATASUM ;
}
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
if ( parfileref - > fcb - > inode_item . flags & BTRFS_INODE_COMPRESS & &
! ( fcb - > inode_item . flags & BTRFS_INODE_NODATACOW ) ) {
2016-09-04 15:27:46 +00:00
fcb - > inode_item . flags | = BTRFS_INODE_COMPRESS ;
2022-09-28 16:08:10 +00:00
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
if ( ! ( fcb - > inode_item . flags & BTRFS_INODE_NODATACOW ) ) {
fcb - > prop_compression = parfileref - > fcb - > prop_compression ;
fcb - > prop_compression_changed = fcb - > prop_compression ! = PropCompression_None ;
} else
fcb - > prop_compression = PropCompression_None ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
2016-03-23 20:35:05 +00:00
fcb - > Header . AllocationSize . QuadPart = 0 ;
fcb - > Header . FileSize . QuadPart = 0 ;
fcb - > Header . ValidDataLength . QuadPart = 0 ;
2017-09-08 08:02:43 +00:00
fcb - > atts = IrpSp - > Parameters . Create . FileAttributes & ~ FILE_ATTRIBUTE_NORMAL ;
2016-07-27 19:24:26 +00:00
fcb - > atts_changed = fcb - > atts ! = defda ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2016-05-05 17:26:47 +00:00
rc = InterlockedIncrement ( & parfileref - > fcb - > refcount ) ;
2019-11-12 18:32:46 +00:00
WARN ( " fcb %p: refcount now %i \n " , parfileref - > fcb , rc ) ;
2016-05-05 17:26:47 +00:00
# else
InterlockedIncrement ( & parfileref - > fcb - > refcount ) ;
2016-03-23 20:35:05 +00:00
# endif
2016-05-05 17:26:47 +00:00
fcb - > subvol = parfileref - > fcb - > subvol ;
2016-03-23 20:35:05 +00:00
fcb - > inode = inode ;
fcb - > type = type ;
2019-09-01 12:53:20 +00:00
fcb - > created = true ;
fcb - > deleted = true ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) & inode , sizeof ( uint64_t ) ) ;
2019-05-11 09:20:02 +00:00
acquire_fcb_lock_exclusive ( Vcb ) ;
if ( fcb - > subvol - > fcbs_ptrs [ fcb - > hash > > 24 ] ) {
LIST_ENTRY * le = fcb - > subvol - > fcbs_ptrs [ fcb - > hash > > 24 ] ;
while ( le ! = & fcb - > subvol - > fcbs ) {
struct _fcb * fcb2 = CONTAINING_RECORD ( le , struct _fcb , list_entry ) ;
if ( fcb2 - > hash > fcb - > hash ) {
lastle = le - > Blink ;
break ;
}
le = le - > Flink ;
}
}
if ( ! lastle ) {
2019-09-01 12:53:20 +00:00
uint8_t c = fcb - > hash > > 24 ;
2019-05-11 09:20:02 +00:00
if ( c ! = 0xff ) {
2019-09-01 12:53:20 +00:00
uint8_t d = c + 1 ;
2019-05-11 09:20:02 +00:00
do {
if ( fcb - > subvol - > fcbs_ptrs [ d ] ) {
lastle = fcb - > subvol - > fcbs_ptrs [ d ] - > Blink ;
break ;
}
d + + ;
} while ( d ! = 0 ) ;
}
}
if ( lastle ) {
InsertHeadList ( lastle , & fcb - > list_entry ) ;
if ( lastle = = & fcb - > subvol - > fcbs | | ( CONTAINING_RECORD ( lastle , struct _fcb , list_entry ) - > hash > > 24 ) ! = ( fcb - > hash > > 24 ) )
fcb - > subvol - > fcbs_ptrs [ fcb - > hash > > 24 ] = & fcb - > list_entry ;
} else {
InsertTailList ( & fcb - > subvol - > fcbs , & fcb - > list_entry ) ;
if ( fcb - > list_entry . Blink = = & fcb - > subvol - > fcbs | | ( CONTAINING_RECORD ( fcb - > list_entry . Blink , struct _fcb , list_entry ) - > hash > > 24 ) ! = ( fcb - > hash > > 24 ) )
fcb - > subvol - > fcbs_ptrs [ fcb - > hash > > 24 ] = & fcb - > list_entry ;
}
InsertTailList ( & Vcb - > all_fcbs , & fcb - > list_entry_all ) ;
fcb - > subvol - > fcbs_version + + ;
release_fcb_lock ( Vcb ) ;
2017-09-08 08:02:43 +00:00
mark_fcb_dirty ( fcb ) ;
2016-05-05 17:26:47 +00:00
Status = fcb_get_new_sd ( fcb , parfileref , IrpSp - > Parameters . Create . SecurityContext - > AccessState ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " fcb_get_new_sd returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( utf8 ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > sd_dirty = true ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ea & & ealen > 0 ) {
2018-12-16 11:03:16 +00:00
Status = file_create_parse_ea ( fcb , ea ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " file_create_parse_ea returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( utf8 ) ;
2018-12-16 11:03:16 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
}
2017-09-08 08:02:43 +00:00
fileref = create_fileref ( Vcb ) ;
2016-07-27 19:24:26 +00:00
if ( ! fileref ) {
2016-03-23 20:35:05 +00:00
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( utf8 ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > fcb = fcb ;
2017-01-01 17:12:12 +00:00
2022-04-28 19:37:02 +00:00
if ( Irp - > Overlay . AllocationSize . QuadPart > 0 & & ! write_fcb_compressed ( fcb ) & & fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
2019-09-01 12:53:20 +00:00
Status = extend_file ( fcb , fileref , Irp - > Overlay . AllocationSize . QuadPart , true , NULL , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " extend_file returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( utf8 ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
}
2016-09-04 15:27:46 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
fcb - > hash_ptrs = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! fcb - > hash_ptrs ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( utf8 ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( fcb - > hash_ptrs , sizeof ( LIST_ENTRY * ) * 256 ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fcb - > hash_ptrs_uc = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! fcb - > hash_ptrs_uc ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( utf8 ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( fcb - > hash_ptrs_uc , sizeof ( LIST_ENTRY * ) * 256 ) ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > deleted = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fileref - > created = true ;
2017-09-08 08:02:43 +00:00
fcb - > subvol - > root_item . ctransid = Vcb - > superblock . generation ;
fcb - > subvol - > root_item . ctime = now ;
utf8as . Buffer = utf8 ;
2019-09-01 12:53:20 +00:00
utf8as . Length = utf8as . MaximumLength = ( uint16_t ) utf8len ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & parfileref - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
// check again doesn't already exist
if ( case_sensitive ) {
2019-09-01 12:53:20 +00:00
uint32_t dc_hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) fpus - > Buffer , fpus - > Length ) ;
2019-05-11 09:20:02 +00:00
if ( parfileref - > fcb - > hash_ptrs [ dc_hash > > 24 ] ) {
LIST_ENTRY * le = parfileref - > fcb - > hash_ptrs [ dc_hash > > 24 ] ;
while ( le ! = & parfileref - > fcb - > dir_children_hash ) {
2019-09-01 12:53:20 +00:00
dc = CONTAINING_RECORD ( le , dir_child , list_entry_hash ) ;
2019-05-11 09:20:02 +00:00
if ( dc - > hash = = dc_hash & & dc - > name . Length = = fpus - > Length & & RtlCompareMemory ( dc - > name . Buffer , fpus - > Buffer , fpus - > Length ) = = fpus - > Length ) {
existing_fileref = dc - > fileref ;
break ;
} else if ( dc - > hash > dc_hash )
break ;
le = le - > Flink ;
}
}
} else {
UNICODE_STRING fpusuc ;
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & fpusuc , fpus , true ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ExReleaseResourceLite ( & parfileref - > fcb - > nonpaged - > dir_children_lock ) ;
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2019-05-11 09:20:02 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
ExFreePool ( utf8 ) ;
return Status ;
}
2019-11-12 18:32:46 +00:00
uint32_t dc_hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) fpusuc . Buffer , fpusuc . Length ) ;
2019-05-11 09:20:02 +00:00
if ( parfileref - > fcb - > hash_ptrs_uc [ dc_hash > > 24 ] ) {
LIST_ENTRY * le = parfileref - > fcb - > hash_ptrs_uc [ dc_hash > > 24 ] ;
while ( le ! = & parfileref - > fcb - > dir_children_hash_uc ) {
2019-09-01 12:53:20 +00:00
dc = CONTAINING_RECORD ( le , dir_child , list_entry_hash_uc ) ;
2019-05-11 09:20:02 +00:00
if ( dc - > hash_uc = = dc_hash & & dc - > name . Length = = fpusuc . Length & & RtlCompareMemory ( dc - > name . Buffer , fpusuc . Buffer , fpusuc . Length ) = = fpusuc . Length ) {
existing_fileref = dc - > fileref ;
break ;
} else if ( dc - > hash_uc > dc_hash )
break ;
le = le - > Flink ;
}
}
ExFreePool ( fpusuc . Buffer ) ;
}
if ( existing_fileref ) {
ExReleaseResourceLite ( & parfileref - > fcb - > nonpaged - > dir_children_lock ) ;
reap_fileref ( Vcb , fileref ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2019-05-11 09:20:02 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
ExFreePool ( utf8 ) ;
increase_fileref_refcount ( existing_fileref ) ;
* pfr = existing_fileref ;
return STATUS_OBJECT_NAME_COLLISION ;
}
2019-09-01 12:53:20 +00:00
Status = add_dir_child ( parfileref - > fcb , fcb - > inode , false , & utf8as , fpus , fcb - > type , & dc ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ExReleaseResourceLite ( & parfileref - > fcb - > nonpaged - > dir_children_lock ) ;
2020-04-23 02:38:57 +00:00
ERR ( " add_dir_child returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2019-05-11 09:20:02 +00:00
parfileref - > fcb - > inode_item . st_size - = utf8len * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
ExFreePool ( utf8 ) ;
return Status ;
}
fileref - > parent = parfileref ;
2017-09-08 08:02:43 +00:00
fileref - > dc = dc ;
dc - > fileref = fileref ;
2019-05-11 09:20:02 +00:00
if ( type = = BTRFS_TYPE_DIRECTORY )
fileref - > fcb - > fileref = fileref ;
2017-09-08 08:02:43 +00:00
InsertTailList ( & parfileref - > children , & fileref - > list_entry ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & parfileref - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExFreePool ( utf8 ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
mark_fileref_dirty ( fileref ) ;
increase_fileref_refcount ( parfileref ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
* pfr = fileref ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
TRACE ( " created new file in subvol %I64x, inode %I64x \n " , fcb - > subvol - > id , fcb - > inode ) ;
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 create_stream ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) device_extension * Vcb ,
file_ref * * pfileref , file_ref * * pparfileref , PUNICODE_STRING fpus , PUNICODE_STRING stream , PIRP Irp ,
2019-09-01 12:53:20 +00:00
ULONG options , POOL_TYPE pool_type , bool case_sensitive , LIST_ENTRY * rollback ) {
2017-09-08 08:02:43 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2016-09-04 15:27:46 +00:00
file_ref * fileref , * newpar , * parfileref ;
fcb * fcb ;
2018-12-16 11:03:16 +00:00
static const char xapref [ ] = " user. " ;
static const WCHAR DOSATTRIB [ ] = L " DOSATTRIB " ;
static const WCHAR EA [ ] = L " EA " ;
static const WCHAR reparse [ ] = L " reparse " ;
2019-06-11 10:35:19 +00:00
static const WCHAR casesensitive_str [ ] = L " casesensitive " ;
2016-09-04 15:27:46 +00:00
LARGE_INTEGER time ;
BTRFS_TIME now ;
2017-09-08 08:02:43 +00:00
ULONG utf8len , overhead ;
2016-09-04 15:27:46 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
dir_child * dc ;
2019-05-11 09:20:02 +00:00
dir_child * existing_dc = NULL ;
2017-09-08 08:02:43 +00:00
ACCESS_MASK granted_access ;
2016-09-04 15:27:46 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
LONG rc ;
# endif
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " fpus = %.*S \n " , ( int ) ( fpus - > Length / sizeof ( WCHAR ) ) , fpus - > Buffer ) ;
TRACE ( " stream = %.*S \n " , ( int ) ( stream - > Length / sizeof ( WCHAR ) ) , stream - > Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
parfileref = * pparfileref ;
2017-09-08 08:02:43 +00:00
if ( parfileref - > fcb = = Vcb - > dummy_fcb )
return STATUS_ACCESS_DENIED ;
2022-04-28 19:37:02 +00:00
Status = check_file_name_valid ( stream , false , true ) ;
if ( ! NT_SUCCESS ( Status ) )
return Status ;
2019-09-01 12:53:20 +00:00
Status = open_fileref ( Vcb , & newpar , fpus , parfileref , false , NULL , NULL , PagedPool , case_sensitive , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Status = = STATUS_OBJECT_NAME_NOT_FOUND ) {
UNICODE_STRING fpus2 ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:37:02 +00:00
Status = check_file_name_valid ( fpus , false , false ) ;
2022-04-28 19:34:48 +00:00
if ( ! NT_SUCCESS ( Status ) )
return Status ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
fpus2 . Length = fpus2 . MaximumLength = fpus - > Length ;
fpus2 . Buffer = ExAllocatePoolWithTag ( pool_type , fpus2 . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! fpus2 . Buffer ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
RtlCopyMemory ( fpus2 . Buffer , fpus - > Buffer , fpus2 . Length ) ;
2017-09-08 08:02:43 +00:00
SeLockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
if ( ! SeAccessCheck ( parfileref - > fcb - > sd , & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ,
2019-09-01 12:53:20 +00:00
true , options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE , 0 , NULL ,
2017-09-08 08:02:43 +00:00
IoGetFileObjectGenericMapping ( ) , IrpSp - > Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp - > RequestorMode ,
& granted_access , & Status ) ) {
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
return Status ;
}
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
2019-05-11 09:20:02 +00:00
Status = file_create2 ( Irp , Vcb , & fpus2 , parfileref , options , NULL , 0 , & newpar , case_sensitive , rollback ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " file_create2 returned %08lx \n " , Status ) ;
2016-09-04 15:27:46 +00:00
ExFreePool ( fpus2 . Buffer ) ;
return Status ;
2019-05-11 09:20:02 +00:00
} else if ( Status ! = STATUS_OBJECT_NAME_COLLISION ) {
send_notification_fileref ( newpar , options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_ADDED , NULL ) ;
2019-11-12 18:32:46 +00:00
queue_notification_fcb ( newpar - > parent , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExFreePool ( fpus2 . Buffer ) ;
2016-09-04 15:27:46 +00:00
} else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref returned %08lx \n " , Status ) ;
2016-09-04 15:27:46 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
parfileref = newpar ;
* pparfileref = parfileref ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( parfileref - > fcb - > type ! = BTRFS_TYPE_FILE & & parfileref - > fcb - > type ! = BTRFS_TYPE_SYMLINK & & parfileref - > fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
WARN ( " parent not file, directory, or symlink \n " ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( options & FILE_DIRECTORY_FILE ) {
WARN ( " tried to create directory as stream \n " ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( parfileref - > fcb - > atts & FILE_ATTRIBUTE_READONLY & & ! ( IrpSp - > Flags & SL_IGNORE_READONLY_ATTRIBUTE ) ) {
2019-05-11 09:20:02 +00:00
free_fileref ( parfileref ) ;
2017-09-08 08:02:43 +00:00
return STATUS_ACCESS_DENIED ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
SeLockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
if ( ! SeAccessCheck ( parfileref - > fcb - > sd , & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ,
2019-09-01 12:53:20 +00:00
true , FILE_WRITE_DATA , 0 , NULL , IoGetFileObjectGenericMapping ( ) , IrpSp - > Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp - > RequestorMode ,
2017-09-08 08:02:43 +00:00
& granted_access , & Status ) ) {
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfileref ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
2018-12-16 11:03:16 +00:00
if ( ( stream - > Length = = sizeof ( DOSATTRIB ) - sizeof ( WCHAR ) & & RtlCompareMemory ( stream - > Buffer , DOSATTRIB , stream - > Length ) = = stream - > Length ) | |
( stream - > Length = = sizeof ( EA ) - sizeof ( WCHAR ) & & RtlCompareMemory ( stream - > Buffer , EA , stream - > Length ) = = stream - > Length ) | |
2019-06-11 10:35:19 +00:00
( stream - > Length = = sizeof ( reparse ) - sizeof ( WCHAR ) & & RtlCompareMemory ( stream - > Buffer , reparse , stream - > Length ) = = stream - > Length ) | |
( stream - > Length = = sizeof ( casesensitive_str ) - sizeof ( WCHAR ) & & RtlCompareMemory ( stream - > Buffer , casesensitive_str , stream - > Length ) = = stream - > Length ) ) {
2019-05-11 09:20:02 +00:00
free_fileref ( parfileref ) ;
2016-10-29 17:05:10 +00:00
return STATUS_OBJECT_NAME_INVALID ;
}
2017-09-08 08:02:43 +00:00
fcb = create_fcb ( Vcb , pool_type ) ;
2016-09-04 15:27:46 +00:00
if ( ! fcb ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
fcb - > Vcb = Vcb ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
fcb - > Header . AllocationSize . QuadPart = 0 ;
fcb - > Header . FileSize . QuadPart = 0 ;
fcb - > Header . ValidDataLength . QuadPart = 0 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
rc = InterlockedIncrement ( & parfileref - > fcb - > refcount ) ;
2019-11-12 18:32:46 +00:00
WARN ( " fcb %p: refcount now %i \n " , parfileref - > fcb , rc ) ;
2016-09-04 15:27:46 +00:00
# else
InterlockedIncrement ( & parfileref - > fcb - > refcount ) ;
# endif
fcb - > subvol = parfileref - > fcb - > subvol ;
fcb - > inode = parfileref - > fcb - > inode ;
2022-04-28 19:34:48 +00:00
fcb - > hash = parfileref - > fcb - > hash ;
2016-09-04 15:27:46 +00:00
fcb - > type = parfileref - > fcb - > type ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > ads = true ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , stream - > Buffer , stream - > Length ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf16_to_utf8 1 returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > adsxattr . Length = ( uint16_t ) utf8len + sizeof ( xapref ) - 1 ;
2016-09-04 15:27:46 +00:00
fcb - > adsxattr . MaximumLength = fcb - > adsxattr . Length + 1 ;
fcb - > adsxattr . Buffer = ExAllocatePoolWithTag ( pool_type , fcb - > adsxattr . MaximumLength , ALLOC_TAG ) ;
if ( ! fcb - > adsxattr . Buffer ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
RtlCopyMemory ( fcb - > adsxattr . Buffer , xapref , sizeof ( xapref ) - 1 ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( & fcb - > adsxattr . Buffer [ sizeof ( xapref ) - 1 ] , utf8len , & utf8len , stream - > Buffer , stream - > Length ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf16_to_utf8 2 returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
fcb - > adsxattr . Buffer [ fcb - > adsxattr . Length ] = 0 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
TRACE ( " adsxattr = %s \n " , fcb - > adsxattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > adshash = calc_crc32c ( 0xfffffffe , ( uint8_t * ) fcb - > adsxattr . Buffer , fcb - > adsxattr . Length ) ;
2016-09-04 15:27:46 +00:00
TRACE ( " adshash = %08x \n " , fcb - > adshash ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
searchkey . obj_id = parfileref - > fcb - > inode ;
searchkey . obj_type = TYPE_XATTR_ITEM ;
searchkey . offset = fcb - > adshash ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , parfileref - > fcb - > subvol , & tp , & searchkey , false , Irp ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( tp . item - > key , searchkey ) )
2016-09-04 15:27:46 +00:00
overhead = tp . item - > size ;
else
overhead = 0 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
fcb - > adsmaxlen = Vcb - > superblock . node_size - sizeof ( tree_header ) - sizeof ( leaf_node ) - ( sizeof ( DIR_ITEM ) - 1 ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
if ( utf8len + sizeof ( xapref ) - 1 + overhead > fcb - > adsmaxlen ) {
2022-09-28 16:08:10 +00:00
WARN ( " not enough room for new DIR_ITEM (%Iu + %lu > %lu) \n " , utf8len + sizeof ( xapref ) - 1 , overhead , fcb - > adsmaxlen ) ;
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return STATUS_DISK_FULL ;
} else
2018-12-16 11:03:16 +00:00
fcb - > adsmaxlen - = overhead + utf8len + sizeof ( xapref ) - 1 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > created = true ;
fcb - > deleted = true ;
2019-05-11 09:20:02 +00:00
acquire_fcb_lock_exclusive ( Vcb ) ;
InsertHeadList ( & parfileref - > fcb - > list_entry , & fcb - > list_entry ) ; // insert in list after parent fcb
InsertTailList ( & Vcb - > all_fcbs , & fcb - > list_entry_all ) ;
parfileref - > fcb - > subvol - > fcbs_version + + ;
release_fcb_lock ( Vcb ) ;
mark_fcb_dirty ( fcb ) ;
fileref = create_fileref ( Vcb ) ;
if ( ! fileref ) {
ERR ( " out of memory \n " ) ;
free_fcb ( fcb ) ;
free_fileref ( parfileref ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
fileref - > fcb = fcb ;
2017-09-08 08:02:43 +00:00
dc = ExAllocatePoolWithTag ( PagedPool , sizeof ( dir_child ) , ALLOC_TAG ) ;
if ( ! dc ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
free_fileref ( parfileref ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlZeroMemory ( dc , sizeof ( dir_child ) ) ;
2018-12-16 11:03:16 +00:00
dc - > utf8 . MaximumLength = dc - > utf8 . Length = fcb - > adsxattr . Length + 1 - sizeof ( xapref ) ;
2017-09-08 08:02:43 +00:00
dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , dc - > utf8 . MaximumLength , ALLOC_TAG ) ;
if ( ! dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( dc ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
free_fileref ( parfileref ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2018-12-16 11:03:16 +00:00
RtlCopyMemory ( dc - > utf8 . Buffer , & fcb - > adsxattr . Buffer [ sizeof ( xapref ) - 1 ] , fcb - > adsxattr . Length + 1 - sizeof ( xapref ) ) ;
2017-09-08 08:02:43 +00:00
dc - > name . MaximumLength = dc - > name . Length = stream - > Length ;
dc - > name . Buffer = ExAllocatePoolWithTag ( pool_type , dc - > name . MaximumLength , ALLOC_TAG ) ;
if ( ! dc - > name . Buffer ) {
2016-09-04 15:27:46 +00:00
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( dc - > name . Buffer , stream - > Buffer , stream - > Length ) ;
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & dc - > name_uc , & dc - > name , true ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " RtlUpcaseUnicodeString returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
2019-05-11 09:20:02 +00:00
reap_fileref ( Vcb , fileref ) ;
free_fileref ( parfileref ) ;
2016-09-04 15:27:46 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & parfileref - > fcb - > nonpaged - > dir_children_lock , true ) ;
2019-05-11 09:20:02 +00:00
LIST_ENTRY * le = parfileref - > fcb - > dir_children_index . Flink ;
while ( le ! = & parfileref - > fcb - > dir_children_index ) {
dir_child * dc2 = CONTAINING_RECORD ( le , dir_child , list_entry_index ) ;
if ( dc2 - > index = = 0 ) {
if ( ( case_sensitive & & dc2 - > name . Length = = dc - > name . Length & & RtlCompareMemory ( dc2 - > name . Buffer , dc - > name . Buffer , dc2 - > name . Length ) = = dc2 - > name . Length ) | |
( ! case_sensitive & & dc2 - > name_uc . Length = = dc - > name_uc . Length & & RtlCompareMemory ( dc2 - > name_uc . Buffer , dc - > name_uc . Buffer , dc2 - > name_uc . Length ) = = dc2 - > name_uc . Length )
) {
existing_dc = dc2 ;
break ;
}
} else
break ;
le = le - > Flink ;
}
if ( existing_dc ) {
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc ) ;
reap_fileref ( Vcb , fileref ) ;
free_fileref ( parfileref ) ;
increase_fileref_refcount ( existing_dc - > fileref ) ;
* pfileref = existing_dc - > fileref ;
return STATUS_OBJECT_NAME_COLLISION ;
}
2017-09-08 08:02:43 +00:00
dc - > fileref = fileref ;
fileref - > dc = dc ;
2019-05-11 09:20:02 +00:00
fileref - > parent = ( struct _file_ref * ) parfileref ;
2019-09-01 12:53:20 +00:00
fcb - > deleted = false ;
2017-09-08 08:02:43 +00:00
InsertHeadList ( & parfileref - > fcb - > dir_children_index , & dc - > list_entry_index ) ;
2019-05-11 09:20:02 +00:00
InsertTailList ( & parfileref - > children , & fileref - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & parfileref - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
mark_fileref_dirty ( fileref ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
parfileref - > fcb - > inode_item . transid = Vcb - > superblock . generation ;
parfileref - > fcb - > inode_item . sequence + + ;
parfileref - > fcb - > inode_item . st_ctime = now ;
2019-09-01 12:53:20 +00:00
parfileref - > fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
mark_fcb_dirty ( parfileref - > fcb ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
parfileref - > fcb - > subvol - > root_item . ctransid = Vcb - > superblock . generation ;
parfileref - > fcb - > subvol - > root_item . ctime = now ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
increase_fileref_refcount ( parfileref ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
* pfileref = fileref ;
2017-09-08 08:02:43 +00:00
2017-10-16 18:05:33 +00:00
send_notification_fileref ( parfileref , FILE_NOTIFY_CHANGE_STREAM_NAME , FILE_ACTION_ADDED_STREAM , & fileref - > dc - > name ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
// LXSS programs can be distinguished by the fact they have a NULL PEB.
# ifdef _AMD64_
2019-09-01 12:53:20 +00:00
static __inline bool called_from_lxss ( ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
PROCESS_BASIC_INFORMATION pbi ;
ULONG retlen ;
Status = ZwQueryInformationProcess ( NtCurrentProcess ( ) , ProcessBasicInformation , & pbi , sizeof ( pbi ) , & retlen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwQueryInformationProcess returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
return ! pbi . PebBaseAddress ;
}
# else
2019-09-01 12:53:20 +00:00
# define called_from_lxss() false
2017-09-08 08:02:43 +00:00
# endif
static NTSTATUS file_create ( PIRP Irp , _Requires_lock_held_ ( _Curr_ - > tree_lock ) _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) device_extension * Vcb ,
2019-09-01 12:53:20 +00:00
PFILE_OBJECT FileObject , file_ref * related , bool loaded_related , PUNICODE_STRING fnus , ULONG disposition , ULONG options ,
2019-05-11 09:20:02 +00:00
file_ref * * existing_fileref , LIST_ENTRY * rollback ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-01-01 17:12:12 +00:00
file_ref * fileref , * parfileref = NULL ;
2017-09-08 08:02:43 +00:00
ULONG i , j ;
2016-03-23 20:35:05 +00:00
ccb * ccb ;
2018-12-16 11:03:16 +00:00
static const WCHAR datasuf [ ] = { ' : ' , ' $ ' , ' D ' , ' A ' , ' T ' , ' A ' , 0 } ;
2016-03-23 20:35:05 +00:00
UNICODE_STRING dsus , fpus , stream ;
2016-05-05 17:26:47 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2016-09-04 15:27:46 +00:00
POOL_TYPE pool_type = IrpSp - > Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool ;
2018-12-16 11:03:16 +00:00
ECP_LIST * ecp_list ;
ATOMIC_CREATE_ECP_CONTEXT * acec = NULL ;
2016-05-05 17:26:47 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2016-03-26 11:53:07 +00:00
LONG oc ;
2016-05-05 17:26:47 +00:00
# endif
2016-09-04 15:27:46 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " (%p, %p, %p, %.*S, %lx, %lx) \n " , Irp , Vcb , FileObject , ( int ) ( fnus - > Length / sizeof ( WCHAR ) ) , fnus - > Buffer , disposition , options ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( Vcb - > readonly )
return STATUS_MEDIA_WRITE_PROTECTED ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( options & FILE_DELETE_ON_CLOSE & & IrpSp - > Parameters . Create . FileAttributes & FILE_ATTRIBUTE_READONLY & &
! ( IrpSp - > Flags & SL_IGNORE_READONLY_ATTRIBUTE ) ) {
2017-10-16 18:05:33 +00:00
return STATUS_CANNOT_DELETE ;
2022-04-28 19:31:44 +00:00
}
2017-10-16 18:05:33 +00:00
2019-09-01 12:53:20 +00:00
if ( fFsRtlGetEcpListFromIrp & & fFsRtlGetNextExtraCreateParameter ) {
if ( NT_SUCCESS ( fFsRtlGetEcpListFromIrp ( Irp , & ecp_list ) ) & & ecp_list ) {
void * ctx = NULL ;
GUID type ;
ULONG ctxsize ;
2018-12-16 11:03:16 +00:00
2019-09-01 12:53:20 +00:00
do {
Status = fFsRtlGetNextExtraCreateParameter ( ecp_list , ctx , & type , & ctx , & ctxsize ) ;
2018-12-16 11:03:16 +00:00
2019-09-01 12:53:20 +00:00
if ( NT_SUCCESS ( Status ) ) {
2019-11-12 18:32:46 +00:00
if ( RtlCompareMemory ( & type , & GUID_ECP_ATOMIC_CREATE , sizeof ( GUID ) ) = = sizeof ( GUID ) ) {
if ( ctxsize > = sizeof ( ATOMIC_CREATE_ECP_CONTEXT ) )
acec = ctx ;
else {
2020-04-23 02:38:57 +00:00
ERR ( " GUID_ECP_ATOMIC_CREATE context was too short: %lu bytes, expected %Iu \n " , ctxsize ,
2019-11-12 18:32:46 +00:00
sizeof ( ATOMIC_CREATE_ECP_CONTEXT ) ) ;
}
2020-04-23 02:38:57 +00:00
} else if ( RtlCompareMemory ( & type , & GUID_ECP_QUERY_ON_CREATE , sizeof ( GUID ) ) = = sizeof ( GUID ) )
WARN ( " unhandled ECP GUID_ECP_QUERY_ON_CREATE \n " ) ;
else if ( RtlCompareMemory ( & type , & GUID_ECP_CREATE_REDIRECTION , sizeof ( GUID ) ) = = sizeof ( GUID ) )
WARN ( " unhandled ECP GUID_ECP_CREATE_REDIRECTION \n " ) ;
else {
WARN ( " unhandled ECP {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x} \n " , type . Data1 , type . Data2 ,
2019-11-12 18:32:46 +00:00
type . Data3 , type . Data4 [ 0 ] , type . Data4 [ 1 ] , type . Data4 [ 2 ] , type . Data4 [ 3 ] , type . Data4 [ 4 ] , type . Data4 [ 5 ] ,
type . Data4 [ 6 ] , type . Data4 [ 7 ] ) ;
2019-09-01 12:53:20 +00:00
}
2018-12-16 11:03:16 +00:00
}
2019-09-01 12:53:20 +00:00
} while ( NT_SUCCESS ( Status ) ) ;
}
2018-12-16 11:03:16 +00:00
}
dsus . Buffer = ( WCHAR * ) datasuf ;
dsus . Length = dsus . MaximumLength = sizeof ( datasuf ) - sizeof ( WCHAR ) ;
2016-03-23 20:35:05 +00:00
fpus . Buffer = NULL ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! loaded_related ) {
2019-09-01 12:53:20 +00:00
Status = open_fileref ( Vcb , & parfileref , fnus , related , true , NULL , NULL , pool_type , IrpSp - > Flags & SL_CASE_SENSITIVE , Irp ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2016-05-05 17:26:47 +00:00
} else
2017-01-01 17:12:12 +00:00
parfileref = related ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( parfileref - > fcb - > type ! = BTRFS_TYPE_DIRECTORY & & ( fnus - > Length < sizeof ( WCHAR ) | | fnus - > Buffer [ 0 ] ! = ' : ' ) ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_OBJECT_PATH_NOT_FOUND ;
goto end ;
}
2017-09-08 08:02:43 +00:00
if ( is_subvol_readonly ( parfileref - > fcb - > subvol , Irp ) ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
i = ( fnus - > Length / sizeof ( WCHAR ) ) - 1 ;
while ( ( fnus - > Buffer [ i ] = = ' \\ ' | | fnus - > Buffer [ i ] = = ' / ' ) & & i > 0 ) { i - - ; }
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
j = i ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( i > 0 & & fnus - > Buffer [ i - 1 ] ! = ' \\ ' & & fnus - > Buffer [ i - 1 ] ! = ' / ' ) { i - - ; }
2017-09-08 08:02:43 +00:00
fpus . MaximumLength = ( USHORT ) ( ( j - i + 2 ) * sizeof ( WCHAR ) ) ;
2016-09-04 15:27:46 +00:00
fpus . Buffer = ExAllocatePoolWithTag ( pool_type , fpus . MaximumLength , ALLOC_TAG ) ;
2016-03-23 20:35:05 +00:00
if ( ! fpus . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
fpus . Length = ( USHORT ) ( ( j - i + 1 ) * sizeof ( WCHAR ) ) ;
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( fpus . Buffer , & fnus - > Buffer [ i ] , ( j - i + 1 ) * sizeof ( WCHAR ) ) ;
fpus . Buffer [ j - i + 1 ] = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fpus . Length > dsus . Length ) { // check for :$DATA suffix
UNICODE_STRING lb ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
lb . Buffer = & fpus . Buffer [ ( fpus . Length - dsus . Length ) / sizeof ( WCHAR ) ] ;
lb . Length = lb . MaximumLength = dsus . Length ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " lb = %.*S \n " , ( int ) ( lb . Length / sizeof ( WCHAR ) ) , lb . Buffer ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( FsRtlAreNamesEqual ( & dsus , & lb , true , NULL ) ) {
2016-03-23 20:35:05 +00:00
TRACE ( " ignoring :$DATA suffix \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fpus . Length - = lb . Length ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fpus . Length > sizeof ( WCHAR ) & & fpus . Buffer [ ( fpus . Length - 1 ) / sizeof ( WCHAR ) ] = = ' : ' )
fpus . Length - = sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " fpus = %.*S \n " , ( int ) ( fpus . Length / sizeof ( WCHAR ) ) , fpus . Buffer ) ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
stream . Length = 0 ;
2017-09-08 08:02:43 +00:00
for ( i = 0 ; i < fpus . Length / sizeof ( WCHAR ) ; i + + ) {
2016-03-23 20:35:05 +00:00
if ( fpus . Buffer [ i ] = = ' : ' ) {
2017-09-08 08:02:43 +00:00
stream . Length = ( USHORT ) ( fpus . Length - ( i * sizeof ( WCHAR ) ) - sizeof ( WCHAR ) ) ;
2016-03-23 20:35:05 +00:00
stream . Buffer = & fpus . Buffer [ i + 1 ] ;
fpus . Buffer [ i ] = 0 ;
2017-09-08 08:02:43 +00:00
fpus . Length = ( USHORT ) ( i * sizeof ( WCHAR ) ) ;
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
if ( stream . Length > 0 ) {
2016-10-29 17:05:10 +00:00
Status = create_stream ( Vcb , & fileref , & parfileref , & fpus , & stream , Irp , options , pool_type , IrpSp - > Flags & SL_CASE_SENSITIVE , rollback ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " create_stream returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
IoSetShareAccess ( IrpSp - > Parameters . Create . SecurityContext - > DesiredAccess , IrpSp - > Parameters . Create . ShareAccess ,
FileObject , & fileref - > fcb - > share_access ) ;
2016-03-23 20:35:05 +00:00
} else {
2017-09-08 08:02:43 +00:00
ACCESS_MASK granted_access ;
2022-04-28 19:34:48 +00:00
Status = check_file_name_valid ( & fpus , false , false ) ;
if ( ! NT_SUCCESS ( Status ) )
2016-05-05 17:26:47 +00:00
goto end ;
2017-09-08 08:02:43 +00:00
SeLockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
if ( ! SeAccessCheck ( parfileref - > fcb - > sd , & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ,
2019-09-01 12:53:20 +00:00
true , options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE , 0 , NULL ,
2017-09-08 08:02:43 +00:00
IoGetFileObjectGenericMapping ( ) , IrpSp - > Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp - > RequestorMode ,
& granted_access , & Status ) ) {
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
goto end ;
}
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
2016-10-29 17:05:10 +00:00
if ( Irp - > AssociatedIrp . SystemBuffer & & IrpSp - > Parameters . Create . EaLength > 0 ) {
ULONG offset ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = IoCheckEaBufferValidity ( Irp - > AssociatedIrp . SystemBuffer , IrpSp - > Parameters . Create . EaLength , & offset ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCheckEaBufferValidity returned %08lx (error at offset %lu) \n " , Status , offset ) ;
2016-10-29 17:05:10 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = file_create2 ( Irp , Vcb , & fpus , parfileref , options , Irp - > AssociatedIrp . SystemBuffer , IrpSp - > Parameters . Create . EaLength ,
2019-05-11 09:20:02 +00:00
& fileref , IrpSp - > Flags & SL_CASE_SENSITIVE , rollback ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( Status = = STATUS_OBJECT_NAME_COLLISION ) {
* existing_fileref = fileref ;
goto end ;
} else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " file_create2 returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
IoSetShareAccess ( IrpSp - > Parameters . Create . SecurityContext - > DesiredAccess , IrpSp - > Parameters . Create . ShareAccess , FileObject , & fileref - > fcb - > share_access ) ;
send_notification_fileref ( fileref , options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_ADDED , NULL ) ;
2019-11-12 18:32:46 +00:00
queue_notification_fcb ( fileref - > parent , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
FileObject - > FsContext = fileref - > fcb ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ccb = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( * ccb ) , ALLOC_TAG ) ;
if ( ! ccb ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
2019-09-01 12:53:20 +00:00
fileref - > deleted = true ;
fileref - > fcb - > deleted = true ;
2018-12-16 11:03:16 +00:00
if ( stream . Length = = 0 ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2018-12-16 11:03:16 +00:00
parfileref - > fcb - > inode_item . st_size - = fileref - > dc - > utf8 . Length * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
}
2019-05-11 09:20:02 +00:00
free_fileref ( fileref ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlZeroMemory ( ccb , sizeof ( * ccb ) ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ccb - > fileref = fileref ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ccb - > NodeType = BTRFS_NODE_TYPE_CCB ;
2017-09-08 08:02:43 +00:00
ccb - > NodeSize = sizeof ( * ccb ) ;
2016-03-23 20:35:05 +00:00
ccb - > disposition = disposition ;
ccb - > options = options ;
ccb - > query_dir_offset = 0 ;
RtlInitUnicodeString ( & ccb - > query_string , NULL ) ;
2019-09-01 12:53:20 +00:00
ccb - > has_wildcard = false ;
ccb - > specific_file = false ;
2017-09-08 08:02:43 +00:00
ccb - > access = IrpSp - > Parameters . Create . SecurityContext - > DesiredAccess ;
2016-10-29 17:05:10 +00:00
ccb - > case_sensitive = IrpSp - > Flags & SL_CASE_SENSITIVE ;
2019-09-01 12:53:20 +00:00
ccb - > reserving = false ;
2017-09-08 08:02:43 +00:00
ccb - > lxss = called_from_lxss ( ) ;
2016-03-26 11:53:07 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2016-10-29 17:05:10 +00:00
oc = InterlockedIncrement ( & fileref - > open_count ) ;
ERR ( " fileref %p: open_count now %i \n " , fileref , oc ) ;
2016-05-05 17:26:47 +00:00
# else
2016-10-29 17:05:10 +00:00
InterlockedIncrement ( & fileref - > open_count ) ;
2016-03-26 11:53:07 +00:00
# endif
2016-10-29 17:05:10 +00:00
InterlockedIncrement ( & Vcb - > open_files ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FileObject - > FsContext2 = ccb ;
2016-05-05 17:26:47 +00:00
FileObject - > SectionObjectPointer = & fileref - > fcb - > nonpaged - > segment_object ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
// FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT
if ( acec & & acec - > InFlags & ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED ) {
2019-09-01 12:53:20 +00:00
if ( acec - > ReparseBufferLength > sizeof ( uint32_t ) & & * ( uint32_t * ) acec - > ReparseBuffer = = IO_REPARSE_TAG_SYMLINK ) {
2018-12-16 11:03:16 +00:00
fileref - > fcb - > inode_item . st_mode & = ~ ( __S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK ) ;
fileref - > fcb - > type = BTRFS_TYPE_FILE ;
2022-04-28 19:31:44 +00:00
fileref - > fcb - > atts & = ~ FILE_ATTRIBUTE_DIRECTORY ;
2018-12-16 11:03:16 +00:00
}
if ( fileref - > fcb - > type = = BTRFS_TYPE_SOCKET | | fileref - > fcb - > type = = BTRFS_TYPE_FIFO | |
fileref - > fcb - > type = = BTRFS_TYPE_CHARDEV | | fileref - > fcb - > type = = BTRFS_TYPE_BLOCKDEV ) {
// NOP. If called from LXSS, humour it - we hardcode the values elsewhere.
} else {
Status = set_reparse_point2 ( fileref - > fcb , acec - > ReparseBuffer , acec - > ReparseBufferLength , NULL , NULL , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " set_reparse_point2 returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
fileref - > deleted = true ;
fileref - > fcb - > deleted = true ;
2018-12-16 11:03:16 +00:00
if ( stream . Length = = 0 ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( parfileref - > fcb - > Header . Resource , true ) ;
2018-12-16 11:03:16 +00:00
parfileref - > fcb - > inode_item . st_size - = fileref - > dc - > utf8 . Length * 2 ;
ExReleaseResourceLite ( parfileref - > fcb - > Header . Resource ) ;
}
2019-05-11 09:20:02 +00:00
free_fileref ( fileref ) ;
2018-12-16 11:03:16 +00:00
return Status ;
}
}
acec - > OutFlags | = ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET ;
}
2020-04-23 02:38:57 +00:00
if ( acec & & acec - > InFlags & ATOMIC_CREATE_ECP_IN_FLAG_OP_FLAGS_SPECIFIED ) {
if ( acec - > InOpFlags & ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED & & fileref - > fcb - > atts & FILE_ATTRIBUTE_DIRECTORY ) {
if ( ( acec - > InCaseSensitiveFlags & acec - > CaseSensitiveFlagsMask ) & FILE_CS_FLAG_CASE_SENSITIVE_DIR ) {
acec - > OutCaseSensitiveFlags = FILE_CS_FLAG_CASE_SENSITIVE_DIR ;
fileref - > fcb - > case_sensitive = true ;
ccb - > case_sensitive = true ;
}
acec - > OutOpFlags | = ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET ;
}
acec - > OutFlags | = ATOMIC_CREATE_ECP_OUT_FLAG_OP_FLAGS_HONORED ;
}
2018-12-16 11:03:16 +00:00
fileref - > dc - > type = fileref - > fcb - > type ;
2017-09-08 08:02:43 +00:00
end :
2016-03-23 20:35:05 +00:00
if ( fpus . Buffer )
ExFreePool ( fpus . Buffer ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( parfileref & & ! loaded_related )
2019-05-11 09:20:02 +00:00
free_fileref ( parfileref ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return Status ;
}
static __inline void debug_create_options ( ULONG RequestedOptions ) {
if ( RequestedOptions ! = 0 ) {
ULONG options = RequestedOptions ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " requested options: \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options & FILE_DIRECTORY_FILE ) {
TRACE ( " FILE_DIRECTORY_FILE \n " ) ;
options & = ~ FILE_DIRECTORY_FILE ;
}
if ( options & FILE_WRITE_THROUGH ) {
TRACE ( " FILE_WRITE_THROUGH \n " ) ;
options & = ~ FILE_WRITE_THROUGH ;
}
if ( options & FILE_SEQUENTIAL_ONLY ) {
TRACE ( " FILE_SEQUENTIAL_ONLY \n " ) ;
options & = ~ FILE_SEQUENTIAL_ONLY ;
}
if ( options & FILE_NO_INTERMEDIATE_BUFFERING ) {
TRACE ( " FILE_NO_INTERMEDIATE_BUFFERING \n " ) ;
options & = ~ FILE_NO_INTERMEDIATE_BUFFERING ;
}
if ( options & FILE_SYNCHRONOUS_IO_ALERT ) {
TRACE ( " FILE_SYNCHRONOUS_IO_ALERT \n " ) ;
options & = ~ FILE_SYNCHRONOUS_IO_ALERT ;
}
if ( options & FILE_SYNCHRONOUS_IO_NONALERT ) {
TRACE ( " FILE_SYNCHRONOUS_IO_NONALERT \n " ) ;
options & = ~ FILE_SYNCHRONOUS_IO_NONALERT ;
}
if ( options & FILE_NON_DIRECTORY_FILE ) {
TRACE ( " FILE_NON_DIRECTORY_FILE \n " ) ;
options & = ~ FILE_NON_DIRECTORY_FILE ;
}
if ( options & FILE_CREATE_TREE_CONNECTION ) {
TRACE ( " FILE_CREATE_TREE_CONNECTION \n " ) ;
options & = ~ FILE_CREATE_TREE_CONNECTION ;
}
if ( options & FILE_COMPLETE_IF_OPLOCKED ) {
TRACE ( " FILE_COMPLETE_IF_OPLOCKED \n " ) ;
options & = ~ FILE_COMPLETE_IF_OPLOCKED ;
}
if ( options & FILE_NO_EA_KNOWLEDGE ) {
TRACE ( " FILE_NO_EA_KNOWLEDGE \n " ) ;
options & = ~ FILE_NO_EA_KNOWLEDGE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options & FILE_OPEN_REMOTE_INSTANCE ) {
TRACE ( " FILE_OPEN_REMOTE_INSTANCE \n " ) ;
options & = ~ FILE_OPEN_REMOTE_INSTANCE ;
}
if ( options & FILE_RANDOM_ACCESS ) {
TRACE ( " FILE_RANDOM_ACCESS \n " ) ;
options & = ~ FILE_RANDOM_ACCESS ;
}
if ( options & FILE_DELETE_ON_CLOSE ) {
TRACE ( " FILE_DELETE_ON_CLOSE \n " ) ;
options & = ~ FILE_DELETE_ON_CLOSE ;
}
if ( options & FILE_OPEN_BY_FILE_ID ) {
TRACE ( " FILE_OPEN_BY_FILE_ID \n " ) ;
options & = ~ FILE_OPEN_BY_FILE_ID ;
}
if ( options & FILE_OPEN_FOR_BACKUP_INTENT ) {
TRACE ( " FILE_OPEN_FOR_BACKUP_INTENT \n " ) ;
options & = ~ FILE_OPEN_FOR_BACKUP_INTENT ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options & FILE_NO_COMPRESSION ) {
TRACE ( " FILE_NO_COMPRESSION \n " ) ;
options & = ~ FILE_NO_COMPRESSION ;
}
# if NTDDI_VERSION >= NTDDI_WIN7
if ( options & FILE_OPEN_REQUIRING_OPLOCK ) {
TRACE ( " FILE_OPEN_REQUIRING_OPLOCK \n " ) ;
options & = ~ FILE_OPEN_REQUIRING_OPLOCK ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options & FILE_DISALLOW_EXCLUSIVE ) {
TRACE ( " FILE_DISALLOW_EXCLUSIVE \n " ) ;
options & = ~ FILE_DISALLOW_EXCLUSIVE ;
}
# endif
if ( options & FILE_RESERVE_OPFILTER ) {
TRACE ( " FILE_RESERVE_OPFILTER \n " ) ;
options & = ~ FILE_RESERVE_OPFILTER ;
}
if ( options & FILE_OPEN_REPARSE_POINT ) {
TRACE ( " FILE_OPEN_REPARSE_POINT \n " ) ;
options & = ~ FILE_OPEN_REPARSE_POINT ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options & FILE_OPEN_NO_RECALL ) {
TRACE ( " FILE_OPEN_NO_RECALL \n " ) ;
options & = ~ FILE_OPEN_NO_RECALL ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options & FILE_OPEN_FOR_FREE_SPACE_QUERY ) {
TRACE ( " FILE_OPEN_FOR_FREE_SPACE_QUERY \n " ) ;
options & = ~ FILE_OPEN_FOR_FREE_SPACE_QUERY ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( options )
2020-04-23 02:38:57 +00:00
TRACE ( " unknown options: %lx \n " , options ) ;
2016-03-23 20:35:05 +00:00
} else {
TRACE ( " requested options: (none) \n " ) ;
}
}
2019-09-01 12:53:20 +00:00
static NTSTATUS get_reparse_block ( fcb * fcb , uint8_t * * data ) {
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > type = = BTRFS_TYPE_FILE | | fcb - > type = = BTRFS_TYPE_SYMLINK ) {
ULONG size , bytes_read , i ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( fcb - > type = = BTRFS_TYPE_FILE & & fcb - > inode_item . st_size < sizeof ( ULONG ) ) {
2016-05-05 17:26:47 +00:00
WARN ( " file was too short to be a reparse point \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// 0x10007 = 0xffff (maximum length of data buffer) + 8 bytes header
2017-09-08 08:02:43 +00:00
size = ( ULONG ) min ( 0x10007 , fcb - > inode_item . st_size ) ;
if ( size = = 0 )
return STATUS_INVALID_PARAMETER ;
2016-05-05 17:26:47 +00:00
* data = ExAllocatePoolWithTag ( PagedPool , size , ALLOC_TAG ) ;
if ( ! * data ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
Status = read_file ( fcb , * data , 0 , size , & bytes_read , NULL ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " read_file_fcb returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
ExFreePool ( * data ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > type = = BTRFS_TYPE_SYMLINK ) {
2017-09-08 08:02:43 +00:00
ULONG stringlen , reqlen ;
2019-09-01 12:53:20 +00:00
uint16_t subnamelen , printnamelen ;
2016-05-05 17:26:47 +00:00
REPARSE_DATA_BUFFER * rdb ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & stringlen , ( char * ) * data , bytes_read ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
ExFreePool ( * data ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
subnamelen = printnamelen = ( USHORT ) stringlen ;
2016-05-05 17:26:47 +00:00
reqlen = offsetof ( REPARSE_DATA_BUFFER , SymbolicLinkReparseBuffer . PathBuffer ) + subnamelen + printnamelen ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
rdb = ExAllocatePoolWithTag ( PagedPool , reqlen , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! rdb ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( * data ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
rdb - > ReparseTag = IO_REPARSE_TAG_SYMLINK ;
2017-09-08 08:02:43 +00:00
rdb - > ReparseDataLength = ( USHORT ) ( reqlen - offsetof ( REPARSE_DATA_BUFFER , SymbolicLinkReparseBuffer ) ) ;
2016-05-05 17:26:47 +00:00
rdb - > Reserved = 0 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
rdb - > SymbolicLinkReparseBuffer . SubstituteNameOffset = 0 ;
rdb - > SymbolicLinkReparseBuffer . SubstituteNameLength = subnamelen ;
rdb - > SymbolicLinkReparseBuffer . PrintNameOffset = subnamelen ;
rdb - > SymbolicLinkReparseBuffer . PrintNameLength = printnamelen ;
rdb - > SymbolicLinkReparseBuffer . Flags = SYMLINK_FLAG_RELATIVE ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( & rdb - > SymbolicLinkReparseBuffer . PathBuffer [ rdb - > SymbolicLinkReparseBuffer . SubstituteNameOffset / sizeof ( WCHAR ) ] ,
2016-05-05 17:26:47 +00:00
stringlen , & stringlen , ( char * ) * data , size ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
ExFreePool ( rdb ) ;
ExFreePool ( * data ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
for ( i = 0 ; i < stringlen / sizeof ( WCHAR ) ; i + + ) {
if ( rdb - > SymbolicLinkReparseBuffer . PathBuffer [ ( rdb - > SymbolicLinkReparseBuffer . SubstituteNameOffset / sizeof ( WCHAR ) ) + i ] = = ' / ' )
rdb - > SymbolicLinkReparseBuffer . PathBuffer [ ( rdb - > SymbolicLinkReparseBuffer . SubstituteNameOffset / sizeof ( WCHAR ) ) + i ] = ' \\ ' ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( & rdb - > SymbolicLinkReparseBuffer . PathBuffer [ rdb - > SymbolicLinkReparseBuffer . PrintNameOffset / sizeof ( WCHAR ) ] ,
& rdb - > SymbolicLinkReparseBuffer . PathBuffer [ rdb - > SymbolicLinkReparseBuffer . SubstituteNameOffset / sizeof ( WCHAR ) ] ,
rdb - > SymbolicLinkReparseBuffer . SubstituteNameLength ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ExFreePool ( * data ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
* data = ( uint8_t * ) rdb ;
2016-05-05 17:26:47 +00:00
} else {
2019-09-01 12:53:20 +00:00
Status = fFsRtlValidateReparsePointBuffer ( bytes_read , ( REPARSE_DATA_BUFFER * ) * data ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " FsRtlValidateReparsePointBuffer returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
ExFreePool ( * data ) ;
return Status ;
}
}
2016-07-27 19:24:26 +00:00
} else if ( fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
if ( ! fcb - > reparse_xattr . Buffer | | fcb - > reparse_xattr . Length = = 0 )
2016-05-05 17:26:47 +00:00
return STATUS_INTERNAL_ERROR ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > reparse_xattr . Length < sizeof ( ULONG ) ) {
2016-05-05 17:26:47 +00:00
WARN ( " xattr was too short to be a reparse point \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = fFsRtlValidateReparsePointBuffer ( fcb - > reparse_xattr . Length , ( REPARSE_DATA_BUFFER * ) fcb - > reparse_xattr . Buffer ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " FsRtlValidateReparsePointBuffer returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
* data = ExAllocatePoolWithTag ( PagedPool , fcb - > reparse_xattr . Length , ALLOC_TAG ) ;
if ( ! * data ) {
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 ( * data , fcb - > reparse_xattr . Buffer , fcb - > reparse_xattr . Length ) ;
2018-12-16 11:03:16 +00:00
} else
return STATUS_INVALID_PARAMETER ;
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 void fcb_load_csums ( _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , fcb * fcb , PIRP Irp ) {
LIST_ENTRY * le ;
NTSTATUS Status ;
if ( fcb - > csum_loaded )
return ;
if ( IsListEmpty ( & fcb - > extents ) | | fcb - > inode_item . flags & BTRFS_INODE_NODATASUM )
goto end ;
le = fcb - > extents . Flink ;
while ( le ! = & fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2019-11-12 18:32:46 +00:00
if ( ! ext - > ignore & & ext - > extent_data . type = = EXTENT_TYPE_REGULAR ) {
2017-09-08 08:02:43 +00:00
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) & ext - > extent_data . data [ 0 ] ;
2019-09-01 12:53:20 +00:00
uint64_t len ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
len = ( ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE ? ed2 - > num_bytes : ed2 - > size ) > > Vcb - > sector_shift ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
ext - > csum = ExAllocatePoolWithTag ( NonPagedPool , ( ULONG ) ( len * Vcb - > csum_size ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
if ( ! ext - > csum ) {
ERR ( " out of memory \n " ) ;
goto end ;
}
Status = load_csum ( Vcb , ext - > csum , ed2 - > address + ( ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE ? ed2 - > offset : 0 ) , len , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_csum returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
}
le = le - > Flink ;
}
end :
2019-09-01 12:53:20 +00:00
fcb - > csum_loaded = true ;
2017-09-08 08:02:43 +00:00
}
2022-04-28 19:34:48 +00:00
static NTSTATUS open_file3 ( device_extension * Vcb , PIRP Irp , ACCESS_MASK granted_access , file_ref * fileref , LIST_ENTRY * rollback ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2022-04-28 19:34:48 +00:00
ULONG options = IrpSp - > Parameters . Create . Options & FILE_VALID_OPTION_FLAGS ;
ULONG RequestedDisposition = ( ( IrpSp - > Parameters . Create . Options > > 24 ) & 0xff ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
POOL_TYPE pool_type = IrpSp - > Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool ;
ccb * ccb ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:34:48 +00:00
if ( granted_access & FILE_WRITE_DATA | | options & FILE_DELETE_ON_CLOSE ) {
if ( ! MmFlushImageSection ( & fileref - > fcb - > nonpaged - > segment_object , MmFlushForWrite ) )
return ( options & FILE_DELETE_ON_CLOSE ) ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION ;
2019-11-12 18:32:46 +00:00
}
2019-05-11 09:20:02 +00:00
if ( RequestedDisposition = = FILE_OVERWRITE | | RequestedDisposition = = FILE_OVERWRITE_IF | | RequestedDisposition = = FILE_SUPERSEDE ) {
ULONG defda , oldatts , filter ;
LARGE_INTEGER time ;
BTRFS_TIME now ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:34:48 +00:00
if ( ! fileref - > fcb - > ads & & ( IrpSp - > Parameters . Create . FileAttributes & ( FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM ) ) ! = ( ( fileref - > fcb - > atts & ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ) ) )
return STATUS_ACCESS_DENIED ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( fileref - > fcb - > ads ) {
2019-09-01 12:53:20 +00:00
Status = stream_set_end_of_file_information ( Vcb , 0 , fileref - > fcb , fileref , false ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " stream_set_end_of_file_information returned %08lx \n " , Status ) ;
2022-04-28 19:34:48 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2019-05-11 09:20:02 +00:00
} else {
Status = truncate_file ( fileref - > fcb , 0 , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " truncate_file returned %08lx \n " , Status ) ;
2022-04-28 19:34:48 +00:00
return Status ;
2019-05-11 09:20:02 +00:00
}
2017-10-16 18:05:33 +00:00
}
2019-05-11 09:20:02 +00:00
if ( Irp - > Overlay . AllocationSize . QuadPart > 0 ) {
2019-09-01 12:53:20 +00:00
Status = extend_file ( fileref - > fcb , fileref , Irp - > Overlay . AllocationSize . QuadPart , true , NULL , rollback ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " extend_file returned %08lx \n " , Status ) ;
2022-04-28 19:34:48 +00:00
return Status ;
2017-09-08 08:02:43 +00:00
}
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! fileref - > fcb - > ads ) {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( Irp - > AssociatedIrp . SystemBuffer & & IrpSp - > Parameters . Create . EaLength > 0 ) {
ULONG offset ;
FILE_FULL_EA_INFORMATION * eainfo ;
2016-07-27 19:24:26 +00:00
2019-05-11 09:20:02 +00:00
Status = IoCheckEaBufferValidity ( Irp - > AssociatedIrp . SystemBuffer , IrpSp - > Parameters . Create . EaLength , & offset ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCheckEaBufferValidity returned %08lx (error at offset %lu) \n " , Status , offset ) ;
2022-04-28 19:34:48 +00:00
return Status ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
fileref - > fcb - > ealen = 4 ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
// capitalize EA name
eainfo = Irp - > AssociatedIrp . SystemBuffer ;
do {
STRING s ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
s . Length = s . MaximumLength = eainfo - > EaNameLength ;
s . Buffer = eainfo - > EaName ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
RtlUpperString ( & s , & s ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
fileref - > fcb - > ealen + = 5 + eainfo - > EaNameLength + eainfo - > EaValueLength ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( eainfo - > NextEntryOffset = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
eainfo = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) eainfo ) + eainfo - > NextEntryOffset ) ;
} while ( true ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( fileref - > fcb - > ea_xattr . Buffer )
ExFreePool ( fileref - > fcb - > ea_xattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
fileref - > fcb - > ea_xattr . Buffer = ExAllocatePoolWithTag ( pool_type , IrpSp - > Parameters . Create . EaLength , ALLOC_TAG ) ;
if ( ! fileref - > fcb - > ea_xattr . Buffer ) {
ERR ( " out of memory \n " ) ;
2022-04-28 19:34:48 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
fileref - > fcb - > ea_xattr . Length = fileref - > fcb - > ea_xattr . MaximumLength = ( USHORT ) IrpSp - > Parameters . Create . EaLength ;
RtlCopyMemory ( fileref - > fcb - > ea_xattr . Buffer , Irp - > AssociatedIrp . SystemBuffer , fileref - > fcb - > ea_xattr . Length ) ;
} else {
if ( fileref - > fcb - > ea_xattr . Length > 0 ) {
ExFreePool ( fileref - > fcb - > ea_xattr . Buffer ) ;
fileref - > fcb - > ea_xattr . Buffer = NULL ;
fileref - > fcb - > ea_xattr . Length = fileref - > fcb - > ea_xattr . MaximumLength = 0 ;
2019-09-01 12:53:20 +00:00
fileref - > fcb - > ea_changed = true ;
2019-05-11 09:20:02 +00:00
fileref - > fcb - > ealen = 0 ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
// remove streams and send notifications
le = fileref - > fcb - > dir_children_index . Flink ;
while ( le ! = & fileref - > fcb - > dir_children_index ) {
dir_child * dc = CONTAINING_RECORD ( le , dir_child , list_entry_index ) ;
LIST_ENTRY * le2 = le - > Flink ;
2016-03-23 20:35:05 +00:00
2019-05-11 09:20:02 +00:00
if ( dc - > index = = 0 ) {
if ( ! dc - > fileref ) {
file_ref * fr2 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = open_fileref_child ( Vcb , fileref , & dc - > name , true , true , true , PagedPool , & fr2 , NULL ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " open_fileref_child returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( dc - > fileref ) {
2019-11-12 18:32:46 +00:00
queue_notification_fcb ( fileref , FILE_NOTIFY_CHANGE_STREAM_NAME , FILE_ACTION_REMOVED_STREAM , & dc - > name ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = delete_fileref ( dc - > fileref , NULL , false , NULL , rollback ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_fileref returned %08lx \n " , Status ) ;
2022-04-28 19:34:48 +00:00
return Status ;
2019-05-11 09:20:02 +00:00
}
}
} else
break ;
le = le2 ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
filter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( fileref - > fcb - > ads ) {
fileref - > parent - > fcb - > inode_item . st_mtime = now ;
2019-09-01 12:53:20 +00:00
fileref - > parent - > fcb - > inode_item_changed = true ;
2019-05-11 09:20:02 +00:00
mark_fcb_dirty ( fileref - > parent - > fcb ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
queue_notification_fcb ( fileref - > parent , filter , FILE_ACTION_MODIFIED , & fileref - > dc - > name ) ;
2019-05-11 09:20:02 +00:00
} else {
mark_fcb_dirty ( fileref - > fcb ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
oldatts = fileref - > fcb - > atts ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
defda = get_file_attributes ( Vcb , fileref - > fcb - > subvol , fileref - > fcb - > inode , fileref - > fcb - > type ,
2019-09-01 12:53:20 +00:00
fileref - > dc & & fileref - > dc - > name . Length > = sizeof ( WCHAR ) & & fileref - > dc - > name . Buffer [ 0 ] = = ' . ' , true , Irp ) ;
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
if ( RequestedDisposition = = FILE_SUPERSEDE )
fileref - > fcb - > atts = IrpSp - > Parameters . Create . FileAttributes | FILE_ATTRIBUTE_ARCHIVE ;
else
fileref - > fcb - > atts | = IrpSp - > Parameters . Create . FileAttributes | FILE_ATTRIBUTE_ARCHIVE ;
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
if ( fileref - > fcb - > atts ! = oldatts ) {
2019-09-01 12:53:20 +00:00
fileref - > fcb - > atts_changed = true ;
2019-05-11 09:20:02 +00:00
fileref - > fcb - > atts_deleted = IrpSp - > Parameters . Create . FileAttributes = = defda ;
filter | = FILE_NOTIFY_CHANGE_ATTRIBUTES ;
2017-10-16 18:05:33 +00:00
}
2019-05-11 09:20:02 +00:00
fileref - > fcb - > inode_item . transid = Vcb - > superblock . generation ;
fileref - > fcb - > inode_item . sequence + + ;
fileref - > fcb - > inode_item . st_ctime = now ;
fileref - > fcb - > inode_item . st_mtime = now ;
2019-09-01 12:53:20 +00:00
fileref - > fcb - > inode_item_changed = true ;
2019-05-11 09:20:02 +00:00
2019-11-12 18:32:46 +00:00
queue_notification_fcb ( fileref , filter , FILE_ACTION_MODIFIED , NULL ) ;
2019-05-11 09:20:02 +00:00
}
} else {
if ( options & FILE_NO_EA_KNOWLEDGE & & fileref - > fcb - > ea_xattr . Length > 0 ) {
FILE_FULL_EA_INFORMATION * ffei = ( FILE_FULL_EA_INFORMATION * ) fileref - > fcb - > ea_xattr . Buffer ;
do {
if ( ffei - > Flags & FILE_NEED_EA ) {
WARN ( " returning STATUS_ACCESS_DENIED as no EA knowledge \n " ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:34:48 +00:00
return STATUS_ACCESS_DENIED ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ffei - > NextEntryOffset = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ffei = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ffei ) + ffei - > NextEntryOffset ) ;
} while ( true ) ;
2019-05-11 09:20:02 +00:00
}
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
FileObject - > FsContext = fileref - > fcb ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ccb = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( * ccb ) , ALLOC_TAG ) ;
if ( ! ccb ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:34:48 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
RtlZeroMemory ( ccb , sizeof ( * ccb ) ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ccb - > NodeType = BTRFS_NODE_TYPE_CCB ;
ccb - > NodeSize = sizeof ( * ccb ) ;
ccb - > disposition = RequestedDisposition ;
ccb - > options = options ;
ccb - > query_dir_offset = 0 ;
RtlInitUnicodeString ( & ccb - > query_string , NULL ) ;
2019-09-01 12:53:20 +00:00
ccb - > has_wildcard = false ;
ccb - > specific_file = false ;
2022-04-28 19:34:48 +00:00
ccb - > access = granted_access ;
2019-05-11 09:20:02 +00:00
ccb - > case_sensitive = IrpSp - > Flags & SL_CASE_SENSITIVE ;
2019-09-01 12:53:20 +00:00
ccb - > reserving = false ;
2019-05-11 09:20:02 +00:00
ccb - > lxss = called_from_lxss ( ) ;
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
ccb - > fileref = fileref ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
FileObject - > FsContext2 = ccb ;
FileObject - > SectionObjectPointer = & fileref - > fcb - > nonpaged - > segment_object ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
switch ( RequestedDisposition ) {
case FILE_SUPERSEDE :
Irp - > IoStatus . Information = FILE_SUPERSEDED ;
break ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
case FILE_OPEN :
case FILE_OPEN_IF :
Irp - > IoStatus . Information = FILE_OPENED ;
break ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
case FILE_OVERWRITE :
case FILE_OVERWRITE_IF :
Irp - > IoStatus . Information = FILE_OVERWRITTEN ;
break ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
// Make sure paging files don't have any extents marked as being prealloc,
// as this would mean we'd have to lock exclusively when writing.
if ( IrpSp - > Flags & SL_OPEN_PAGING_FILE ) {
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool changed = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
le = fileref - > fcb - > extents . Flink ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
while ( le ! = & fileref - > fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ext - > extent_data . type = = EXTENT_TYPE_PREALLOC ) {
ext - > extent_data . type = EXTENT_TYPE_REGULAR ;
2019-09-01 12:53:20 +00:00
changed = true ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( changed ) {
2019-09-01 12:53:20 +00:00
fileref - > fcb - > extents_changed = true ;
2019-05-11 09:20:02 +00:00
mark_fcb_dirty ( fileref - > fcb ) ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
fileref - > fcb - > Header . Flags2 | = FSRTL_FLAG2_IS_PAGING_FILE ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
LONG oc = InterlockedIncrement ( & fileref - > open_count ) ;
ERR ( " fileref %p: open_count now %i \n " , fileref , oc ) ;
# else
InterlockedIncrement ( & fileref - > open_count ) ;
# endif
InterlockedIncrement ( & Vcb - > open_files ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:34:48 +00:00
return STATUS_SUCCESS ;
}
2022-04-28 19:37:02 +00:00
static void __stdcall oplock_complete ( PVOID Context , PIRP Irp ) {
2022-04-28 19:34:48 +00:00
NTSTATUS Status ;
LIST_ENTRY rollback ;
bool skip_lock ;
oplock_context * ctx = Context ;
device_extension * Vcb = ctx - > Vcb ;
TRACE ( " (%p, %p) \n " , Context , Irp ) ;
InitializeListHead ( & rollback ) ;
skip_lock = ExIsResourceAcquiredExclusiveLite ( & Vcb - > tree_lock ) ;
if ( ! skip_lock )
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
ExAcquireResourceSharedLite ( & Vcb - > fileref_lock , true ) ;
// FIXME - trans
Status = open_file3 ( Vcb , Irp , ctx - > granted_access , ctx - > fileref , & rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
free_fileref ( ctx - > fileref ) ;
do_rollback ( ctx - > Vcb , & rollback ) ;
} else
clear_rollback ( & rollback ) ;
ExReleaseResourceLite ( & Vcb - > fileref_lock ) ;
if ( Status = = STATUS_SUCCESS ) {
fcb * fcb2 ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
bool skip_fcb_lock ;
IrpSp - > Parameters . Create . SecurityContext - > AccessState - > PreviouslyGrantedAccess | = ctx - > granted_access ;
IrpSp - > Parameters . Create . SecurityContext - > AccessState - > RemainingDesiredAccess & = ~ ( ctx - > granted_access | MAXIMUM_ALLOWED ) ;
if ( ! FileObject - > Vpb )
FileObject - > Vpb = Vcb - > devobj - > Vpb ;
fcb2 = FileObject - > FsContext ;
if ( fcb2 - > ads ) {
struct _ccb * ccb2 = FileObject - > FsContext2 ;
fcb2 = ccb2 - > fileref - > parent - > fcb ;
}
skip_fcb_lock = ExIsResourceAcquiredExclusiveLite ( fcb2 - > Header . Resource ) ;
if ( ! skip_fcb_lock )
ExAcquireResourceExclusiveLite ( fcb2 - > Header . Resource , true ) ;
fcb_load_csums ( Vcb , fcb2 , Irp ) ;
if ( ! skip_fcb_lock )
ExReleaseResourceLite ( fcb2 - > Header . Resource ) ;
}
if ( ! skip_lock )
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
// FIXME - call free_trans if failed and within transaction
Irp - > IoStatus . Status = Status ;
IoCompleteRequest ( Irp , NT_SUCCESS ( Status ) ? IO_DISK_INCREMENT : IO_NO_INCREMENT ) ;
2022-04-28 19:37:02 +00:00
ctx - > Status = Status ;
KeSetEvent ( & ctx - > event , 0 , false ) ;
2022-04-28 19:34:48 +00:00
}
static NTSTATUS open_file2 ( device_extension * Vcb , ULONG RequestedDisposition , file_ref * fileref , ACCESS_MASK * granted_access ,
2022-04-28 19:37:02 +00:00
PFILE_OBJECT FileObject , UNICODE_STRING * fn , ULONG options , PIRP Irp , LIST_ENTRY * rollback ,
oplock_context * * opctx ) {
2022-04-28 19:34:48 +00:00
NTSTATUS Status ;
file_ref * sf ;
bool readonly ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
if ( RequestedDisposition = = FILE_SUPERSEDE | | RequestedDisposition = = FILE_OVERWRITE | | RequestedDisposition = = FILE_OVERWRITE_IF ) {
LARGE_INTEGER zero ;
if ( fileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY | | is_subvol_readonly ( fileref - > fcb - > subvol , Irp ) ) {
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
if ( Vcb - > readonly ) {
Status = STATUS_MEDIA_WRITE_PROTECTED ;
goto end ;
}
zero . QuadPart = 0 ;
if ( ! MmCanFileBeTruncated ( & fileref - > fcb - > nonpaged - > segment_object , & zero ) ) {
Status = STATUS_USER_MAPPED_FILE ;
goto end ;
}
}
if ( IrpSp - > Parameters . Create . SecurityContext - > DesiredAccess ! = 0 ) {
SeLockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
if ( ! SeAccessCheck ( ( fileref - > fcb - > ads | | fileref - > fcb = = Vcb - > dummy_fcb ) ? fileref - > parent - > fcb - > sd : fileref - > fcb - > sd ,
& IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ,
true , IrpSp - > Parameters . Create . SecurityContext - > DesiredAccess , 0 , NULL ,
IoGetFileObjectGenericMapping ( ) , IrpSp - > Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp - > RequestorMode ,
granted_access , & Status ) ) {
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
TRACE ( " SeAccessCheck failed, returning %08lx \n " , Status ) ;
goto end ;
}
SeUnlockSubjectContext ( & IrpSp - > Parameters . Create . SecurityContext - > AccessState - > SubjectSecurityContext ) ;
} else
* granted_access = 0 ;
TRACE ( " deleted = %s \n " , fileref - > deleted ? " true " : " false " ) ;
sf = fileref ;
while ( sf ) {
if ( sf - > delete_on_close ) {
TRACE ( " could not open as deletion pending \n " ) ;
Status = STATUS_DELETE_PENDING ;
goto end ;
}
sf = sf - > parent ;
}
readonly = ( ! fileref - > fcb - > ads & & fileref - > fcb - > atts & FILE_ATTRIBUTE_READONLY & & ! ( IrpSp - > Flags & SL_IGNORE_READONLY_ATTRIBUTE ) ) | |
( fileref - > fcb - > ads & & fileref - > parent - > fcb - > atts & FILE_ATTRIBUTE_READONLY & & ! ( IrpSp - > Flags & SL_IGNORE_READONLY_ATTRIBUTE ) ) | |
is_subvol_readonly ( fileref - > fcb - > subvol , Irp ) | | fileref - > fcb = = Vcb - > dummy_fcb | | Vcb - > readonly ;
if ( options & FILE_DELETE_ON_CLOSE & & ( fileref = = Vcb - > root_fileref | | readonly ) ) {
Status = STATUS_CANNOT_DELETE ;
goto end ;
}
2022-04-28 19:37:02 +00:00
readonly | = fileref - > fcb - > inode_item . flags_ro & BTRFS_INODE_RO_VERITY ;
2022-04-28 19:34:48 +00:00
if ( readonly ) {
ACCESS_MASK allowed ;
allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | FILE_READ_DATA |
FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE | FILE_LIST_DIRECTORY |
FILE_TRAVERSE ;
if ( ! Vcb - > readonly & & ( fileref - > fcb = = Vcb - > dummy_fcb | | fileref - > fcb - > inode = = SUBVOL_ROOT_INODE ) )
allowed | = DELETE ;
if ( fileref - > fcb ! = Vcb - > dummy_fcb & & ! is_subvol_readonly ( fileref - > fcb - > subvol , Irp ) & & ! Vcb - > readonly ) {
allowed | = DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES ;
if ( ! fileref - > fcb - > ads & & fileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY )
allowed | = FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD ;
} else if ( fileref - > fcb - > inode = = SUBVOL_ROOT_INODE & & is_subvol_readonly ( fileref - > fcb - > subvol , Irp ) & & ! Vcb - > readonly ) {
// We allow a subvolume root to be opened read-write even if its readonly flag is set, so it can be cleared
allowed | = FILE_WRITE_ATTRIBUTES ;
}
if ( IrpSp - > Parameters . Create . SecurityContext - > DesiredAccess & MAXIMUM_ALLOWED ) {
* granted_access & = allowed ;
IrpSp - > Parameters . Create . SecurityContext - > AccessState - > PreviouslyGrantedAccess & = allowed ;
} else if ( * granted_access & ~ allowed ) {
Status = Vcb - > readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED ;
goto end ;
}
if ( RequestedDisposition = = FILE_OVERWRITE | | RequestedDisposition = = FILE_OVERWRITE_IF ) {
WARN ( " cannot overwrite readonly file \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
}
if ( ( fileref - > fcb - > type = = BTRFS_TYPE_SYMLINK | | fileref - > fcb - > atts & FILE_ATTRIBUTE_REPARSE_POINT ) & & ! ( options & FILE_OPEN_REPARSE_POINT ) ) {
REPARSE_DATA_BUFFER * data ;
/* How reparse points work from the point of view of the filesystem appears to
* undocumented . When returning STATUS_REPARSE , MSDN encourages us to return
* IO_REPARSE in Irp - > IoStatus . Information , but that means we have to do our own
* translation . If we instead return the reparse tag in Information , and store
* a pointer to the reparse data buffer in Irp - > Tail . Overlay . AuxiliaryBuffer ,
* IopSymlinkProcessReparse will do the translation for us . */
Status = get_reparse_block ( fileref - > fcb , ( uint8_t * * ) & data ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " get_reparse_block returned %08lx \n " , Status ) ;
Status = STATUS_SUCCESS ;
} else {
Irp - > IoStatus . Information = data - > ReparseTag ;
if ( fn - > Buffer [ ( fn - > Length / sizeof ( WCHAR ) ) - 1 ] = = ' \\ ' )
data - > Reserved = sizeof ( WCHAR ) ;
Irp - > Tail . Overlay . AuxiliaryBuffer = ( void * ) data ;
Status = STATUS_REPARSE ;
goto end ;
}
}
if ( fileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY & & ! fileref - > fcb - > ads ) {
if ( options & FILE_NON_DIRECTORY_FILE & & ! ( fileref - > fcb - > atts & FILE_ATTRIBUTE_REPARSE_POINT ) ) {
Status = STATUS_FILE_IS_A_DIRECTORY ;
goto end ;
}
} else if ( options & FILE_DIRECTORY_FILE ) {
TRACE ( " returning STATUS_NOT_A_DIRECTORY (type = %u) \n " , fileref - > fcb - > type ) ;
Status = STATUS_NOT_A_DIRECTORY ;
goto end ;
}
if ( fileref - > open_count > 0 ) {
oplock_context * ctx ;
Status = IoCheckShareAccess ( * granted_access , IrpSp - > Parameters . Create . ShareAccess , FileObject , & fileref - > fcb - > share_access , false ) ;
if ( ! NT_SUCCESS ( Status ) ) {
if ( Status = = STATUS_SHARING_VIOLATION )
TRACE ( " IoCheckShareAccess failed, returning %08lx \n " , Status ) ;
else
WARN ( " IoCheckShareAccess failed, returning %08lx \n " , Status ) ;
goto end ;
}
ctx = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( oplock_context ) , ALLOC_TAG ) ;
if ( ! ctx ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
ctx - > Vcb = Vcb ;
ctx - > granted_access = * granted_access ;
ctx - > fileref = fileref ;
2022-04-28 19:37:02 +00:00
KeInitializeEvent ( & ctx - > event , NotificationEvent , false ) ;
2022-04-28 19:34:48 +00:00
# ifdef __REACTOS__
Status = FsRtlCheckOplock ( fcb_oplock ( fileref - > fcb ) , Irp , ctx , ( POPLOCK_WAIT_COMPLETE_ROUTINE ) oplock_complete , NULL ) ;
# else
Status = FsRtlCheckOplock ( fcb_oplock ( fileref - > fcb ) , Irp , ctx , oplock_complete , NULL ) ;
# endif /* __REACTOS__ */
2022-04-28 19:37:02 +00:00
if ( Status = = STATUS_PENDING ) {
* opctx = ctx ;
2022-04-28 19:34:48 +00:00
return Status ;
2022-04-28 19:37:02 +00:00
}
2022-04-28 19:34:48 +00:00
ExFreePool ( ctx ) ;
if ( ! NT_SUCCESS ( Status ) ) {
WARN ( " FsRtlCheckOplock returned %08lx \n " , Status ) ;
goto end ;
}
IoUpdateShareAccess ( FileObject , & fileref - > fcb - > share_access ) ;
} else
IoSetShareAccess ( * granted_access , IrpSp - > Parameters . Create . ShareAccess , FileObject , & fileref - > fcb - > share_access ) ;
Status = open_file3 ( Vcb , Irp , * granted_access , fileref , rollback ) ;
2022-04-28 19:34:24 +00:00
if ( ! NT_SUCCESS ( Status ) )
IoRemoveShareAccess ( FileObject , & fileref - > fcb - > share_access ) ;
end :
if ( ! NT_SUCCESS ( Status ) )
free_fileref ( fileref ) ;
return Status ;
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
NTSTATUS open_fileref_by_inode ( _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) device_extension * Vcb ,
2019-09-01 12:53:20 +00:00
root * subvol , uint64_t inode , file_ref * * pfr , PIRP Irp ) {
2019-05-11 09:20:02 +00:00
NTSTATUS Status ;
fcb * fcb ;
2019-09-01 12:53:20 +00:00
uint64_t parent = 0 ;
2019-05-11 09:20:02 +00:00
UNICODE_STRING name ;
2019-09-01 12:53:20 +00:00
bool hl_alloc = false ;
2019-05-11 09:20:02 +00:00
file_ref * parfr , * fr ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = open_fcb ( Vcb , subvol , inode , 0 , NULL , true , NULL , & fcb , PagedPool , Irp ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fcb returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( fcb - > Header . Resource , true ) ;
2019-06-11 10:35:19 +00:00
if ( fcb - > inode_item . st_nlink = = 0 | | fcb - > deleted ) {
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
free_fcb ( fcb ) ;
return STATUS_OBJECT_NAME_NOT_FOUND ;
}
2019-05-11 09:20:02 +00:00
if ( fcb - > fileref ) {
* pfr = fcb - > fileref ;
increase_fileref_refcount ( fcb - > fileref ) ;
2019-06-11 10:35:19 +00:00
free_fcb ( fcb ) ;
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2019-05-11 09:20:02 +00:00
return STATUS_SUCCESS ;
}
2017-10-16 18:05:33 +00:00
2019-06-11 10:35:19 +00:00
if ( IsListEmpty ( & fcb - > hardlinks ) ) {
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > dirty_filerefs_lock , true ) ;
2019-06-11 10:35:19 +00:00
if ( ! IsListEmpty ( & Vcb - > dirty_filerefs ) ) {
LIST_ENTRY * le = Vcb - > dirty_filerefs . Flink ;
while ( le ! = & Vcb - > dirty_filerefs ) {
2019-09-01 12:53:20 +00:00
fr = CONTAINING_RECORD ( le , file_ref , list_entry_dirty ) ;
2019-06-11 10:35:19 +00:00
if ( fr - > fcb = = fcb ) {
ExReleaseResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
increase_fileref_refcount ( fr ) ;
free_fcb ( fcb ) ;
* pfr = fr ;
return STATUS_SUCCESS ;
}
le = le - > Flink ;
}
}
ExReleaseResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
{
KEY searchkey ;
traverse_ptr tp ;
searchkey . obj_id = fcb - > inode ;
searchkey . obj_type = TYPE_INODE_REF ;
searchkey . offset = 0 ;
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , subvol , & tp , & searchkey , false , Irp ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
free_fcb ( fcb ) ;
return Status ;
}
do {
traverse_ptr next_tp ;
if ( tp . item - > key . obj_id > fcb - > inode | | ( tp . item - > key . obj_id = = fcb - > inode & & tp . item - > key . obj_type > TYPE_INODE_EXTREF ) )
break ;
if ( tp . item - > key . obj_id = = fcb - > inode ) {
if ( tp . item - > key . obj_type = = TYPE_INODE_REF ) {
INODE_REF * ir = ( INODE_REF * ) tp . item - > data ;
if ( tp . item - > size < offsetof ( INODE_REF , name [ 0 ] ) | | tp . item - > size < offsetof ( INODE_REF , name [ 0 ] ) + ir - > n ) {
ERR ( " INODE_REF was too short \n " ) ;
free_fcb ( fcb ) ;
return STATUS_INTERNAL_ERROR ;
}
ULONG stringlen ;
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & stringlen , ir - > name , ir - > n ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
free_fcb ( fcb ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
name . Length = name . MaximumLength = ( uint16_t ) stringlen ;
2019-06-11 10:35:19 +00:00
if ( stringlen = = 0 )
name . Buffer = NULL ;
else {
name . Buffer = ExAllocatePoolWithTag ( PagedPool , name . MaximumLength , ALLOC_TAG ) ;
if ( ! name . Buffer ) {
ERR ( " out of memory \n " ) ;
free_fcb ( fcb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( name . Buffer , stringlen , & stringlen , ir - > name , ir - > n ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
ExFreePool ( name . Buffer ) ;
free_fcb ( fcb ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
hl_alloc = true ;
2019-06-11 10:35:19 +00:00
}
parent = tp . item - > key . offset ;
break ;
} else if ( tp . item - > key . obj_type = = TYPE_INODE_EXTREF ) {
INODE_EXTREF * ier = ( INODE_EXTREF * ) tp . item - > data ;
if ( tp . item - > size < offsetof ( INODE_EXTREF , name [ 0 ] ) | | tp . item - > size < offsetof ( INODE_EXTREF , name [ 0 ] ) + ier - > n ) {
ERR ( " INODE_EXTREF was too short \n " ) ;
free_fcb ( fcb ) ;
return STATUS_INTERNAL_ERROR ;
}
ULONG stringlen ;
2017-10-16 18:05:33 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & stringlen , ier - > name , ier - > n ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
free_fcb ( fcb ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
name . Length = name . MaximumLength = ( uint16_t ) stringlen ;
2019-06-11 10:35:19 +00:00
if ( stringlen = = 0 )
name . Buffer = NULL ;
else {
name . Buffer = ExAllocatePoolWithTag ( PagedPool , name . MaximumLength , ALLOC_TAG ) ;
if ( ! name . Buffer ) {
ERR ( " out of memory \n " ) ;
free_fcb ( fcb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( name . Buffer , stringlen , & stringlen , ier - > name , ier - > n ) ;
2019-06-11 10:35:19 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
ExFreePool ( name . Buffer ) ;
free_fcb ( fcb ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
hl_alloc = true ;
2019-06-11 10:35:19 +00:00
}
parent = ier - > dir ;
break ;
}
}
2019-09-01 12:53:20 +00:00
if ( find_next_item ( Vcb , & tp , & next_tp , false , Irp ) )
2019-06-11 10:35:19 +00:00
tp = next_tp ;
else
break ;
2019-09-01 12:53:20 +00:00
} while ( true ) ;
2019-06-11 10:35:19 +00:00
}
if ( parent = = 0 ) {
WARN ( " trying to open inode with no references \n " ) ;
free_fcb ( fcb ) ;
return STATUS_INVALID_PARAMETER ;
}
} else {
hardlink * hl = CONTAINING_RECORD ( fcb - > hardlinks . Flink , hardlink , list_entry ) ;
name = hl - > name ;
parent = hl - > parent ;
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
}
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
if ( parent = = inode ) { // subvolume root
KEY searchkey ;
traverse_ptr tp ;
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
searchkey . obj_id = subvol - > id ;
searchkey . obj_type = TYPE_ROOT_BACKREF ;
searchkey . offset = 0xffffffffffffffff ;
2017-10-16 18:05:33 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_item returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
return Status ;
}
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
if ( tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
ROOT_REF * rr = ( ROOT_REF * ) tp . item - > data ;
LIST_ENTRY * le ;
root * r = NULL ;
ULONG stringlen ;
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
if ( tp . item - > size < sizeof ( ROOT_REF ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( ROOT_REF ) ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-10-16 18:05:33 +00:00
2019-05-11 09:20:02 +00:00
if ( tp . item - > size < offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
return STATUS_INTERNAL_ERROR ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r2 = CONTAINING_RECORD ( le , root , list_entry ) ;
if ( r2 - > id = = tp . item - > key . offset ) {
r = r2 ;
break ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! r ) {
2019-09-01 12:53:20 +00:00
ERR ( " couldn't find subvol %I64x \n " , tp . item - > key . offset ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
Status = open_fileref_by_inode ( Vcb , r , rr - > dir , & parfr , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref_by_inode returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & stringlen , rr - > name , rr - > n ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 1 returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
name . Length = name . MaximumLength = ( uint16_t ) stringlen ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( stringlen = = 0 )
name . Buffer = NULL ;
else {
2019-06-11 10:35:19 +00:00
if ( hl_alloc )
ExFreePool ( name . Buffer ) ;
2019-05-11 09:20:02 +00:00
name . Buffer = ExAllocatePoolWithTag ( PagedPool , name . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! name . Buffer ) {
ERR ( " out of memory \n " ) ;
free_fcb ( fcb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
2017-09-08 08:02:43 +00:00
}
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( name . Buffer , stringlen , & stringlen , rr - > name , rr - > n ) ;
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 2 returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
ExFreePool ( name . Buffer ) ;
free_fcb ( fcb ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
hl_alloc = true ;
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
} else {
2019-11-12 18:32:46 +00:00
if ( ! Vcb - > options . no_root_dir & & subvol - > id = = BTRFS_ROOT_FSTREE & & Vcb - > root_fileref - > fcb - > subvol ! = subvol ) {
Status = open_fileref_by_inode ( Vcb , Vcb - > root_fileref - > fcb - > subvol , SUBVOL_ROOT_INODE , & parfr , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref_by_inode returned %08lx \n " , Status ) ;
2019-11-12 18:32:46 +00:00
free_fcb ( fcb ) ;
return Status ;
}
name . Length = name . MaximumLength = sizeof ( root_dir_utf16 ) - sizeof ( WCHAR ) ;
name . Buffer = ( WCHAR * ) root_dir_utf16 ;
} else {
ERR ( " couldn't find parent for subvol %I64x \n " , subvol - > id ) ;
free_fcb ( fcb ) ;
return STATUS_INTERNAL_ERROR ;
}
2019-05-11 09:20:02 +00:00
}
} else {
Status = open_fileref_by_inode ( Vcb , subvol , parent , & parfr , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref_by_inode returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = open_fileref_child ( Vcb , parfr , & name , true , true , false , PagedPool , & fr , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( hl_alloc )
ExFreePool ( name . Buffer ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref_child returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
free_fileref ( parfr ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
* pfr = fr ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
free_fileref ( parfr ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:37:02 +00:00
static NTSTATUS open_file ( PDEVICE_OBJECT DeviceObject , _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , PIRP Irp ,
LIST_ENTRY * rollback , oplock_context * * opctx ) {
2019-05-11 09:20:02 +00:00
PFILE_OBJECT FileObject = NULL ;
ULONG RequestedDisposition ;
ULONG options ;
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
USHORT parsed ;
ULONG fn_offset = 0 ;
file_ref * related , * fileref = NULL ;
POOL_TYPE pool_type = IrpSp - > Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool ;
ACCESS_MASK granted_access ;
2019-09-01 12:53:20 +00:00
bool loaded_related = false ;
2019-05-11 09:20:02 +00:00
UNICODE_STRING fn ;
Irp - > IoStatus . Information = 0 ;
RequestedDisposition = ( ( IrpSp - > Parameters . Create . Options > > 24 ) & 0xff ) ;
options = IrpSp - > Parameters . Create . Options & FILE_VALID_OPTION_FLAGS ;
if ( options & FILE_DIRECTORY_FILE & & RequestedDisposition = = FILE_SUPERSEDE ) {
WARN ( " error - supersede requested with FILE_DIRECTORY_FILE \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
FileObject = IrpSp - > FileObject ;
if ( ! FileObject ) {
ERR ( " FileObject was NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( FileObject - > RelatedFileObject & & FileObject - > RelatedFileObject - > FsContext2 ) {
struct _ccb * relatedccb = FileObject - > RelatedFileObject - > FsContext2 ;
related = relatedccb - > fileref ;
} else
related = NULL ;
debug_create_options ( options ) ;
switch ( RequestedDisposition ) {
case FILE_SUPERSEDE :
TRACE ( " requested disposition: FILE_SUPERSEDE \n " ) ;
break ;
case FILE_CREATE :
TRACE ( " requested disposition: FILE_CREATE \n " ) ;
break ;
case FILE_OPEN :
TRACE ( " requested disposition: FILE_OPEN \n " ) ;
break ;
case FILE_OPEN_IF :
TRACE ( " requested disposition: FILE_OPEN_IF \n " ) ;
break ;
case FILE_OVERWRITE :
TRACE ( " requested disposition: FILE_OVERWRITE \n " ) ;
break ;
case FILE_OVERWRITE_IF :
TRACE ( " requested disposition: FILE_OVERWRITE_IF \n " ) ;
break ;
default :
2020-04-23 02:38:57 +00:00
ERR ( " unknown disposition: %lx \n " , RequestedDisposition ) ;
2019-05-11 09:20:02 +00:00
Status = STATUS_NOT_IMPLEMENTED ;
goto exit ;
}
fn = FileObject - > FileName ;
2020-04-23 02:38:57 +00:00
TRACE ( " (%.*S) \n " , ( int ) ( fn . Length / sizeof ( WCHAR ) ) , fn . Buffer ) ;
2019-05-11 09:20:02 +00:00
TRACE ( " FileObject = %p \n " , FileObject ) ;
if ( Vcb - > readonly & & ( RequestedDisposition = = FILE_SUPERSEDE | | RequestedDisposition = = FILE_CREATE | | RequestedDisposition = = FILE_OVERWRITE ) ) {
Status = STATUS_MEDIA_WRITE_PROTECTED ;
goto exit ;
}
if ( options & FILE_OPEN_BY_FILE_ID ) {
2019-06-11 10:35:19 +00:00
if ( RequestedDisposition ! = FILE_OPEN ) {
WARN ( " FILE_OPEN_BY_FILE_ID not supported for anything other than FILE_OPEN \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
2019-09-01 12:53:20 +00:00
if ( fn . Length = = sizeof ( uint64_t ) ) {
uint64_t inode ;
2019-05-11 09:20:02 +00:00
2019-06-11 10:35:19 +00:00
if ( ! related ) {
2022-09-28 16:08:10 +00:00
WARN ( " cannot open by short file ID unless related fileref also provided " \ n ) ;
2019-06-11 10:35:19 +00:00
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
2020-04-23 02:38:57 +00:00
inode = ( * ( uint64_t * ) fn . Buffer ) & 0xffffffffff ;
2019-05-11 09:20:02 +00:00
if ( related - > fcb = = Vcb - > root_fileref - > fcb & & inode = = 0 )
inode = Vcb - > root_fileref - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( inode = = 0 ) { // we use 0 to mean the parent of a subvolume
fileref = related - > parent ;
increase_fileref_refcount ( fileref ) ;
Status = STATUS_SUCCESS ;
} else
Status = open_fileref_by_inode ( Vcb , related - > fcb - > subvol , inode , & fileref , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
goto loaded ;
} else if ( fn . Length = = sizeof ( FILE_ID_128 ) ) {
2019-09-01 12:53:20 +00:00
uint64_t inode , subvol_id ;
2019-06-11 10:35:19 +00:00
root * subvol = NULL ;
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & inode , fn . Buffer , sizeof ( uint64_t ) ) ;
RtlCopyMemory ( & subvol_id , ( uint8_t * ) fn . Buffer + sizeof ( uint64_t ) , sizeof ( uint64_t ) ) ;
2019-06-11 10:35:19 +00:00
if ( subvol_id = = BTRFS_ROOT_FSTREE | | ( subvol_id > = 0x100 & & subvol_id < 0x8000000000000000 ) ) {
LIST_ENTRY * le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
if ( r - > id = = subvol_id ) {
subvol = r ;
break ;
}
le = le - > Flink ;
}
}
if ( ! subvol ) {
2019-09-01 12:53:20 +00:00
WARN ( " subvol %I64x not found \n " , subvol_id ) ;
2019-06-11 10:35:19 +00:00
Status = STATUS_OBJECT_NAME_NOT_FOUND ;
} else
Status = open_fileref_by_inode ( Vcb , subvol , inode , & fileref , Irp ) ;
2019-05-11 09:20:02 +00:00
goto loaded ;
} else {
2019-06-11 10:35:19 +00:00
WARN ( " invalid ID size for FILE_OPEN_BY_FILE_ID \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( related & & fn . Length ! = 0 & & fn . Buffer [ 0 ] = = ' \\ ' ) {
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! related & & RequestedDisposition ! = FILE_OPEN & & ! ( IrpSp - > Flags & SL_OPEN_TARGET_DIRECTORY ) ) {
ULONG fnoff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = open_fileref ( Vcb , & related , & fn , NULL , true , & parsed , & fnoff ,
2019-05-11 09:20:02 +00:00
pool_type , IrpSp - > Flags & SL_CASE_SENSITIVE , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( Status = = STATUS_OBJECT_NAME_NOT_FOUND )
Status = STATUS_OBJECT_PATH_NOT_FOUND ;
else if ( Status = = STATUS_REPARSE )
fileref = related ;
else if ( NT_SUCCESS ( Status ) ) {
fnoff * = sizeof ( WCHAR ) ;
fnoff + = ( related - > dc ? related - > dc - > name . Length : 0 ) + sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( related - > fcb - > atts & FILE_ATTRIBUTE_REPARSE_POINT ) {
Status = STATUS_REPARSE ;
fileref = related ;
parsed = ( USHORT ) fnoff - sizeof ( WCHAR ) ;
} else {
fn . Buffer = & fn . Buffer [ fnoff / sizeof ( WCHAR ) ] ;
fn . Length - = ( USHORT ) fnoff ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
Status = open_fileref ( Vcb , & fileref , & fn , related , IrpSp - > Flags & SL_OPEN_TARGET_DIRECTORY , & parsed , & fn_offset ,
pool_type , IrpSp - > Flags & SL_CASE_SENSITIVE , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
loaded_related = true ;
2016-03-23 20:35:05 +00:00
}
}
2019-05-11 09:20:02 +00:00
} else {
Status = open_fileref ( Vcb , & fileref , & fn , related , IrpSp - > Flags & SL_OPEN_TARGET_DIRECTORY , & parsed , & fn_offset ,
pool_type , IrpSp - > Flags & SL_CASE_SENSITIVE , Irp ) ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
loaded :
if ( Status = = STATUS_REPARSE ) {
REPARSE_DATA_BUFFER * data ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( fileref - > fcb - > Header . Resource , true ) ;
Status = get_reparse_block ( fileref - > fcb , ( uint8_t * * ) & data ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " get_reparse_block returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
Status = STATUS_SUCCESS ;
} else {
Status = STATUS_REPARSE ;
RtlCopyMemory ( & Irp - > IoStatus . Information , data , sizeof ( ULONG ) ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
data - > Reserved = FileObject - > FileName . Length - parsed ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
Irp - > Tail . Overlay . AuxiliaryBuffer = ( void * ) data ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_fileref ( fileref ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
goto exit ;
}
}
if ( NT_SUCCESS ( Status ) & & fileref - > deleted )
Status = STATUS_OBJECT_NAME_NOT_FOUND ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( NT_SUCCESS ( Status ) ) {
if ( RequestedDisposition = = FILE_CREATE ) {
2019-11-12 18:32:46 +00:00
TRACE ( " file already exists, returning STATUS_OBJECT_NAME_COLLISION \n " ) ;
2019-05-11 09:20:02 +00:00
Status = STATUS_OBJECT_NAME_COLLISION ;
free_fileref ( fileref ) ;
goto exit ;
2016-10-29 17:05:10 +00:00
}
2019-05-11 09:20:02 +00:00
} else if ( Status = = STATUS_OBJECT_NAME_NOT_FOUND ) {
if ( RequestedDisposition = = FILE_OPEN | | RequestedDisposition = = FILE_OVERWRITE ) {
TRACE ( " file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND \n " ) ;
goto exit ;
}
2022-04-28 19:35:05 +00:00
} else if ( Status = = STATUS_OBJECT_PATH_NOT_FOUND | | Status = = STATUS_OBJECT_NAME_INVALID ) {
2020-04-23 02:38:57 +00:00
TRACE ( " open_fileref returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
goto exit ;
} else {
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:37:02 +00:00
if ( NT_SUCCESS ( Status ) ) { // file already exists
Status = open_file2 ( Vcb , RequestedDisposition , fileref , & granted_access , FileObject , & fn ,
options , Irp , rollback , opctx ) ;
} else {
2022-04-28 19:33:48 +00:00
file_ref * existing_file = NULL ;
2019-05-11 09:20:02 +00:00
Status = file_create ( Irp , Vcb , FileObject , related , loaded_related , & fn , RequestedDisposition , options , & existing_file , rollback ) ;
if ( Status = = STATUS_OBJECT_NAME_COLLISION ) { // already exists
fileref = existing_file ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:37:02 +00:00
Status = open_file2 ( Vcb , RequestedDisposition , fileref , & granted_access , FileObject , & fn ,
options , Irp , rollback , opctx ) ;
2019-05-11 09:20:02 +00:00
} else {
Irp - > IoStatus . Information = NT_SUCCESS ( Status ) ? FILE_CREATED : 0 ;
granted_access = IrpSp - > Parameters . Create . SecurityContext - > DesiredAccess ;
}
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 ( NT_SUCCESS ( Status ) & & ! ( options & FILE_NO_INTERMEDIATE_BUFFERING ) )
FileObject - > Flags | = FO_CACHE_SUPPORTED ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit :
2019-05-11 09:20:02 +00:00
if ( loaded_related )
free_fileref ( related ) ;
2017-09-08 08:02:43 +00:00
if ( Status = = STATUS_SUCCESS ) {
fcb * fcb2 ;
IrpSp - > Parameters . Create . SecurityContext - > AccessState - > PreviouslyGrantedAccess | = granted_access ;
IrpSp - > Parameters . Create . SecurityContext - > AccessState - > RemainingDesiredAccess & = ~ ( granted_access | MAXIMUM_ALLOWED ) ;
2016-03-23 20:35:05 +00:00
if ( ! FileObject - > Vpb )
FileObject - > Vpb = DeviceObject - > Vpb ;
2017-09-08 08:02:43 +00:00
fcb2 = FileObject - > FsContext ;
if ( fcb2 - > ads ) {
struct _ccb * ccb2 = FileObject - > FsContext2 ;
fcb2 = ccb2 - > fileref - > parent - > fcb ;
}
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fcb2 - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
fcb_load_csums ( Vcb , fcb2 , Irp ) ;
ExReleaseResourceLite ( fcb2 - > Header . Resource ) ;
} else if ( Status ! = STATUS_REPARSE & & Status ! = STATUS_OBJECT_NAME_NOT_FOUND & & Status ! = STATUS_OBJECT_PATH_NOT_FOUND )
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
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
static NTSTATUS verify_vcb ( device_extension * Vcb , PIRP Irp ) {
2017-01-01 17:12:12 +00:00
NTSTATUS Status ;
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool need_verify = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , 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 * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( dev - > devobj & & dev - > removable ) {
2016-09-04 15:27:46 +00:00
ULONG cc ;
IO_STATUS_BLOCK iosb ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = dev_ioctl ( dev - > devobj , IOCTL_STORAGE_CHECK_VERIFY , NULL , 0 , & cc , sizeof ( ULONG ) , true , & iosb ) ;
2017-09-08 08:02:43 +00:00
if ( IoIsErrorUserInduced ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IOCTL_STORAGE_CHECK_VERIFY returned %08lx (user-induced) \n " , Status ) ;
2019-09-01 12:53:20 +00:00
need_verify = true ;
2017-09-08 08:02:43 +00:00
} else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IOCTL_STORAGE_CHECK_VERIFY returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto end ;
2017-09-08 08:02:43 +00:00
} else if ( iosb . Information < sizeof ( ULONG ) ) {
2016-09-04 15:27:46 +00:00
ERR ( " iosb.Information was too short \n " ) ;
2017-01-01 17:12:12 +00:00
Status = STATUS_INTERNAL_ERROR ;
2017-09-08 08:02:43 +00:00
} else if ( cc ! = dev - > change_count ) {
2017-01-01 17:12:12 +00:00
dev - > devobj - > Flags | = DO_VERIFY_VOLUME ;
2019-09-01 12:53:20 +00:00
need_verify = true ;
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
2017-01-01 17:12:12 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
end :
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2017-09-08 08:02:43 +00:00
if ( need_verify ) {
PDEVICE_OBJECT devobj ;
devobj = IoGetDeviceToVerify ( Irp - > Tail . Overlay . Thread ) ;
IoSetDeviceToVerify ( Irp - > Tail . Overlay . Thread , NULL ) ;
if ( ! devobj ) {
devobj = IoGetDeviceToVerify ( PsGetCurrentThread ( ) ) ;
IoSetDeviceToVerify ( PsGetCurrentThread ( ) , NULL ) ;
}
devobj = Vcb - > Vpb ? Vcb - > Vpb - > RealDevice : NULL ;
if ( devobj )
2019-09-01 12:53:20 +00:00
Status = IoVerifyVolume ( devobj , false ) ;
2017-09-08 08:02:43 +00:00
else
Status = STATUS_VERIFY_REQUIRED ;
}
2017-01-01 17:12:12 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
static bool has_manage_volume_privilege ( ACCESS_STATE * access_state , KPROCESSOR_MODE processor_mode ) {
2017-01-01 17:12:12 +00:00
PRIVILEGE_SET privset ;
privset . PrivilegeCount = 1 ;
privset . Control = PRIVILEGE_SET_ALL_NECESSARY ;
privset . Privilege [ 0 ] . Luid = RtlConvertLongToLuid ( SE_MANAGE_VOLUME_PRIVILEGE ) ;
privset . Privilege [ 0 ] . Attributes = 0 ;
2019-09-01 12:53:20 +00:00
return SePrivilegeCheck ( & privset , & access_state - > SubjectSecurityContext , processor_mode ) ? true : false ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_CREATE )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
NTSTATUS __stdcall drv_create ( 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 ;
2019-09-01 12:53:20 +00:00
bool top_level , locked = false ;
2022-04-28 19:37:02 +00:00
oplock_context * opctx = NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " create (flags = %lx) \n " , Irp - > Flags ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
/* return success if just called for FS device object */
2017-09-08 08:02:43 +00:00
if ( DeviceObject = = master_devobj ) {
2016-03-23 20:35:05 +00:00
TRACE ( " create called for FS device object \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Information = FILE_OPENED ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto exit ;
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_create ( DeviceObject , Irp ) ;
goto exit ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
if ( ! ( Vcb - > Vpb - > Flags & VPB_MOUNTED ) ) {
Status = STATUS_DEVICE_NOT_READY ;
goto exit ;
}
if ( Vcb - > removing ) {
Status = STATUS_ACCESS_DENIED ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = verify_vcb ( Vcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " verify_vcb returned %08lx \n " , Status ) ;
2016-09-04 15:27:46 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > load_lock , true ) ;
locked = true ;
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
if ( IrpSp - > Flags ! = 0 ) {
2019-09-01 12:53:20 +00:00
uint32_t flags = IrpSp - > Flags ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " flags: \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( flags & SL_CASE_SENSITIVE ) {
TRACE ( " SL_CASE_SENSITIVE \n " ) ;
flags & = ~ SL_CASE_SENSITIVE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( flags & SL_FORCE_ACCESS_CHECK ) {
TRACE ( " SL_FORCE_ACCESS_CHECK \n " ) ;
flags & = ~ SL_FORCE_ACCESS_CHECK ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( flags & SL_OPEN_PAGING_FILE ) {
TRACE ( " SL_OPEN_PAGING_FILE \n " ) ;
flags & = ~ SL_OPEN_PAGING_FILE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( flags & SL_OPEN_TARGET_DIRECTORY ) {
TRACE ( " SL_OPEN_TARGET_DIRECTORY \n " ) ;
flags & = ~ SL_OPEN_TARGET_DIRECTORY ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( flags & SL_STOP_ON_SYMLINK ) {
TRACE ( " SL_STOP_ON_SYMLINK \n " ) ;
flags & = ~ SL_STOP_ON_SYMLINK ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( flags & SL_IGNORE_READONLY_ATTRIBUTE ) {
TRACE ( " SL_IGNORE_READONLY_ATTRIBUTE \n " ) ;
flags & = ~ SL_IGNORE_READONLY_ATTRIBUTE ;
}
2016-03-23 20:35:05 +00:00
if ( flags )
WARN ( " unknown flags: %x \n " , flags ) ;
} else {
TRACE ( " flags: (none) \n " ) ;
}
2017-09-08 08:02:43 +00:00
if ( ! IrpSp - > FileObject ) {
ERR ( " FileObject was NULL \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
if ( IrpSp - > FileObject - > RelatedFileObject ) {
fcb * relatedfcb = IrpSp - > FileObject - > RelatedFileObject - > FsContext ;
if ( relatedfcb & & relatedfcb - > Vcb ! = Vcb ) {
WARN ( " RelatedFileObject was for different device \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
}
2016-03-23 20:35:05 +00:00
// opening volume
if ( IrpSp - > FileObject - > FileName . Length = = 0 & & ! IrpSp - > FileObject - > RelatedFileObject ) {
ULONG RequestedDisposition = ( ( IrpSp - > Parameters . Create . Options > > 24 ) & 0xff ) ;
ULONG RequestedOptions = IrpSp - > Parameters . Create . Options & FILE_VALID_OPTION_FLAGS ;
2016-05-05 17:26:47 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2017-09-08 08:02:43 +00:00
LONG rc ;
2016-05-05 17:26:47 +00:00
# endif
2017-01-01 17:12:12 +00:00
ccb * ccb ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " open operation for volume \n " ) ;
2017-01-01 17:12:12 +00:00
if ( RequestedDisposition ! = FILE_OPEN & & RequestedDisposition ! = FILE_OPEN_IF ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_ACCESS_DENIED ;
goto exit ;
}
2017-01-01 17:12:12 +00:00
if ( RequestedOptions & FILE_DIRECTORY_FILE ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_NOT_A_DIRECTORY ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ccb = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( * ccb ) , ALLOC_TAG ) ;
if ( ! ccb ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( ccb , sizeof ( * ccb ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ccb - > NodeType = BTRFS_NODE_TYPE_CCB ;
2017-09-08 08:02:43 +00:00
ccb - > NodeSize = sizeof ( * ccb ) ;
2017-01-01 17:12:12 +00:00
ccb - > disposition = RequestedDisposition ;
ccb - > options = RequestedOptions ;
ccb - > access = IrpSp - > Parameters . Create . SecurityContext - > AccessState - > PreviouslyGrantedAccess ;
ccb - > manage_volume_privilege = has_manage_volume_privilege ( IrpSp - > Parameters . Create . SecurityContext - > AccessState ,
IrpSp - > Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp - > RequestorMode ) ;
2019-09-01 12:53:20 +00:00
ccb - > reserving = false ;
2017-09-08 08:02:43 +00:00
ccb - > lxss = called_from_lxss ( ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2016-03-26 11:53:07 +00:00
rc = InterlockedIncrement ( & Vcb - > volume_fcb - > refcount ) ;
WARN ( " fcb %p: refcount now %i (volume) \n " , Vcb - > volume_fcb , rc ) ;
2016-05-05 17:26:47 +00:00
# else
InterlockedIncrement ( & Vcb - > volume_fcb - > refcount ) ;
2016-03-23 20:35:05 +00:00
# endif
2016-05-05 17:26:47 +00:00
IrpSp - > FileObject - > FsContext = Vcb - > volume_fcb ;
2017-01-01 17:12:12 +00:00
IrpSp - > FileObject - > FsContext2 = ccb ;
2017-09-08 08:02:43 +00:00
2016-03-26 11:53:07 +00:00
IrpSp - > FileObject - > SectionObjectPointer = & Vcb - > volume_fcb - > nonpaged - > segment_object ;
2016-07-27 19:24:26 +00:00
if ( ! IrpSp - > FileObject - > Vpb )
IrpSp - > FileObject - > Vpb = DeviceObject - > Vpb ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InterlockedIncrement ( & Vcb - > open_files ) ;
2016-07-27 19:24:26 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Information = FILE_OPENED ;
Status = STATUS_SUCCESS ;
} else {
2017-09-08 08:02:43 +00:00
LIST_ENTRY rollback ;
2019-09-01 12:53:20 +00:00
bool skip_lock ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & rollback ) ;
2020-04-23 02:38:57 +00:00
TRACE ( " file name: %.*S \n " , ( int ) ( IrpSp - > FileObject - > FileName . Length / sizeof ( WCHAR ) ) , IrpSp - > FileObject - > FileName . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( IrpSp - > FileObject - > RelatedFileObject )
2019-11-12 18:32:46 +00:00
TRACE ( " related file = %p \n " , IrpSp - > FileObject - > RelatedFileObject ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// Don't lock again if we're being called from within CcCopyRead etc.
skip_lock = ExIsResourceAcquiredExclusiveLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
if ( ! skip_lock )
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > fileref_lock , true ) ;
2019-05-11 09:20:02 +00:00
2022-04-28 19:37:02 +00:00
Status = open_file ( DeviceObject , Vcb , Irp , & rollback , & opctx ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) )
2016-03-23 20:35:05 +00:00
do_rollback ( Vcb , & rollback ) ;
else
2017-09-08 08:02:43 +00:00
clear_rollback ( & rollback ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & Vcb - > fileref_lock ) ;
2016-05-05 17:26:47 +00:00
if ( ! skip_lock )
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit :
2022-04-28 19:37:02 +00:00
if ( Status ! = STATUS_PENDING ) {
Irp - > IoStatus . Status = Status ;
2022-04-28 19:34:48 +00:00
IoCompleteRequest ( Irp , NT_SUCCESS ( Status ) ? IO_DISK_INCREMENT : IO_NO_INCREMENT ) ;
2022-04-28 19:37:02 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( locked )
ExReleaseResourceLite ( & Vcb - > load_lock ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:37:02 +00:00
if ( Status = = STATUS_PENDING ) {
KeWaitForSingleObject ( & opctx - > event , Executive , KernelMode , false , NULL ) ;
Status = opctx - > Status ;
ExFreePool ( opctx ) ;
}
TRACE ( " create returning %08lx \n " , Status ) ;
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 ;
}