https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f381137c89da4ff272e939bedb91c34262369846
commit f381137c89da4ff272e939bedb91c34262369846 Author: Pierre Schweitzer <pie...@reactos.org> AuthorDate: Tue Jun 11 12:35:19 2019 +0200 Commit: Pierre Schweitzer <pie...@reactos.org> CommitDate: Tue Jun 11 12:35:19 2019 +0200 [BTRFS] Upgrade to 1.3 CORE-16111 --- dll/win32/ubtrfs/ubtrfs.rc | 24 +- drivers/filesystems/btrfs/btrfs.c | 166 ++++++--- drivers/filesystems/btrfs/btrfs.h | 3 + drivers/filesystems/btrfs/btrfs.rc | 8 +- drivers/filesystems/btrfs/btrfs_drv.h | 23 +- drivers/filesystems/btrfs/create.c | 269 ++++++++++++-- drivers/filesystems/btrfs/dirctrl.c | 158 +++++++- drivers/filesystems/btrfs/fileinfo.c | 630 +++++++++++++++++++++++++++++--- drivers/filesystems/btrfs/flushthread.c | 196 +++++++++- drivers/filesystems/btrfs/free-space.c | 4 +- drivers/filesystems/btrfs/fsctl.c | 10 +- drivers/filesystems/btrfs/write.c | 2 +- media/doc/README.FSD | 4 +- 13 files changed, 1344 insertions(+), 153 deletions(-) diff --git a/dll/win32/ubtrfs/ubtrfs.rc b/dll/win32/ubtrfs/ubtrfs.rc index c4c486f92af..2fbce14c1f1 100644 --- a/dll/win32/ubtrfs/ubtrfs.rc +++ b/dll/win32/ubtrfs/ubtrfs.rc @@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK // TEXTINCLUDE // -1 TEXTINCLUDE +1 TEXTINCLUDE BEGIN "resource.h\0" END -2 TEXTINCLUDE +2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END -3 TEXTINCLUDE +3 TEXTINCLUDE BEGIN "\r\n" "\0" @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,0,0 - PRODUCTVERSION 1,1,0,0 + FILEVERSION 1,3,0,0 + PRODUCTVERSION 1,3,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -60,20 +60,20 @@ VS_VERSION_INFO VERSIONINFO FILEFLAGS 0x0L #endif FILEOS 0x4L - FILETYPE 0x0L + FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "080904b0" BEGIN - VALUE "FileDescription", "Btrfs formatting utility" - VALUE "FileVersion", "1.1" - VALUE "InternalName", "mkbtrfs" - VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-18" - VALUE "OriginalFilename", "mkbtrfs.exe" + VALUE "FileDescription", "Btrfs utility DLL" + VALUE "FileVersion", "1.3" + VALUE "InternalName", "ubtrfs" + VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19" + VALUE "OriginalFilename", "ubtrfs.dll" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.1" + VALUE "ProductVersion", "1.3" END END BLOCK "VarFileInfo" diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c index 4cd6bb10a10..c480d9f0502 100644 --- a/drivers/filesystems/btrfs/btrfs.c +++ b/drivers/filesystems/btrfs/btrfs.c @@ -795,7 +795,8 @@ static NTSTATUS drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _ data->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH | FILE_UNICODE_ON_DISK | FILE_NAMED_STREAMS | FILE_SUPPORTS_HARD_LINKS | FILE_PERSISTENT_ACLS | FILE_SUPPORTS_REPARSE_POINTS | FILE_SUPPORTS_SPARSE_FILES | FILE_SUPPORTS_OBJECT_IDS | - FILE_SUPPORTS_OPEN_BY_FILE_ID | FILE_SUPPORTS_EXTENDED_ATTRIBUTES | FILE_SUPPORTS_BLOCK_REFCOUNTING; + FILE_SUPPORTS_OPEN_BY_FILE_ID | FILE_SUPPORTS_EXTENDED_ATTRIBUTES | FILE_SUPPORTS_BLOCK_REFCOUNTING | + FILE_SUPPORTS_POSIX_UNLINK_RENAME; if (Vcb->readonly) data->FileSystemAttributes |= FILE_READ_ONLY_VOLUME; @@ -1068,6 +1069,7 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM)); r->root_item.num_references = 1; r->fcbs_version = 0; + r->checked_for_orphans = TRUE; InitializeListHead(&r->fcbs); RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256); @@ -1966,7 +1968,63 @@ void uninit(_In_ device_extension* Vcb) { ZwClose(Vcb->flush_thread_handle); } -NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) { +static NTSTATUS delete_fileref_fcb(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) { + NTSTATUS Status; + LIST_ENTRY* le; + + // excise extents + + if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) { + Status = excise_extents(fileref->fcb->Vcb, fileref->fcb, 0, sector_align(fileref->fcb->inode_item.st_size, fileref->fcb->Vcb->superblock.sector_size), Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("excise_extents returned %08x\n", Status); + return Status; + } + } + + fileref->fcb->Header.AllocationSize.QuadPart = 0; + fileref->fcb->Header.FileSize.QuadPart = 0; + fileref->fcb->Header.ValidDataLength.QuadPart = 0; + + if (FileObject) { + CC_FILE_SIZES ccfs; + + ccfs.AllocationSize = fileref->fcb->Header.AllocationSize; + ccfs.FileSize = fileref->fcb->Header.FileSize; + ccfs.ValidDataLength = fileref->fcb->Header.ValidDataLength; + + Status = STATUS_SUCCESS; + + _SEH2_TRY { + CcSetFileSizes(FileObject, &ccfs); + } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { + Status = _SEH2_GetExceptionCode(); + } _SEH2_END; + + if (!NT_SUCCESS(Status)) { + ERR("CcSetFileSizes threw exception %08x\n", Status); + return Status; + } + } + + fileref->fcb->deleted = TRUE; + + le = fileref->children.Flink; + while (le != &fileref->children) { + file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry); + + if (fr2->fcb->ads) { + fr2->fcb->deleted = TRUE; + mark_fcb_dirty(fr2->fcb); + } + + le = le->Flink; + } + + return STATUS_SUCCESS; +} + +NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_ BOOL make_orphan, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) { LARGE_INTEGER newlength, time; BTRFS_TIME now; NTSTATUS Status; @@ -2002,61 +2060,17 @@ NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject fileref->fcb->inode_item_changed = TRUE; - if (fileref->fcb->inode_item.st_nlink > 1) { + if (fileref->fcb->inode_item.st_nlink > 1 || make_orphan) { fileref->fcb->inode_item.st_nlink--; fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation; fileref->fcb->inode_item.sequence++; fileref->fcb->inode_item.st_ctime = now; } else { - // excise extents - - if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) { - Status = excise_extents(fileref->fcb->Vcb, fileref->fcb, 0, sector_align(fileref->fcb->inode_item.st_size, fileref->fcb->Vcb->superblock.sector_size), Irp, rollback); - if (!NT_SUCCESS(Status)) { - ERR("excise_extents returned %08x\n", Status); - ExReleaseResourceLite(fileref->fcb->Header.Resource); - return Status; - } - } - - fileref->fcb->Header.AllocationSize.QuadPart = 0; - fileref->fcb->Header.FileSize.QuadPart = 0; - fileref->fcb->Header.ValidDataLength.QuadPart = 0; - - if (FileObject) { - CC_FILE_SIZES ccfs; - - ccfs.AllocationSize = fileref->fcb->Header.AllocationSize; - ccfs.FileSize = fileref->fcb->Header.FileSize; - ccfs.ValidDataLength = fileref->fcb->Header.ValidDataLength; - - Status = STATUS_SUCCESS; - - _SEH2_TRY { - CcSetFileSizes(FileObject, &ccfs); - } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { - Status = _SEH2_GetExceptionCode(); - } _SEH2_END; - - if (!NT_SUCCESS(Status)) { - ERR("CcSetFileSizes threw exception %08x\n", Status); - ExReleaseResourceLite(fileref->fcb->Header.Resource); - return Status; - } - } - - fileref->fcb->deleted = TRUE; - - le = fileref->children.Flink; - while (le != &fileref->children) { - file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry); - - if (fr2->fcb->ads) { - fr2->fcb->deleted = TRUE; - mark_fcb_dirty(fr2->fcb); - } - - le = le->Flink; + Status = delete_fileref_fcb(fileref, FileObject, Irp, rollback); + if (!NT_SUCCESS(Status)) { + ERR("delete_fileref_fcb returned %08x\n", Status); + ExReleaseResourceLite(fileref->fcb->Header.Resource); + return Status; } } @@ -2271,9 +2285,26 @@ static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { // FIXME - flush all of subvol's fcbs } - if (fileref && oc == 0) { + if (fileref && (oc == 0 || (fileref->delete_on_close && fileref->posix_delete))) { if (!fcb->Vcb->removing) { - if (fileref && fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) { + if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0 && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) { // last handle closed on POSIX-deleted file + LIST_ENTRY rollback; + + InitializeListHead(&rollback); + + Status = delete_fileref_fcb(fileref, FileObject, Irp, &rollback); + if (!NT_SUCCESS(Status)) { + ERR("delete_fileref_fcb returned %08x\n", Status); + do_rollback(fcb->Vcb, &rollback); + ExReleaseResourceLite(fileref->fcb->Header.Resource); + ExReleaseResourceLite(&fcb->Vcb->tree_lock); + goto exit; + } + + clear_rollback(&rollback); + + mark_fcb_dirty(fileref->fcb); + } else if (fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) { LIST_ENTRY rollback; InitializeListHead(&rollback); @@ -2292,7 +2323,7 @@ static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { // fileref_lock needs to be acquired before fcb->Header.Resource ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE); - Status = delete_fileref(fileref, FileObject, Irp, &rollback); + Status = delete_fileref(fileref, FileObject, oc > 0 && fileref->posix_delete, Irp, &rollback); if (!NT_SUCCESS(Status)) { ERR("delete_fileref returned %08x\n", Status); do_rollback(fcb->Vcb, &rollback); @@ -2677,6 +2708,7 @@ static NTSTATUS add_root(_Inout_ device_extension* Vcb, _In_ UINT64 id, _In_ UIN r->parent = 0; r->send_ops = 0; r->fcbs_version = 0; + r->checked_for_orphans = FALSE; InitializeListHead(&r->fcbs); RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256); @@ -3530,6 +3562,26 @@ void protect_superblocks(_Inout_ chunk* c) { } } +UINT64 chunk_estimate_phys_size(device_extension* Vcb, chunk* c, UINT64 u) { + UINT64 nfactor, dfactor; + + if (c->chunk_item->type & BLOCK_FLAG_DUPLICATE || c->chunk_item->type & BLOCK_FLAG_RAID1 || c->chunk_item->type & BLOCK_FLAG_RAID10) { + nfactor = 1; + dfactor = 2; + } else if (c->chunk_item->type & BLOCK_FLAG_RAID5) { + nfactor = Vcb->superblock.num_devices - 1; + dfactor = Vcb->superblock.num_devices; + } else if (c->chunk_item->type & BLOCK_FLAG_RAID6) { + nfactor = Vcb->superblock.num_devices - 2; + dfactor = Vcb->superblock.num_devices; + } else { + nfactor = 1; + dfactor = 1; + } + + return u * dfactor / nfactor; +} + NTSTATUS find_chunk_usage(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { LIST_ENTRY* le = Vcb->chunks.Flink; chunk* c; @@ -3540,6 +3592,8 @@ NTSTATUS find_chunk_usage(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_ex searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM; + Vcb->superblock.bytes_used = 0; + while (le != &Vcb->chunks) { c = CONTAINING_RECORD(le, chunk, list_entry); @@ -3559,6 +3613,8 @@ NTSTATUS find_chunk_usage(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_ex c->used = c->oldused = bgi->used; TRACE("chunk %llx has %llx bytes used\n", c->offset, c->used); + + Vcb->superblock.bytes_used += chunk_estimate_phys_size(Vcb, c, bgi->used); } else { ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n", Vcb->extent_root->id, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(BLOCK_GROUP_ITEM)); diff --git a/drivers/filesystems/btrfs/btrfs.h b/drivers/filesystems/btrfs/btrfs.h index eede4059854..d0d2c933d42 100644 --- a/drivers/filesystems/btrfs/btrfs.h +++ b/drivers/filesystems/btrfs/btrfs.h @@ -19,6 +19,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4 #define TYPE_INODE_REF 0x0C #define TYPE_INODE_EXTREF 0x0D #define TYPE_XATTR_ITEM 0x18 +#define TYPE_ORPHAN_INODE 0x30 #define TYPE_DIR_ITEM 0x54 #define TYPE_DIR_INDEX 0x60 #define TYPE_EXTENT_DATA 0x6C @@ -113,6 +114,8 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0x4 #define BTRFS_SUPERBLOCK_FLAGS_SEEDING 0x100000000 +#define BTRFS_ORPHAN_INODE_OBJID 0xFFFFFFFFFFFFFFFB + #pragma pack(push, 1) typedef struct { diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc index d10323e56c3..da8380e5562 100644 --- a/drivers/filesystems/btrfs/btrfs.rc +++ b/drivers/filesystems/btrfs/btrfs.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,2,1,0 - PRODUCTVERSION 1,2,1,0 + FILEVERSION 1,3,0,0 + PRODUCTVERSION 1,3,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BLOCK "080904b0" BEGIN VALUE "FileDescription", "WinBtrfs" - VALUE "FileVersion", "1.2.1" + VALUE "FileVersion", "1.3" VALUE "InternalName", "btrfs" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19" VALUE "OriginalFilename", "btrfs.sys" VALUE "ProductName", "WinBtrfs" - VALUE "ProductVersion", "1.2.1" + VALUE "ProductVersion", "1.3" END END BLOCK "VarFileInfo" diff --git a/drivers/filesystems/btrfs/btrfs_drv.h b/drivers/filesystems/btrfs/btrfs_drv.h index b41c9794d30..b5d1cd2e4f0 100644 --- a/drivers/filesystems/btrfs/btrfs_drv.h +++ b/drivers/filesystems/btrfs/btrfs_drv.h @@ -101,6 +101,9 @@ #define EA_EA "user.EA" #define EA_EA_HASH 0x8270dd43 +#define EA_CASE_SENSITIVE "user.casesensitive" +#define EA_CASE_SENSITIVE_HASH 0x1a9d97d4 + #define EA_PROP_COMPRESSION "btrfs.compression" #define EA_PROP_COMPRESSION_HASH 0x20ccdf69 @@ -132,10 +135,20 @@ #define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 #endif +#ifndef FILE_SUPPORTS_POSIX_UNLINK_RENAME +#define FILE_SUPPORTS_POSIX_UNLINK_RENAME 0x00000400 +#endif + #ifndef FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL #define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000 #endif +#ifndef _MSC_VER +typedef struct _FILE_ID_128 { + UCHAR Identifier[16]; +} FILE_ID_128, *PFILE_ID_128; +#endif + typedef struct _DUPLICATE_EXTENTS_DATA { HANDLE FileHandle; LARGE_INTEGER SourceFileOffset; @@ -280,6 +293,9 @@ typedef struct _fcb { BOOL inode_item_changed; enum prop_compression_type prop_compression; LIST_ENTRY xattrs; + BOOL marked_as_orphan; + BOOL case_sensitive; + BOOL case_sensitive_set; LIST_ENTRY dir_children_index; LIST_ENTRY dir_children_hash; @@ -317,6 +333,7 @@ typedef struct _file_ref { ANSI_STRING oldutf8; UINT64 oldindex; BOOL delete_on_close; + BOOL posix_delete; BOOL deleted; BOOL created; file_ref_nonpaged* nonpaged; @@ -434,6 +451,7 @@ typedef struct _root { UINT64 parent; LONG send_ops; UINT64 fcbs_version; + BOOL checked_for_orphans; LIST_ENTRY fcbs; LIST_ENTRY* fcbs_ptrs[256]; LIST_ENTRY list_entry; @@ -1123,7 +1141,7 @@ WCHAR* file_desc(_In_ PFILE_OBJECT FileObject); WCHAR* file_desc_fileref(_In_ file_ref* fileref); void mark_fcb_dirty(_In_ fcb* fcb); void mark_fileref_dirty(_In_ file_ref* fileref); -NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback); +NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_ BOOL make_orphan, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback); void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length); void chunk_unlock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length); void init_device(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ BOOL get_nums); @@ -1142,6 +1160,7 @@ void reap_fcb(fcb* fcb); void reap_fcbs(device_extension* Vcb); void reap_fileref(device_extension* Vcb, file_ref* fr); void reap_filerefs(device_extension* Vcb, file_ref* fr); +UINT64 chunk_estimate_phys_size(device_extension* Vcb, chunk* c, UINT64 u); #ifdef _MSC_VER #define funcname __FUNCTION__ @@ -1412,7 +1431,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv _In_ PUNICODE_STRING fnus, _In_opt_ file_ref* related, _In_ BOOL parent, _Out_opt_ USHORT* parsed, _Out_opt_ ULONG* fn_offset, _In_ POOL_TYPE pooltype, _In_ BOOL case_sensitive, _In_opt_ PIRP Irp); NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb, - root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp); + root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, BOOL always_add_hl, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp); NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length, PIRP Irp); NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, fcb* fcb, BOOL ignore_size, PIRP Irp); NTSTATUS add_dir_child(fcb* fcb, UINT64 inode, BOOL subvol, PANSI_STRING utf8, PUNICODE_STRING name, UINT8 type, dir_child** pdc); diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c index 089b19c8a83..2d996edc7c5 100644 --- a/drivers/filesystems/btrfs/create.c +++ b/drivers/filesystems/btrfs/create.c @@ -593,7 +593,7 @@ cont: } NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb, - root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp) { + root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, BOOL always_add_hl, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp) { KEY searchkey; traverse_ptr tp, next_tp; NTSTATUS Status; @@ -719,7 +719,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if ((no_data && tp.item->key.obj_type > TYPE_XATTR_ITEM) || tp.item->key.obj_type > TYPE_EXTENT_DATA) break; - if (fcb->inode_item.st_nlink > 1 && tp.item->key.obj_type == TYPE_INODE_REF) { + if ((always_add_hl || fcb->inode_item.st_nlink > 1) && tp.item->key.obj_type == TYPE_INODE_REF) { ULONG len; INODE_REF* ir; @@ -784,7 +784,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo len -= sizeof(INODE_REF) - 1 + ir->n; ir = (INODE_REF*)&ir->name[ir->n]; } - } else if (fcb->inode_item.st_nlink > 1 && tp.item->key.obj_type == TYPE_INODE_EXTREF) { + } else if ((always_add_hl || fcb->inode_item.st_nlink > 1) && tp.item->key.obj_type == TYPE_INODE_EXTREF) { ULONG len; INODE_EXTREF* ier; @@ -971,6 +971,11 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo else fcb->prop_compression = PropCompression_None; } + } else if (tp.item->key.offset == EA_CASE_SENSITIVE_HASH && di->n == sizeof(EA_CASE_SENSITIVE) - 1 && RtlCompareMemory(EA_CASE_SENSITIVE, di->name, di->n) == di->n) { + if (di->m > 0) { + fcb->case_sensitive = di->m == 1 && di->name[di->n] == '1'; + fcb->case_sensitive_set = TRUE; + } } else if (di->n > sizeof(xapref) - 1 && RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) { dir_child* dc; ULONG utf16len; @@ -1165,8 +1170,8 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo #endif *pfcb = fcb2; - release_fcb_lock(Vcb); reap_fcb(fcb); + release_fcb_lock(Vcb); return STATUS_SUCCESS; } } @@ -1174,8 +1179,8 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo if (deleted_fcb) { InterlockedIncrement(&deleted_fcb->refcount); *pfcb = deleted_fcb; - release_fcb_lock(Vcb); reap_fcb(fcb); + release_fcb_lock(Vcb); return STATUS_SUCCESS; } @@ -1514,7 +1519,7 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex #ifdef DEBUG_STATS time1 = KeQueryPerformanceCounter(NULL); #endif - Status = open_fcb(Vcb, subvol, inode, dc->type, &dc->utf8, sf->fcb, &fcb, pooltype, Irp); + Status = open_fcb(Vcb, subvol, inode, dc->type, &dc->utf8, FALSE, sf->fcb, &fcb, pooltype, Irp); #ifdef DEBUG_STATS time2 = KeQueryPerformanceCounter(NULL); Vcb->stats.open_fcb_calls++; @@ -1692,7 +1697,16 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv #ifdef DEBUG_STATS time1 = KeQueryPerformanceCounter(NULL); #endif - Status = open_fileref_child(Vcb, sf, &nb->us, case_sensitive, lastpart, streampart, pooltype, &sf2, Irp); + BOOL cs = case_sensitive; + + if (!cs) { + if (streampart) + cs = sf->parent->fcb->case_sensitive; + else + cs = sf->fcb->case_sensitive; + } + + Status = open_fileref_child(Vcb, sf, &nb->us, cs, lastpart, streampart, pooltype, &sf2, Irp); #ifdef DEBUG_STATS time2 = KeQueryPerformanceCounter(NULL); Vcb->stats.open_fileref_child_calls++; @@ -2529,6 +2543,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ static const WCHAR DOSATTRIB[] = L"DOSATTRIB"; static const WCHAR EA[] = L"EA"; static const WCHAR reparse[] = L"reparse"; + static const WCHAR casesensitive_str[] = L"casesensitive"; LARGE_INTEGER time; BTRFS_TIME now; ULONG utf8len, overhead; @@ -2634,7 +2649,8 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) || (stream->Length == sizeof(EA) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) || - (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) { + (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length) || + (stream->Length == sizeof(casesensitive_str) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, casesensitive_str, stream->Length) == stream->Length)) { free_fileref(parfileref); return STATUS_OBJECT_NAME_INVALID; } @@ -3774,7 +3790,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO if (dc->fileref) { send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name); - Status = delete_fileref(dc->fileref, NULL, NULL, rollback); + Status = delete_fileref(dc->fileref, NULL, FALSE, NULL, rollback); if (!NT_SUCCESS(Status)) { ERR("delete_fileref returned %08x\n", Status); @@ -3953,30 +3969,198 @@ NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) UNICODE_STRING name; BOOL hl_alloc = FALSE; file_ref *parfr, *fr; -#ifdef __REACTOS__ - hardlink* hl; -#endif - Status = open_fcb(Vcb, subvol, inode, 0, NULL, NULL, &fcb, PagedPool, Irp); + Status = open_fcb(Vcb, subvol, inode, 0, NULL, TRUE, NULL, &fcb, PagedPool, Irp); if (!NT_SUCCESS(Status)) { ERR("open_fcb returned %08x\n", Status); return Status; } + ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE); + + if (fcb->inode_item.st_nlink == 0 || fcb->deleted) { + ExReleaseResourceLite(fcb->Header.Resource); + free_fcb(fcb); + return STATUS_OBJECT_NAME_NOT_FOUND; + } + if (fcb->fileref) { *pfr = fcb->fileref; increase_fileref_refcount(fcb->fileref); + free_fcb(fcb); + ExReleaseResourceLite(fcb->Header.Resource); return STATUS_SUCCESS; } + if (IsListEmpty(&fcb->hardlinks)) { + ExReleaseResourceLite(fcb->Header.Resource); + + ExAcquireResourceSharedLite(&Vcb->dirty_filerefs_lock, TRUE); + + if (!IsListEmpty(&Vcb->dirty_filerefs)) { + LIST_ENTRY* le = Vcb->dirty_filerefs.Flink; + while (le != &Vcb->dirty_filerefs) { + file_ref* fr = CONTAINING_RECORD(le, file_ref, list_entry_dirty); + + if (fr->fcb == fcb) { + ExReleaseResourceLite(&Vcb->dirty_filerefs_lock); + increase_fileref_refcount(fr); + free_fcb(fcb); + *pfr = fr; + return STATUS_SUCCESS; + } + + le = le->Flink; + } + } + + ExReleaseResourceLite(&Vcb->dirty_filerefs_lock); + + { + KEY searchkey; + traverse_ptr tp; + + searchkey.obj_id = fcb->inode; + searchkey.obj_type = TYPE_INODE_REF; + searchkey.offset = 0; + + Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp); + if (!NT_SUCCESS(Status)) { + ERR("find_item returned %08x\n", Status); + free_fcb(fcb); + return Status; + } + + do { + traverse_ptr next_tp; + + if (tp.item->key.obj_id > fcb->inode || (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type > TYPE_INODE_EXTREF)) + break; + + if (tp.item->key.obj_id == fcb->inode) { + if (tp.item->key.obj_type == TYPE_INODE_REF) { + INODE_REF* ir = (INODE_REF*)tp.item->data; +#ifdef __REACTOS__ + ULONG stringlen; +#endif + + if (tp.item->size < offsetof(INODE_REF, name[0]) || tp.item->size < offsetof(INODE_REF, name[0]) + ir->n) { + ERR("INODE_REF was too short\n"); + free_fcb(fcb); + return STATUS_INTERNAL_ERROR; + } + #ifndef __REACTOS__ - hardlink* hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry); -#else - hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry); + ULONG stringlen; #endif - name = hl->name; - parent = hl->parent; + Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ir->name, ir->n); + if (!NT_SUCCESS(Status)) { + ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status); + free_fcb(fcb); + return Status; + } + + name.Length = name.MaximumLength = (UINT16)stringlen; + + if (stringlen == 0) + name.Buffer = NULL; + else { + name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG); + + if (!name.Buffer) { + ERR("out of memory\n"); + free_fcb(fcb); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = RtlUTF8ToUnicodeN(name.Buffer, stringlen, &stringlen, ir->name, ir->n); + if (!NT_SUCCESS(Status)) { + ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status); + ExFreePool(name.Buffer); + free_fcb(fcb); + return Status; + } + + hl_alloc = TRUE; + } + + parent = tp.item->key.offset; + + break; + } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) { + INODE_EXTREF* ier = (INODE_EXTREF*)tp.item->data; +#ifdef __REACTOS__ + ULONG stringlen; +#endif + + if (tp.item->size < offsetof(INODE_EXTREF, name[0]) || tp.item->size < offsetof(INODE_EXTREF, name[0]) + ier->n) { + ERR("INODE_EXTREF was too short\n"); + free_fcb(fcb); + return STATUS_INTERNAL_ERROR; + } + +#ifndef __REACTOS__ + ULONG stringlen; +#endif + + Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ier->name, ier->n); + if (!NT_SUCCESS(Status)) { + ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status); + free_fcb(fcb); + return Status; + } + + name.Length = name.MaximumLength = (UINT16)stringlen; + + if (stringlen == 0) + name.Buffer = NULL; + else { + name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG); + + if (!name.Buffer) { + ERR("out of memory\n"); + free_fcb(fcb); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = RtlUTF8ToUnicodeN(name.Buffer, stringlen, &stringlen, ier->name, ier->n); + if (!NT_SUCCESS(Status)) { + ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status); + ExFreePool(name.Buffer); + free_fcb(fcb); + return Status; + } + + hl_alloc = TRUE; + } + + parent = ier->dir; + + break; + } + } + + if (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp)) + tp = next_tp; + else + break; + } while (TRUE); + } + + if (parent == 0) { + WARN("trying to open inode with no references\n"); + free_fcb(fcb); + return STATUS_INVALID_PARAMETER; + } + } else { + hardlink* hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry); + + name = hl->name; + parent = hl->parent; + + ExReleaseResourceLite(fcb->Header.Resource); + } if (parent == inode) { // subvolume root KEY searchkey; @@ -4048,6 +4232,9 @@ NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) if (stringlen == 0) name.Buffer = NULL; else { + if (hl_alloc) + ExFreePool(name.Buffer); + name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG); if (!name.Buffer) { @@ -4190,9 +4377,21 @@ static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Cur } if (options & FILE_OPEN_BY_FILE_ID) { - if (fn.Length == sizeof(UINT64) && related && RequestedDisposition == FILE_OPEN) { + if (RequestedDisposition != FILE_OPEN) { + WARN("FILE_OPEN_BY_FILE_ID not supported for anything other than FILE_OPEN\n"); + Status = STATUS_INVALID_PARAMETER; + goto exit; + } + + if (fn.Length == sizeof(UINT64)) { UINT64 inode; + if (!related) { + WARN("cannot open by short file ID unless related fileref also provided"); + Status = STATUS_INVALID_PARAMETER; + goto exit; + } + RtlCopyMemory(&inode, fn.Buffer, sizeof(UINT64)); if (related->fcb == Vcb->root_fileref->fcb && inode == 0) @@ -4205,10 +4404,38 @@ static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Cur } else Status = open_fileref_by_inode(Vcb, related->fcb->subvol, inode, &fileref, Irp); + goto loaded; + } else if (fn.Length == sizeof(FILE_ID_128)) { + UINT64 inode, subvol_id; + root* subvol = NULL; + + RtlCopyMemory(&inode, fn.Buffer, sizeof(UINT64)); + RtlCopyMemory(&subvol_id, (UINT8*)fn.Buffer + sizeof(UINT64), sizeof(UINT64)); + + if (subvol_id == BTRFS_ROOT_FSTREE || (subvol_id >= 0x100 && subvol_id < 0x8000000000000000)) { + LIST_ENTRY* le = Vcb->roots.Flink; + while (le != &Vcb->roots) { + root* r = CONTAINING_RECORD(le, root, list_entry); + + if (r->id == subvol_id) { + subvol = r; + break; + } + + le = le->Flink; + } + } + + if (!subvol) { + WARN("subvol %llx not found\n", subvol_id); + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } else + Status = open_fileref_by_inode(Vcb, subvol, inode, &fileref, Irp); + goto loaded; } else { - WARN("FILE_OPEN_BY_FILE_ID only supported for inodes\n"); - Status = STATUS_NOT_IMPLEMENTED; + WARN("invalid ID size for FILE_OPEN_BY_FILE_ID\n"); + Status = STATUS_INVALID_PARAMETER; goto exit; } } diff --git a/drivers/filesystems/btrfs/dirctrl.c b/drivers/filesystems/btrfs/dirctrl.c index 19b261b0180..48e7fc2aca6 100644 --- a/drivers/filesystems/btrfs/dirctrl.c +++ b/drivers/filesystems/btrfs/dirctrl.c @@ -17,6 +17,49 @@ #include "btrfs_drv.h" +// not currently in mingw +#ifndef _MSC_VER +#define FileIdExtdDirectoryInformation (enum _FILE_INFORMATION_CLASS)60 +#define FileIdExtdBothDirectoryInformation (enum _FILE_INFORMATION_CLASS)63 + +typedef struct _FILE_ID_EXTD_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + WCHAR FileName[1]; +} FILE_ID_EXTD_DIR_INFORMATION, *PFILE_ID_EXTD_DIR_INFORMATION; + +typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION; + +#endif + enum DirEntryType { DirEntryType_File, DirEntryType_Self, @@ -79,7 +122,7 @@ ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 t if (!(atts & FILE_ATTRIBUTE_REPARSE_POINT)) return 0; - Status = open_fcb(Vcb, subvol, inode, type, NULL, NULL, &fcb, PagedPool, Irp); + Status = open_fcb(Vcb, subvol, inode, type, NULL, FALSE, NULL, &fcb, PagedPool, Irp); if (!NT_SUCCESS(Status)) { ERR("open_fcb returned %08x\n", Status); return 0; @@ -221,7 +264,9 @@ static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG* len, PIRP Ir IrpSp->Parameters.QueryDirectory.FileInformationClass == FileDirectoryInformation || IrpSp->Parameters.QueryDirectory.FileInformationClass == FileFullDirectoryInformation || IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation || - IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation) { + IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation || + IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdExtdDirectoryInformation || + IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdExtdBothDirectoryInformation) { BOOL dotfile = de->name.Length > sizeof(WCHAR) && de->name.Buffer[0] == '.'; @@ -231,7 +276,9 @@ static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG* len, PIRP Ir if (IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation || IrpSp->Parameters.QueryDirectory.FileInformationClass == FileFullDirectoryInformation || IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdBothDirectoryInformation || - IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation) { + IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdFullDirectoryInformation || + IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdExtdDirectoryInformation || + IrpSp->Parameters.QueryDirectory.FileInformationClass == FileIdExtdBothDirectoryInformation) { ealen = get_ea_len(fcb->Vcb, r, inode, Irp); } } @@ -465,6 +512,102 @@ static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG* len, PIRP Ir return STATUS_SUCCESS; } +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + case FileIdExtdDirectoryInformation: + { + FILE_ID_EXTD_DIR_INFORMATION* fiedi = buf; + + TRACE("FileIdExtdDirectoryInformation\n"); + + needed = offsetof(FILE_ID_EXTD_DIR_INFORMATION, FileName[0]) + de->name.Length; + + if (needed > *len) { + TRACE("buffer overflow - %u > %u\n", needed, *len); + return STATUS_BUFFER_OVERFLOW; + } + + fiedi->NextEntryOffset = 0; + fiedi->FileIndex = 0; + fiedi->CreationTime.QuadPart = unix_time_to_win(&ii.otime); + fiedi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime); + fiedi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime); + fiedi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime); + fiedi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size; + + if (de->type == BTRFS_TYPE_SYMLINK) + fiedi->AllocationSize.QuadPart = 0; + else if (atts & FILE_ATTRIBUTE_SPARSE_FILE) + fiedi->AllocationSize.QuadPart = ii.st_blocks; + else + fiedi->AllocationSize.QuadPart = sector_align(ii.st_size, fcb->Vcb->superblock.sector_size); + + fiedi->FileAttributes = atts; + fiedi->FileNameLength = de->name.Length; + fiedi->EaSize = ealen; + fiedi->ReparsePointTag = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, ccb->lxss, Irp); + + RtlCopyMemory(&fiedi->FileId.Identifier[0], &fcb->inode, sizeof(UINT64)); + RtlCopyMemory(&fiedi->FileId.Identifier[sizeof(UINT64)], &fcb->subvol->id, sizeof(UINT64)); + + RtlCopyMemory(fiedi->FileName, de->name.Buffer, de->name.Length); + + *len -= needed; + + return STATUS_SUCCESS; + } + + case FileIdExtdBothDirectoryInformation: + { + FILE_ID_EXTD_BOTH_DIR_INFORMATION* fiebdi = buf; + + TRACE("FileIdExtdBothDirectoryInformation\n"); + + needed = offsetof(FILE_ID_EXTD_BOTH_DIR_INFORMATION, FileName[0]) + de->name.Length; + + if (needed > *len) { + TRACE("buffer overflow - %u > %u\n", needed, *len); + return STATUS_BUFFER_OVERFLOW; + } + + fiebdi->NextEntryOffset = 0; + fiebdi->FileIndex = 0; + fiebdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime); + fiebdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime); + fiebdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime); + fiebdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime); + fiebdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size; + + if (de->type == BTRFS_TYPE_SYMLINK) + fiebdi->AllocationSize.QuadPart = 0; + else if (atts & FILE_ATTRIBUTE_SPARSE_FILE) + fiebdi->AllocationSize.QuadPart = ii.st_blocks; + else + fiebdi->AllocationSize.QuadPart = sector_align(ii.st_size, fcb->Vcb->superblock.sector_size); + + fiebdi->FileAttributes = atts; + fiebdi->FileNameLength = de->name.Length; + fiebdi->EaSize = ealen; + fiebdi->ReparsePointTag = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, ccb->lxss, Irp); + + RtlCopyMemory(&fiebdi->FileId.Identifier[0], &fcb->inode, sizeof(UINT64)); + RtlCopyMemory(&fiebdi->FileId.Identifier[sizeof(UINT64)], &fcb->subvol->id, sizeof(UINT64)); + + fiebdi->ShortNameLength = 0; + + RtlCopyMemory(fiebdi->FileName, de->name.Buffer, de->name.Length); + + *len -= needed; + + return STATUS_SUCCESS; + } + +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif + case FileNamesInformation: { FILE_NAMES_INFORMATION* fni = buf; @@ -857,13 +1000,22 @@ static NTSTATUS query_directory(PIRP Irp) { while (length > 0) { switch (IrpSp->Parameters.QueryDirectory.FileInformationClass) { +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif case FileBothDirectoryInformation: case FileDirectoryInformation: case FileIdBothDirectoryInformation: case FileFullDirectoryInformation: case FileIdFullDirectoryInformation: + case FileIdExtdDirectoryInformation: + case FileIdExtdBothDirectoryInformation: length -= length % 8; break; +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif case FileNamesInformation: length -= length % 4; diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c index 2339c5dedaa..06ae42ac65c 100644 --- a/drivers/filesystems/btrfs/fileinfo.c +++ b/drivers/filesystems/btrfs/fileinfo.c @@ -21,7 +21,32 @@ // not currently in mingw - introduced with Windows 10 #ifndef _MSC_VER #define FileIdInformation (enum _FILE_INFORMATION_CLASS)59 +#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 #define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70 +#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; typedef struct _FILE_STAT_LX_INFORMATION { LARGE_INTEGER FileId; @@ -49,9 +74,119 @@ typedef struct _FILE_STAT_LX_INFORMATION { #define LX_FILE_METADATA_HAS_DEVICE_ID 0x08 #define LX_FILE_CASE_SENSITIVE_DIR 0x10 +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 + #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 +#endif + static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject) { FILE_BASIC_INFORMATION* fbi = Irp->AssociatedIrp.SystemBuffer; fcb* fcb = FileObject->FsContext; @@ -219,20 +354,29 @@ end: return Status; } -static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject) { - FILE_DISPOSITION_INFORMATION* fdi = Irp->AssociatedIrp.SystemBuffer; +static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject, BOOL ex) { fcb* fcb = FileObject->FsContext; ccb* ccb = FileObject->FsContext2; file_ref* fileref = ccb ? ccb->fileref : NULL; - ULONG atts; + ULONG atts, flags; NTSTATUS Status; if (!fileref) return STATUS_INVALID_PARAMETER; + 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; + } + ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); - TRACE("changing delete_on_close to %s for %S (fcb %p)\n", fdi->DeleteFile ? "TRUE" : "FALSE", file_desc(FileObject), fcb); + TRACE("changing delete_on_close to %s for %S (fcb %p)\n", flags & FILE_DISPOSITION_DELETE ? "TRUE" : "FALSE", file_desc(FileObject), fcb); if (fcb->ads) { if (fileref->parent) @@ -261,14 +405,19 @@ static NTSTATUS set_disposition_information(device_extension* Vcb, PIRP Irp, PFI } if (!MmFlushImageSection(&fcb->nonpaged->segment_object, MmFlushForDelete)) { - TRACE("trying to delete file which is being mapped as an image\n"); - Status = STATUS_CANNOT_DELETE; - goto end; + 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; + } } - ccb->fileref->delete_on_close = fdi->DeleteFile; + ccb->fileref->delete_on_close = flags & FILE_DISPOSITION_DELETE; + + FileObject->DeletePending = flags & FILE_DISPOSITION_DELETE; - FileObject->DeletePending = fdi->DeleteFile; + if (flags & FILE_DISPOSITION_DELETE && flags & FILE_DISPOSITION_POSIX_SEMANTICS) + ccb->fileref->posix_delete = TRUE; Status = STATUS_SUCCESS; @@ -276,7 +425,7 @@ end: ExReleaseResourceLite(fcb->Header.Resource); // send notification that directory is about to be deleted - if (NT_SUCCESS(Status) && fdi->DeleteFile && fcb->type == BTRFS_TYPE_DIRECTORY) { + if (NT_SUCCESS(Status) && flags & FILE_DISPOSITION_DELETE && fcb->type == BTRFS_TYPE_DIRECTORY) { FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext, NULL, FALSE, FALSE, 0, NULL, NULL, NULL); } @@ -1161,7 +1310,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd } if (!me->dummyfileref->fcb->ads) { - Status = delete_fileref(me->dummyfileref, NULL, Irp, rollback); + Status = delete_fileref(me->dummyfileref, NULL, FALSE, Irp, rollback); if (!NT_SUCCESS(Status)) { ERR("delete_fileref returned %08x\n", Status); goto end; @@ -1217,7 +1366,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd me = CONTAINING_RECORD(le, move_entry, list_entry); if (me->dummyfileref->fcb->ads && me->parent->dummyfileref->fcb->deleted) { - Status = delete_fileref(me->dummyfileref, NULL, Irp, rollback); + Status = delete_fileref(me->dummyfileref, NULL, FALSE, Irp, rollback); if (!NT_SUCCESS(Status)) { ERR("delete_fileref returned %08x\n", Status); goto end; @@ -1349,9 +1498,8 @@ void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc) { } } -static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject, PFILE_OBJECT tfo) { - PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); - FILE_RENAME_INFORMATION* fri = Irp->AssociatedIrp.SystemBuffer; +static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject, PFILE_OBJECT tfo, BOOL ex) { + FILE_RENAME_INFORMATION_EX* fri = Irp->AssociatedIrp.SystemBuffer; fcb *fcb = FileObject->FsContext; ccb* ccb = FileObject->FsContext2; file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL; @@ -1366,11 +1514,17 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB hardlink* hl; SECURITY_SUBJECT_CONTEXT subjcont; ACCESS_MASK access; + ULONG flags; InitializeListHead(&rollback); + if (ex) + flags = fri->Flags; + else + flags = fri->ReplaceIfExists ? FILE_RENAME_REPLACE_IF_EXISTS : 0; + TRACE("tfo = %p\n", tfo); - TRACE("ReplaceIfExists = %u\n", IrpSp->Parameters.SetFile.ReplaceIfExists); + TRACE("Flags = %x\n", flags); TRACE("RootDirectory = %p\n", fri->RootDirectory); TRACE("FileName = %.*S\n", fri->FileNameLength / sizeof(WCHAR), fri->FileName); @@ -1451,16 +1605,21 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB TRACE("destination file %S already exists\n", file_desc_fileref(oldfileref)); if (fileref != oldfileref && !oldfileref->deleted) { - if (!IrpSp->Parameters.SetFile.ReplaceIfExists) { + if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) { Status = STATUS_OBJECT_NAME_COLLISION; goto end; - } else if ((oldfileref->open_count >= 1 || has_open_children(oldfileref)) && !oldfileref->deleted) { + } 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) { WARN("trying to overwrite open file\n"); Status = STATUS_ACCESS_DENIED; goto end; - } - - if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) { + } 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) { WARN("trying to overwrite directory\n"); Status = STATUS_ACCESS_DENIED; goto end; @@ -1516,7 +1675,12 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OB SeReleaseSubjectContext(&subjcont); - Status = delete_fileref(oldfileref, NULL, Irp, &rollback); + if (oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS) { + oldfileref->delete_on_close = TRUE; + oldfileref->posix_delete = TRUE; + } + + Status = delete_fileref(oldfileref, NULL, oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS, Irp, &rollback); if (!NT_SUCCESS(Status)) { ERR("delete_fileref returned %08x\n", Status); goto end; @@ -2177,8 +2341,8 @@ static NTSTATUS set_position_information(PFILE_OBJECT FileObject, PIRP Irp) { return STATUS_SUCCESS; } -static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject, PFILE_OBJECT tfo) { - FILE_LINK_INFORMATION* fli = Irp->AssociatedIrp.SystemBuffer; +static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT FileObject, PFILE_OBJECT tfo, BOOL ex) { + FILE_LINK_INFORMATION_EX* fli = Irp->AssociatedIrp.SystemBuffer; fcb *fcb = FileObject->FsContext, *tfofcb, *parfcb; ccb* ccb = FileObject->FsContext2; file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL; @@ -2194,13 +2358,19 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE ACCESS_MASK access; SECURITY_SUBJECT_CONTEXT subjcont; dir_child* dc = NULL; + ULONG flags; InitializeListHead(&rollback); // FIXME - check fli length // FIXME - don't ignore fli->RootDirectory - TRACE("ReplaceIfExists = %x\n", fli->ReplaceIfExists); + if (ex) + flags = fli->Flags; + else + flags = fli->ReplaceIfExists ? FILE_LINK_REPLACE_IF_EXISTS : 0; + + TRACE("flags = %x\n", flags); TRACE("RootDirectory = %p\n", fli->RootDirectory); TRACE("FileNameLength = %x\n", fli->FileNameLength); TRACE("FileName = %.*S\n", fli->FileNameLength / sizeof(WCHAR), fli->FileName); @@ -2292,19 +2462,21 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE if (!oldfileref->deleted) { WARN("destination file %S already exists\n", file_desc_fileref(oldfileref)); - if (!fli->ReplaceIfExists) { + if (!(flags & FILE_LINK_REPLACE_IF_EXISTS)) { Status = STATUS_OBJECT_NAME_COLLISION; goto end; - } else if (oldfileref->open_count >= 1 && !oldfileref->deleted) { + } 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) { WARN("trying to overwrite open file\n"); Status = STATUS_ACCESS_DENIED; goto end; - } else if (fileref == oldfileref) { + } else if (!(flags & FILE_LINK_IGNORE_READONLY_ATTRIBUTE) && oldfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) { + WARN("trying to overwrite readonly file\n"); Status = STATUS_ACCESS_DENIED; goto end; - } - - if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) { + } else if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) { WARN("trying to overwrite directory\n"); Status = STATUS_ACCESS_DENIED; goto end; @@ -2353,7 +2525,12 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP Irp, PFILE_OBJE SeReleaseSubjectContext(&subjcont); - Status = delete_fileref(oldfileref, NULL, Irp, &rollback); + if (oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS) { + oldfileref->delete_on_close = TRUE; + oldfileref->posix_delete = TRUE; + } + + Status = delete_fileref(oldfileref, NULL, oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS, Irp, &rollback); if (!NT_SUCCESS(Status)) { ERR("delete_fileref returned %08x\n", Status); goto end; @@ -2608,6 +2785,40 @@ end: return Status; } +#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; + } + + ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE); + + fcb->case_sensitive = fcsi->Flags & FILE_CS_FLAG_CASE_SENSITIVE_DIR; + mark_fcb_dirty(fcb); + + ExReleaseResourceLite(&fcb->Vcb->tree_lock); + + return STATUS_SUCCESS; +} +#endif + _Dispatch_type_(IRP_MJ_SET_INFORMATION) _Function_class_(DRIVER_DISPATCH) NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { @@ -2655,7 +2866,11 @@ NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) } if (fcb != Vcb->dummy_fcb && is_subvol_readonly(fcb->subvol, Irp) && IrpSp->Parameters.SetFile.FileInformationClass != FilePositionInformation && +#ifndef __REACTOS__ + (fcb->inode != SUBVOL_ROOT_INODE || (IrpSp->Parameters.SetFile.FileInformationClass != FileBasicInformation && IrpSp->Parameters.SetFile.FileInformationClass != FileRenameInformation && IrpSp->Parameters.SetFile.FileInformationClass != FileRenameInformationEx))) { +#else (fcb->inode != SUBVOL_ROOT_INODE || (IrpSp->Parameters.SetFile.FileInformationClass != FileBasicInformation && IrpSp->Parameters.SetFile.FileInformationClass != FileRenameInformation))) { +#endif Status = STATUS_ACCESS_DENIED; goto end; } @@ -2704,7 +2919,7 @@ NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) break; } - Status = set_disposition_information(Vcb, Irp, IrpSp->FileObject); + Status = set_disposition_information(Vcb, Irp, IrpSp->FileObject, FALSE); break; } @@ -2726,7 +2941,7 @@ NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) case FileLinkInformation: TRACE("FileLinkInformation\n"); - Status = set_link_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject); + Status = set_link_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, FALSE); break; case FilePositionInformation: @@ -2737,7 +2952,7 @@ NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) case FileRenameInformation: TRACE("FileRenameInformation\n"); // FIXME - make this work with streams - Status = set_rename_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject); + Status = set_rename_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, FALSE); break; case FileValidDataLengthInformation: @@ -2755,6 +2970,52 @@ NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) break; } +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif +#ifndef __REACTOS__ + case FileDispositionInformationEx: + { + TRACE("FileDispositionInformationEx\n"); + + if (Irp->RequestorMode == UserMode && !(ccb->access & DELETE)) { + WARN("insufficient privileges\n"); + Status = STATUS_ACCESS_DENIED; + break; + } + + Status = set_disposition_information(Vcb, Irp, IrpSp->FileObject, TRUE); + + break; + } + + case FileRenameInformationEx: + TRACE("FileRenameInformationEx\n"); + Status = set_rename_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, TRUE); + break; + + case FileLinkInformationEx: + TRACE("FileLinkInformationEx\n"); + Status = set_link_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, TRUE); + 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; +#endif +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif + default: WARN("unknown FileInformationClass %u\n", IrpSp->Parameters.SetFile.FileInformationClass); } @@ -3362,16 +3623,176 @@ static NTSTATUS fill_in_hard_link_information(FILE_LINKS_INFORMATION* fli, file_ #endif /* __REACTOS__ */ #if (NTDDI_VERSION >= NTDDI_WIN10) -#ifdef __MINGW32__ -typedef struct _FILE_ID_128 { - UCHAR Identifier[16]; -} FILE_ID_128, *PFILE_ID_128; +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; + BOOL overflow = FALSE; + fcb* fcb = fileref->fcb; + ULONG len; -typedef struct _FILE_ID_INFORMATION { - ULONGLONG VolumeSerialNumber; - FILE_ID_128 FileId; -} FILE_ID_INFORMATION, *PFILE_ID_INFORMATION; -#endif + 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; + + ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE); + + 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) + overflow = TRUE; + + 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 { + RtlCopyMemory(&flefii->ParentFileId.Identifier[0], &fileref->parent->fcb->inode, sizeof(UINT64)); + RtlCopyMemory(&flefii->ParentFileId.Identifier[sizeof(UINT64)], &fileref->parent->fcb->subvol->id, sizeof(UINT64)); + + 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 { + ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE); + + if (IsListEmpty(&fcb->hardlinks)) { + bytes_needed += offsetof(FILE_LINK_ENTRY_FULL_ID_INFORMATION, FileName[0]) + fileref->dc->name.Length; + + if (bytes_needed > *length) + overflow = TRUE; + + if (!overflow) { + flefii = &flfii->Entry; + + flefii->NextEntryOffset = 0; + + RtlCopyMemory(&flefii->ParentFileId.Identifier[0], &fileref->parent->fcb->inode, sizeof(UINT64)); + RtlCopyMemory(&flefii->ParentFileId.Identifier[sizeof(UINT64)], &fileref->parent->fcb->subvol->id, sizeof(UINT64)); + + 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; + + TRACE("parent %llx, index %llx, name %.*S\n", hl->parent, hl->index, hl->name.Length / sizeof(WCHAR), hl->name.Buffer); + + 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; + BOOL found = FALSE, deleted = FALSE; + 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) { + found = TRUE; + 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) + overflow = TRUE; + + if (!overflow) { + if (flefii) { + flefii->NextEntryOffset = (ULONG)sector_align(offsetof(FILE_LINK_ENTRY_FULL_ID_INFORMATION, FileName[0]) + (flefii->FileNameLength * sizeof(WCHAR)), 8); + flefii = (FILE_LINK_ENTRY_FULL_ID_INFORMATION*)((UINT8*)flefii + flefii->NextEntryOffset); + } else + flefii = &flfii->Entry; + + flefii->NextEntryOffset = 0; + + RtlCopyMemory(&flefii->ParentFileId.Identifier[0], &parfr->fcb->inode, sizeof(UINT64)); + RtlCopyMemory(&flefii->ParentFileId.Identifier[sizeof(UINT64)], &parfr->fcb->subvol->id, sizeof(UINT64)); + + 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; +} static NTSTATUS fill_in_file_id_information(FILE_ID_INFORMATION* fii, fcb* fcb, LONG* length) { RtlCopyMemory(&fii->VolumeSerialNumber, &fcb->Vcb->superblock.uuid.uuid[8], sizeof(UINT64)); @@ -3385,6 +3806,66 @@ static NTSTATUS fill_in_file_id_information(FILE_ID_INFORMATION* fii, fcb* fcb, #endif #ifndef __REACTOS__ +static NTSTATUS fill_in_file_stat_information(FILE_STAT_INFORMATION* fsi, fcb* fcb, ccb* ccb, LONG* length) { + INODE_ITEM* ii; + + fsi->FileId.LowPart = (UINT32)fcb->inode; + fsi->FileId.HighPart = (UINT32)fcb->subvol->id; + + if (fcb->ads) + ii = &ccb->fileref->parent->fcb->inode_item; + else + ii = &fcb->inode_item; + + if (fcb == fcb->Vcb->dummy_fcb) { + LARGE_INTEGER time; + + KeQuerySystemTime(&time); + 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; +} + static NTSTATUS fill_in_file_stat_lx_information(FILE_STAT_LX_INFORMATION* fsli, fcb* fcb, ccb* ccb, LONG* length) { INODE_ITEM* ii; @@ -3439,7 +3920,11 @@ static NTSTATUS fill_in_file_stat_lx_information(FILE_STAT_LX_INFORMATION* fsli, fsli->NumberOfLinks = fcb->inode_item.st_nlink; fsli->EffectiveAccess = ccb->access; - fsli->LxFlags = LX_FILE_METADATA_HAS_UID | LX_FILE_METADATA_HAS_GID | LX_FILE_METADATA_HAS_MODE | LX_FILE_METADATA_HAS_DEVICE_ID; // FIXME - LX_FILE_CASE_SENSITIVE_DIR + fsli->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; + fsli->LxUid = ii->st_uid; fsli->LxGid = ii->st_gid; fsli->LxMode = ii->st_mode; @@ -3456,6 +3941,14 @@ static NTSTATUS fill_in_file_stat_lx_information(FILE_STAT_LX_INFORMATION* fsli, return STATUS_SUCCESS; } + +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; +} #endif static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObject, PIRP Irp) { @@ -3746,6 +4239,23 @@ static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObject, PIRP break; } + 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; + } + case FileStatLxInformation: { FILE_STAT_LX_INFORMATION* fsli = Irp->AssociatedIrp.SystemBuffer; @@ -3762,6 +4272,36 @@ static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObject, PIRP break; } + + 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"); + + ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); + Status = fill_in_hard_link_full_id_information(flfii, fileref, Irp, &length); + ExReleaseResourceLite(&Vcb->tree_lock); + + break; + } #ifndef _MSC_VER #pragma GCC diagnostic pop #endif diff --git a/drivers/filesystems/btrfs/flushthread.c b/drivers/filesystems/btrfs/flushthread.c index 6784de5277e..5801ff3329d 100644 --- a/drivers/filesystems/btrfs/flushthread.c +++ b/drivers/filesystems/btrfs/flushthread.c @@ -515,6 +515,9 @@ static NTSTATUS add_parents(device_extension* Vcb, PIRP Irp) { KEY searchkey; traverse_ptr tp; NTSTATUS Status; +#ifdef __REACTOS__ + tree* t2; +#endif searchkey.obj_id = t->root->id; searchkey.obj_type = TYPE_ROOT_ITEM; @@ -555,6 +558,17 @@ static NTSTATUS add_parents(device_extension* Vcb, PIRP Irp) { return Status; } } + +#ifndef __REACTOS__ + tree* t2 = tp.tree; +#else + t2 = tp.tree; +#endif + while (t2) { + t2->write = TRUE; + + t2 = t2->parent; + } } } @@ -2713,6 +2727,9 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* } if (c->used != c->oldused) { +#ifdef __REACTOS__ + UINT64 old_phys_used, phys_used; +#endif searchkey.obj_id = c->offset; searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM; searchkey.offset = c->chunk_item->size; @@ -2767,11 +2784,18 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp, LIST_ENTRY* goto end; } - TRACE("bytes_used = %llx\n", Vcb->superblock.bytes_used); - - Vcb->superblock.bytes_used += c->used - c->oldused; +#ifndef __REACTOS__ + UINT64 old_phys_used = chunk_estimate_phys_size(Vcb, c, c->oldused); + UINT64 phys_used = chunk_estimate_phys_size(Vcb, c, c->used); +#else + old_phys_used = chunk_estimate_phys_size(Vcb, c, c->oldused); + phys_used = chunk_estimate_phys_size(Vcb, c, c->used); +#endif - TRACE("bytes_used = %llx\n", Vcb->superblock.bytes_used); + if (Vcb->superblock.bytes_used + phys_used > old_phys_used) + Vcb->superblock.bytes_used += phys_used - old_phys_used; + else + Vcb->superblock.bytes_used = 0; c->oldused = c->used; } @@ -4118,6 +4142,8 @@ static NTSTATUS create_chunk(device_extension* Vcb, chunk* c, PIRP Irp) { c->created = FALSE; c->oldused = c->used; + Vcb->superblock.bytes_used += chunk_estimate_phys_size(Vcb, c, c->used); + return STATUS_SUCCESS; } @@ -4652,6 +4678,15 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp) { } } + if (fcb->marked_as_orphan) { + Status = insert_tree_item_batch(batchlist, fcb->Vcb, fcb->subvol, BTRFS_ORPHAN_INODE_OBJID, TYPE_ORPHAN_INODE, + fcb->inode, NULL, 0, Batch_Delete); + if (!NT_SUCCESS(Status)) { + ERR("insert_tree_item_batch returned %08x\n", Status); + goto end; + } + } + Status = STATUS_SUCCESS; goto end; } @@ -5146,6 +5181,37 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist, PIRP Irp) { fcb->xattrs_changed = FALSE; } + if ((fcb->case_sensitive_set && !fcb->case_sensitive)) { + Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_CASE_SENSITIVE, + sizeof(EA_CASE_SENSITIVE) - 1, EA_CASE_SENSITIVE_HASH); + if (!NT_SUCCESS(Status)) { + ERR("delete_xattr returned %08x\n", Status); + goto end; + } + + fcb->case_sensitive_set = FALSE; + } else if ((!fcb->case_sensitive_set && fcb->case_sensitive)) { + Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode, EA_CASE_SENSITIVE, + sizeof(EA_CASE_SENSITIVE) - 1, EA_CASE_SENSITIVE_HASH, (UINT8*)"1", 1); + if (!NT_SUCCESS(Status)) { + ERR("set_xattr returned %08x\n", Status); + goto end; + } + + fcb->case_sensitive_set = TRUE; + } + + if (fcb->inode_item.st_nlink == 0 && !fcb->marked_as_orphan) { // mark as orphan + Status = insert_tree_item_batch(batchlist, fcb->Vcb, fcb->subvol, BTRFS_ORPHAN_INODE_OBJID, TYPE_ORPHAN_INODE, + fcb->inode, NULL, 0, Batch_Insert); + if (!NT_SUCCESS(Status)) { + ERR("insert_tree_item_batch returned %08x\n", Status); + goto end; + } + + fcb->marked_as_orphan = TRUE; + } + Status = STATUS_SUCCESS; end: @@ -5197,6 +5263,9 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c, LIST_ENTRY* batchlis KEY searchkey; traverse_ptr tp; UINT64 i, factor; +#ifdef __REACTOS__ + UINT64 phys_used; +#endif CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];; TRACE("dropping chunk %llx\n", c->offset); @@ -5441,7 +5510,16 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c, LIST_ENTRY* batchlis Vcb->superblock.incompat_flags &= ~BTRFS_INCOMPAT_FLAGS_RAID56; } - Vcb->superblock.bytes_used -= c->oldused; +#ifndef __REACTOS__ + UINT64 phys_used = chunk_estimate_phys_size(Vcb, c, c->oldused); +#else + phys_used = chunk_estimate_phys_size(Vcb, c, c->oldused); +#endif + + if (phys_used < Vcb->superblock.bytes_used) + Vcb->superblock.bytes_used -= phys_used; + else + Vcb->superblock.bytes_used = 0; ExFreePool(c->chunk_item); ExFreePool(c->devices); @@ -6943,6 +7021,108 @@ static NTSTATUS test_not_full(device_extension* Vcb) { return STATUS_DISK_FULL; } +static NTSTATUS check_for_orphans_root(device_extension* Vcb, root* r, PIRP Irp) { + NTSTATUS Status; + KEY searchkey; + traverse_ptr tp; + LIST_ENTRY rollback; + + TRACE("(%p, %p)\n", Vcb, r); + + InitializeListHead(&rollback); + + searchkey.obj_id = BTRFS_ORPHAN_INODE_OBJID; + searchkey.obj_type = TYPE_ORPHAN_INODE; + searchkey.offset = 0; + + Status = find_item(Vcb, r, &tp, &searchkey, FALSE, Irp); + if (!NT_SUCCESS(Status)) { + ERR("find_item returned %08x\n", Status); + return Status; + } + + do { + traverse_ptr next_tp; + + if (tp.item->key.obj_id > searchkey.obj_id || (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type > searchkey.obj_type)) + break; + + if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) { + fcb* fcb; + + TRACE("removing orphaned inode %llx\n", tp.item->key.offset); + + Status = open_fcb(Vcb, r, tp.item->key.offset, 0, NULL, FALSE, NULL, &fcb, PagedPool, Irp); + if (!NT_SUCCESS(Status)) + ERR("open_fcb returned %08x\n", Status); + else { + if (fcb->inode_item.st_nlink == 0) { + if (fcb->type != BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0) { + Status = excise_extents(Vcb, fcb, 0, sector_align(fcb->inode_item.st_size, Vcb->superblock.sector_size), Irp, &rollback); + if (!NT_SUCCESS(Status)) { + ERR("excise_extents returned %08x\n", Status); + goto end; + } + } + + fcb->deleted = TRUE; + + mark_fcb_dirty(fcb); + } + + free_fcb(fcb); + + Status = delete_tree_item(Vcb, &tp); + if (!NT_SUCCESS(Status)) { + ERR("delete_tree_item returned %08x\n", Status); + goto end; + } + } + } + + if (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp)) + tp = next_tp; + else + break; + } while (TRUE); + + Status = STATUS_SUCCESS; + + clear_rollback(&rollback); + +end: + do_rollback(Vcb, &rollback); + + return Status; +} + +static NTSTATUS check_for_orphans(device_extension* Vcb, PIRP Irp) { + NTSTATUS Status; + LIST_ENTRY* le; + + if (IsListEmpty(&Vcb->dirty_filerefs)) + return STATUS_SUCCESS; + + le = Vcb->dirty_filerefs.Flink; + while (le != &Vcb->dirty_filerefs) { + file_ref* fr = CONTAINING_RECORD(le, file_ref, list_entry_dirty); + + if (!fr->fcb->subvol->checked_for_orphans) { + Status = check_for_orphans_root(Vcb, fr->fcb->subvol, Irp); + if (!NT_SUCCESS(Status)) { + ERR("check_for_orphans_root returned %08x\n", Status); + return Status; + } + + fr->fcb->subvol->checked_for_orphans = TRUE; + } + + le = le->Flink; + } + + return STATUS_SUCCESS; +} + static NTSTATUS do_write2(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) { NTSTATUS Status; LIST_ENTRY *le, batchlist; @@ -6965,6 +7145,12 @@ static NTSTATUS do_write2(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) time1 = KeQueryPerformanceCounter(&freq); #endif + Status = check_for_orphans(Vcb, Irp); + if (!NT_SUCCESS(Status)) { + ERR("check_for_orphans returned %08x\n", Status); + return Status; + } + ExAcquireResourceExclusiveLite(&Vcb->dirty_filerefs_lock, TRUE); while (!IsListEmpty(&Vcb->dirty_filerefs)) { diff --git a/drivers/filesystems/btrfs/free-space.c b/drivers/filesystems/btrfs/free-space.c index cd3de367f45..e74a4a5346f 100644 --- a/drivers/filesystems/btrfs/free-space.c +++ b/drivers/filesystems/btrfs/free-space.c @@ -25,7 +25,7 @@ static NTSTATUS remove_free_space_inode(device_extension* Vcb, UINT64 inode, LIS NTSTATUS Status; fcb* fcb; - Status = open_fcb(Vcb, Vcb->root_root, inode, BTRFS_TYPE_FILE, NULL, NULL, &fcb, PagedPool, Irp); + Status = open_fcb(Vcb, Vcb->root_root, inode, BTRFS_TYPE_FILE, NULL, FALSE, NULL, &fcb, PagedPool, Irp); if (!NT_SUCCESS(Status)) { ERR("open_fcb returned %08x\n", Status); return Status; @@ -497,7 +497,7 @@ NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, BOOL load num_entries = fsi->num_entries; num_bitmaps = fsi->num_bitmaps; - Status = open_fcb(Vcb, Vcb->root_root, inode, BTRFS_TYPE_FILE, NULL, NULL, &c->cache, PagedPool, Irp); + Status = open_fcb(Vcb, Vcb->root_root, inode, BTRFS_TYPE_FILE, NULL, FALSE, NULL, &c->cache, PagedPool, Irp); if (!NT_SUCCESS(Status)) { ERR("open_fcb returned %08x\n", Status); return STATUS_NOT_FOUND; diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c index 3845965ca19..90622508cb2 100644 --- a/drivers/filesystems/btrfs/fsctl.c +++ b/drivers/filesystems/btrfs/fsctl.c @@ -432,7 +432,7 @@ static NTSTATUS do_create_snapshot(device_extension* Vcb, PFILE_OBJECT parent, f goto end; } - Status = open_fcb(Vcb, r, r->root_item.objid, BTRFS_TYPE_DIRECTORY, utf8, fcb, &fr->fcb, PagedPool, Irp); + Status = open_fcb(Vcb, r, r->root_item.objid, BTRFS_TYPE_DIRECTORY, utf8, FALSE, fcb, &fr->fcb, PagedPool, Irp); if (!NT_SUCCESS(Status)) { ERR("open_fcb returned %08x\n", Status); free_fileref(fr); @@ -4342,6 +4342,14 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT FileObject, fcb->ea_changed = TRUE; mark_fcb_dirty(fcb); + Status = STATUS_SUCCESS; + goto end; + } else if (bsxa->namelen == sizeof(EA_CASE_SENSITIVE) - 1 && RtlCompareMemory(bsxa->data, EA_CASE_SENSITIVE, sizeof(EA_CASE_SENSITIVE) - 1) == sizeof(EA_CASE_SENSITIVE) - 1) { + if (bsxa->valuelen > 0 && bsxa->data[bsxa->namelen] == '1') { + fcb->case_sensitive = TRUE; + mark_fcb_dirty(fcb); + } + Status = STATUS_SUCCESS; goto end; } else if (bsxa->namelen == sizeof(EA_PROP_COMPRESSION) - 1 && RtlCompareMemory(bsxa->data, EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1) == sizeof(EA_PROP_COMPRESSION) - 1) { diff --git a/drivers/filesystems/btrfs/write.c b/drivers/filesystems/btrfs/write.c index ed1df4c897a..a38ea7fb890 100644 --- a/drivers/filesystems/btrfs/write.c +++ b/drivers/filesystems/btrfs/write.c @@ -4498,7 +4498,7 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void ExFreePool(data); } else { if (write_irp && Irp->MdlAddress && no_buf) { - BOOL locked = Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED; + BOOL locked = Irp->MdlAddress->MdlFlags & (MDL_PAGES_LOCKED | MDL_PARTIAL); if (!locked) { Status = STATUS_SUCCESS; diff --git a/media/doc/README.FSD b/media/doc/README.FSD index f70f2a54a93..d86c5bd5861 100644 --- a/media/doc/README.FSD +++ b/media/doc/README.FSD @@ -3,9 +3,9 @@ The following FSD are shared with: https://github.com/maharmstone/btrfs. -reactos/drivers/filesystems/btrfs # Synced to 1.2.1 +reactos/drivers/filesystems/btrfs # Synced to 1.3 reactos/dll/shellext/shellbtrfs # Synced to 1.1 -reactos/sdk/lib/fslib/btrfslib # Synced to 1.2.1 +reactos/sdk/lib/fslib/btrfslib # Synced to 1.3 The following FSD are shared with: http://www.ext2fsd.com/