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"
2019-09-02 20:17:17 +00:00
# if (NTDDI_VERSION >= NTDDI_WIN10)
2016-07-27 19:24:26 +00:00
// not currently in mingw - introduced with Windows 10
2019-05-11 09:20:02 +00:00
# ifndef _MSC_VER
2016-07-27 19:24:26 +00:00
# define FileIdInformation (enum _FILE_INFORMATION_CLASS)59
2019-06-11 10:35:19 +00:00
# define FileHardLinkFullIdInformation (enum _FILE_INFORMATION_CLASS)62
# define FileDispositionInformationEx (enum _FILE_INFORMATION_CLASS)64
# define FileRenameInformationEx (enum _FILE_INFORMATION_CLASS)65
# define FileStatInformation (enum _FILE_INFORMATION_CLASS)68
2018-12-16 11:03:16 +00:00
# define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
2019-06-11 10:35:19 +00:00
# define FileCaseSensitiveInformation (enum _FILE_INFORMATION_CLASS)71
# define FileLinkInformationEx (enum _FILE_INFORMATION_CLASS)72
typedef struct _FILE_ID_INFORMATION {
ULONGLONG VolumeSerialNumber ;
FILE_ID_128 FileId ;
} FILE_ID_INFORMATION , * PFILE_ID_INFORMATION ;
typedef struct _FILE_STAT_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 ;
} FILE_STAT_INFORMATION , * PFILE_STAT_INFORMATION ;
2018-12-16 11:03:16 +00:00
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
2019-06-11 10:35:19 +00:00
typedef struct _FILE_RENAME_INFORMATION_EX {
union {
BOOLEAN ReplaceIfExists ;
ULONG Flags ;
} ;
HANDLE RootDirectory ;
ULONG FileNameLength ;
WCHAR FileName [ 1 ] ;
} FILE_RENAME_INFORMATION_EX , * PFILE_RENAME_INFORMATION_EX ;
typedef struct _FILE_DISPOSITION_INFORMATION_EX {
ULONG Flags ;
} FILE_DISPOSITION_INFORMATION_EX , * PFILE_DISPOSITION_INFORMATION_EX ;
typedef struct _FILE_LINK_INFORMATION_EX {
union {
BOOLEAN ReplaceIfExists ;
ULONG Flags ;
} ;
HANDLE RootDirectory ;
ULONG FileNameLength ;
WCHAR FileName [ 1 ] ;
} FILE_LINK_INFORMATION_EX , * PFILE_LINK_INFORMATION_EX ;
typedef struct _FILE_CASE_SENSITIVE_INFORMATION {
ULONG Flags ;
} FILE_CASE_SENSITIVE_INFORMATION , * PFILE_CASE_SENSITIVE_INFORMATION ;
typedef struct _FILE_LINK_ENTRY_FULL_ID_INFORMATION {
ULONG NextEntryOffset ;
FILE_ID_128 ParentFileId ;
ULONG FileNameLength ;
WCHAR FileName [ 1 ] ;
} FILE_LINK_ENTRY_FULL_ID_INFORMATION , * PFILE_LINK_ENTRY_FULL_ID_INFORMATION ;
typedef struct _FILE_LINKS_FULL_ID_INFORMATION {
ULONG BytesNeeded ;
ULONG EntriesReturned ;
FILE_LINK_ENTRY_FULL_ID_INFORMATION Entry ;
} FILE_LINKS_FULL_ID_INFORMATION , * PFILE_LINKS_FULL_ID_INFORMATION ;
# define FILE_RENAME_REPLACE_IF_EXISTS 0x001
# define FILE_RENAME_POSIX_SEMANTICS 0x002
# define FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE 0x004
# define FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x008
# define FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE 0x010
# define FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE 0x020
# define FILE_RENAME_IGNORE_READONLY_ATTRIBUTE 0x040
# define FILE_RENAME_FORCE_RESIZE_TARGET_SR 0x080
# define FILE_RENAME_FORCE_RESIZE_SOURCE_SR 0x100
# define FILE_DISPOSITION_DELETE 0x1
# define FILE_DISPOSITION_POSIX_SEMANTICS 0x2
# define FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK 0x4
# define FILE_DISPOSITION_ON_CLOSE 0x8
# define FILE_LINK_REPLACE_IF_EXISTS 0x001
# define FILE_LINK_POSIX_SEMANTICS 0x002
# define FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x008
# define FILE_LINK_NO_INCREASE_AVAILABLE_SPACE 0x010
# define FILE_LINK_NO_DECREASE_AVAILABLE_SPACE 0x020
# define FILE_LINK_IGNORE_READONLY_ATTRIBUTE 0x040
# define FILE_LINK_FORCE_RESIZE_TARGET_SR 0x080
# define FILE_LINK_FORCE_RESIZE_SOURCE_SR 0x100
# define FILE_CS_FLAG_CASE_SENSITIVE_DIR 1
# else
# define FILE_RENAME_INFORMATION_EX FILE_RENAME_INFORMATION
# define FILE_LINK_INFORMATION_EX FILE_LINK_INFORMATION
2019-09-02 20:17:17 +00:00
# endif
# endif
# ifdef __REACTOS__
typedef struct _FILE_RENAME_INFORMATION_EX {
union {
BOOLEAN ReplaceIfExists ;
ULONG Flags ;
} ;
HANDLE RootDirectory ;
ULONG FileNameLength ;
WCHAR FileName [ 1 ] ;
} FILE_RENAME_INFORMATION_EX , * PFILE_RENAME_INFORMATION_EX ;
typedef struct _FILE_DISPOSITION_INFORMATION_EX {
ULONG Flags ;
} FILE_DISPOSITION_INFORMATION_EX , * PFILE_DISPOSITION_INFORMATION_EX ;
typedef struct _FILE_LINK_INFORMATION_EX {
union {
BOOLEAN ReplaceIfExists ;
ULONG Flags ;
} ;
HANDLE RootDirectory ;
ULONG FileNameLength ;
WCHAR FileName [ 1 ] ;
} FILE_LINK_INFORMATION_EX , * PFILE_LINK_INFORMATION_EX ;
# define FILE_RENAME_REPLACE_IF_EXISTS 0x001
# define FILE_RENAME_POSIX_SEMANTICS 0x002
# define FILE_RENAME_IGNORE_READONLY_ATTRIBUTE 0x040
# define FILE_DISPOSITION_DELETE 0x1
# define FILE_DISPOSITION_POSIX_SEMANTICS 0x2
# define FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK 0x4
# define FILE_LINK_REPLACE_IF_EXISTS 0x001
# define FILE_LINK_POSIX_SEMANTICS 0x002
# define FILE_LINK_IGNORE_READONLY_ATTRIBUTE 0x040
2019-06-11 10:35:19 +00:00
# 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 ;
2019-09-01 12:53:20 +00:00
bool inode_item_changed = false ;
2016-03-23 20:35:05 +00:00
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 ;
}
2019-11-12 18:32:46 +00:00
TRACE ( " file = %p, attributes = %x \n " , FileObject , fbi - > FileAttributes ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +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 )
2019-09-01 12:53:20 +00:00
ccb - > user_set_creation_time = true ;
2016-10-29 17:05:10 +00:00
else if ( fbi - > CreationTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > CreationTime , & fcb - > inode_item . otime ) ;
2019-09-01 12:53:20 +00:00
inode_item_changed = true ;
2016-10-29 17:05:10 +00:00
filter | = FILE_NOTIFY_CHANGE_CREATION ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ccb - > user_set_creation_time = true ;
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 ( fbi - > LastAccessTime . QuadPart = = - 1 )
2019-09-01 12:53:20 +00:00
ccb - > user_set_access_time = true ;
2016-10-29 17:05:10 +00:00
else if ( fbi - > LastAccessTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > LastAccessTime , & fcb - > inode_item . st_atime ) ;
2019-09-01 12:53:20 +00:00
inode_item_changed = true ;
2016-10-29 17:05:10 +00:00
filter | = FILE_NOTIFY_CHANGE_LAST_ACCESS ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ccb - > user_set_access_time = true ;
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 ( fbi - > LastWriteTime . QuadPart = = - 1 )
2019-09-01 12:53:20 +00:00
ccb - > user_set_write_time = true ;
2016-10-29 17:05:10 +00:00
else if ( fbi - > LastWriteTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > LastWriteTime , & fcb - > inode_item . st_mtime ) ;
2019-09-01 12:53:20 +00:00
inode_item_changed = true ;
2016-10-29 17:05:10 +00:00
filter | = FILE_NOTIFY_CHANGE_LAST_WRITE ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ccb - > user_set_write_time = true ;
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 ( fbi - > ChangeTime . QuadPart = = - 1 )
2019-09-01 12:53:20 +00:00
ccb - > user_set_change_time = true ;
2016-10-29 17:05:10 +00:00
else if ( fbi - > ChangeTime . QuadPart ! = 0 ) {
win_time_to_unix ( fbi - > ChangeTime , & fcb - > inode_item . st_ctime ) ;
2019-09-01 12:53:20 +00:00
inode_item_changed = true ;
2016-10-29 17:05:10 +00:00
// no filter for this
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ccb - > user_set_change_time = true ;
2016-10-29 17:05:10 +00:00
}
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 ] = = ' . ' ,
2019-09-01 12:53:20 +00:00
true , Irp ) ;
2017-09-08 08:02:43 +00:00
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
2019-09-01 12:53:20 +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 )
2019-09-01 12:53:20 +00:00
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 ) )
2019-09-01 12:53:20 +00:00
fcb - > atts_deleted = true ;
2017-09-08 08:02:43 +00:00
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
2019-09-01 12:53:20 +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 + + ;
2019-09-01 12:53:20 +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 )
2019-11-12 18:32:46 +00:00
queue_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
}
2019-09-01 12:53:20 +00:00
static NTSTATUS set_disposition_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject , bool ex ) {
2016-03-23 20:35:05 +00:00
fcb * fcb = FileObject - > FsContext ;
2016-05-05 17:26:47 +00:00
ccb * ccb = FileObject - > FsContext2 ;
file_ref * fileref = ccb ? ccb - > fileref : NULL ;
2019-06-11 10:35:19 +00:00
ULONG atts , flags ;
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
2019-06-11 10:35:19 +00:00
if ( ex ) {
FILE_DISPOSITION_INFORMATION_EX * fdi = Irp - > AssociatedIrp . SystemBuffer ;
flags = fdi - > Flags ;
} else {
FILE_DISPOSITION_INFORMATION * fdi = Irp - > AssociatedIrp . SystemBuffer ;
flags = fdi - > DeleteFile ? FILE_DISPOSITION_DELETE : 0 ;
}
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
TRACE ( " changing delete_on_close to %s for fcb %p \n " , flags & FILE_DISPOSITION_DELETE ? " true " : " false " , 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
2019-11-12 18:32:46 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE & & fcb - > subvol - > id = = BTRFS_ROOT_FSTREE ) {
WARN ( " not allowing \\ $Root to be deleted \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
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 ) ) {
2019-06-11 10:35:19 +00:00
if ( ! ex | | flags & FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK ) {
TRACE ( " trying to delete file which is being mapped as an image \n " ) ;
Status = STATUS_CANNOT_DELETE ;
goto end ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
ccb - > fileref - > delete_on_close = flags & FILE_DISPOSITION_DELETE ;
FileObject - > DeletePending = flags & FILE_DISPOSITION_DELETE ;
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
if ( flags & FILE_DISPOSITION_DELETE & & flags & FILE_DISPOSITION_POSIX_SEMANTICS )
2019-09-01 12:53:20 +00:00
ccb - > fileref - > posix_delete = true ;
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
// send notification that directory is about to be deleted
2019-06-11 10:35:19 +00:00
if ( NT_SUCCESS ( Status ) & & flags & FILE_DISPOSITION_DELETE & & fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
2017-09-08 08:02:43 +00:00
FsRtlNotifyFullChangeDirectory ( Vcb - > NotifySync , & Vcb - > DirNotifyList , FileObject - > FsContext ,
2019-09-01 12:53:20 +00:00
NULL , false , false , 0 , NULL , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
}
2016-10-29 17:05:10 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2019-09-01 12:53:20 +00:00
bool has_open_children ( file_ref * fileref ) {
2016-07-27 19:24:26 +00:00
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 ) )
2019-09-01 12:53:20 +00:00
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 )
2019-09-01 12:53:20 +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 ) )
2019-09-01 12:53:20 +00:00
return true ;
2016-07-27 19:24:26 +00:00
2016-03-23 20:35:05 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return false ;
2016-07-27 19:24:26 +00:00
}
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 ) {
2019-09-01 12:53:20 +00:00
fcb - > ads = true ;
2016-07-27 19:24:26 +00:00
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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 ) ) ;
2019-09-01 12:53:20 +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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 ) ;
2019-09-01 12:53:20 +00:00
ext2 - > unique = false ;
ext2 - > ignore = false ;
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 ;
2019-09-01 12:53:20 +00:00
len = len * sizeof ( uint32_t ) / 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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( 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 " ) ;
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & me - > fileref - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
Status = open_fileref_child ( Vcb , me - > fileref , & dc - > name , true , true , dc - > index = = 0 ? true : false , PagedPool , & fr , Irp ) ;
2017-09-08 08:02:43 +00:00
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 ) {
2019-09-01 12:53:20 +00:00
uint8_t 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 ;
2019-09-01 12:53:20 +00:00
fcb - > inode_item . st_mode = __S_IFDIR | inherit_mode ( parfcb , true ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
fcb - > atts = get_file_attributes ( Vcb , fcb - > subvol , fcb - > inode , fcb - > type , false , true , NULL ) ;
2017-09-08 08:02:43 +00:00
SeCaptureSubjectContext ( & subjcont ) ;
2019-09-01 12:53:20 +00:00
Status = SeAssignSecurity ( parfcb - > sd , NULL , ( void * * ) & fcb - > sd , true , & subjcont , IoGetFileObjectGenericMapping ( ) , PagedPool ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
ERR ( " SeAssignSecurity returned %08x \n " , Status ) ;
return Status ;
}
if ( ! fcb - > sd ) {
2019-05-11 09:20:02 +00:00
reap_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
fcb - > sd_dirty = true ;
2017-09-08 08:02:43 +00:00
} 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 ) ;
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
fcb - > Header . AllocationSize . QuadPart = 0 ;
fcb - > Header . FileSize . QuadPart = 0 ;
fcb - > Header . ValidDataLength . QuadPart = 0 ;
2019-09-01 12:53:20 +00:00
fcb - > created = true ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-05-11 09:20:02 +00:00
acquire_fcb_lock_exclusive ( Vcb ) ;
InsertTailList ( & r - > fcbs , & fcb - > list_entry ) ;
InsertTailList ( & Vcb - > all_fcbs , & fcb - > list_entry_all ) ;
r - > fcbs_version + + ;
release_fcb_lock ( Vcb ) ;
mark_fcb_dirty ( fcb ) ;
2017-09-08 08:02:43 +00:00
* 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 ;
2019-05-11 09:20:02 +00:00
// FIXME - make sure me->dummyfileref and me->dummyfcb get freed properly
2017-09-08 08:02:43 +00:00
InitializeListHead ( & move_list ) ;
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2019-05-11 09:20:02 +00:00
acquire_fcb_lock_exclusive ( fileref - > fcb - > Vcb ) ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( me - > fileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
bool inserted = false ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le3 ;
2019-09-01 12:53:20 +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 ] = = ' . ' ,
2019-09-01 12:53:20 +00:00
true , Irp ) ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-09-01 12:53:20 +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 ) ;
2019-09-01 12:53:20 +00:00
xa - > dirty = true ;
2017-09-08 08:02:43 +00:00
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 ) {
2019-09-01 12:53:20 +00:00
ERR ( " get_chunk_from_address(%I64x) failed \n " , ed2 - > address ) ;
2016-07-27 19:24:26 +00:00
} else {
Status = update_changed_extent_ref ( me - > fileref - > fcb - > Vcb , c , ed2 - > address , ed2 - > size , me - > fileref - > fcb - > subvol - > id , me - > fileref - > fcb - > inode ,
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +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 ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
2017-01-01 17:12:12 +00:00
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
2019-09-01 12:53:20 +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 {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( me - > fileref - > fcb - > Header . Resource , true ) ;
2016-07-27 19:24:26 +00:00
me - > fileref - > fcb - > inode_item . st_nlink + + ;
2019-09-01 12:53:20 +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 ;
2019-09-01 12:53:20 +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 ) )
2019-09-01 12:53:20 +00:00
name_changed = true ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & me - > dummyfileref - > parent - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
InsertTailList ( & me - > dummyfileref - > parent - > children , & me - > dummyfileref - > list_entry ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & me - > dummyfileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
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
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-01-01 17:12:12 +00:00
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 ;
2019-09-01 12:53:20 +00:00
me - > fileref - > parent - > fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & fileref - > dc - > name_uc , & fileref - > dc - > name , true ) ;
2017-09-08 08:02:43 +00:00
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
2019-09-01 12:53:20 +00:00
me - > fileref - > dc - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) me - > fileref - > dc - > name . Buffer , me - > fileref - > dc - > name . Length ) ;
me - > fileref - > dc - > hash_uc = calc_crc32c ( 0xffffffff , ( uint8_t * ) me - > fileref - > dc - > name_uc . Buffer , me - > fileref - > dc - > name_uc . Length ) ;
2017-01-01 17:12:12 +00:00
}
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
2019-09-01 12:53:20 +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
2019-05-11 09:20:02 +00:00
free_fileref ( me - > fileref - > parent ) ;
2017-01-01 17:12:12 +00:00
me - > fileref - > parent = destdir ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
InsertTailList ( & me - > fileref - > parent - > children , & me - > fileref - > list_entry ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " me->fileref->parent->fcb->inode_item.st_size (inode %I64x) was %I64x \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 ;
2019-09-01 12:53:20 +00:00
TRACE ( " me->fileref->parent->fcb->inode_item.st_size (inode %I64x) now %I64x \n " , me - > fileref - > parent - > fcb - > inode , me - > fileref - > parent - > fcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
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 ;
2019-09-01 12:53:20 +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 ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & me - > fileref - > parent - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & me - > parent - > fileref - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
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 ) {
2019-09-01 12:53:20 +00:00
Status = delete_fileref ( me - > dummyfileref , NULL , false , 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 ) {
2019-09-01 12:53:20 +00:00
Status = delete_fileref ( me - > dummyfileref , NULL , false , 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 )
2019-05-11 09:20:02 +00:00
free_fcb ( me - > dummyfcb ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( me - > dummyfileref )
2019-05-11 09:20:02 +00:00
free_fileref ( me - > dummyfileref ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_fileref ( me - > fileref ) ;
2017-09-08 08:02:43 +00:00
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
2019-05-11 09:20:02 +00:00
destdir - > fcb - > subvol - > fcbs_version + + ;
fileref - > fcb - > subvol - > fcbs_version + + ;
release_fcb_lock ( fileref - > fcb - > Vcb ) ;
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 ) {
2019-09-01 12:53:20 +00:00
bool inserted ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
uint8_t 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
2019-09-01 12:53:20 +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 ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
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
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
2019-09-01 12:53:20 +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 ) ;
2019-09-01 12:53:20 +00:00
inserted = true ;
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
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 ;
}
}
2019-11-12 18:32:46 +00:00
static NTSTATUS rename_stream_to_file ( device_extension * Vcb , file_ref * fileref , ccb * ccb , ULONG flags ,
PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
file_ref * ofr ;
ANSI_STRING adsdata ;
dir_child * dc ;
fcb * dummyfcb ;
if ( fileref - > fcb - > type ! = BTRFS_TYPE_FILE )
return STATUS_INVALID_PARAMETER ;
if ( ! ( flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE ) & & fileref - > parent - > fcb - > atts & FILE_ATTRIBUTE_READONLY ) {
WARN ( " trying to rename stream on readonly file \n " ) ;
return STATUS_ACCESS_DENIED ;
}
if ( Irp - > RequestorMode = = UserMode & & ccb & & ! ( ccb - > access & DELETE ) ) {
WARN ( " insufficient permissions \n " ) ;
return STATUS_ACCESS_DENIED ;
}
if ( ! ( flags & FILE_RENAME_REPLACE_IF_EXISTS ) ) // file will always exist
return STATUS_OBJECT_NAME_COLLISION ;
// FIXME - POSIX overwrites of stream?
ofr = fileref - > parent ;
if ( ofr - > open_count > 0 ) {
WARN ( " trying to overwrite open file \n " ) ;
return STATUS_ACCESS_DENIED ;
}
if ( ofr - > fcb - > inode_item . st_size > 0 ) {
WARN ( " can only overwrite existing stream if it is zero-length \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
dummyfcb = create_fcb ( Vcb , PagedPool ) ;
if ( ! dummyfcb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
// copy parent fcb onto this one
fileref - > fcb - > subvol = ofr - > fcb - > subvol ;
fileref - > fcb - > inode = ofr - > fcb - > inode ;
fileref - > fcb - > hash = ofr - > fcb - > hash ;
fileref - > fcb - > type = ofr - > fcb - > type ;
fileref - > fcb - > inode_item = ofr - > fcb - > inode_item ;
fileref - > fcb - > sd = ofr - > fcb - > sd ;
ofr - > fcb - > sd = NULL ;
fileref - > fcb - > deleted = ofr - > fcb - > deleted ;
fileref - > fcb - > atts = ofr - > fcb - > atts ;
fileref - > fcb - > reparse_xattr = ofr - > fcb - > reparse_xattr ;
ofr - > fcb - > reparse_xattr . Buffer = NULL ;
ofr - > fcb - > reparse_xattr . Length = ofr - > fcb - > reparse_xattr . MaximumLength = 0 ;
fileref - > fcb - > ea_xattr = ofr - > fcb - > ea_xattr ;
ofr - > fcb - > ea_xattr . Buffer = NULL ;
ofr - > fcb - > ea_xattr . Length = ofr - > fcb - > ea_xattr . MaximumLength = 0 ;
fileref - > fcb - > ealen = ofr - > fcb - > ealen ;
while ( ! IsListEmpty ( & ofr - > fcb - > hardlinks ) ) {
InsertTailList ( & fileref - > fcb - > hardlinks , RemoveHeadList ( & ofr - > fcb - > hardlinks ) ) ;
}
fileref - > fcb - > inode_item_changed = true ;
fileref - > fcb - > prop_compression = ofr - > fcb - > prop_compression ;
while ( ! IsListEmpty ( & ofr - > fcb - > xattrs ) ) {
InsertTailList ( & fileref - > fcb - > xattrs , RemoveHeadList ( & ofr - > fcb - > xattrs ) ) ;
}
fileref - > fcb - > marked_as_orphan = ofr - > fcb - > marked_as_orphan ;
fileref - > fcb - > case_sensitive = ofr - > fcb - > case_sensitive ;
fileref - > fcb - > case_sensitive_set = ofr - > fcb - > case_sensitive_set ;
while ( ! IsListEmpty ( & ofr - > fcb - > dir_children_index ) ) {
InsertTailList ( & fileref - > fcb - > dir_children_index , RemoveHeadList ( & ofr - > fcb - > dir_children_index ) ) ;
}
while ( ! IsListEmpty ( & ofr - > fcb - > dir_children_hash ) ) {
InsertTailList ( & fileref - > fcb - > dir_children_hash , RemoveHeadList ( & ofr - > fcb - > dir_children_hash ) ) ;
}
while ( ! IsListEmpty ( & ofr - > fcb - > dir_children_hash_uc ) ) {
InsertTailList ( & fileref - > fcb - > dir_children_hash_uc , RemoveHeadList ( & ofr - > fcb - > dir_children_hash_uc ) ) ;
}
fileref - > fcb - > hash_ptrs = ofr - > fcb - > hash_ptrs ;
fileref - > fcb - > hash_ptrs_uc = ofr - > fcb - > hash_ptrs_uc ;
ofr - > fcb - > hash_ptrs = NULL ;
ofr - > fcb - > hash_ptrs_uc = NULL ;
fileref - > fcb - > sd_dirty = ofr - > fcb - > sd_dirty ;
fileref - > fcb - > sd_deleted = ofr - > fcb - > sd_deleted ;
fileref - > fcb - > atts_changed = ofr - > fcb - > atts_changed ;
fileref - > fcb - > atts_deleted = ofr - > fcb - > atts_deleted ;
fileref - > fcb - > extents_changed = true ;
fileref - > fcb - > reparse_xattr_changed = ofr - > fcb - > reparse_xattr_changed ;
fileref - > fcb - > ea_changed = ofr - > fcb - > ea_changed ;
fileref - > fcb - > prop_compression_changed = ofr - > fcb - > prop_compression_changed ;
fileref - > fcb - > xattrs_changed = ofr - > fcb - > xattrs_changed ;
fileref - > fcb - > created = ofr - > fcb - > created ;
fileref - > fcb - > ads = false ;
if ( fileref - > fcb - > adsxattr . Buffer ) {
ExFreePool ( fileref - > fcb - > adsxattr . Buffer ) ;
fileref - > fcb - > adsxattr . Length = fileref - > fcb - > adsxattr . MaximumLength = 0 ;
fileref - > fcb - > adsxattr . Buffer = NULL ;
}
adsdata = fileref - > fcb - > adsdata ;
fileref - > fcb - > adsdata . Buffer = NULL ;
fileref - > fcb - > adsdata . Length = fileref - > fcb - > adsdata . MaximumLength = 0 ;
InsertHeadList ( ofr - > fcb - > list_entry . Blink , & fileref - > fcb - > list_entry ) ;
if ( fileref - > fcb - > subvol - > fcbs_ptrs [ fileref - > fcb - > hash > > 24 ] = = & ofr - > fcb - > list_entry )
fileref - > fcb - > subvol - > fcbs_ptrs [ fileref - > fcb - > hash > > 24 ] = & fileref - > fcb - > list_entry ;
RemoveEntryList ( & ofr - > fcb - > list_entry ) ;
ofr - > fcb - > list_entry . Flink = ofr - > fcb - > list_entry . Blink = NULL ;
mark_fcb_dirty ( fileref - > fcb ) ;
// mark old parent fcb so it gets ignored by flush_fcb
ofr - > fcb - > created = true ;
ofr - > fcb - > deleted = true ;
mark_fcb_dirty ( ofr - > fcb ) ;
// copy parent fileref onto this one
fileref - > oldutf8 = ofr - > oldutf8 ;
ofr - > oldutf8 . Buffer = NULL ;
ofr - > oldutf8 . Length = ofr - > oldutf8 . MaximumLength = 0 ;
fileref - > oldindex = ofr - > oldindex ;
fileref - > delete_on_close = ofr - > delete_on_close ;
fileref - > posix_delete = ofr - > posix_delete ;
fileref - > deleted = ofr - > deleted ;
fileref - > created = ofr - > created ;
fileref - > parent = ofr - > parent ;
RemoveEntryList ( & fileref - > list_entry ) ;
InsertHeadList ( ofr - > list_entry . Blink , & fileref - > list_entry ) ;
RemoveEntryList ( & ofr - > list_entry ) ;
ofr - > list_entry . Flink = ofr - > list_entry . Blink = NULL ;
while ( ! IsListEmpty ( & ofr - > children ) ) {
file_ref * fr = CONTAINING_RECORD ( RemoveHeadList ( & ofr - > children ) , file_ref , list_entry ) ;
free_fileref ( fr - > parent ) ;
fr - > parent = fileref ;
InterlockedIncrement ( & fileref - > refcount ) ;
InsertTailList ( & fileref - > children , & fr - > list_entry ) ;
}
dc = fileref - > dc ;
fileref - > dc = ofr - > dc ;
fileref - > dc - > fileref = fileref ;
mark_fileref_dirty ( fileref ) ;
// mark old parent fileref so it gets ignored by flush_fileref
ofr - > created = true ;
ofr - > deleted = true ;
// write file data
fileref - > fcb - > inode_item . st_size = adsdata . Length ;
if ( adsdata . Length > 0 ) {
bool make_inline = adsdata . Length < = Vcb - > options . max_inline ;
if ( make_inline ) {
EXTENT_DATA * ed = ExAllocatePoolWithTag ( PagedPool , ( uint16_t ) ( offsetof ( EXTENT_DATA , data [ 0 ] ) + adsdata . Length ) , ALLOC_TAG ) ;
if ( ! ed ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( adsdata . Buffer ) ;
reap_fcb ( dummyfcb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
ed - > generation = Vcb - > superblock . generation ;
ed - > decoded_size = adsdata . Length ;
ed - > compression = BTRFS_COMPRESSION_NONE ;
ed - > encryption = BTRFS_ENCRYPTION_NONE ;
ed - > encoding = BTRFS_ENCODING_NONE ;
ed - > type = EXTENT_TYPE_INLINE ;
RtlCopyMemory ( ed - > data , adsdata . Buffer , adsdata . Length ) ;
ExFreePool ( adsdata . Buffer ) ;
Status = add_extent_to_fcb ( fileref - > fcb , 0 , ed , ( uint16_t ) ( offsetof ( EXTENT_DATA , data [ 0 ] ) + adsdata . Length ) , false , NULL , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " add_extent_to_fcb returned %08x \n " , Status ) ;
ExFreePool ( ed ) ;
reap_fcb ( dummyfcb ) ;
return Status ;
}
ExFreePool ( ed ) ;
} else if ( adsdata . Length % Vcb - > superblock . sector_size ) {
char * newbuf = ExAllocatePoolWithTag ( PagedPool , ( uint16_t ) sector_align ( adsdata . Length , Vcb - > superblock . sector_size ) , ALLOC_TAG ) ;
if ( ! newbuf ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( adsdata . Buffer ) ;
reap_fcb ( dummyfcb ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlCopyMemory ( newbuf , adsdata . Buffer , adsdata . Length ) ;
RtlZeroMemory ( newbuf + adsdata . Length , ( uint16_t ) ( sector_align ( adsdata . Length , Vcb - > superblock . sector_size ) - adsdata . Length ) ) ;
ExFreePool ( adsdata . Buffer ) ;
adsdata . Buffer = newbuf ;
adsdata . Length = adsdata . MaximumLength = ( uint16_t ) sector_align ( adsdata . Length , Vcb - > superblock . sector_size ) ;
}
if ( ! make_inline ) {
Status = do_write_file ( fileref - > fcb , 0 , adsdata . Length , adsdata . Buffer , Irp , false , 0 , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " do_write_file returned %08x \n " , Status ) ;
ExFreePool ( adsdata . Buffer ) ;
reap_fcb ( dummyfcb ) ;
return Status ;
}
ExFreePool ( adsdata . Buffer ) ;
}
fileref - > fcb - > inode_item . st_blocks = adsdata . Length ;
fileref - > fcb - > inode_item_changed = true ;
}
RemoveEntryList ( & dc - > list_entry_index ) ;
if ( dc - > utf8 . Buffer )
ExFreePool ( dc - > utf8 . Buffer ) ;
if ( dc - > name . Buffer )
ExFreePool ( dc - > name . Buffer ) ;
if ( dc - > name_uc . Buffer )
ExFreePool ( dc - > name_uc . Buffer ) ;
ExFreePool ( dc ) ;
// FIXME - csums?
// add dummy deleted xattr with old name
dummyfcb - > Vcb = Vcb ;
dummyfcb - > subvol = fileref - > fcb - > subvol ;
dummyfcb - > inode = fileref - > fcb - > inode ;
dummyfcb - > adsxattr = fileref - > fcb - > adsxattr ;
dummyfcb - > adshash = fileref - > fcb - > adshash ;
dummyfcb - > ads = true ;
dummyfcb - > deleted = true ;
// FIXME - dummyfileref as well?
mark_fcb_dirty ( dummyfcb ) ;
free_fcb ( dummyfcb ) ;
return STATUS_SUCCESS ;
}
static NTSTATUS rename_stream ( device_extension * Vcb , file_ref * fileref , ccb * ccb , FILE_RENAME_INFORMATION_EX * fri ,
ULONG flags , PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
UNICODE_STRING fn ;
file_ref * sf = NULL ;
uint16_t newmaxlen ;
ULONG utf8len ;
ANSI_STRING utf8 ;
UNICODE_STRING utf16 , utf16uc ;
ANSI_STRING adsxattr ;
uint32_t crc32 ;
fcb * dummyfcb ;
static const WCHAR datasuf [ ] = L " :$DATA " ;
static const char xapref [ ] = " user. " ;
if ( ! fileref ) {
ERR ( " fileref not set \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( ! fileref - > parent ) {
ERR ( " fileref->parent not set \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( fri - > FileNameLength < sizeof ( WCHAR ) ) {
WARN ( " filename too short \n " ) ;
return STATUS_OBJECT_NAME_INVALID ;
}
if ( fri - > FileName [ 0 ] ! = ' : ' ) {
WARN ( " destination filename must begin with a colon \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( Irp - > RequestorMode = = UserMode & & ccb & & ! ( ccb - > access & DELETE ) ) {
WARN ( " insufficient permissions \n " ) ;
return STATUS_ACCESS_DENIED ;
}
fn . Buffer = & fri - > FileName [ 1 ] ;
fn . Length = fn . MaximumLength = ( USHORT ) ( fri - > FileNameLength - sizeof ( WCHAR ) ) ;
// remove :$DATA suffix
if ( fn . Length > = sizeof ( datasuf ) - sizeof ( WCHAR ) & &
RtlCompareMemory ( & fn . Buffer [ ( fn . Length - sizeof ( datasuf ) + sizeof ( WCHAR ) ) / sizeof ( WCHAR ) ] , datasuf , sizeof ( datasuf ) - sizeof ( WCHAR ) ) = = sizeof ( datasuf ) - sizeof ( WCHAR ) )
fn . Length - = sizeof ( datasuf ) - sizeof ( WCHAR ) ;
if ( fn . Length = = 0 )
return rename_stream_to_file ( Vcb , fileref , ccb , flags , Irp , rollback ) ;
if ( ! is_file_name_valid ( & fn , false , true ) ) {
WARN ( " invalid stream name %.*S \n " , fn . Length / sizeof ( WCHAR ) , fn . Buffer ) ;
return STATUS_OBJECT_NAME_INVALID ;
}
if ( ! ( flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE ) & & fileref - > parent - > fcb - > atts & FILE_ATTRIBUTE_READONLY ) {
WARN ( " trying to rename stream on readonly file \n " ) ;
return STATUS_ACCESS_DENIED ;
}
Status = open_fileref_child ( Vcb , fileref - > parent , & fn , fileref - > parent - > fcb - > case_sensitive , true , true , PagedPool , & sf , Irp ) ;
if ( Status ! = STATUS_OBJECT_NAME_NOT_FOUND ) {
if ( Status = = STATUS_SUCCESS ) {
if ( fileref = = sf | | sf - > deleted ) {
free_fileref ( sf ) ;
sf = NULL ;
} else {
if ( ! ( flags & FILE_RENAME_REPLACE_IF_EXISTS ) ) {
Status = STATUS_OBJECT_NAME_COLLISION ;
goto end ;
}
// FIXME - POSIX overwrites of stream?
if ( sf - > open_count > 0 ) {
WARN ( " trying to overwrite open file \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
if ( sf - > fcb - > adsdata . Length > 0 ) {
WARN ( " can only overwrite existing stream if it is zero-length \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
Status = delete_fileref ( sf , NULL , false , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref returned %08x \n " , Status ) ;
goto end ;
}
}
} else {
ERR ( " open_fileref_child returned %08x \n " , Status ) ;
goto end ;
}
}
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , fn . Buffer , fn . Length ) ;
if ( ! NT_SUCCESS ( Status ) )
goto end ;
utf8 . MaximumLength = utf8 . Length = ( uint16_t ) utf8len ;
utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 . MaximumLength , ALLOC_TAG ) ;
if ( ! utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
Status = utf16_to_utf8 ( utf8 . Buffer , utf8len , & utf8len , fn . Buffer , fn . Length ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ExFreePool ( utf8 . Buffer ) ;
goto end ;
}
adsxattr . Length = adsxattr . MaximumLength = sizeof ( xapref ) - 1 + utf8 . Length ;
adsxattr . Buffer = ExAllocatePoolWithTag ( PagedPool , adsxattr . MaximumLength , ALLOC_TAG ) ;
if ( ! adsxattr . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
goto end ;
}
RtlCopyMemory ( adsxattr . Buffer , xapref , sizeof ( xapref ) - 1 ) ;
RtlCopyMemory ( & adsxattr . Buffer [ sizeof ( xapref ) - 1 ] , utf8 . Buffer , utf8 . Length ) ;
// don't allow if it's one of our reserved names
if ( ( adsxattr . Length = = sizeof ( EA_DOSATTRIB ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_DOSATTRIB , adsxattr . Length ) = = adsxattr . Length ) | |
( adsxattr . Length = = sizeof ( EA_EA ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_EA , adsxattr . Length ) = = adsxattr . Length ) | |
( adsxattr . Length = = sizeof ( EA_REPARSE ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_REPARSE , adsxattr . Length ) = = adsxattr . Length ) | |
( adsxattr . Length = = sizeof ( EA_CASE_SENSITIVE ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_CASE_SENSITIVE , adsxattr . Length ) = = adsxattr . Length ) ) {
Status = STATUS_OBJECT_NAME_INVALID ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
utf16 . Length = utf16 . MaximumLength = fn . Length ;
utf16 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf16 . MaximumLength , ALLOC_TAG ) ;
if ( ! utf16 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
RtlCopyMemory ( utf16 . Buffer , fn . Buffer , fn . Length ) ;
newmaxlen = Vcb - > superblock . node_size - sizeof ( tree_header ) - sizeof ( leaf_node ) -
offsetof ( DIR_ITEM , name [ 0 ] ) ;
if ( newmaxlen < adsxattr . Length ) {
WARN ( " cannot rename as data too long \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
newmaxlen - = adsxattr . Length ;
if ( newmaxlen < fileref - > fcb - > adsdata . Length ) {
WARN ( " cannot rename as data too long \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
Status = RtlUpcaseUnicodeString ( & utf16uc , & fn , true ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUpcaseUnicodeString returned %08x \n " ) ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
// add dummy deleted xattr with old name
dummyfcb = create_fcb ( Vcb , PagedPool ) ;
if ( ! dummyfcb ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
dummyfcb - > Vcb = Vcb ;
dummyfcb - > subvol = fileref - > fcb - > subvol ;
dummyfcb - > inode = fileref - > fcb - > inode ;
dummyfcb - > adsxattr = fileref - > fcb - > adsxattr ;
dummyfcb - > adshash = fileref - > fcb - > adshash ;
dummyfcb - > ads = true ;
dummyfcb - > deleted = true ;
mark_fcb_dirty ( dummyfcb ) ;
free_fcb ( dummyfcb ) ;
// change fcb values
fileref - > dc - > utf8 = utf8 ;
fileref - > dc - > name = utf16 ;
fileref - > dc - > name_uc = utf16uc ;
crc32 = calc_crc32c ( 0xfffffffe , ( uint8_t * ) adsxattr . Buffer , adsxattr . Length ) ;
fileref - > fcb - > adsxattr = adsxattr ;
fileref - > fcb - > adshash = crc32 ;
fileref - > fcb - > adsmaxlen = newmaxlen ;
fileref - > fcb - > created = true ;
mark_fcb_dirty ( fileref - > fcb ) ;
Status = STATUS_SUCCESS ;
end :
if ( sf )
free_fileref ( sf ) ;
return Status ;
}
static NTSTATUS rename_file_to_stream ( device_extension * Vcb , file_ref * fileref , ccb * ccb , FILE_RENAME_INFORMATION_EX * fri ,
ULONG flags , PIRP Irp , LIST_ENTRY * rollback ) {
NTSTATUS Status ;
UNICODE_STRING fn ;
file_ref * sf = NULL ;
uint16_t newmaxlen ;
ULONG utf8len ;
ANSI_STRING utf8 ;
UNICODE_STRING utf16 , utf16uc ;
ANSI_STRING adsxattr , adsdata ;
uint32_t crc32 ;
fcb * dummyfcb ;
file_ref * dummyfileref ;
dir_child * dc ;
LIST_ENTRY * le ;
static const WCHAR datasuf [ ] = L " :$DATA " ;
static const char xapref [ ] = " user. " ;
if ( ! fileref ) {
ERR ( " fileref not set \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( fri - > FileNameLength < sizeof ( WCHAR ) ) {
WARN ( " filename too short \n " ) ;
return STATUS_OBJECT_NAME_INVALID ;
}
if ( fri - > FileName [ 0 ] ! = ' : ' ) {
WARN ( " destination filename must begin with a colon \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( Irp - > RequestorMode = = UserMode & & ccb & & ! ( ccb - > access & DELETE ) ) {
WARN ( " insufficient permissions \n " ) ;
return STATUS_ACCESS_DENIED ;
}
if ( fileref - > fcb - > type ! = BTRFS_TYPE_FILE )
return STATUS_INVALID_PARAMETER ;
fn . Buffer = & fri - > FileName [ 1 ] ;
fn . Length = fn . MaximumLength = ( USHORT ) ( fri - > FileNameLength - sizeof ( WCHAR ) ) ;
// remove :$DATA suffix
if ( fn . Length > = sizeof ( datasuf ) - sizeof ( WCHAR ) & &
RtlCompareMemory ( & fn . Buffer [ ( fn . Length - sizeof ( datasuf ) + sizeof ( WCHAR ) ) / sizeof ( WCHAR ) ] , datasuf , sizeof ( datasuf ) - sizeof ( WCHAR ) ) = = sizeof ( datasuf ) - sizeof ( WCHAR ) )
fn . Length - = sizeof ( datasuf ) - sizeof ( WCHAR ) ;
if ( fn . Length = = 0 ) {
WARN ( " not allowing overwriting file with itself \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
if ( ! is_file_name_valid ( & fn , false , true ) ) {
WARN ( " invalid stream name %.*S \n " , fn . Length / sizeof ( WCHAR ) , fn . Buffer ) ;
return STATUS_OBJECT_NAME_INVALID ;
}
if ( ! ( flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE ) & & fileref - > fcb - > atts & FILE_ATTRIBUTE_READONLY ) {
WARN ( " trying to rename stream on readonly file \n " ) ;
return STATUS_ACCESS_DENIED ;
}
Status = open_fileref_child ( Vcb , fileref , & fn , fileref - > fcb - > case_sensitive , true , true , PagedPool , & sf , Irp ) ;
if ( Status ! = STATUS_OBJECT_NAME_NOT_FOUND ) {
if ( Status = = STATUS_SUCCESS ) {
if ( fileref = = sf | | sf - > deleted ) {
free_fileref ( sf ) ;
sf = NULL ;
} else {
if ( ! ( flags & FILE_RENAME_REPLACE_IF_EXISTS ) ) {
Status = STATUS_OBJECT_NAME_COLLISION ;
goto end ;
}
// FIXME - POSIX overwrites of stream?
if ( sf - > open_count > 0 ) {
WARN ( " trying to overwrite open file \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
if ( sf - > fcb - > adsdata . Length > 0 ) {
WARN ( " can only overwrite existing stream if it is zero-length \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
Status = delete_fileref ( sf , NULL , false , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref returned %08x \n " , Status ) ;
goto end ;
}
}
} else {
ERR ( " open_fileref_child returned %08x \n " , Status ) ;
goto end ;
}
}
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , fn . Buffer , fn . Length ) ;
if ( ! NT_SUCCESS ( Status ) )
goto end ;
utf8 . MaximumLength = utf8 . Length = ( uint16_t ) utf8len ;
utf8 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf8 . MaximumLength , ALLOC_TAG ) ;
if ( ! utf8 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
Status = utf16_to_utf8 ( utf8 . Buffer , utf8len , & utf8len , fn . Buffer , fn . Length ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ExFreePool ( utf8 . Buffer ) ;
goto end ;
}
adsxattr . Length = adsxattr . MaximumLength = sizeof ( xapref ) - 1 + utf8 . Length ;
adsxattr . Buffer = ExAllocatePoolWithTag ( PagedPool , adsxattr . MaximumLength , ALLOC_TAG ) ;
if ( ! adsxattr . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
goto end ;
}
RtlCopyMemory ( adsxattr . Buffer , xapref , sizeof ( xapref ) - 1 ) ;
RtlCopyMemory ( & adsxattr . Buffer [ sizeof ( xapref ) - 1 ] , utf8 . Buffer , utf8 . Length ) ;
// don't allow if it's one of our reserved names
if ( ( adsxattr . Length = = sizeof ( EA_DOSATTRIB ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_DOSATTRIB , adsxattr . Length ) = = adsxattr . Length ) | |
( adsxattr . Length = = sizeof ( EA_EA ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_EA , adsxattr . Length ) = = adsxattr . Length ) | |
( adsxattr . Length = = sizeof ( EA_REPARSE ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_REPARSE , adsxattr . Length ) = = adsxattr . Length ) | |
( adsxattr . Length = = sizeof ( EA_CASE_SENSITIVE ) - sizeof ( WCHAR ) & & RtlCompareMemory ( adsxattr . Buffer , EA_CASE_SENSITIVE , adsxattr . Length ) = = adsxattr . Length ) ) {
Status = STATUS_OBJECT_NAME_INVALID ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
utf16 . Length = utf16 . MaximumLength = fn . Length ;
utf16 . Buffer = ExAllocatePoolWithTag ( PagedPool , utf16 . MaximumLength , ALLOC_TAG ) ;
if ( ! utf16 . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
RtlCopyMemory ( utf16 . Buffer , fn . Buffer , fn . Length ) ;
newmaxlen = Vcb - > superblock . node_size - sizeof ( tree_header ) - sizeof ( leaf_node ) -
offsetof ( DIR_ITEM , name [ 0 ] ) ;
if ( newmaxlen < adsxattr . Length ) {
WARN ( " cannot rename as data too long \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
newmaxlen - = adsxattr . Length ;
if ( newmaxlen < fileref - > fcb - > inode_item . st_size ) {
WARN ( " cannot rename as data too long \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
Status = RtlUpcaseUnicodeString ( & utf16uc , & fn , true ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlUpcaseUnicodeString returned %08x \n " ) ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
// read existing file data
if ( fileref - > fcb - > inode_item . st_size > 0 ) {
ULONG bytes_read ;
adsdata . Length = adsdata . MaximumLength = ( uint16_t ) fileref - > fcb - > inode_item . st_size ;
adsdata . Buffer = ExAllocatePoolWithTag ( PagedPool , adsdata . MaximumLength , ALLOC_TAG ) ;
if ( ! adsdata . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
goto end ;
}
Status = read_file ( fileref - > fcb , ( uint8_t * ) adsdata . Buffer , 0 , adsdata . Length , & bytes_read , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
ExFreePool ( adsdata . Buffer ) ;
goto end ;
}
if ( bytes_read < fileref - > fcb - > inode_item . st_size ) {
ERR ( " short read \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
ExFreePool ( adsdata . Buffer ) ;
goto end ;
}
} else
adsdata . Buffer = NULL ;
dc = ExAllocatePoolWithTag ( PagedPool , sizeof ( dir_child ) , ALLOC_TAG ) ;
if ( ! dc ) {
ERR ( " short read \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ; ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
if ( adsdata . Buffer )
ExFreePool ( adsdata . Buffer ) ;
goto end ;
}
// add dummy deleted fcb with old name
Status = duplicate_fcb ( fileref - > fcb , & dummyfcb ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " duplicate_fcb returned %08x \n " , Status ) ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
if ( adsdata . Buffer )
ExFreePool ( adsdata . Buffer ) ;
ExFreePool ( dc ) ;
goto end ;
}
dummyfileref = create_fileref ( Vcb ) ;
if ( ! dummyfileref ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
if ( adsdata . Buffer )
ExFreePool ( adsdata . Buffer ) ;
ExFreePool ( dc ) ;
reap_fcb ( dummyfcb ) ;
goto end ;
}
dummyfileref - > fcb = dummyfcb ;
dummyfcb - > Vcb = Vcb ;
dummyfcb - > subvol = fileref - > fcb - > subvol ;
dummyfcb - > inode = fileref - > fcb - > inode ;
dummyfcb - > hash = fileref - > fcb - > hash ;
if ( fileref - > fcb - > inode_item . st_size > 0 ) {
Status = excise_extents ( Vcb , dummyfcb , 0 , sector_align ( fileref - > fcb - > inode_item . st_size , Vcb - > superblock . sector_size ) ,
Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " excise_extents returned %08x \n " , Status ) ;
ExFreePool ( utf8 . Buffer ) ;
ExFreePool ( utf16 . Buffer ) ;
ExFreePool ( utf16uc . Buffer ) ;
ExFreePool ( adsxattr . Buffer ) ;
ExFreePool ( adsdata . Buffer ) ;
ExFreePool ( dc ) ;
reap_fileref ( Vcb , dummyfileref ) ;
reap_fcb ( dummyfcb ) ;
goto end ;
}
dummyfcb - > inode_item . st_size = 0 ;
dummyfcb - > Header . AllocationSize . QuadPart = 0 ;
dummyfcb - > Header . FileSize . QuadPart = 0 ;
dummyfcb - > Header . ValidDataLength . QuadPart = 0 ;
}
dummyfcb - > hash_ptrs = fileref - > fcb - > hash_ptrs ;
dummyfcb - > hash_ptrs_uc = fileref - > fcb - > hash_ptrs_uc ;
dummyfcb - > created = fileref - > fcb - > created ;
le = fileref - > fcb - > extents . Flink ;
while ( le ! = & fileref - > fcb - > extents ) {
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
ext - > ignore = true ;
le = le - > Flink ;
}
while ( ! IsListEmpty ( & fileref - > fcb - > dir_children_index ) ) {
InsertTailList ( & dummyfcb - > dir_children_index , RemoveHeadList ( & fileref - > fcb - > dir_children_index ) ) ;
}
while ( ! IsListEmpty ( & fileref - > fcb - > dir_children_hash ) ) {
InsertTailList ( & dummyfcb - > dir_children_hash , RemoveHeadList ( & fileref - > fcb - > dir_children_hash ) ) ;
}
while ( ! IsListEmpty ( & fileref - > fcb - > dir_children_hash_uc ) ) {
InsertTailList ( & dummyfcb - > dir_children_hash_uc , RemoveHeadList ( & fileref - > fcb - > dir_children_hash_uc ) ) ;
}
InsertTailList ( & Vcb - > all_fcbs , & dummyfcb - > list_entry_all ) ;
InsertHeadList ( fileref - > fcb - > list_entry . Blink , & dummyfcb - > list_entry ) ;
if ( fileref - > fcb - > subvol - > fcbs_ptrs [ dummyfcb - > hash > > 24 ] = = & fileref - > fcb - > list_entry )
fileref - > fcb - > subvol - > fcbs_ptrs [ dummyfcb - > hash > > 24 ] = & dummyfcb - > list_entry ;
RemoveEntryList ( & fileref - > fcb - > list_entry ) ;
fileref - > fcb - > list_entry . Flink = fileref - > fcb - > list_entry . Blink = NULL ;
mark_fcb_dirty ( dummyfcb ) ;
// create dummy fileref
dummyfileref - > oldutf8 = fileref - > oldutf8 ;
dummyfileref - > oldindex = fileref - > oldindex ;
dummyfileref - > delete_on_close = fileref - > delete_on_close ;
dummyfileref - > posix_delete = fileref - > posix_delete ;
dummyfileref - > deleted = fileref - > deleted ;
dummyfileref - > created = fileref - > created ;
dummyfileref - > parent = fileref - > parent ;
while ( ! IsListEmpty ( & fileref - > children ) ) {
file_ref * fr = CONTAINING_RECORD ( RemoveHeadList ( & fileref - > children ) , file_ref , list_entry ) ;
free_fileref ( fr - > parent ) ;
fr - > parent = dummyfileref ;
InterlockedIncrement ( & dummyfileref - > refcount ) ;
InsertTailList ( & dummyfileref - > children , & fr - > list_entry ) ;
}
InsertTailList ( fileref - > list_entry . Blink , & dummyfileref - > list_entry ) ;
RemoveEntryList ( & fileref - > list_entry ) ;
InsertTailList ( & dummyfileref - > children , & fileref - > list_entry ) ;
dummyfileref - > dc = fileref - > dc ;
dummyfileref - > dc - > fileref = dummyfileref ;
mark_fileref_dirty ( dummyfileref ) ;
free_fileref ( dummyfileref ) ;
// change fcb values
fileref - > fcb - > hash_ptrs = NULL ;
fileref - > fcb - > hash_ptrs_uc = NULL ;
fileref - > fcb - > ads = true ;
fileref - > oldutf8 . Length = fileref - > oldutf8 . MaximumLength = 0 ;
fileref - > oldutf8 . Buffer = NULL ;
RtlZeroMemory ( dc , sizeof ( dir_child ) ) ;
dc - > utf8 = utf8 ;
dc - > name = utf16 ;
dc - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name . Buffer , dc - > name . Length ) ;
dc - > name_uc = utf16uc ;
dc - > hash_uc = calc_crc32c ( 0xffffffff , ( uint8_t * ) dc - > name_uc . Buffer , dc - > name_uc . Length ) ;
dc - > fileref = fileref ;
InsertTailList ( & dummyfcb - > dir_children_index , & dc - > list_entry_index ) ;
fileref - > dc = dc ;
fileref - > parent = dummyfileref ;
crc32 = calc_crc32c ( 0xfffffffe , ( uint8_t * ) adsxattr . Buffer , adsxattr . Length ) ;
fileref - > fcb - > adsxattr = adsxattr ;
fileref - > fcb - > adshash = crc32 ;
fileref - > fcb - > adsmaxlen = newmaxlen ;
fileref - > fcb - > adsdata = adsdata ;
fileref - > fcb - > created = true ;
mark_fcb_dirty ( fileref - > fcb ) ;
Status = STATUS_SUCCESS ;
end :
if ( sf )
free_fileref ( sf ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS set_rename_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject , PFILE_OBJECT tfo , bool ex ) {
2019-06-11 10:35:19 +00:00
FILE_RENAME_INFORMATION_EX * fri = Irp - > AssociatedIrp . SystemBuffer ;
2019-11-12 18:32:46 +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 ;
2019-06-11 10:35:19 +00:00
ULONG flags ;
2019-11-12 18:32:46 +00:00
# ifdef __REACTOS__
unsigned int i ;
# endif
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
2019-06-11 10:35:19 +00:00
if ( ex )
flags = fri - > Flags ;
else
flags = fri - > ReplaceIfExists ? FILE_RENAME_REPLACE_IF_EXISTS : 0 ;
2016-07-27 19:24:26 +00:00
TRACE ( " tfo = %p \n " , tfo ) ;
2019-06-11 10:35:19 +00:00
TRACE ( " Flags = %x \n " , flags ) ;
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
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
ExAcquireResourceExclusiveLite ( & Vcb - > fileref_lock , true ) ;
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE & & fcb - > subvol - > id = = BTRFS_ROOT_FSTREE ) {
WARN ( " not allowing \\ $Root to be renamed \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2016-07-27 19:24:26 +00:00
if ( fcb - > ads ) {
2019-11-12 18:32:46 +00:00
if ( FileObject - > SectionObjectPointer & & FileObject - > SectionObjectPointer - > DataSectionObject ) {
IO_STATUS_BLOCK iosb ;
CcFlushCache ( FileObject - > SectionObjectPointer , NULL , 0 , & iosb ) ;
if ( ! NT_SUCCESS ( iosb . Status ) ) {
ERR ( " CcFlushCache returned %08x \n " , iosb . Status ) ;
Status = iosb . Status ;
goto end ;
}
}
Status = rename_stream ( Vcb , fileref , ccb , fri , flags , Irp , & rollback ) ;
goto end ;
} else if ( fnlen > = 1 & & fn [ 0 ] = = ' : ' ) {
if ( FileObject - > SectionObjectPointer & & FileObject - > SectionObjectPointer - > DataSectionObject ) {
IO_STATUS_BLOCK iosb ;
CcFlushCache ( FileObject - > SectionObjectPointer , NULL , 0 , & iosb ) ;
if ( ! NT_SUCCESS ( iosb . Status ) ) {
ERR ( " CcFlushCache returned %08x \n " , iosb . Status ) ;
Status = iosb . Status ;
goto end ;
}
}
Status = rename_file_to_stream ( Vcb , fileref , ccb , fri , flags , Irp , & rollback ) ;
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 ;
2019-09-01 12:53:20 +00:00
fnus . Length = fnus . MaximumLength = ( uint16_t ) ( fnlen * sizeof ( WCHAR ) ) ;
2017-09-08 08:02:43 +00:00
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
2019-11-12 18:32:46 +00:00
# ifndef __REACTOS__
for ( unsigned int i = 0 ; i < fnus . Length / sizeof ( WCHAR ) ; i + + ) {
# else
for ( i = 0 ; i < fnus . Length / sizeof ( WCHAR ) ; i + + ) {
# endif
if ( fnus . Buffer [ i ] = = ' : ' ) {
TRACE ( " colon in filename \n " ) ;
Status = STATUS_OBJECT_NAME_INVALID ;
goto end ;
}
}
2017-09-08 08:02:43 +00:00
origutf8len = fileref - > dc - > utf8 . Length ;
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
utf8 . MaximumLength = utf8 . Length = ( uint16_t ) 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
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( utf8 . Buffer , utf8len , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
2016-03-23 20:35:05 +00:00
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
2019-09-01 12:53:20 +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 ) ) {
2019-11-12 18:32:46 +00:00
TRACE ( " destination file already exists \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref ! = oldfileref & & ! oldfileref - > deleted ) {
2019-06-11 10:35:19 +00:00
if ( ! ( flags & FILE_RENAME_REPLACE_IF_EXISTS ) ) {
2016-03-23 20:35:05 +00:00
Status = STATUS_OBJECT_NAME_COLLISION ;
goto end ;
2019-06-11 10:35:19 +00:00
} else if ( fileref = = oldfileref ) {
Status = STATUS_ACCESS_DENIED ;
goto end ;
} else if ( ! ( flags & FILE_RENAME_POSIX_SEMANTICS ) & & ( oldfileref - > open_count > 0 | | 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 ;
2019-06-11 10:35:19 +00:00
} else if ( ! ( flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE ) & & oldfileref - > fcb - > atts & FILE_ATTRIBUTE_READONLY ) {
WARN ( " trying to overwrite readonly file \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
} else 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 ) {
2019-05-11 09:20:02 +00:00
free_fileref ( 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 ) {
2019-09-01 12:53:20 +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 ) ;
2019-09-01 12:53:20 +00:00
if ( ! SeAccessCheck ( related - > fcb - > sd , & subjcont , false , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE , 0 , NULL ,
2017-09-08 08:02:43 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
if ( ! SeAccessCheck ( oldfileref - > fcb - > sd , & subjcont , false , DELETE , 0 , NULL ,
2016-09-04 15:27:46 +00:00
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
2019-06-11 10:35:19 +00:00
if ( oldfileref - > open_count > 0 & & flags & FILE_RENAME_POSIX_SEMANTICS ) {
2019-09-01 12:53:20 +00:00
oldfileref - > delete_on_close = true ;
oldfileref - > posix_delete = true ;
2019-06-11 10:35:19 +00:00
}
Status = delete_fileref ( oldfileref , NULL , oldfileref - > open_count > 0 & & flags & FILE_RENAME_POSIX_SEMANTICS , 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
2019-09-01 12:53:20 +00:00
oldfn . MaximumLength = ( uint16_t ) reqlen ;
2017-09-08 08:02:43 +00:00
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 ) {
2019-09-01 12:53:20 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & fileref - > dc - > name_uc , & fileref - > dc - > name , true ) ;
2017-09-08 08:02:43 +00:00
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
2019-09-01 12:53:20 +00:00
fileref - > dc - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
fileref - > dc - > hash_uc = calc_crc32c ( 0xffffffff , ( uint8_t * ) 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 ;
}
2019-09-01 12:53:20 +00:00
newfn . MaximumLength = ( uint16_t ) reqlen ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
TRACE ( " related->fcb->inode_item.st_size (inode %I64x) was %I64x \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
related - > fcb - > inode_item . st_size = related - > fcb - > inode_item . st_size + ( 2 * utf8 . Length ) - ( 2 * oldutf8len ) ;
2019-09-01 12:53:20 +00:00
TRACE ( " related->fcb->inode_item.st_size (inode %I64x) now %I64x \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
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
2019-09-01 12:53:20 +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 ;
2019-09-01 12:53:20 +00:00
fr2 - > deleted = true ;
2016-07-27 19:24:26 +00:00
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 ;
2019-09-01 12:53:20 +00:00
fileref - > deleted = false ;
fileref - > created = true ;
2016-07-27 19:24:26 +00:00
fileref - > parent = related ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock , true ) ;
2016-07-27 19:24:26 +00:00
InsertHeadList ( & fileref - > list_entry , & fr2 - > list_entry ) ;
RemoveEntryList ( & fileref - > list_entry ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & fileref - > parent - > fcb - > nonpaged - > dir_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
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fr2 - > parent - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-01-01 17:12:12 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
Status = RtlUpcaseUnicodeString ( & fileref - > dc - > name_uc , & fileref - > dc - > name , true ) ;
2017-09-08 08:02:43 +00:00
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
2019-09-01 12:53:20 +00:00
fileref - > dc - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
fileref - > dc - > hash_uc = calc_crc32c ( 0xffffffff , ( uint8_t * ) fileref - > dc - > name_uc . Buffer , fileref - > dc - > name_uc . Length ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// add to new parent
2019-09-01 12:53:20 +00:00
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
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & related - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
InsertTailList ( & related - > children , & fileref - > list_entry ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & related - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
TRACE ( " related->fcb->inode_item.st_size (inode %I64x) was %I64x \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
related - > fcb - > inode_item . st_size + = 2 * utf8len ;
2019-09-01 12:53:20 +00:00
TRACE ( " related->fcb->inode_item.st_size (inode %I64x) now %I64x \n " , related - > fcb - > inode , related - > fcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
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
2019-09-01 12:53:20 +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 ;
2019-09-01 12:53:20 +00:00
TRACE ( " fr2->parent->fcb->inode_item.st_size (inode %I64x) was %I64x \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 ;
2019-09-01 12:53:20 +00:00
TRACE ( " fr2->parent->fcb->inode_item.st_size (inode %I64x) now %I64x \n " , fr2 - > parent - > fcb - > inode , fr2 - > parent - > fcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
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
2019-05-11 09:20:02 +00:00
free_fileref ( fr2 ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +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 )
2019-05-11 09:20:02 +00:00
free_fileref ( oldfileref ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & related )
2019-05-11 09:20:02 +00:00
free_fileref ( related ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & fr2 )
2019-05-11 09:20:02 +00:00
free_fileref ( fr2 ) ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & Vcb - > fileref_lock ) ;
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 ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS stream_set_end_of_file_information ( device_extension * Vcb , uint16_t 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
2019-09-01 12:53:20 +00:00
TRACE ( " setting new end to %I64x 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
2019-09-01 12:53:20 +00:00
TRACE ( " truncating stream to %I64x 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 ) {
2019-09-01 12:53:20 +00:00
TRACE ( " extending stream to %I64x 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
2019-09-01 12:53:20 +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 ;
}
2019-09-01 12:53:20 +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 ;
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
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 ;
}
2019-09-01 12:53:20 +00:00
Status = stream_set_end_of_file_information ( Vcb , ( uint16_t ) feofi - > EndOfFile . QuadPart , fcb , fileref , advance_only ) ;
2017-09-08 08:02:43 +00:00
if ( NT_SUCCESS ( Status ) ) {
ccfs . AllocationSize = fcb - > Header . AllocationSize ;
ccfs . FileSize = fcb - > Header . FileSize ;
ccfs . ValidDataLength = fcb - > Header . ValidDataLength ;
2019-09-01 12:53:20 +00:00
set_size = true ;
2017-09-08 08:02:43 +00:00
}
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 ;
2019-09-01 12:53:20 +00:00
fileref - > parent - > fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
mark_fcb_dirty ( fileref - > parent - > fcb ) ;
}
2019-11-12 18:32:46 +00:00
queue_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
2019-11-12 18:32:46 +00:00
TRACE ( " file: %p \n " , FileObject ) ;
2019-09-01 12:53:20 +00:00
TRACE ( " paging IO: %s \n " , Irp - > Flags & IRP_PAGING_IO ? " true " : " false " ) ;
TRACE ( " FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x \n " ,
2016-03-23 20:35:05 +00:00
fcb - > Header . AllocationSize . QuadPart , fcb - > Header . FileSize . QuadPart , fcb - > Header . ValidDataLength . QuadPart ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " setting new end to %I64x bytes (currently %I64x) \n " , feofi - > EndOfFile . QuadPart , fcb - > inode_item . st_size ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ( uint64_t ) 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
2019-09-01 12:53:20 +00:00
TRACE ( " truncating file to %I64x 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
}
2019-09-01 12:53:20 +00:00
} else if ( ( uint64_t ) 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
2019-09-01 12:53:20 +00:00
TRACE ( " extending file to %I64x 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
}
2019-09-01 12:53:20 +00:00
} else if ( ( uint64_t ) feofi - > EndOfFile . QuadPart = = fcb - > inode_item . st_size & & advance_only ) {
2018-05-26 08:44:36 +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
ccfs . AllocationSize = fcb - > Header . AllocationSize ;
ccfs . FileSize = fcb - > Header . FileSize ;
ccfs . ValidDataLength = fcb - > Header . ValidDataLength ;
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fcb ) ;
2019-11-12 18:32:46 +00:00
queue_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
2019-11-12 18:32:46 +00:00
TRACE ( " setting the position on %p to %I64x \n " , 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 ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS set_link_information ( device_extension * Vcb , PIRP Irp , PFILE_OBJECT FileObject , PFILE_OBJECT tfo , bool ex ) {
2019-06-11 10:35:19 +00:00
FILE_LINK_INFORMATION_EX * 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 ;
2019-06-11 10:35:19 +00:00
ULONG flags ;
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
2019-06-11 10:35:19 +00:00
if ( ex )
flags = fli - > Flags ;
else
flags = fli - > ReplaceIfExists ? FILE_LINK_REPLACE_IF_EXISTS : 0 ;
TRACE ( " flags = %x \n " , flags ) ;
2016-05-05 17:26:47 +00:00
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
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
ExAcquireResourceExclusiveLite ( & Vcb - > fileref_lock , true ) ;
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 ;
2019-09-01 12:53:20 +00:00
fnus . Length = fnus . MaximumLength = ( uint16_t ) ( fnlen * sizeof ( WCHAR ) ) ;
2017-09-08 08:02:43 +00:00
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
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
utf8 . MaximumLength = utf8 . Length = ( uint16_t ) 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
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( utf8 . Buffer , utf8len , & utf8len , fn , ( ULONG ) fnlen * sizeof ( WCHAR ) ) ;
2016-05-05 17:26:47 +00:00
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
2019-09-01 12:53:20 +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 ) {
2019-11-12 18:32:46 +00:00
WARN ( " destination file already exists \n " ) ;
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
if ( ! ( flags & FILE_LINK_REPLACE_IF_EXISTS ) ) {
2016-05-05 17:26:47 +00:00
Status = STATUS_OBJECT_NAME_COLLISION ;
goto end ;
2019-06-11 10:35:19 +00:00
} else if ( fileref = = oldfileref ) {
Status = STATUS_ACCESS_DENIED ;
goto end ;
} else if ( ! ( flags & FILE_LINK_POSIX_SEMANTICS ) & & ( oldfileref - > open_count > 0 | | has_open_children ( oldfileref ) ) & & ! oldfileref - > deleted ) {
2016-05-05 17:26:47 +00:00
WARN ( " trying to overwrite open file \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
2019-06-11 10:35:19 +00:00
} else if ( ! ( flags & FILE_LINK_IGNORE_READONLY_ATTRIBUTE ) & & oldfileref - > fcb - > atts & FILE_ATTRIBUTE_READONLY ) {
WARN ( " trying to overwrite readonly file \n " ) ;
2016-07-27 19:24:26 +00:00
Status = STATUS_ACCESS_DENIED ;
goto end ;
2019-06-11 10:35:19 +00:00
} else if ( oldfileref - > fcb - > type = = BTRFS_TYPE_DIRECTORY ) {
2016-05-05 17:26:47 +00:00
WARN ( " trying to overwrite directory \n " ) ;
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2016-07-27 19:24:26 +00:00
} else {
2019-05-11 09:20:02 +00:00
free_fileref ( 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 ) {
2019-09-01 12:53:20 +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 ) ;
2019-09-01 12:53:20 +00:00
if ( ! SeAccessCheck ( related - > fcb - > sd , & subjcont , false , FILE_ADD_FILE , 0 , NULL ,
2016-07-27 19:24:26 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
if ( ! SeAccessCheck ( oldfileref - > fcb - > sd , & subjcont , false , DELETE , 0 , NULL ,
2016-07-27 19:24:26 +00:00
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
2019-06-11 10:35:19 +00:00
if ( oldfileref - > open_count > 0 & & flags & FILE_RENAME_POSIX_SEMANTICS ) {
2019-09-01 12:53:20 +00:00
oldfileref - > delete_on_close = true ;
oldfileref - > posix_delete = true ;
2019-06-11 10:35:19 +00:00
}
Status = delete_fileref ( oldfileref , NULL , oldfileref - > open_count > 0 & & flags & FILE_RENAME_POSIX_SEMANTICS , 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
2019-09-01 12:53:20 +00:00
fr2 - > created = true ;
2016-07-27 19:24:26 +00:00
fr2 - > parent = related ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +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 ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & related - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
InsertTailList ( & related - > children , & fr2 - > list_entry ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & related - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( fr2 ) ;
2017-09-08 08:02:43 +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
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
2019-09-01 12:53:20 +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 ;
2019-09-01 12:53:20 +00:00
TRACE ( " parfcb->inode_item.st_size (inode %I64x) was %I64x \n " , parfcb - > inode , parfcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
parfcb - > inode_item . st_size + = 2 * utf8len ;
2019-09-01 12:53:20 +00:00
TRACE ( " parfcb->inode_item.st_size (inode %I64x) now %I64x \n " , parfcb - > inode , parfcb - > inode_item . st_size ) ;
2016-07-27 19:24:26 +00:00
parfcb - > inode_item . sequence + + ;
parfcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +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 )
2019-05-11 09:20:02 +00:00
free_fileref ( oldfileref ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & related )
2019-05-11 09:20:02 +00:00
free_fileref ( related ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & fr2 )
2019-05-11 09:20:02 +00:00
free_fileref ( fr2 ) ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & Vcb - > fileref_lock ) ;
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 ;
2019-09-01 12:53:20 +00:00
bool set_size = false ;
2017-09-08 08:02:43 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
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 ) {
2019-09-01 12:53:20 +00:00
TRACE ( " invalid VDL of %I64u (current VDL = %I64u, file size = %I64u) \n " , fvdli - > ValidDataLength . QuadPart ,
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
set_size = true ;
2017-09-08 08:02:43 +00:00
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 ;
}
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
mark_fcb_dirty ( fcb ) ;
2019-11-12 18:32:46 +00:00
queue_notification_fcb ( fileref , filter , FILE_ACTION_MODIFIED , NULL ) ;
2017-09-08 08:02:43 +00:00
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 ;
}
2019-06-11 10:35:19 +00:00
# ifndef __REACTOS__
static NTSTATUS set_case_sensitive_information ( PIRP Irp ) {
FILE_CASE_SENSITIVE_INFORMATION * fcsi = ( FILE_CASE_SENSITIVE_INFORMATION * ) Irp - > AssociatedIrp . SystemBuffer ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
if ( IrpSp - > Parameters . FileSystemControl . InputBufferLength < sizeof ( FILE_CASE_SENSITIVE_INFORMATION ) )
return STATUS_INFO_LENGTH_MISMATCH ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
if ( ! FileObject )
return STATUS_INVALID_PARAMETER ;
fcb * fcb = FileObject - > FsContext ;
if ( ! fcb )
return STATUS_INVALID_PARAMETER ;
if ( ! ( fcb - > atts & FILE_ATTRIBUTE_DIRECTORY ) ) {
WARN ( " cannot set case-sensitive flag on anything other than directory \n " ) ;
return STATUS_INVALID_PARAMETER ;
}
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & fcb - > Vcb - > tree_lock , true ) ;
2019-06-11 10:35:19 +00:00
fcb - > case_sensitive = fcsi - > Flags & FILE_CS_FLAG_CASE_SENSITIVE_DIR ;
mark_fcb_dirty ( fcb ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
return STATUS_SUCCESS ;
}
# endif
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_SET_INFORMATION )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
NTSTATUS __stdcall 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 ;
2019-09-01 12:53:20 +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 & &
2019-09-02 20:17:17 +00:00
# ifndef __REACTOS__
2019-06-11 10:35:19 +00:00
( fcb - > inode ! = SUBVOL_ROOT_INODE | | ( IrpSp - > Parameters . SetFile . FileInformationClass ! = FileBasicInformation & & IrpSp - > Parameters . SetFile . FileInformationClass ! = FileRenameInformation & & IrpSp - > Parameters . SetFile . FileInformationClass ! = FileRenameInformationEx ) ) ) {
2019-09-02 20:17:17 +00:00
# else
( fcb - > inode ! = SUBVOL_ROOT_INODE | | ( IrpSp - > Parameters . SetFile . FileInformationClass ! = FileBasicInformation & & IrpSp - > Parameters . SetFile . FileInformationClass ! = FileRenameInformation ) ) ) {
# endif
2016-05-05 17:26:47 +00:00
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
Status = STATUS_NOT_IMPLEMENTED ;
TRACE ( " set information \n " ) ;
2019-11-12 18:32:46 +00:00
FsRtlCheckOplock ( fcb_oplock ( fcb ) , Irp , NULL , NULL , NULL ) ;
2016-05-05 17:26:47 +00:00
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
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +00:00
Status = set_disposition_information ( Vcb , Irp , IrpSp - > FileObject , false ) ;
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
2019-09-01 12:53:20 +00:00
Status = set_end_of_file_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . AdvanceOnly , false ) ;
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 FileLinkInformation :
TRACE ( " FileLinkInformation \n " ) ;
2019-09-01 12:53:20 +00:00
Status = set_link_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . FileObject , false ) ;
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 " ) ;
2019-09-01 12:53:20 +00:00
Status = set_rename_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . FileObject , false ) ;
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
}
2019-09-01 12:53:20 +00:00
# ifndef __REACTOS__
2019-06-11 10:35:19 +00:00
# ifndef _MSC_VER
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wswitch"
# endif
case FileDispositionInformationEx :
{
TRACE ( " FileDispositionInformationEx \n " ) ;
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & DELETE ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
break ;
}
2019-09-01 12:53:20 +00:00
Status = set_disposition_information ( Vcb , Irp , IrpSp - > FileObject , true ) ;
2019-06-11 10:35:19 +00:00
break ;
}
case FileRenameInformationEx :
TRACE ( " FileRenameInformationEx \n " ) ;
2019-09-01 12:53:20 +00:00
Status = set_rename_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . FileObject , true ) ;
2019-06-11 10:35:19 +00:00
break ;
case FileLinkInformationEx :
TRACE ( " FileLinkInformationEx \n " ) ;
2019-09-01 12:53:20 +00:00
Status = set_link_information ( Vcb , Irp , IrpSp - > FileObject , IrpSp - > Parameters . SetFile . FileObject , true ) ;
2019-06-11 10:35:19 +00:00
break ;
case FileCaseSensitiveInformation :
TRACE ( " FileCaseSensitiveInformation \n " ) ;
if ( Irp - > RequestorMode = = UserMode & & ! ( ccb - > access & FILE_WRITE_ATTRIBUTES ) ) {
WARN ( " insufficient privileges \n " ) ;
Status = STATUS_ACCESS_DENIED ;
break ;
}
Status = set_case_sensitive_information ( Irp ) ;
break ;
# ifndef _MSC_VER
# pragma GCC diagnostic pop
2019-09-01 12:53:20 +00:00
# endif
2019-06-11 10:35:19 +00:00
# endif
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 ;
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +00:00
TRACE ( " length = %I64u \n " , fsi - > EndOfFile . QuadPart ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +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 ;
2019-09-01 12:53:20 +00:00
bool overflow = false ;
2017-09-08 08:02:43 +00:00
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 )
2019-09-01 12:53:20 +00:00
overflow = true ;
2017-09-08 08:02:43 +00:00
}
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 ;
2019-09-01 12:53:20 +00:00
overflow = true ;
2017-09-08 08:02:43 +00:00
}
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 } ;
2019-09-01 12:53:20 +00:00
uint16_t 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 ;
2019-09-01 12:53:20 +00:00
fn . MaximumLength = ( uint16_t ) * length ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & fileref - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
entry = ( FILE_STREAM_INFORMATION * ) ( ( uint8_t * ) entry + off ) ;
2017-09-08 08:02:43 +00:00
}
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 )
2019-09-01 12:53:20 +00:00
lastentry - > NextEntryOffset = ( uint32_t ) ( ( uint8_t * ) entry - ( uint8_t * ) lastentry ) ;
2017-09-08 08:02:43 +00:00
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 ;
2019-09-01 12:53:20 +00:00
entry = ( FILE_STREAM_INFORMATION * ) ( ( uint8_t * ) 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 ;
2019-09-01 12:53:20 +00:00
fsli - > DeletePending = fileref ? fileref - > delete_on_close : false ;
fsli - > Directory = ( ! fcb - > ads & & fcb - > type = = BTRFS_TYPE_DIRECTORY ) ? true : false ;
2017-09-08 08:02:43 +00:00
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 ;
}
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 ;
2019-09-01 12:53:20 +00:00
bool overflow = false ;
2016-07-27 19:24:26 +00:00
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
2019-09-01 12:53:20 +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 )
2019-09-01 12:53:20 +00:00
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 {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > fileref_lock , true ) ;
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 )
2019-09-01 12:53:20 +00:00
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
2019-09-01 12:53:20 +00:00
TRACE ( " parent %I64x, index %I64x, 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 ;
2019-09-01 12:53:20 +00:00
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 ) {
2019-09-01 12:53:20 +00:00
found = true ;
2017-01-01 17:12:12 +00:00
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 )
2019-09-01 12:53:20 +00:00
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 ) ;
2019-09-01 12:53:20 +00:00
feli = ( FILE_LINK_ENTRY_INFORMATION * ) ( ( uint8_t * ) feli + feli - > NextEntryOffset ) ;
2017-01-01 17:12:12 +00:00
} 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
2019-05-11 09:20:02 +00:00
free_fileref ( 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
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fileref_lock ) ;
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 ;
}
2019-06-11 10:35:19 +00:00
static NTSTATUS fill_in_hard_link_full_id_information ( FILE_LINKS_FULL_ID_INFORMATION * flfii , file_ref * fileref , PIRP Irp , LONG * length ) {
NTSTATUS Status ;
LIST_ENTRY * le ;
LONG bytes_needed ;
FILE_LINK_ENTRY_FULL_ID_INFORMATION * flefii ;
2019-09-01 12:53:20 +00:00
bool overflow = false ;
2019-06-11 10:35:19 +00:00
fcb * fcb = fileref - > fcb ;
ULONG len ;
2016-07-27 19:24:26 +00:00
2019-06-11 10:35:19 +00:00
if ( fcb - > ads )
return STATUS_INVALID_PARAMETER ;
if ( * length < ( LONG ) offsetof ( FILE_LINKS_FULL_ID_INFORMATION , Entry ) )
return STATUS_INVALID_PARAMETER ;
RtlZeroMemory ( flfii , * length ) ;
bytes_needed = offsetof ( FILE_LINKS_FULL_ID_INFORMATION , Entry ) ;
len = bytes_needed ;
flefii = NULL ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( fcb - > Header . Resource , true ) ;
2019-06-11 10:35:19 +00:00
if ( fcb - > inode = = SUBVOL_ROOT_INODE ) {
ULONG namelen ;
if ( fcb = = fcb - > Vcb - > root_fileref - > fcb )
namelen = sizeof ( WCHAR ) ;
else
namelen = fileref - > dc - > name . Length ;
bytes_needed + = offsetof ( FILE_LINK_ENTRY_FULL_ID_INFORMATION , FileName [ 0 ] ) + namelen ;
if ( bytes_needed > * length )
2019-09-01 12:53:20 +00:00
overflow = true ;
2019-06-11 10:35:19 +00:00
if ( ! overflow ) {
flefii = & flfii - > Entry ;
flefii - > NextEntryOffset = 0 ;
if ( fcb = = fcb - > Vcb - > root_fileref - > fcb ) {
RtlZeroMemory ( & flefii - > ParentFileId . Identifier [ 0 ] , sizeof ( FILE_ID_128 ) ) ;
flefii - > FileNameLength = 1 ;
flefii - > FileName [ 0 ] = ' . ' ;
} else {
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & flefii - > ParentFileId . Identifier [ 0 ] , & fileref - > parent - > fcb - > inode , sizeof ( uint64_t ) ) ;
RtlCopyMemory ( & flefii - > ParentFileId . Identifier [ sizeof ( uint64_t ) ] , & fileref - > parent - > fcb - > subvol - > id , sizeof ( uint64_t ) ) ;
2019-06-11 10:35:19 +00:00
flefii - > FileNameLength = fileref - > dc - > name . Length / sizeof ( WCHAR ) ;
RtlCopyMemory ( flefii - > FileName , fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
}
flfii - > EntriesReturned + + ;
len = bytes_needed ;
}
} else {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > fileref_lock , true ) ;
2019-06-11 10:35:19 +00:00
if ( IsListEmpty ( & fcb - > hardlinks ) ) {
bytes_needed + = offsetof ( FILE_LINK_ENTRY_FULL_ID_INFORMATION , FileName [ 0 ] ) + fileref - > dc - > name . Length ;
if ( bytes_needed > * length )
2019-09-01 12:53:20 +00:00
overflow = true ;
2019-06-11 10:35:19 +00:00
if ( ! overflow ) {
flefii = & flfii - > Entry ;
flefii - > NextEntryOffset = 0 ;
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & flefii - > ParentFileId . Identifier [ 0 ] , & fileref - > parent - > fcb - > inode , sizeof ( uint64_t ) ) ;
RtlCopyMemory ( & flefii - > ParentFileId . Identifier [ sizeof ( uint64_t ) ] , & fileref - > parent - > fcb - > subvol - > id , sizeof ( uint64_t ) ) ;
2019-06-11 10:35:19 +00:00
flefii - > FileNameLength = fileref - > dc - > name . Length / sizeof ( WCHAR ) ;
RtlCopyMemory ( flefii - > FileName , fileref - > dc - > name . Buffer , fileref - > dc - > name . Length ) ;
flfii - > EntriesReturned + + ;
len = bytes_needed ;
}
} else {
le = fcb - > hardlinks . Flink ;
while ( le ! = & fcb - > hardlinks ) {
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
file_ref * parfr ;
2019-09-01 12:53:20 +00:00
TRACE ( " parent %I64x, index %I64x, name %.*S \n " , hl - > parent , hl - > index , hl - > name . Length / sizeof ( WCHAR ) , hl - > name . Buffer ) ;
2019-06-11 10:35:19 +00:00
Status = open_fileref_by_inode ( fcb - > Vcb , fcb - > subvol , hl - > parent , & parfr , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " open_fileref_by_inode returned %08x \n " , Status ) ;
} else if ( ! parfr - > deleted ) {
LIST_ENTRY * le2 ;
2019-09-01 12:53:20 +00:00
bool found = false , deleted = false ;
2019-06-11 10:35:19 +00:00
UNICODE_STRING * fn = NULL ;
le2 = parfr - > children . Flink ;
while ( le2 ! = & parfr - > children ) {
file_ref * fr2 = CONTAINING_RECORD ( le2 , file_ref , list_entry ) ;
if ( fr2 - > dc - > index = = hl - > index ) {
2019-09-01 12:53:20 +00:00
found = true ;
2019-06-11 10:35:19 +00:00
deleted = fr2 - > deleted ;
if ( ! deleted )
fn = & fr2 - > dc - > name ;
break ;
}
le2 = le2 - > Flink ;
}
if ( ! found )
fn = & hl - > name ;
if ( ! deleted ) {
TRACE ( " fn = %.*S (found = %u) \n " , fn - > Length / sizeof ( WCHAR ) , fn - > Buffer , found ) ;
if ( flefii )
bytes_needed = ( LONG ) sector_align ( bytes_needed , 8 ) ;
bytes_needed + = offsetof ( FILE_LINK_ENTRY_FULL_ID_INFORMATION , FileName [ 0 ] ) + fn - > Length ;
if ( bytes_needed > * length )
2019-09-01 12:53:20 +00:00
overflow = true ;
2019-06-11 10:35:19 +00:00
if ( ! overflow ) {
if ( flefii ) {
flefii - > NextEntryOffset = ( ULONG ) sector_align ( offsetof ( FILE_LINK_ENTRY_FULL_ID_INFORMATION , FileName [ 0 ] ) + ( flefii - > FileNameLength * sizeof ( WCHAR ) ) , 8 ) ;
2019-09-01 12:53:20 +00:00
flefii = ( FILE_LINK_ENTRY_FULL_ID_INFORMATION * ) ( ( uint8_t * ) flefii + flefii - > NextEntryOffset ) ;
2019-06-11 10:35:19 +00:00
} else
flefii = & flfii - > Entry ;
flefii - > NextEntryOffset = 0 ;
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & flefii - > ParentFileId . Identifier [ 0 ] , & parfr - > fcb - > inode , sizeof ( uint64_t ) ) ;
RtlCopyMemory ( & flefii - > ParentFileId . Identifier [ sizeof ( uint64_t ) ] , & parfr - > fcb - > subvol - > id , sizeof ( uint64_t ) ) ;
2019-06-11 10:35:19 +00:00
flefii - > FileNameLength = fn - > Length / sizeof ( WCHAR ) ;
RtlCopyMemory ( flefii - > FileName , fn - > Buffer , fn - > Length ) ;
flfii - > EntriesReturned + + ;
len = bytes_needed ;
}
}
free_fileref ( parfr ) ;
}
le = le - > Flink ;
}
}
ExReleaseResourceLite ( & fcb - > Vcb - > fileref_lock ) ;
}
flfii - > BytesNeeded = bytes_needed ;
* length - = len ;
Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
return Status ;
}
2016-07-27 19:24:26 +00:00
static NTSTATUS fill_in_file_id_information ( FILE_ID_INFORMATION * fii , fcb * fcb , LONG * length ) {
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & fii - > VolumeSerialNumber , & fcb - > Vcb - > superblock . uuid . uuid [ 8 ] , sizeof ( uint64_t ) ) ;
RtlCopyMemory ( & fii - > FileId . Identifier [ 0 ] , & fcb - > inode , sizeof ( uint64_t ) ) ;
RtlCopyMemory ( & fii - > FileId . Identifier [ sizeof ( uint64_t ) ] , & fcb - > subvol - > id , sizeof ( uint64_t ) ) ;
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 ;
}
2019-06-11 10:35:19 +00:00
static NTSTATUS fill_in_file_stat_information ( FILE_STAT_INFORMATION * fsi , fcb * fcb , ccb * ccb , LONG * length ) {
INODE_ITEM * ii ;
2019-09-01 12:53:20 +00:00
fsi - > FileId . LowPart = ( uint32_t ) fcb - > inode ;
fsi - > FileId . HighPart = ( uint32_t ) fcb - > subvol - > id ;
2019-06-11 10:35:19 +00:00
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 ) ;
fsi - > CreationTime = fsi - > LastAccessTime = fsi - > LastWriteTime = fsi - > ChangeTime = time ;
} else {
fsi - > CreationTime . QuadPart = unix_time_to_win ( & ii - > otime ) ;
fsi - > LastAccessTime . QuadPart = unix_time_to_win ( & ii - > st_atime ) ;
fsi - > LastWriteTime . QuadPart = unix_time_to_win ( & ii - > st_mtime ) ;
fsi - > ChangeTime . QuadPart = unix_time_to_win ( & ii - > st_ctime ) ;
}
if ( fcb - > ads ) {
fsi - > AllocationSize . QuadPart = fsi - > EndOfFile . QuadPart = fcb - > adsdata . Length ;
fsi - > FileAttributes = ccb - > fileref - > parent - > fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : ccb - > fileref - > parent - > fcb - > atts ;
} else {
fsi - > AllocationSize . QuadPart = fcb_alloc_size ( fcb ) ;
fsi - > EndOfFile . QuadPart = S_ISDIR ( fcb - > inode_item . st_mode ) ? 0 : fcb - > inode_item . st_size ;
fsi - > FileAttributes = fcb - > atts = = 0 ? FILE_ATTRIBUTE_NORMAL : fcb - > atts ;
}
if ( fcb - > type = = BTRFS_TYPE_SOCKET )
fsi - > ReparseTag = IO_REPARSE_TAG_LXSS_SOCKET ;
else if ( fcb - > type = = BTRFS_TYPE_FIFO )
fsi - > ReparseTag = IO_REPARSE_TAG_LXSS_FIFO ;
else if ( fcb - > type = = BTRFS_TYPE_CHARDEV )
fsi - > ReparseTag = IO_REPARSE_TAG_LXSS_CHARDEV ;
else if ( fcb - > type = = BTRFS_TYPE_BLOCKDEV )
fsi - > ReparseTag = IO_REPARSE_TAG_LXSS_BLOCKDEV ;
else if ( ! ( fsi - > FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) )
fsi - > ReparseTag = 0 ;
else
fsi - > 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 )
fsi - > FileAttributes | = FILE_ATTRIBUTE_REPARSE_POINT ;
if ( fcb - > ads )
fsi - > NumberOfLinks = ccb - > fileref - > parent - > fcb - > inode_item . st_nlink ;
else
fsi - > NumberOfLinks = fcb - > inode_item . st_nlink ;
fsi - > EffectiveAccess = ccb - > access ;
* length - = sizeof ( FILE_STAT_INFORMATION ) ;
return STATUS_SUCCESS ;
}
2018-12-16 11:03:16 +00:00
static NTSTATUS fill_in_file_stat_lx_information ( FILE_STAT_LX_INFORMATION * fsli , fcb * fcb , ccb * ccb , LONG * length ) {
INODE_ITEM * ii ;
2019-09-01 12:53:20 +00:00
fsli - > FileId . LowPart = ( uint32_t ) fcb - > inode ;
fsli - > FileId . HighPart = ( uint32_t ) fcb - > subvol - > id ;
2018-12-16 11:03:16 +00:00
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 ;
2019-06-11 10:35:19 +00:00
fsli - > LxFlags = LX_FILE_METADATA_HAS_UID | LX_FILE_METADATA_HAS_GID | LX_FILE_METADATA_HAS_MODE | LX_FILE_METADATA_HAS_DEVICE_ID ;
if ( fcb - > case_sensitive )
fsli - > LxFlags | = LX_FILE_CASE_SENSITIVE_DIR ;
2018-12-16 11:03:16 +00:00
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 ;
}
2019-06-11 10:35:19 +00:00
static NTSTATUS fill_in_file_case_sensitive_information ( FILE_CASE_SENSITIVE_INFORMATION * fcsi , fcb * fcb , LONG * length ) {
fcsi - > Flags = fcb - > case_sensitive ? FILE_CS_FLAG_CASE_SENSITIVE_DIR : 0 ;
* length - = sizeof ( FILE_CASE_SENSITIVE_INFORMATION ) ;
return STATUS_SUCCESS ;
}
2018-12-16 11:03:16 +00:00
# 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
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +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 ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
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 ;
2016-07-27 19:24:26 +00:00
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
2019-06-11 10:35:19 +00:00
case FileStatInformation :
{
FILE_STAT_INFORMATION * fsi = Irp - > AssociatedIrp . SystemBuffer ;
if ( IrpSp - > Parameters . QueryFile . Length < sizeof ( FILE_STAT_LX_INFORMATION ) ) {
WARN ( " overflow \n " ) ;
Status = STATUS_BUFFER_OVERFLOW ;
goto exit ;
}
TRACE ( " FileStatInformation \n " ) ;
Status = fill_in_file_stat_information ( fsi , fcb , ccb , & length ) ;
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 ;
}
2019-06-11 10:35:19 +00:00
case FileCaseSensitiveInformation :
{
FILE_CASE_SENSITIVE_INFORMATION * fcsi = Irp - > AssociatedIrp . SystemBuffer ;
if ( IrpSp - > Parameters . QueryFile . Length < sizeof ( FILE_CASE_SENSITIVE_INFORMATION ) ) {
WARN ( " overflow \n " ) ;
Status = STATUS_BUFFER_OVERFLOW ;
goto exit ;
}
TRACE ( " FileCaseSensitiveInformation \n " ) ;
Status = fill_in_file_case_sensitive_information ( fcsi , fcb , & length ) ;
break ;
}
case FileHardLinkFullIdInformation :
{
FILE_LINKS_FULL_ID_INFORMATION * flfii = Irp - > AssociatedIrp . SystemBuffer ;
TRACE ( " FileHardLinkFullIdInformation \n " ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
2019-06-11 10:35:19 +00:00
Status = fill_in_hard_link_full_id_information ( flfii , fileref , Irp , & length ) ;
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
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 )
2019-09-01 12:53:20 +00:00
NTSTATUS __stdcall 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 ;
2019-09-01 12:53:20 +00:00
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 )
2019-09-01 12:53:20 +00:00
NTSTATUS __stdcall drv_query_ea ( IN PDEVICE_OBJECT DeviceObject , IN PIRP Irp ) {
2016-10-29 17:05:10 +00:00
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-10-29 17:05:10 +00:00
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 ;
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +00:00
in = ( FILE_GET_EA_INFORMATION * ) ( ( ( uint8_t * ) 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 {
2019-09-01 12:53:20 +00:00
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 ) {
2019-09-01 12:53:20 +00:00
found = true ;
2016-10-29 17:05:10 +00:00
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
2019-09-01 12:53:20 +00:00
in = ( FILE_GET_EA_INFORMATION * ) ( ( ( uint8_t * ) in ) + in - > NextEntryOffset ) ;
} while ( true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( found ) {
2019-09-01 12:53:20 +00:00
uint8_t 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 ;
2019-09-01 12:53:20 +00:00
out = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) out ) + out - > NextEntryOffset ) ;
2016-10-29 17:05:10 +00:00
} 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
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ea ) + ea - > NextEntryOffset ) ;
} while ( true ) ;
2016-10-29 17:05:10 +00:00
} 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
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ea ) + ea - > NextEntryOffset ) ;
2016-10-29 17:05:10 +00:00
}
}
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 {
2019-09-01 12:53:20 +00:00
uint8_t 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 ;
2019-09-01 12:53:20 +00:00
out = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) out ) + out - > NextEntryOffset ) ;
2016-10-29 17:05:10 +00:00
} 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
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ea ) + ea - > NextEntryOffset ) ;
} while ( true ) ;
2016-10-29 17:05:10 +00:00
}
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 )
2019-09-01 12:53:20 +00:00
NTSTATUS __stdcall 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 ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-10-29 17:05:10 +00:00
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
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ea ) + ea - > NextEntryOffset ) ;
} while ( true ) ;
2016-10-29 17:05:10 +00:00
}
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 ;
2019-09-01 12:53:20 +00:00
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 ] ;
2019-09-01 12:53:20 +00:00
found = true ;
2016-10-29 17:05:10 +00:00
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
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) 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 ) {
2019-09-01 12:53:20 +00:00
if ( item - > value . Length < sizeof ( uint32_t ) ) {
2018-12-16 11:03:16 +00:00
ERR ( " uid value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end2 ;
}
if ( Irp - > RequestorMode = = KernelMode ) {
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & fcb - > inode_item . st_uid , item - > value . Buffer , sizeof ( uint32_t ) ) ;
fcb - > sd_dirty = true ;
fcb - > sd_deleted = false ;
2018-12-16 11:03:16 +00:00
}
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
} else if ( item - > name . Length = = sizeof ( lxgid ) - 1 & & RtlCompareMemory ( item - > name . Buffer , lxgid , item - > name . Length ) = = item - > name . Length ) {
2019-09-01 12:53:20 +00:00
if ( item - > value . Length < sizeof ( uint32_t ) ) {
2018-12-16 11:03:16 +00:00
ERR ( " gid value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end2 ;
}
if ( Irp - > RequestorMode = = KernelMode )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & fcb - > inode_item . st_gid , item - > value . Buffer , sizeof ( uint32_t ) ) ;
2018-12-16 11:03:16 +00:00
RemoveEntryList ( & item - > list_entry ) ;
ExFreePool ( item ) ;
} else if ( item - > name . Length = = sizeof ( lxmod ) - 1 & & RtlCompareMemory ( item - > name . Buffer , lxmod , item - > name . Length ) = = item - > name . Length ) {
2019-09-01 12:53:20 +00:00
if ( item - > value . Length < sizeof ( uint32_t ) ) {
2018-12-16 11:03:16 +00:00
ERR ( " mode value was shorter than expected \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto end2 ;
}
if ( Irp - > RequestorMode = = KernelMode ) {
2019-09-01 12:53:20 +00:00
uint32_t allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID ;
uint32_t val ;
2018-12-16 11:03:16 +00:00
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( & val , item - > value . Buffer , sizeof ( uint32_t ) ) ;
2018-12-16 11:03:16 +00:00
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 {
2019-09-01 12:53:20 +00:00
uint16_t 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
2019-09-01 12:53:20 +00:00
size + = ( uint16_t ) offsetof ( FILE_FULL_EA_INFORMATION , EaName [ 0 ] ) + item - > name . Length + 1 + item - > value . Length ;
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
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
2019-09-01 12:53:20 +00:00
ea = ( FILE_FULL_EA_INFORMATION * ) ( ( ( uint8_t * ) ea ) + ea - > NextEntryOffset ) ;
2016-10-29 17:05:10 +00:00
} 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
2019-09-01 12:53:20 +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
2019-09-01 12:53:20 +00:00
fcb - > inode_item_changed = true ;
2016-10-29 17:05:10 +00:00
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 ;
}