[BTRFS] Upgrade to 1.3

CORE-16111
This commit is contained in:
Pierre Schweitzer 2019-06-11 12:35:19 +02:00
parent 90aa2c26f8
commit f381137c89
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
13 changed files with 1347 additions and 156 deletions

View file

@ -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"

View file

@ -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));

View file

@ -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 {

View file

@ -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"

View file

@ -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);

View file

@ -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;
}
#ifndef __REACTOS__
hardlink* hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry);
#else
hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry);
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
name = hl->name;
parent = hl->parent;
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__
ULONG stringlen;
#endif
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;
}
}

View file

@ -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;

View file

@ -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 = fdi->DeleteFile;
FileObject->DeletePending = flags & FILE_DISPOSITION_DELETE;
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) {
WARN("trying to overwrite open file\n");
Status = STATUS_ACCESS_DENIED;
goto end;
} else if (fileref == oldfileref) {
Status = STATUS_ACCESS_DENIED;
goto end;
}
if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
} 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 (!(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;
} 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

View file

@ -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);
#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
Vcb->superblock.bytes_used += c->used - c->oldused;
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)) {

View file

@ -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;

View file

@ -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) {

View file

@ -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;

View file

@ -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/