From 0df3e104b460f70724b138ba4725a59435695532 Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Sat, 26 Mar 2016 11:53:07 +0000 Subject: [PATCH] [BTRFS] Upgrade the WinBtrfs to release 0.3. Mostly bugfixes CORE-11024 #resolve #comment Committed in r71052 svn path=/trunk/; revision=71052 --- reactos/drivers/filesystems/btrfs/btrfs.c | 41 +- reactos/drivers/filesystems/btrfs/btrfs_drv.h | 2 + .../drivers/filesystems/btrfs/btrfsioctl.h | 12 + reactos/drivers/filesystems/btrfs/cache.c | 11 +- reactos/drivers/filesystems/btrfs/create.c | 86 ++-- reactos/drivers/filesystems/btrfs/fastio.c | 66 ++- reactos/drivers/filesystems/btrfs/fileinfo.c | 4 +- reactos/drivers/filesystems/btrfs/fsctl.c | 28 ++ reactos/drivers/filesystems/btrfs/read.c | 20 +- reactos/drivers/filesystems/btrfs/treefuncs.c | 13 +- reactos/drivers/filesystems/btrfs/write.c | 411 ++++++++++++------ 11 files changed, 491 insertions(+), 203 deletions(-) create mode 100644 reactos/drivers/filesystems/btrfs/btrfsioctl.h diff --git a/reactos/drivers/filesystems/btrfs/btrfs.c b/reactos/drivers/filesystems/btrfs/btrfs.c index 90bb09ed618..6a1d25635cc 100644 --- a/reactos/drivers/filesystems/btrfs/btrfs.c +++ b/reactos/drivers/filesystems/btrfs/btrfs.c @@ -1550,8 +1550,8 @@ NTSTATUS delete_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback) { // FIXME - delete all children if deleting directory if (fcb->deleted) { - ERR("trying to delete already-deleted file\n"); - return STATUS_INTERNAL_ERROR; + WARN("trying to delete already-deleted file\n"); + return STATUS_SUCCESS; } if (!fcb->par) { @@ -1772,7 +1772,7 @@ NTSTATUS delete_fcb(fcb* fcb, PFILE_OBJECT FileObject, LIST_ENTRY* rollback) { InitializeListHead(&changed_sector_list); - if (fcb->type != BTRFS_TYPE_DIRECTORY) { + if (fcb->type != BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0) { Status = excise_extents(fcb->Vcb, fcb, 0, sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size), &changed_sector_list, rollback); if (!NT_SUCCESS(Status)) { ERR("excise_extents returned %08x\n", Status); @@ -1879,9 +1879,9 @@ void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line) #ifdef DEBUG_FCB_REFCOUNTS // WARN("fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer); #ifdef DEBUG_LONG_MESSAGES - _debug_message(func, file, line, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer); + _debug_message(func, 1, file, line, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer); #else - _debug_message(func, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer); + _debug_message(func, 1, "fcb %p: refcount now %i (%.*S)\n", fcb, rc, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer); #endif #endif @@ -1930,9 +1930,9 @@ void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line) ExFreePool(fcb); #ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_LONG_MESSAGES - _debug_message(func, file, line, "freeing fcb %p\n", fcb); + _debug_message(func, 1, file, line, "freeing fcb %p\n", fcb); #else - _debug_message(func, "freeing fcb %p\n", fcb); + _debug_message(func, 1, "freeing fcb %p\n", fcb); #endif #endif } @@ -1964,13 +1964,10 @@ static NTSTATUS STDCALL close_file(device_extension* Vcb, PFILE_OBJECT FileObjec ExFreePool(ccb); } - if (fcb->refcount == 1) - CcUninitializeCacheMap(FileObject, NULL, NULL); + CcUninitializeCacheMap(FileObject, NULL, NULL); free_fcb(fcb); - FileObject->FsContext = NULL; - return STATUS_SUCCESS; } @@ -2072,6 +2069,9 @@ static NTSTATUS STDCALL drv_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) IoRemoveShareAccess(FileObject, &fcb->share_access); oc = InterlockedDecrement(&fcb->open_count); +#ifdef DEBUG_FCB_REFCOUNTS + ERR("fcb %p: open_count now %i\n", fcb, oc); +#endif if (oc == 0) { if (fcb->delete_on_close && fcb != fcb->Vcb->root_fcb && fcb != fcb->Vcb->volume_fcb) { @@ -2115,11 +2115,11 @@ static NTSTATUS STDCALL drv_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n", FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); } + + if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb) + CcUninitializeCacheMap(FileObject, NULL, NULL); } - if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb) - CcUninitializeCacheMap(FileObject, NULL, NULL); - FileObject->Flags |= FO_CLEANUP_COMPLETE; } @@ -3029,12 +3029,23 @@ void protect_superblocks(device_extension* Vcb, chunk* c) { for (j = 0; j < ci->num_stripes; j++) { if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { + UINT32 size; + TRACE("cut out superblock in chunk %llx\n", c->offset); addr = (superblock_addrs[i] - cis[j].offset) + c->offset; TRACE("addr %llx\n", addr); - add_to_space_list(c, addr, sizeof(superblock), SPACE_TYPE_USED); + // This prevents trees from spanning a stripe boundary, which btrfs check complains + // about. It also prevents the chunk tree being placed at 0x11000, which for some + // reason makes the FS unmountable on Linux (it tries to read 0x10000, i.e. the + // superblock, instead). + if (ci->type & BLOCK_FLAG_SYSTEM || ci->type & BLOCK_FLAG_METADATA) + size = max(sizeof(superblock), Vcb->superblock.node_size); + else + size = sizeof(superblock); + + add_to_space_list(c, addr, size, SPACE_TYPE_USED); } } diff --git a/reactos/drivers/filesystems/btrfs/btrfs_drv.h b/reactos/drivers/filesystems/btrfs/btrfs_drv.h index 8eec01b864a..df44b609b12 100644 --- a/reactos/drivers/filesystems/btrfs/btrfs_drv.h +++ b/reactos/drivers/filesystems/btrfs/btrfs_drv.h @@ -204,6 +204,7 @@ typedef struct _tree { // UINT8 level; tree_header header; LONG refcount; + BOOL has_address; UINT32 size; struct _device_extension* Vcb; struct _tree* parent; @@ -213,6 +214,7 @@ typedef struct _tree { LIST_ENTRY itemlist; LIST_ENTRY list_entry; UINT64 new_address; + BOOL has_new_address; UINT64 flags; } tree; diff --git a/reactos/drivers/filesystems/btrfs/btrfsioctl.h b/reactos/drivers/filesystems/btrfs/btrfsioctl.h new file mode 100644 index 00000000000..c1171a31632 --- /dev/null +++ b/reactos/drivers/filesystems/btrfs/btrfsioctl.h @@ -0,0 +1,12 @@ +#ifndef BTRFSIOCTL_H_DEFINED +#define BTRFSIOCTL_H_DEFINED + +#define FSCTL_BTRFS_GET_FILE_IDS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x829, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) + +typedef struct { + UINT64 subvol; + UINT64 inode; + BOOL top; +} btrfs_get_file_ids; + +#endif diff --git a/reactos/drivers/filesystems/btrfs/cache.c b/reactos/drivers/filesystems/btrfs/cache.c index de6cfa6a6a9..2a6ba4d054e 100644 --- a/reactos/drivers/filesystems/btrfs/cache.c +++ b/reactos/drivers/filesystems/btrfs/cache.c @@ -26,7 +26,10 @@ static BOOLEAN STDCALL acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) { TRACE("(%p, %u)\n", Context, Wait); - if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE) +// if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE) +// return FALSE; + + if (!ExAcquireResourceSharedLite(fcb->Header.PagingIoResource, Wait)) return FALSE; fcb->lazy_writer_thread = KeGetCurrentThread(); @@ -40,10 +43,12 @@ static void STDCALL release_from_lazy_write(PVOID Context) { TRACE("(%p)\n", Context); - if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE) - return; +// if (!fcb || FileObject->Flags & FO_CLEANUP_COMPLETE) +// return; fcb->lazy_writer_thread = NULL; + + ExReleaseResourceLite(fcb->Header.PagingIoResource); } static BOOLEAN STDCALL acquire_for_read_ahead(PVOID Context, BOOLEAN Wait) { diff --git a/reactos/drivers/filesystems/btrfs/create.c b/reactos/drivers/filesystems/btrfs/create.c index a1106f7f7ed..3756bdf4e94 100644 --- a/reactos/drivers/filesystems/btrfs/create.c +++ b/reactos/drivers/filesystems/btrfs/create.c @@ -648,6 +648,7 @@ static NTSTATUS split_path(PUNICODE_STRING path, UNICODE_STRING** parts, ULONG* static fcb* search_fcb_children(fcb* dir, PUNICODE_STRING name) { LIST_ENTRY* le; fcb *c, *deleted = NULL; + ULONG rc; le = dir->children.Flink; while (le != &dir->children) { @@ -657,9 +658,9 @@ static fcb* search_fcb_children(fcb* dir, PUNICODE_STRING name) { if (c->deleted) { deleted = c; } else { - c->refcount++; + rc = InterlockedIncrement(&c->refcount); #ifdef DEBUG_FCB_REFCOUNTS - WARN("fcb %p: refcount now %i (%.*S)\n", c, c->refcount, c->full_filename.Length / sizeof(WCHAR), c->full_filename.Buffer); + WARN("fcb %p: refcount now %i (%.*S)\n", c, rc, c->full_filename.Length / sizeof(WCHAR), c->full_filename.Buffer); #endif return c; } @@ -668,20 +669,27 @@ static fcb* search_fcb_children(fcb* dir, PUNICODE_STRING name) { le = le->Flink; } + if (deleted) { + rc = InterlockedIncrement(&deleted->refcount); +#ifdef DEBUG_FCB_REFCOUNTS + WARN("fcb %p: refcount now %i (%.*S)\n", deleted, rc, deleted->full_filename.Length / sizeof(WCHAR), deleted->full_filename.Buffer); +#endif + } + return deleted; } -#ifdef DEBUG_FCB_REFCOUNTS -static void print_fcbs(device_extension* Vcb) { - fcb* fcb = Vcb->fcbs; - - while (fcb) { - ERR("fcb %p (%.*S): refcount %u\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb->refcount); - - fcb = fcb->next; - } -} -#endif +// #ifdef DEBUG_FCB_REFCOUNTS +// static void print_fcbs(device_extension* Vcb) { +// fcb* fcb = Vcb->fcbs; +// +// while (fcb) { +// ERR("fcb %p (%.*S): refcount %u\n", fcb, fcb->full_filename.Length / sizeof(WCHAR), fcb->full_filename.Buffer, fcb->refcount); +// +// fcb = fcb->next; +// } +// } +// #endif NTSTATUS get_fcb(device_extension* Vcb, fcb** pfcb, PUNICODE_STRING fnus, fcb* relatedfcb, BOOL parent) { fcb *dir, *sf, *sf2; @@ -693,9 +701,9 @@ NTSTATUS get_fcb(device_extension* Vcb, fcb** pfcb, PUNICODE_STRING fnus, fcb* r TRACE("(%p, %p, %.*S, %p, %s)\n", Vcb, pfcb, fnus->Length / sizeof(WCHAR), fnus->Buffer, relatedfcb, parent ? "TRUE" : "FALSE"); -#ifdef DEBUG_FCB_REFCOUNTS - print_fcbs(Vcb); -#endif +// #ifdef DEBUG_FCB_REFCOUNTS +// print_fcbs(Vcb); +// #endif fnus2 = *fnus; @@ -713,10 +721,12 @@ NTSTATUS get_fcb(device_extension* Vcb, fcb** pfcb, PUNICODE_STRING fnus, fcb* r } if (fnus2.Length == sizeof(WCHAR)) { + LONG rc; + *pfcb = Vcb->root_fcb; - Vcb->root_fcb->refcount++; + rc = InterlockedIncrement(&Vcb->root_fcb->refcount); #ifdef DEBUG_FCB_REFCOUNTS - WARN("fcb %p: refcount now %i (root)\n", Vcb->root_fcb, Vcb->root_fcb->refcount); + WARN("fcb %p: refcount now %i (root)\n", Vcb->root_fcb, rc); #endif return STATUS_SUCCESS; } @@ -1028,9 +1038,9 @@ end2: if (parts) ExFreePool(parts); -#ifdef DEBUG_FCB_REFCOUNTS - print_fcbs(Vcb); -#endif +// #ifdef DEBUG_FCB_REFCOUNTS +// print_fcbs(Vcb); +// #endif TRACE("returning %08x\n", Status); @@ -1064,6 +1074,7 @@ static NTSTATUS STDCALL file_create2(PIRP Irp, device_extension* Vcb, PUNICODE_S PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); ANSI_STRING utf8as; ULONG defda; + LONG rc; Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fpus->Buffer, fpus->Length); if (!NT_SUCCESS(Status)) @@ -1281,9 +1292,9 @@ static NTSTATUS STDCALL file_create2(PIRP Irp, device_extension* Vcb, PUNICODE_S fcb->delete_on_close = TRUE; fcb->par = parfcb; - parfcb->refcount++; + rc = InterlockedIncrement(&parfcb->refcount); #ifdef DEBUG_FCB_REFCOUNTS - WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, parfcb->refcount, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer); + WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, rc, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer); #endif fcb->subvol = parfcb->subvol; fcb->inode = inode; @@ -1355,6 +1366,7 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC ccb* ccb; static WCHAR datasuf[] = {':','$','D','A','T','A',0}; UNICODE_STRING dsus, fpus, stream; + LONG oc; TRACE("(%p, %p, %p, %.*S, %x, %x)\n", Irp, Vcb, FileObject, fnus->Length / sizeof(WCHAR), fnus->Buffer, disposition, options); @@ -1444,6 +1456,7 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC KEY searchkey; traverse_ptr tp; INODE_ITEM* ii; + LONG rc; TRACE("fpus = %.*S\n", fpus.Length / sizeof(WCHAR), fpus.Buffer); TRACE("stream = %.*S\n", stream.Length / sizeof(WCHAR), stream.Buffer); @@ -1497,9 +1510,9 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC fcb->delete_on_close = TRUE; fcb->par = parfcb; - parfcb->refcount++; + rc = InterlockedIncrement(&parfcb->refcount); #ifdef DEBUG_FCB_REFCOUNTS - WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, parfcb->refcount, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer); + WARN("fcb %p: refcount now %i (%.*S)\n", parfcb, rc, parfcb->full_filename.Length / sizeof(WCHAR), parfcb->full_filename.Buffer); #endif fcb->subvol = parfcb->subvol; fcb->inode = parfcb->inode; @@ -1658,7 +1671,10 @@ static NTSTATUS STDCALL file_create(PIRP Irp, device_extension* Vcb, PFILE_OBJEC ccb->has_wildcard = FALSE; ccb->specific_file = FALSE; - InterlockedIncrement(&fcb->open_count); + oc = InterlockedIncrement(&fcb->open_count); +#ifdef DEBUG_FCB_REFCOUNTS + ERR("fcb %p: open_count now %i\n", fcb, oc); +#endif FileObject->FsContext2 = ccb; @@ -1884,6 +1900,7 @@ static NTSTATUS STDCALL create_file(PDEVICE_OBJECT DeviceObject, PIRP Irp, LIST_ PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); ULONG access; PACCESS_STATE access_state = Stack->Parameters.Create.SecurityContext->AccessState; + LONG oc; Irp->IoStatus.Information = 0; @@ -1948,6 +1965,7 @@ static NTSTATUS STDCALL create_file(PDEVICE_OBJECT DeviceObject, PIRP Irp, LIST_ if (NT_SUCCESS(Status) && fcb->deleted) { free_fcb(fcb); Status = STATUS_OBJECT_NAME_NOT_FOUND; + goto exit; } if (NT_SUCCESS(Status)) { @@ -2217,7 +2235,10 @@ static NTSTATUS STDCALL create_file(PDEVICE_OBJECT DeviceObject, PIRP Irp, LIST_ } } - InterlockedIncrement(&fcb->open_count); + oc = InterlockedIncrement(&fcb->open_count); +#ifdef DEBUG_FCB_REFCOUNTS + ERR("fcb %p: open_count now %i\n", fcb, oc); +#endif } else { Status = file_create(Irp, DeviceObject->DeviceExtension, FileObject, &FileObject->FileName, RequestedDisposition, options, rollback); Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0; @@ -2316,6 +2337,7 @@ NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { if (IrpSp->FileObject->FileName.Length == 0 && !IrpSp->FileObject->RelatedFileObject) { ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff); ULONG RequestedOptions = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; + LONG rc, oc; TRACE("open operation for volume\n"); @@ -2332,14 +2354,18 @@ NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { goto exit; } - Vcb->volume_fcb->refcount++; + rc = InterlockedIncrement(&Vcb->volume_fcb->refcount); + oc = InterlockedIncrement(&Vcb->volume_fcb->open_count); #ifdef DEBUG_FCB_REFCOUNTS - WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, Vcb->volume_fcb->refcount); + WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, rc); + WARN("fcb %p: open_count now %i (volume)\n", Vcb->volume_fcb, oc); #endif attach_fcb_to_fileobject(Vcb, Vcb->volume_fcb, IrpSp->FileObject); // // NtfsAttachFCBToFileObject(DeviceExt, DeviceExt->VolumeFcb, FileObject); // // DeviceExt->VolumeFcb->RefCount++; -// + + IrpSp->FileObject->SectionObjectPointer = &Vcb->volume_fcb->nonpaged->segment_object; + Irp->IoStatus.Information = FILE_OPENED; Status = STATUS_SUCCESS; } else { diff --git a/reactos/drivers/filesystems/btrfs/fastio.c b/reactos/drivers/filesystems/btrfs/fastio.c index acb13a1b922..f895fedc1c1 100644 --- a/reactos/drivers/filesystems/btrfs/fastio.c +++ b/reactos/drivers/filesystems/btrfs/fastio.c @@ -137,22 +137,58 @@ static NTSTATUS STDCALL fast_io_release_for_mod_write(PFILE_OBJECT FileObject, s static NTSTATUS STDCALL fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject){ TRACE("STUB: fast_io_acquire_for_ccflush\n"); - return STATUS_NOT_IMPLEMENTED; + return STATUS_SUCCESS; } static NTSTATUS STDCALL fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject){ TRACE("STUB: fast_io_release_for_ccflush\n"); - return STATUS_NOT_IMPLEMENTED; + return STATUS_SUCCESS; } +#ifdef DEBUG +static BOOLEAN STDCALL fast_io_read(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { + TRACE("(%p, %p, %x, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); + + return FsRtlCopyRead(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); +} + +static BOOLEAN STDCALL fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { + TRACE("(%p, %p, %x, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); + + return FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); +} + +static BOOLEAN STDCALL fast_io_mdl_read(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PMDL* MdlChain, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { + TRACE("(%p, %p, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject); + + return FsRtlMdlReadDev(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject); +} + +static BOOLEAN STDCALL fast_io_mdl_read_complete(PFILE_OBJECT FileObject, PMDL* MdlChain, PDEVICE_OBJECT DeviceObject) { + TRACE("(%p, %p, %p)\n", FileObject, MdlChain, DeviceObject); + + return FsRtlMdlReadCompleteDev(FileObject, MdlChain, DeviceObject); +} + +static BOOLEAN STDCALL fast_io_prepare_mdl_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PMDL* MdlChain, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { + TRACE("(%p, %p, %x, %x, %p, %p, %p)\n", FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject); + + return FsRtlPrepareMdlWriteDev(FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus, DeviceObject); +} + +static BOOLEAN STDCALL fast_io_mdl_write_complete(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PMDL* MdlChain, PDEVICE_OBJECT DeviceObject) { + TRACE("(%p, %p, %p, %p)\n", FileObject, FileOffset, MdlChain, DeviceObject); + + return FsRtlMdlWriteCompleteDev(FileObject, FileOffset, MdlChain, DeviceObject); +} +#endif + void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) { RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch)); FastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); FastIoDispatch.FastIoCheckIfPossible = fast_io_check_if_possible; - FastIoDispatch.FastIoRead = FsRtlCopyRead; - FastIoDispatch.FastIoWrite = FsRtlCopyWrite; FastIoDispatch.FastIoQueryBasicInfo = fast_query_basic_info; FastIoDispatch.FastIoQueryStandardInfo = fast_query_standard_info; FastIoDispatch.FastIoLock = fast_io_lock; @@ -165,10 +201,6 @@ void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) { FastIoDispatch.FastIoDetachDevice = fast_io_detach_device; FastIoDispatch.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info; FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write; - FastIoDispatch.MdlRead = FsRtlMdlReadDev; - FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev; - FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev; - FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev; FastIoDispatch.FastIoReadCompressed = fast_io_read_compressed; FastIoDispatch.FastIoWriteCompressed = fast_io_write_compressed; FastIoDispatch.MdlReadCompleteCompressed = fast_io_mdl_read_complete_compressed; @@ -178,5 +210,21 @@ void __stdcall init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) { FastIoDispatch.AcquireForCcFlush = fast_io_acquire_for_ccflush; FastIoDispatch.ReleaseForCcFlush = fast_io_release_for_ccflush; +#ifdef DEBUG + FastIoDispatch.FastIoRead = fast_io_read; + FastIoDispatch.FastIoWrite = fast_io_write; + FastIoDispatch.MdlRead = fast_io_mdl_read; + FastIoDispatch.MdlReadComplete = fast_io_mdl_read_complete; + FastIoDispatch.PrepareMdlWrite = fast_io_prepare_mdl_write; + FastIoDispatch.MdlWriteComplete = fast_io_mdl_write_complete; +#else + FastIoDispatch.FastIoRead = FsRtlCopyRead; + FastIoDispatch.FastIoWrite = FsRtlCopyWrite; + FastIoDispatch.MdlRead = FsRtlMdlReadDev; + FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev; + FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev; + FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev; +#endif + *fiod = &FastIoDispatch; -} \ No newline at end of file +} diff --git a/reactos/drivers/filesystems/btrfs/fileinfo.c b/reactos/drivers/filesystems/btrfs/fileinfo.c index 9f6e54f41fe..e21c88b0bf9 100644 --- a/reactos/drivers/filesystems/btrfs/fileinfo.c +++ b/reactos/drivers/filesystems/btrfs/fileinfo.c @@ -2194,7 +2194,7 @@ NTSTATUS STDCALL drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp break; case FileRemoteProtocolInformation: - FIXME("STUB: FileRemoteProtocolInformation\n"); + TRACE("FileRemoteProtocolInformation\n"); break; #endif @@ -2884,7 +2884,7 @@ static NTSTATUS STDCALL query_info(device_extension* Vcb, PFILE_OBJECT FileObjec } case FileRemoteProtocolInformation: - FIXME("STUB: FileRemoteProtocolInformation\n"); + TRACE("FileRemoteProtocolInformation\n"); Status = STATUS_INVALID_PARAMETER; goto exit; #endif diff --git a/reactos/drivers/filesystems/btrfs/fsctl.c b/reactos/drivers/filesystems/btrfs/fsctl.c index 9405e7287e7..9afacee9d39 100644 --- a/reactos/drivers/filesystems/btrfs/fsctl.c +++ b/reactos/drivers/filesystems/btrfs/fsctl.c @@ -16,11 +16,36 @@ * along with WinBtrfs. If not, see . */ #include "btrfs_drv.h" +#include "btrfsioctl.h" #ifndef FSCTL_CSV_CONTROL #define FSCTL_CSV_CONTROL CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 181, METHOD_BUFFERED, FILE_ANY_ACCESS) #endif +static NTSTATUS get_file_ids(PFILE_OBJECT FileObject, void* data, ULONG length) { + btrfs_get_file_ids* bgfi; + fcb* fcb; + + if (length < sizeof(btrfs_get_file_ids)) + return STATUS_BUFFER_OVERFLOW; + + if (!FileObject) + return STATUS_INVALID_PARAMETER; + + fcb = FileObject->FsContext; + + if (!fcb) + return STATUS_INVALID_PARAMETER; + + bgfi = data; + + bgfi->subvol = fcb->subvol->id; + bgfi->inode = fcb->inode; + bgfi->top = fcb->Vcb->root_fcb == fcb ? TRUE : FALSE; + + return STATUS_SUCCESS; +} + NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); NTSTATUS Status; @@ -496,6 +521,9 @@ NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL Status = STATUS_NOT_IMPLEMENTED; break; #endif + case FSCTL_BTRFS_GET_FILE_IDS: + Status = get_file_ids(IrpSp->FileObject, map_user_buffer(Irp), IrpSp->Parameters.DeviceIoControl.OutputBufferLength); + break; default: WARN("unknown control code %x (DeviceType = %x, Access = %x, Function = %x, Method = %x)\n", diff --git a/reactos/drivers/filesystems/btrfs/read.c b/reactos/drivers/filesystems/btrfs/read.c index 1b460344d40..16e045f82ca 100644 --- a/reactos/drivers/filesystems/btrfs/read.c +++ b/reactos/drivers/filesystems/btrfs/read.c @@ -368,6 +368,9 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI // } do { + UINT64 len; + EXTENT_DATA2* ed2; + ed = (EXTENT_DATA*)tp.item->data; if (tp.item->size < sizeof(EXTENT_DATA)) { @@ -384,7 +387,11 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI goto exit; } - if (tp.item->key.offset + ed->decoded_size < start) { + ed2 = (EXTENT_DATA2*)ed->data; + + len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes; + + if (tp.item->key.offset + len < start) { ERR("Tried to read beyond end of file\n"); free_traverse_ptr(&tp); Status = STATUS_END_OF_FILE; @@ -416,9 +423,8 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI case EXTENT_TYPE_INLINE: { UINT64 off = start + bytes_read - tp.item->key.offset; - UINT64 read; + UINT64 read = len - off; - read = ed->decoded_size - off; if (read > length) read = length; RtlCopyMemory(data + bytes_read, &ed->data[off], read); @@ -430,12 +436,11 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI case EXTENT_TYPE_REGULAR: { - EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data; UINT64 off = start + bytes_read - tp.item->key.offset; UINT32 to_read, read; UINT8* buf; - read = ed->decoded_size - off; + read = len - off; if (read > length) read = length; if (ed2->address == 0) { @@ -476,9 +481,8 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI case EXTENT_TYPE_PREALLOC: { UINT64 off = start + bytes_read - tp.item->key.offset; - UINT32 read; + UINT32 read = len - off; - read = ed->decoded_size - off; if (read > length) read = length; RtlZeroMemory(data + bytes_read, read); @@ -503,7 +507,7 @@ NTSTATUS STDCALL read_file(device_extension* Vcb, root* subvol, UINT64 inode, UI break; else if (next_tp.item->key.obj_id != inode || next_tp.item->key.obj_type != TYPE_EXTENT_DATA || - next_tp.item->key.offset != tp.item->key.offset + ed->decoded_size + next_tp.item->key.offset != tp.item->key.offset + len ) { free_traverse_ptr(&next_tp); break; diff --git a/reactos/drivers/filesystems/btrfs/treefuncs.c b/reactos/drivers/filesystems/btrfs/treefuncs.c index e5b5ac60587..ecaf18ae713 100644 --- a/reactos/drivers/filesystems/btrfs/treefuncs.c +++ b/reactos/drivers/filesystems/btrfs/treefuncs.c @@ -386,6 +386,7 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** // t->address = addr; // t->level = th->level; t->refcount = 1; + t->has_address = TRUE; t->Vcb = Vcb; t->parent = NULL; t->root = r; @@ -393,6 +394,7 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** t->paritem = NULL; t->size = 0; t->new_address = 0; + t->has_new_address = FALSE; #ifdef DEBUG_TREE_REFCOUNTS #ifdef DEBUG_LONG_MESSAGES _debug_message(func, file, line, "loaded tree %p (%llx)\n", t, addr); @@ -698,11 +700,20 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver } if (t->header.level == 0 && cmp == 0 && !ignore && td && td->ignore) { + tree_data* origtd = td; + while (td && td->ignore) td = next_item(t, td); - if (td) + if (td) { cmp = keycmp(searchkey, &td->key); + + if (cmp != 0) { + td = origtd; + cmp = 0; + } + } else + td = origtd; } } while (td && cmp == 1); diff --git a/reactos/drivers/filesystems/btrfs/write.c b/reactos/drivers/filesystems/btrfs/write.c index bff05188ea7..855e6b0060a 100644 --- a/reactos/drivers/filesystems/btrfs/write.c +++ b/reactos/drivers/filesystems/btrfs/write.c @@ -1093,13 +1093,13 @@ static BOOL trees_consistent(device_extension* Vcb) { tree_cache* tc2 = CONTAINING_RECORD(le, tree_cache, list_entry); if (tc2->write) { - if (tc2->tree->header.num_items == 0) + if (tc2->tree->header.num_items == 0 && tc2->tree->parent) return FALSE; if (tc2->tree->size > maxsize) return FALSE; - if (tc2->tree->new_address == 0) + if (!tc2->tree->has_new_address) return FALSE; } @@ -1263,6 +1263,7 @@ static BOOL insert_tree_extent_skinny(device_extension* Vcb, tree* t, chunk* c, free_traverse_ptr(&insert_tp); t->new_address = address; + t->has_new_address = TRUE; return TRUE; } @@ -1272,7 +1273,7 @@ static BOOL insert_tree_extent(device_extension* Vcb, tree* t, chunk* c, LIST_EN EXTENT_ITEM_TREE2* eit2; traverse_ptr insert_tp; - TRACE("(%p, %p, %p, %p)\n", Vcb, t, c); + TRACE("(%p, %p, %p, %p)\n", Vcb, t, c, rollback); if (!find_address_in_chunk(Vcb, c, Vcb->superblock.node_size, &address)) return FALSE; @@ -1316,6 +1317,7 @@ static BOOL insert_tree_extent(device_extension* Vcb, tree* t, chunk* c, LIST_EN free_traverse_ptr(&insert_tp); t->new_address = address; + t->has_new_address = TRUE; return TRUE; } @@ -1341,7 +1343,7 @@ static NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, LIST_ENTRY* // } // } - if (t->header.address != 0) { + if (t->has_address) { origchunk = get_chunk_from_address(Vcb, t->header.address); if (insert_tree_extent(Vcb, t, origchunk, rollback)) @@ -1384,7 +1386,7 @@ static BOOL reduce_tree_extent_skinny(device_extension* Vcb, UINT64 address, tre searchkey.obj_id = address; searchkey.obj_type = TYPE_METADATA_ITEM; - searchkey.offset = t->header.level; + searchkey.offset = 0xffffffffffffffff; Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE); if (!NT_SUCCESS(Status)) { @@ -1392,7 +1394,7 @@ static BOOL reduce_tree_extent_skinny(device_extension* Vcb, UINT64 address, tre return FALSE; } - if (keycmp(&tp.item->key, &searchkey)) { + if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) { TRACE("could not find %llx,%x,%llx in extent_root\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset); free_traverse_ptr(&tp); return FALSE; @@ -1765,7 +1767,7 @@ static NTSTATUS allocate_tree_extents(device_extension* Vcb, LIST_ENTRY* rollbac while (le != &Vcb->tree_cache) { tree_cache* tc2 = CONTAINING_RECORD(le, tree_cache, list_entry); - if (tc2->write && tc2->tree->new_address == 0) { + if (tc2->write && !tc2->tree->has_new_address) { chunk* c; Status = get_tree_new_address(Vcb, tc2->tree, rollback); @@ -1776,7 +1778,7 @@ static NTSTATUS allocate_tree_extents(device_extension* Vcb, LIST_ENTRY* rollbac TRACE("allocated extent %llx\n", tc2->tree->new_address); - if (tc2->tree->header.address != 0) { + if (tc2->tree->has_address) { Status = reduce_tree_extent(Vcb, tc2->tree->header.address, tc2->tree, rollback); if (!NT_SUCCESS(Status)) { @@ -2088,7 +2090,7 @@ static NTSTATUS write_trees(device_extension* Vcb) { traverse_ptr tp; EXTENT_ITEM_TREE* eit; - if (tc2->tree->new_address == 0) { + if (!tc2->tree->has_new_address) { ERR("error - tried to write tree with no new address\n"); int3; } @@ -2226,13 +2228,8 @@ static NTSTATUS write_trees(device_extension* Vcb) { crash = TRUE; } - if (tc2->tree->new_address == 0) { - ERR("tree %llx, level %x: tried to write tree to address 0\n", tc2->tree->root->id, tc2->tree->header.level); - crash = TRUE; - } - - if (tc2->tree->header.num_items == 0) { - ERR("tree %llx, level %x: tried to write empty tree\n", tc2->tree->root->id, tc2->tree->header.level); + if (tc2->tree->header.num_items == 0 && tc2->tree->parent) { + ERR("tree %llx, level %x: tried to write empty tree with parent\n", tc2->tree->root->id, tc2->tree->header.level); crash = TRUE; } @@ -2257,6 +2254,7 @@ static NTSTATUS write_trees(device_extension* Vcb) { tc2->tree->header.address = tc2->tree->new_address; tc2->tree->header.generation = Vcb->superblock.generation; tc2->tree->header.flags |= HEADER_FLAG_MIXED_BACKREF; + tc2->tree->has_address = TRUE; data = ExAllocatePoolWithTag(NonPagedPool, Vcb->superblock.node_size, ALLOC_TAG); if (!data) { @@ -2564,11 +2562,13 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data* nt->header.flags = HEADER_FLAG_MIXED_BACKREF; nt->refcount = 0; + nt->has_address = FALSE; nt->Vcb = Vcb; nt->parent = t->parent; nt->root = t->root; // nt->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG); nt->new_address = 0; + nt->has_new_address = FALSE; nt->flags = t->flags; InitializeListHead(&nt->itemlist); @@ -2637,6 +2637,22 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data* // // TRACE("last item is now (%x,%x,%x)\n", (UINT32)oldlastitem->key.obj_id, oldlastitem->key.obj_type, (UINT32)oldlastitem->key.offset); + if (nt->header.level > 0) { + LIST_ENTRY* le = nt->itemlist.Flink; + + while (le != &nt->itemlist) { + tree_data* td2 = CONTAINING_RECORD(le, tree_data, list_entry); + + if (td2->treeholder.tree) { + td2->treeholder.tree->parent = nt; + increase_tree_rc(nt); + free_tree(t); + } + + le = le->Flink; + } + } + if (nt->parent) { increase_tree_rc(nt->parent); @@ -2648,7 +2664,7 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data* td->key = newfirstitem->key; - InsertAfter(&t->itemlist, &td->list_entry, &t->paritem->list_entry); + InsertHeadList(&t->paritem->list_entry, &td->list_entry); td->ignore = FALSE; td->inserted = TRUE; @@ -2683,11 +2699,13 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data* pt->header.flags = HEADER_FLAG_MIXED_BACKREF; pt->refcount = 2; + pt->has_address = FALSE; pt->Vcb = Vcb; pt->parent = NULL; pt->paritem = NULL; pt->root = t->root; pt->new_address = 0; + pt->has_new_address = FALSE; // pt->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(tree_nonpaged), ALLOC_TAG); pt->size = pt->header.num_items * sizeof(internal_node); pt->flags = t->flags; @@ -2743,6 +2761,7 @@ static NTSTATUS STDCALL split_tree_at(device_extension* Vcb, tree* t, tree_data* nt->parent = pt; end: + t->root->root_item.bytes_used += Vcb->superblock.node_size; // #ifdef DEBUG_PARANOID // lastkey2.obj_id = 0xffffffffffffffff; @@ -2857,6 +2876,22 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY* t->header.num_items += next_tree->header.num_items; t->size += next_tree->size; + if (next_tree->header.level > 0) { + le = next_tree->itemlist.Flink; + + while (le != &next_tree->itemlist) { + tree_data* td2 = CONTAINING_RECORD(le, tree_data, list_entry); + + if (td2->treeholder.tree) { + td2->treeholder.tree->parent = t; + increase_tree_rc(t); + free_tree(next_tree); + } + + le = le->Flink; + } + } + t->itemlist.Blink->Flink = next_tree->itemlist.Flink; t->itemlist.Blink->Flink->Blink = t->itemlist.Blink; t->itemlist.Blink = next_tree->itemlist.Blink; @@ -2877,7 +2912,7 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY* next_tree->header.num_items = 0; next_tree->size = 0; - if (next_tree->new_address != 0) { // delete associated EXTENT_ITEM + if (next_tree->has_new_address) { // delete associated EXTENT_ITEM Status = reduce_tree_extent(Vcb, next_tree->new_address, next_tree, rollback); if (!NT_SUCCESS(Status)) { @@ -2885,7 +2920,7 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY* free_tree(next_tree); return Status; } - } else if (next_tree->header.address != 0) { + } else if (next_tree->has_address) { Status = reduce_tree_extent(Vcb, next_tree->header.address, next_tree, rollback); if (!NT_SUCCESS(Status)) { @@ -2911,6 +2946,8 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY* ExFreePool(next_tree->paritem); next_tree->paritem = NULL; + next_tree->root->root_item.bytes_used -= Vcb->superblock.node_size; + free_tree(next_tree); // remove next_tree from tree cache @@ -2951,6 +2988,12 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY* RemoveEntryList(&td->list_entry); InsertTailList(&t->itemlist, &td->list_entry); + if (next_tree->header.level > 0 && td->treeholder.tree) { + td->treeholder.tree->parent = t; + increase_tree_rc(t); + free_tree(next_tree); + } + if (!td->ignore) { next_tree->size -= size; t->size += size; @@ -2993,6 +3036,106 @@ static NTSTATUS try_tree_amalgamate(device_extension* Vcb, tree* t, LIST_ENTRY* return STATUS_SUCCESS; } +static NTSTATUS update_extent_level(device_extension* Vcb, UINT64 address, tree* t, UINT8 level, LIST_ENTRY* rollback) { + KEY searchkey; + traverse_ptr tp; + NTSTATUS Status; + + if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA) { + searchkey.obj_id = address; + searchkey.obj_type = TYPE_METADATA_ITEM; + searchkey.offset = t->header.level; + + Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE); + if (!NT_SUCCESS(Status)) { + ERR("error - find_item returned %08x\n", Status); + return Status; + } + + if (!keycmp(&tp.item->key, &searchkey)) { + EXTENT_ITEM_SKINNY_METADATA* eism; + + if (tp.item->size > 0) { + eism = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG); + + if (!eism) { + ERR("out of memory\n"); + free_traverse_ptr(&tp); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(eism, tp.item->data, tp.item->size); + } else + eism = NULL; + + delete_tree_item(Vcb, &tp, rollback); + + if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_METADATA_ITEM, level, eism, tp.item->size, NULL, rollback)) { + ERR("insert_tree_item failed\n"); + ExFreePool(eism); + free_traverse_ptr(&tp); + return STATUS_INTERNAL_ERROR; + } + + free_traverse_ptr(&tp); + return STATUS_SUCCESS; + } + + free_traverse_ptr(&tp); + } + + searchkey.obj_id = address; + searchkey.obj_type = TYPE_EXTENT_ITEM; + searchkey.offset = 0xffffffffffffffff; + + Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE); + if (!NT_SUCCESS(Status)) { + ERR("error - find_item returned %08x\n", Status); + return Status; + } + + if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) { + EXTENT_ITEM_TREE* eit; + + if (tp.item->size < sizeof(EXTENT_ITEM_TREE)) { + 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, sizeof(EXTENT_ITEM_TREE)); + free_traverse_ptr(&tp); + return STATUS_INTERNAL_ERROR; + } + + eit = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG); + + if (!eit) { + ERR("out of memory\n"); + free_traverse_ptr(&tp); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory(eit, tp.item->data, tp.item->size); + + delete_tree_item(Vcb, &tp, rollback); + + eit->level = level; + + if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, eit, tp.item->size, NULL, rollback)) { + ERR("insert_tree_item failed\n"); + ExFreePool(eit); + free_traverse_ptr(&tp); + return STATUS_INTERNAL_ERROR; + } + + free_traverse_ptr(&tp); + + return STATUS_SUCCESS; + } + + ERR("could not find EXTENT_ITEM for address %llx\n", address); + + free_traverse_ptr(&tp); + + return STATUS_INTERNAL_ERROR; +} + static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) { // LIST_ENTRY *le, *le2; // write_tree* wt; @@ -3025,38 +3168,39 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) { empty = FALSE; if (tc2->tree->header.num_items == 0) { - LIST_ENTRY* le2; - KEY firstitem = {0xcccccccccccccccc,0xcc,0xcccccccccccccccc}; - - done_deletions = TRUE; - - le2 = tc2->tree->itemlist.Flink; - while (le2 != &tc2->tree->itemlist) { - tree_data* td = CONTAINING_RECORD(le2, tree_data, list_entry); - firstitem = td->key; - break; - } - - ERR("deleting tree in root %llx (first item was %llx,%x,%llx)\n", - tc2->tree->root->id, firstitem.obj_id, firstitem.obj_type, firstitem.offset); - - if (tc2->tree->new_address != 0) { // delete associated EXTENT_ITEM - Status = reduce_tree_extent(Vcb, tc2->tree->new_address, tc2->tree, rollback); - - if (!NT_SUCCESS(Status)) { - ERR("reduce_tree_extent returned %08x\n", Status); - return Status; - } - } else if (tc2->tree->header.address != 0) { - Status = reduce_tree_extent(Vcb,tc2->tree->header.address, tc2->tree, rollback); - - if (!NT_SUCCESS(Status)) { - ERR("reduce_tree_extent returned %08x\n", Status); - return Status; - } - } - if (tc2->tree->parent) { + LIST_ENTRY* le2; + KEY firstitem = {0xcccccccccccccccc,0xcc,0xcccccccccccccccc}; + + done_deletions = TRUE; + + le2 = tc2->tree->itemlist.Flink; + while (le2 != &tc2->tree->itemlist) { + tree_data* td = CONTAINING_RECORD(le2, tree_data, list_entry); + firstitem = td->key; + break; + } + TRACE("deleting tree in root %llx (first item was %llx,%x,%llx)\n", + tc2->tree->root->id, firstitem.obj_id, firstitem.obj_type, firstitem.offset); + + tc2->tree->root->root_item.bytes_used -= Vcb->superblock.node_size; + + if (tc2->tree->has_new_address) { // delete associated EXTENT_ITEM + Status = reduce_tree_extent(Vcb, tc2->tree->new_address, tc2->tree, rollback); + + if (!NT_SUCCESS(Status)) { + ERR("reduce_tree_extent returned %08x\n", Status); + return Status; + } + } else if (tc2->tree->has_address) { + Status = reduce_tree_extent(Vcb,tc2->tree->header.address, tc2->tree, rollback); + + if (!NT_SUCCESS(Status)) { + ERR("reduce_tree_extent returned %08x\n", Status); + return Status; + } + } + if (!tc2->tree->paritem->ignore) { tc2->tree->paritem->ignore = TRUE; tc2->tree->parent->header.num_items--; @@ -3071,19 +3215,25 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) { RemoveEntryList(le); ExFreePool(tc2); - } else { - FIXME("trying to delete top root, not sure what to do here\n"); // FIXME - return STATUS_INTERNAL_ERROR; - } - } else { - if (tc2->tree->size > Vcb->superblock.node_size - sizeof(tree_header)) { - TRACE("splitting overlarge tree (%x > %x)\n", tc2->tree->size, Vcb->superblock.node_size - sizeof(tree_header)); - Status = split_tree(Vcb, tc2->tree); - - if (!NT_SUCCESS(Status)) { - ERR("split_tree returned %08x\n", Status); - return Status; + } else if (tc2->tree->header.level != 0) { + if (tc2->tree->has_new_address) { + Status = update_extent_level(Vcb, tc2->tree->new_address, tc2->tree, 0, rollback); + + if (!NT_SUCCESS(Status)) { + ERR("update_extent_level returned %08x\n", Status); + return Status; + } } + + tc2->tree->header.level = 0; + } + } else if (tc2->tree->size > Vcb->superblock.node_size - sizeof(tree_header)) { + TRACE("splitting overlarge tree (%x > %x)\n", tc2->tree->size, Vcb->superblock.node_size - sizeof(tree_header)); + Status = split_tree(Vcb, tc2->tree); + + if (!NT_SUCCESS(Status)) { + ERR("split_tree returned %08x\n", Status); + return Status; } } } @@ -3145,16 +3295,16 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) { le2 = le2->Flink; } - ERR("deleting top-level tree in root %llx with one item\n", tc2->tree->root->id); + TRACE("deleting top-level tree in root %llx with one item\n", tc2->tree->root->id); - if (tc2->tree->new_address != 0) { // delete associated EXTENT_ITEM + if (tc2->tree->has_new_address) { // delete associated EXTENT_ITEM Status = reduce_tree_extent(Vcb, tc2->tree->new_address, tc2->tree, rollback); if (!NT_SUCCESS(Status)) { ERR("reduce_tree_extent returned %08x\n", Status); return Status; } - } else if (tc2->tree->header.address != 0) { + } else if (tc2->tree->has_address) { Status = reduce_tree_extent(Vcb,tc2->tree->header.address, tc2->tree, rollback); if (!NT_SUCCESS(Status)) { @@ -3180,8 +3330,11 @@ static NTSTATUS STDCALL do_splits(device_extension* Vcb, LIST_ENTRY* rollback) { if (child_tree) { child_tree->parent = NULL; + child_tree->paritem = NULL; free_tree(tc2->tree); } + + tc2->tree->root->root_item.bytes_used -= Vcb->superblock.node_size; free_tree(tc2->tree); @@ -3208,7 +3361,7 @@ NTSTATUS STDCALL do_write(device_extension* Vcb, LIST_ENTRY* rollback) { TRACE("(%p)\n", Vcb); // If only changing superblock, e.g. changing label, we still need to rewrite - // the root tree so the generations mach. Otherwise you won't be able to mount on Linux. + // the root tree so the generations match, otherwise you won't be able to mount on Linux. if (Vcb->write_trees > 0) { KEY searchkey; traverse_ptr tp; @@ -4236,6 +4389,8 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT do { EXTENT_DATA* ed = (EXTENT_DATA*)tp.item->data; + EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data; + UINT64 len; if (tp.item->size < sizeof(EXTENT_DATA)) { 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, sizeof(EXTENT_DATA)); @@ -4251,7 +4406,9 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT b = find_next_item(Vcb, &tp, &next_tp, FALSE); - if (tp.item->key.offset < end_data && tp.item->key.offset + ed->decoded_size >= start_data) { + len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes; + + if (tp.item->key.offset < end_data && tp.item->key.offset + len >= start_data) { if (ed->compression != BTRFS_COMPRESSION_NONE) { FIXME("FIXME - compression not supported at present\n"); Status = STATUS_NOT_SUPPORTED; @@ -4270,20 +4427,18 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT goto end; } - // FIXME - is ed->decoded_size the size of the whole extent, or just this bit of it? - if (ed->type == EXTENT_TYPE_INLINE) { - if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove all + if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove all delete_tree_item(Vcb, &tp, rollback); - fcb->inode_item.st_blocks -= ed->decoded_size; - } else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove beginning + fcb->inode_item.st_blocks -= len; + } else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove beginning EXTENT_DATA* ned; UINT64 size; delete_tree_item(Vcb, &tp, rollback); - size = ed->decoded_size - (end_data - tp.item->key.offset); + size = len - (end_data - tp.item->key.offset); ned = ExAllocatePoolWithTag(PagedPool, sizeof(EXTENT_DATA) - 1 + size, ALLOC_TAG); if (!ned) { @@ -4309,7 +4464,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT } fcb->inode_item.st_blocks -= end_data - tp.item->key.offset; - } else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove end + } else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove end EXTENT_DATA* ned; UINT64 size; @@ -4340,8 +4495,8 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT goto end; } - fcb->inode_item.st_blocks -= tp.item->key.offset + ed->decoded_size - start_data; - } else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove middle + fcb->inode_item.st_blocks -= tp.item->key.offset + len - start_data; + } else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove middle EXTENT_DATA* ned; UINT64 size; @@ -4372,7 +4527,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT goto end; } - size = tp.item->key.offset + ed->decoded_size - end_data; + size = tp.item->key.offset + len - end_data; ned = ExAllocatePoolWithTag(PagedPool, sizeof(EXTENT_DATA) - 1 + size, ALLOC_TAG); if (!ned) { @@ -4400,39 +4555,24 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT fcb->inode_item.st_blocks -= end_data - start_data; } } else if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) { - EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ed->data[0]; - - if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove all + if (start_data <= tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove all if (ed2->address != 0) { - Status = remove_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, tp.item->key.offset, changed_sector_list, rollback); + Status = remove_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, tp.item->key.offset - ed2->offset, changed_sector_list, rollback); if (!NT_SUCCESS(Status)) { ERR("remove_extent_ref returned %08x\n", Status); goto end; } - fcb->inode_item.st_blocks -= ed->decoded_size; + fcb->inode_item.st_blocks -= len; } delete_tree_item(Vcb, &tp, rollback); - } else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove beginning + } else if (start_data <= tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove beginning EXTENT_DATA* ned; EXTENT_DATA2* ned2; - if (ed2->address != 0) { - Status = add_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, end_data, rollback); - if (!NT_SUCCESS(Status)) { - ERR("add_extent_ref returned %08x\n", Status); - goto end; - } - - Status = remove_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, tp.item->key.offset, changed_sector_list, rollback); - if (!NT_SUCCESS(Status)) { - ERR("remove_extent_ref returned %08x\n", Status); - goto end; - } - + if (ed2->address != 0) fcb->inode_item.st_blocks -= end_data - tp.item->key.offset; - } delete_tree_item(Vcb, &tp, rollback); @@ -4446,7 +4586,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT ned2 = (EXTENT_DATA2*)&ned->data[0]; ned->generation = Vcb->superblock.generation; - ned->decoded_size = ed->decoded_size - (end_data - tp.item->key.offset); + ned->decoded_size = ed->decoded_size; ned->compression = ed->compression; ned->encryption = ed->encryption; ned->encoding = ed->encoding; @@ -4462,12 +4602,12 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT Status = STATUS_INTERNAL_ERROR; goto end; } - } else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + ed->decoded_size) { // remove end + } else if (start_data > tp.item->key.offset && end_data >= tp.item->key.offset + len) { // remove end EXTENT_DATA* ned; EXTENT_DATA2* ned2; if (ed2->address != 0) - fcb->inode_item.st_blocks -= tp.item->key.offset + ed->decoded_size - start_data; + fcb->inode_item.st_blocks -= tp.item->key.offset + len - start_data; delete_tree_item(Vcb, &tp, rollback); @@ -4481,7 +4621,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT ned2 = (EXTENT_DATA2*)&ned->data[0]; ned->generation = Vcb->superblock.generation; - ned->decoded_size = start_data - tp.item->key.offset; + ned->decoded_size = ed->decoded_size; ned->compression = ed->compression; ned->encryption = ed->encryption; ned->encoding = ed->encoding; @@ -4497,19 +4637,12 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT Status = STATUS_INTERNAL_ERROR; goto end; } - } else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + ed->decoded_size) { // remove middle + } else if (start_data > tp.item->key.offset && end_data < tp.item->key.offset + len) { // remove middle EXTENT_DATA* ned; EXTENT_DATA2* ned2; - if (ed2->address != 0) { - Status = add_extent_ref(Vcb, ed2->address, ed2->size, fcb->subvol, fcb->inode, end_data, rollback); - if (!NT_SUCCESS(Status)) { - ERR("add_extent_ref returned %08x\n", Status); - goto end; - } - + if (ed2->address != 0) fcb->inode_item.st_blocks -= end_data - start_data; - } delete_tree_item(Vcb, &tp, rollback); @@ -4523,7 +4656,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT ned2 = (EXTENT_DATA2*)&ned->data[0]; ned->generation = Vcb->superblock.generation; - ned->decoded_size = start_data - tp.item->key.offset; + ned->decoded_size = ed->decoded_size; ned->compression = ed->compression; ned->encryption = ed->encryption; ned->encoding = ed->encoding; @@ -4550,7 +4683,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT ned2 = (EXTENT_DATA2*)&ned->data[0]; ned->generation = Vcb->superblock.generation; - ned->decoded_size = tp.item->key.offset + ed->decoded_size - end_data; + ned->decoded_size = ed->decoded_size; ned->compression = ed->compression; ned->encryption = ed->encryption; ned->encoding = ed->encoding; @@ -4558,7 +4691,7 @@ NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT ned2->address = ed2->address; ned2->size = ed2->size; ned2->offset = ed2->address == 0 ? 0 : (ed2->offset + (end_data - tp.item->key.offset)); - ned2->num_bytes = tp.item->key.offset + ed->decoded_size - end_data; + ned2->num_bytes = tp.item->key.offset + len - end_data; if (!insert_tree_item(Vcb, fcb->subvol, fcb->inode, TYPE_EXTENT_DATA, end_data, ned, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2), NULL, rollback)) { ERR("insert_tree_item failed\n"); @@ -4830,9 +4963,16 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data, TRACE("not extending extent which is not EXTENT_TYPE_REGULAR\n"); goto end; } + + ed2 = (EXTENT_DATA2*)ed->data; + + if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) { + ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)); + goto end; + } - if (tp.item->key.offset + ed->decoded_size != start_data) { - TRACE("last EXTENT_DATA does not run up to start_data (%llx + %llx != %llx)\n", tp.item->key.offset, ed->decoded_size, start_data); + if (tp.item->key.offset + ed2->num_bytes != start_data) { + TRACE("last EXTENT_DATA does not run up to start_data (%llx + %llx != %llx)\n", tp.item->key.offset, ed2->num_bytes, start_data); goto end; } @@ -4851,14 +4991,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64 start_data, goto end; } - ed2 = (EXTENT_DATA2*)ed->data; - - if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) { - ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)); - goto end; - } - - if (ed2->size - ed2->offset != ed->decoded_size) { + if (ed2->size - ed2->offset != ed2->num_bytes) { TRACE("last EXTENT_DATA does not run all the way to the end of the extent\n"); goto end; } @@ -5033,6 +5166,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data traverse_ptr tp; NTSTATUS Status; EXTENT_DATA* ed; + UINT64 len; searchkey.obj_id = fcb->inode; searchkey.obj_type = TYPE_EXTENT_DATA; @@ -5065,19 +5199,24 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data // return STATUS_INTERNAL_ERROR; // } - if (tp.item->key.obj_type == TYPE_EXTENT_DATA && tp.item->size >= sizeof(EXTENT_DATA)) + if (tp.item->key.obj_type == TYPE_EXTENT_DATA && tp.item->size >= sizeof(EXTENT_DATA)) { + EXTENT_DATA2* ed2; + ed = (EXTENT_DATA*)tp.item->data; - else + ed2 = (EXTENT_DATA2*)ed->data; + + len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes; + } else ed = NULL; - if (tp.item->key.obj_id != fcb->inode || tp.item->key.obj_type != TYPE_EXTENT_DATA || !ed || tp.item->key.offset + ed->decoded_size < start_data) { + if (tp.item->key.obj_id != fcb->inode || tp.item->key.obj_type != TYPE_EXTENT_DATA || !ed || tp.item->key.offset + len < start_data) { if (tp.item->key.obj_id != fcb->inode || tp.item->key.obj_type != TYPE_EXTENT_DATA) Status = insert_sparse_extent(Vcb, fcb->subvol, fcb->inode, 0, start_data, rollback); else if (!ed) 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, sizeof(EXTENT_DATA)); else { - Status = insert_sparse_extent(Vcb, fcb->subvol, fcb->inode, tp.item->key.offset + ed->decoded_size, - start_data - tp.item->key.offset - ed->decoded_size, rollback); + Status = insert_sparse_extent(Vcb, fcb->subvol, fcb->inode, tp.item->key.offset + len, + start_data - tp.item->key.offset - len, rollback); } if (!NT_SUCCESS(Status)) { ERR("insert_sparse_extent returned %08x\n", Status); @@ -5388,14 +5527,17 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) { oldalloc = 0; if (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type == TYPE_EXTENT_DATA) { + EXTENT_DATA* ed = (EXTENT_DATA*)tp.item->data; + EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data; + if (tp.item->size < sizeof(EXTENT_DATA)) { 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, sizeof(EXTENT_DATA)); free_traverse_ptr(&tp); return STATUS_INTERNAL_ERROR; } - oldalloc = tp.item->key.offset + ((EXTENT_DATA*)tp.item->data)->decoded_size; - cur_inline = ((EXTENT_DATA*)tp.item->data)->type == EXTENT_TYPE_INLINE; + oldalloc = tp.item->key.offset + (ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes); + cur_inline = ed->type == EXTENT_TYPE_INLINE; if (cur_inline && end > fcb->Vcb->max_inline) { LIST_ENTRY changed_sector_list; @@ -5405,7 +5547,7 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) { TRACE("giving inline file proper extents\n"); - origlength = ((EXTENT_DATA*)tp.item->data)->decoded_size; + origlength = ed->decoded_size; cur_inline = FALSE; @@ -5426,7 +5568,7 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) { if (length > origlength) RtlZeroMemory(data + origlength, length - origlength); - RtlCopyMemory(data, ((EXTENT_DATA*)tp.item->data)->data, origlength); + RtlCopyMemory(data, ed->data, origlength); fcb->inode_item.st_blocks -= origlength; @@ -5447,7 +5589,6 @@ NTSTATUS extend_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback) { } if (cur_inline) { - EXTENT_DATA* ed; ULONG edsize; if (end > oldalloc) { @@ -5868,7 +6009,7 @@ static void check_extents_consistent(device_extension* Vcb, fcb* fcb) { ed = (EXTENT_DATA*)tp.item->data; ed2 = (EXTENT_DATA2*)&ed->data[0]; - length = oldlength = ed->decoded_size; + length = oldlength = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes; lastoff = tp.item->key.offset; TRACE("(%llx,%x,%llx) length = %llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, length); @@ -5895,7 +6036,7 @@ static void check_extents_consistent(device_extension* Vcb, fcb* fcb) { ed = (EXTENT_DATA*)tp.item->data; ed2 = (EXTENT_DATA2*)&ed->data[0]; - length = ed->decoded_size; + length = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes; TRACE("(%llx,%x,%llx) length = %llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, length);