2016-03-23 20:35:05 +00:00
/* Copyright (c) Mark Harmstone 2016
*
* This file is part of WinBtrfs .
*
* WinBtrfs is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation , either version 3 of the Licence , or
* ( at your option ) any later version .
*
* WinBtrfs is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public Licence for more details .
*
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs . If not , see < http : //www.gnu.org/licenses/>. */
# include "btrfs_drv.h"
enum DirEntryType {
DirEntryType_File ,
DirEntryType_Self ,
DirEntryType_Parent
} ;
typedef struct {
KEY key ;
2016-07-27 19:24:26 +00:00
BOOL name_alloc ;
2016-03-23 20:35:05 +00:00
char * name ;
ULONG namelen ;
UINT8 type ;
enum DirEntryType dir_entry_type ;
} dir_entry ;
2016-07-27 19:24:26 +00:00
static ULONG STDCALL get_reparse_tag ( device_extension * Vcb , root * subvol , UINT64 inode , UINT8 type , ULONG atts ) {
fcb * fcb ;
ULONG tag = 0 , br ;
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
// FIXME - will this slow things down?
if ( type = = BTRFS_TYPE_SYMLINK )
return IO_REPARSE_TAG_SYMLINK ;
if ( type ! = BTRFS_TYPE_FILE & & type ! = BTRFS_TYPE_DIRECTORY )
return 0 ;
2016-07-27 19:24:26 +00:00
if ( ! ( atts & FILE_ATTRIBUTE_REPARSE_POINT ) )
return 0 ;
2016-05-05 17:26:47 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > fcb_lock , TRUE ) ;
Status = open_fcb ( Vcb , subvol , inode , type , NULL , NULL , & fcb ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " open_fcb returned %08x \n " , Status ) ;
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
2016-05-05 17:26:47 +00:00
return 0 ;
2016-07-27 19:24:26 +00:00
}
ExReleaseResourceLite ( & Vcb - > fcb_lock ) ;
ExAcquireResourceSharedLite ( fcb - > Header . Resource , TRUE ) ;
2016-05-05 17:26:47 +00:00
if ( type = = BTRFS_TYPE_DIRECTORY ) {
2016-07-27 19:24:26 +00:00
if ( ! fcb - > reparse_xattr . Buffer | | fcb - > reparse_xattr . Length < sizeof ( ULONG ) )
goto end ;
2016-05-05 17:26:47 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( & tag , fcb - > reparse_xattr . Buffer , sizeof ( ULONG ) ) ;
2016-05-05 17:26:47 +00:00
} else {
2016-07-27 19:24:26 +00:00
Status = read_file ( fcb , ( UINT8 * ) & tag , 0 , sizeof ( ULONG ) , & br , NULL ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " read_file returned %08x \n " , Status ) ;
2016-07-27 19:24:26 +00:00
goto end ;
2016-05-05 17:26:47 +00:00
}
if ( br < sizeof ( ULONG ) )
2016-07-27 19:24:26 +00:00
goto end ;
2016-05-05 17:26:47 +00:00
}
2016-07-27 19:24:26 +00:00
end :
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
free_fcb ( fcb ) ;
2016-05-05 17:26:47 +00:00
return tag ;
}
static NTSTATUS STDCALL query_dir_item ( fcb * fcb , file_ref * fileref , void * buf , LONG * len , PIRP Irp , dir_entry * de , root * r ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp ;
UINT32 needed ;
UINT64 inode ;
INODE_ITEM ii ;
NTSTATUS Status ;
ULONG stringlen ;
2016-07-27 19:24:26 +00:00
ULONG atts ;
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
if ( de - > key . obj_type = = TYPE_ROOT_ITEM ) { // subvol
2016-05-05 17:26:47 +00:00
LIST_ENTRY * le ;
r = NULL ;
le = fcb - > Vcb - > roots . Flink ;
while ( le ! = & fcb - > Vcb - > roots ) {
root * subvol = CONTAINING_RECORD ( le , root , list_entry ) ;
if ( subvol - > id = = de - > key . obj_id ) {
r = subvol ;
break ;
}
le = le - > Flink ;
}
2016-03-23 20:35:05 +00:00
if ( ! r ) {
ERR ( " could not find root %llx \n " , de - > key . obj_id ) ;
return STATUS_OBJECT_NAME_NOT_FOUND ;
}
inode = SUBVOL_ROOT_INODE ;
} else {
inode = de - > key . obj_id ;
}
if ( IrpSp - > Parameters . QueryDirectory . FileInformationClass ! = FileNamesInformation ) { // FIXME - object ID and reparse point classes too?
switch ( de - > dir_entry_type ) {
case DirEntryType_File :
{
LIST_ENTRY * le ;
BOOL found = FALSE ;
2016-07-27 19:24:26 +00:00
ExAcquireResourceSharedLite ( & fcb - > Vcb - > fcb_lock , TRUE ) ;
if ( ! IsListEmpty ( & r - > fcbs ) ) {
le = r - > fcbs . Flink ;
while ( le ! = & r - > fcbs ) {
struct _fcb * fcb2 = CONTAINING_RECORD ( le , struct _fcb , list_entry ) ;
2016-05-05 17:26:47 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb2 - > inode = = inode & & ! fcb2 - > ads ) {
ii = fcb2 - > inode_item ;
atts = fcb2 - > atts ;
2016-05-05 17:26:47 +00:00
found = TRUE ;
break ;
}
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
}
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fcb_lock ) ;
2016-03-23 20:35:05 +00:00
if ( ! found ) {
KEY searchkey ;
traverse_ptr tp ;
searchkey . obj_id = inode ;
searchkey . obj_type = TYPE_INODE_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
Status = find_item ( fcb - > Vcb , r , & tp , & searchkey , FALSE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
return Status ;
}
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
ERR ( " could not find inode item for inode %llx in root %llx \n " , inode , r - > id ) ;
return STATUS_INTERNAL_ERROR ;
}
RtlZeroMemory ( & ii , sizeof ( INODE_ITEM ) ) ;
if ( tp . item - > size > 0 )
RtlCopyMemory ( & ii , tp . item - > data , min ( sizeof ( INODE_ITEM ) , tp . item - > size ) ) ;
2016-07-27 19:24:26 +00:00
if ( IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileBothDirectoryInformation | |
IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileDirectoryInformation | |
IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileFullDirectoryInformation | |
IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileIdBothDirectoryInformation ) {
BOOL dotfile = de - > namelen > 1 & & de - > name [ 0 ] = = ' . ' ;
atts = get_file_attributes ( fcb - > Vcb , & ii , r , inode , de - > type , dotfile , FALSE ) ;
}
2016-03-23 20:35:05 +00:00
}
break ;
}
case DirEntryType_Self :
ii = fcb - > inode_item ;
r = fcb - > subvol ;
inode = fcb - > inode ;
2016-07-27 19:24:26 +00:00
atts = fcb - > atts ;
2016-03-23 20:35:05 +00:00
break ;
case DirEntryType_Parent :
2016-05-05 17:26:47 +00:00
if ( fileref & & fileref - > parent ) {
ii = fileref - > parent - > fcb - > inode_item ;
r = fileref - > parent - > fcb - > subvol ;
inode = fileref - > parent - > fcb - > inode ;
2016-07-27 19:24:26 +00:00
atts = fileref - > parent - > fcb - > atts ;
2016-05-05 17:26:47 +00:00
} else {
ERR ( " no fileref \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2016-03-23 20:35:05 +00:00
break ;
}
}
// FICs which return the filename
if ( IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileBothDirectoryInformation | |
IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileDirectoryInformation | |
IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileFullDirectoryInformation | |
IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileIdBothDirectoryInformation | |
IrpSp - > Parameters . QueryDirectory . FileInformationClass = = FileNamesInformation ) {
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & stringlen , de - > name , de - > namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
return Status ;
}
}
switch ( IrpSp - > Parameters . QueryDirectory . FileInformationClass ) {
case FileBothDirectoryInformation :
{
FILE_BOTH_DIR_INFORMATION * fbdi = buf ;
TRACE ( " FileBothDirectoryInformation \n " ) ;
needed = sizeof ( FILE_BOTH_DIR_INFORMATION ) - sizeof ( WCHAR ) + stringlen ;
if ( needed > * len ) {
2016-07-27 19:24:26 +00:00
TRACE ( " buffer overflow - %u > %u \n " , needed , * len ) ;
2016-03-23 20:35:05 +00:00
return STATUS_BUFFER_OVERFLOW ;
}
fbdi - > NextEntryOffset = 0 ;
fbdi - > FileIndex = 0 ;
fbdi - > CreationTime . QuadPart = unix_time_to_win ( & ii . otime ) ;
fbdi - > LastAccessTime . QuadPart = unix_time_to_win ( & ii . st_atime ) ;
fbdi - > LastWriteTime . QuadPart = unix_time_to_win ( & ii . st_mtime ) ;
fbdi - > ChangeTime . QuadPart = 0 ;
fbdi - > EndOfFile . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_size ;
fbdi - > AllocationSize . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_blocks ;
2016-07-27 19:24:26 +00:00
fbdi - > FileAttributes = atts ;
2016-03-23 20:35:05 +00:00
fbdi - > FileNameLength = stringlen ;
2016-07-27 19:24:26 +00:00
fbdi - > EaSize = get_reparse_tag ( fcb - > Vcb , r , inode , de - > type , atts ) ;
2016-03-23 20:35:05 +00:00
fbdi - > ShortNameLength = 0 ;
// fibdi->ShortName[12];
Status = RtlUTF8ToUnicodeN ( fbdi - > FileName , stringlen , & stringlen , de - > name , de - > namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
return Status ;
}
* len - = needed ;
return STATUS_SUCCESS ;
}
case FileDirectoryInformation :
{
FILE_DIRECTORY_INFORMATION * fdi = buf ;
TRACE ( " FileDirectoryInformation \n " ) ;
needed = sizeof ( FILE_DIRECTORY_INFORMATION ) - sizeof ( WCHAR ) + stringlen ;
if ( needed > * len ) {
2016-07-27 19:24:26 +00:00
TRACE ( " buffer overflow - %u > %u \n " , needed , * len ) ;
2016-03-23 20:35:05 +00:00
return STATUS_BUFFER_OVERFLOW ;
}
fdi - > NextEntryOffset = 0 ;
fdi - > FileIndex = 0 ;
fdi - > CreationTime . QuadPart = unix_time_to_win ( & ii . otime ) ;
fdi - > LastAccessTime . QuadPart = unix_time_to_win ( & ii . st_atime ) ;
fdi - > LastWriteTime . QuadPart = unix_time_to_win ( & ii . st_mtime ) ;
fdi - > ChangeTime . QuadPart = 0 ;
fdi - > EndOfFile . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_size ;
fdi - > AllocationSize . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_blocks ;
2016-07-27 19:24:26 +00:00
fdi - > FileAttributes = atts ;
2016-03-23 20:35:05 +00:00
fdi - > FileNameLength = stringlen ;
Status = RtlUTF8ToUnicodeN ( fdi - > FileName , stringlen , & stringlen , de - > name , de - > namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
return Status ;
}
* len - = needed ;
return STATUS_SUCCESS ;
}
case FileFullDirectoryInformation :
{
FILE_FULL_DIR_INFORMATION * ffdi = buf ;
TRACE ( " FileFullDirectoryInformation \n " ) ;
needed = sizeof ( FILE_FULL_DIR_INFORMATION ) - sizeof ( WCHAR ) + stringlen ;
if ( needed > * len ) {
2016-07-27 19:24:26 +00:00
TRACE ( " buffer overflow - %u > %u \n " , needed , * len ) ;
2016-03-23 20:35:05 +00:00
return STATUS_BUFFER_OVERFLOW ;
}
ffdi - > NextEntryOffset = 0 ;
ffdi - > FileIndex = 0 ;
ffdi - > CreationTime . QuadPart = unix_time_to_win ( & ii . otime ) ;
ffdi - > LastAccessTime . QuadPart = unix_time_to_win ( & ii . st_atime ) ;
ffdi - > LastWriteTime . QuadPart = unix_time_to_win ( & ii . st_mtime ) ;
ffdi - > ChangeTime . QuadPart = 0 ;
ffdi - > EndOfFile . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_size ;
ffdi - > AllocationSize . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_blocks ;
2016-07-27 19:24:26 +00:00
ffdi - > FileAttributes = atts ;
2016-03-23 20:35:05 +00:00
ffdi - > FileNameLength = stringlen ;
2016-07-27 19:24:26 +00:00
ffdi - > EaSize = get_reparse_tag ( fcb - > Vcb , r , inode , de - > type , atts ) ;
2016-03-23 20:35:05 +00:00
Status = RtlUTF8ToUnicodeN ( ffdi - > FileName , stringlen , & stringlen , de - > name , de - > namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
return Status ;
}
* len - = needed ;
return STATUS_SUCCESS ;
}
case FileIdBothDirectoryInformation :
{
FILE_ID_BOTH_DIR_INFORMATION * fibdi = buf ;
TRACE ( " FileIdBothDirectoryInformation \n " ) ;
needed = sizeof ( FILE_ID_BOTH_DIR_INFORMATION ) - sizeof ( WCHAR ) + stringlen ;
if ( needed > * len ) {
2016-07-27 19:24:26 +00:00
TRACE ( " buffer overflow - %u > %u \n " , needed , * len ) ;
2016-03-23 20:35:05 +00:00
return STATUS_BUFFER_OVERFLOW ;
}
// if (!buf)
// return STATUS_INVALID_POINTER;
fibdi - > NextEntryOffset = 0 ;
fibdi - > FileIndex = 0 ;
fibdi - > CreationTime . QuadPart = unix_time_to_win ( & ii . otime ) ;
fibdi - > LastAccessTime . QuadPart = unix_time_to_win ( & ii . st_atime ) ;
fibdi - > LastWriteTime . QuadPart = unix_time_to_win ( & ii . st_mtime ) ;
fibdi - > ChangeTime . QuadPart = 0 ;
fibdi - > EndOfFile . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_size ;
fibdi - > AllocationSize . QuadPart = de - > type = = BTRFS_TYPE_SYMLINK ? 0 : ii . st_blocks ;
2016-07-27 19:24:26 +00:00
fibdi - > FileAttributes = atts ;
2016-03-23 20:35:05 +00:00
fibdi - > FileNameLength = stringlen ;
2016-07-27 19:24:26 +00:00
fibdi - > EaSize = get_reparse_tag ( fcb - > Vcb , r , inode , de - > type , atts ) ;
2016-03-23 20:35:05 +00:00
fibdi - > ShortNameLength = 0 ;
// fibdi->ShortName[12];
fibdi - > FileId . QuadPart = inode ;
Status = RtlUTF8ToUnicodeN ( fibdi - > FileName , stringlen , & stringlen , de - > name , de - > namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
return Status ;
}
* len - = needed ;
return STATUS_SUCCESS ;
}
case FileIdFullDirectoryInformation :
FIXME ( " STUB: FileIdFullDirectoryInformation \n " ) ;
break ;
case FileNamesInformation :
{
FILE_NAMES_INFORMATION * fni = buf ;
TRACE ( " FileNamesInformation \n " ) ;
needed = sizeof ( FILE_NAMES_INFORMATION ) - sizeof ( WCHAR ) + stringlen ;
if ( needed > * len ) {
2016-07-27 19:24:26 +00:00
TRACE ( " buffer overflow - %u > %u \n " , needed , * len ) ;
2016-03-23 20:35:05 +00:00
return STATUS_BUFFER_OVERFLOW ;
}
fni - > NextEntryOffset = 0 ;
fni - > FileIndex = 0 ;
fni - > FileNameLength = stringlen ;
Status = RtlUTF8ToUnicodeN ( fni - > FileName , stringlen , & stringlen , de - > name , de - > namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
return Status ;
}
* len - = needed ;
return STATUS_SUCCESS ;
}
case FileObjectIdInformation :
FIXME ( " STUB: FileObjectIdInformation \n " ) ;
return STATUS_NOT_IMPLEMENTED ;
case FileQuotaInformation :
FIXME ( " STUB: FileQuotaInformation \n " ) ;
return STATUS_NOT_IMPLEMENTED ;
case FileReparsePointInformation :
FIXME ( " STUB: FileReparsePointInformation \n " ) ;
return STATUS_NOT_IMPLEMENTED ;
default :
WARN ( " Unknown FileInformationClass %u \n " , IrpSp - > Parameters . QueryDirectory . FileInformationClass ) ;
return STATUS_NOT_IMPLEMENTED ;
}
return STATUS_NO_MORE_FILES ;
}
2016-07-27 19:24:26 +00:00
static NTSTATUS STDCALL next_dir_entry ( file_ref * fileref , UINT64 * offset , dir_entry * de ) {
2016-03-23 20:35:05 +00:00
KEY searchkey ;
2016-07-27 19:24:26 +00:00
traverse_ptr tp , next_tp ;
2016-03-23 20:35:05 +00:00
DIR_ITEM * di ;
NTSTATUS Status ;
2016-07-27 19:24:26 +00:00
file_ref * fr ;
LIST_ENTRY * le ;
char * name ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref - > parent ) { // don't return . and .. if root directory
2016-03-23 20:35:05 +00:00
if ( * offset = = 0 ) {
2016-07-27 19:24:26 +00:00
de - > key . obj_id = fileref - > fcb - > inode ;
2016-03-23 20:35:05 +00:00
de - > key . obj_type = TYPE_INODE_ITEM ;
de - > key . offset = 0 ;
de - > dir_entry_type = DirEntryType_Self ;
de - > name = " . " ;
2016-07-27 19:24:26 +00:00
de - > name_alloc = FALSE ;
2016-03-23 20:35:05 +00:00
de - > namelen = 1 ;
de - > type = BTRFS_TYPE_DIRECTORY ;
* offset = 1 ;
return STATUS_SUCCESS ;
} else if ( * offset = = 1 ) {
2016-05-05 17:26:47 +00:00
de - > key . obj_id = fileref - > parent - > fcb - > inode ;
2016-03-23 20:35:05 +00:00
de - > key . obj_type = TYPE_INODE_ITEM ;
de - > key . offset = 0 ;
de - > dir_entry_type = DirEntryType_Parent ;
de - > name = " .. " ;
2016-07-27 19:24:26 +00:00
de - > name_alloc = FALSE ;
2016-03-23 20:35:05 +00:00
de - > namelen = 2 ;
de - > type = BTRFS_TYPE_DIRECTORY ;
* offset = 2 ;
return STATUS_SUCCESS ;
}
}
2016-07-27 19:24:26 +00:00
if ( * offset < 2 )
* offset = 2 ;
ExAcquireResourceSharedLite ( & fileref - > nonpaged - > children_lock , TRUE ) ;
fr = NULL ;
le = fileref - > children . Flink ;
// skip entries before offset
while ( le ! = & fileref - > children ) {
file_ref * fr2 = CONTAINING_RECORD ( le , file_ref , list_entry ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
if ( fr2 - > index > = * offset ) {
fr = fr2 ;
break ;
2016-03-23 20:35:05 +00:00
}
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
do {
if ( fr & & fr - > index = = * offset ) {
if ( ! fr - > deleted ) {
if ( fr - > fcb - > subvol = = fileref - > fcb - > subvol ) {
de - > key . obj_id = fr - > fcb - > inode ;
de - > key . obj_type = TYPE_INODE_ITEM ;
de - > key . offset = 0 ;
} else {
de - > key . obj_id = fr - > fcb - > subvol - > id ;
de - > key . obj_type = TYPE_ROOT_ITEM ;
de - > key . offset = 0 ;
}
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
name = fr - > utf8 . Buffer ;
de - > namelen = fr - > utf8 . Length ;
de - > type = fr - > fcb - > type ;
de - > dir_entry_type = DirEntryType_File ;
( * offset ) + + ;
Status = STATUS_SUCCESS ;
goto end ;
} else {
( * offset ) + + ;
fr = fr - > list_entry . Flink = = & fileref - > children ? NULL : CONTAINING_RECORD ( fr - > list_entry . Flink , file_ref , list_entry ) ;
continue ;
2016-03-23 20:35:05 +00:00
}
}
2016-07-27 19:24:26 +00:00
searchkey . obj_id = fileref - > fcb - > inode ;
searchkey . obj_type = TYPE_DIR_INDEX ;
searchkey . offset = * offset ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
Status = find_item ( fileref - > fcb - > Vcb , fileref - > fcb - > subvol , & tp , & searchkey , FALSE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - find_item returned %08x \n " , Status ) ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2016-07-27 19:24:26 +00:00
if ( keycmp ( & tp . item - > key , & searchkey ) = = - 1 ) {
if ( find_next_item ( fileref - > fcb - > Vcb , & tp , & next_tp , FALSE ) )
tp = next_tp ;
}
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
if ( keycmp ( & tp . item - > key , & searchkey ) ! = - 1 & & tp . item - > key . obj_id = = searchkey . obj_id & & tp . item - > key . obj_type = = searchkey . obj_type ) {
do {
if ( fr ) {
if ( fr - > index < = tp . item - > key . offset & & ! fr - > deleted ) {
if ( fr - > fcb - > subvol = = fileref - > fcb - > subvol ) {
de - > key . obj_id = fr - > fcb - > inode ;
de - > key . obj_type = TYPE_INODE_ITEM ;
de - > key . offset = 0 ;
} else {
de - > key . obj_id = fr - > fcb - > subvol - > id ;
de - > key . obj_type = TYPE_ROOT_ITEM ;
de - > key . offset = 0 ;
}
name = fr - > utf8 . Buffer ;
de - > namelen = fr - > utf8 . Length ;
de - > type = fr - > fcb - > type ;
de - > dir_entry_type = DirEntryType_File ;
* offset = fr - > index + 1 ;
Status = STATUS_SUCCESS ;
goto end ;
}
if ( fr - > index = = tp . item - > key . offset & & fr - > deleted )
break ;
fr = fr - > list_entry . Flink = = & fileref - > children ? NULL : CONTAINING_RECORD ( fr - > list_entry . Flink , file_ref , list_entry ) ;
}
} while ( fr & & fr - > index < tp . item - > key . offset ) ;
if ( fr & & fr - > index = = tp . item - > key . offset & & fr - > deleted ) {
* offset = fr - > index + 1 ;
fr = fr - > list_entry . Flink = = & fileref - > children ? NULL : CONTAINING_RECORD ( fr - > list_entry . Flink , file_ref , list_entry ) ;
continue ;
}
* offset = tp . item - > key . offset + 1 ;
di = ( DIR_ITEM * ) tp . item - > data ;
if ( tp . item - > size < sizeof ( DIR_ITEM ) | | tp . item - > size < sizeof ( DIR_ITEM ) - 1 + di - > m + di - > n ) {
ERR ( " (%llx,%x,%llx) was %u bytes, expected at least %u \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DIR_ITEM ) ) ;
Status = STATUS_INTERNAL_ERROR ;
goto end ;
}
de - > key = di - > key ;
name = di - > name ;
de - > namelen = di - > n ;
de - > type = di - > type ;
de - > dir_entry_type = DirEntryType_File ;
Status = STATUS_SUCCESS ;
goto end ;
} else {
if ( fr ) {
if ( fr - > fcb - > subvol = = fileref - > fcb - > subvol ) {
de - > key . obj_id = fr - > fcb - > inode ;
de - > key . obj_type = TYPE_INODE_ITEM ;
de - > key . offset = 0 ;
} else {
de - > key . obj_id = fr - > fcb - > subvol - > id ;
de - > key . obj_type = TYPE_ROOT_ITEM ;
de - > key . offset = 0 ;
}
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
name = fr - > utf8 . Buffer ;
de - > namelen = fr - > utf8 . Length ;
de - > type = fr - > fcb - > type ;
de - > dir_entry_type = DirEntryType_File ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
* offset = fr - > index + 1 ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
Status = STATUS_SUCCESS ;
goto end ;
} else {
Status = STATUS_NO_MORE_FILES ;
goto end ;
}
}
} while ( TRUE ) ;
end :
ExReleaseResourceLite ( & fileref - > nonpaged - > children_lock ) ;
if ( NT_SUCCESS ( Status ) ) {
de - > name_alloc = TRUE ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
de - > name = ExAllocatePoolWithTag ( PagedPool , de - > namelen , ALLOC_TAG ) ;
if ( ! de - > name ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( de - > name , name , de - > namelen ) ;
} else
de - > name_alloc = FALSE ;
return Status ;
2016-03-23 20:35:05 +00:00
}
static NTSTATUS STDCALL query_directory ( PDEVICE_OBJECT DeviceObject , PIRP Irp ) {
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status , status2 ;
fcb * fcb ;
ccb * ccb ;
2016-05-05 17:26:47 +00:00
file_ref * fileref ;
2016-03-23 20:35:05 +00:00
void * buf ;
UINT8 * curitem , * lastitem ;
LONG length ;
ULONG count ;
2016-05-05 17:26:47 +00:00
BOOL has_wildcard = FALSE , specific_file = FALSE , initial ;
2016-03-23 20:35:05 +00:00
// UINT64 num_reads_orig;
dir_entry de ;
2016-07-27 19:24:26 +00:00
UINT64 newoffset ;
ANSI_STRING utf8 ;
2016-03-23 20:35:05 +00:00
TRACE ( " query directory \n " ) ;
// get_uid(); // TESTING
// num_reads_orig = num_reads;
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
fcb = IrpSp - > FileObject - > FsContext ;
ccb = IrpSp - > FileObject - > FsContext2 ;
2016-05-05 17:26:47 +00:00
fileref = ccb ? ccb - > fileref : NULL ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
utf8 . Buffer = NULL ;
if ( ! fileref )
return STATUS_INVALID_PARAMETER ;
if ( ! ccb ) {
ERR ( " ccb was NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( ! ( ccb - > access & FILE_LIST_DIRECTORY ) ) {
WARN ( " insufficient privileges \n " ) ;
return STATUS_ACCESS_DENIED ;
}
ExAcquireResourceSharedLite ( & fcb - > Vcb - > tree_lock , TRUE ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " %S \n " , file_desc ( IrpSp - > FileObject ) ) ;
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Flags = = 0 ) {
TRACE ( " QD flags: (none) \n " ) ;
} else {
ULONG flags = IrpSp - > Flags ;
TRACE ( " QD flags: \n " ) ;
if ( flags & SL_INDEX_SPECIFIED ) {
TRACE ( " SL_INDEX_SPECIFIED \n " ) ;
flags & = ~ SL_INDEX_SPECIFIED ;
}
if ( flags & SL_RESTART_SCAN ) {
TRACE ( " SL_RESTART_SCAN \n " ) ;
flags & = ~ SL_RESTART_SCAN ;
}
if ( flags & SL_RETURN_SINGLE_ENTRY ) {
TRACE ( " SL_RETURN_SINGLE_ENTRY \n " ) ;
flags & = ~ SL_RETURN_SINGLE_ENTRY ;
}
if ( flags ! = 0 )
TRACE ( " unknown flags: %u \n " , flags ) ;
}
2016-05-05 17:26:47 +00:00
initial = ! ccb - > query_string . Buffer ;
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Flags & SL_RESTART_SCAN ) {
ccb - > query_dir_offset = 0 ;
if ( ccb - > query_string . Buffer ) {
RtlFreeUnicodeString ( & ccb - > query_string ) ;
ccb - > query_string . Buffer = NULL ;
}
}
2016-07-27 19:24:26 +00:00
if ( IrpSp - > Parameters . QueryDirectory . FileName & & IrpSp - > Parameters . QueryDirectory . FileName - > Length > 1 ) {
2016-03-23 20:35:05 +00:00
TRACE ( " QD filename: %.*S \n " , IrpSp - > Parameters . QueryDirectory . FileName - > Length / sizeof ( WCHAR ) , IrpSp - > Parameters . QueryDirectory . FileName - > Buffer ) ;
2016-07-27 19:24:26 +00:00
if ( IrpSp - > Parameters . QueryDirectory . FileName - > Buffer [ 0 ] ! = ' * ' ) {
specific_file = TRUE ;
if ( FsRtlDoesNameContainWildCards ( IrpSp - > Parameters . QueryDirectory . FileName ) ) {
has_wildcard = TRUE ;
specific_file = FALSE ;
}
}
2016-03-23 20:35:05 +00:00
if ( ccb - > query_string . Buffer )
RtlFreeUnicodeString ( & ccb - > query_string ) ;
2016-07-27 19:24:26 +00:00
if ( has_wildcard )
2016-03-23 20:35:05 +00:00
RtlUpcaseUnicodeString ( & ccb - > query_string , IrpSp - > Parameters . QueryDirectory . FileName , TRUE ) ;
2016-07-27 19:24:26 +00:00
else {
ccb - > query_string . Buffer = ExAllocatePoolWithTag ( PagedPool , IrpSp - > Parameters . QueryDirectory . FileName - > Length , ALLOC_TAG ) ;
if ( ! ccb - > query_string . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
ccb - > query_string . Length = ccb - > query_string . MaximumLength = IrpSp - > Parameters . QueryDirectory . FileName - > Length ;
RtlCopyMemory ( ccb - > query_string . Buffer , IrpSp - > Parameters . QueryDirectory . FileName - > Buffer , IrpSp - > Parameters . QueryDirectory . FileName - > Length ) ;
}
2016-03-23 20:35:05 +00:00
ccb - > has_wildcard = has_wildcard ;
ccb - > specific_file = specific_file ;
} else {
has_wildcard = ccb - > has_wildcard ;
specific_file = ccb - > specific_file ;
2016-05-05 17:26:47 +00:00
2016-07-27 19:24:26 +00:00
if ( ! ( IrpSp - > Flags & SL_RESTART_SCAN ) ) {
2016-05-05 17:26:47 +00:00
initial = FALSE ;
2016-07-27 19:24:26 +00:00
if ( specific_file ) {
Status = STATUS_NO_MORE_FILES ;
goto end ;
}
}
2016-03-23 20:35:05 +00:00
}
if ( ccb - > query_string . Buffer ) {
TRACE ( " query string = %.*S \n " , ccb - > query_string . Length / sizeof ( WCHAR ) , ccb - > query_string . Buffer ) ;
}
2016-07-27 19:24:26 +00:00
newoffset = ccb - > query_dir_offset ;
Status = next_dir_entry ( fileref , & newoffset , & de ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2016-05-05 17:26:47 +00:00
if ( Status = = STATUS_NO_MORE_FILES & & initial )
2016-03-23 20:35:05 +00:00
Status = STATUS_NO_SUCH_FILE ;
goto end ;
}
2016-07-27 19:24:26 +00:00
ccb - > query_dir_offset = newoffset ;
2016-03-23 20:35:05 +00:00
buf = map_user_buffer ( Irp ) ;
if ( Irp - > MdlAddress & & ! buf ) {
ERR ( " MmGetSystemAddressForMdlSafe returned NULL \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
length = IrpSp - > Parameters . QueryDirectory . Length ;
2016-07-27 19:24:26 +00:00
if ( specific_file ) {
BOOL found = FALSE ;
root * found_subvol ;
UINT64 found_inode , found_index ;
UINT8 found_type ;
UNICODE_STRING us ;
LIST_ENTRY * le ;
Status = RtlUpcaseUnicodeString ( & us , & ccb - > query_string , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUpcaseUnicodeString returned %08x \n " , Status ) ;
goto end ;
}
ExAcquireResourceSharedLite ( & fileref - > nonpaged - > children_lock , TRUE ) ;
le = fileref - > children . Flink ;
while ( le ! = & fileref - > children ) {
file_ref * fr2 = CONTAINING_RECORD ( le , file_ref , list_entry ) ;
if ( ! fr2 - > deleted & & fr2 - > filepart_uc . Length = = us . Length & &
RtlCompareMemory ( fr2 - > filepart_uc . Buffer , us . Buffer , us . Length ) = = us . Length ) {
found = TRUE ;
if ( fr2 - > fcb - > subvol = = fcb - > subvol ) {
de . key . obj_id = fr2 - > fcb - > inode ;
de . key . obj_type = TYPE_INODE_ITEM ;
de . key . offset = 0 ;
} else {
de . key . obj_id = fr2 - > fcb - > subvol - > id ;
de . key . obj_type = TYPE_ROOT_ITEM ;
de . key . offset = 0 ;
}
de . name = ExAllocatePoolWithTag ( PagedPool , fr2 - > utf8 . Length , ALLOC_TAG ) ;
if ( ! de . name ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
RtlCopyMemory ( de . name , fr2 - > utf8 . Buffer , fr2 - > utf8 . Length ) ;
de . name_alloc = TRUE ;
de . namelen = fr2 - > utf8 . Length ;
de . type = fr2 - > fcb - > type ;
de . dir_entry_type = DirEntryType_File ;
break ;
}
le = le - > Flink ;
}
ExReleaseResourceLite ( & fileref - > nonpaged - > children_lock ) ;
if ( us . Buffer )
ExFreePool ( us . Buffer ) ;
if ( ! found ) {
Status = find_file_in_dir ( fcb - > Vcb , & ccb - > query_string , fileref , & found_subvol , & found_inode , & found_type , & found_index , & utf8 ) ;
if ( ! NT_SUCCESS ( Status ) ) {
Status = STATUS_NO_SUCH_FILE ;
goto end ;
}
if ( found_subvol = = fcb - > subvol ) {
de . key . obj_id = found_inode ;
de . key . obj_type = TYPE_INODE_ITEM ;
de . key . offset = 0 ;
} else {
de . key . obj_id = found_subvol - > id ;
de . key . obj_type = TYPE_ROOT_ITEM ;
de . key . offset = 0 ;
}
de . name = utf8 . Buffer ;
de . name_alloc = FALSE ;
de . namelen = utf8 . Length ;
de . type = found_type ;
de . dir_entry_type = DirEntryType_File ;
}
} else if ( has_wildcard ) {
2016-03-23 20:35:05 +00:00
WCHAR * uni_fn ;
ULONG stringlen ;
UNICODE_STRING di_uni_fn ;
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & stringlen , de . name , de . namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
goto end ;
}
uni_fn = ExAllocatePoolWithTag ( PagedPool , stringlen , ALLOC_TAG ) ;
if ( ! uni_fn ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
Status = RtlUTF8ToUnicodeN ( uni_fn , stringlen , & stringlen , de . name , de . namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
goto end ;
}
di_uni_fn . Length = di_uni_fn . MaximumLength = stringlen ;
di_uni_fn . Buffer = uni_fn ;
while ( ! FsRtlIsNameInExpression ( & ccb - > query_string , & di_uni_fn , TRUE , NULL ) ) {
2016-07-27 19:24:26 +00:00
if ( de . name_alloc )
ExFreePool ( de . name ) ;
newoffset = ccb - > query_dir_offset ;
Status = next_dir_entry ( fileref , & newoffset , & de ) ;
2016-03-23 20:35:05 +00:00
ExFreePool ( uni_fn ) ;
if ( NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
ccb - > query_dir_offset = newoffset ;
2016-03-23 20:35:05 +00:00
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & stringlen , de . name , de . namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
goto end ;
}
uni_fn = ExAllocatePoolWithTag ( PagedPool , stringlen , ALLOC_TAG ) ;
if ( ! uni_fn ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
Status = RtlUTF8ToUnicodeN ( uni_fn , stringlen , & stringlen , de . name , de . namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
ExFreePool ( uni_fn ) ;
goto end ;
}
di_uni_fn . Length = di_uni_fn . MaximumLength = stringlen ;
di_uni_fn . Buffer = uni_fn ;
} else {
2016-05-05 17:26:47 +00:00
if ( Status = = STATUS_NO_MORE_FILES & & initial )
2016-03-23 20:35:05 +00:00
Status = STATUS_NO_SUCH_FILE ;
goto end ;
}
}
ExFreePool ( uni_fn ) ;
}
TRACE ( " file(0) = %.*s \n " , de . namelen , de . name ) ;
TRACE ( " offset = %u \n " , ccb - > query_dir_offset - 1 ) ;
2016-05-05 17:26:47 +00:00
Status = query_dir_item ( fcb , fileref , buf , & length , Irp , & de , fcb - > subvol ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
if ( de . name_alloc )
ExFreePool ( de . name ) ;
2016-03-23 20:35:05 +00:00
count = 0 ;
if ( NT_SUCCESS ( Status ) & & ! ( IrpSp - > Flags & SL_RETURN_SINGLE_ENTRY ) & & ! specific_file ) {
lastitem = ( UINT8 * ) buf ;
while ( length > 0 ) {
switch ( IrpSp - > Parameters . QueryDirectory . FileInformationClass ) {
case FileBothDirectoryInformation :
case FileDirectoryInformation :
case FileIdBothDirectoryInformation :
case FileFullDirectoryInformation :
length - = length % 8 ;
break ;
case FileNamesInformation :
length - = length % 4 ;
break ;
default :
WARN ( " unhandled file information class %u \n " , IrpSp - > Parameters . QueryDirectory . FileInformationClass ) ;
break ;
}
if ( length > 0 ) {
WCHAR * uni_fn = NULL ;
UNICODE_STRING di_uni_fn ;
2016-07-27 19:24:26 +00:00
newoffset = ccb - > query_dir_offset ;
Status = next_dir_entry ( fileref , & newoffset , & de ) ;
2016-03-23 20:35:05 +00:00
if ( NT_SUCCESS ( Status ) ) {
if ( has_wildcard ) {
ULONG stringlen ;
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & stringlen , de . name , de . namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
2016-07-27 19:24:26 +00:00
if ( de . name_alloc ) ExFreePool ( de . name ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
uni_fn = ExAllocatePoolWithTag ( PagedPool , stringlen , ALLOC_TAG ) ;
if ( ! uni_fn ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
2016-07-27 19:24:26 +00:00
if ( de . name_alloc ) ExFreePool ( de . name ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
Status = RtlUTF8ToUnicodeN ( uni_fn , stringlen , & stringlen , de . name , de . namelen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN returned %08x \n " , Status ) ;
ExFreePool ( uni_fn ) ;
2016-07-27 19:24:26 +00:00
if ( de . name_alloc ) ExFreePool ( de . name ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
di_uni_fn . Length = di_uni_fn . MaximumLength = stringlen ;
di_uni_fn . Buffer = uni_fn ;
}
if ( ! has_wildcard | | FsRtlIsNameInExpression ( & ccb - > query_string , & di_uni_fn , TRUE , NULL ) ) {
curitem = ( UINT8 * ) buf + IrpSp - > Parameters . QueryDirectory . Length - length ;
count + + ;
TRACE ( " file(%u) %u = %.*s \n " , count , curitem - ( UINT8 * ) buf , de . namelen , de . name ) ;
TRACE ( " offset = %u \n " , ccb - > query_dir_offset - 1 ) ;
2016-05-05 17:26:47 +00:00
status2 = query_dir_item ( fcb , fileref , curitem , & length , Irp , & de , fcb - > subvol ) ;
2016-03-23 20:35:05 +00:00
if ( NT_SUCCESS ( status2 ) ) {
ULONG * lastoffset = ( ULONG * ) lastitem ;
* lastoffset = ( ULONG ) ( curitem - lastitem ) ;
2016-07-27 19:24:26 +00:00
ccb - > query_dir_offset = newoffset ;
2016-03-23 20:35:05 +00:00
lastitem = curitem ;
} else {
if ( uni_fn ) ExFreePool ( uni_fn ) ;
2016-07-27 19:24:26 +00:00
if ( de . name_alloc ) ExFreePool ( de . name ) ;
2016-03-23 20:35:05 +00:00
break ;
}
2016-07-27 19:24:26 +00:00
} else
ccb - > query_dir_offset = newoffset ;
2016-03-23 20:35:05 +00:00
if ( uni_fn ) {
ExFreePool ( uni_fn ) ;
uni_fn = NULL ;
}
2016-07-27 19:24:26 +00:00
if ( de . name_alloc )
ExFreePool ( de . name ) ;
2016-03-23 20:35:05 +00:00
} else {
if ( Status = = STATUS_NO_MORE_FILES )
Status = STATUS_SUCCESS ;
break ;
}
} else
break ;
}
}
Irp - > IoStatus . Information = IrpSp - > Parameters . QueryDirectory . Length - length ;
end :
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2016-07-27 19:24:26 +00:00
if ( utf8 . Buffer )
ExFreePool ( utf8 . Buffer ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
static NTSTATUS STDCALL notify_change_directory ( device_extension * Vcb , PIRP Irp ) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
fcb * fcb = FileObject - > FsContext ;
2016-05-05 17:26:47 +00:00
ccb * ccb = FileObject - > FsContext2 ;
file_ref * fileref = ccb - > fileref ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
TRACE ( " IRP_MN_NOTIFY_CHANGE_DIRECTORY \n " ) ;
2016-07-27 19:24:26 +00:00
if ( ! ccb ) {
ERR ( " ccb was NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2016-05-05 17:26:47 +00:00
if ( ! fileref ) {
ERR ( " no fileref \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2016-07-27 19:24:26 +00:00
if ( ! ( ccb - > access & FILE_LIST_DIRECTORY ) ) {
WARN ( " insufficient privileges \n " ) ;
return STATUS_ACCESS_DENIED ;
}
ExAcquireResourceSharedLite ( & fcb - > Vcb - > tree_lock , TRUE ) ;
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2016-03-23 20:35:05 +00:00
if ( fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
// FIXME - raise exception if FCB marked for deletion?
2016-05-05 17:26:47 +00:00
TRACE ( " %S \n " , file_desc ( FileObject ) ) ;
2016-07-27 19:24:26 +00:00
if ( ccb - > filename . Length = = 0 ) {
Status = fileref_get_filename ( fileref , & ccb - > filename , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
goto end ;
}
}
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
FsRtlNotifyFilterChangeDirectory ( Vcb - > NotifySync , & Vcb - > DirNotifyList , FileObject - > FsContext2 , ( PSTRING ) & ccb - > filename ,
IrpSp - > Flags & SL_WATCH_TREE , FALSE , IrpSp - > Parameters . NotifyDirectory . CompletionFilter , Irp ,
NULL , NULL , NULL ) ;
2016-03-23 20:35:05 +00:00
Status = STATUS_PENDING ;
end :
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
NTSTATUS STDCALL drv_directory_control ( IN PDEVICE_OBJECT DeviceObject , IN PIRP Irp ) {
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
ULONG func ;
BOOL top_level ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2016-03-23 20:35:05 +00:00
TRACE ( " directory control \n " ) ;
FsRtlEnterFileSystem ( ) ;
top_level = is_top_level ( Irp ) ;
2016-07-27 19:24:26 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_PARTITION0 ) {
Status = part0_passthrough ( DeviceObject , Irp ) ;
goto exit ;
}
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
Irp - > IoStatus . Information = 0 ;
func = IrpSp - > MinorFunction ;
switch ( func ) {
case IRP_MN_NOTIFY_CHANGE_DIRECTORY :
2016-07-27 19:24:26 +00:00
Status = notify_change_directory ( Vcb , Irp ) ;
2016-03-23 20:35:05 +00:00
break ;
case IRP_MN_QUERY_DIRECTORY :
Status = query_directory ( DeviceObject , Irp ) ;
break ;
default :
WARN ( " unknown minor %u \n " , func ) ;
Status = STATUS_NOT_IMPLEMENTED ;
Irp - > IoStatus . Status = Status ;
break ;
}
2016-07-27 19:24:26 +00:00
if ( Status = = STATUS_PENDING )
goto exit ;
Irp - > IoStatus . Status = Status ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
// if (Irp->UserIosb)
// *Irp->UserIosb = Irp->IoStatus;
2016-05-05 17:26:47 +00:00
2016-07-27 19:24:26 +00:00
IoCompleteRequest ( Irp , IO_DISK_INCREMENT ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
exit :
2016-03-23 20:35:05 +00:00
if ( top_level )
IoSetTopLevelIrp ( NULL ) ;
FsRtlExitFileSystem ( ) ;
return Status ;
}