[BTRFS] Upgrade to 1.1

CORE-15452
This commit is contained in:
Pierre Schweitzer 2018-12-16 12:03:16 +01:00
parent e8d16d0a7d
commit eb7fbc253f
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
61 changed files with 22605 additions and 596 deletions

View file

@ -23,7 +23,24 @@
extern PDEVICE_OBJECT master_devobj;
static WCHAR datastring[] = L"::$DATA";
static const WCHAR datastring[] = L"::$DATA";
// Windows 10
#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
#define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
typedef struct _ATOMIC_CREATE_ECP_CONTEXT {
USHORT Size;
USHORT InFlags;
USHORT OutFlags;
USHORT ReparseBufferLength;
PREPARSE_DATA_BUFFER ReparseBuffer;
LONGLONG FileSize;
LONGLONG ValidDataLength;
} ATOMIC_CREATE_ECP_CONTEXT, *PATOMIC_CREATE_ECP_CONTEXT;
static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
fcb* fcb;
@ -308,11 +325,11 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENT
InsertTailList(parts, &nb->list_entry);
if (has_stream) {
static WCHAR datasuf[] = {':','$','D','A','T','A',0};
static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
UNICODE_STRING dsus;
dsus.Buffer = datasuf;
dsus.Length = dsus.MaximumLength = (UINT16)wcslen(datasuf) * sizeof(WCHAR);
dsus.Buffer = (WCHAR*)datasuf;
dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
for (i = 0; i < nb->us.Length / sizeof(WCHAR); i++) {
if (nb->us.Buffer[i] == ':') {
@ -799,7 +816,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
ULONG len;
DIR_ITEM* di;
static char xapref[] = "user.";
static const char xapref[] = "user.";
if (tp.item->size < offsetof(DIR_ITEM, name[0])) {
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(DIR_ITEM, name[0]));
@ -813,7 +830,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
if (len < offsetof(DIR_ITEM, name[0]) + di->m + di->n)
break;
if (tp.item->key.offset == EA_REPARSE_HASH && di->n == strlen(EA_REPARSE) && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) {
if (tp.item->key.offset == EA_REPARSE_HASH && di->n == sizeof(EA_REPARSE) - 1 && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) {
if (di->m > 0) {
fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
if (!fcb->reparse_xattr.Buffer) {
@ -827,7 +844,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
fcb->reparse_xattr.Buffer = NULL;
fcb->reparse_xattr.Length = fcb->reparse_xattr.MaximumLength = di->m;
} else if (tp.item->key.offset == EA_EA_HASH && di->n == strlen(EA_EA) && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) {
} else if (tp.item->key.offset == EA_EA_HASH && di->n == sizeof(EA_EA) - 1 && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) {
if (di->m > 0) {
ULONG offset;
@ -863,7 +880,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
} while (TRUE);
}
}
} else if (tp.item->key.offset == EA_DOSATTRIB_HASH && di->n == strlen(EA_DOSATTRIB) && RtlCompareMemory(EA_DOSATTRIB, di->name, di->n) == di->n) {
} else if (tp.item->key.offset == EA_DOSATTRIB_HASH && di->n == sizeof(EA_DOSATTRIB) - 1 && RtlCompareMemory(EA_DOSATTRIB, di->name, di->n) == di->n) {
if (di->m > 0) {
if (get_file_attributes_from_xattr(&di->name[di->n], di->m, &fcb->atts)) {
atts_set = TRUE;
@ -884,7 +901,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
}
}
}
} else if (tp.item->key.offset == EA_NTACL_HASH && di->n == strlen(EA_NTACL) && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n) {
} else if (tp.item->key.offset == EA_NTACL_HASH && di->n == sizeof(EA_NTACL) - 1 && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n) {
if (di->m > 0) {
fcb->sd = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
if (!fcb->sd) {
@ -902,23 +919,26 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
else
sd_set = TRUE;
}
} else if (tp.item->key.offset == EA_PROP_COMPRESSION_HASH && di->n == strlen(EA_PROP_COMPRESSION) && RtlCompareMemory(EA_PROP_COMPRESSION, di->name, di->n) == di->n) {
} else if (tp.item->key.offset == EA_PROP_COMPRESSION_HASH && di->n == sizeof(EA_PROP_COMPRESSION) - 1 && RtlCompareMemory(EA_PROP_COMPRESSION, di->name, di->n) == di->n) {
if (di->m > 0) {
const char lzo[] = "lzo";
const char zlib[] = "zlib";
static const char lzo[] = "lzo";
static const char zlib[] = "zlib";
static const char zstd[] = "zstd";
if (di->m == strlen(lzo) && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
if (di->m == sizeof(lzo) - 1 && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
fcb->prop_compression = PropCompression_LZO;
else if (di->m == strlen(zlib) && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
else if (di->m == sizeof(zlib) - 1 && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
fcb->prop_compression = PropCompression_Zlib;
else if (di->m == sizeof(zstd) - 1 && RtlCompareMemory(&di->name[di->n], zstd, di->m) == di->m)
fcb->prop_compression = PropCompression_ZSTD;
else
fcb->prop_compression = PropCompression_None;
}
} else if (di->n > strlen(xapref) && RtlCompareMemory(xapref, di->name, strlen(xapref)) == strlen(xapref)) {
} else if (di->n > sizeof(xapref) - 1 && RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) {
dir_child* dc;
ULONG utf16len;
Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[strlen(xapref)], di->n - (ULONG)strlen(xapref));
Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref));
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
free_fcb(Vcb, fcb);
@ -934,7 +954,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
RtlZeroMemory(dc, sizeof(dir_child));
dc->utf8.MaximumLength = dc->utf8.Length = di->n - (UINT16)strlen(xapref);
dc->utf8.MaximumLength = dc->utf8.Length = di->n + 1 - sizeof(xapref);
dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
if (!dc->utf8.Buffer) {
ERR("out of memory\n");
@ -943,7 +963,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(dc->utf8.Buffer, &di->name[strlen(xapref)], dc->utf8.Length);
RtlCopyMemory(dc->utf8.Buffer, &di->name[sizeof(xapref) - 1], dc->utf8.Length);
dc->name.MaximumLength = dc->name.Length = (UINT16)utf16len;
dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
@ -1113,11 +1133,11 @@ static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require
NTSTATUS Status;
KEY searchkey;
traverse_ptr tp;
static char xapref[] = "user.";
static const char xapref[] = "user.";
ANSI_STRING xattr;
UINT32 crc32;
xattr.Length = (UINT16)strlen(xapref) + dc->utf8.Length;
xattr.Length = sizeof(xapref) - 1 + dc->utf8.Length;
xattr.MaximumLength = xattr.Length + 1;
xattr.Buffer = ExAllocatePoolWithTag(PagedPool, xattr.MaximumLength, ALLOC_TAG);
if (!xattr.Buffer) {
@ -1125,8 +1145,8 @@ static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(xattr.Buffer, xapref, strlen(xapref));
RtlCopyMemory(&xattr.Buffer[strlen(xapref)], dc->utf8.Buffer, dc->utf8.Length);
RtlCopyMemory(xattr.Buffer, xapref, sizeof(xapref) - 1);
RtlCopyMemory(&xattr.Buffer[sizeof(xapref) - 1], dc->utf8.Buffer, dc->utf8.Length);
xattr.Buffer[xattr.Length] = 0;
fcb = create_fcb(Vcb, PagedPool);
@ -1454,7 +1474,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv
InitializeListHead(&parts);
if (fnus->Length != 0 &&
(fnus->Length != wcslen(datastring) * sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, wcslen(datastring) * sizeof(WCHAR)) != wcslen(datastring) * sizeof(WCHAR))) {
(fnus->Length != sizeof(datastring) - sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, sizeof(datastring) - sizeof(WCHAR)) != sizeof(datastring) - sizeof(WCHAR))) {
Status = split_path(Vcb, &fnus2, &parts, &has_stream);
if (!NT_SUCCESS(Status)) {
ERR("split_path returned %08x\n", Status);
@ -1649,6 +1669,218 @@ UINT32 inherit_mode(fcb* parfcb, BOOL is_dir) {
return mode;
}
static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION* ea) {
NTSTATUS Status;
LIST_ENTRY ealist, *le;
UINT16 size = 0;
char* buf;
InitializeListHead(&ealist);
do {
STRING s;
BOOL found = FALSE;
s.Length = s.MaximumLength = ea->EaNameLength;
s.Buffer = ea->EaName;
RtlUpperString(&s, &s);
le = ealist.Flink;
while (le != &ealist) {
ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
if (item->name.Length == s.Length && RtlCompareMemory(item->name.Buffer, s.Buffer, s.Length) == s.Length) {
item->flags = ea->Flags;
item->value.Length = item->value.MaximumLength = ea->EaValueLength;
item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
found = TRUE;
break;
}
le = le->Flink;
}
if (!found) {
ea_item* item = ExAllocatePoolWithTag(PagedPool, sizeof(ea_item), ALLOC_TAG);
if (!item) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
item->name.Length = item->name.MaximumLength = ea->EaNameLength;
item->name.Buffer = ea->EaName;
item->value.Length = item->value.MaximumLength = ea->EaValueLength;
item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
item->flags = ea->Flags;
InsertTailList(&ealist, &item->list_entry);
}
if (ea->NextEntryOffset == 0)
break;
ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
} while (TRUE);
// handle LXSS values
le = ealist.Flink;
while (le != &ealist) {
LIST_ENTRY* le2 = le->Flink;
ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
if (item->name.Length == sizeof(lxuid) - 1 && RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) == item->name.Length) {
if (item->value.Length < sizeof(UINT32)) {
ERR("uid value was shorter than expected\n");
Status = STATUS_INVALID_PARAMETER;
goto end;
}
RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer, sizeof(UINT32));
fcb->sd_dirty = TRUE;
fcb->sd_deleted = FALSE;
RemoveEntryList(&item->list_entry);
ExFreePool(item);
} else if (item->name.Length == sizeof(lxgid) - 1 && RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) == item->name.Length) {
if (item->value.Length < sizeof(UINT32)) {
ERR("gid value was shorter than expected\n");
Status = STATUS_INVALID_PARAMETER;
goto end;
}
RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer, sizeof(UINT32));
RemoveEntryList(&item->list_entry);
ExFreePool(item);
} else if (item->name.Length == sizeof(lxmod) - 1 && RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) == item->name.Length) {
UINT32 allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID;
UINT32 val;
if (item->value.Length < sizeof(UINT32)) {
ERR("mode value was shorter than expected\n");
Status = STATUS_INVALID_PARAMETER;
goto end;
}
RtlCopyMemory(&val, item->value.Buffer, sizeof(UINT32));
if (fcb->type != BTRFS_TYPE_DIRECTORY)
allowed |= __S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK;
fcb->inode_item.st_mode &= ~allowed;
fcb->inode_item.st_mode |= val & allowed;
if (fcb->type != BTRFS_TYPE_DIRECTORY) {
if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
fcb->type = BTRFS_TYPE_CHARDEV;
else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
fcb->type = BTRFS_TYPE_BLOCKDEV;
else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
fcb->type = BTRFS_TYPE_FIFO;
else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
fcb->type = BTRFS_TYPE_SOCKET;
}
RemoveEntryList(&item->list_entry);
ExFreePool(item);
} else if (item->name.Length == sizeof(lxdev) - 1 && RtlCompareMemory(item->name.Buffer, lxdev, item->name.Length) == item->name.Length) {
UINT32 major, minor;
if (item->value.Length < sizeof(UINT64)) {
ERR("dev value was shorter than expected\n");
Status = STATUS_INVALID_PARAMETER;
goto end;
}
major = *(UINT32*)item->value.Buffer;
minor = *(UINT32*)&item->value.Buffer[sizeof(UINT32)];
fcb->inode_item.st_rdev = (minor & 0xFFFFF) | ((major & 0xFFFFFFFFFFF) << 20);
RemoveEntryList(&item->list_entry);
ExFreePool(item);
}
le = le2;
}
if (fcb->type != BTRFS_TYPE_CHARDEV && fcb->type != BTRFS_TYPE_BLOCKDEV)
fcb->inode_item.st_rdev = 0;
if (IsListEmpty(&ealist))
return STATUS_SUCCESS;
le = ealist.Flink;
while (le != &ealist) {
ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
if (size % 4 > 0)
size += 4 - (size % 4);
size += (UINT16)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + item->name.Length + 1 + item->value.Length;
le = le->Flink;
}
buf = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
if (!buf) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = size;
fcb->ea_xattr.Buffer = buf;
fcb->ealen = 4;
ea = NULL;
le = ealist.Flink;
while (le != &ealist) {
ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
if (ea) {
ea->NextEntryOffset = (ULONG)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + ea->EaNameLength + ea->EaValueLength;
if (ea->NextEntryOffset % 4 > 0)
ea->NextEntryOffset += 4 - (ea->NextEntryOffset % 4);
ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
} else
ea = (FILE_FULL_EA_INFORMATION*)fcb->ea_xattr.Buffer;
ea->NextEntryOffset = 0;
ea->Flags = item->flags;
ea->EaNameLength = (UCHAR)item->name.Length;
ea->EaValueLength = item->value.Length;
RtlCopyMemory(ea->EaName, item->name.Buffer, item->name.Length);
ea->EaName[item->name.Length] = 0;
RtlCopyMemory(&ea->EaName[item->name.Length + 1], item->value.Buffer, item->value.Length);
fcb->ealen += 5 + item->name.Length + item->value.Length;
le = le->Flink;
}
fcb->ea_changed = TRUE;
Status = STATUS_SUCCESS;
end:
while (!IsListEmpty(&ealist)) {
ea_item* item = CONTAINING_RECORD(RemoveHeadList(&ealist), ea_item, list_entry);
ExFreePool(item);
}
return Status;
}
static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _In_ PUNICODE_STRING fpus,
_In_ file_ref* parfileref, _In_ ULONG options, _In_reads_bytes_opt_(ealen) FILE_FULL_EA_INFORMATION* ea, _In_ ULONG ealen,
_Out_ file_ref** pfr, _In_ LIST_ENTRY* rollback) {
@ -1843,44 +2075,17 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr
fcb->sd_dirty = TRUE;
if (ea && ealen > 0) {
FILE_FULL_EA_INFORMATION* eainfo;
fcb->ealen = 4;
// capitalize EA names
eainfo = ea;
do {
STRING s;
s.Length = s.MaximumLength = eainfo->EaNameLength;
s.Buffer = eainfo->EaName;
RtlUpperString(&s, &s);
fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
if (eainfo->NextEntryOffset == 0)
break;
eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) + eainfo->NextEntryOffset);
} while (TRUE);
fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, ealen, ALLOC_TAG);
if (!fcb->ea_xattr.Buffer) {
ERR("out of memory\n");
Status = file_create_parse_ea(fcb, ea);
if (!NT_SUCCESS(Status)) {
ERR("file_create_parse_ea returned %08x\n", Status);
free_fcb(Vcb, fcb);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
parfileref->fcb->inode_item.st_size -= utf8len * 2;
ExReleaseResourceLite(parfileref->fcb->Header.Resource);
return STATUS_INSUFFICIENT_RESOURCES;
return Status;
}
fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = (UINT16)ealen;
RtlCopyMemory(fcb->ea_xattr.Buffer, ea, fcb->ea_xattr.Length);
fcb->ea_changed = TRUE;
}
fileref = create_fileref(Vcb);
@ -1989,11 +2194,10 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
file_ref *fileref, *newpar, *parfileref;
fcb* fcb;
static char xapref[] = "user.";
static WCHAR DOSATTRIB[] = L"DOSATTRIB";
static WCHAR EA[] = L"EA";
static WCHAR reparse[] = L"reparse";
UINT16 xapreflen = (UINT16)strlen(xapref);
static const char xapref[] = "user.";
static const WCHAR DOSATTRIB[] = L"DOSATTRIB";
static const WCHAR EA[] = L"EA";
static const WCHAR reparse[] = L"reparse";
LARGE_INTEGER time;
BTRFS_TIME now;
ULONG utf8len, overhead;
@ -2086,9 +2290,9 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
if ((stream->Length == wcslen(DOSATTRIB) * sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) ||
(stream->Length == wcslen(EA) * sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) ||
(stream->Length == wcslen(reparse) * sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) {
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)) {
return STATUS_OBJECT_NAME_INVALID;
}
@ -2124,7 +2328,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return Status;
}
fcb->adsxattr.Length = (UINT16)utf8len + xapreflen;
fcb->adsxattr.Length = (UINT16)utf8len + sizeof(xapref) - 1;
fcb->adsxattr.MaximumLength = fcb->adsxattr.Length + 1;
fcb->adsxattr.Buffer = ExAllocatePoolWithTag(pool_type, fcb->adsxattr.MaximumLength, ALLOC_TAG);
if (!fcb->adsxattr.Buffer) {
@ -2133,9 +2337,9 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(fcb->adsxattr.Buffer, xapref, xapreflen);
RtlCopyMemory(fcb->adsxattr.Buffer, xapref, sizeof(xapref) - 1);
Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[xapreflen], utf8len, &utf8len, stream->Buffer, stream->Length);
Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len, &utf8len, stream->Buffer, stream->Length);
if (!NT_SUCCESS(Status)) {
ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status);
free_fcb(Vcb, fcb);
@ -2167,12 +2371,12 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
if (utf8len + xapreflen + overhead > fcb->adsmaxlen) {
WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len + xapreflen, overhead, fcb->adsmaxlen);
if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) {
WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen);
free_fcb(Vcb, fcb);
return STATUS_DISK_FULL;
} else
fcb->adsmaxlen -= overhead + utf8len + xapreflen;
fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
fileref = create_fileref(Vcb);
if (!fileref) {
@ -2192,7 +2396,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
RtlZeroMemory(dc, sizeof(dir_child));
dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length - xapreflen;
dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length + 1 - sizeof(xapref);
dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
if (!dc->utf8.Buffer) {
ERR("out of memory\n");
@ -2201,7 +2405,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[xapreflen], fcb->adsxattr.Length - xapreflen);
RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[sizeof(xapref) - 1], fcb->adsxattr.Length + 1 - sizeof(xapref));
dc->name.MaximumLength = dc->name.Length = stream->Length;
dc->name.Buffer = ExAllocatePoolWithTag(pool_type, dc->name.MaximumLength, ALLOC_TAG);
@ -2302,10 +2506,14 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
file_ref *fileref, *parfileref = NULL;
ULONG i, j;
ccb* ccb;
static WCHAR datasuf[] = {':','$','D','A','T','A',0};
static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
UNICODE_STRING dsus, fpus, stream;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
#ifndef __REACTOS__
ECP_LIST* ecp_list;
ATOMIC_CREATE_ECP_CONTEXT* acec = NULL;
#endif
#ifdef DEBUG_FCB_REFCOUNTS
LONG oc;
#endif
@ -2318,8 +2526,27 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
if (options & FILE_DELETE_ON_CLOSE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY)
return STATUS_CANNOT_DELETE;
dsus.Buffer = datasuf;
dsus.Length = dsus.MaximumLength = (USHORT)wcslen(datasuf) * sizeof(WCHAR);
#ifndef __REACTOS__
if (NT_SUCCESS(FsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) {
void* ctx = NULL;
GUID type;
ULONG ctxsize;
do {
Status = FsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize);
if (NT_SUCCESS(Status)) {
if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT)) {
acec = ctx;
break;
}
}
} while (NT_SUCCESS(Status));
}
#endif
dsus.Buffer = (WCHAR*)datasuf;
dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
fpus.Buffer = NULL;
if (!loaded_related) {
@ -2451,6 +2678,15 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
if (!ccb) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
fileref->deleted = TRUE;
fileref->fcb->deleted = TRUE;
if (stream.Length == 0) {
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
ExReleaseResourceLite(parfileref->fcb->Header.Resource);
}
free_fileref(Vcb, fileref);
goto end;
}
@ -2484,6 +2720,41 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
#ifndef __REACTOS__
// FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT
if (acec && acec->InFlags & ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED) {
if (acec->ReparseBufferLength > sizeof(UINT32) && *(UINT32*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) {
fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK);
fileref->fcb->type = BTRFS_TYPE_FILE;
}
if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO ||
fileref->fcb->type == BTRFS_TYPE_CHARDEV || fileref->fcb->type == BTRFS_TYPE_BLOCKDEV) {
// NOP. If called from LXSS, humour it - we hardcode the values elsewhere.
} else {
Status = set_reparse_point2(fileref->fcb, acec->ReparseBuffer, acec->ReparseBufferLength, NULL, NULL, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("set_reparse_point2 returned %08x\n", Status);
fileref->deleted = TRUE;
fileref->fcb->deleted = TRUE;
if (stream.Length == 0) {
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
ExReleaseResourceLite(parfileref->fcb->Header.Resource);
}
free_fileref(Vcb, fileref);
return Status;
}
}
acec->OutFlags |= ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET;
}
#endif
fileref->dc->type = fileref->fcb->type;
goto end2;
end:
@ -2738,7 +3009,8 @@ static NTSTATUS get_reparse_block(fcb* fcb, UINT8** data) {
}
RtlCopyMemory(*data, fcb->reparse_xattr.Buffer, fcb->reparse_xattr.Length);
}
} else
return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS;
}