https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f381137c89da4ff272e93…
commit f381137c89da4ff272e939bedb91c34262369846
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Tue Jun 11 12:35:19 2019 +0200
Commit: Pierre Schweitzer <pierre(a)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/