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/>. */
# include "btrfs_drv.h"
2016-07-27 19:24:26 +00:00
# if (NTDDI_VERSION >= NTDDI_WIN10)
// not currently in mingw - introduced with Windows 10
# ifndef FileIdInformation
# define FileIdInformation (enum _FILE_INFORMATION_CLASS)59
2018-12-16 11:03:16 +00:00
# define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
typedef struct _FILE_STAT_LX_INFORMATION {
LARGE_INTEGER FileId ;
LARGE_INTEGER CreationTime ;
LARGE_INTEGER LastAccessTime ;
LARGE_INTEGER LastWriteTime ;
LARGE_INTEGER ChangeTime ;
LARGE_INTEGER AllocationSize ;
LARGE_INTEGER EndOfFile ;
ULONG FileAttributes ;
ULONG ReparseTag ;
ULONG NumberOfLinks ;
ACCESS_MASK EffectiveAccess ;
ULONG LxFlags ;
ULONG LxUid ;
ULONG LxGid ;
ULONG LxMode ;
ULONG LxDeviceIdMajor ;
ULONG LxDeviceIdMinor ;
} FILE_STAT_LX_INFORMATION , * PFILE_STAT_LX_INFORMATION ;
# define LX_FILE_METADATA_HAS_UID 0x01
# define LX_FILE_METADATA_HAS_GID 0x02
# define LX_FILE_METADATA_HAS_MODE 0x04
# define LX_FILE_METADATA_HAS_DEVICE_ID 0x08
# define LX_FILE_CASE_SENSITIVE_DIR 0x10
2016-07-27 19:24:26 +00:00
# endif
# endif
2017-09-08 08:02:43 +00:00
static NTSTATUS set_basic_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject ) {
2016-03-23 20:35:05 +00:00
FILE_BASIC_INFORMATION * fbi = Irp - > AssociatedIrp . SystemBuffer ;
fcb * fcb = FileObject - > FsContext ;
2016-05-05 17:26:47 +00:00
ccb * ccb = FileObject - > FsContext2 ;
file_ref * fileref = ccb ? ccb - > fileref : NULL ;
2016-07-27 19:24:26 +00:00
ULONG defda , filter = 0 ;
2016-03-23 20:35:05 +00:00
BOOL inode_item_changed = FALSE ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
if ( fileref & & fileref - > parent )
fcb = fileref - > parent - > fcb ;
else {
ERR ( " stream did not have fileref \n " ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INTERNAL_ERROR ;
2016-05-05 17:26:47 +00:00
}
}
2017-09-08 08:02:43 +00:00
if ( ! ccb ) {
ERR ( " ccb was NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2016-05-05 17:26:47 +00:00
TRACE ( " file = %S, attributes = %x \n " , file_desc ( FileObject ) , fbi - > FileAttributes ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fbi - > FileAttributes & FILE_ATTRIBUTE_DIRECTORY & & fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
WARN ( " attempted to set FILE_ATTRIBUTE_DIRECTORY on non-directory \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE & & is_subvol_readonly ( fcb - > subvol , Irp ) & &
2017-01-01 17:12:12 +00:00
( fbi - > FileAttributes = = 0 | | fbi - > FileAttributes & FILE_ATTRIBUTE_READONLY ) ) {
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
// don't allow readonly subvol to be made r/w if send operation running on it
if ( fcb - > inode = = SUBVOL_ROOT_INODE & & fcb - > subvol - > root_item . flags & BTRFS_SUBVOL_READONLY & &
fcb - > subvol - > send_ops > 0 ) {
Status = STATUS_DEVICE_NOT_READY ;
goto end ;
}
2018-12-16 11:03:16 +00:00
// times of -2 are some sort of undocumented behaviour to do with LXSS
if ( fbi - > CreationTime . QuadPart = = - 2 )
fbi - > CreationTime . QuadPart = 0 ;
if ( fbi - > LastAccessTime . QuadPart = = - 2 )
fbi - > LastAccessTime . QuadPart = 0 ;
if ( fbi - > LastWriteTime . QuadPart = = - 2 )
fbi - > LastWriteTime . QuadPart = 0 ;
if ( fbi - > ChangeTime . QuadPart = = - 2 )
fbi - > ChangeTime . QuadPart = 0 ;
2016-10-29 17:05:10 +00:00
if ( fbi - > CreationTime . QuadPart = = - 1 )
ccb - > user_set_creation_time = TRUE ;
else if ( fbi - > CreationTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > CreationTime , & fcb - > inode_item . otime ) ;
inode_item_changed = TRUE ;
filter | = FILE_NOTIFY_CHANGE_CREATION ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ccb - > user_set_creation_time = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fbi - > LastAccessTime . QuadPart = = - 1 )
ccb - > user_set_access_time = TRUE ;
else if ( fbi - > LastAccessTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > LastAccessTime , & fcb - > inode_item . st_atime ) ;
inode_item_changed = TRUE ;
filter | = FILE_NOTIFY_CHANGE_LAST_ACCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ccb - > user_set_access_time = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fbi - > LastWriteTime . QuadPart = = - 1 )
ccb - > user_set_write_time = TRUE ;
else if ( fbi - > LastWriteTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > LastWriteTime , & fcb - > inode_item . st_mtime ) ;
inode_item_changed = TRUE ;
filter | = FILE_NOTIFY_CHANGE_LAST_WRITE ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ccb - > user_set_write_time = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fbi - > ChangeTime . QuadPart = = - 1 )
ccb - > user_set_change_time = TRUE ;
else if ( fbi - > ChangeTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > ChangeTime , & fcb - > inode_item . st_ctime ) ;
inode_item_changed = TRUE ;
// no filter for this
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ccb - > user_set_change_time = TRUE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FileAttributes == 0 means don't set - undocumented, but seen in fastfat
if ( fbi - > FileAttributes ! = 0 ) {
LARGE_INTEGER time ;
BTRFS_TIME now ;
2017-09-08 08:02:43 +00:00
fbi - > FileAttributes & = ~ FILE_ATTRIBUTE_NORMAL ;
defda = get_file_attributes ( Vcb , fcb - > subvol , fcb - > inode , fcb - > type , fileref & & fileref - > dc & & fileref - > dc - > name . Length > = sizeof ( WCHAR ) & & fileref - > dc - > name . Buffer [ 0 ] = = ' . ' ,
TRUE , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( fcb - > type = = BTRFS_TYPE_DIRECTORY )
fbi - > FileAttributes | = FILE_ATTRIBUTE_DIRECTORY ;
else if ( fcb - > type = = BTRFS_TYPE_SYMLINK )
fbi - > FileAttributes | = FILE_ATTRIBUTE_REPARSE_POINT ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > atts_changed = TRUE ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > atts & FILE_ATTRIBUTE_REPARSE_POINT )
fbi - > FileAttributes | = FILE_ATTRIBUTE_REPARSE_POINT ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( defda = = fbi - > FileAttributes )
fcb - > atts_deleted = TRUE ;
2017-09-08 08:02:43 +00:00
else if ( fcb - > inode = = SUBVOL_ROOT_INODE & & ( defda | FILE_ATTRIBUTE_READONLY ) = = ( fbi - > FileAttributes | FILE_ATTRIBUTE_READONLY ) )
fcb - > atts_deleted = TRUE ;
2016-03-23 20:35:05 +00:00
fcb - > atts = fbi - > FileAttributes ;
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
2016-10-29 17:05:10 +00:00
if ( ! ccb - > user_set_change_time )
fcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fcb - > subvol - > root_item . ctransid = Vcb - > superblock . generation ;
fcb - > subvol - > root_item . ctime = now ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE ) {
if ( fbi - > FileAttributes & FILE_ATTRIBUTE_READONLY )
fcb - > subvol - > root_item . flags | = BTRFS_SUBVOL_READONLY ;
else
fcb - > subvol - > root_item . flags & = ~ BTRFS_SUBVOL_READONLY ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
inode_item_changed = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
filter | = FILE_NOTIFY_CHANGE_ATTRIBUTES ;
2016-03-23 20:35:05 +00:00
}
if ( inode_item_changed ) {
fcb - > inode_item . transid = Vcb - > superblock . generation ;
fcb - > inode_item . sequence + + ;
2016-10-29 17:05:10 +00:00
fcb - > inode_item_changed = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fcb ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( filter ! = 0 )
2017-09-08 08:02:43 +00:00
send_notification_fcb ( fileref , filter , FILE_ACTION_MODIFIED , NULL ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_SUCCESS ;
end :
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS set_disposition_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject ) {
2016-03-23 20:35:05 +00:00
FILE_DISPOSITION_INFORMATION * fdi = Irp - > AssociatedIrp . SystemBuffer ;
fcb * fcb = FileObject - > FsContext ;
2016-05-05 17:26:47 +00:00
ccb * ccb = FileObject - > FsContext2 ;
file_ref * fileref = ccb ? ccb - > fileref : NULL ;
2016-03-23 20:35:05 +00:00
ULONG atts ;
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! fileref )
return STATUS_INVALID_PARAMETER ;
2017-09-08 08:02:43 +00:00
2017-10-16 18:05:33 +00:00
acquire_fcb_lock_exclusive ( Vcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " changing delete_on_close to %s for %S (fcb %p) \n " , fdi - > DeleteFile ? " TRUE " : " FALSE " , file_desc ( FileObject ) , fcb ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
if ( fileref - > parent )
atts = fileref - > parent - > fcb - > atts ;
else {
ERR ( " no fileref for stream \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_INTERNAL_ERROR ;
goto end ;
2016-05-05 17:26:47 +00:00
}
} else
atts = fcb - > atts ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " atts = %x \n " , atts ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( atts & FILE_ATTRIBUTE_READONLY ) {
2017-09-08 08:02:43 +00:00
TRACE ( " not allowing readonly file to be deleted \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_CANNOT_DELETE ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - can we skip this bit for subvols?
2017-09-08 08:02:43 +00:00
if ( fcb - > type = = BTRFS_TYPE_DIRECTORY & & fcb - > inode_item . st_size > 0 & & ( ! fileref | | fileref - > fcb ! = Vcb - > dummy_fcb ) ) {
TRACE ( " directory not empty \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_DIRECTORY_NOT_EMPTY ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! MmFlushImageSection ( & fcb - > nonpaged - > segment_object , MmFlushForDelete ) ) {
2017-09-08 08:02:43 +00:00
TRACE ( " trying to delete file which is being mapped as an image \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_CANNOT_DELETE ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ccb - > fileref - > delete_on_close = fdi - > DeleteFile ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FileObject - > DeletePending = fdi - > DeleteFile ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
end :
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2017-10-16 18:05:33 +00:00
release_fcb_lock ( Vcb ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
// send notification that directory is about to be deleted
if ( NT_SUCCESS ( Status ) & & fdi - > DeleteFile & & fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
FsRtlNotifyFullChangeDirectory ( Vcb - > NotifySync , & Vcb - > DirNotifyList , FileObject - > FsContext ,
NULL , FALSE , FALSE , 0 , NULL , NULL , NULL ) ;
}
2016-10-29 17:05:10 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2016-07-27 19:24:26 +00:00
BOOL has_open_children ( file_ref * fileref ) {
LIST_ENTRY * le = fileref - > children . Flink ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( IsListEmpty ( & fileref - > children ) )
return FALSE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( le ! = & fileref - > children ) {
2016-05-05 17:26:47 +00:00
file_ref * c = CONTAINING_RECORD ( le , file_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c - > open_count > 0 )
2016-07-27 19:24:26 +00:00
return TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( has_open_children ( c ) )
return TRUE ;
2016-03-23 20:35:05 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return FALSE ;
}
static NTSTATUS duplicate_fcb ( fcb * oldfcb , fcb * * pfcb ) {
2016-09-04 15:27:46 +00:00
device_extension * Vcb = oldfcb - > Vcb ;
2016-07-27 19:24:26 +00:00
fcb * fcb ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// FIXME - we can skip a lot of this if the inode is about to be deleted
2017-09-08 08:02:43 +00:00
fcb = create_fcb ( Vcb , PagedPool ) ; // FIXME - what if we duplicate the paging file?
2016-07-27 19:24:26 +00:00
if ( ! fcb ) {
2016-03-23 20:35:05 +00:00
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
fcb - > Vcb = Vcb ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
fcb - > Header . AllocationSize = oldfcb - > Header . AllocationSize ;
fcb - > Header . FileSize = oldfcb - > Header . FileSize ;
fcb - > Header . ValidDataLength = oldfcb - > Header . ValidDataLength ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > type = oldfcb - > type ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( oldfcb - > ads ) {
fcb - > ads = TRUE ;
fcb - > adshash = oldfcb - > adshash ;
2016-09-04 15:27:46 +00:00
fcb - > adsmaxlen = oldfcb - > adsmaxlen ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( oldfcb - > adsxattr . Buffer & & oldfcb - > adsxattr . Length > 0 ) {
fcb - > adsxattr . Length = oldfcb - > adsxattr . Length ;
fcb - > adsxattr . MaximumLength = fcb - > adsxattr . Length + 1 ;
fcb - > adsxattr . Buffer = ExAllocatePoolWithTag ( PagedPool , fcb - > adsxattr . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! fcb - > adsxattr . Buffer ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2016-07-27 19:24:26 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( fcb - > adsxattr . Buffer , oldfcb - > adsxattr . Buffer , fcb - > adsxattr . Length ) ;
fcb - > adsxattr . Buffer [ fcb - > adsxattr . Length ] = 0 ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( oldfcb - > adsdata . Buffer & & oldfcb - > adsdata . Length > 0 ) {
fcb - > adsdata . Length = fcb - > adsdata . MaximumLength = oldfcb - > adsdata . Length ;
fcb - > adsdata . Buffer = ExAllocatePoolWithTag ( PagedPool , fcb - > adsdata . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! fcb - > adsdata . Buffer ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
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
RtlCopyMemory ( fcb - > adsdata . Buffer , oldfcb - > adsdata . Buffer , fcb - > adsdata . Length ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( & fcb - > inode_item , & oldfcb - > inode_item , sizeof ( INODE_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
fcb - > inode_item_changed = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( oldfcb - > sd & & RtlLengthSecurityDescriptor ( oldfcb - > sd ) > 0 ) {
fcb - > sd = ExAllocatePoolWithTag ( PagedPool , RtlLengthSecurityDescriptor ( oldfcb - > sd ) , ALLOC_TAG ) ;
if ( ! fcb - > sd ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
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
RtlCopyMemory ( fcb - > sd , oldfcb - > sd , RtlLengthSecurityDescriptor ( oldfcb - > sd ) ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > atts = oldfcb - > atts ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = oldfcb - > extents . Flink ;
while ( le ! = & oldfcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! ext - > ignore ) {
2017-09-08 08:02:43 +00:00
extent * ext2 = ExAllocatePoolWithTag ( PagedPool , offsetof ( extent , extent_data ) + ext - > datalen , ALLOC_TAG ) ;
2016-07-27 19:24:26 +00:00
if ( ! ext2 ) {
2016-03-23 20:35:05 +00:00
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ext2 - > offset = ext - > offset ;
ext2 - > datalen = ext - > datalen ;
2017-09-08 08:02:43 +00:00
if ( ext2 - > datalen > 0 )
RtlCopyMemory ( & ext2 - > extent_data , & ext - > extent_data , ext2 - > datalen ) ;
2016-07-27 19:24:26 +00:00
ext2 - > unique = FALSE ;
ext2 - > ignore = FALSE ;
2017-01-01 17:12:12 +00:00
ext2 - > inserted = TRUE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ext - > csum ) {
ULONG len ;
2017-09-08 08:02:43 +00:00
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
if ( ext - > extent_data . compression = = BTRFS_COMPRESSION_NONE )
len = ( ULONG ) ed2 - > num_bytes ;
2017-01-01 17:12:12 +00:00
else
2017-09-08 08:02:43 +00:00
len = ( ULONG ) ed2 - > size ;
2017-01-01 17:12:12 +00:00
len = len * sizeof ( UINT32 ) / Vcb - > superblock . sector_size ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ext2 - > csum = ExAllocatePoolWithTag ( PagedPool , len , ALLOC_TAG ) ;
if ( ! ext2 - > csum ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , 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
RtlCopyMemory ( ext2 - > csum , ext - > csum , len ) ;
} else
ext2 - > csum = NULL ;
2016-07-27 19:24:26 +00:00
InsertTailList ( & fcb - > extents , & ext2 - > list_entry ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = oldfcb - > hardlinks . Flink ;
while ( le ! = & oldfcb - > hardlinks ) {
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) , * hl2 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
hl2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( hardlink ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! hl2 ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
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
hl2 - > parent = hl - > parent ;
hl2 - > index = hl - > index ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
hl2 - > name . Length = hl2 - > name . MaximumLength = hl - > name . Length ;
hl2 - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , hl2 - > name . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! hl2 - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl2 ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
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
RtlCopyMemory ( hl2 - > name . Buffer , hl - > name . Buffer , hl - > name . Length ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
hl2 - > utf8 . Length = hl2 - > utf8 . MaximumLength = hl - > utf8 . Length ;
hl2 - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , hl2 - > utf8 . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! hl2 - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl2 - > name . Buffer ) ;
ExFreePool ( hl2 ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
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
RtlCopyMemory ( hl2 - > utf8 . Buffer , hl - > utf8 . Buffer , hl - > utf8 . Length ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InsertTailList ( & fcb - > hardlinks , & hl2 - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( oldfcb - > reparse_xattr . Buffer & & oldfcb - > reparse_xattr . Length > 0 ) {
fcb - > reparse_xattr . Length = fcb - > reparse_xattr . MaximumLength = oldfcb - > reparse_xattr . Length ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > reparse_xattr . Buffer = ExAllocatePoolWithTag ( PagedPool , fcb - > reparse_xattr . MaximumLength , ALLOC_TAG ) ;
if ( ! fcb - > reparse_xattr . Buffer ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
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
RtlCopyMemory ( fcb - > reparse_xattr . Buffer , oldfcb - > reparse_xattr . Buffer , fcb - > reparse_xattr . Length ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( oldfcb - > ea_xattr . Buffer & & oldfcb - > ea_xattr . Length > 0 ) {
fcb - > ea_xattr . Length = fcb - > ea_xattr . MaximumLength = oldfcb - > ea_xattr . Length ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > ea_xattr . Buffer = ExAllocatePoolWithTag ( PagedPool , fcb - > ea_xattr . MaximumLength , ALLOC_TAG ) ;
if ( ! fcb - > ea_xattr . Buffer ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2016-10-29 17:05:10 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlCopyMemory ( fcb - > ea_xattr . Buffer , oldfcb - > ea_xattr . Buffer , fcb - > ea_xattr . Length ) ;
}
2016-07-27 19:24:26 +00:00
2017-09-08 08:02:43 +00:00
fcb - > prop_compression = oldfcb - > prop_compression ;
le = oldfcb - > xattrs . Flink ;
while ( le ! = & oldfcb - > xattrs ) {
xattr * xa = CONTAINING_RECORD ( le , xattr , list_entry ) ;
if ( xa - > valuelen > 0 ) {
xattr * xa2 ;
xa2 = ExAllocatePoolWithTag ( PagedPool , offsetof ( xattr , data [ 0 ] ) + xa - > namelen + xa - > valuelen , ALLOC_TAG ) ;
if ( ! xa2 ) {
ERR ( " out of memory \n " ) ;
free_fcb ( Vcb , fcb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
xa2 - > namelen = xa - > namelen ;
xa2 - > valuelen = xa - > valuelen ;
xa2 - > dirty = xa - > dirty ;
memcpy ( xa2 - > data , xa - > data , xa - > namelen + xa - > valuelen ) ;
InsertTailList ( & fcb - > xattrs , & xa2 - > list_entry ) ;
}
le = le - > Flink ;
}
2016-07-27 19:24:26 +00:00
end :
* pfcb = fcb ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
typedef struct _move_entry {
file_ref * fileref ;
fcb * dummyfcb ;
file_ref * dummyfileref ;
struct _move_entry * parent ;
LIST_ENTRY list_entry ;
} move_entry ;
2017-09-08 08:02:43 +00:00
static NTSTATUS add_children_to_move_list ( device_extension * Vcb , move_entry * me , PIRP Irp ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceSharedLite ( & me - > fileref - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
le = me - > fileref - > fcb - > dir_children_index . Flink ;
while ( le ! = & me - > fileref - > fcb - > dir_children_index ) {
dir_child * dc = CONTAINING_RECORD ( le , dir_child , list_entry_index ) ;
file_ref * fr ;
move_entry * me2 ;
Status = open_fileref_child ( Vcb , me - > fileref , & dc - > name , TRUE , TRUE , dc - > index = = 0 ? TRUE : FALSE , PagedPool , & fr , Irp ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2017-09-08 08:02:43 +00:00
ERR ( " open_fileref_child returned %08x \n " , Status ) ;
ExReleaseResourceLite ( & me - > fileref - > fcb - > nonpaged - > dir_children_lock ) ;
return Status ;
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
me2 = ExAllocatePoolWithTag ( PagedPool , sizeof ( move_entry ) , ALLOC_TAG ) ;
if ( ! me2 ) {
ERR ( " out of memory \n " ) ;
ExReleaseResourceLite ( & me - > fileref - > fcb - > nonpaged - > dir_children_lock ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
me2 - > fileref = fr ;
me2 - > dummyfcb = NULL ;
me2 - > dummyfileref = NULL ;
me2 - > parent = me ;
InsertHeadList ( & me - > list_entry , & me2 - > list_entry ) ;
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & me - > fileref - > fcb - > nonpaged - > dir_children_lock ) ;
return STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
}
2017-01-01 17:12:12 +00:00
void remove_dir_child_from_hash_lists ( fcb * fcb , dir_child * dc ) {
UINT8 c ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c = dc - > hash > > 24 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > hash_ptrs [ c ] = = & dc - > list_entry_hash ) {
if ( dc - > list_entry_hash . Flink = = & fcb - > dir_children_hash )
fcb - > hash_ptrs [ c ] = NULL ;
else {
dir_child * dc2 = CONTAINING_RECORD ( dc - > list_entry_hash . Flink , dir_child , list_entry_hash ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc2 - > hash > > 24 = = c )
fcb - > hash_ptrs [ c ] = & dc2 - > list_entry_hash ;
else
fcb - > hash_ptrs [ c ] = NULL ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RemoveEntryList ( & dc - > list_entry_hash ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c = dc - > hash_uc > > 24 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > hash_ptrs_uc [ c ] = = & dc - > list_entry_hash_uc ) {
if ( dc - > list_entry_hash_uc . Flink = = & fcb - > dir_children_hash_uc )
fcb - > hash_ptrs_uc [ c ] = NULL ;
else {
dir_child * dc2 = CONTAINING_RECORD ( dc - > list_entry_hash_uc . Flink , dir_child , list_entry_hash_uc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc2 - > hash_uc > > 24 = = c )
fcb - > hash_ptrs_uc [ c ] = & dc2 - > list_entry_hash_uc ;
else
fcb - > hash_ptrs_uc [ c ] = NULL ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RemoveEntryList ( & dc - > list_entry_hash_uc ) ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS create_directory_fcb ( device_extension * Vcb , root * r , fcb * parfcb , fcb * * pfcb ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
fcb * fcb ;
SECURITY_SUBJECT_CONTEXT subjcont ;
PSID owner ;
BOOLEAN defaulted ;
2016-07-27 19:24:26 +00:00
LARGE_INTEGER time ;
BTRFS_TIME now ;
2017-09-08 08:02:43 +00:00
fcb = create_fcb ( Vcb , PagedPool ) ;
if ( ! fcb ) {
2016-07-27 19:24:26 +00:00
ERR ( " out of memory \n " ) ;
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
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
fcb - > Vcb = Vcb ;
fcb - > subvol = r ;
fcb - > inode = InterlockedIncrement64 ( & r - > lastinode ) ;
fcb - > type = BTRFS_TYPE_DIRECTORY ;
fcb - > inode_item . generation = Vcb - > superblock . generation ;
fcb - > inode_item . transid = Vcb - > superblock . generation ;
fcb - > inode_item . st_nlink = 1 ;
fcb - > inode_item . st_mode = __S_IFDIR | inherit_mode ( parfcb , TRUE ) ;
fcb - > inode_item . st_atime = fcb - > inode_item . st_ctime = fcb - > inode_item . st_mtime = fcb - > inode_item . otime = now ;
fcb - > inode_item . st_gid = GID_NOBODY ;
fcb - > atts = get_file_attributes ( Vcb , fcb - > subvol , fcb - > inode , fcb - > type , FALSE , TRUE , NULL ) ;
SeCaptureSubjectContext ( & subjcont ) ;
Status = SeAssignSecurity ( parfcb - > sd , NULL , ( void * * ) & fcb - > sd , TRUE , & subjcont , IoGetFileObjectGenericMapping ( ) , PagedPool ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " SeAssignSecurity returned %08x \n " , Status ) ;
return Status ;
}
if ( ! fcb - > sd ) {
ERR ( " SeAssignSecurity returned NULL security descriptor \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
Status = RtlGetOwnerSecurityDescriptor ( fcb - > sd , & owner , & defaulted ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlGetOwnerSecurityDescriptor returned %08x \n " , Status ) ;
fcb - > inode_item . st_uid = UID_NOBODY ;
fcb - > sd_dirty = TRUE ;
} else {
fcb - > inode_item . st_uid = sid_to_uid ( owner ) ;
fcb - > sd_dirty = fcb - > inode_item . st_uid = = UID_NOBODY ;
}
find_gid ( fcb , parfcb , & subjcont ) ;
fcb - > inode_item_changed = TRUE ;
InsertTailList ( & r - > fcbs , & fcb - > list_entry ) ;
InsertTailList ( & Vcb - > all_fcbs , & fcb - > list_entry_all ) ;
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
fcb - > Header . AllocationSize . QuadPart = 0 ;
fcb - > Header . FileSize . QuadPart = 0 ;
fcb - > Header . ValidDataLength . QuadPart = 0 ;
fcb - > created = TRUE ;
mark_fcb_dirty ( fcb ) ;
if ( parfcb - > inode_item . flags & BTRFS_INODE_COMPRESS )
fcb - > inode_item . flags | = BTRFS_INODE_COMPRESS ;
fcb - > prop_compression = parfcb - > prop_compression ;
fcb - > prop_compression_changed = fcb - > prop_compression ! = PropCompression_None ;
fcb - > hash_ptrs = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! fcb - > hash_ptrs ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlZeroMemory ( fcb - > hash_ptrs , sizeof ( LIST_ENTRY * ) * 256 ) ;
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 ;
}
RtlZeroMemory ( fcb - > hash_ptrs_uc , sizeof ( LIST_ENTRY * ) * 256 ) ;
* pfcb = fcb ;
return STATUS_SUCCESS ;
}
static NTSTATUS move_across_subvols ( file_ref * fileref , ccb * ccb , file_ref * destdir , PANSI_STRING utf8 , PUNICODE_STRING fnus , PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
LIST_ENTRY move_list , * le ;
move_entry * me ;
LARGE_INTEGER time ;
BTRFS_TIME now ;
file_ref * origparent ;
InitializeListHead ( & move_list ) ;
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
me = ExAllocatePoolWithTag ( PagedPool , sizeof ( move_entry ) , ALLOC_TAG ) ;
if ( ! me ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
origparent = fileref - > parent ;
me - > fileref = fileref ;
increase_fileref_refcount ( me - > fileref ) ;
me - > dummyfcb = NULL ;
me - > dummyfileref = NULL ;
me - > parent = NULL ;
InsertTailList ( & move_list , & me - > list_entry ) ;
le = move_list . Flink ;
while ( le ! = & move_list ) {
me = CONTAINING_RECORD ( le , move_entry , list_entry ) ;
ExAcquireResourceSharedLite ( me - > fileref - > fcb - > Header . Resource , TRUE ) ;
if ( ! me - > fileref - > fcb - > ads & & me - > fileref - > fcb - > subvol = = origparent - > fcb - > subvol ) {
Status = add_children_to_move_list ( fileref - > fcb - > Vcb , me , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " add_children_to_move_list returned %08x \n " , Status ) ;
goto end ;
}
}
ExReleaseResourceLite ( me - > fileref - > fcb - > Header . Resource ) ;
le = le - > Flink ;
}
send_notification_fileref ( fileref , fileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_REMOVED , NULL ) ;
// loop through list and create new inodes
le = move_list . Flink ;
while ( le ! = & move_list ) {
me = CONTAINING_RECORD ( le , move_entry , list_entry ) ;
if ( me - > fileref - > fcb - > inode ! = SUBVOL_ROOT_INODE & & me - > fileref - > fcb ! = fileref - > fcb - > Vcb - > dummy_fcb ) {
2016-07-27 19:24:26 +00:00
if ( ! me - > dummyfcb ) {
ULONG defda ;
2017-01-01 17:12:12 +00:00
BOOL inserted = FALSE ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le3 ;
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( me - > fileref - > fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = duplicate_fcb ( me - > fileref - > fcb , & me - > dummyfcb ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " duplicate_fcb returned %08x \n " , Status ) ;
ExReleaseResourceLite ( me - > fileref - > fcb - > Header . Resource ) ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me - > dummyfcb - > subvol = me - > fileref - > fcb - > subvol ;
me - > dummyfcb - > inode = me - > fileref - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! me - > dummyfcb - > ads ) {
me - > dummyfcb - > sd_dirty = me - > fileref - > fcb - > sd_dirty ;
me - > dummyfcb - > atts_changed = me - > fileref - > fcb - > atts_changed ;
me - > dummyfcb - > atts_deleted = me - > fileref - > fcb - > atts_deleted ;
me - > dummyfcb - > extents_changed = me - > fileref - > fcb - > extents_changed ;
me - > dummyfcb - > reparse_xattr_changed = me - > fileref - > fcb - > reparse_xattr_changed ;
2016-10-29 17:05:10 +00:00
me - > dummyfcb - > ea_changed = me - > fileref - > fcb - > ea_changed ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me - > dummyfcb - > created = me - > fileref - > fcb - > created ;
me - > dummyfcb - > deleted = me - > fileref - > fcb - > deleted ;
mark_fcb_dirty ( me - > dummyfcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! me - > fileref - > fcb - > ads ) {
LIST_ENTRY * le2 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me - > fileref - > fcb - > subvol = destdir - > fcb - > subvol ;
2016-10-29 17:05:10 +00:00
me - > fileref - > fcb - > inode = InterlockedIncrement64 ( & destdir - > fcb - > subvol - > lastinode ) ;
2016-07-27 19:24:26 +00:00
me - > fileref - > fcb - > inode_item . st_nlink = 1 ;
2017-09-08 08:02:43 +00:00
defda = get_file_attributes ( me - > fileref - > fcb - > Vcb , me - > fileref - > fcb - > subvol , me - > fileref - > fcb - > inode ,
me - > fileref - > fcb - > type , me - > fileref - > dc & & me - > fileref - > dc - > name . Length > = sizeof ( WCHAR ) & & me - > fileref - > dc - > name . Buffer [ 0 ] = = ' . ' ,
TRUE , Irp ) ;
2016-07-27 19:24:26 +00:00
me - > fileref - > fcb - > sd_dirty = ! ! me - > fileref - > fcb - > sd ;
me - > fileref - > fcb - > atts_changed = defda ! = me - > fileref - > fcb - > atts ;
me - > fileref - > fcb - > extents_changed = ! IsListEmpty ( & me - > fileref - > fcb - > extents ) ;
me - > fileref - > fcb - > reparse_xattr_changed = ! ! me - > fileref - > fcb - > reparse_xattr . Buffer ;
2016-10-29 17:05:10 +00:00
me - > fileref - > fcb - > ea_changed = ! ! me - > fileref - > fcb - > ea_xattr . Buffer ;
2017-09-08 08:02:43 +00:00
me - > fileref - > fcb - > xattrs_changed = ! IsListEmpty ( & me - > fileref - > fcb - > xattrs ) ;
2016-10-29 17:05:10 +00:00
me - > fileref - > fcb - > inode_item_changed = TRUE ;
2017-09-08 08:02:43 +00:00
le2 = me - > fileref - > fcb - > xattrs . Flink ;
while ( le2 ! = & me - > fileref - > fcb - > xattrs ) {
xattr * xa = CONTAINING_RECORD ( le2 , xattr , list_entry ) ;
xa - > dirty = TRUE ;
le2 = le2 - > Flink ;
}
if ( le = = move_list . Flink ) { // first entry
me - > fileref - > fcb - > inode_item . transid = me - > fileref - > fcb - > Vcb - > superblock . generation ;
me - > fileref - > fcb - > inode_item . sequence + + ;
if ( ! ccb - > user_set_change_time )
me - > fileref - > fcb - > inode_item . st_ctime = now ;
}
2016-07-27 19:24:26 +00:00
le2 = me - > fileref - > fcb - > extents . Flink ;
while ( le2 ! = & me - > fileref - > fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le2 , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( ! ext - > ignore & & ( ext - > extent_data . type = = EXTENT_TYPE_REGULAR | | ext - > extent_data . type = = EXTENT_TYPE_PREALLOC ) ) {
EXTENT_DATA2 * ed2 = ( EXTENT_DATA2 * ) ext - > extent_data . data ;
2016-07-27 19:24:26 +00:00
if ( ed2 - > size ! = 0 ) {
chunk * c = get_chunk_from_address ( me - > fileref - > fcb - > Vcb , ed2 - > address ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! c ) {
ERR ( " get_chunk_from_address(%llx) failed \n " , ed2 - > address ) ;
} else {
Status = update_changed_extent_ref ( me - > fileref - > fcb - > Vcb , c , ed2 - > address , ed2 - > size , me - > fileref - > fcb - > subvol - > id , me - > fileref - > fcb - > inode ,
2016-10-29 17:05:10 +00:00
ext - > offset - ed2 - > offset , 1 , me - > fileref - > fcb - > inode_item . flags & BTRFS_INODE_NODATASUM , FALSE , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " update_changed_extent_ref returned %08x \n " , Status ) ;
ExReleaseResourceLite ( me - > fileref - > fcb - > Header . Resource ) ;
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le2 = le2 - > Flink ;
}
} else {
me - > fileref - > fcb - > subvol = me - > parent - > fileref - > fcb - > subvol ;
me - > fileref - > fcb - > inode = me - > parent - > fileref - > fcb - > inode ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me - > fileref - > fcb - > created = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InsertHeadList ( & me - > fileref - > fcb - > list_entry , & me - > dummyfcb - > list_entry ) ;
RemoveEntryList ( & me - > fileref - > fcb - > list_entry ) ;
2017-09-08 08:02:43 +00:00
le3 = destdir - > fcb - > subvol - > fcbs . Flink ;
while ( le3 ! = & destdir - > fcb - > subvol - > fcbs ) {
fcb * fcb = CONTAINING_RECORD ( le3 , struct _fcb , list_entry ) ;
2017-01-01 17:12:12 +00:00
if ( fcb - > inode > me - > fileref - > fcb - > inode ) {
2017-09-08 08:02:43 +00:00
InsertHeadList ( le3 - > Blink , & me - > fileref - > fcb - > list_entry ) ;
2017-01-01 17:12:12 +00:00
inserted = TRUE ;
break ;
}
2017-09-08 08:02:43 +00:00
le3 = le3 - > Flink ;
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 ( ! inserted )
InsertTailList ( & destdir - > fcb - > subvol - > fcbs , & me - > fileref - > fcb - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InsertTailList ( & me - > fileref - > fcb - > Vcb - > all_fcbs , & me - > dummyfcb - > list_entry_all ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( ! IsListEmpty ( & me - > fileref - > fcb - > hardlinks ) ) {
2017-09-08 08:02:43 +00:00
hardlink * hl = CONTAINING_RECORD ( RemoveHeadList ( & me - > fileref - > fcb - > hardlinks ) , hardlink , list_entry ) ;
2016-07-27 19:24:26 +00:00
if ( hl - > name . Buffer )
ExFreePool ( hl - > name . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( hl - > utf8 . Buffer )
ExFreePool ( hl - > utf8 . Buffer ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
ExFreePool ( hl ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
me - > fileref - > fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( me - > fileref - > fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ( ! me - > dummyfcb - > ads & & me - > dummyfcb - > inode_item . st_nlink > 1 ) | | ( me - > dummyfcb - > ads & & me - > parent - > dummyfcb - > inode_item . st_nlink > 1 ) ) {
LIST_ENTRY * le2 = le - > Flink ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( le2 ! = & move_list ) {
move_entry * me2 = CONTAINING_RECORD ( le2 , move_entry , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( me2 - > fileref - > fcb = = me - > fileref - > fcb & & ! me2 - > fileref - > fcb - > ads ) {
me2 - > dummyfcb = me - > dummyfcb ;
InterlockedIncrement ( & me - > dummyfcb - > refcount ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le2 = le2 - > Flink ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( me - > fileref - > fcb - > Header . Resource ) ;
} else {
ExAcquireResourceExclusiveLite ( me - > fileref - > fcb - > Header . Resource , TRUE ) ;
me - > fileref - > fcb - > inode_item . st_nlink + + ;
2016-10-29 17:05:10 +00:00
me - > fileref - > fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( me - > fileref - > fcb - > Header . Resource ) ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > fcb - > subvol - > root_item . ctransid = fileref - > fcb - > Vcb - > superblock . generation ;
fileref - > fcb - > subvol - > root_item . ctime = now ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// loop through list and create new filerefs
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = move_list . Flink ;
while ( le ! = & move_list ) {
hardlink * hl ;
2017-01-01 17:12:12 +00:00
BOOL name_changed = FALSE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me = CONTAINING_RECORD ( le , move_entry , list_entry ) ;
2017-09-08 08:02:43 +00:00
me - > dummyfileref = create_fileref ( fileref - > fcb - > Vcb ) ;
2016-07-27 19:24:26 +00:00
if ( ! me - > dummyfileref ) {
2016-03-23 20:35:05 +00:00
ERR ( " out of memory \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
if ( me - > fileref - > fcb = = me - > fileref - > fcb - > Vcb - > dummy_fcb ) {
root * r = me - > parent ? me - > parent - > fileref - > fcb - > subvol : destdir - > fcb - > subvol ;
Status = create_directory_fcb ( me - > fileref - > fcb - > Vcb , r , me - > fileref - > parent - > fcb , & me - > fileref - > fcb ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " create_directory_fcb returnd %08x \n " , Status ) ;
goto end ;
}
me - > fileref - > dc - > key . obj_id = me - > fileref - > fcb - > inode ;
me - > fileref - > dc - > key . obj_type = TYPE_INODE_ITEM ;
me - > dummyfileref - > fcb = me - > fileref - > fcb - > Vcb - > dummy_fcb ;
} else if ( me - > fileref - > fcb - > inode = = SUBVOL_ROOT_INODE ) {
2016-07-27 19:24:26 +00:00
me - > dummyfileref - > fcb = me - > fileref - > fcb ;
2017-09-08 08:02:43 +00:00
me - > fileref - > fcb - > subvol - > parent = le = = move_list . Flink ? destdir - > fcb - > subvol - > id : me - > parent - > fileref - > fcb - > subvol - > id ;
} else
2016-07-27 19:24:26 +00:00
me - > dummyfileref - > fcb = me - > dummyfcb ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InterlockedIncrement ( & me - > dummyfileref - > fcb - > refcount ) ;
me - > dummyfileref - > oldutf8 = me - > fileref - > oldutf8 ;
2017-09-08 08:02:43 +00:00
me - > dummyfileref - > oldindex = me - > fileref - > dc - > index ;
if ( le = = move_list . Flink & & ( me - > fileref - > dc - > utf8 . Length ! = utf8 - > Length | | RtlCompareMemory ( me - > fileref - > dc - > utf8 . Buffer , utf8 - > Buffer , utf8 - > Length ) ! = utf8 - > Length ) )
name_changed = TRUE ;
if ( ( le = = move_list . Flink | | me - > fileref - > fcb - > inode = = SUBVOL_ROOT_INODE ) & & ! me - > dummyfileref - > oldutf8 . Buffer ) {
me - > dummyfileref - > oldutf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , me - > fileref - > dc - > utf8 . Length , ALLOC_TAG ) ;
if ( ! me - > dummyfileref - > oldutf8 . Buffer ) {
2016-07-27 19:24:26 +00:00
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( me - > dummyfileref - > oldutf8 . Buffer , me - > fileref - > dc - > utf8 . Buffer , me - > fileref - > dc - > utf8 . Length ) ;
me - > dummyfileref - > oldutf8 . Length = me - > dummyfileref - > oldutf8 . MaximumLength = me - > fileref - > dc - > utf8 . Length ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me - > dummyfileref - > delete_on_close = me - > fileref - > delete_on_close ;
me - > dummyfileref - > deleted = me - > fileref - > deleted ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me - > dummyfileref - > created = me - > fileref - > created ;
me - > fileref - > created = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me - > dummyfileref - > parent = me - > parent ? me - > parent - > dummyfileref : origparent ;
increase_fileref_refcount ( me - > dummyfileref - > parent ) ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & me - > dummyfileref - > parent - > nonpaged - > children_lock , TRUE ) ;
InsertTailList ( & me - > dummyfileref - > parent - > children , & me - > dummyfileref - > list_entry ) ;
ExReleaseResourceLite ( & me - > dummyfileref - > parent - > nonpaged - > children_lock ) ;
2016-07-27 19:24:26 +00:00
me - > dummyfileref - > debug_desc = me - > fileref - > debug_desc ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( me - > dummyfileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY )
me - > dummyfileref - > fcb - > fileref = me - > dummyfileref ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! me - > parent ) {
RemoveEntryList ( & me - > fileref - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
increase_fileref_refcount ( destdir ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( me - > fileref - > dc ) {
// remove from old parent
ExAcquireResourceExclusiveLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
RemoveEntryList ( & me - > fileref - > dc - > list_entry_index ) ;
remove_dir_child_from_hash_lists ( me - > fileref - > parent - > fcb , me - > fileref - > dc ) ;
ExReleaseResourceLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
me - > fileref - > parent - > fcb - > inode_item . st_size - = me - > fileref - > dc - > utf8 . Length * 2 ;
me - > fileref - > parent - > fcb - > inode_item . transid = me - > fileref - > fcb - > Vcb - > superblock . generation ;
me - > fileref - > parent - > fcb - > inode_item . sequence + + ;
me - > fileref - > parent - > fcb - > inode_item . st_ctime = now ;
me - > fileref - > parent - > fcb - > inode_item . st_mtime = now ;
me - > fileref - > parent - > fcb - > inode_item_changed = TRUE ;
mark_fcb_dirty ( me - > fileref - > parent - > fcb ) ;
2017-01-01 17:12:12 +00:00
if ( name_changed ) {
ExFreePool ( me - > fileref - > dc - > utf8 . Buffer ) ;
ExFreePool ( me - > fileref - > dc - > name . Buffer ) ;
ExFreePool ( me - > fileref - > dc - > name_uc . Buffer ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
me - > fileref - > dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 - > Length , ALLOC_TAG ) ;
if ( ! me - > fileref - > dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
me - > fileref - > dc - > utf8 . Length = me - > fileref - > dc - > utf8 . MaximumLength = utf8 - > Length ;
RtlCopyMemory ( me - > fileref - > dc - > utf8 . Buffer , utf8 - > Buffer , utf8 - > Length ) ;
me - > fileref - > dc - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , fnus - > Length , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! me - > fileref - > dc - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
me - > fileref - > dc - > name . Length = me - > fileref - > dc - > name . MaximumLength = fnus - > Length ;
RtlCopyMemory ( me - > fileref - > dc - > name . Buffer , fnus - > Buffer , fnus - > Length ) ;
Status = RtlUpcaseUnicodeString ( & fileref - > dc - > name_uc , & fileref - > dc - > name , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUpcaseUnicodeString returned %08x \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
me - > fileref - > dc - > hash = calc_crc32c ( 0xffffffff , ( UINT8 * ) me - > fileref - > dc - > name . Buffer , me - > fileref - > dc - > name . Length ) ;
me - > fileref - > dc - > hash_uc = calc_crc32c ( 0xffffffff , ( UINT8 * ) me - > fileref - > dc - > name_uc . Buffer , me - > fileref - > dc - > name_uc . Length ) ;
}
2017-09-08 08:02:43 +00:00
if ( me - > fileref - > dc - > key . obj_type = = TYPE_INODE_ITEM )
me - > fileref - > dc - > key . obj_id = me - > fileref - > fcb - > inode ;
2017-01-01 17:12:12 +00:00
// add to new parent
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExAcquireResourceExclusiveLite ( & destdir - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
if ( IsListEmpty ( & destdir - > fcb - > dir_children_index ) )
me - > fileref - > dc - > index = 2 ;
else {
dir_child * dc2 = CONTAINING_RECORD ( destdir - > fcb - > dir_children_index . Blink , dir_child , list_entry_index ) ;
me - > fileref - > dc - > index = max ( 2 , dc2 - > index + 1 ) ;
}
2017-01-01 17:12:12 +00:00
InsertTailList ( & destdir - > fcb - > dir_children_index , & me - > fileref - > dc - > list_entry_index ) ;
insert_dir_child_into_hash_lists ( destdir - > fcb , me - > fileref - > dc ) ;
ExReleaseResourceLite ( & destdir - > fcb - > nonpaged - > dir_children_lock ) ;
}
2017-09-08 08:02:43 +00:00
free_fileref ( fileref - > fcb - > Vcb , me - > fileref - > parent ) ;
2017-01-01 17:12:12 +00:00
me - > fileref - > parent = destdir ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & me - > fileref - > parent - > nonpaged - > children_lock , TRUE ) ;
InsertTailList ( & me - > fileref - > parent - > children , & me - > fileref - > list_entry ) ;
ExReleaseResourceLite ( & me - > fileref - > parent - > nonpaged - > children_lock ) ;
2016-07-27 19:24:26 +00:00
TRACE ( " me->fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx \n " , me - > fileref - > parent - > fcb - > inode , me - > fileref - > parent - > fcb - > inode_item . st_size ) ;
2017-09-08 08:02:43 +00:00
me - > fileref - > parent - > fcb - > inode_item . st_size + = me - > fileref - > dc - > utf8 . Length * 2 ;
2016-07-27 19:24:26 +00:00
TRACE ( " me->fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx \n " , me - > fileref - > parent - > fcb - > inode , me - > fileref - > parent - > fcb - > inode_item . st_size ) ;
me - > fileref - > parent - > fcb - > inode_item . transid = me - > fileref - > fcb - > Vcb - > superblock . generation ;
me - > fileref - > parent - > fcb - > inode_item . sequence + + ;
me - > fileref - > parent - > fcb - > inode_item . st_ctime = now ;
me - > fileref - > parent - > fcb - > inode_item . st_mtime = now ;
2016-10-29 17:05:10 +00:00
me - > fileref - > parent - > fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( me - > fileref - > parent - > fcb ) ;
2017-09-08 08:02:43 +00:00
} else {
if ( me - > fileref - > dc ) {
ExAcquireResourceExclusiveLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
RemoveEntryList ( & me - > fileref - > dc - > list_entry_index ) ;
if ( ! me - > fileref - > fcb - > ads )
remove_dir_child_from_hash_lists ( me - > fileref - > parent - > fcb , me - > fileref - > dc ) ;
ExReleaseResourceLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
ExAcquireResourceExclusiveLite ( & me - > parent - > fileref - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
if ( me - > fileref - > fcb - > ads )
InsertHeadList ( & me - > parent - > fileref - > fcb - > dir_children_index , & me - > fileref - > dc - > list_entry_index ) ;
else {
if ( me - > fileref - > fcb - > inode ! = SUBVOL_ROOT_INODE )
me - > fileref - > dc - > key . obj_id = me - > fileref - > fcb - > inode ;
if ( IsListEmpty ( & me - > parent - > fileref - > fcb - > dir_children_index ) )
me - > fileref - > dc - > index = 2 ;
else {
dir_child * dc2 = CONTAINING_RECORD ( me - > parent - > fileref - > fcb - > dir_children_index . Blink , dir_child , list_entry_index ) ;
me - > fileref - > dc - > index = max ( 2 , dc2 - > index + 1 ) ;
}
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
InsertTailList ( & me - > parent - > fileref - > fcb - > dir_children_index , & me - > fileref - > dc - > list_entry_index ) ;
insert_dir_child_into_hash_lists ( me - > parent - > fileref - > fcb , me - > fileref - > dc ) ;
}
ExReleaseResourceLite ( & me - > parent - > fileref - > fcb - > nonpaged - > dir_children_lock ) ;
}
}
2016-07-27 19:24:26 +00:00
if ( ! me - > dummyfileref - > fcb - > ads ) {
2016-09-04 15:27:46 +00:00
Status = delete_fileref ( me - > dummyfileref , NULL , Irp , rollback ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref returned %08x \n " , Status ) ;
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( me - > fileref - > fcb - > inode_item . st_nlink > 1 ) {
hl = ExAllocatePoolWithTag ( PagedPool , sizeof ( hardlink ) , ALLOC_TAG ) ;
if ( ! hl ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl - > parent = me - > fileref - > parent - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
hl - > index = me - > fileref - > dc - > index ;
hl - > utf8 . Length = hl - > utf8 . MaximumLength = me - > fileref - > dc - > utf8 . Length ;
2017-01-01 17:12:12 +00:00
hl - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , hl - > utf8 . MaximumLength , ALLOC_TAG ) ;
if ( ! hl - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( hl ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( hl - > utf8 . Buffer , me - > fileref - > dc - > utf8 . Buffer , me - > fileref - > dc - > utf8 . Length ) ;
hl - > name . Length = hl - > name . MaximumLength = me - > fileref - > dc - > name . Length ;
2017-01-01 17:12:12 +00:00
hl - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , hl - > name . MaximumLength , ALLOC_TAG ) ;
if ( ! hl - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( hl - > utf8 . Buffer ) ;
ExFreePool ( hl ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( hl - > name . Buffer , me - > fileref - > dc - > name . Buffer , me - > fileref - > dc - > name . Length ) ;
2017-01-01 17:12:12 +00:00
InsertTailList ( & me - > fileref - > fcb - > hardlinks , & hl - > list_entry ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fileref_dirty ( me - > fileref ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// loop through, and only mark streams as deleted if their parent inodes are also deleted
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = move_list . Flink ;
while ( le ! = & move_list ) {
me = CONTAINING_RECORD ( le , move_entry , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( me - > dummyfileref - > fcb - > ads & & me - > parent - > dummyfileref - > fcb - > deleted ) {
2016-09-04 15:27:46 +00:00
Status = delete_fileref ( me - > dummyfileref , NULL , Irp , rollback ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref returned %08x \n " , Status ) ;
goto end ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
destdir - > fcb - > subvol - > root_item . ctransid = destdir - > fcb - > Vcb - > superblock . generation ;
destdir - > fcb - > subvol - > root_item . ctime = now ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
me = CONTAINING_RECORD ( move_list . Flink , move_entry , list_entry ) ;
2017-09-08 08:02:43 +00:00
send_notification_fileref ( fileref , fileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_ADDED , NULL ) ;
send_notification_fileref ( me - > dummyfileref - > parent , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
send_notification_fileref ( fileref - > parent , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
end :
while ( ! IsListEmpty ( & move_list ) ) {
le = RemoveHeadList ( & move_list ) ;
me = CONTAINING_RECORD ( le , move_entry , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( me - > dummyfcb )
2017-09-08 08:02:43 +00:00
free_fcb ( fileref - > fcb - > Vcb , me - > dummyfcb ) ;
2017-01-01 17:12:12 +00:00
if ( me - > dummyfileref )
2017-09-08 08:02:43 +00:00
free_fileref ( fileref - > fcb - > Vcb , me - > dummyfileref ) ;
free_fileref ( fileref - > fcb - > Vcb , me - > fileref ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( me ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2017-01-01 17:12:12 +00:00
void insert_dir_child_into_hash_lists ( fcb * fcb , dir_child * dc ) {
BOOL inserted ;
LIST_ENTRY * le ;
UINT8 c , d ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c = dc - > hash > > 24 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
inserted = FALSE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
d = c ;
do {
le = fcb - > hash_ptrs [ d ] ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( d = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
d - - ;
} while ( ! le ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! le )
le = fcb - > dir_children_hash . Flink ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( le ! = & fcb - > dir_children_hash ) {
dir_child * dc2 = 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 ( dc2 - > hash > dc - > hash ) {
InsertHeadList ( le - > Blink , & dc - > list_entry_hash ) ;
inserted = TRUE ;
break ;
}
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
if ( ! inserted )
InsertTailList ( & fcb - > dir_children_hash , & dc - > list_entry_hash ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! fcb - > hash_ptrs [ c ] )
fcb - > hash_ptrs [ c ] = & dc - > list_entry_hash ;
else {
dir_child * dc2 = CONTAINING_RECORD ( fcb - > hash_ptrs [ c ] , dir_child , list_entry_hash ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc2 - > hash > dc - > hash )
fcb - > hash_ptrs [ c ] = & dc - > list_entry_hash ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c = dc - > hash_uc > > 24 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
inserted = FALSE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
d = c ;
do {
le = fcb - > hash_ptrs_uc [ d ] ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( d = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
d - - ;
} while ( ! le ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! le )
le = fcb - > dir_children_hash_uc . Flink ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( le ! = & fcb - > dir_children_hash_uc ) {
dir_child * dc2 = 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 ( dc2 - > hash_uc > dc - > hash_uc ) {
InsertHeadList ( le - > Blink , & dc - > list_entry_hash_uc ) ;
inserted = TRUE ;
break ;
}
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
if ( ! inserted )
InsertTailList ( & fcb - > dir_children_hash_uc , & dc - > list_entry_hash_uc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! fcb - > hash_ptrs_uc [ c ] )
fcb - > hash_ptrs_uc [ c ] = & dc - > list_entry_hash_uc ;
else {
dir_child * dc2 = CONTAINING_RECORD ( fcb - > hash_ptrs_uc [ c ] , dir_child , list_entry_hash_uc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dc2 - > hash_uc > dc - > hash_uc )
fcb - > hash_ptrs_uc [ c ] = & dc - > list_entry_hash_uc ;
}
}
2017-09-08 08:02:43 +00:00
static NTSTATUS set_rename_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject , PFILE_OBJECT tfo ) {
2016-09-04 15:27:46 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2016-03-23 20:35:05 +00:00
FILE_RENAME_INFORMATION * fri = Irp - > AssociatedIrp . SystemBuffer ;
2016-07-27 19:24:26 +00:00
fcb * fcb = FileObject - > FsContext ;
2016-05-05 17:26:47 +00:00
ccb * ccb = FileObject - > FsContext2 ;
2016-07-27 19:24:26 +00:00
file_ref * fileref = ccb ? ccb - > fileref : NULL , * oldfileref = NULL , * related = NULL , * fr2 = NULL ;
2016-03-23 20:35:05 +00:00
WCHAR * fn ;
2017-09-08 08:02:43 +00:00
ULONG fnlen , utf8len , origutf8len ;
2016-03-23 20:35:05 +00:00
UNICODE_STRING fnus ;
ANSI_STRING utf8 ;
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
2016-03-23 20:35:05 +00:00
LARGE_INTEGER time ;
BTRFS_TIME now ;
2016-07-27 19:24:26 +00:00
LIST_ENTRY rollback , * le ;
hardlink * hl ;
2017-09-08 08:02:43 +00:00
SECURITY_SUBJECT_CONTEXT subjcont ;
ACCESS_MASK access ;
2016-07-27 19:24:26 +00:00
InitializeListHead ( & rollback ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " tfo = %p \n " , tfo ) ;
2016-09-04 15:27:46 +00:00
TRACE ( " ReplaceIfExists = %u \n " , IrpSp - > Parameters . SetFile . ReplaceIfExists ) ;
2016-07-27 19:24:26 +00:00
TRACE ( " RootDirectory = %p \n " , fri - > RootDirectory ) ;
TRACE ( " FileName = %.*S \n " , fri - > FileNameLength / sizeof ( WCHAR ) , fri - > FileName ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fn = fri - > FileName ;
fnlen = fri - > FileNameLength / sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! tfo ) {
2016-07-27 19:24:26 +00:00
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref set and no directory given \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2016-03-23 20:35:05 +00:00
} else {
2016-07-27 19:24:26 +00:00
LONG i ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
while ( fnlen > 0 & & ( fri - > FileName [ fnlen - 1 ] = = ' / ' | | fri - > FileName [ fnlen - 1 ] = = ' \\ ' ) )
fnlen - - ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( fnlen = = 0 )
return STATUS_INVALID_PARAMETER ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
for ( i = fnlen - 1 ; i > = 0 ; i - - ) {
if ( fri - > FileName [ i ] = = ' \\ ' | | fri - > FileName [ i ] = = ' / ' ) {
fn = & fri - > FileName [ i + 1 ] ;
fnlen = ( fri - > FileNameLength / sizeof ( WCHAR ) ) - i - 1 ;
break ;
}
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
2017-10-16 18:05:33 +00:00
acquire_fcb_lock_exclusive ( Vcb ) ;
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > ads ) {
2017-09-08 08:02:43 +00:00
// MSDN says that NTFS data streams can be renamed (https://msdn.microsoft.com/en-us/library/windows/hardware/ff540344.aspx),
// but if you try it always seems to return STATUS_INVALID_PARAMETER. There is a function in ntfs.sys called NtfsStreamRename,
// but it never seems to get invoked... If you know what's going on here, I'd appreciate it if you let me know.
Status = STATUS_INVALID_PARAMETER ;
2016-07-27 19:24:26 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fnus . Buffer = fn ;
2017-09-08 08:02:43 +00:00
fnus . Length = fnus . MaximumLength = ( UINT16 ) ( fnlen * sizeof ( WCHAR ) ) ;
2016-03-23 20:35:05 +00:00
TRACE ( " fnus = %.*S \n " , fnus . Length / sizeof ( WCHAR ) , fnus . Buffer ) ;
2017-09-08 08:02:43 +00:00
origutf8len = fileref - > dc - > utf8 . Length ;
2016-03-23 20:35:05 +00:00
Status = RtlUnicodeToUTF8N ( NULL , 0 , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
utf8 . MaximumLength = utf8 . Length = ( UINT16 ) utf8len ;
2016-03-23 20:35:05 +00:00
utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 . MaximumLength , ALLOC_TAG ) ;
if ( ! utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = RtlUnicodeToUTF8N ( utf8 . Buffer , utf8len , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( tfo & & tfo - > FsContext2 ) {
struct _ccb * relatedccb = tfo - > FsContext2 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
related = relatedccb - > fileref ;
2016-07-27 19:24:26 +00:00
increase_fileref_refcount ( related ) ;
2016-10-29 17:05:10 +00:00
} else if ( fnus . Length > = sizeof ( WCHAR ) & & fnus . Buffer [ 0 ] ! = ' \\ ' ) {
related = fileref - > parent ;
increase_fileref_refcount ( related ) ;
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
2016-10-29 17:05:10 +00:00
Status = open_fileref ( Vcb , & oldfileref , & fnus , related , FALSE , NULL , NULL , PagedPool , ccb - > case_sensitive , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
TRACE ( " destination file %S already exists \n " , file_desc_fileref ( oldfileref ) ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref ! = oldfileref & & ! oldfileref - > deleted ) {
2016-09-04 15:27:46 +00:00
if ( ! IrpSp - > Parameters . SetFile . ReplaceIfExists ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_OBJECT_NAME_COLLISION ;
goto end ;
2016-10-29 17:05:10 +00:00
} else if ( ( oldfileref - > open_count > = 1 | | has_open_children ( oldfileref ) ) & & ! oldfileref - > deleted ) {
2016-03-23 20:35:05 +00:00
WARN ( " trying to overwrite open file \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( oldfileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
2016-03-23 20:35:05 +00:00
WARN ( " trying to overwrite directory \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( fileref = = oldfileref | | oldfileref - > deleted ) {
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , oldfileref ) ;
2016-07-27 19:24:26 +00:00
oldfileref = NULL ;
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! related ) {
2016-10-29 17:05:10 +00:00
Status = open_fileref ( Vcb , & related , & fnus , NULL , TRUE , NULL , NULL , PagedPool , ccb - > case_sensitive , Irp ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " open_fileref returned %08x \n " , Status ) ;
goto end ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
if ( related - > fcb = = Vcb - > dummy_fcb ) {
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
SeCaptureSubjectContext ( & subjcont ) ;
if ( ! SeAccessCheck ( related - > fcb - > sd , & subjcont , FALSE , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE , 0 , NULL ,
IoGetFileObjectGenericMapping ( ) , Irp - > RequestorMode , & access , & Status ) ) {
SeReleaseSubjectContext ( & subjcont ) ;
TRACE ( " SeAccessCheck failed, returning %08x \n " , Status ) ;
goto end ;
}
SeReleaseSubjectContext ( & subjcont ) ;
2016-05-05 17:26:47 +00:00
if ( has_open_children ( fileref ) ) {
2016-03-23 20:35:05 +00:00
WARN ( " trying to rename file with open children \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( oldfileref ) {
2016-09-04 15:27:46 +00:00
SeCaptureSubjectContext ( & subjcont ) ;
if ( ! SeAccessCheck ( oldfileref - > fcb - > sd , & subjcont , FALSE , DELETE , 0 , NULL ,
IoGetFileObjectGenericMapping ( ) , Irp - > RequestorMode , & access , & Status ) ) {
SeReleaseSubjectContext ( & subjcont ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " SeAccessCheck failed, returning %08x \n " , Status ) ;
2016-09-04 15:27:46 +00:00
goto end ;
}
SeReleaseSubjectContext ( & subjcont ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = delete_fileref ( oldfileref , NULL , Irp , & rollback ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2016-05-05 17:26:47 +00:00
ERR ( " delete_fileref returned %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
if ( fileref - > parent - > fcb - > subvol ! = related - > fcb - > subvol & & ( fileref - > fcb - > subvol = = fileref - > parent - > fcb - > subvol | | fileref - > fcb = = Vcb - > dummy_fcb ) ) {
Status = move_across_subvols ( fileref , ccb , related , & utf8 , & fnus , Irp , & rollback ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " move_across_subvols returned %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
}
2016-07-27 19:24:26 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( related = = fileref - > parent ) { // keeping file in same directory
2017-09-08 08:02:43 +00:00
UNICODE_STRING oldfn , newfn ;
2016-07-27 19:24:26 +00:00
USHORT name_offset ;
2017-09-08 08:02:43 +00:00
ULONG reqlen , oldutf8len ;
oldfn . Length = oldfn . MaximumLength = 0 ;
Status = fileref_get_filename ( fileref , & oldfn , & name_offset , & reqlen ) ;
if ( Status ! = STATUS_BUFFER_OVERFLOW ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
oldfn . Buffer = ExAllocatePoolWithTag ( PagedPool , reqlen , ALLOC_TAG ) ;
if ( ! oldfn . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
2016-07-27 19:24:26 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
oldfn . MaximumLength = ( UINT16 ) reqlen ;
Status = fileref_get_filename ( fileref , & oldfn , & name_offset , & reqlen ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
ExFreePool ( oldfn . Buffer ) ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
oldutf8len = fileref - > dc - > utf8 . Length ;
if ( ! fileref - > created & & ! fileref - > oldutf8 . Buffer ) {
fileref - > oldutf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , fileref - > dc - > utf8 . Length , ALLOC_TAG ) ;
if ( ! fileref - > oldutf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
fileref - > oldutf8 . Length = fileref - > oldutf8 . MaximumLength = fileref - > dc - > utf8 . Length ;
RtlCopyMemory ( fileref - > oldutf8 . Buffer , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
TRACE ( " renaming %.*S to %.*S \n " , fileref - > dc - > name . Length / sizeof ( WCHAR ) , fileref - > dc - > name . Buffer , fnus . Length / sizeof ( WCHAR ) , fnus . Buffer ) ;
2016-07-27 19:24:26 +00:00
mark_fileref_dirty ( fileref ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fileref - > dc ) {
ExAcquireResourceExclusiveLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( fileref - > dc - > utf8 . Buffer ) ;
ExFreePool ( fileref - > dc - > name . Buffer ) ;
ExFreePool ( fileref - > dc - > name_uc . Buffer ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fileref - > dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 . Length , ALLOC_TAG ) ;
if ( ! fileref - > dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExReleaseResourceLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( oldfn . Buffer ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
fileref - > dc - > utf8 . Length = fileref - > dc - > utf8 . MaximumLength = utf8 . Length ;
RtlCopyMemory ( fileref - > dc - > utf8 . Buffer , utf8 . Buffer , utf8 . Length ) ;
fileref - > dc - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , fnus . Length , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! fileref - > dc - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExReleaseResourceLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( oldfn . Buffer ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
fileref - > dc - > name . Length = fileref - > dc - > name . MaximumLength = fnus . Length ;
RtlCopyMemory ( fileref - > dc - > name . Buffer , fnus . Buffer , fnus . Length ) ;
Status = RtlUpcaseUnicodeString ( & fileref - > dc - > name_uc , & fileref - > dc - > name , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUpcaseUnicodeString returned %08x \n " , Status ) ;
2017-01-01 17:12:12 +00:00
ExReleaseResourceLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( oldfn . Buffer ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
remove_dir_child_from_hash_lists ( fileref - > parent - > fcb , fileref - > dc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fileref - > dc - > hash = calc_crc32c ( 0xffffffff , ( UINT8 * ) fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
fileref - > dc - > hash_uc = calc_crc32c ( 0xffffffff , ( UINT8 * ) fileref - > dc - > name_uc . Buffer , fileref - > dc - > name_uc . Length ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
insert_dir_child_into_hash_lists ( fileref - > parent - > fcb , fileref - > dc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExReleaseResourceLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
}
2017-09-08 08:02:43 +00:00
newfn . Length = newfn . MaximumLength = 0 ;
Status = fileref_get_filename ( fileref , & newfn , & name_offset , & reqlen ) ;
if ( Status ! = STATUS_BUFFER_OVERFLOW ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
ExFreePool ( oldfn . Buffer ) ;
goto end ;
}
newfn . Buffer = ExAllocatePoolWithTag ( PagedPool , reqlen , ALLOC_TAG ) ;
if ( ! newfn . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( oldfn . Buffer ) ;
goto end ;
}
newfn . MaximumLength = ( UINT16 ) reqlen ;
Status = fileref_get_filename ( fileref , & newfn , & name_offset , & reqlen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
ExFreePool ( oldfn . Buffer ) ;
ExFreePool ( newfn . Buffer ) ;
goto end ;
}
2016-07-27 19:24:26 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
if ( fcb ! = Vcb - > dummy_fcb & & ( fileref - > parent - > fcb - > subvol = = fcb - > subvol | | ! is_subvol_readonly ( fcb - > subvol , Irp ) ) ) {
fcb - > inode_item . transid = Vcb - > superblock . generation ;
fcb - > inode_item . sequence + + ;
if ( ! ccb - > user_set_change_time )
fcb - > inode_item . st_ctime = now ;
fcb - > inode_item_changed = TRUE ;
mark_fcb_dirty ( fcb ) ;
}
2016-07-27 19:24:26 +00:00
// update parent's INODE_ITEM
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
related - > fcb - > inode_item . transid = Vcb - > superblock . generation ;
TRACE ( " related->fcb->inode_item.st_size (inode %llx) was %llx \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
related - > fcb - > inode_item . st_size = related - > fcb - > inode_item . st_size + ( 2 * utf8 . Length ) - ( 2 * oldutf8len ) ;
TRACE ( " related->fcb->inode_item.st_size (inode %llx) now %llx \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
related - > fcb - > inode_item . sequence + + ;
related - > fcb - > inode_item . st_ctime = now ;
related - > fcb - > inode_item . st_mtime = now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
related - > fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( related - > fcb ) ;
2017-09-08 08:02:43 +00:00
send_notification_fileref ( related , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
2016-07-27 19:24:26 +00:00
FsRtlNotifyFilterReportChange ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ( PSTRING ) & oldfn , name_offset , NULL , NULL ,
fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_RENAMED_OLD_NAME , NULL , NULL ) ;
FsRtlNotifyFilterReportChange ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ( PSTRING ) & newfn , name_offset , NULL , NULL ,
fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_RENAMED_NEW_NAME , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExFreePool ( oldfn . Buffer ) ;
ExFreePool ( newfn . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = STATUS_SUCCESS ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// We move files by moving the existing fileref to the new directory, and
// replacing it with a dummy fileref with the same original values, but marked as deleted.
2017-09-08 08:02:43 +00:00
send_notification_fileref ( fileref , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_REMOVED , NULL ) ;
fr2 = create_fileref ( Vcb ) ;
2016-07-27 19:24:26 +00:00
fr2 - > fcb = fileref - > fcb ;
fr2 - > fcb - > refcount + + ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fr2 - > oldutf8 = fileref - > oldutf8 ;
2017-09-08 08:02:43 +00:00
fr2 - > oldindex = fileref - > dc - > index ;
2016-07-27 19:24:26 +00:00
fr2 - > delete_on_close = fileref - > delete_on_close ;
fr2 - > deleted = TRUE ;
fr2 - > created = fileref - > created ;
fr2 - > parent = fileref - > parent ;
2017-01-01 17:12:12 +00:00
fr2 - > dc = NULL ;
2017-09-08 08:02:43 +00:00
if ( ! fr2 - > oldutf8 . Buffer ) {
fr2 - > oldutf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , fileref - > dc - > utf8 . Length , ALLOC_TAG ) ;
if ( ! fr2 - > oldutf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
RtlCopyMemory ( fr2 - > oldutf8 . Buffer , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
fr2 - > oldutf8 . Length = fr2 - > oldutf8 . MaximumLength = fileref - > dc - > utf8 . Length ;
}
2016-07-27 19:24:26 +00:00
if ( fr2 - > fcb - > type = = BTRFS_TYPE_DIRECTORY )
fr2 - > fcb - > fileref = fr2 ;
2017-09-08 08:02:43 +00:00
if ( fileref - > fcb - > inode = = SUBVOL_ROOT_INODE )
fileref - > fcb - > subvol - > parent = related - > fcb - > subvol - > id ;
fileref - > oldutf8 . Length = fileref - > oldutf8 . MaximumLength = 0 ;
2016-07-27 19:24:26 +00:00
fileref - > oldutf8 . Buffer = NULL ;
fileref - > deleted = FALSE ;
fileref - > created = TRUE ;
fileref - > parent = related ;
ExAcquireResourceExclusiveLite ( & fileref - > parent - > nonpaged - > children_lock , TRUE ) ;
InsertHeadList ( & fileref - > list_entry , & fr2 - > list_entry ) ;
RemoveEntryList ( & fileref - > list_entry ) ;
ExReleaseResourceLite ( & fileref - > parent - > nonpaged - > children_lock ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fileref_dirty ( fr2 ) ;
mark_fileref_dirty ( fileref ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fileref - > dc ) {
// remove from old parent
ExAcquireResourceExclusiveLite ( & fr2 - > parent - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
RemoveEntryList ( & fileref - > dc - > list_entry_index ) ;
remove_dir_child_from_hash_lists ( fr2 - > parent - > fcb , fileref - > dc ) ;
ExReleaseResourceLite ( & fr2 - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
if ( fileref - > dc - > utf8 . Length ! = utf8 . Length | | RtlCompareMemory ( fileref - > dc - > utf8 . Buffer , utf8 . Buffer , utf8 . Length ) ! = utf8 . Length ) {
2017-01-01 17:12:12 +00:00
// handle changed name
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( fileref - > dc - > utf8 . Buffer ) ;
ExFreePool ( fileref - > dc - > name . Buffer ) ;
ExFreePool ( fileref - > dc - > name_uc . Buffer ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fileref - > dc - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 . Length , ALLOC_TAG ) ;
if ( ! fileref - > dc - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
fileref - > dc - > utf8 . Length = fileref - > dc - > utf8 . MaximumLength = utf8 . Length ;
RtlCopyMemory ( fileref - > dc - > utf8 . Buffer , utf8 . Buffer , utf8 . Length ) ;
fileref - > dc - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , fnus . Length , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! fileref - > dc - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
fileref - > dc - > name . Length = fileref - > dc - > name . MaximumLength = fnus . Length ;
RtlCopyMemory ( fileref - > dc - > name . Buffer , fnus . Buffer , fnus . Length ) ;
Status = RtlUpcaseUnicodeString ( & fileref - > dc - > name_uc , & fileref - > dc - > name , TRUE ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUpcaseUnicodeString returned %08x \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fileref - > dc - > hash = calc_crc32c ( 0xffffffff , ( UINT8 * ) fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
fileref - > dc - > hash_uc = calc_crc32c ( 0xffffffff , ( UINT8 * ) fileref - > dc - > name_uc . Buffer , fileref - > dc - > name_uc . Length ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// add to new parent
ExAcquireResourceExclusiveLite ( & related - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
if ( IsListEmpty ( & related - > fcb - > dir_children_index ) )
fileref - > dc - > index = 2 ;
else {
dir_child * dc2 = CONTAINING_RECORD ( related - > fcb - > dir_children_index . Blink , dir_child , list_entry_index ) ;
fileref - > dc - > index = max ( 2 , dc2 - > index + 1 ) ;
}
2017-01-01 17:12:12 +00:00
InsertTailList ( & related - > fcb - > dir_children_index , & fileref - > dc - > list_entry_index ) ;
insert_dir_child_into_hash_lists ( related - > fcb , fileref - > dc ) ;
ExReleaseResourceLite ( & related - > fcb - > nonpaged - > dir_children_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & related - > nonpaged - > children_lock , TRUE ) ;
InsertTailList ( & related - > children , & fileref - > list_entry ) ;
ExReleaseResourceLite ( & related - > nonpaged - > children_lock ) ;
2017-01-01 17:12:12 +00:00
if ( fcb - > inode_item . st_nlink > 1 ) {
// add new hardlink entry to fcb
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl = ExAllocatePoolWithTag ( PagedPool , sizeof ( hardlink ) , ALLOC_TAG ) ;
if ( ! hl ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl - > parent = related - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
hl - > index = fileref - > dc - > index ;
hl - > name . Length = hl - > name . MaximumLength = fnus . Length ;
2017-01-01 17:12:12 +00:00
hl - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , 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 ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( hl - > name . Buffer , fnus . Buffer , fnus . Length ) ;
hl - > utf8 . Length = hl - > utf8 . MaximumLength = fileref - > dc - > utf8 . Length ;
2017-01-01 17:12:12 +00:00
hl - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , hl - > utf8 . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! hl - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl - > name . Buffer ) ;
ExFreePool ( hl ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( hl - > utf8 . Buffer , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
2017-01-01 17:12:12 +00:00
InsertTailList ( & fcb - > hardlinks , & hl - > list_entry ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// delete old hardlink entry from fcb
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = fcb - > hardlinks . Flink ;
while ( le ! = & fcb - > hardlinks ) {
hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( hl - > parent = = fr2 - > parent - > fcb - > inode & & hl - > index = = fr2 - > oldindex ) {
2016-07-27 19:24:26 +00:00
RemoveEntryList ( & hl - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( hl - > utf8 . Buffer )
ExFreePool ( hl - > utf8 . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( hl - > name . Buffer )
ExFreePool ( hl - > name . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExFreePool ( hl ) ;
break ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2016-07-27 19:24:26 +00:00
// update inode's INODE_ITEM
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
if ( fcb ! = Vcb - > dummy_fcb & & ( fileref - > parent - > fcb - > subvol = = fcb - > subvol | | ! is_subvol_readonly ( fcb - > subvol , Irp ) ) ) {
fcb - > inode_item . transid = Vcb - > superblock . generation ;
fcb - > inode_item . sequence + + ;
if ( ! ccb - > user_set_change_time )
fcb - > inode_item . st_ctime = now ;
fcb - > inode_item_changed = TRUE ;
mark_fcb_dirty ( fcb ) ;
}
2016-07-27 19:24:26 +00:00
// update new parent's INODE_ITEM
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
related - > fcb - > inode_item . transid = Vcb - > superblock . generation ;
TRACE ( " related->fcb->inode_item.st_size (inode %llx) was %llx \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
related - > fcb - > inode_item . st_size + = 2 * utf8len ;
TRACE ( " related->fcb->inode_item.st_size (inode %llx) now %llx \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
related - > fcb - > inode_item . sequence + + ;
related - > fcb - > inode_item . st_ctime = now ;
related - > fcb - > inode_item . st_mtime = now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
related - > fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( related - > fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// update old parent's INODE_ITEM
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fr2 - > parent - > fcb - > inode_item . transid = Vcb - > superblock . generation ;
TRACE ( " fr2->parent->fcb->inode_item.st_size (inode %llx) was %llx \n " , fr2 - > parent - > fcb - > inode , fr2 - > parent - > fcb - > inode_item . st_size ) ;
2017-09-08 08:02:43 +00:00
fr2 - > parent - > fcb - > inode_item . st_size - = 2 * origutf8len ;
2016-07-27 19:24:26 +00:00
TRACE ( " fr2->parent->fcb->inode_item.st_size (inode %llx) now %llx \n " , fr2 - > parent - > fcb - > inode , fr2 - > parent - > fcb - > inode_item . st_size ) ;
fr2 - > parent - > fcb - > inode_item . sequence + + ;
fr2 - > parent - > fcb - > inode_item . st_ctime = now ;
fr2 - > parent - > fcb - > inode_item . st_mtime = now ;
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , fr2 ) ;
2016-10-29 17:05:10 +00:00
fr2 - > parent - > fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fr2 - > parent - > fcb ) ;
2017-09-08 08:02:43 +00:00
send_notification_fileref ( fileref , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_ADDED , NULL ) ;
send_notification_fileref ( related , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
send_notification_fileref ( fr2 - > parent , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
2016-07-27 19:24:26 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
2017-01-01 17:12:12 +00:00
2016-03-23 20:35:05 +00:00
end :
2017-01-01 17:12:12 +00:00
if ( oldfileref )
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , oldfileref ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & related )
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , related ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & fr2 )
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , fr2 ) ;
2016-07-27 19:24:26 +00:00
if ( NT_SUCCESS ( Status ) )
2017-09-08 08:02:43 +00:00
clear_rollback ( & rollback ) ;
2016-07-27 19:24:26 +00:00
else
do_rollback ( Vcb , & rollback ) ;
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2017-10-16 18:05:33 +00:00
release_fcb_lock ( Vcb ) ;
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
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
NTSTATUS stream_set_end_of_file_information ( device_extension * Vcb , UINT16 end , fcb * fcb , file_ref * fileref , BOOL advance_only ) {
2016-03-23 20:35:05 +00:00
LARGE_INTEGER time ;
BTRFS_TIME now ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " setting new end to %llx bytes (currently %x) \n " , end , fcb - > adsdata . Length ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref for stream \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( end < fcb - > adsdata . Length ) {
2016-03-23 20:35:05 +00:00
if ( advance_only )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " truncating stream to %llx bytes \n " , end ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > adsdata . Length = end ;
} else if ( end > fcb - > adsdata . Length ) {
2016-05-05 17:26:47 +00:00
TRACE ( " extending stream to %llx bytes \n " , end ) ;
2016-09-04 15:27:46 +00:00
if ( end > fcb - > adsmaxlen ) {
2017-10-16 18:05:33 +00:00
ERR ( " error - xattr too long (%u > %u) \n " , end , fcb - > adsmaxlen ) ;
2016-09-04 15:27:46 +00:00
return STATUS_DISK_FULL ;
}
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
if ( end > fcb - > adsdata . MaximumLength ) {
char * data = ExAllocatePoolWithTag ( PagedPool , end , ALLOC_TAG ) ;
if ( ! data ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( data ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > adsdata . Buffer ) {
RtlCopyMemory ( data , fcb - > adsdata . Buffer , fcb - > adsdata . Length ) ;
ExFreePool ( fcb - > adsdata . Buffer ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > adsdata . Buffer = data ;
fcb - > adsdata . MaximumLength = end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlZeroMemory ( & fcb - > adsdata . Buffer [ fcb - > adsdata . Length ] , end - fcb - > adsdata . Length ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > adsdata . Length = end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > Header . AllocationSize . QuadPart = end ;
fcb - > Header . FileSize . QuadPart = end ;
fcb - > Header . ValidDataLength . QuadPart = end ;
2016-03-23 20:35:05 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
fileref - > parent - > fcb - > inode_item . transid = Vcb - > superblock . generation ;
fileref - > parent - > fcb - > inode_item . sequence + + ;
fileref - > parent - > fcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fileref - > parent - > fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > parent - > fcb ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
fileref - > parent - > fcb - > subvol - > root_item . ctransid = Vcb - > superblock . generation ;
fileref - > parent - > fcb - > subvol - > root_item . ctime = now ;
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS set_end_of_file_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject , BOOL advance_only , BOOL prealloc ) {
2016-03-23 20:35:05 +00:00
FILE_END_OF_FILE_INFORMATION * feofi = Irp - > AssociatedIrp . SystemBuffer ;
fcb * fcb = FileObject - > FsContext ;
2016-05-05 17:26:47 +00:00
ccb * ccb = FileObject - > FsContext2 ;
file_ref * fileref = ccb ? ccb - > fileref : NULL ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
LARGE_INTEGER time ;
CC_FILE_SIZES ccfs ;
2016-07-27 19:24:26 +00:00
LIST_ENTRY rollback ;
2017-01-01 17:12:12 +00:00
BOOL set_size = FALSE ;
2017-09-08 08:02:43 +00:00
ULONG filter ;
2016-07-27 19:24:26 +00:00
if ( ! fileref ) {
ERR ( " fileref is NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InitializeListHead ( & rollback ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref ? fileref - > deleted : fcb - > deleted ) {
Status = STATUS_FILE_CLOSED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > ads ) {
2017-09-08 08:02:43 +00:00
if ( feofi - > EndOfFile . QuadPart > 0xffff ) {
Status = STATUS_DISK_FULL ;
goto end ;
}
if ( feofi - > EndOfFile . QuadPart < 0 ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
Status = stream_set_end_of_file_information ( Vcb , ( UINT16 ) feofi - > EndOfFile . QuadPart , fcb , fileref , advance_only ) ;
if ( NT_SUCCESS ( Status ) ) {
ccfs . AllocationSize = fcb - > Header . AllocationSize ;
ccfs . FileSize = fcb - > Header . FileSize ;
ccfs . ValidDataLength = fcb - > Header . ValidDataLength ;
set_size = TRUE ;
}
2017-10-16 18:05:33 +00:00
filter = FILE_NOTIFY_CHANGE_STREAM_SIZE ;
2017-09-08 08:02:43 +00:00
if ( ! ccb - > user_set_write_time ) {
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & fileref - > parent - > fcb - > inode_item . st_mtime ) ;
filter | = FILE_NOTIFY_CHANGE_LAST_WRITE ;
fileref - > parent - > fcb - > inode_item_changed = TRUE ;
mark_fcb_dirty ( fileref - > parent - > fcb ) ;
}
2017-10-16 18:05:33 +00:00
send_notification_fcb ( fileref - > parent , filter , FILE_ACTION_MODIFIED_STREAM , & fileref - > dc - > name ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " file: %S \n " , file_desc ( FileObject ) ) ;
2016-03-23 20:35:05 +00:00
TRACE ( " paging IO: %s \n " , Irp - > Flags & IRP_PAGING_IO ? " TRUE " : " FALSE " ) ;
TRACE ( " FileObject: AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx \n " ,
fcb - > Header . AllocationSize . QuadPart , fcb - > Header . FileSize . QuadPart , fcb - > Header . ValidDataLength . QuadPart ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " setting new end to %llx bytes (currently %llx) \n " , feofi - > EndOfFile . QuadPart , fcb - > inode_item . st_size ) ;
2017-09-08 08:02:43 +00:00
if ( ( UINT64 ) feofi - > EndOfFile . QuadPart < fcb - > inode_item . st_size ) {
2016-07-27 19:24:26 +00:00
if ( advance_only ) {
Status = STATUS_SUCCESS ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " truncating file to %llx bytes \n " , feofi - > EndOfFile . QuadPart ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! MmCanFileBeTruncated ( & fcb - > nonpaged - > segment_object , & feofi - > EndOfFile ) ) {
Status = STATUS_USER_MAPPED_FILE ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = truncate_file ( fcb , feofi - > EndOfFile . QuadPart , Irp , & rollback ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - truncate_file failed \n " ) ;
2016-07-27 19:24:26 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
} else if ( ( UINT64 ) feofi - > EndOfFile . QuadPart > fcb - > inode_item . st_size ) {
2016-03-23 20:35:05 +00:00
if ( Irp - > Flags & IRP_PAGING_IO ) {
TRACE ( " paging IO tried to extend file size \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_SUCCESS ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " extending file to %llx bytes \n " , feofi - > EndOfFile . QuadPart ) ;
2017-09-08 08:02:43 +00:00
Status = extend_file ( fcb , fileref , feofi - > EndOfFile . QuadPart , prealloc , NULL , & rollback ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " error - extend_file failed \n " ) ;
2016-07-27 19:24:26 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2018-05-26 08:44:36 +00:00
} else if ( ( UINT64 ) feofi - > EndOfFile . QuadPart = = fcb - > inode_item . st_size & & advance_only ) {
Status = STATUS_SUCCESS ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ccfs . AllocationSize = fcb - > Header . AllocationSize ;
ccfs . FileSize = fcb - > Header . FileSize ;
ccfs . ValidDataLength = fcb - > Header . ValidDataLength ;
2017-01-01 17:12:12 +00:00
set_size = TRUE ;
2017-09-08 08:02:43 +00:00
filter = FILE_NOTIFY_CHANGE_SIZE ;
2016-10-29 17:05:10 +00:00
if ( ! ccb - > user_set_write_time ) {
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & fcb - > inode_item . st_mtime ) ;
2017-09-08 08:02:43 +00:00
filter | = FILE_NOTIFY_CHANGE_LAST_WRITE ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fcb ) ;
2017-09-08 08:02:43 +00:00
send_notification_fcb ( fileref , filter , FILE_ACTION_MODIFIED , NULL ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_SUCCESS ;
end :
if ( NT_SUCCESS ( Status ) )
2017-09-08 08:02:43 +00:00
clear_rollback ( & rollback ) ;
2016-03-23 20:35:05 +00:00
else
2016-07-27 19:24:26 +00:00
do_rollback ( Vcb , & rollback ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
if ( set_size ) {
_SEH2_TRY {
CcSetFileSizes ( FileObject , & ccfs ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
} _SEH2_END ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " CcSetFileSizes threw exception %08x \n " , Status ) ;
}
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS set_position_information ( PFILE_OBJECT FileObject , PIRP Irp ) {
2016-03-23 20:35:05 +00:00
FILE_POSITION_INFORMATION * fpi = ( FILE_POSITION_INFORMATION * ) Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " setting the position on %S to %llx \n " , file_desc ( FileObject ) , fpi - > CurrentByteOffset . QuadPart ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FileObject - > CurrentByteOffset = fpi - > CurrentByteOffset ;
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 set_link_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject , PFILE_OBJECT tfo ) {
2016-05-05 17:26:47 +00:00
FILE_LINK_INFORMATION * fli = Irp - > AssociatedIrp . SystemBuffer ;
2016-07-27 19:24:26 +00:00
fcb * fcb = FileObject - > FsContext , * tfofcb , * parfcb ;
2016-05-05 17:26:47 +00:00
ccb * ccb = FileObject - > FsContext2 ;
2016-07-27 19:24:26 +00:00
file_ref * fileref = ccb ? ccb - > fileref : NULL , * oldfileref = NULL , * related = NULL , * fr2 = NULL ;
2016-05-05 17:26:47 +00:00
WCHAR * fn ;
2016-07-27 19:24:26 +00:00
ULONG fnlen , utf8len ;
2016-05-05 17:26:47 +00:00
UNICODE_STRING fnus ;
ANSI_STRING utf8 ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2016-05-05 17:26:47 +00:00
LARGE_INTEGER time ;
BTRFS_TIME now ;
2016-07-27 19:24:26 +00:00
LIST_ENTRY rollback ;
hardlink * hl ;
ACCESS_MASK access ;
SECURITY_SUBJECT_CONTEXT subjcont ;
2017-01-01 17:12:12 +00:00
dir_child * dc = NULL ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InitializeListHead ( & rollback ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - check fli length
// FIXME - don't ignore fli->RootDirectory
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " ReplaceIfExists = %x \n " , fli - > ReplaceIfExists ) ;
TRACE ( " RootDirectory = %p \n " , fli - > RootDirectory ) ;
TRACE ( " FileNameLength = %x \n " , fli - > FileNameLength ) ;
TRACE ( " FileName = %.*S \n " , fli - > FileNameLength / sizeof ( WCHAR ) , fli - > FileName ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
fn = fli - > FileName ;
fnlen = fli - > FileNameLength / sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! tfo ) {
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref set and no directory given \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
parfcb = fileref - > parent - > fcb ;
2016-05-05 17:26:47 +00:00
tfofcb = NULL ;
} else {
LONG i ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
tfofcb = tfo - > FsContext ;
2016-07-27 19:24:26 +00:00
parfcb = tfofcb ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
while ( fnlen > 0 & & ( fli - > FileName [ fnlen - 1 ] = = ' / ' | | fli - > FileName [ fnlen - 1 ] = = ' \\ ' ) )
fnlen - - ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( fnlen = = 0 )
return STATUS_INVALID_PARAMETER ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
for ( i = fnlen - 1 ; i > = 0 ; i - - ) {
if ( fli - > FileName [ i ] = = ' \\ ' | | fli - > FileName [ i ] = = ' / ' ) {
fn = & fli - > FileName [ i + 1 ] ;
fnlen = ( fli - > FileNameLength / sizeof ( WCHAR ) ) - i - 1 ;
break ;
}
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
2017-10-16 18:05:33 +00:00
acquire_fcb_lock_exclusive ( Vcb ) ;
2016-07-27 19:24:26 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
WARN ( " tried to create hard link on directory \n " ) ;
Status = STATUS_FILE_IS_A_DIRECTORY ;
2016-03-23 20:35:05 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
WARN ( " tried to create hard link on stream \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
2016-03-23 20:35:05 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
if ( fcb - > inode_item . st_nlink > = 65535 ) {
Status = STATUS_TOO_MANY_LINKS ;
goto end ;
}
2016-05-05 17:26:47 +00:00
fnus . Buffer = fn ;
2017-09-08 08:02:43 +00:00
fnus . Length = fnus . MaximumLength = ( UINT16 ) ( fnlen * sizeof ( WCHAR ) ) ;
2016-05-05 17:26:47 +00:00
TRACE ( " fnus = %.*S \n " , fnus . Length / sizeof ( WCHAR ) , fnus . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = RtlUnicodeToUTF8N ( NULL , 0 , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
utf8 . MaximumLength = utf8 . Length = ( UINT16 ) utf8len ;
2016-05-05 17:26:47 +00:00
utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 . MaximumLength , ALLOC_TAG ) ;
if ( ! utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = RtlUnicodeToUTF8N ( utf8 . Buffer , utf8len , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( tfo & & tfo - > FsContext2 ) {
struct _ccb * relatedccb = tfo - > FsContext2 ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
related = relatedccb - > fileref ;
2016-07-27 19:24:26 +00:00
increase_fileref_refcount ( related ) ;
}
2016-03-23 20:35:05 +00:00
2016-10-29 17:05:10 +00:00
Status = open_fileref ( Vcb , & oldfileref , & fnus , related , FALSE , NULL , NULL , PagedPool , ccb - > case_sensitive , Irp ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
if ( NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
if ( ! oldfileref - > deleted ) {
WARN ( " destination file %S already exists \n " , file_desc_fileref ( oldfileref ) ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! fli - > ReplaceIfExists ) {
Status = STATUS_OBJECT_NAME_COLLISION ;
goto end ;
2016-10-29 17:05:10 +00:00
} else if ( oldfileref - > open_count > = 1 & & ! oldfileref - > deleted ) {
2016-05-05 17:26:47 +00:00
WARN ( " trying to overwrite open file \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
2016-07-27 19:24:26 +00:00
} else if ( fileref = = oldfileref ) {
Status = STATUS_ACCESS_DENIED ;
goto end ;
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 ( oldfileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
WARN ( " trying to overwrite directory \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2016-07-27 19:24:26 +00:00
} else {
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , oldfileref ) ;
2016-07-27 19:24:26 +00:00
oldfileref = NULL ;
2016-05-05 17:26:47 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! related ) {
2016-10-29 17:05:10 +00:00
Status = open_fileref ( Vcb , & related , & fnus , NULL , TRUE , NULL , NULL , PagedPool , ccb - > case_sensitive , Irp ) ;
2016-07-27 19:24:26 +00:00
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2016-07-27 19:24:26 +00:00
ERR ( " open_fileref returned %08x \n " , Status ) ;
2016-05-05 17:26:47 +00:00
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
SeCaptureSubjectContext ( & subjcont ) ;
if ( ! SeAccessCheck ( related - > fcb - > sd , & subjcont , FALSE , FILE_ADD_FILE , 0 , NULL ,
IoGetFileObjectGenericMapping ( ) , Irp - > RequestorMode , & access , & Status ) ) {
SeReleaseSubjectContext ( & subjcont ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " SeAccessCheck failed, returning %08x \n " , Status ) ;
2016-05-05 17:26:47 +00:00
goto end ;
}
2016-07-27 19:24:26 +00:00
SeReleaseSubjectContext ( & subjcont ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > subvol ! = parfcb - > subvol ) {
WARN ( " can't create hard link over subvolume boundary \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
2016-05-05 17:26:47 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( oldfileref ) {
SeCaptureSubjectContext ( & subjcont ) ;
if ( ! SeAccessCheck ( oldfileref - > fcb - > sd , & subjcont , FALSE , DELETE , 0 , NULL ,
IoGetFileObjectGenericMapping ( ) , Irp - > RequestorMode , & access , & Status ) ) {
SeReleaseSubjectContext ( & subjcont ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " SeAccessCheck failed, returning %08x \n " , Status ) ;
2016-07-27 19:24:26 +00:00
goto end ;
}
SeReleaseSubjectContext ( & subjcont ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = delete_fileref ( oldfileref , NULL , Irp , & rollback ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref returned %08x \n " , Status ) ;
goto end ;
}
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
fr2 = create_fileref ( Vcb ) ;
2016-07-27 19:24:26 +00:00
fr2 - > fcb = fcb ;
fcb - > refcount + + ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fr2 - > created = TRUE ;
fr2 - > parent = related ;
2017-09-08 08:02:43 +00:00
Status = add_dir_child ( related - > fcb , fcb - > inode , FALSE , & utf8 , & fnus , fcb - > type , & dc ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) )
WARN ( " add_dir_child returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fr2 - > dc = dc ;
dc - > fileref = fr2 ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceExclusiveLite ( & related - > nonpaged - > children_lock , TRUE ) ;
InsertTailList ( & related - > children , & fr2 - > list_entry ) ;
ExReleaseResourceLite ( & related - > nonpaged - > children_lock ) ;
2017-01-01 17:12:12 +00:00
// add hardlink for existing fileref, if it's not there already
if ( IsListEmpty ( & fcb - > hardlinks ) ) {
hl = ExAllocatePoolWithTag ( PagedPool , sizeof ( hardlink ) , ALLOC_TAG ) ;
if ( ! hl ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
hl - > parent = fileref - > parent - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
hl - > index = fileref - > dc - > index ;
hl - > name . Length = hl - > name . MaximumLength = fnus . Length ;
hl - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , fnus . Length , ALLOC_TAG ) ;
2017-01-01 17:12:12 +00:00
if ( ! hl - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( hl - > name . Buffer , fnus . Buffer , fnus . Length ) ;
hl - > utf8 . Length = hl - > utf8 . MaximumLength = fileref - > dc - > utf8 . Length ;
2017-01-01 17:12:12 +00:00
hl - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , hl - > utf8 . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! hl - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl - > name . Buffer ) ;
ExFreePool ( hl ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( hl - > utf8 . Buffer , fileref - > dc - > utf8 . Buffer , fileref - > dc - > utf8 . Length ) ;
2017-01-01 17:12:12 +00:00
InsertTailList ( & fcb - > hardlinks , & hl - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
hl = ExAllocatePoolWithTag ( PagedPool , sizeof ( hardlink ) , ALLOC_TAG ) ;
if ( ! hl ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
2016-05-05 17:26:47 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
hl - > parent = related - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
hl - > index = dc - > index ;
2016-07-27 19:24:26 +00:00
hl - > name . Length = hl - > name . MaximumLength = fnus . Length ;
hl - > name . Buffer = ExAllocatePoolWithTag ( PagedPool , hl - > name . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! hl - > name . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( hl - > name . Buffer , fnus . Buffer , fnus . Length ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
hl - > utf8 . Length = hl - > utf8 . MaximumLength = utf8 . Length ;
hl - > utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , hl - > utf8 . MaximumLength , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! hl - > utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( hl - > name . Buffer ) ;
ExFreePool ( hl ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
2016-05-05 17:26:47 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( hl - > utf8 . Buffer , utf8 . Buffer , utf8 . Length ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( utf8 . Buffer ) ;
2016-07-27 19:24:26 +00:00
InsertTailList ( & fcb - > hardlinks , & hl - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fileref_dirty ( fr2 ) ;
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , fr2 ) ;
2016-07-27 19:24:26 +00:00
// update inode's INODE_ITEM
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fcb - > inode_item . transid = Vcb - > superblock . generation ;
fcb - > inode_item . sequence + + ;
fcb - > inode_item . st_nlink + + ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ccb - > user_set_change_time )
fcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// update parent's INODE_ITEM
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
parfcb - > inode_item . transid = Vcb - > superblock . generation ;
TRACE ( " parfcb->inode_item.st_size (inode %llx) was %llx \n " , parfcb - > inode , parfcb - > inode_item . st_size ) ;
parfcb - > inode_item . st_size + = 2 * utf8len ;
TRACE ( " parfcb->inode_item.st_size (inode %llx) now %llx \n " , parfcb - > inode , parfcb - > inode_item . st_size ) ;
parfcb - > inode_item . sequence + + ;
parfcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
parfcb - > inode_item_changed = TRUE ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( parfcb ) ;
2017-09-08 08:02:43 +00:00
send_notification_fileref ( fr2 , FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_ADDED , NULL ) ;
2016-05-05 17:26:47 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
end :
2017-01-01 17:12:12 +00:00
if ( oldfileref )
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , oldfileref ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & related )
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , related ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & fr2 )
2017-09-08 08:02:43 +00:00
free_fileref ( Vcb , fr2 ) ;
2016-07-27 19:24:26 +00:00
if ( NT_SUCCESS ( Status ) )
2017-09-08 08:02:43 +00:00
clear_rollback ( & rollback ) ;
2016-07-27 19:24:26 +00:00
else
do_rollback ( Vcb , & rollback ) ;
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2017-10-16 18:05:33 +00:00
release_fcb_lock ( Vcb ) ;
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
static NTSTATUS set_valid_data_length_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject ) {
FILE_VALID_DATA_LENGTH_INFORMATION * fvdli = Irp - > AssociatedIrp . SystemBuffer ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
fcb * fcb = FileObject - > FsContext ;
ccb * ccb = FileObject - > FsContext2 ;
file_ref * fileref = ccb ? ccb - > fileref : NULL ;
NTSTATUS Status ;
LARGE_INTEGER time ;
CC_FILE_SIZES ccfs ;
LIST_ENTRY rollback ;
BOOL set_size = FALSE ;
ULONG filter ;
if ( IrpSp - > Parameters . SetFile . Length < sizeof ( FILE_VALID_DATA_LENGTH_INFORMATION ) ) {
ERR ( " input buffer length was %u, expected %u \n " , IrpSp - > Parameters . SetFile . Length , sizeof ( FILE_VALID_DATA_LENGTH_INFORMATION ) ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( ! fileref ) {
ERR ( " fileref is NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
InitializeListHead ( & rollback ) ;
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
if ( fcb - > atts & FILE_ATTRIBUTE_SPARSE_FILE ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
if ( fvdli - > ValidDataLength . QuadPart < = fcb - > Header . ValidDataLength . QuadPart | | fvdli - > ValidDataLength . QuadPart > fcb - > Header . FileSize . QuadPart ) {
TRACE ( " invalid VDL of %llu (current VDL = %llu, file size = %llu) \n " , fvdli - > ValidDataLength . QuadPart ,
fcb - > Header . ValidDataLength . QuadPart , fcb - > Header . FileSize . QuadPart ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
if ( fileref ? fileref - > deleted : fcb - > deleted ) {
Status = STATUS_FILE_CLOSED ;
goto end ;
}
// This function doesn't really do anything - the fsctl can only increase the value of ValidDataLength,
// and we set it to the max anyway.
ccfs . AllocationSize = fcb - > Header . AllocationSize ;
ccfs . FileSize = fcb - > Header . FileSize ;
ccfs . ValidDataLength = fvdli - > ValidDataLength ;
set_size = TRUE ;
filter = FILE_NOTIFY_CHANGE_SIZE ;
if ( ! ccb - > user_set_write_time ) {
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & fcb - > inode_item . st_mtime ) ;
filter | = FILE_NOTIFY_CHANGE_LAST_WRITE ;
}
fcb - > inode_item_changed = TRUE ;
mark_fcb_dirty ( fcb ) ;
send_notification_fcb ( fileref , filter , FILE_ACTION_MODIFIED , NULL ) ;
Status = STATUS_SUCCESS ;
end :
if ( NT_SUCCESS ( Status ) )
clear_rollback ( & rollback ) ;
else
do_rollback ( Vcb , & rollback ) ;
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
if ( set_size ) {
_SEH2_TRY {
CcSetFileSizes ( FileObject , & ccfs ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
} _SEH2_END ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " CcSetFileSizes threw exception %08x \n " , Status ) ;
else
fcb - > Header . AllocationSize = ccfs . AllocationSize ;
}
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_SET_INFORMATION )
_Function_class_ ( DRIVER_DISPATCH )
2018-08-21 05:05:40 +00:00
NTSTATUS NTAPI drv_set_information ( IN PDEVICE_OBJECT DeviceObject , IN PIRP Irp ) {
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
fcb * fcb = IrpSp - > FileObject - > FsContext ;
2016-07-27 19:24:26 +00:00
ccb * ccb = IrpSp - > FileObject - > FsContext2 ;
2016-05-05 17:26:47 +00:00
BOOL top_level ;
2016-07-27 19:24:26 +00:00
2016-05-05 17:26:47 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
Irp - > IoStatus . Information = 0 ;
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_set_information ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! ( Vcb - > Vpb - > Flags & VPB_MOUNTED ) ) {
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > readonly & & IrpSp - > Parameters . SetFile . FileInformationClass ! = FilePositionInformation ) {
2016-05-05 17:26:47 +00:00
Status = STATUS_MEDIA_WRITE_PROTECTED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! fcb ) {
ERR ( " no fcb \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! ccb ) {
ERR ( " no ccb \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
if ( fcb ! = Vcb - > dummy_fcb & & is_subvol_readonly ( fcb - > subvol , Irp ) & & IrpSp - > Parameters . SetFile . FileInformationClass ! = FilePositionInformation & &
( fcb - > inode ! = SUBVOL_ROOT_INODE | | ( IrpSp - > Parameters . SetFile . FileInformationClass ! = FileBasicInformation & & IrpSp - > Parameters . SetFile . FileInformationClass ! = FileRenameInformation ) ) ) {
2016-05-05 17:26:47 +00:00
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
Status = STATUS_NOT_IMPLEMENTED ;
TRACE ( " set information \n " ) ;
switch ( IrpSp - > Parameters . SetFile . FileInformationClass ) {
case FileAllocationInformation :
2016-07-27 19:24:26 +00:00
{
2016-05-05 17:26:47 +00:00
TRACE ( " FileAllocationInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & FILE_WRITE_DATA ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
break ;
}
2017-09-08 08:02:43 +00:00
Status = set_end_of_file_information ( Vcb , Irp , IrpSp - > FileObject , FALSE , TRUE ) ;
2016-05-05 17:26:47 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2016-05-05 17:26:47 +00:00
case FileBasicInformation :
2016-07-27 19:24:26 +00:00
{
2016-05-05 17:26:47 +00:00
TRACE ( " FileBasicInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & FILE_WRITE_ATTRIBUTES ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = set_basic_information ( Vcb , Irp , IrpSp - > FileObject ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2016-05-05 17:26:47 +00:00
case FileDispositionInformation :
2016-07-27 19:24:26 +00:00
{
2016-05-05 17:26:47 +00:00
TRACE ( " FileDispositionInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & DELETE ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = set_disposition_information ( Vcb , Irp , IrpSp - > FileObject ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2016-05-05 17:26:47 +00:00
case FileEndOfFileInformation :
2016-07-27 19:24:26 +00:00
{
2016-05-05 17:26:47 +00:00
TRACE ( " FileEndOfFileInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & ( FILE_WRITE_DATA | FILE_APPEND_DATA ) ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
break ;
}
2017-09-08 08:02:43 +00:00
Status = set_end_of_file_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . AdvanceOnly , FALSE ) ;
2016-05-05 17:26:47 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2016-05-05 17:26:47 +00:00
case FileLinkInformation :
TRACE ( " FileLinkInformation \n " ) ;
2016-07-27 19:24:26 +00:00
Status = set_link_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . FileObject ) ;
2016-05-05 17:26:47 +00:00
break ;
case FilePositionInformation :
TRACE ( " FilePositionInformation \n " ) ;
2017-09-08 08:02:43 +00:00
Status = set_position_information ( IrpSp - > FileObject , Irp ) ;
2016-05-05 17:26:47 +00:00
break ;
case FileRenameInformation :
TRACE ( " FileRenameInformation \n " ) ;
// FIXME - make this work with streams
2016-09-04 15:27:46 +00:00
Status = set_rename_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . FileObject ) ;
2016-05-05 17:26:47 +00:00
break ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
case FileValidDataLengthInformation :
2017-09-08 08:02:43 +00:00
{
TRACE ( " FileValidDataLengthInformation \n " ) ;
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & ( FILE_WRITE_DATA | FILE_APPEND_DATA ) ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
break ;
}
Status = set_valid_data_length_information ( Vcb , Irp , IrpSp - > FileObject ) ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
}
2016-03-23 20:35:05 +00:00
default :
WARN ( " unknown FileInformationClass %u \n " , IrpSp - > Parameters . SetFile . FileInformationClass ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
end :
Irp - > IoStatus . Status = Status ;
2017-09-08 08:02:43 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2016-07-27 19:24:26 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS fill_in_file_basic_information ( FILE_BASIC_INFORMATION * fbi , INODE_ITEM * ii , LONG * length , fcb * fcb , file_ref * fileref ) {
2016-03-23 20:35:05 +00:00
RtlZeroMemory ( fbi , sizeof ( FILE_BASIC_INFORMATION ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_BASIC_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
if ( fcb = = fcb - > Vcb - > dummy_fcb ) {
LARGE_INTEGER time ;
KeQuerySystemTime ( & time ) ;
fbi - > CreationTime = fbi - > LastAccessTime = fbi - > LastWriteTime = fbi - > ChangeTime = time ;
} else {
fbi - > CreationTime . QuadPart = unix_time_to_win ( & ii - > otime ) ;
fbi - > LastAccessTime . QuadPart = unix_time_to_win ( & ii - > st_atime ) ;
fbi - > LastWriteTime . QuadPart = unix_time_to_win ( & ii - > st_mtime ) ;
fbi - > ChangeTime . QuadPart = unix_time_to_win ( & ii - > st_ctime ) ;
}
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref for stream \n " ) ;
return STATUS_INTERNAL_ERROR ;
} else
2017-09-08 08:02:43 +00:00
fbi - > FileAttributes = fileref - > parent - > fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : fileref - > parent - > fcb - > atts ;
2016-05-05 17:26:47 +00:00
} else
2017-09-08 08:02:43 +00:00
fbi - > FileAttributes = fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : fcb - > atts ;
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS fill_in_file_network_open_information ( FILE_NETWORK_OPEN_INFORMATION * fnoi , fcb * fcb , file_ref * fileref , LONG * length ) {
2016-03-23 20:35:05 +00:00
INODE_ITEM * ii ;
2017-09-08 08:02:43 +00:00
if ( * length < ( LONG ) sizeof ( FILE_NETWORK_OPEN_INFORMATION ) ) {
2016-03-23 20:35:05 +00:00
WARN ( " overflow \n " ) ;
return STATUS_BUFFER_OVERFLOW ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlZeroMemory ( fnoi , sizeof ( FILE_NETWORK_OPEN_INFORMATION ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_NETWORK_OPEN_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref for stream \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ii = & fileref - > parent - > fcb - > inode_item ;
} else
2016-03-23 20:35:05 +00:00
ii = & fcb - > inode_item ;
2017-09-08 08:02:43 +00:00
if ( fcb = = fcb - > Vcb - > dummy_fcb ) {
LARGE_INTEGER time ;
KeQuerySystemTime ( & time ) ;
fnoi - > CreationTime = fnoi - > LastAccessTime = fnoi - > LastWriteTime = fnoi - > ChangeTime = time ;
} else {
fnoi - > CreationTime . QuadPart = unix_time_to_win ( & ii - > otime ) ;
fnoi - > LastAccessTime . QuadPart = unix_time_to_win ( & ii - > st_atime ) ;
fnoi - > LastWriteTime . QuadPart = unix_time_to_win ( & ii - > st_mtime ) ;
fnoi - > ChangeTime . QuadPart = unix_time_to_win ( & ii - > st_ctime ) ;
}
2016-03-23 20:35:05 +00:00
if ( fcb - > ads ) {
2016-07-27 19:24:26 +00:00
fnoi - > AllocationSize . QuadPart = fnoi - > EndOfFile . QuadPart = fcb - > adsdata . Length ;
2017-09-08 08:02:43 +00:00
fnoi - > FileAttributes = fileref - > parent - > fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : fileref - > parent - > fcb - > atts ;
2016-03-23 20:35:05 +00:00
} else {
2017-09-08 08:02:43 +00:00
fnoi - > AllocationSize . QuadPart = fcb_alloc_size ( fcb ) ;
2016-03-23 20:35:05 +00:00
fnoi - > EndOfFile . QuadPart = S_ISDIR ( fcb - > inode_item . st_mode ) ? 0 : fcb - > inode_item . st_size ;
2017-09-08 08:02:43 +00:00
fnoi - > FileAttributes = fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : fcb - > atts ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS fill_in_file_standard_information ( FILE_STANDARD_INFORMATION * fsi , fcb * fcb , file_ref * fileref , LONG * length ) {
2016-03-23 20:35:05 +00:00
RtlZeroMemory ( fsi , sizeof ( FILE_STANDARD_INFORMATION ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_STANDARD_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > ads ) {
2016-05-05 17:26:47 +00:00
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref for stream \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fsi - > AllocationSize . QuadPart = fsi - > EndOfFile . QuadPart = fcb - > adsdata . Length ;
2016-05-05 17:26:47 +00:00
fsi - > NumberOfLinks = fileref - > parent - > fcb - > inode_item . st_nlink ;
2017-09-08 08:02:43 +00:00
fsi - > Directory = FALSE ;
2016-03-23 20:35:05 +00:00
} else {
2017-09-08 08:02:43 +00:00
fsi - > AllocationSize . QuadPart = fcb_alloc_size ( fcb ) ;
2016-03-23 20:35:05 +00:00
fsi - > EndOfFile . QuadPart = S_ISDIR ( fcb - > inode_item . st_mode ) ? 0 : fcb - > inode_item . st_size ;
fsi - > NumberOfLinks = fcb - > inode_item . st_nlink ;
fsi - > Directory = S_ISDIR ( fcb - > inode_item . st_mode ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " length = %llu \n " , fsi - > EndOfFile . QuadPart ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
fsi - > DeletePending = fileref ? fileref - > delete_on_close : FALSE ;
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 fill_in_file_internal_information ( FILE_INTERNAL_INFORMATION * fii , fcb * fcb , LONG * length ) {
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_INTERNAL_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fii - > IndexNumber . QuadPart = make_file_id ( fcb - > subvol , 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 fill_in_file_ea_information ( FILE_EA_INFORMATION * eai , fcb * fcb , LONG * length ) {
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_EA_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
/* This value appears to be the size of the structure NTFS stores on disk, and not,
* as might be expected , the size of FILE_FULL_EA_INFORMATION ( which is what we store ) .
* The formula is 4 bytes as a header , followed by 5 + NameLength + ValueLength for each
* item . */
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
eai - > EaSize = fcb - > ealen ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS fill_in_file_position_information ( FILE_POSITION_INFORMATION * fpi , PFILE_OBJECT FileObject , LONG * length ) {
2016-03-23 20:35:05 +00:00
RtlZeroMemory ( fpi , sizeof ( FILE_POSITION_INFORMATION ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_POSITION_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
fpi - > CurrentByteOffset = FileObject - > CurrentByteOffset ;
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS fileref_get_filename ( file_ref * fileref , PUNICODE_STRING fn , USHORT * name_offset , ULONG * preqlen ) {
2016-07-27 19:24:26 +00:00
file_ref * fr ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG reqlen = 0 ;
USHORT offset ;
BOOL overflow = FALSE ;
2016-07-27 19:24:26 +00:00
// FIXME - we need a lock on filerefs' filepart
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref = = fileref - > fcb - > Vcb - > root_fileref ) {
2017-09-08 08:02:43 +00:00
if ( fn - > MaximumLength > = sizeof ( WCHAR ) ) {
fn - > Buffer [ 0 ] = ' \\ ' ;
fn - > Length = sizeof ( WCHAR ) ;
2017-01-01 17:12:12 +00:00
2017-09-08 08:02:43 +00:00
if ( name_offset )
* name_offset = 0 ;
2017-01-01 17:12:12 +00:00
2017-09-08 08:02:43 +00:00
return STATUS_SUCCESS ;
} else {
if ( preqlen )
* preqlen = sizeof ( WCHAR ) ;
fn - > Length = 0 ;
return STATUS_BUFFER_OVERFLOW ;
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fr = fileref ;
2017-09-08 08:02:43 +00:00
offset = 0 ;
while ( fr - > parent ) {
USHORT movelen ;
if ( ! fr - > dc )
return STATUS_INTERNAL_ERROR ;
if ( ! overflow ) {
if ( fr - > dc - > name . Length + sizeof ( WCHAR ) + fn - > Length > fn - > MaximumLength )
overflow = TRUE ;
}
if ( overflow )
movelen = fn - > MaximumLength - fr - > dc - > name . Length - sizeof ( WCHAR ) ;
else
movelen = fn - > Length ;
if ( ( ! overflow | | fn - > MaximumLength > fr - > dc - > name . Length + sizeof ( WCHAR ) ) & & movelen > 0 ) {
RtlMoveMemory ( & fn - > Buffer [ ( fr - > dc - > name . Length / sizeof ( WCHAR ) ) + 1 ] , fn - > Buffer , movelen ) ;
offset + = fr - > dc - > name . Length + sizeof ( WCHAR ) ;
}
if ( fn - > MaximumLength > = sizeof ( WCHAR ) ) {
fn - > Buffer [ 0 ] = fr - > fcb - > ads ? ' : ' : ' \\ ' ;
fn - > Length + = sizeof ( WCHAR ) ;
if ( fn - > MaximumLength > sizeof ( WCHAR ) ) {
RtlCopyMemory ( & fn - > Buffer [ 1 ] , fr - > dc - > name . Buffer , min ( fr - > dc - > name . Length , fn - > MaximumLength - sizeof ( WCHAR ) ) ) ;
fn - > Length + = fr - > dc - > name . Length ;
}
if ( fn - > Length > fn - > MaximumLength ) {
fn - > Length = fn - > MaximumLength ;
overflow = TRUE ;
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
reqlen + = sizeof ( WCHAR ) + fr - > dc - > name . Length ;
2016-07-27 19:24:26 +00:00
fr = fr - > parent ;
}
2017-09-08 08:02:43 +00:00
offset + = sizeof ( WCHAR ) ;
if ( overflow ) {
if ( preqlen )
* preqlen = reqlen ;
Status = STATUS_BUFFER_OVERFLOW ;
} else {
if ( name_offset )
* name_offset = offset ;
Status = STATUS_SUCCESS ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS fill_in_file_name_information ( FILE_NAME_INFORMATION * fni , fcb * fcb , file_ref * fileref , LONG * length ) {
ULONG reqlen ;
2016-07-27 19:24:26 +00:00
UNICODE_STRING fn ;
NTSTATUS Status ;
2018-12-16 11:03:16 +00:00
static const WCHAR datasuf [ ] = { ' : ' , ' $ ' , ' D ' , ' A ' , ' T ' , ' A ' , 0 } ;
UINT16 datasuflen = sizeof ( datasuf ) - sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! fileref ) {
ERR ( " called without fileref \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* length - = ( LONG ) offsetof ( FILE_NAME_INFORMATION , FileName [ 0 ] ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " maximum length is %u \n " , * length ) ;
fni - > FileNameLength = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fni - > FileName [ 0 ] = 0 ;
2017-09-08 08:02:43 +00:00
fn . Buffer = fni - > FileName ;
fn . Length = 0 ;
fn . MaximumLength = ( UINT16 ) * length ;
Status = fileref_get_filename ( fileref , & fn , NULL , & reqlen ) ;
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_BUFFER_OVERFLOW ) {
2016-07-27 19:24:26 +00:00
ERR ( " fileref_get_filename returned %08x \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > ads ) {
2017-09-08 08:02:43 +00:00
if ( Status = = STATUS_BUFFER_OVERFLOW )
reqlen + = datasuflen ;
else {
if ( fn . Length + datasuflen > fn . MaximumLength ) {
RtlCopyMemory ( & fn . Buffer [ fn . Length / sizeof ( WCHAR ) ] , datasuf , fn . MaximumLength - fn . Length ) ;
reqlen + = datasuflen ;
Status = STATUS_BUFFER_OVERFLOW ;
} else {
RtlCopyMemory ( & fn . Buffer [ fn . Length / sizeof ( WCHAR ) ] , datasuf , datasuflen ) ;
fn . Length + = datasuflen ;
2016-03-23 20:35:05 +00:00
}
}
}
2017-09-08 08:02:43 +00:00
if ( Status = = STATUS_BUFFER_OVERFLOW ) {
* length = - 1 ;
fni - > FileNameLength = reqlen ;
TRACE ( " %.*S (truncated) \n " , fn . Length / sizeof ( WCHAR ) , fn . Buffer ) ;
} else {
* length - = fn . Length ;
fni - > FileNameLength = fn . Length ;
TRACE ( " %.*S \n " , fn . Length / sizeof ( WCHAR ) , fn . Buffer ) ;
}
return Status ;
2016-03-23 20:35:05 +00:00
}
2018-12-16 11:03:16 +00:00
static NTSTATUS fill_in_file_attribute_information ( FILE_ATTRIBUTE_TAG_INFORMATION * ati , fcb * fcb , ccb * ccb , LONG * length ) {
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_ATTRIBUTE_TAG_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
2017-09-08 08:02:43 +00:00
if ( ! ccb - > fileref | | ! ccb - > fileref - > parent ) {
2016-05-05 17:26:47 +00:00
ERR ( " no fileref for stream \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
ati - > FileAttributes = ccb - > fileref - > parent - > fcb - > atts ;
2016-05-05 17:26:47 +00:00
} else
ati - > FileAttributes = fcb - > atts ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! ( ati - > FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) )
ati - > ReparseTag = 0 ;
else
2018-12-16 11:03:16 +00:00
ati - > ReparseTag = get_reparse_tag_fcb ( fcb ) ;
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 fill_in_file_stream_information ( FILE_STREAM_INFORMATION * fsi , file_ref * fileref , LONG * length ) {
LONG reqsize ;
LIST_ENTRY * le ;
2016-07-27 19:24:26 +00:00
FILE_STREAM_INFORMATION * entry , * lastentry ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
static const WCHAR datasuf [ ] = L " :$DATA " ;
2016-03-23 20:35:05 +00:00
UNICODE_STRING suf ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! fileref ) {
ERR ( " fileref was NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
suf . Buffer = ( WCHAR * ) datasuf ;
suf . Length = suf . MaximumLength = sizeof ( datasuf ) - sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
if ( fileref - > fcb - > type ! = BTRFS_TYPE_DIRECTORY )
reqsize = sizeof ( FILE_STREAM_INFORMATION ) - sizeof ( WCHAR ) + suf . Length + sizeof ( WCHAR ) ;
else
reqsize = 0 ;
ExAcquireResourceSharedLite ( & fileref - > fcb - > nonpaged - > dir_children_lock , TRUE ) ;
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 ) ;
if ( dc - > index = = 0 ) {
reqsize = ( ULONG ) sector_align ( reqsize , sizeof ( LONGLONG ) ) ;
reqsize + = sizeof ( FILE_STREAM_INFORMATION ) - sizeof ( WCHAR ) + suf . Length + sizeof ( WCHAR ) + dc - > name . Length ;
} else
break ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
2016-03-23 20:35:05 +00:00
TRACE ( " length = %i, reqsize = %u \n " , * length , reqsize ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( reqsize > * length ) {
Status = STATUS_BUFFER_OVERFLOW ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
entry = fsi ;
2016-07-27 19:24:26 +00:00
lastentry = NULL ;
2017-09-08 08:02:43 +00:00
if ( fileref - > fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
ULONG off ;
entry - > NextEntryOffset = 0 ;
entry - > StreamNameLength = suf . Length + sizeof ( WCHAR ) ;
entry - > StreamSize . QuadPart = fileref - > fcb - > inode_item . st_size ;
entry - > StreamAllocationSize . QuadPart = fcb_alloc_size ( fileref - > fcb ) ;
entry - > StreamName [ 0 ] = ' : ' ;
RtlCopyMemory ( & entry - > StreamName [ 1 ] , suf . Buffer , suf . Length ) ;
off = ( ULONG ) sector_align ( sizeof ( FILE_STREAM_INFORMATION ) - sizeof ( WCHAR ) + suf . Length + sizeof ( WCHAR ) , sizeof ( LONGLONG ) ) ;
lastentry = entry ;
entry = ( FILE_STREAM_INFORMATION * ) ( ( UINT8 * ) entry + off ) ;
}
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 ) ;
if ( dc - > index = = 0 ) {
2016-07-27 19:24:26 +00:00
ULONG off ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
entry - > NextEntryOffset = 0 ;
2017-09-08 08:02:43 +00:00
entry - > StreamNameLength = dc - > name . Length + suf . Length + sizeof ( WCHAR ) ;
if ( dc - > fileref )
entry - > StreamSize . QuadPart = dc - > fileref - > fcb - > adsdata . Length ;
2016-07-27 19:24:26 +00:00
else
2017-09-08 08:02:43 +00:00
entry - > StreamSize . QuadPart = dc - > size ;
entry - > StreamAllocationSize . QuadPart = entry - > StreamSize . QuadPart ;
2016-07-27 19:24:26 +00:00
entry - > StreamName [ 0 ] = ' : ' ;
2017-09-08 08:02:43 +00:00
RtlCopyMemory ( & entry - > StreamName [ 1 ] , dc - > name . Buffer , dc - > name . Length ) ;
RtlCopyMemory ( & entry - > StreamName [ 1 + ( dc - > name . Length / sizeof ( WCHAR ) ) ] , suf . Buffer , suf . Length ) ;
2016-07-27 19:24:26 +00:00
if ( lastentry )
2017-09-08 08:02:43 +00:00
lastentry - > NextEntryOffset = ( UINT32 ) ( ( UINT8 * ) entry - ( UINT8 * ) lastentry ) ;
off = ( ULONG ) sector_align ( sizeof ( FILE_STREAM_INFORMATION ) - sizeof ( WCHAR ) + suf . Length + sizeof ( WCHAR ) + dc - > name . Length , sizeof ( LONGLONG ) ) ;
2016-03-23 20:35:05 +00:00
2016-07-27 19:24:26 +00:00
lastentry = entry ;
entry = ( FILE_STREAM_INFORMATION * ) ( ( UINT8 * ) entry + off ) ;
2017-09-08 08:02:43 +00:00
} else
break ;
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* length - = reqsize ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
end :
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & fileref - > fcb - > nonpaged - > dir_children_lock ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2016-05-09 09:10:13 +00:00
# ifndef __REACTOS__
2017-09-08 08:02:43 +00:00
static NTSTATUS fill_in_file_standard_link_information ( FILE_STANDARD_LINK_INFORMATION * fsli , fcb * fcb , file_ref * fileref , LONG * length ) {
2016-03-23 20:35:05 +00:00
TRACE ( " FileStandardLinkInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - NumberOfAccessibleLinks should subtract open links which have been marked as delete_on_close
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fsli - > NumberOfAccessibleLinks = fcb - > inode_item . st_nlink ;
fsli - > TotalNumberOfLinks = fcb - > inode_item . st_nlink ;
2016-05-05 17:26:47 +00:00
fsli - > DeletePending = fileref ? fileref - > delete_on_close : FALSE ;
2017-09-08 08:02:43 +00:00
fsli - > Directory = ( ! fcb - > ads & & fcb - > type = = BTRFS_TYPE_DIRECTORY ) ? TRUE : FALSE ;
2016-03-23 20:35:05 +00:00
* length - = sizeof ( FILE_STANDARD_LINK_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2016-05-09 09:10:13 +00:00
# endif /* __REACTOS__ */
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
NTSTATUS open_fileref_by_inode ( _Requires_exclusive_lock_held_ ( _Curr_ - > fcb_lock ) device_extension * Vcb ,
root * subvol , UINT64 inode , file_ref * * pfr , PIRP Irp ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
fcb * fcb ;
2017-09-08 08:02:43 +00:00
UINT64 parent = 0 ;
UNICODE_STRING name ;
BOOL hl_alloc = FALSE ;
2016-07-27 19:24:26 +00:00
file_ref * parfr , * fr ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = open_fcb ( Vcb , subvol , inode , 0 , NULL , NULL , & fcb , PagedPool , Irp ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " open_fcb returned %08x \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > fileref ) {
* pfr = fcb - > fileref ;
increase_fileref_refcount ( fcb - > fileref ) ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// find hardlink if fcb doesn't have any loaded
if ( IsListEmpty ( & fcb - > hardlinks ) ) {
KEY searchkey ;
traverse_ptr tp ;
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_INODE_EXTREF ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = find_item ( Vcb , fcb - > subvol , & tp , & searchkey , FALSE , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " find_item returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
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 ( tp . item - > key . obj_id = = fcb - > inode ) {
if ( tp . item - > key . obj_type = = TYPE_INODE_REF ) {
INODE_REF * ir ;
ULONG stringlen ;
ir = ( INODE_REF * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
parent = tp . item - > key . offset ;
2017-01-01 17:12:12 +00:00
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & stringlen , ir - > name , ir - > n ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN 1 returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
name . Length = name . MaximumLength = ( UINT16 ) stringlen ;
2017-01-01 17:12:12 +00:00
if ( stringlen = = 0 )
2017-09-08 08:02:43 +00:00
name . Buffer = NULL ;
2017-01-01 17:12:12 +00:00
else {
2017-09-08 08:02:43 +00:00
name . Buffer = ExAllocatePoolWithTag ( PagedPool , name . MaximumLength , ALLOC_TAG ) ;
if ( ! name . Buffer ) {
2017-01-01 17:12:12 +00:00
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
Status = RtlUTF8ToUnicodeN ( name . Buffer , stringlen , & stringlen , ir - > name , ir - > n ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN 2 returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( name . Buffer ) ;
free_fcb ( Vcb , fcb ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
hl_alloc = TRUE ;
2017-01-01 17:12:12 +00:00
}
} else if ( tp . item - > key . obj_type = = TYPE_INODE_EXTREF ) {
INODE_EXTREF * ier ;
ULONG stringlen ;
ier = ( INODE_EXTREF * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
parent = ier - > dir ;
2017-01-01 17:12:12 +00:00
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & stringlen , ier - > name , ier - > n ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN 1 returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
name . Length = name . MaximumLength = ( UINT16 ) stringlen ;
2017-01-01 17:12:12 +00:00
if ( stringlen = = 0 )
2017-09-08 08:02:43 +00:00
name . Buffer = NULL ;
2017-01-01 17:12:12 +00:00
else {
2017-09-08 08:02:43 +00:00
name . Buffer = ExAllocatePoolWithTag ( PagedPool , name . MaximumLength , ALLOC_TAG ) ;
if ( ! name . Buffer ) {
2017-01-01 17:12:12 +00:00
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
Status = RtlUTF8ToUnicodeN ( name . Buffer , stringlen , & stringlen , ier - > name , ier - > n ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN 2 returned %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( name . Buffer ) ;
free_fcb ( Vcb , fcb ) ;
2017-01-01 17:12:12 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
hl_alloc = TRUE ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
}
}
2017-09-08 08:02:43 +00:00
} else {
hardlink * hl = CONTAINING_RECORD ( fcb - > hardlinks . Flink , hardlink , list_entry ) ;
name = hl - > name ;
parent = hl - > parent ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
if ( parent = = 0 ) {
2016-07-27 19:24:26 +00:00
ERR ( " subvol %llx, inode %llx has no hardlinks \n " , subvol - > id , inode ) ;
2017-09-08 08:02:43 +00:00
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc ) ExFreePool ( name . Buffer ) ;
return STATUS_INVALID_PARAMETER ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( parent = = inode ) { // subvolume root
KEY searchkey ;
traverse_ptr tp ;
searchkey . obj_id = subvol - > id ;
searchkey . obj_type = TYPE_ROOT_BACKREF ;
searchkey . offset = 0xffffffffffffffff ;
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , FALSE , Irp ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2017-09-08 08:02:43 +00:00
ERR ( " find_item returned %08x \n " , Status ) ;
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc ) ExFreePool ( name . Buffer ) ;
2016-07-27 19:24:26 +00:00
return Status ;
}
2017-09-08 08:02:43 +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 ;
if ( tp . item - > size < sizeof ( ROOT_REF ) ) {
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 ( ROOT_REF ) ) ;
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc ) ExFreePool ( name . Buffer ) ;
return STATUS_INTERNAL_ERROR ;
}
if ( tp . item - > size < offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ) {
ERR ( " (%llx,%x,%llx) was %u bytes, expected %u \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , offsetof ( ROOT_REF , name [ 0 ] ) + rr - > n ) ;
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc ) ExFreePool ( name . Buffer ) ;
return STATUS_INTERNAL_ERROR ;
}
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 ;
}
le = le - > Flink ;
}
if ( ! r ) {
ERR ( " couldn't find subvol %llx \n " , tp . item - > key . offset ) ;
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc ) ExFreePool ( name . Buffer ) ;
return STATUS_INTERNAL_ERROR ;
}
Status = open_fileref_by_inode ( Vcb , r , rr - > dir , & parfr , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " open_fileref_by_inode returned %08x \n " , Status ) ;
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc ) ExFreePool ( name . Buffer ) ;
return Status ;
}
if ( hl_alloc ) {
ExFreePool ( name . Buffer ) ;
hl_alloc = FALSE ;
}
Status = RtlUTF8ToUnicodeN ( NULL , 0 , & stringlen , rr - > name , rr - > n ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN 1 returned %08x \n " , Status ) ;
free_fcb ( Vcb , fcb ) ;
return Status ;
}
name . Length = name . MaximumLength = ( UINT16 ) stringlen ;
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 ( Vcb , fcb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
Status = RtlUTF8ToUnicodeN ( name . Buffer , stringlen , & stringlen , rr - > name , rr - > n ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUTF8ToUnicodeN 2 returned %08x \n " , Status ) ;
ExFreePool ( name . Buffer ) ;
free_fcb ( Vcb , fcb ) ;
return Status ;
}
hl_alloc = TRUE ;
}
} else {
ERR ( " couldn't find parent for subvol %llx \n " , subvol - > id ) ;
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc ) ExFreePool ( name . Buffer ) ;
return STATUS_INTERNAL_ERROR ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
} else {
Status = open_fileref_by_inode ( Vcb , subvol , parent , & parfr , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " open_fileref_by_inode returned %08x \n " , Status ) ;
free_fcb ( Vcb , fcb ) ;
if ( hl_alloc )
ExFreePool ( name . Buffer ) ;
return Status ;
2016-07-27 19:24:26 +00:00
}
}
2017-09-08 08:02:43 +00:00
Status = open_fileref_child ( Vcb , parfr , & name , TRUE , TRUE , FALSE , PagedPool , & fr , Irp ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2017-09-08 08:02:43 +00:00
ERR ( " open_fileref_child returned %08x \n " , Status ) ;
if ( hl_alloc )
ExFreePool ( name . Buffer ) ;
free_fcb ( Vcb , fcb ) ;
free_fileref ( Vcb , parfr ) ;
2016-07-27 19:24:26 +00:00
return Status ;
}
* pfr = fr ;
2017-09-08 08:02:43 +00:00
if ( hl_alloc )
ExFreePool ( name . Buffer ) ;
free_fcb ( Vcb , fcb ) ;
free_fileref ( Vcb , parfr ) ;
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2016-05-09 09:10:13 +00:00
# ifndef __REACTOS__
2017-09-08 08:02:43 +00:00
static NTSTATUS fill_in_hard_link_information ( FILE_LINKS_INFORMATION * fli , file_ref * fileref , PIRP Irp , LONG * length ) {
2016-05-05 17:26:47 +00:00
NTSTATUS Status ;
2016-07-27 19:24:26 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
LONG bytes_needed ;
2016-05-05 17:26:47 +00:00
FILE_LINK_ENTRY_INFORMATION * feli ;
2016-07-27 19:24:26 +00:00
BOOL overflow = FALSE ;
fcb * fcb = fileref - > fcb ;
ULONG len ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads )
return STATUS_INVALID_PARAMETER ;
2017-09-08 08:02:43 +00:00
if ( * length < ( LONG ) offsetof ( FILE_LINKS_INFORMATION , Entry ) )
2016-05-05 17:26:47 +00:00
return STATUS_INVALID_PARAMETER ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlZeroMemory ( fli , * length ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
bytes_needed = offsetof ( FILE_LINKS_INFORMATION , Entry ) ;
len = bytes_needed ;
feli = NULL ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExAcquireResourceSharedLite ( fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE ) {
ULONG namelen ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb = = fcb - > Vcb - > root_fileref - > fcb )
namelen = sizeof ( WCHAR ) ;
else
2017-09-08 08:02:43 +00:00
namelen = fileref - > dc - > name . Length ;
2016-07-27 19:24:26 +00:00
bytes_needed + = sizeof ( FILE_LINK_ENTRY_INFORMATION ) - sizeof ( WCHAR ) + namelen ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( bytes_needed > * length )
overflow = TRUE ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! overflow ) {
feli = & fli - > Entry ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
feli - > NextEntryOffset = 0 ;
feli - > ParentFileId = 0 ; // we use an inode of 0 to mean the parent of a subvolume
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb = = fcb - > Vcb - > root_fileref - > fcb ) {
feli - > FileNameLength = 1 ;
feli - > FileName [ 0 ] = ' . ' ;
} else {
2017-09-08 08:02:43 +00:00
feli - > FileNameLength = fileref - > dc - > name . Length / sizeof ( WCHAR ) ;
RtlCopyMemory ( feli - > FileName , fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fli - > EntriesReturned + + ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
len = bytes_needed ;
}
} else {
2017-10-16 18:05:33 +00:00
acquire_fcb_lock_exclusive ( fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( IsListEmpty ( & fcb - > hardlinks ) ) {
2017-09-08 08:02:43 +00:00
bytes_needed + = sizeof ( FILE_LINK_ENTRY_INFORMATION ) + fileref - > dc - > name . Length - sizeof ( WCHAR ) ;
2017-01-01 17:12:12 +00:00
if ( bytes_needed > * length )
overflow = TRUE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! overflow ) {
feli = & fli - > Entry ;
feli - > NextEntryOffset = 0 ;
feli - > ParentFileId = fileref - > parent - > fcb - > inode ;
2017-09-08 08:02:43 +00:00
feli - > FileNameLength = fileref - > dc - > name . Length / sizeof ( WCHAR ) ;
RtlCopyMemory ( feli - > FileName , fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
2017-01-01 17:12:12 +00:00
fli - > EntriesReturned + + ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
len = bytes_needed ;
}
} else {
le = fcb - > hardlinks . Flink ;
while ( le ! = & fcb - > hardlinks ) {
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
file_ref * parfr ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " parent %llx, index %llx, name %.*S \n " , hl - > parent , hl - > index , hl - > name . Length / sizeof ( WCHAR ) , hl - > name . Buffer ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = open_fileref_by_inode ( fcb - > Vcb , fcb - > subvol , hl - > parent , & parfr , Irp ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " open_fileref_by_inode returned %08x \n " , Status ) ;
} else if ( ! parfr - > deleted ) {
LIST_ENTRY * le2 ;
BOOL found = FALSE , deleted = FALSE ;
2017-09-08 08:02:43 +00:00
UNICODE_STRING * fn = NULL ;
2017-01-01 17:12:12 +00:00
le2 = parfr - > children . Flink ;
while ( le2 ! = & parfr - > children ) {
file_ref * fr2 = CONTAINING_RECORD ( le2 , file_ref , list_entry ) ;
2017-09-08 08:02:43 +00:00
if ( fr2 - > dc - > index = = hl - > index ) {
2017-01-01 17:12:12 +00:00
found = TRUE ;
deleted = fr2 - > deleted ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! deleted )
2017-09-08 08:02:43 +00:00
fn = & fr2 - > dc - > name ;
2017-01-01 17:12:12 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le2 = le2 - > Flink ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! found )
fn = & hl - > name ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! deleted ) {
TRACE ( " fn = %.*S (found = %u) \n " , fn - > Length / sizeof ( WCHAR ) , fn - > Buffer , found ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( feli )
2017-09-08 08:02:43 +00:00
bytes_needed = ( LONG ) sector_align ( bytes_needed , 8 ) ;
2017-01-01 17:12:12 +00:00
bytes_needed + = sizeof ( FILE_LINK_ENTRY_INFORMATION ) + fn - > Length - sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( bytes_needed > * length )
overflow = TRUE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! overflow ) {
if ( feli ) {
2017-09-08 08:02:43 +00:00
feli - > NextEntryOffset = ( ULONG ) sector_align ( sizeof ( FILE_LINK_ENTRY_INFORMATION ) + ( ( feli - > FileNameLength - 1 ) * sizeof ( WCHAR ) ) , 8 ) ;
2017-01-01 17:12:12 +00:00
feli = ( FILE_LINK_ENTRY_INFORMATION * ) ( ( UINT8 * ) feli + feli - > NextEntryOffset ) ;
} else
feli = & fli - > Entry ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
feli - > NextEntryOffset = 0 ;
feli - > ParentFileId = parfr - > fcb - > inode ;
feli - > FileNameLength = fn - > Length / sizeof ( WCHAR ) ;
RtlCopyMemory ( feli - > FileName , fn - > Buffer , fn - > Length ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fli - > EntriesReturned + + ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
len = bytes_needed ;
}
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
free_fileref ( fcb - > Vcb , parfr ) ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-05-05 17:26:47 +00:00
}
}
2017-09-08 08:02:43 +00:00
2017-10-16 18:05:33 +00:00
release_fcb_lock ( fcb - > Vcb ) ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fli - > BytesNeeded = bytes_needed ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
* length - = len ;
Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2016-05-05 17:26:47 +00:00
return Status ;
}
2016-05-09 09:10:13 +00:00
# endif /* __REACTOS__ */
2016-05-05 17:26:47 +00:00
2016-07-27 19:24:26 +00:00
# if (NTDDI_VERSION >= NTDDI_WIN10)
# ifdef __MINGW32__
typedef struct _FILE_ID_128 {
UCHAR Identifier [ 16 ] ;
2017-09-08 08:02:43 +00:00
} FILE_ID_128 , * PFILE_ID_128 ;
2016-07-27 19:24:26 +00:00
typedef struct _FILE_ID_INFORMATION {
ULONGLONG VolumeSerialNumber ;
FILE_ID_128 FileId ;
} FILE_ID_INFORMATION , * PFILE_ID_INFORMATION ;
# endif
static NTSTATUS fill_in_file_id_information ( FILE_ID_INFORMATION * fii , fcb * fcb , LONG * length ) {
RtlCopyMemory ( & fii - > VolumeSerialNumber , & fcb - > Vcb - > superblock . uuid . uuid [ 8 ] , sizeof ( UINT64 ) ) ;
RtlCopyMemory ( & fii - > FileId . Identifier [ 0 ] , & fcb - > inode , sizeof ( UINT64 ) ) ;
RtlCopyMemory ( & fii - > FileId . Identifier [ sizeof ( UINT64 ) ] , & fcb - > subvol - > id , sizeof ( UINT64 ) ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
* length - = sizeof ( FILE_ID_INFORMATION ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
# endif
2018-12-16 11:03:16 +00:00
# ifndef __REACTOS__
static NTSTATUS fill_in_file_stat_lx_information ( FILE_STAT_LX_INFORMATION * fsli , fcb * fcb , ccb * ccb , LONG * length ) {
INODE_ITEM * ii ;
fsli - > FileId . LowPart = ( UINT32 ) fcb - > inode ;
fsli - > FileId . HighPart = ( UINT32 ) fcb - > subvol - > id ;
if ( fcb - > ads )
ii = & ccb - > fileref - > parent - > fcb - > inode_item ;
else
ii = & fcb - > inode_item ;
if ( fcb = = fcb - > Vcb - > dummy_fcb ) {
LARGE_INTEGER time ;
KeQuerySystemTime ( & time ) ;
fsli - > CreationTime = fsli - > LastAccessTime = fsli - > LastWriteTime = fsli - > ChangeTime = time ;
} else {
fsli - > CreationTime . QuadPart = unix_time_to_win ( & ii - > otime ) ;
fsli - > LastAccessTime . QuadPart = unix_time_to_win ( & ii - > st_atime ) ;
fsli - > LastWriteTime . QuadPart = unix_time_to_win ( & ii - > st_mtime ) ;
fsli - > ChangeTime . QuadPart = unix_time_to_win ( & ii - > st_ctime ) ;
}
if ( fcb - > ads ) {
fsli - > AllocationSize . QuadPart = fsli - > EndOfFile . QuadPart = fcb - > adsdata . Length ;
fsli - > FileAttributes = ccb - > fileref - > parent - > fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : ccb - > fileref - > parent - > fcb - > atts ;
} else {
fsli - > AllocationSize . QuadPart = fcb_alloc_size ( fcb ) ;
fsli - > EndOfFile . QuadPart = S_ISDIR ( fcb - > inode_item . st_mode ) ? 0 : fcb - > inode_item . st_size ;
fsli - > FileAttributes = fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : fcb - > atts ;
}
if ( fcb - > type = = BTRFS_TYPE_SOCKET )
fsli - > ReparseTag = IO_REPARSE_TAG_LXSS_SOCKET ;
else if ( fcb - > type = = BTRFS_TYPE_FIFO )
fsli - > ReparseTag = IO_REPARSE_TAG_LXSS_FIFO ;
else if ( fcb - > type = = BTRFS_TYPE_CHARDEV )
fsli - > ReparseTag = IO_REPARSE_TAG_LXSS_CHARDEV ;
else if ( fcb - > type = = BTRFS_TYPE_BLOCKDEV )
fsli - > ReparseTag = IO_REPARSE_TAG_LXSS_BLOCKDEV ;
else if ( ! ( fsli - > FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) )
fsli - > ReparseTag = 0 ;
else
fsli - > ReparseTag = get_reparse_tag_fcb ( fcb ) ;
if ( fcb - > type = = BTRFS_TYPE_SOCKET | | fcb - > type = = BTRFS_TYPE_FIFO | | fcb - > type = = BTRFS_TYPE_CHARDEV | | fcb - > type = = BTRFS_TYPE_BLOCKDEV )
fsli - > FileAttributes | = FILE_ATTRIBUTE_REPARSE_POINT ;
if ( fcb - > ads )
fsli - > NumberOfLinks = ccb - > fileref - > parent - > fcb - > inode_item . st_nlink ;
else
fsli - > NumberOfLinks = fcb - > inode_item . st_nlink ;
fsli - > EffectiveAccess = ccb - > access ;
fsli - > LxFlags = LX_FILE_METADATA_HAS_UID | LX_FILE_METADATA_HAS_GID | LX_FILE_METADATA_HAS_MODE | LX_FILE_METADATA_HAS_DEVICE_ID ; // FIXME - LX_FILE_CASE_SENSITIVE_DIR
fsli - > LxUid = ii - > st_uid ;
fsli - > LxGid = ii - > st_gid ;
fsli - > LxMode = ii - > st_mode ;
if ( ii - > st_mode & __S_IFBLK | | ii - > st_mode & __S_IFCHR ) {
fsli - > LxDeviceIdMajor = ( ii - > st_rdev & 0xFFFFFFFFFFF00000 ) > > 20 ;
fsli - > LxDeviceIdMinor = ( ii - > st_rdev & 0xFFFFF ) ;
} else {
fsli - > LxDeviceIdMajor = 0 ;
fsli - > LxDeviceIdMinor = 0 ;
}
* length - = sizeof ( FILE_STAT_LX_INFORMATION ) ;
return STATUS_SUCCESS ;
}
# endif
2017-09-08 08:02:43 +00:00
static NTSTATUS query_info ( device_extension * Vcb , PFILE_OBJECT FileObject , PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
LONG length = IrpSp - > Parameters . QueryFile . Length ;
fcb * fcb = FileObject - > FsContext ;
ccb * ccb = FileObject - > FsContext2 ;
2016-05-05 17:26:47 +00:00
file_ref * fileref = ccb ? ccb - > fileref : NULL ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " (%p, %p, %p) \n " , Vcb , FileObject , Irp ) ;
TRACE ( " fcb = %p \n " , fcb ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb = = Vcb - > volume_fcb )
return STATUS_INVALID_PARAMETER ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! ccb ) {
ERR ( " ccb is NULL \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( IrpSp - > Parameters . QueryFile . FileInformationClass ) {
case FileAllInformation :
{
FILE_ALL_INFORMATION * fai = Irp - > AssociatedIrp . SystemBuffer ;
INODE_ITEM * ii ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileAllInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Irp - > RequestorMode ! = KernelMode & & ! ( ccb - > access & ( FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES ) ) ) {
2016-07-27 19:24:26 +00:00
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref for stream \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ii = & fileref - > parent - > fcb - > inode_item ;
} else
2016-03-23 20:35:05 +00:00
ii = & fcb - > inode_item ;
2017-09-08 08:02:43 +00:00
// Access, mode, and alignment are all filled in by the kernel
2016-03-23 20:35:05 +00:00
if ( length > 0 )
2016-05-05 17:26:47 +00:00
fill_in_file_basic_information ( & fai - > BasicInformation , ii , & length , fcb , fileref ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( length > 0 )
2016-05-05 17:26:47 +00:00
fill_in_file_standard_information ( & fai - > StandardInformation , fcb , fileref , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( length > 0 )
2016-10-29 17:05:10 +00:00
fill_in_file_internal_information ( & fai - > InternalInformation , fcb , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( length > 0 )
2016-10-29 17:05:10 +00:00
fill_in_file_ea_information ( & fai - > EaInformation , fcb , & length ) ;
2017-09-08 08:02:43 +00:00
length - = sizeof ( FILE_ACCESS_INFORMATION ) ;
2016-03-23 20:35:05 +00:00
if ( length > 0 )
fill_in_file_position_information ( & fai - > PositionInformation , FileObject , & length ) ;
2017-09-08 08:02:43 +00:00
length - = sizeof ( FILE_MODE_INFORMATION ) ;
length - = sizeof ( FILE_ALIGNMENT_INFORMATION ) ;
2016-03-23 20:35:05 +00:00
if ( length > 0 )
2016-05-05 17:26:47 +00:00
fill_in_file_name_information ( & fai - > NameInformation , fcb , fileref , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
break ;
}
case FileAttributeTagInformation :
{
FILE_ATTRIBUTE_TAG_INFORMATION * ati = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileAttributeTagInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Irp - > RequestorMode ! = KernelMode & & ! ( ccb - > access & ( FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES ) ) ) {
2016-07-27 19:24:26 +00:00
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
2018-12-16 11:03:16 +00:00
Status = fill_in_file_attribute_information ( ati , fcb , ccb , & length ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
break ;
}
case FileBasicInformation :
{
FILE_BASIC_INFORMATION * fbi = Irp - > AssociatedIrp . SystemBuffer ;
INODE_ITEM * ii ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileBasicInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Irp - > RequestorMode ! = KernelMode & & ! ( ccb - > access & ( FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES ) ) ) {
2016-07-27 19:24:26 +00:00
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Parameters . QueryFile . Length < sizeof ( FILE_BASIC_INFORMATION ) ) {
WARN ( " overflow \n " ) ;
Status = STATUS_BUFFER_OVERFLOW ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fcb - > ads ) {
if ( ! fileref | | ! fileref - > parent ) {
ERR ( " no fileref for stream \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ii = & fileref - > parent - > fcb - > inode_item ;
} else
2016-03-23 20:35:05 +00:00
ii = & fcb - > inode_item ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = fill_in_file_basic_information ( fbi , ii , & length , fcb , fileref ) ;
2016-03-23 20:35:05 +00:00
break ;
}
case FileCompressionInformation :
FIXME ( " STUB: FileCompressionInformation \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
case FileEaInformation :
{
FILE_EA_INFORMATION * eai = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileEaInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = fill_in_file_ea_information ( eai , fcb , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileInternalInformation :
{
FILE_INTERNAL_INFORMATION * fii = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileInternalInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = fill_in_file_internal_information ( fii , fcb , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileNameInformation :
{
FILE_NAME_INFORMATION * fni = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileNameInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = fill_in_file_name_information ( fni , fcb , fileref , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileNetworkOpenInformation :
{
FILE_NETWORK_OPEN_INFORMATION * fnoi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileNetworkOpenInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Irp - > RequestorMode ! = KernelMode & & ! ( ccb - > access & ( FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES ) ) ) {
2016-07-27 19:24:26 +00:00
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = fill_in_file_network_open_information ( fnoi , fcb , fileref , & length ) ;
2016-03-23 20:35:05 +00:00
break ;
}
case FilePositionInformation :
{
FILE_POSITION_INFORMATION * fpi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FilePositionInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = fill_in_file_position_information ( fpi , FileObject , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileStandardInformation :
{
FILE_STANDARD_INFORMATION * fsi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileStandardInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Parameters . QueryFile . Length < sizeof ( FILE_STANDARD_INFORMATION ) ) {
WARN ( " overflow \n " ) ;
Status = STATUS_BUFFER_OVERFLOW ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = fill_in_file_standard_information ( fsi , fcb , ccb - > fileref , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileStreamInformation :
{
FILE_STREAM_INFORMATION * fsi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileStreamInformation \n " ) ;
2017-09-08 08:02:43 +00:00
Status = fill_in_file_stream_information ( fsi , fileref , & length ) ;
2016-03-23 20:35:05 +00:00
break ;
}
# if (NTDDI_VERSION >= NTDDI_VISTA)
case FileHardLinkInformation :
2016-05-05 17:26:47 +00:00
{
FILE_LINKS_INFORMATION * fli = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
TRACE ( " FileHardLinkInformation \n " ) ;
2017-09-08 08:02:43 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , TRUE ) ;
2016-09-04 15:27:46 +00:00
Status = fill_in_hard_link_information ( fli , fileref , Irp , & length ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-05-05 17:26:47 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case FileNormalizedNameInformation :
{
FILE_NAME_INFORMATION * fni = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileNormalizedNameInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = fill_in_file_name_information ( fni , fcb , fileref , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# if (NTDDI_VERSION >= NTDDI_WIN7)
case FileStandardLinkInformation :
{
FILE_STANDARD_LINK_INFORMATION * fsli = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileStandardLinkInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Status = fill_in_file_standard_link_information ( fsli , fcb , ccb - > fileref , & length ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case FileRemoteProtocolInformation :
2016-03-26 11:53:07 +00:00
TRACE ( " FileRemoteProtocolInformation \n " ) ;
2016-03-23 20:35:05 +00:00
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
# endif
2016-07-27 19:24:26 +00:00
# if (NTDDI_VERSION >= NTDDI_WIN10)
2017-09-08 08:02:43 +00:00
# ifndef _MSC_VER
2016-07-27 19:24:26 +00:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wswitch"
2017-09-08 08:02:43 +00:00
# endif
2016-07-27 19:24:26 +00:00
case FileIdInformation :
{
FILE_ID_INFORMATION * fii = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( IrpSp - > Parameters . QueryFile . Length < sizeof ( FILE_ID_INFORMATION ) ) {
WARN ( " overflow \n " ) ;
Status = STATUS_BUFFER_OVERFLOW ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " FileIdInformation \n " ) ;
2017-09-08 08:02:43 +00:00
Status = fill_in_file_id_information ( fii , fcb , & length ) ;
2016-07-27 19:24:26 +00:00
break ;
}
2018-12-16 11:03:16 +00:00
case FileStatLxInformation :
{
FILE_STAT_LX_INFORMATION * fsli = Irp - > AssociatedIrp . SystemBuffer ;
if ( IrpSp - > Parameters . QueryFile . Length < sizeof ( FILE_STAT_LX_INFORMATION ) ) {
WARN ( " overflow \n " ) ;
Status = STATUS_BUFFER_OVERFLOW ;
goto exit ;
}
TRACE ( " FileStatLxInformation \n " ) ;
Status = fill_in_file_stat_lx_information ( fsli , fcb , ccb , & length ) ;
break ;
}
2017-09-08 08:02:43 +00:00
# ifndef _MSC_VER
# pragma GCC diagnostic pop
# endif
2016-07-27 19:24:26 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
default :
WARN ( " unknown FileInformationClass %u \n " , IrpSp - > Parameters . QueryFile . FileInformationClass ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( length < 0 ) {
length = 0 ;
Status = STATUS_BUFFER_OVERFLOW ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Information = IrpSp - > Parameters . QueryFile . Length - length ;
2017-09-08 08:02:43 +00:00
exit :
2016-03-23 20:35:05 +00:00
TRACE ( " query_info returning %08x \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
_Dispatch_type_ ( IRP_MJ_QUERY_INFORMATION )
_Function_class_ ( DRIVER_DISPATCH )
2018-08-21 05:05:40 +00:00
NTSTATUS NTAPI drv_query_information ( IN PDEVICE_OBJECT DeviceObject , IN PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
fcb * fcb ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
BOOL top_level ;
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
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_query_information ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " query information \n " ) ;
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
fcb = IrpSp - > FileObject - > FsContext ;
TRACE ( " fcb = %p \n " , fcb ) ;
TRACE ( " fcb->subvol = %p \n " , fcb - > subvol ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = query_info ( fcb - > Vcb , IrpSp - > FileObject , Irp ) ;
2017-09-08 08:02:43 +00:00
end :
2016-03-23 20:35:05 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Status = Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return Status ;
}
2016-10-29 17:05:10 +00:00
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_QUERY_EA )
_Function_class_ ( DRIVER_DISPATCH )
2018-08-21 05:05:40 +00:00
NTSTATUS NTAPI drv_query_ea ( IN PDEVICE_OBJECT DeviceObject , IN PIRP Irp ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
BOOL top_level ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
fcb * fcb ;
ccb * ccb ;
FILE_FULL_EA_INFORMATION * ffei ;
ULONG retlen = 0 ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " (%p, %p) \n " , DeviceObject , Irp ) ;
2016-10-29 17:05:10 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_query_ea ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
ffei = map_user_buffer ( Irp , NormalPagePriority ) ;
2016-10-29 17:05:10 +00:00
if ( ! ffei ) {
ERR ( " could not get output buffer \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! FileObject ) {
ERR ( " no file object \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb = FileObject - > FsContext ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! fcb ) {
ERR ( " no fcb \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ccb = FileObject - > FsContext2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ccb ) {
ERR ( " no ccb \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & ( FILE_READ_EA | FILE_WRITE_EA ) ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
if ( fcb - > ads )
fcb = ccb - > fileref - > parent - > fcb ;
2016-10-29 17:05:10 +00:00
ExAcquireResourceSharedLite ( fcb - > Header . Resource , TRUE ) ;
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
2016-10-29 17:05:10 +00:00
if ( fcb - > ea_xattr . Length = = 0 )
goto end2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( IrpSp - > Parameters . QueryEa . EaList ) {
FILE_FULL_EA_INFORMATION * ea , * out ;
FILE_GET_EA_INFORMATION * in ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
in = IrpSp - > Parameters . QueryEa . EaList ;
do {
STRING s ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
s . Length = s . MaximumLength = in - > EaNameLength ;
s . Buffer = in - > EaName ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlUpperString ( & s , & s ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( in - > NextEntryOffset = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
in = ( FILE_GET_EA_INFORMATION * ) ( ( ( UINT8 * ) in ) + in - > NextEntryOffset ) ;
} while ( TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) fcb - > ea_xattr . Buffer ;
out = NULL ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
do {
BOOL found = FALSE ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
in = IrpSp - > Parameters . QueryEa . EaList ;
do {
if ( in - > EaNameLength = = ea - > EaNameLength & &
RtlCompareMemory ( in - > EaName , ea - > EaName , in - > EaNameLength ) = = in - > EaNameLength ) {
found = TRUE ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( in - > NextEntryOffset = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
in = ( FILE_GET_EA_INFORMATION * ) ( ( ( UINT8 * ) in ) + in - > NextEntryOffset ) ;
} while ( TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( found ) {
UINT8 padding = retlen % 4 > 0 ? ( 4 - ( retlen % 4 ) ) : 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + ea - > EaNameLength + 1 + ea - > EaValueLength > IrpSp - > Parameters . QueryEa . Length - retlen - padding ) {
Status = STATUS_BUFFER_OVERFLOW ;
retlen = 0 ;
goto end2 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
retlen + = padding ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( out ) {
2017-09-08 08:02:43 +00:00
out - > NextEntryOffset = ( ULONG ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + out - > EaNameLength + 1 + out - > EaValueLength + padding ;
2016-10-29 17:05:10 +00:00
out = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) out ) + out - > NextEntryOffset ) ;
} else
out = ffei ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
out - > NextEntryOffset = 0 ;
out - > Flags = ea - > Flags ;
out - > EaNameLength = ea - > EaNameLength ;
out - > EaValueLength = ea - > EaValueLength ;
RtlCopyMemory ( out - > EaName , ea - > EaName , ea - > EaNameLength + ea - > EaValueLength + 1 ) ;
2017-09-08 08:02:43 +00:00
retlen + = ( ULONG ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + ea - > EaNameLength + 1 + ea - > EaValueLength ;
2016-10-29 17:05:10 +00:00
if ( IrpSp - > Flags & SL_RETURN_SINGLE_ENTRY )
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ea - > NextEntryOffset = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) ea ) + ea - > NextEntryOffset ) ;
} while ( TRUE ) ;
} else {
FILE_FULL_EA_INFORMATION * ea , * out ;
ULONG index ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( IrpSp - > Flags & SL_INDEX_SPECIFIED ) {
// The index is 1-based
if ( IrpSp - > Parameters . QueryEa . EaIndex = = 0 ) {
Status = STATUS_NONEXISTENT_EA_ENTRY ;
2017-09-08 08:02:43 +00:00
goto end2 ;
2016-10-29 17:05:10 +00:00
} else
index = IrpSp - > Parameters . QueryEa . EaIndex - 1 ;
} else if ( IrpSp - > Flags & SL_RESTART_SCAN )
index = ccb - > ea_index = 0 ;
else
index = ccb - > ea_index ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) fcb - > ea_xattr . Buffer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( index > 0 ) {
ULONG i ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( i = 0 ; i < index ; i + + ) {
if ( ea - > NextEntryOffset = = 0 ) // last item
goto end2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) ea ) + ea - > NextEntryOffset ) ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
out = NULL ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
do {
UINT8 padding = retlen % 4 > 0 ? ( 4 - ( retlen % 4 ) ) : 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + ea - > EaNameLength + 1 + ea - > EaValueLength > IrpSp - > Parameters . QueryEa . Length - retlen - padding ) {
Status = retlen = = 0 ? STATUS_BUFFER_TOO_SMALL : STATUS_BUFFER_OVERFLOW ;
goto end2 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
retlen + = padding ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( out ) {
2017-09-08 08:02:43 +00:00
out - > NextEntryOffset = ( ULONG ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + out - > EaNameLength + 1 + out - > EaValueLength + padding ;
2016-10-29 17:05:10 +00:00
out = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) out ) + out - > NextEntryOffset ) ;
} else
out = ffei ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
out - > NextEntryOffset = 0 ;
out - > Flags = ea - > Flags ;
out - > EaNameLength = ea - > EaNameLength ;
out - > EaValueLength = ea - > EaValueLength ;
RtlCopyMemory ( out - > EaName , ea - > EaName , ea - > EaNameLength + ea - > EaValueLength + 1 ) ;
2017-09-08 08:02:43 +00:00
retlen + = ( ULONG ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + ea - > EaNameLength + 1 + ea - > EaValueLength ;
2016-10-29 17:05:10 +00:00
if ( ! ( IrpSp - > Flags & SL_INDEX_SPECIFIED ) )
ccb - > ea_index + + ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ea - > NextEntryOffset = = 0 | | IrpSp - > Flags & SL_RETURN_SINGLE_ENTRY )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) ea ) + ea - > NextEntryOffset ) ;
} while ( TRUE ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end2 :
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
2017-09-08 08:02:43 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2016-10-29 17:05:10 +00:00
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = NT_SUCCESS ( Status ) | | Status = = STATUS_BUFFER_OVERFLOW ? retlen : 0 ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-10-29 17:05:10 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_SET_EA )
_Function_class_ ( DRIVER_DISPATCH )
2018-08-21 05:05:40 +00:00
NTSTATUS NTAPI drv_set_ea ( IN PDEVICE_OBJECT DeviceObject , IN PIRP Irp ) {
2016-10-29 17:05:10 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
NTSTATUS Status ;
BOOL top_level ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
fcb * fcb ;
ccb * ccb ;
2017-09-08 08:02:43 +00:00
file_ref * fileref ;
2016-10-29 17:05:10 +00:00
FILE_FULL_EA_INFORMATION * ffei ;
ULONG offset ;
LIST_ENTRY ealist ;
ea_item * item ;
FILE_FULL_EA_INFORMATION * ea ;
LIST_ENTRY * le ;
LARGE_INTEGER time ;
BTRFS_TIME now ;
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " (%p, %p) \n " , DeviceObject , Irp ) ;
2016-10-29 17:05:10 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_set_ea ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > readonly ) {
Status = STATUS_MEDIA_WRITE_PROTECTED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
ffei = map_user_buffer ( Irp , NormalPagePriority ) ;
2016-10-29 17:05:10 +00:00
if ( ! ffei ) {
ERR ( " could not get output buffer \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = IoCheckEaBufferValidity ( ffei , IrpSp - > Parameters . SetEa . Length , & offset ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " IoCheckEaBufferValidity returned %08x (error at offset %u) \n " , Status , offset ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! FileObject ) {
ERR ( " no file object \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb = FileObject - > FsContext ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! fcb ) {
ERR ( " no fcb \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ccb = FileObject - > FsContext2 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ccb ) {
ERR ( " no ccb \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & FILE_WRITE_EA ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
if ( fcb - > ads ) {
fileref = ccb - > fileref - > parent ;
fcb = fileref - > fcb ;
} else
fileref = ccb - > fileref ;
2016-10-29 17:05:10 +00:00
InitializeListHead ( & ealist ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > ea_xattr . Length > 0 ) {
ea = ( FILE_FULL_EA_INFORMATION * ) fcb - > ea_xattr . Buffer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
do {
item = ExAllocatePoolWithTag ( PagedPool , sizeof ( ea_item ) , ALLOC_TAG ) ;
if ( ! item ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end2 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item - > name . Length = item - > name . MaximumLength = ea - > EaNameLength ;
item - > name . Buffer = ea - > EaName ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item - > value . Length = item - > value . MaximumLength = ea - > EaValueLength ;
item - > value . Buffer = & ea - > EaName [ ea - > EaNameLength + 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item - > flags = ea - > Flags ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & ealist , & item - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ea - > NextEntryOffset = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) ea ) + ea - > NextEntryOffset ) ;
} while ( TRUE ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ffei ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
do {
STRING s ;
BOOL found = FALSE ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
s . Length = s . MaximumLength = ea - > EaNameLength ;
s . Buffer = ea - > EaName ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlUpperString ( & s , & s ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = ealist . Flink ;
while ( le ! = & ealist ) {
item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
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 ] ;
found = TRUE ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! found ) {
item = ExAllocatePoolWithTag ( PagedPool , sizeof ( ea_item ) , ALLOC_TAG ) ;
if ( ! item ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end2 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item - > name . Length = item - > name . MaximumLength = ea - > EaNameLength ;
item - > name . Buffer = ea - > EaName ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item - > value . Length = item - > value . MaximumLength = ea - > EaValueLength ;
item - > value . Buffer = & ea - > EaName [ ea - > EaNameLength + 1 ] ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item - > flags = ea - > Flags ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InsertTailList ( & ealist , & item - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ea - > NextEntryOffset = = 0 )
break ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) ea ) + ea - > NextEntryOffset ) ;
} while ( TRUE ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// remove entries with zero-length value
le = ealist . Flink ;
while ( le ! = & ealist ) {
LIST_ENTRY * le2 = le - > Flink ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( item - > value . Length = = 0 ) {
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le2 ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
// handle LXSS values
le = ealist . Flink ;
while ( le ! = & ealist ) {
LIST_ENTRY * le2 = le - > Flink ;
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 ) {
if ( item - > value . Length < sizeof ( UINT32 ) ) {
ERR ( " uid value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end2 ;
}
if ( Irp - > RequestorMode = = KernelMode ) {
RtlCopyMemory ( & fcb - > inode_item . st_uid , item - > value . Buffer , sizeof ( UINT32 ) ) ;
fcb - > sd_dirty = TRUE ;
fcb - > sd_deleted = FALSE ;
}
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 ) {
if ( item - > value . Length < sizeof ( UINT32 ) ) {
ERR ( " gid value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end2 ;
}
if ( Irp - > RequestorMode = = KernelMode )
RtlCopyMemory ( & fcb - > inode_item . st_gid , item - > value . Buffer , sizeof ( UINT32 ) ) ;
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 ) {
if ( item - > value . Length < sizeof ( UINT32 ) ) {
ERR ( " mode value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end2 ;
}
if ( Irp - > RequestorMode = = KernelMode ) {
UINT32 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 val ;
RtlCopyMemory ( & val , item - > value . Buffer , sizeof ( UINT32 ) ) ;
fcb - > inode_item . st_mode & = ~ allowed ;
fcb - > inode_item . st_mode | = val & allowed ;
}
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
}
le = le2 ;
}
2016-10-29 17:05:10 +00:00
if ( IsListEmpty ( & ealist ) ) {
fcb - > ealen = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > ea_xattr . Buffer )
ExFreePool ( fcb - > ea_xattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > ea_xattr . Length = fcb - > ea_xattr . MaximumLength = 0 ;
fcb - > ea_xattr . Buffer = NULL ;
} else {
2017-09-08 08:02:43 +00:00
UINT16 size = 0 ;
2016-10-29 17:05:10 +00:00
char * buf , * oldbuf ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = ealist . Flink ;
while ( le ! = & ealist ) {
item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( size % 4 > 0 )
size + = 4 - ( size % 4 ) ;
2017-09-08 08:02:43 +00:00
size + = ( UINT16 ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + item - > name . Length + 1 + item - > value . Length ;
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
buf = ExAllocatePoolWithTag ( PagedPool , size , ALLOC_TAG ) ;
if ( ! buf ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end2 ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
oldbuf = fcb - > ea_xattr . Buffer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > ea_xattr . Length = fcb - > ea_xattr . MaximumLength = size ;
fcb - > ea_xattr . Buffer = buf ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > ealen = 4 ;
ea = NULL ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = ealist . Flink ;
while ( le ! = & ealist ) {
item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ea ) {
2017-09-08 08:02:43 +00:00
ea - > NextEntryOffset = ( ULONG ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + ea - > EaNameLength + ea - > EaValueLength ;
2016-10-29 17:05:10 +00:00
if ( ea - > NextEntryOffset % 4 > 0 )
ea - > NextEntryOffset + = 4 - ( ea - > NextEntryOffset % 4 ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( UINT8 * ) ea ) + ea - > NextEntryOffset ) ;
} else
ea = ( FILE_FULL_EA_INFORMATION * ) fcb - > ea_xattr . Buffer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ea - > NextEntryOffset = 0 ;
ea - > Flags = item - > flags ;
2017-09-08 08:02:43 +00:00
ea - > EaNameLength = ( UCHAR ) item - > name . Length ;
2016-10-29 17:05:10 +00:00
ea - > EaValueLength = item - > value . Length ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
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 ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > ealen + = 5 + item - > name . Length + item - > value . Length ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( oldbuf )
ExFreePool ( oldbuf ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > ea_changed = TRUE ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
fcb - > inode_item . transid = Vcb - > superblock . generation ;
fcb - > inode_item . sequence + + ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! ccb - > user_set_change_time )
fcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
fcb - > inode_item_changed = TRUE ;
mark_fcb_dirty ( fcb ) ;
2017-09-08 08:02:43 +00:00
send_notification_fileref ( fileref , FILE_NOTIFY_CHANGE_EA , FILE_ACTION_MODIFIED , NULL ) ;
2016-10-29 17:05:10 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end2 :
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
while ( ! IsListEmpty ( & ealist ) ) {
le = RemoveHeadList ( & ealist ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
item = CONTAINING_RECORD ( le , ea_item , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExFreePool ( item ) ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
end :
2017-09-08 08:02:43 +00:00
TRACE ( " returning %08x \n " , Status ) ;
2016-10-29 17:05:10 +00:00
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-10-29 17:05:10 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}