Sync btrfs to 0.6.

CORE-11937

svn path=/trunk/; revision=72576
This commit is contained in:
Pierre Schweitzer 2016-09-04 15:27:46 +00:00
parent 2d33d95a7b
commit 74750c6d1a
24 changed files with 4693 additions and 2756 deletions

View file

@ -1,10 +1,13 @@
add_subdirectory(zlib)
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/drivers
${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib
inc)
list(APPEND SOURCE
btrfs.c
cache.c
compress.c
crc32c.c
create.c
dirctrl.c
@ -29,7 +32,7 @@ add_library(btrfs SHARED ${SOURCE} btrfs.rc)
add_definitions(-D__KERNEL__)
set_module_type(btrfs kernelmodedriver)
target_link_libraries(btrfs ntoskrnl_vista ${PSEH_LIB})
target_link_libraries(btrfs ntoskrnl_vista zlib_solo ${PSEH_LIB})
add_importlibs(btrfs ntoskrnl hal)
add_pch(btrfs btrfs_drv.h SOURCE)
add_cd_file(TARGET btrfs DESTINATION reactos/system32/drivers NO_CAB FOR all)

View file

@ -35,8 +35,9 @@
#endif
#include <mountdev.h>
#define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | \
BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA)
#define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | \
BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES)
#define COMPAT_RO_SUPPORTED 0
static WCHAR device_name[] = {'\\','B','t','r','f','s',0};
@ -53,6 +54,12 @@ LIST_ENTRY volumes;
LIST_ENTRY VcbList;
ERESOURCE global_loading_lock;
UINT32 debug_log_level = 0;
UINT32 mount_compress = 0;
UINT32 mount_compress_force = 0;
UINT32 mount_compress_type = 0;
UINT32 mount_zlib_level = 3;
UINT32 mount_flush_interval = 30;
UINT32 mount_max_inline = 2048;
BOOL log_started = FALSE;
UNICODE_STRING log_device, log_file, registry_path;
@ -313,7 +320,7 @@ static void STDCALL DriverUnload(PDRIVER_OBJECT DriverObject) {
ExFreePool(registry_path.Buffer);
}
BOOL STDCALL get_last_inode(device_extension* Vcb, root* r) {
BOOL STDCALL get_last_inode(device_extension* Vcb, root* r, PIRP Irp) {
KEY searchkey;
traverse_ptr tp, prev_tp;
NTSTATUS Status;
@ -323,13 +330,13 @@ BOOL STDCALL get_last_inode(device_extension* Vcb, root* r) {
searchkey.obj_type = 0xff;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, r, &tp, &searchkey, FALSE);
Status = find_item(Vcb, r, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return FALSE;
}
while (find_prev_item(Vcb, &tp, &prev_tp, FALSE)) {
while (find_prev_item(Vcb, &tp, &prev_tp, FALSE, Irp)) {
tp = prev_tp;
TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
@ -348,7 +355,7 @@ BOOL STDCALL get_last_inode(device_extension* Vcb, root* r) {
return TRUE;
}
BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen) {
BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen, PIRP Irp) {
KEY searchkey;
traverse_ptr tp;
DIR_ITEM* xa;
@ -361,7 +368,7 @@ BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char*
searchkey.obj_type = TYPE_XATTR_ITEM;
searchkey.offset = crc32;
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return FALSE;
@ -419,7 +426,7 @@ BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char*
return FALSE;
}
NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, LIST_ENTRY* rollback) {
NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, PIRP Irp, LIST_ENTRY* rollback) {
KEY searchkey;
traverse_ptr tp;
UINT8* di2;
@ -429,7 +436,7 @@ NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32
searchkey.obj_type = TYPE_DIR_ITEM;
searchkey.offset = crc32;
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -456,11 +463,11 @@ NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32
delete_tree_item(Vcb, &tp, rollback);
insert_tree_item(Vcb, subvol, inode, TYPE_DIR_ITEM, crc32, di2, tp.item->size + disize, NULL, rollback);
insert_tree_item(Vcb, subvol, inode, TYPE_DIR_ITEM, crc32, di2, tp.item->size + disize, NULL, Irp, rollback);
ExFreePool(di);
} else {
insert_tree_item(Vcb, subvol, inode, TYPE_DIR_ITEM, crc32, di, disize, NULL, rollback);
insert_tree_item(Vcb, subvol, inode, TYPE_DIR_ITEM, crc32, di, disize, NULL, Irp, rollback);
}
return STATUS_SUCCESS;
@ -704,8 +711,24 @@ static NTSTATUS STDCALL drv_query_volume_information(IN PDEVICE_OBJECT DeviceObj
break;
case FileFsDeviceInformation:
FIXME("STUB: FileFsDeviceInformation\n");
{
FILE_FS_DEVICE_INFORMATION* ffdi = Irp->AssociatedIrp.SystemBuffer;
TRACE("FileFsDeviceInformation\n");
ffdi->DeviceType = FILE_DEVICE_DISK;
ffdi->Characteristics = Vcb->devices[0].devobj->Characteristics;
if (Vcb->readonly)
ffdi->Characteristics |= FILE_READ_ONLY_DEVICE;
else
ffdi->Characteristics &= ~FILE_READ_ONLY_DEVICE;
BytesCopied = sizeof(FILE_FS_DEVICE_INFORMATION);
Status = STATUS_SUCCESS;
break;
}
case FileFsDriverPathInformation:
FIXME("STUB: FileFsDriverPathInformation\n");
@ -919,7 +942,7 @@ static NTSTATUS STDCALL read_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, P
// }
// }
NTSTATUS create_root(device_extension* Vcb, UINT64 id, root** rootptr, BOOL no_tree, UINT64 offset, LIST_ENTRY* rollback) {
NTSTATUS create_root(device_extension* Vcb, UINT64 id, root** rootptr, BOOL no_tree, UINT64 offset, PIRP Irp, LIST_ENTRY* rollback) {
root* r;
tree* t;
ROOT_ITEM* ri;
@ -975,7 +998,7 @@ NTSTATUS create_root(device_extension* Vcb, UINT64 id, root** rootptr, BOOL no_t
// We ask here for a traverse_ptr to the item we're inserting, so we can
// copy some of the tree's variables
if (!insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, rollback)) {
if (!insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, Irp, rollback)) {
ERR("insert_tree_item failed\n");
ExFreePool(ri);
@ -1159,30 +1182,46 @@ NTSTATUS create_root(device_extension* Vcb, UINT64 id, root** rootptr, BOOL no_t
static NTSTATUS STDCALL set_label(device_extension* Vcb, FILE_FS_LABEL_INFORMATION* ffli) {
ULONG utf8len;
NTSTATUS Status;
USHORT vollen, i;
TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel);
Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, ffli->VolumeLabelLength);
if (!NT_SUCCESS(Status))
goto end;
vollen = ffli->VolumeLabelLength;
if (utf8len > MAX_LABEL_SIZE) {
Status = STATUS_INVALID_VOLUME_LABEL;
goto end;
for (i = 0; i < ffli->VolumeLabelLength / sizeof(WCHAR); i++) {
if (ffli->VolumeLabel[i] == 0) {
vollen = i * sizeof(WCHAR);
break;
} else if (ffli->VolumeLabel[i] == '/' || ffli->VolumeLabel[i] == '\\') {
Status = STATUS_INVALID_VOLUME_LABEL;
goto end;
}
}
// FIXME - check for '/' and '\\' and reject
// utf8 = ExAllocatePoolWithTag(PagedPool, utf8len + 1, ALLOC_TAG);
Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE * sizeof(WCHAR), &utf8len, ffli->VolumeLabel, ffli->VolumeLabelLength);
if (!NT_SUCCESS(Status))
goto release;
if (vollen == 0) {
utf8len = 0;
} else {
Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, vollen);
if (!NT_SUCCESS(Status))
goto end;
if (utf8len > MAX_LABEL_SIZE) {
Status = STATUS_INVALID_VOLUME_LABEL;
goto end;
}
}
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
if (utf8len < MAX_LABEL_SIZE * sizeof(WCHAR))
RtlZeroMemory(Vcb->superblock.label + utf8len, (MAX_LABEL_SIZE * sizeof(WCHAR)) - utf8len);
if (utf8len > 0) {
Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE, &utf8len, ffli->VolumeLabel, vollen);
if (!NT_SUCCESS(Status))
goto release;
} else
Status = STATUS_SUCCESS;
if (utf8len < MAX_LABEL_SIZE)
RtlZeroMemory(Vcb->superblock.label + utf8len, MAX_LABEL_SIZE - utf8len);
// test_tree_deletion(Vcb); // TESTING
// test_tree_splitting(Vcb);
@ -1266,7 +1305,7 @@ exit:
return Status;
}
NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, LIST_ENTRY* rollback) {
NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback) {
KEY searchkey;
traverse_ptr tp;
NTSTATUS Status;
@ -1275,7 +1314,7 @@ NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, U
searchkey.obj_type = TYPE_DIR_ITEM;
searchkey.offset = crc32;
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -1319,7 +1358,7 @@ NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, U
if ((UINT8*)&di->name[di->n + di->m] - tp.item->data < tp.item->size)
RtlCopyMemory(dioff, &di->name[di->n + di->m], tp.item->size - ((UINT8*)&di->name[di->n + di->m] - tp.item->data));
insert_tree_item(Vcb, subvol, parinode, TYPE_DIR_ITEM, crc32, newdi, newlen, NULL, rollback);
insert_tree_item(Vcb, subvol, parinode, TYPE_DIR_ITEM, crc32, newdi, newlen, NULL, Irp, rollback);
}
break;
@ -1336,7 +1375,7 @@ NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, U
return STATUS_SUCCESS;
}
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, LIST_ENTRY* rollback) {
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback) {
KEY searchkey;
traverse_ptr tp;
BOOL changed = FALSE;
@ -1346,7 +1385,7 @@ NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UIN
searchkey.obj_type = TYPE_INODE_REF;
searchkey.offset = parinode;
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -1400,7 +1439,7 @@ NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UIN
if ((UINT8*)&ir->name[ir->n] - tp.item->data < tp.item->size)
RtlCopyMemory(iroff, &ir->name[ir->n], tp.item->size - ((UINT8*)&ir->name[ir->n] - tp.item->data));
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newir, newlen, NULL, rollback);
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newir, newlen, NULL, Irp, rollback);
}
break;
@ -1431,7 +1470,7 @@ NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UIN
searchkey.obj_type = TYPE_INODE_EXTREF;
searchkey.offset = calc_crc32c((UINT32)parinode, (UINT8*)utf8->Buffer, utf8->Length);
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE);
Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -1485,7 +1524,7 @@ NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UIN
if ((UINT8*)&ier->name[ier->n] - tp.item->data < tp.item->size)
RtlCopyMemory(ieroff, &ier->name[ier->n], tp.item->size - ((UINT8*)&ier->name[ier->n] - tp.item->data));
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newier, newlen, NULL, rollback);
insert_tree_item(Vcb, subvol, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newier, newlen, NULL, Irp, rollback);
}
break;
@ -1612,7 +1651,7 @@ void send_notification_fcb(file_ref* fileref, ULONG filter_match, ULONG action)
hardlink* hl = CONTAINING_RECORD(le, hardlink, list_entry);
file_ref* parfr;
Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr);
Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, NULL);
if (!NT_SUCCESS(Status)) {
ERR("open_fileref_by_inode returned %08x\n", Status);
@ -1732,6 +1771,13 @@ void mark_fileref_dirty(file_ref* fileref) {
void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line) {
LONG rc;
// #ifdef DEBUG
// if (!ExIsResourceAcquiredExclusiveLite(&fcb->Vcb->fcb_lock) && !ExIsResourceAcquiredExclusiveLite(&fcb->Vcb->tree_lock)) {
// ERR("fcb_lock not acquired exclusively\n");
// int3;
// }
// #endif
rc = InterlockedDecrement(&fcb->refcount);
#ifdef DEBUG_FCB_REFCOUNTS
@ -1746,7 +1792,7 @@ void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line)
if (rc > 0)
return;
ExAcquireResourceExclusiveLite(&fcb->Vcb->fcb_lock, TRUE);
// ExAcquireResourceExclusiveLite(&fcb->Vcb->fcb_lock, TRUE);
if (fcb->list_entry.Flink)
RemoveEntryList(&fcb->list_entry);
@ -1754,7 +1800,7 @@ void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line)
if (fcb->list_entry_all.Flink)
RemoveEntryList(&fcb->list_entry_all);
ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
// ExReleaseResourceLite(&fcb->Vcb->fcb_lock);
ExDeleteResourceLite(&fcb->nonpaged->resource);
ExDeleteResourceLite(&fcb->nonpaged->paging_resource);
@ -1821,6 +1867,13 @@ void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line)
void _free_fileref(file_ref* fr, const char* func, const char* file, unsigned int line) {
LONG rc;
// #ifdef DEBUG
// if (!ExIsResourceAcquiredExclusiveLite(&fr->fcb->Vcb->fcb_lock) && !ExIsResourceAcquiredExclusiveLite(&fr->fcb->Vcb->tree_lock) && !fr->dirty) {
// ERR("fcb_lock not acquired exclusively\n");
// int3;
// }
// #endif
rc = InterlockedDecrement(&fr->refcount);
#ifdef DEBUG_FCB_REFCOUNTS
@ -1915,6 +1968,9 @@ static NTSTATUS STDCALL close_file(device_extension* Vcb, PFILE_OBJECT FileObjec
CcUninitializeCacheMap(FileObject, NULL, NULL);
if (!(Vcb->Vpb->Flags & VPB_MOUNTED))
return STATUS_SUCCESS;
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
if (fileref)
@ -1935,9 +1991,9 @@ void STDCALL uninit(device_extension* Vcb, BOOL flush) {
LIST_ENTRY* le;
LARGE_INTEGER time;
#ifndef __REACTOS__
Vcb->removing = TRUE;
RemoveEntryList(&Vcb->list_entry);
#endif
Status = registry_mark_volume_unmounted(&Vcb->superblock.uuid);
if (!NT_SUCCESS(Status))
@ -1948,8 +2004,8 @@ void STDCALL uninit(device_extension* Vcb, BOOL flush) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
if (Vcb->need_write)
do_write(Vcb, &rollback);
if (Vcb->need_write && !Vcb->readonly)
do_write(Vcb, NULL, &rollback);
free_trees(Vcb);
@ -1969,8 +2025,6 @@ void STDCALL uninit(device_extension* Vcb, BOOL flush) {
ExFreePool(Vcb->threads.threads);
Vcb->removing = TRUE;
time.QuadPart = 0;
KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early
KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL);
@ -2027,10 +2081,9 @@ void STDCALL uninit(device_extension* Vcb, BOOL flush) {
if (c->cache)
free_fcb(c->cache);
ExDeleteResourceLite(&c->nonpaged->lock);
ExDeleteResourceLite(&c->nonpaged->changed_extents_lock);
ExDeleteResourceLite(&c->lock);
ExDeleteResourceLite(&c->changed_extents_lock);
ExFreePool(c->nonpaged);
ExFreePool(c->chunk_item);
ExFreePool(c);
}
@ -2064,7 +2117,7 @@ void STDCALL uninit(device_extension* Vcb, BOOL flush) {
ZwClose(Vcb->flush_thread_handle);
}
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, LIST_ENTRY* rollback) {
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, PIRP Irp, LIST_ENTRY* rollback) {
LARGE_INTEGER newlength, time;
BTRFS_TIME now;
NTSTATUS Status;
@ -2103,7 +2156,7 @@ NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, LIST_ENTRY*
// 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), rollback);
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);
@ -2265,7 +2318,7 @@ static NTSTATUS STDCALL drv_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
Status = delete_fileref(fileref, FileObject, &rollback);
Status = delete_fileref(fileref, FileObject, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08x\n", Status);
do_rollback(Vcb, &rollback);
@ -2319,14 +2372,14 @@ exit2:
return Status;
}
ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa) {
ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa, PIRP Irp) {
ULONG att;
char* eaval;
UINT16 ealen;
// ii can be NULL
if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen)) {
if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen, Irp)) {
if (ealen > 2) {
if (eaval[0] == '0' && eaval[1] == 'x') {
int i;
@ -2388,7 +2441,7 @@ ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r
return att;
}
NTSTATUS sync_read_phys(PDEVICE_OBJECT DeviceObject, LONGLONG StartingOffset, ULONG Length, PUCHAR Buffer) {
static NTSTATUS sync_read_phys(PDEVICE_OBJECT DeviceObject, LONGLONG StartingOffset, ULONG Length, PUCHAR Buffer, BOOL override) {
IO_STATUS_BLOCK* IoStatus;
LARGE_INTEGER Offset;
PIRP Irp;
@ -2425,9 +2478,13 @@ NTSTATUS sync_read_phys(PDEVICE_OBJECT DeviceObject, LONGLONG StartingOffset, UL
goto exit;
}
Irp->Flags |= IRP_NOCACHE;
IrpSp = IoGetNextIrpStackLocation(Irp);
IrpSp->MajorFunction = IRP_MJ_READ;
if (override)
IrpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
if (DeviceObject->Flags & DO_BUFFERED_IO) {
FIXME("FIXME - buffered IO\n");
} else if (DeviceObject->Flags & DO_DIRECT_IO) {
@ -2461,20 +2518,10 @@ NTSTATUS sync_read_phys(PDEVICE_OBJECT DeviceObject, LONGLONG StartingOffset, UL
IoSetCompletionRoutine(Irp, read_completion, context, TRUE, TRUE, TRUE);
// if (Override)
// {
// Stack = IoGetNextIrpStackLocation(Irp);
// Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
// }
// TRACE("Calling IO Driver... with irp %p\n", Irp);
Status = IoCallDriver(DeviceObject, Irp);
// TRACE("Waiting for IO Operation for %p\n", Irp);
if (Status == STATUS_PENDING) {
// TRACE("Operation pending\n");
KeWaitForSingleObject(&context->Event, Executive, KernelMode, FALSE, NULL);
// TRACE("Getting IO Status... for %p\n", Irp);
Status = context->iosb.Status;
}
@ -2512,7 +2559,7 @@ static NTSTATUS STDCALL read_superblock(device_extension* Vcb, PDEVICE_OBJECT de
if (i > 0 && superblock_addrs[i] + sizeof(superblock) > length)
break;
Status = sync_read_phys(device, superblock_addrs[i], to_read, (PUCHAR)sb);
Status = sync_read_phys(device, superblock_addrs[i], to_read, (PUCHAR)sb, FALSE);
if (!NT_SUCCESS(Status)) {
ERR("Failed to read superblock %u: %08x\n", i, Status);
ExFreePool(sb);
@ -2646,7 +2693,7 @@ static NTSTATUS STDCALL add_root(device_extension* Vcb, UINT64 id, UINT64 addr,
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL look_for_roots(device_extension* Vcb) {
static NTSTATUS STDCALL look_for_roots(device_extension* Vcb, PIRP Irp) {
traverse_ptr tp, next_tp;
KEY searchkey;
BOOL b;
@ -2656,7 +2703,7 @@ static NTSTATUS STDCALL look_for_roots(device_extension* Vcb) {
searchkey.obj_type = 0;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_tree returned %08x\n", Status);
return Status;
@ -2681,7 +2728,7 @@ static NTSTATUS STDCALL look_for_roots(device_extension* Vcb) {
}
}
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (b)
tp = next_tp;
@ -2690,7 +2737,7 @@ static NTSTATUS STDCALL look_for_roots(device_extension* Vcb) {
return STATUS_SUCCESS;
}
static NTSTATUS find_disk_holes(device_extension* Vcb, device* dev) {
static NTSTATUS find_disk_holes(device_extension* Vcb, device* dev, PIRP Irp) {
KEY searchkey;
traverse_ptr tp, next_tp;
BOOL b;
@ -2703,7 +2750,7 @@ static NTSTATUS find_disk_holes(device_extension* Vcb, device* dev) {
searchkey.obj_type = TYPE_DEV_EXTENT;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_tree returned %08x\n", Status);
return Status;
@ -2730,7 +2777,7 @@ static NTSTATUS find_disk_holes(device_extension* Vcb, device* dev) {
}
}
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (b) {
tp = next_tp;
@ -2858,7 +2905,7 @@ static void init_device(device_extension* Vcb, device* dev, BOOL get_length) {
}
}
static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb) {
static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb, PIRP Irp) {
traverse_ptr tp, next_tp;
KEY searchkey;
BOOL b;
@ -2872,7 +2919,7 @@ static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb) {
Vcb->data_flags = 0;
Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -2950,33 +2997,24 @@ static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb) {
if (tp.item->size < sizeof(CHUNK_ITEM)) {
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(CHUNK_ITEM));
} else {
c = ExAllocatePoolWithTag(PagedPool, sizeof(chunk), ALLOC_TAG);
c = ExAllocatePoolWithTag(NonPagedPool, sizeof(chunk), ALLOC_TAG);
if (!c) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
c->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(chunk_nonpaged), ALLOC_TAG);
if (!c->nonpaged) {
ERR("out of memory\n");
ExFreePool(c);
return STATUS_INSUFFICIENT_RESOURCES;
}
c->size = tp.item->size;
c->offset = tp.item->key.offset;
c->used = c->oldused = 0;
c->cache = NULL;
c->created = FALSE;
c->chunk_item = ExAllocatePoolWithTag(PagedPool, tp.item->size, ALLOC_TAG);
c->chunk_item = ExAllocatePoolWithTag(NonPagedPool, tp.item->size, ALLOC_TAG);
if (!c->chunk_item) {
ERR("out of memory\n");
ExFreePool(c);
ExFreePool(c->nonpaged);
return STATUS_INSUFFICIENT_RESOURCES;
}
@ -2988,12 +3026,11 @@ static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb) {
if (c->chunk_item->num_stripes > 0) {
CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
c->devices = ExAllocatePoolWithTag(PagedPool, sizeof(device*) * c->chunk_item->num_stripes, ALLOC_TAG);
c->devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device*) * c->chunk_item->num_stripes, ALLOC_TAG);
if (!c->devices) {
ERR("out of memory\n");
ExFreePool(c);
ExFreePool(c->nonpaged);
ExFreePool(c->chunk_item);
return STATUS_INSUFFICIENT_RESOURCES;
}
@ -3005,8 +3042,8 @@ static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb) {
} else
c->devices = NULL;
ExInitializeResourceLite(&c->nonpaged->lock);
ExInitializeResourceLite(&c->nonpaged->changed_extents_lock);
ExInitializeResourceLite(&c->lock);
ExInitializeResourceLite(&c->changed_extents_lock);
InitializeListHead(&c->space);
InitializeListHead(&c->space_size);
@ -3019,7 +3056,7 @@ static NTSTATUS STDCALL load_chunk_root(device_extension* Vcb) {
}
}
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (b)
tp = next_tp;
@ -3094,7 +3131,7 @@ void protect_superblocks(device_extension* Vcb, chunk* c) {
}
}
static NTSTATUS STDCALL find_chunk_usage(device_extension* Vcb) {
static NTSTATUS STDCALL find_chunk_usage(device_extension* Vcb, PIRP Irp) {
LIST_ENTRY* le = Vcb->chunks.Flink;
chunk* c;
KEY searchkey;
@ -3113,7 +3150,7 @@ static NTSTATUS STDCALL find_chunk_usage(device_extension* Vcb) {
searchkey.obj_id = c->offset;
searchkey.offset = c->chunk_item->size;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -3141,7 +3178,7 @@ static NTSTATUS STDCALL find_chunk_usage(device_extension* Vcb) {
// FIXME - make sure we free occasionally after doing one of these, or we
// might use up a lot of memory with a big disk.
Status = load_free_space_cache(Vcb, c);
Status = load_free_space_cache(Vcb, c, Irp);
if (!NT_SUCCESS(Status)) {
ERR("load_free_space_cache returned %08x\n", Status);
return Status;
@ -3253,12 +3290,24 @@ static NTSTATUS load_sys_chunks(device_extension* Vcb) {
return STATUS_SUCCESS;
}
static root* find_default_subvol(device_extension* Vcb) {
static root* find_default_subvol(device_extension* Vcb, PIRP Irp) {
LIST_ENTRY* le;
static char fn[] = "default";
static UINT32 crc32 = 0x8dbfc2d2;
if (Vcb->options.subvol_id != 0) {
le = Vcb->roots.Flink;
while (le != &Vcb->roots) {
root* r = CONTAINING_RECORD(le, root, list_entry);
if (r->id == Vcb->options.subvol_id)
return r;
le = le->Flink;
}
}
if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL) {
NTSTATUS Status;
KEY searchkey;
@ -3269,7 +3318,7 @@ static root* find_default_subvol(device_extension* Vcb) {
searchkey.obj_type = TYPE_DIR_ITEM;
searchkey.offset = crc32;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
goto end;
@ -3334,7 +3383,7 @@ static NTSTATUS create_worker_threads(PDEVICE_OBJECT DeviceObject) {
ULONG i;
NTSTATUS Status;
Vcb->threads.num_threads = max(3, KeQueryActiveProcessorCount(NULL)); // FIXME - number of processors?
Vcb->threads.num_threads = max(3, KeQueryActiveProcessorCount(NULL));
Vcb->threads.threads = ExAllocatePoolWithTag(NonPagedPool, sizeof(drv_thread) * Vcb->threads.num_threads, ALLOC_TAG);
if (!Vcb->threads.threads) {
@ -3366,6 +3415,8 @@ static NTSTATUS create_worker_threads(PDEVICE_OBJECT DeviceObject) {
}
}
Vcb->threads.pending_jobs = 0;
return STATUS_SUCCESS;
}
@ -3375,6 +3426,9 @@ BOOL add_thread_job(device_extension* Vcb, PIRP Irp) {
threadnum = InterlockedIncrement(&Vcb->threads.next_thread) % Vcb->threads.num_threads;
if (Vcb->threads.pending_jobs >= Vcb->threads.num_threads)
return FALSE;
if (Vcb->threads.threads[threadnum].quit)
return FALSE;
@ -3388,6 +3442,8 @@ BOOL add_thread_job(device_extension* Vcb, PIRP Irp) {
tj->Irp = Irp;
InterlockedIncrement(&Vcb->threads.pending_jobs);
ExInterlockedInsertTailList(&Vcb->threads.threads[threadnum].jobs, &tj->list_entry, &Vcb->threads.threads[threadnum].spin_lock);
KeSetEvent(&Vcb->threads.threads[threadnum].event, 0, FALSE);
@ -3527,7 +3583,7 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
TRACE("btrfs magic found\n");
}
Status = registry_load_volume_options(&Vcb->superblock.uuid, &Vcb->options);
Status = registry_load_volume_options(Vcb);
if (!NT_SUCCESS(Status)) {
ERR("registry_load_volume_options returned %08x\n", Status);
goto exit;
@ -3564,10 +3620,13 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Vcb->readonly = TRUE;
}
if (Vcb->options.readonly)
Vcb->readonly = TRUE;
Vcb->superblock.generation++;
Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF;
Vcb->devices = ExAllocatePoolWithTag(PagedPool, sizeof(device) * Vcb->superblock.num_devices, ALLOC_TAG);
Vcb->devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device) * Vcb->superblock.num_devices, ALLOC_TAG);
if (!Vcb->devices) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -3595,8 +3654,6 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Vcb->log_to_phys_loaded = FALSE;
Vcb->max_inline = Vcb->superblock.node_size / 2;
add_root(Vcb, BTRFS_ROOT_CHUNK, Vcb->superblock.chunk_tree_addr, NULL);
if (!Vcb->chunk_root) {
@ -3629,7 +3686,7 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
FsRtlNotifyInitializeSync(&Vcb->NotifySync);
Status = load_chunk_root(Vcb);
Status = load_chunk_root(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
ERR("load_chunk_root returned %08x\n", Status);
goto exit;
@ -3663,29 +3720,31 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
goto exit;
}
Status = look_for_roots(Vcb);
Status = look_for_roots(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
ERR("look_for_roots returned %08x\n", Status);
goto exit;
}
Status = find_chunk_usage(Vcb);
if (!NT_SUCCESS(Status)) {
ERR("find_chunk_usage returned %08x\n", Status);
goto exit;
if (!Vcb->readonly) {
Status = find_chunk_usage(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
ERR("find_chunk_usage returned %08x\n", Status);
goto exit;
}
}
// We've already increased the generation by one
if (!Vcb->readonly && Vcb->superblock.generation - 1 != Vcb->superblock.cache_generation) {
WARN("generation was %llx, free-space cache generation was %llx; clearing cache...\n", Vcb->superblock.generation - 1, Vcb->superblock.cache_generation);
Status = clear_free_space_cache(Vcb);
Status = clear_free_space_cache(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
ERR("clear_free_space_cache returned %08x\n", Status);
goto exit;
}
}
Vcb->volume_fcb = create_fcb();
Vcb->volume_fcb = create_fcb(NonPagedPool);
if (!Vcb->volume_fcb) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -3695,7 +3754,7 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Vcb->volume_fcb->Vcb = Vcb;
Vcb->volume_fcb->sd = NULL;
root_fcb = create_fcb();
root_fcb = create_fcb(NonPagedPool);
if (!root_fcb) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
@ -3711,7 +3770,7 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
WARN("root FCB = %p\n", root_fcb);
#endif
root_fcb->subvol = find_default_subvol(Vcb);
root_fcb->subvol = find_default_subvol(Vcb, Irp);
if (!root_fcb->subvol) {
ERR("could not find top subvol\n");
@ -3723,7 +3782,7 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
searchkey.obj_type = TYPE_INODE_ITEM;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, root_fcb->subvol, &tp, &searchkey, FALSE);
Status = find_item(Vcb, root_fcb->subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
goto exit;
@ -3738,9 +3797,9 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (tp.item->size > 0)
RtlCopyMemory(&root_fcb->inode_item, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
fcb_get_sd(root_fcb, NULL);
fcb_get_sd(root_fcb, NULL, Irp);
root_fcb->atts = get_file_attributes(Vcb, &root_fcb->inode_item, root_fcb->subvol, root_fcb->inode, root_fcb->type, FALSE, FALSE);
root_fcb->atts = get_file_attributes(Vcb, &root_fcb->inode_item, root_fcb->subvol, root_fcb->inode, root_fcb->type, FALSE, FALSE, Irp);
Vcb->root_fileref = create_fileref();
if (!Vcb->root_fileref) {
@ -3764,18 +3823,13 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Vcb->root_file = IoCreateStreamFileObject(NULL, DeviceToMount);
Vcb->root_file->FsContext = root_fcb;
#ifdef __REACTOS__
Vcb->root_file->SectionObjectPointer = &root_fcb->nonpaged->segment_object;
Vcb->root_file->Vpb = DeviceObject->Vpb;
#endif
RtlZeroMemory(root_ccb, sizeof(ccb));
root_ccb->NodeType = BTRFS_NODE_TYPE_CCB;
root_ccb->NodeSize = sizeof(ccb);
#ifndef __REACTOS__
Vcb->root_file->FsContext = root_ccb;
#else
Vcb->root_file->FsContext2 = root_ccb;
_SEH2_TRY {
@ -3784,10 +3838,9 @@ static NTSTATUS STDCALL mount_vol(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Status = _SEH2_GetExceptionCode();
goto exit;
} _SEH2_END;
#endif
for (i = 0; i < Vcb->superblock.num_devices; i++) {
Status = find_disk_holes(Vcb, &Vcb->devices[i]);
Status = find_disk_holes(Vcb, &Vcb->devices[i], Irp);
if (!NT_SUCCESS(Status)) {
ERR("find_disk_holes returned %08x\n", Status);
goto exit;
@ -3867,6 +3920,92 @@ exit:
return Status;
}
static NTSTATUS verify_volume(PDEVICE_OBJECT device) {
device_extension* Vcb = device->DeviceExtension;
ULONG cc, to_read;
IO_STATUS_BLOCK iosb;
NTSTATUS Status;
superblock* sb;
UINT32 crc32;
UINT64 i;
if (Vcb->removing)
return STATUS_WRONG_VOLUME;
Status = dev_ioctl(Vcb->Vpb->RealDevice, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb);
if (!NT_SUCCESS(Status)) {
ERR("dev_ioctl returned %08x\n", Status);
return Status;
}
to_read = sector_align(sizeof(superblock), device->SectorSize);
sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG);
if (!sb) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = sync_read_phys(Vcb->Vpb->RealDevice, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE);
if (!NT_SUCCESS(Status)) {
ERR("Failed to read superblock: %08x\n", Status);
ExFreePool(sb);
return Status;
}
if (sb->magic != BTRFS_MAGIC) {
ERR("not a BTRFS volume\n");
ExFreePool(sb);
return STATUS_WRONG_VOLUME;
}
if (RtlCompareMemory(&sb->uuid, &Vcb->superblock.uuid, sizeof(BTRFS_UUID)) != sizeof(BTRFS_UUID)) {
ERR("different UUIDs\n");
ExFreePool(sb);
return STATUS_WRONG_VOLUME;
}
crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
TRACE("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum));
if (crc32 != *((UINT32*)sb->checksum)) {
ERR("different UUIDs\n");
ExFreePool(sb);
return STATUS_WRONG_VOLUME;
}
ExFreePool(sb);
for (i = 0; i < Vcb->superblock.num_devices; i++) {
if (Vcb->devices[i].removable) {
NTSTATUS Status;
ULONG cc;
IO_STATUS_BLOCK iosb;
Status = dev_ioctl(Vcb->devices[i].devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb);
if (!NT_SUCCESS(Status)) {
ERR("dev_ioctl returned %08x\n", Status);
return Status;
}
if (iosb.Information < sizeof(ULONG)) {
ERR("iosb.Information was too short\n");
return STATUS_INTERNAL_ERROR;
}
Vcb->devices[i].change_count = cc;
}
Vcb->devices[i].devobj->Flags &= ~DO_VERIFY_VOLUME;
}
Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME;
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL drv_file_system_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
PIO_STACK_LOCATION IrpSp;
NTSTATUS Status;
@ -3910,7 +4049,15 @@ static NTSTATUS STDCALL drv_file_system_control(IN PDEVICE_OBJECT DeviceObject,
break;
case IRP_MN_VERIFY_VOLUME:
FIXME("STUB: IRP_MN_VERIFY_VOLUME\n");
TRACE("IRP_MN_VERIFY_VOLUME\n");
Status = verify_volume(DeviceObject);
if (!NT_SUCCESS(Status) && Vcb->Vpb->Flags & VPB_MOUNTED) {
uninit(Vcb, FALSE);
// Vcb->Vpb->Flags &= ~VPB_MOUNTED;
}
break;
default:
@ -4136,8 +4283,7 @@ static NTSTATUS STDCALL drv_shutdown(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp
Status = STATUS_SUCCESS;
while (!IsListEmpty(&VcbList)) {
LIST_ENTRY* le = RemoveHeadList(&VcbList);
Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
Vcb = CONTAINING_RECORD(VcbList.Flink, device_extension, list_entry);
TRACE("shutting down Vcb %p\n", Vcb);

View file

@ -75,7 +75,7 @@ BEGIN
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016"
VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "0.5"
VALUE "ProductVersion", "0.6"
END
END
BLOCK "VarFileInfo"

View file

@ -56,6 +56,7 @@
#define BTRFS_NODE_TYPE_FCB 0x2296
#define ALLOC_TAG 0x7442484D //'MHBt'
#define ALLOC_TAG_ZLIB 0x7A42484D //'MHBz'
#define STDCALL __stdcall
@ -71,9 +72,10 @@
#define EA_REPARSE "system.reparse"
#define EA_REPARSE_HASH 0x786f6167
#define READ_AHEAD_GRANULARITY 0x10000 // 64 KB
#define MAX_EXTENT_SIZE 0x8000000 // 128 MB
#define COMPRESSED_EXTENT_SIZE 0x20000 // 128 KB
#define READ_AHEAD_GRANULARITY COMPRESSED_EXTENT_SIZE // really ought to be a multiple of COMPRESSED_EXTENT_SIZE
#ifdef _MSC_VER
#define try __try
@ -87,7 +89,7 @@
// #pragma pack(push, 1)
struct device_extension;
struct _device_extension;
typedef struct {
BTRFS_UUID fsuuid;
@ -176,6 +178,7 @@ typedef struct _fcb {
BOOL ads;
UINT32 adshash;
ULONG adsmaxlen;
ANSI_STRING adsxattr;
ANSI_STRING adsdata;
@ -344,11 +347,6 @@ typedef struct {
LIST_ENTRY space;
} device;
typedef struct {
ERESOURCE lock;
ERESOURCE changed_extents_lock;
} chunk_nonpaged;
typedef struct {
CHUNK_ITEM* chunk_item;
UINT32 size;
@ -361,7 +359,8 @@ typedef struct {
LIST_ENTRY space_size;
LIST_ENTRY deleting;
LIST_ENTRY changed_extents;
chunk_nonpaged* nonpaged;
ERESOURCE lock;
ERESOURCE changed_extents_lock;
BOOL created;
LIST_ENTRY list_entry;
@ -424,10 +423,19 @@ typedef struct {
ULONG num_threads;
LONG next_thread;
drv_thread* threads;
LONG pending_jobs;
} drv_threads;
typedef struct {
BOOL ignore;
BOOL compress;
BOOL compress_force;
UINT8 compress_type;
BOOL readonly;
UINT32 zlib_level;
UINT32 flush_interval;
UINT32 max_inline;
UINT64 subvol_id;
} mount_options;
#define VCB_TYPE_VOLUME 1
@ -471,7 +479,6 @@ typedef struct _device_extension {
root* dev_root;
root* uuid_root;
BOOL log_to_phys_loaded;
UINT32 max_inline;
LIST_ENTRY sys_chunks;
LIST_ENTRY chunks;
LIST_ENTRY chunks_changed;
@ -528,10 +535,10 @@ enum write_data_status {
WriteDataStatus_Ignore
};
struct write_data_context;
struct _write_data_context;
typedef struct {
struct write_data_context* context;
struct _write_data_context* context;
UINT8* buf;
BOOL need_free;
device* device;
@ -541,7 +548,7 @@ typedef struct {
LIST_ENTRY list_entry;
} write_data_stripe;
typedef struct {
typedef struct _write_data_context {
KEVENT Event;
LIST_ENTRY stripes;
LONG stripes_left;
@ -596,7 +603,7 @@ static __inline void get_raid0_offset(UINT64 off, UINT64 stripe_length, UINT16 n
startoff = off % (num_stripes * stripe_length);
initoff = (off / (num_stripes * stripe_length)) * stripe_length;
*stripe = startoff / stripe_length;
*stripe = (UINT16)(startoff / stripe_length);
*stripeoff = initoff + startoff - (*stripe * stripe_length);
}
@ -604,19 +611,19 @@ static __inline void get_raid0_offset(UINT64 off, UINT64 stripe_length, UINT16 n
device* find_device_from_uuid(device_extension* Vcb, BTRFS_UUID* uuid);
UINT64 sector_align( UINT64 NumberToBeAligned, UINT64 Alignment );
int keycmp(const KEY* key1, const KEY* key2);
ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa);
BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen);
ULONG STDCALL get_file_attributes(device_extension* Vcb, INODE_ITEM* ii, root* r, UINT64 inode, UINT8 type, BOOL dotfile, BOOL ignore_xa, PIRP Irp);
BOOL STDCALL get_xattr(device_extension* Vcb, root* subvol, UINT64 inode, char* name, UINT32 crc32, UINT8** data, UINT16* datalen, PIRP Irp);
void _free_fcb(fcb* fcb, const char* func, const char* file, unsigned int line);
void _free_fileref(file_ref* fr, const char* func, const char* file, unsigned int line);
BOOL STDCALL get_last_inode(device_extension* Vcb, root* r);
NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, LIST_ENTRY* rollback);
NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, LIST_ENTRY* rollback);
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, LIST_ENTRY* rollback);
fcb* create_fcb();
BOOL STDCALL get_last_inode(device_extension* Vcb, root* r, PIRP Irp);
NTSTATUS add_dir_item(device_extension* Vcb, root* subvol, UINT64 inode, UINT32 crc32, DIR_ITEM* di, ULONG disize, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS delete_dir_item(device_extension* Vcb, root* subvol, UINT64 parinode, UINT32 crc32, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS delete_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback);
fcb* create_fcb(POOL_TYPE pool_type);
file_ref* create_fileref();
void protect_superblocks(device_extension* Vcb, chunk* c);
BOOL is_top_level(PIRP Irp);
NTSTATUS create_root(device_extension* Vcb, UINT64 id, root** rootptr, BOOL no_tree, UINT64 offset, LIST_ENTRY* rollback);
NTSTATUS create_root(device_extension* Vcb, UINT64 id, root** rootptr, BOOL no_tree, UINT64 offset, PIRP Irp, LIST_ENTRY* rollback);
void STDCALL uninit(device_extension* Vcb, BOOL flush);
NTSTATUS STDCALL dev_ioctl(PDEVICE_OBJECT DeviceObject, ULONG ControlCode, PVOID InputBuffer,
ULONG InputBufferSize, PVOID OutputBuffer, ULONG OutputBufferSize, BOOLEAN Override, IO_STATUS_BLOCK* iosb);
@ -629,7 +636,7 @@ BOOL add_thread_job(device_extension* Vcb, PIRP Irp);
NTSTATUS part0_passthrough(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
void mark_fcb_dirty(fcb* fcb);
void mark_fileref_dirty(file_ref* fileref);
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, LIST_ENTRY* rollback);
NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, PIRP Irp, LIST_ENTRY* rollback);
#ifdef _MSC_VER
#define funcname __FUNCTION__
@ -641,6 +648,13 @@ NTSTATUS delete_fileref(file_ref* fileref, PFILE_OBJECT FileObject, LIST_ENTRY*
#define free_fcb(fcb) _free_fcb(fcb, funcname, __FILE__, __LINE__)
#define free_fileref(fileref) _free_fileref(fileref, funcname, __FILE__, __LINE__)
extern UINT32 mount_compress;
extern UINT32 mount_compress_force;
extern UINT32 mount_compress_type;
extern UINT32 mount_zlib_level;
extern UINT32 mount_flush_interval;
extern UINT32 mount_max_inline;
#ifdef _DEBUG
extern BOOL log_started;
@ -696,34 +710,50 @@ void STDCALL init_fast_io_dispatch(FAST_IO_DISPATCH** fiod);
// in crc32c.c
UINT32 STDCALL calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen);
typedef struct {
LIST_ENTRY* list;
LIST_ENTRY* list_size;
UINT64 address;
UINT64 length;
chunk* chunk;
} rollback_space;
typedef struct {
fcb* fcb;
extent* ext;
} rollback_extent;
enum rollback_type {
ROLLBACK_INSERT_ITEM,
ROLLBACK_DELETE_ITEM,
ROLLBACK_INSERT_EXTENT,
ROLLBACK_DELETE_EXTENT
ROLLBACK_DELETE_EXTENT,
ROLLBACK_ADD_SPACE,
ROLLBACK_SUBTRACT_SPACE
};
// in treefuncs.c
NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, const char* func, const char* file, unsigned int line);
BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, const char* func, const char* file, unsigned int line);
BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, const char* func, const char* file, unsigned int line);
NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line);
void STDCALL free_trees(device_extension* Vcb);
BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset, void* data, UINT32 size, traverse_ptr* ptp, LIST_ENTRY* rollback);
BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset, void* data, UINT32 size, traverse_ptr* ptp, PIRP Irp, LIST_ENTRY* rollback);
void STDCALL delete_tree_item(device_extension* Vcb, traverse_ptr* tp, LIST_ENTRY* rollback);
tree* STDCALL _free_tree(tree* t, const char* func, const char* file, unsigned int line);
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, tree* parent, const char* func, const char* file, unsigned int line);
NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, const char* func, const char* file, unsigned int line);
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, tree* parent, PIRP Irp, const char* func, const char* file, unsigned int line);
NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, PIRP Irp,
const char* func, const char* file, unsigned int line);
void clear_rollback(LIST_ENTRY* rollback);
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback);
void free_trees_root(device_extension* Vcb, root* r);
void add_rollback(LIST_ENTRY* rollback, enum rollback_type type, void* ptr);
#define find_item(Vcb, r, tp, searchkey, ignore) _find_item(Vcb, r, tp, searchkey, ignore, funcname, __FILE__, __LINE__)
#define find_next_item(Vcb, tp, next_tp, ignore) _find_next_item(Vcb, tp, next_tp, ignore, funcname, __FILE__, __LINE__)
#define find_prev_item(Vcb, tp, prev_tp, ignore) _find_prev_item(Vcb, tp, prev_tp, ignore, funcname, __FILE__, __LINE__)
#define find_item(Vcb, r, tp, searchkey, ignore, Irp) _find_item(Vcb, r, tp, searchkey, ignore, Irp, funcname, __FILE__, __LINE__)
#define find_next_item(Vcb, tp, next_tp, ignore, Irp) _find_next_item(Vcb, tp, next_tp, ignore, Irp, funcname, __FILE__, __LINE__)
#define find_prev_item(Vcb, tp, prev_tp, ignore, Irp) _find_prev_item(Vcb, tp, prev_tp, ignore, Irp, funcname, __FILE__, __LINE__)
#define free_tree(t) _free_tree(t, funcname, __FILE__, __LINE__)
#define load_tree(t, addr, r, pt, parent) _load_tree(t, addr, r, pt, parent, funcname, __FILE__, __LINE__)
#define do_load_tree(Vcb, th, r, t, td, loaded) _do_load_tree(Vcb, th, r, t, td, loaded, funcname, __FILE__, __LINE__)
#define load_tree(t, addr, r, pt, parent, Irp) _load_tree(t, addr, r, pt, parent, Irp, funcname, __FILE__, __LINE__)
#define do_load_tree(Vcb, th, r, t, td, loaded, Irp) _do_load_tree(Vcb, th, r, t, td, loaded, Irp, funcname, __FILE__, __LINE__)
// in search.c
void STDCALL look_for_vols(PDRIVER_OBJECT DriverObject, LIST_ENTRY* volumes);
@ -734,51 +764,52 @@ void STDCALL free_cache();
extern CACHE_MANAGER_CALLBACKS* cache_callbacks;
// in write.c
NTSTATUS STDCALL do_write(device_extension* Vcb, LIST_ENTRY* rollback);
NTSTATUS STDCALL do_write(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS write_file(device_extension* Vcb, PIRP Irp, BOOL wait, BOOL deferred_write);
NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void* buf, ULONG* length, BOOL paging_io, BOOL no_cache,
BOOL wait, BOOL deferred_write, LIST_ENTRY* rollback);
NTSTATUS truncate_file(fcb* fcb, UINT64 end, LIST_ENTRY* rollback);
NTSTATUS truncate_file(fcb* fcb, UINT64 end, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS extend_file(fcb* fcb, file_ref* fileref, UINT64 end, BOOL prealloc, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, LIST_ENTRY* rollback);
NTSTATUS excise_extents(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, PIRP Irp, LIST_ENTRY* rollback);
void commit_checksum_changes(device_extension* Vcb, LIST_ENTRY* changed_sector_list);
NTSTATUS insert_sparse_extent(fcb* fcb, UINT64 start, UINT64 length, LIST_ENTRY* rollback);
chunk* get_chunk_from_address(device_extension* Vcb, UINT64 address);
chunk* alloc_chunk(device_extension* Vcb, UINT64 flags, LIST_ENTRY* rollback);
NTSTATUS STDCALL write_data(device_extension* Vcb, UINT64 address, void* data, BOOL need_free, UINT32 length, write_data_context* wtc, PIRP Irp);
NTSTATUS STDCALL write_data_complete(device_extension* Vcb, UINT64 address, void* data, UINT32 length, PIRP Irp);
chunk* alloc_chunk(device_extension* Vcb, UINT64 flags);
NTSTATUS STDCALL write_data(device_extension* Vcb, UINT64 address, void* data, BOOL need_free, UINT32 length, write_data_context* wtc, PIRP Irp, chunk* c);
NTSTATUS STDCALL write_data_complete(device_extension* Vcb, UINT64 address, void* data, UINT32 length, PIRP Irp, chunk* c);
void free_write_data_stripes(write_data_context* wtc);
NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, LIST_ENTRY* rollback);
NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS STDCALL drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
void flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* rollback);
void flush_fcb(fcb* fcb, BOOL cache, PIRP Irp, LIST_ENTRY* rollback);
BOOL insert_extent_chunk(device_extension* Vcb, fcb* fcb, chunk* c, UINT64 start_data, UINT64 length, BOOL prealloc, void* data, LIST_ENTRY* changed_sector_list,
PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS do_nocow_write(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
PIRP Irp, LIST_ENTRY* rollback, UINT8 compression, UINT64 decoded_size);
NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb, UINT64 start_data, UINT64 length, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
void remove_fcb_extent(extent* ext, LIST_ENTRY* rollback);
NTSTATUS update_changed_extent_ref(device_extension* Vcb, chunk* c, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset,
signed long long count, BOOL no_csum, UINT64 new_size);
signed long long count, BOOL no_csum, UINT64 new_size, PIRP Irp);
NTSTATUS do_write_file(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS write_compressed(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
// in dirctrl.c
NTSTATUS STDCALL drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, ULONG atts, PIRP Irp);
// in security.c
NTSTATUS STDCALL drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS STDCALL drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
void fcb_get_sd(fcb* fcb, struct _fcb* parent);
void fcb_get_sd(fcb* fcb, struct _fcb* parent, PIRP Irp);
// UINT32 STDCALL get_uid();
void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid);
UINT32 sid_to_uid(PSID sid);
void uid_to_sid(UINT32 uid, PSID* sid);
NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as);
// in fileinfo.c
NTSTATUS STDCALL drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS STDCALL drv_query_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS add_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, UINT64 index, PANSI_STRING utf8, LIST_ENTRY* rollback);
NTSTATUS add_inode_ref(device_extension* Vcb, root* subvol, UINT64 inode, UINT64 parinode, UINT64 index, PANSI_STRING utf8, PIRP Irp, LIST_ENTRY* rollback);
BOOL has_open_children(file_ref* fileref);
NTSTATUS STDCALL stream_set_end_of_file_information(device_extension* Vcb, UINT64 end, fcb* fcb, file_ref* fileref, PFILE_OBJECT FileObject, BOOL advance_only, LIST_ENTRY* rollback);
NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* name_offset);
NTSTATUS open_fileref_by_inode(device_extension* Vcb, root* subvol, UINT64 inode, file_ref** pfr);
NTSTATUS open_fileref_by_inode(device_extension* Vcb, root* subvol, UINT64 inode, file_ref** pfr, PIRP Irp);
// in reparse.c
NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void* buffer, DWORD buflen, DWORD* retlen);
@ -787,15 +818,14 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
// in create.c
NTSTATUS STDCALL drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS STDCALL find_file_in_dir_with_crc32(device_extension* Vcb, PUNICODE_STRING filename, UINT32 crc32, file_ref* fr, root** subvol,
UINT64* inode, UINT8* type, UINT64* index, PANSI_STRING utf8);
NTSTATUS STDCALL find_file_in_dir(device_extension* Vcb, PUNICODE_STRING filename, file_ref* fr,
root** subvol, UINT64* inode, UINT8* type, UINT64* index, PANSI_STRING utf8);
NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* unparsed);
NTSTATUS open_fcb(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb);
NTSTATUS open_fcb_stream(device_extension* Vcb, root* subvol, UINT64 inode, ANSI_STRING* xattr, UINT32 streamhash, fcb* parent, fcb** pfcb);
root** subvol, UINT64* inode, UINT8* type, UINT64* index, PANSI_STRING utf8, PIRP Irp);
NTSTATUS open_fileref(device_extension* Vcb, file_ref** pfr, PUNICODE_STRING fnus, file_ref* related, BOOL parent, USHORT* unparsed, ULONG* fn_offset, PIRP Irp);
NTSTATUS open_fcb(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, PIRP Irp);
NTSTATUS open_fcb_stream(device_extension* Vcb, root* subvol, UINT64 inode, ANSI_STRING* xattr, UINT32 streamhash, fcb* parent, fcb** pfcb, PIRP Irp);
void insert_fileref_child(file_ref* parent, file_ref* child, BOOL do_lock);
NTSTATUS fcb_get_last_dir_index(fcb* fcb, UINT64* index);
NTSTATUS fcb_get_last_dir_index(fcb* fcb, UINT64* index, PIRP Irp);
NTSTATUS verify_vcb(device_extension* Vcb, PIRP Irp);
// in fsctl.c
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP Irp, UINT32 type, BOOL user);
@ -814,29 +844,29 @@ NTSTATUS do_read(PIRP Irp, BOOL wait, ULONG* bytes_read);
NTSTATUS STDCALL drv_pnp(PDEVICE_OBJECT DeviceObject, PIRP Irp);
// in free-space.c
NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c);
NTSTATUS clear_free_space_cache(device_extension* Vcb);
NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, LIST_ENTRY* rollback);
NTSTATUS update_chunk_caches(device_extension* Vcb, LIST_ENTRY* rollback);
NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c, PIRP Irp);
NTSTATUS clear_free_space_cache(device_extension* Vcb, PIRP Irp);
NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS add_space_entry(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 offset, UINT64 size);
void _space_list_add(device_extension* Vcb, chunk* c, BOOL deleting, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, chunk* c, LIST_ENTRY* rollback, const char* func);
void _space_list_subtract(device_extension* Vcb, chunk* c, BOOL deleting, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func);
void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, chunk* c, LIST_ENTRY* rollback, const char* func);
#define space_list_add(Vcb, c, deleting, address, length, rollback) _space_list_add(Vcb, c, deleting, address, length, rollback, funcname)
#define space_list_add2(list, list_size, address, length, rollback) _space_list_add2(list, list_size, address, length, rollback, funcname)
#define space_list_add2(list, list_size, address, length, rollback) _space_list_add2(list, list_size, address, length, NULL, rollback, funcname)
#define space_list_subtract(Vcb, c, deleting, address, length, rollback) _space_list_subtract(Vcb, c, deleting, address, length, rollback, funcname)
#define space_list_subtract2(list, list_size, address, length, rollback) _space_list_subtract2(list, list_size, address, length, rollback, funcname)
#define space_list_subtract2(list, list_size, address, length, rollback) _space_list_subtract2(list, list_size, address, length, NULL, rollback, funcname)
// in extent-tree.c
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_shared_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, UINT64 parent, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_old(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, LIST_ENTRY* rollback);
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_shared_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, UINT64 parent, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS decrease_extent_refcount_old(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, PIRP Irp, LIST_ENTRY* rollback);
void decrease_chunk_usage(chunk* c, UINT64 delta);
NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, LIST_ENTRY* rollback);
UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset);
NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, PIRP Irp, LIST_ENTRY* rollback);
UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, PIRP Irp);
// in worker-thread.c
void STDCALL worker_thread(void* context);
@ -847,7 +877,11 @@ void do_write_job(device_extension* Vcb, PIRP Irp);
void STDCALL read_registry(PUNICODE_STRING regpath);
NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid);
NTSTATUS registry_mark_volume_unmounted(BTRFS_UUID* uuid);
NTSTATUS registry_load_volume_options(BTRFS_UUID* uuid, mount_options* options);
NTSTATUS registry_load_volume_options(device_extension* Vcb);
// in compress.c
NTSTATUS decompress(UINT8 type, UINT8* inbuf, UINT64 inlen, UINT8* outbuf, UINT64 outlen);
NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback);
#define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable)
@ -874,6 +908,23 @@ static __inline void InsertAfter(LIST_ENTRY* head, LIST_ENTRY* item, LIST_ENTRY*
head->Blink = item;
}
static __inline BOOL write_fcb_compressed(fcb* fcb) {
// make sure we don't accidentally write the cache inodes or pagefile compressed
if (fcb->subvol->id == BTRFS_ROOT_ROOT || fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE)
return FALSE;
if (fcb->Vcb->options.compress_force)
return TRUE;
if (fcb->inode_item.flags & BTRFS_INODE_NOCOMPRESS)
return FALSE;
if (fcb->inode_item.flags & BTRFS_INODE_COMPRESS || fcb->Vcb->options.compress)
return TRUE;
return FALSE;
}
#ifdef DEBUG_FCB_REFCOUNTS
#ifdef DEBUG_LONG_MESSAGES
#define increase_fileref_refcount(fileref) {\

View file

@ -1,9 +1,13 @@
// No copyright claimed in this file - do what you want with it.
#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)
#define FSCTL_BTRFS_CREATE_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82a, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_CREATE_SNAPSHOT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82b, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_GET_INODE_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82c, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_SET_INODE_INFO CTL_CODE(FILE_DEVICE_UNKNOWN, 0x82d, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
typedef struct {
UINT64 subvol;
@ -17,4 +21,29 @@ typedef struct {
WCHAR name[1];
} btrfs_create_snapshot;
typedef struct {
UINT64 subvol;
UINT64 inode;
BOOL top;
UINT8 type;
UINT32 st_uid;
UINT32 st_gid;
UINT32 st_mode;
UINT64 st_rdev;
UINT64 flags;
UINT32 inline_length;
UINT64 disk_size[3];
} btrfs_inode_info;
typedef struct {
UINT64 flags;
BOOL flags_changed;
UINT32 st_uid;
BOOL uid_changed;
UINT32 st_gid;
BOOL gid_changed;
UINT32 st_mode;
BOOL mode_changed;
} btrfs_set_inode_info;
#endif

View file

@ -0,0 +1,898 @@
/* Copyright (c) Mark Harmstone 2016
* Copyright (c) Reimar Doeffinger 2006
* Copyright (c) Markus Oberhumer 1996
*
* This file is part of WinBtrfs.
*
* WinBtrfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation, either version 3 of the Licence, or
* (at your option) any later version.
*
* WinBtrfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public Licence for more details.
*
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
// Portion of the LZO decompression code here were cribbed from code in
// libavcodec, also under the LGPL. Thank you, Reimar Doeffinger.
// The LZO compression code comes from v0.22 of lzo, written way back in
// 1996, and available here:
// https://www.ibiblio.org/pub/historic-linux/ftp-archives/sunsite.unc.edu/Sep-29-1996/libs/lzo-0.22.tar.gz
// Modern versions of lzo are licensed under the GPL, but the very oldest
// versions are under the LGPL and hence okay to use here.
#include "btrfs_drv.h"
#define Z_SOLO
#define ZLIB_INTERNAL
#ifndef __REACTOS__
#include "zlib/zlib.h"
#include "zlib/inftrees.h"
#include "zlib/inflate.h"
#else
#include <zlib.h>
#endif
#define LINUX_PAGE_SIZE 4096
typedef struct {
UINT8* in;
UINT32 inlen;
UINT32 inpos;
UINT8* out;
UINT32 outlen;
UINT32 outpos;
BOOL error;
void* wrkmem;
} lzo_stream;
#define LZO1X_MEM_COMPRESS ((UINT32) (16384L * sizeof(UINT8*)))
#define M1_MAX_OFFSET 0x0400
#define M2_MAX_OFFSET 0x0800
#define M3_MAX_OFFSET 0x4000
#define M4_MAX_OFFSET 0xbfff
#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
#define M1_MARKER 0
#define M2_MARKER 64
#define M3_MARKER 32
#define M4_MARKER 16
#define _DV2(p, shift1, shift2) (((( (UINT32)(p[2]) << shift1) ^ p[1]) << shift2) ^ p[0])
#define DVAL_NEXT(dv, p) dv ^= p[-1]; dv = (((dv) >> 5) ^ ((UINT32)(p[2]) << (2*5)))
#define _DV(p, shift) _DV2(p, shift, shift)
#define DVAL_FIRST(dv, p) dv = _DV((p), 5)
#define _DINDEX(dv, p) ((40799u * (dv)) >> 5)
#define DINDEX(dv, p) (((_DINDEX(dv, p)) & 0x3fff) << 0)
#define UPDATE_D(dict, cycle, dv, p) dict[DINDEX(dv, p)] = (p)
#define UPDATE_I(dict, cycle, index, p) dict[index] = (p)
#define LZO_CHECK_MPOS_NON_DET(m_pos, m_off, in, ip, max_offset) \
((void*) m_pos < (void*) in || \
(m_off = (UINT8*) ip - (UINT8*) m_pos) <= 0 || \
m_off > max_offset)
#define LZO_BYTE(x) ((unsigned char) (x))
static UINT8 lzo_nextbyte(lzo_stream* stream) {
UINT8 c;
if (stream->inpos >= stream->inlen) {
stream->error = TRUE;
return 0;
}
c = stream->in[stream->inpos];
stream->inpos++;
return c;
}
static int lzo_len(lzo_stream* stream, int byte, int mask) {
int len = byte & mask;
if (len == 0) {
while (!(byte = lzo_nextbyte(stream))) {
if (stream->error) return 0;
len += 255;
}
len += mask + byte;
}
return len;
}
static void lzo_copy(lzo_stream* stream, int len) {
if (stream->inpos + len > stream->inlen) {
stream->error = TRUE;
return;
}
if (stream->outpos + len > stream->outlen) {
stream->error = TRUE;
return;
}
do {
stream->out[stream->outpos] = stream->in[stream->inpos];
stream->inpos++;
stream->outpos++;
len--;
} while (len > 0);
}
static void lzo_copyback(lzo_stream* stream, int back, int len) {
if (stream->outpos < back) {
stream->error = TRUE;
return;
}
if (stream->outpos + len > stream->outlen) {
stream->error = TRUE;
return;
}
do {
stream->out[stream->outpos] = stream->out[stream->outpos - back];
stream->outpos++;
len--;
} while (len > 0);
}
static NTSTATUS do_lzo_decompress(lzo_stream* stream) {
UINT8 byte;
UINT32 len, back;
BOOL backcopy = FALSE;
stream->error = FALSE;
byte = lzo_nextbyte(stream);
if (stream->error) return STATUS_INTERNAL_ERROR;
if (byte > 17) {
lzo_copy(stream, byte - 17);
if (stream->error) return STATUS_INTERNAL_ERROR;
byte = lzo_nextbyte(stream);
if (stream->error) return STATUS_INTERNAL_ERROR;
if (byte < 16) return STATUS_INTERNAL_ERROR;
}
while (1) {
if (byte >> 4) {
backcopy = TRUE;
if (byte >> 6) {
len = (byte >> 5) - 1;
back = (lzo_nextbyte(stream) << 3) + ((byte >> 2) & 7) + 1;
if (stream->error) return STATUS_INTERNAL_ERROR;
} else if (byte >> 5) {
len = lzo_len(stream, byte, 31);
if (stream->error) return STATUS_INTERNAL_ERROR;
byte = lzo_nextbyte(stream);
if (stream->error) return STATUS_INTERNAL_ERROR;
back = (lzo_nextbyte(stream) << 6) + (byte >> 2) + 1;
if (stream->error) return STATUS_INTERNAL_ERROR;
} else {
len = lzo_len(stream, byte, 7);
if (stream->error) return STATUS_INTERNAL_ERROR;
back = (1 << 14) + ((byte & 8) << 11);
byte = lzo_nextbyte(stream);
if (stream->error) return STATUS_INTERNAL_ERROR;
back += (lzo_nextbyte(stream) << 6) + (byte >> 2);
if (stream->error) return STATUS_INTERNAL_ERROR;
if (back == (1 << 14)) {
if (len != 1)
return STATUS_INTERNAL_ERROR;
break;
}
}
} else if (backcopy) {
len = 0;
back = (lzo_nextbyte(stream) << 2) + (byte >> 2) + 1;
if (stream->error) return STATUS_INTERNAL_ERROR;
} else {
len = lzo_len(stream, byte, 15);
if (stream->error) return STATUS_INTERNAL_ERROR;
lzo_copy(stream, len + 3);
if (stream->error) return STATUS_INTERNAL_ERROR;
byte = lzo_nextbyte(stream);
if (stream->error) return STATUS_INTERNAL_ERROR;
if (byte >> 4)
continue;
len = 1;
back = (1 << 11) + (lzo_nextbyte(stream) << 2) + (byte >> 2) + 1;
if (stream->error) return STATUS_INTERNAL_ERROR;
break;
}
lzo_copyback(stream, back, len + 2);
if (stream->error) return STATUS_INTERNAL_ERROR;
len = byte & 3;
if (len) {
lzo_copy(stream, len);
if (stream->error) return STATUS_INTERNAL_ERROR;
} else
backcopy = !backcopy;
byte = lzo_nextbyte(stream);
if (stream->error) return STATUS_INTERNAL_ERROR;
}
return STATUS_SUCCESS;
}
static NTSTATUS lzo_decompress(UINT8* inbuf, UINT64 inlen, UINT8* outbuf, UINT64 outlen) {
NTSTATUS Status;
UINT32 extlen, partlen, inoff, outoff;
lzo_stream stream;
extlen = *((UINT32*)inbuf);
if (inlen < extlen) {
ERR("compressed extent was %llx, should have been at least %x\n", inlen, extlen);
return STATUS_INTERNAL_ERROR;
}
inoff = sizeof(UINT32);
outoff = 0;
do {
partlen = *(UINT32*)&inbuf[inoff];
if (partlen + inoff > inlen) {
ERR("overflow: %x + %x > %llx\n", partlen, inoff, inlen);
return STATUS_INTERNAL_ERROR;
}
inoff += sizeof(UINT32);
stream.in = &inbuf[inoff];
stream.inlen = partlen;
stream.inpos = 0;
stream.out = &outbuf[outoff];
stream.outlen = LINUX_PAGE_SIZE;
stream.outpos = 0;
Status = do_lzo_decompress(&stream);
if (!NT_SUCCESS(Status)) {
ERR("do_lzo_decompress returned %08x\n", Status);
return Status;
}
if (stream.outpos < stream.outlen)
RtlZeroMemory(&stream.out[stream.outpos], stream.outlen - stream.outpos);
inoff += partlen;
outoff += stream.outlen;
if (LINUX_PAGE_SIZE - (inoff % LINUX_PAGE_SIZE) < sizeof(UINT32))
inoff = ((inoff / LINUX_PAGE_SIZE) + 1) * LINUX_PAGE_SIZE;
} while (inoff < extlen);
return STATUS_SUCCESS;
}
static void* zlib_alloc(void* opaque, unsigned int items, unsigned int size) {
return ExAllocatePoolWithTag(PagedPool, items * size, ALLOC_TAG_ZLIB);
}
static void zlib_free(void* opaque, void* ptr) {
ExFreePool(ptr);
}
static NTSTATUS zlib_decompress(UINT8* inbuf, UINT64 inlen, UINT8* outbuf, UINT64 outlen) {
z_stream c_stream;
int ret;
c_stream.zalloc = zlib_alloc;
c_stream.zfree = zlib_free;
c_stream.opaque = (voidpf)0;
ret = inflateInit(&c_stream);
if (ret != Z_OK) {
ERR("inflateInit returned %08x\n", ret);
return STATUS_INTERNAL_ERROR;
}
c_stream.next_in = inbuf;
c_stream.avail_in = inlen;
c_stream.next_out = outbuf;
c_stream.avail_out = outlen;
do {
ret = inflate(&c_stream, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
ERR("inflate returned %08x\n", ret);
inflateEnd(&c_stream);
return STATUS_INTERNAL_ERROR;
}
} while (ret != Z_STREAM_END);
ret = inflateEnd(&c_stream);
if (ret != Z_OK) {
ERR("inflateEnd returned %08x\n", ret);
return STATUS_INTERNAL_ERROR;
}
// FIXME - if we're short, should we zero the end of outbuf so we don't leak information into userspace?
return STATUS_SUCCESS;
}
NTSTATUS decompress(UINT8 type, UINT8* inbuf, UINT64 inlen, UINT8* outbuf, UINT64 outlen) {
if (type == BTRFS_COMPRESSION_ZLIB)
return zlib_decompress(inbuf, inlen, outbuf, outlen);
else if (type == BTRFS_COMPRESSION_LZO)
return lzo_decompress(inbuf, inlen, outbuf, outlen);
else {
ERR("unsupported compression type %x\n", type);
return STATUS_NOT_SUPPORTED;
}
}
static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
UINT8 compression;
UINT64 comp_length;
UINT8* comp_data;
UINT32 out_left;
LIST_ENTRY* le;
chunk* c;
z_stream c_stream;
int ret;
comp_data = ExAllocatePoolWithTag(PagedPool, end_data - start_data, ALLOC_TAG);
if (!comp_data) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = excise_extents(fcb->Vcb, fcb, start_data, end_data, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("excise_extents returned %08x\n", Status);
ExFreePool(comp_data);
return Status;
}
c_stream.zalloc = zlib_alloc;
c_stream.zfree = zlib_free;
c_stream.opaque = (voidpf)0;
ret = deflateInit(&c_stream, fcb->Vcb->options.zlib_level);
if (ret != Z_OK) {
ERR("deflateInit returned %08x\n", ret);
ExFreePool(comp_data);
return STATUS_INTERNAL_ERROR;
}
c_stream.avail_in = end_data - start_data;
c_stream.next_in = data;
c_stream.avail_out = end_data - start_data;
c_stream.next_out = comp_data;
do {
ret = deflate(&c_stream, Z_FINISH);
if (ret == Z_STREAM_ERROR) {
ERR("deflate returned %x\n", ret);
ExFreePool(comp_data);
return STATUS_INTERNAL_ERROR;
}
} while (c_stream.avail_in > 0 && c_stream.avail_out > 0);
out_left = c_stream.avail_out;
ret = deflateEnd(&c_stream);
if (ret != Z_OK) {
ERR("deflateEnd returned %08x\n", ret);
ExFreePool(comp_data);
return STATUS_INTERNAL_ERROR;
}
if (out_left < fcb->Vcb->superblock.sector_size) { // compressed extent would be larger than or same size as uncompressed extent
ExFreePool(comp_data);
comp_length = end_data - start_data;
comp_data = data;
compression = BTRFS_COMPRESSION_NONE;
*compressed = FALSE;
} else {
UINT32 cl;
compression = BTRFS_COMPRESSION_ZLIB;
cl = end_data - start_data - out_left;
comp_length = sector_align(cl, fcb->Vcb->superblock.sector_size);
RtlZeroMemory(comp_data + cl, comp_length - cl);
*compressed = TRUE;
}
ExAcquireResourceSharedLite(&fcb->Vcb->chunk_lock, TRUE);
le = fcb->Vcb->chunks.Flink;
while (le != &fcb->Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
ExReleaseResourceLite(&c->lock);
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
if (compression != BTRFS_COMPRESSION_NONE)
ExFreePool(comp_data);
return STATUS_SUCCESS;
}
}
ExReleaseResourceLite(&c->lock);
le = le->Flink;
}
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
ExAcquireResourceExclusiveLite(&fcb->Vcb->chunk_lock, TRUE);
if ((c = alloc_chunk(fcb->Vcb, fcb->Vcb->data_flags))) {
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
ExReleaseResourceLite(&c->lock);
if (compression != BTRFS_COMPRESSION_NONE)
ExFreePool(comp_data);
return STATUS_SUCCESS;
}
}
ExReleaseResourceLite(&c->lock);
} else
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
WARN("couldn't find any data chunks with %llx bytes free\n", comp_length);
return STATUS_DISK_FULL;
}
static NTSTATUS lzo_do_compress(const UINT8* in, UINT32 in_len, UINT8* out, UINT32* out_len, void* wrkmem) {
const UINT8* ip;
UINT32 dv;
UINT8* op;
const UINT8* in_end = in + in_len;
const UINT8* ip_end = in + in_len - 9 - 4;
const UINT8* ii;
const UINT8** dict = (const UINT8**)wrkmem;
op = out;
ip = in;
ii = ip;
DVAL_FIRST(dv, ip); UPDATE_D(dict, cycle, dv, ip); ip++;
DVAL_NEXT(dv, ip); UPDATE_D(dict, cycle, dv, ip); ip++;
DVAL_NEXT(dv, ip); UPDATE_D(dict, cycle, dv, ip); ip++;
DVAL_NEXT(dv, ip); UPDATE_D(dict, cycle, dv, ip); ip++;
while (1) {
const UINT8* m_pos;
UINT32 m_len;
ptrdiff_t m_off;
UINT32 lit, dindex;
dindex = DINDEX(dv, ip);
m_pos = dict[dindex];
UPDATE_I(dict, cycle, dindex, ip);
if (!LZO_CHECK_MPOS_NON_DET(m_pos, m_off, in, ip, M4_MAX_OFFSET) && m_pos[0] == ip[0] && m_pos[1] == ip[1] && m_pos[2] == ip[2]) {
lit = ip - ii;
m_pos += 3;
if (m_off <= M2_MAX_OFFSET)
goto match;
if (lit == 3) { /* better compression, but slower */
if (op - 2 <= out)
return STATUS_INTERNAL_ERROR;
op[-2] |= LZO_BYTE(3);
*op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
goto code_match;
}
if (*m_pos == ip[3])
goto match;
}
/* a literal */
++ip;
if (ip >= ip_end)
break;
DVAL_NEXT(dv, ip);
continue;
/* a match */
match:
/* store current literal run */
if (lit > 0) {
UINT32 t = lit;
if (t <= 3) {
if (op - 2 <= out)
return STATUS_INTERNAL_ERROR;
op[-2] |= LZO_BYTE(t);
} else if (t <= 18)
*op++ = LZO_BYTE(t - 3);
else {
UINT32 tt = t - 18;
*op++ = 0;
while (tt > 255) {
tt -= 255;
*op++ = 0;
}
if (tt <= 0)
return STATUS_INTERNAL_ERROR;
*op++ = LZO_BYTE(tt);
}
do {
*op++ = *ii++;
} while (--t > 0);
}
/* code the match */
code_match:
if (ii != ip)
return STATUS_INTERNAL_ERROR;
ip += 3;
if (*m_pos++ != *ip++ || *m_pos++ != *ip++ || *m_pos++ != *ip++ ||
*m_pos++ != *ip++ || *m_pos++ != *ip++ || *m_pos++ != *ip++) {
--ip;
m_len = ip - ii;
if (m_len < 3 || m_len > 8)
return STATUS_INTERNAL_ERROR;
if (m_off <= M2_MAX_OFFSET) {
m_off -= 1;
*op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
*op++ = LZO_BYTE(m_off >> 3);
} else if (m_off <= M3_MAX_OFFSET) {
m_off -= 1;
*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
goto m3_m4_offset;
} else {
m_off -= 0x4000;
if (m_off <= 0 || m_off > 0x7fff)
return STATUS_INTERNAL_ERROR;
*op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
goto m3_m4_offset;
}
} else {
const UINT8* end;
end = in_end;
while (ip < end && *m_pos == *ip)
m_pos++, ip++;
m_len = (ip - ii);
if (m_len < 3)
return STATUS_INTERNAL_ERROR;
if (m_off <= M3_MAX_OFFSET) {
m_off -= 1;
if (m_len <= 33)
*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
else {
m_len -= 33;
*op++ = M3_MARKER | 0;
goto m3_m4_len;
}
} else {
m_off -= 0x4000;
if (m_off <= 0 || m_off > 0x7fff)
return STATUS_INTERNAL_ERROR;
if (m_len <= 9)
*op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
else {
m_len -= 9;
*op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
m3_m4_len:
while (m_len > 255) {
m_len -= 255;
*op++ = 0;
}
if (m_len <= 0)
return STATUS_INTERNAL_ERROR;
*op++ = LZO_BYTE(m_len);
}
}
m3_m4_offset:
*op++ = LZO_BYTE((m_off & 63) << 2);
*op++ = LZO_BYTE(m_off >> 6);
}
ii = ip;
if (ip >= ip_end)
break;
DVAL_FIRST(dv, ip);
}
/* store final literal run */
if (in_end - ii > 0) {
UINT32 t = in_end - ii;
if (op == out && t <= 238)
*op++ = LZO_BYTE(17 + t);
else if (t <= 3)
op[-2] |= LZO_BYTE(t);
else if (t <= 18)
*op++ = LZO_BYTE(t - 3);
else {
UINT32 tt = t - 18;
*op++ = 0;
while (tt > 255) {
tt -= 255;
*op++ = 0;
}
if (tt <= 0)
return STATUS_INTERNAL_ERROR;
*op++ = LZO_BYTE(tt);
}
do {
*op++ = *ii++;
} while (--t > 0);
}
*out_len = op - out;
return STATUS_SUCCESS;
}
static NTSTATUS lzo1x_1_compress(lzo_stream* stream) {
UINT8 *op = stream->out;
NTSTATUS Status = STATUS_SUCCESS;
if (stream->inlen <= 0)
stream->outlen = 0;
else if (stream->inlen <= 9 + 4) {
*op++ = LZO_BYTE(17 + stream->inlen);
stream->inpos = 0;
do {
*op++ = stream->in[stream->inpos];
stream->inpos++;
} while (stream->inlen < stream->inpos);
stream->outlen = op - stream->out;
} else
Status = lzo_do_compress(stream->in, stream->inlen, stream->out, &stream->outlen, stream->wrkmem);
if (Status == STATUS_SUCCESS) {
op = stream->out + stream->outlen;
*op++ = M4_MARKER | 1;
*op++ = 0;
*op++ = 0;
stream->outlen += 3;
}
return Status;
}
static __inline UINT32 lzo_max_outlen(UINT32 inlen) {
return inlen + (inlen / 16) + 64 + 3; // formula comes from LZO.FAQ
}
static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
UINT8 compression;
UINT64 comp_length;
ULONG comp_data_len, num_pages, i;
UINT8* comp_data;
BOOL skip_compression = FALSE;
lzo_stream stream;
UINT32* out_size;
LIST_ENTRY* le;
chunk* c;
num_pages = (sector_align(end_data - start_data, LINUX_PAGE_SIZE)) / LINUX_PAGE_SIZE;
// Four-byte overall header
// Another four-byte header page
// Each page has a maximum size of lzo_max_outlen(LINUX_PAGE_SIZE)
// Plus another four bytes for possible padding
comp_data_len = sizeof(UINT32) + ((lzo_max_outlen(LINUX_PAGE_SIZE) + (2 * sizeof(UINT32))) * num_pages);
comp_data = ExAllocatePoolWithTag(PagedPool, comp_data_len, ALLOC_TAG);
if (!comp_data) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
stream.wrkmem = ExAllocatePoolWithTag(PagedPool, LZO1X_MEM_COMPRESS, ALLOC_TAG);
if (!stream.wrkmem) {
ERR("out of memory\n");
ExFreePool(comp_data);
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = excise_extents(fcb->Vcb, fcb, start_data, end_data, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("excise_extents returned %08x\n", Status);
ExFreePool(comp_data);
ExFreePool(stream.wrkmem);
return Status;
}
out_size = (UINT32*)comp_data;
*out_size = sizeof(UINT32);
stream.in = data;
stream.out = comp_data + (2 * sizeof(UINT32));
for (i = 0; i < num_pages; i++) {
UINT32* pagelen = (UINT32*)(stream.out - sizeof(UINT32));
stream.inlen = min(LINUX_PAGE_SIZE, end_data - start_data - (i * LINUX_PAGE_SIZE));
Status = lzo1x_1_compress(&stream);
if (!NT_SUCCESS(Status)) {
ERR("lzo1x_1_compress returned %08x\n", Status);
skip_compression = TRUE;
break;
}
*pagelen = stream.outlen;
*out_size += stream.outlen + sizeof(UINT32);
stream.in += LINUX_PAGE_SIZE;
stream.out += stream.outlen + sizeof(UINT32);
if (LINUX_PAGE_SIZE - (*out_size % LINUX_PAGE_SIZE) < sizeof(UINT32)) {
RtlZeroMemory(stream.out, LINUX_PAGE_SIZE - (*out_size % LINUX_PAGE_SIZE));
stream.out += LINUX_PAGE_SIZE - (*out_size % LINUX_PAGE_SIZE);
*out_size += LINUX_PAGE_SIZE - (*out_size % LINUX_PAGE_SIZE);
}
}
ExFreePool(stream.wrkmem);
if (skip_compression || *out_size >= end_data - start_data - fcb->Vcb->superblock.sector_size) { // compressed extent would be larger than or same size as uncompressed extent
ExFreePool(comp_data);
comp_length = end_data - start_data;
comp_data = data;
compression = BTRFS_COMPRESSION_NONE;
*compressed = FALSE;
} else {
compression = BTRFS_COMPRESSION_LZO;
comp_length = sector_align(*out_size, fcb->Vcb->superblock.sector_size);
RtlZeroMemory(comp_data + *out_size, comp_length - *out_size);
*compressed = TRUE;
}
ExAcquireResourceSharedLite(&fcb->Vcb->chunk_lock, TRUE);
le = fcb->Vcb->chunks.Flink;
while (le != &fcb->Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
ExReleaseResourceLite(&c->lock);
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
if (compression != BTRFS_COMPRESSION_NONE)
ExFreePool(comp_data);
return STATUS_SUCCESS;
}
}
ExReleaseResourceLite(&c->lock);
le = le->Flink;
}
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
ExAcquireResourceExclusiveLite(&fcb->Vcb->chunk_lock, TRUE);
if ((c = alloc_chunk(fcb->Vcb, fcb->Vcb->data_flags))) {
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == fcb->Vcb->data_flags && (c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE, comp_data, changed_sector_list, Irp, rollback, compression, end_data - start_data)) {
ExReleaseResourceLite(&c->lock);
if (compression != BTRFS_COMPRESSION_NONE)
ExFreePool(comp_data);
return STATUS_SUCCESS;
}
}
ExReleaseResourceLite(&c->lock);
} else
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
WARN("couldn't find any data chunks with %llx bytes free\n", comp_length);
return STATUS_DISK_FULL;
}
NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data, BOOL* compressed, LIST_ENTRY* changed_sector_list, PIRP Irp, LIST_ENTRY* rollback) {
UINT8 type;
if (fcb->Vcb->options.compress_type != 0)
type = fcb->Vcb->options.compress_type;
else {
if (fcb->Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO)
type = BTRFS_COMPRESSION_LZO;
else
type = BTRFS_COMPRESSION_ZLIB;
}
if (type == BTRFS_COMPRESSION_LZO) {
fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO;
return lzo_write_compressed_bit(fcb, start_data, end_data, data, compressed, changed_sector_list, Irp, rollback);
} else
return zlib_write_compressed_bit(fcb, start_data, end_data, data, compressed, changed_sector_list, Irp, rollback);
}

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,7 @@ typedef struct {
enum DirEntryType dir_entry_type;
} dir_entry;
static ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, ULONG atts) {
ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type, ULONG atts, PIRP Irp) {
fcb* fcb;
ULONG tag = 0, br;
NTSTATUS Status;
@ -49,7 +49,7 @@ static ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64
return 0;
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
Status = open_fcb(Vcb, subvol, inode, type, NULL, NULL, &fcb);
Status = open_fcb(Vcb, subvol, inode, type, NULL, NULL, &fcb, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fcb returned %08x\n", Status);
ExReleaseResourceLite(&Vcb->fcb_lock);
@ -78,7 +78,9 @@ static ULONG STDCALL get_reparse_tag(device_extension* Vcb, root* subvol, UINT64
end:
ExReleaseResourceLite(fcb->Header.Resource);
ExAcquireResourceExclusiveLite(&Vcb->fcb_lock, TRUE);
free_fcb(fcb);
ExReleaseResourceLite(&Vcb->fcb_lock);
return tag;
}
@ -154,7 +156,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
searchkey.obj_type = TYPE_INODE_ITEM;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(fcb->Vcb, r, &tp, &searchkey, FALSE);
Status = find_item(fcb->Vcb, r, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -177,7 +179,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
BOOL dotfile = de->namelen > 1 && de->name[0] == '.';
atts = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE);
atts = get_file_attributes(fcb->Vcb, &ii, r, inode, de->type, dotfile, FALSE, Irp);
}
}
@ -238,12 +240,12 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fbdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
fbdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
fbdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
fbdi->ChangeTime.QuadPart = 0;
fbdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
fbdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
fbdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
fbdi->FileAttributes = atts;
fbdi->FileNameLength = stringlen;
fbdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts);
fbdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, Irp);
fbdi->ShortNameLength = 0;
// fibdi->ShortName[12];
@ -277,7 +279,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
fdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
fdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
fdi->ChangeTime.QuadPart = 0;
fdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
fdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
fdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
fdi->FileAttributes = atts;
@ -313,12 +315,12 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
ffdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
ffdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
ffdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
ffdi->ChangeTime.QuadPart = 0;
ffdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
ffdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
ffdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
ffdi->FileAttributes = atts;
ffdi->FileNameLength = stringlen;
ffdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts);
ffdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, Irp);
Status = RtlUTF8ToUnicodeN(ffdi->FileName, stringlen, &stringlen, de->name, de->namelen);
@ -353,12 +355,12 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
fibdi->CreationTime.QuadPart = unix_time_to_win(&ii.otime);
fibdi->LastAccessTime.QuadPart = unix_time_to_win(&ii.st_atime);
fibdi->LastWriteTime.QuadPart = unix_time_to_win(&ii.st_mtime);
fibdi->ChangeTime.QuadPart = 0;
fibdi->ChangeTime.QuadPart = unix_time_to_win(&ii.st_ctime);
fibdi->EndOfFile.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_size;
fibdi->AllocationSize.QuadPart = de->type == BTRFS_TYPE_SYMLINK ? 0 : ii.st_blocks;
fibdi->FileAttributes = atts;
fibdi->FileNameLength = stringlen;
fibdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts);
fibdi->EaSize = get_reparse_tag(fcb->Vcb, r, inode, de->type, atts, Irp);
fibdi->ShortNameLength = 0;
// fibdi->ShortName[12];
fibdi->FileId.QuadPart = inode;
@ -428,7 +430,7 @@ static NTSTATUS STDCALL query_dir_item(fcb* fcb, file_ref* fileref, void* buf, L
return STATUS_NO_MORE_FILES;
}
static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_entry* de) {
static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_entry* de, PIRP Irp) {
KEY searchkey;
traverse_ptr tp, next_tp;
DIR_ITEM* di;
@ -520,14 +522,14 @@ static NTSTATUS STDCALL next_dir_entry(file_ref* fileref, UINT64* offset, dir_en
searchkey.obj_type = TYPE_DIR_INDEX;
searchkey.offset = *offset;
Status = find_item(fileref->fcb->Vcb, fileref->fcb->subvol, &tp, &searchkey, FALSE);
Status = find_item(fileref->fcb->Vcb, fileref->fcb->subvol, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
goto end;
}
if (keycmp(&tp.item->key, &searchkey) == -1) {
if (find_next_item(fileref->fcb->Vcb, &tp, &next_tp, FALSE))
if (find_next_item(fileref->fcb->Vcb, &tp, &next_tp, FALSE, Irp))
tp = next_tp;
}
@ -766,7 +768,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
}
newoffset = ccb->query_dir_offset;
Status = next_dir_entry(fileref, &newoffset, &de);
Status = next_dir_entry(fileref, &newoffset, &de, Irp);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_NO_MORE_FILES && initial)
@ -845,7 +847,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExFreePool(us.Buffer);
if (!found) {
Status = find_file_in_dir(fcb->Vcb, &ccb->query_string, fileref, &found_subvol, &found_inode, &found_type, &found_index, &utf8);
Status = find_file_in_dir(fcb->Vcb, &ccb->query_string, fileref, &found_subvol, &found_inode, &found_type, &found_index, &utf8, Irp);
if (!NT_SUCCESS(Status)) {
Status = STATUS_NO_SUCH_FILE;
@ -901,7 +903,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExFreePool(de.name);
newoffset = ccb->query_dir_offset;
Status = next_dir_entry(fileref, &newoffset, &de);
Status = next_dir_entry(fileref, &newoffset, &de, Irp);
ExFreePool(uni_fn);
if (NT_SUCCESS(Status)) {
@ -976,7 +978,7 @@ static NTSTATUS STDCALL query_directory(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
UNICODE_STRING di_uni_fn;
newoffset = ccb->query_dir_offset;
Status = next_dir_entry(fileref, &newoffset, &de);
Status = next_dir_entry(fileref, &newoffset, &de, Irp);
if (NT_SUCCESS(Status)) {
if (has_wildcard) {
ULONG stringlen;

View file

@ -91,7 +91,7 @@ static UINT64 get_extent_hash(UINT8 type, void* data) {
}
}
static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem, UINT8 level, LIST_ENTRY* rollback) {
static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem, UINT8 level, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
KEY searchkey;
traverse_ptr tp;
@ -113,7 +113,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
searchkey.obj_type = TYPE_EXTENT_ITEM;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -153,7 +153,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
*ptr = type;
RtlCopyMemory(ptr + 1, data, datalen);
if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_EXTENT_ITEM, size, ei, eisize, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_EXTENT_ITEM, size, ei, eisize, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -184,13 +184,13 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, ei, sizeof(EXTENT_ITEM), NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, ei, sizeof(EXTENT_ITEM), NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
ExFreePool(ei);
return STATUS_INTERNAL_ERROR;
}
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -265,7 +265,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -335,7 +335,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size + sizeof(UINT8) + datalen, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size + sizeof(UINT8) + datalen, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -352,7 +352,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
searchkey.obj_type = type;
searchkey.offset = offset;
Status = find_item(Vcb, Vcb->extent_root, &tp2, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp2, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -381,7 +381,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp2, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, data2, tp2.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, data2, tp2.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -394,7 +394,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -408,7 +408,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
data2 = ExAllocatePoolWithTag(PagedPool, datalen, ALLOC_TAG);
RtlCopyMemory(data2, data, datalen);
if (!insert_tree_item(Vcb, Vcb->extent_root, address, type, offset, data2, datalen, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, address, type, offset, data2, datalen, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -421,7 +421,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -429,7 +429,7 @@ static NTSTATUS increase_extent_refcount(device_extension* Vcb, UINT64 address,
return STATUS_SUCCESS;
}
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback) {
NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode, UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback) {
EXTENT_DATA_REF edr;
edr.root = root;
@ -437,7 +437,7 @@ NTSTATUS increase_extent_refcount_data(device_extension* Vcb, UINT64 address, UI
edr.offset = offset;
edr.count = refcount;
return increase_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, rollback);
return increase_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, Irp, rollback);
}
void decrease_chunk_usage(chunk* c, UINT64 delta) {
@ -447,7 +447,7 @@ void decrease_chunk_usage(chunk* c, UINT64 delta) {
}
static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT8 type, void* data, KEY* firstitem,
UINT8 level, UINT64 parent, LIST_ENTRY* rollback) {
UINT8 level, UINT64 parent, PIRP Irp, LIST_ENTRY* rollback) {
KEY searchkey;
NTSTATUS Status;
traverse_ptr tp, tp2;
@ -464,7 +464,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
searchkey.obj_type = TYPE_EXTENT_ITEM;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -498,13 +498,13 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, ei, sizeof(EXTENT_ITEM), &tp, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, ei, sizeof(EXTENT_ITEM), &tp, Irp, rollback)) {
ERR("insert_tree_item failed\n");
ExFreePool(ei);
return STATUS_INTERNAL_ERROR;
}
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -604,7 +604,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, neweilen, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, neweilen, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -643,7 +643,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, neweilen, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, neweilen, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -670,7 +670,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
searchkey.obj_type = type;
searchkey.offset = (type == TYPE_SHARED_DATA_REF || type == TYPE_EXTENT_REF_V0) ? parent : get_extent_hash(type, data);
Status = find_item(Vcb, Vcb->extent_root, &tp2, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp2, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -717,7 +717,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
newedr->count -= edr->count;
if (!insert_tree_item(Vcb, Vcb->extent_root, tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, newedr, tp2.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset, newedr, tp2.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -736,7 +736,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -775,7 +775,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -810,7 +810,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
delete_tree_item(Vcb, &tp, rollback);
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, newei, tp.item->size, NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
@ -823,7 +823,7 @@ static NTSTATUS decrease_extent_refcount(device_extension* Vcb, UINT64 address,
}
NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 inode,
UINT64 offset, UINT32 refcount, LIST_ENTRY* rollback) {
UINT64 offset, UINT32 refcount, PIRP Irp, LIST_ENTRY* rollback) {
EXTENT_DATA_REF edr;
edr.root = root;
@ -831,20 +831,20 @@ NTSTATUS decrease_extent_refcount_data(device_extension* Vcb, UINT64 address, UI
edr.offset = offset;
edr.count = refcount;
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, 0, rollback);
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_DATA_REF, &edr, NULL, 0, 0, Irp, rollback);
}
NTSTATUS decrease_extent_refcount_shared_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, UINT64 parent, LIST_ENTRY* rollback) {
NTSTATUS decrease_extent_refcount_shared_data(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, UINT64 parent, PIRP Irp, LIST_ENTRY* rollback) {
SHARED_DATA_REF sdr;
sdr.offset = treeaddr;
sdr.count = 1;
return decrease_extent_refcount(Vcb, address, size, TYPE_SHARED_DATA_REF, &sdr, NULL, 0, parent, rollback);
return decrease_extent_refcount(Vcb, address, size, TYPE_SHARED_DATA_REF, &sdr, NULL, 0, parent, Irp, rollback);
}
NTSTATUS decrease_extent_refcount_old(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, LIST_ENTRY* rollback) {
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_REF_V0, NULL, NULL, 0, treeaddr, rollback);
NTSTATUS decrease_extent_refcount_old(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 treeaddr, PIRP Irp, LIST_ENTRY* rollback) {
return decrease_extent_refcount(Vcb, address, size, TYPE_EXTENT_REF_V0, NULL, NULL, 0, treeaddr, Irp, rollback);
}
typedef struct {
@ -918,7 +918,7 @@ static NTSTATUS add_data_extent_ref(LIST_ENTRY* extent_refs, UINT64 tree_id, UIN
return STATUS_SUCCESS;
}
static NTSTATUS construct_extent_item(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 flags, LIST_ENTRY* extent_refs, LIST_ENTRY* rollback) {
static NTSTATUS construct_extent_item(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 flags, LIST_ENTRY* extent_refs, PIRP Irp, LIST_ENTRY* rollback) {
LIST_ENTRY *le, *next_le;
UINT64 refcount;
ULONG inline_len;
@ -1005,7 +1005,7 @@ static NTSTATUS construct_extent_item(device_extension* Vcb, UINT64 address, UIN
le = le->Flink;
}
if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_EXTENT_ITEM, size, ei, inline_len, NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, address, TYPE_EXTENT_ITEM, size, ei, inline_len, NULL, Irp, rollback)) {
ERR("error - failed to insert item\n");
ExFreePool(ei);
return STATUS_INTERNAL_ERROR;
@ -1017,7 +1017,7 @@ static NTSTATUS construct_extent_item(device_extension* Vcb, UINT64 address, UIN
while (le != extent_refs) {
extent_ref* er = CONTAINING_RECORD(le, extent_ref, list_entry);
if (!insert_tree_item(Vcb, Vcb->extent_root, address, er->type, er->hash, er->data, get_extent_data_len(er->type), NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->extent_root, address, er->type, er->hash, er->data, get_extent_data_len(er->type), NULL, Irp, rollback)) {
ERR("error - failed to insert item\n");
return STATUS_INTERNAL_ERROR;
}
@ -1081,7 +1081,7 @@ static NTSTATUS populate_extent_refs_from_tree(device_extension* Vcb, UINT64 tre
return STATUS_SUCCESS;
}
NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, LIST_ENTRY* rollback) {
NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 size, PIRP Irp, LIST_ENTRY* rollback) {
KEY searchkey;
traverse_ptr tp, next_tp;
BOOL b;
@ -1092,7 +1092,7 @@ NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 s
searchkey.obj_type = TYPE_EXTENT_ITEM;
searchkey.offset = size;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -1114,7 +1114,7 @@ NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 s
searchkey.obj_type = TYPE_EXTENT_REF_V0;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -1123,7 +1123,7 @@ NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 s
InitializeListHead(&extent_refs);
do {
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
Status = populate_extent_refs_from_tree(Vcb, tp.item->key.offset, address, &extent_refs);
@ -1143,7 +1143,7 @@ NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 s
}
} while (b);
Status = construct_extent_item(Vcb, address, size, EXTENT_ITEM_DATA, &extent_refs, rollback);
Status = construct_extent_item(Vcb, address, size, EXTENT_ITEM_DATA, &extent_refs, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("construct_extent_item returned %08x\n", Status);
free_extent_refs(&extent_refs);
@ -1155,7 +1155,7 @@ NTSTATUS convert_old_data_extent(device_extension* Vcb, UINT64 address, UINT64 s
return STATUS_SUCCESS;
}
UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset) {
UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 size, UINT64 root, UINT64 objid, UINT64 offset, PIRP Irp) {
NTSTATUS Status;
KEY searchkey;
traverse_ptr tp;
@ -1166,14 +1166,14 @@ UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 s
searchkey.obj_type = TYPE_EXTENT_ITEM;
searchkey.offset = 0xffffffffffffffff;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return 0;
}
if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
ERR("could not find address %llx in extent tree\n", address);
TRACE("could not find address %llx in extent tree\n", address);
return 0;
}
@ -1249,7 +1249,7 @@ UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 s
searchkey.obj_type = TYPE_EXTENT_DATA_REF;
searchkey.offset = get_extent_data_ref_hash2(root, objid, offset);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return 0;
@ -1272,7 +1272,7 @@ UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 s
searchkey.obj_type = TYPE_EXTENT_REF_V0;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return 0;
@ -1281,7 +1281,7 @@ UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 s
do {
traverse_ptr next_tp;
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
if (tp.item->size >= sizeof(EXTENT_REF_V0)) {
@ -1335,7 +1335,7 @@ UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 s
searchkey.obj_type = TYPE_SHARED_DATA_REF;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return 0;
@ -1344,7 +1344,7 @@ UINT64 find_extent_data_refcount(device_extension* Vcb, UINT64 address, UINT64 s
do {
traverse_ptr next_tp;
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
if (tp.item->size >= sizeof(SHARED_DATA_REF)) {

View file

@ -67,7 +67,7 @@ static BOOLEAN STDCALL fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wa
fbi->CreationTime.QuadPart = unix_time_to_win(&fcb->inode_item.otime);
fbi->LastAccessTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_atime);
fbi->LastWriteTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_mtime);
fbi->ChangeTime.QuadPart = 0;
fbi->ChangeTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_ctime);
fbi->FileAttributes = fcb->atts;
IoStatus->Status = STATUS_SUCCESS;
@ -212,9 +212,22 @@ static BOOLEAN STDCALL fast_io_query_network_open_info(PFILE_OBJECT FileObject,
return FALSE;
}
static NTSTATUS STDCALL fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset, struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject){
TRACE("STUB: fast_io_acquire_for_mod_write\n");
return STATUS_NOT_IMPLEMENTED;
static NTSTATUS STDCALL fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset, struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject) {
fcb* fcb;
TRACE("(%p, %llx, %p, %p)\n", FileObject, EndingOffset->QuadPart, ResourceToRelease, DeviceObject);
fcb = FileObject->FsContext;
if (!fcb)
return STATUS_INVALID_PARAMETER;
*ResourceToRelease = fcb->Header.PagingIoResource;
if (!ExAcquireResourceSharedLite(*ResourceToRelease, FALSE))
return STATUS_CANT_WAIT;
return STATUS_SUCCESS;
}
static BOOLEAN STDCALL fast_io_read_compressed(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, ULONG LockKey, PVOID Buffer, PMDL *MdlChain, PIO_STATUS_BLOCK IoStatus, struct _COMPRESSED_DATA_INFO *CompressedDataInfo, ULONG CompressedDataInfoLength, PDEVICE_OBJECT DeviceObject){

File diff suppressed because it is too large Load diff

View file

@ -17,8 +17,6 @@
#include "btrfs_drv.h"
#define INTERVAL 15000 // in milliseconds
static void do_flush(device_extension* Vcb) {
LIST_ENTRY rollback;
@ -28,8 +26,8 @@ static void do_flush(device_extension* Vcb) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
if (Vcb->need_write)
do_write(Vcb, &rollback);
if (Vcb->need_write && !Vcb->readonly)
do_write(Vcb, NULL, &rollback);
free_trees(Vcb);
@ -49,7 +47,7 @@ void STDCALL flush_thread(void* context) {
KeInitializeTimer(&Vcb->flush_thread_timer);
due_time.QuadPart = -INTERVAL * 10000;
due_time.QuadPart = (UINT64)Vcb->options.flush_interval * -10000000;
KeSetTimer(&Vcb->flush_thread_timer, due_time, NULL);

View file

@ -23,11 +23,11 @@
// #define DEBUG_SPACE_LISTS
static NTSTATUS remove_free_space_inode(device_extension* Vcb, UINT64 inode, LIST_ENTRY* rollback) {
static NTSTATUS remove_free_space_inode(device_extension* Vcb, UINT64 inode, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
fcb* fcb;
Status = open_fcb(Vcb, Vcb->root_root, inode, BTRFS_TYPE_FILE, NULL, NULL, &fcb);
Status = open_fcb(Vcb, Vcb->root_root, inode, BTRFS_TYPE_FILE, NULL, NULL, &fcb, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fcb returned %08x\n", Status);
return Status;
@ -36,7 +36,7 @@ static NTSTATUS remove_free_space_inode(device_extension* Vcb, UINT64 inode, LIS
fcb->dirty = TRUE;
if (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), rollback);
Status = excise_extents(fcb->Vcb, fcb, 0, sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size), Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("excise_extents returned %08x\n", Status);
return Status;
@ -45,14 +45,14 @@ static NTSTATUS remove_free_space_inode(device_extension* Vcb, UINT64 inode, LIS
fcb->deleted = TRUE;
flush_fcb(fcb, FALSE, rollback);
flush_fcb(fcb, FALSE, Irp, rollback);
free_fcb(fcb);
return STATUS_SUCCESS;
}
NTSTATUS clear_free_space_cache(device_extension* Vcb) {
NTSTATUS clear_free_space_cache(device_extension* Vcb, PIRP Irp) {
KEY searchkey;
traverse_ptr tp, next_tp;
NTSTATUS Status;
@ -65,7 +65,7 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb) {
searchkey.obj_type = 0;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -86,7 +86,7 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb) {
else {
LIST_ENTRY* le;
Status = remove_free_space_inode(Vcb, fsi->key.obj_id, &rollback);
Status = remove_free_space_inode(Vcb, fsi->key.obj_id, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("remove_free_space_inode for (%llx,%x,%llx) returned %08x\n", fsi->key.obj_id, fsi->key.obj_type, fsi->key.offset, Status);
@ -109,7 +109,7 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb) {
WARN("(%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(FREE_SPACE_ITEM));
}
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (b)
tp = next_tp;
} while (b);
@ -245,7 +245,7 @@ static void order_space_entry(space* s, LIST_ENTRY* list_size) {
InsertTailList(list_size, &s->list_entry_size);
}
static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c) {
static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c, PIRP Irp) {
KEY searchkey;
traverse_ptr tp;
FREE_SPACE_ITEM* fsi;
@ -266,7 +266,7 @@ static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c) {
searchkey.obj_type = 0;
searchkey.offset = c->offset;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -293,10 +293,10 @@ static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c) {
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);
Status = open_fcb(Vcb, Vcb->root_root, inode, BTRFS_TYPE_FILE, NULL, NULL, &c->cache, Irp);
if (!NT_SUCCESS(Status)) {
ERR("open_fcb returned %08x\n", Status);
return Status;
return STATUS_NOT_FOUND;
}
if (c->cache->inode_item.st_size == 0) {
@ -329,7 +329,7 @@ static NTSTATUS load_stored_free_space_cache(device_extension* Vcb, chunk* c) {
free_fcb(c->cache);
c->cache = NULL;
return Status;
return STATUS_NOT_FOUND;
}
if (size > c->cache->inode_item.st_size)
@ -446,7 +446,7 @@ clearcache:
InitializeListHead(&rollback);
Status = excise_extents(Vcb, c->cache, 0, c->cache->inode_item.st_size, &rollback);
Status = excise_extents(Vcb, c->cache, 0, c->cache->inode_item.st_size, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("excise_extents returned %08x\n", Status);
do_rollback(Vcb, &rollback);
@ -463,7 +463,7 @@ clearcache:
return STATUS_NOT_FOUND;
}
NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c) {
NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c, PIRP Irp) {
traverse_ptr tp, next_tp;
KEY searchkey;
UINT64 lastaddr;
@ -473,7 +473,7 @@ NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c) {
// LIST_ENTRY* le;
if (Vcb->superblock.generation - 1 == Vcb->superblock.cache_generation) {
Status = load_stored_free_space_cache(Vcb, c);
Status = load_stored_free_space_cache(Vcb, c, Irp);
if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) {
ERR("load_stored_free_space_cache returned %08x\n", Status);
@ -489,7 +489,7 @@ NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c) {
searchkey.obj_type = TYPE_EXTENT_ITEM;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -525,7 +525,7 @@ NTSTATUS load_free_space_cache(device_extension* Vcb, chunk* c) {
lastaddr = tp.item->key.obj_id + tp.item->key.offset;
}
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (b)
tp = next_tp;
} while (b);
@ -568,48 +568,52 @@ static NTSTATUS insert_cache_extent(fcb* fcb, UINT64 start, UINT64 length, LIST_
flags = fcb->Vcb->data_flags;
ExAcquireResourceExclusiveLite(&fcb->Vcb->chunk_lock, TRUE);
ExAcquireResourceSharedLite(&fcb->Vcb->chunk_lock, TRUE);
while (le != &fcb->Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry);
ExAcquireResourceExclusiveLite(&c->nonpaged->lock, TRUE);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, NULL, rollback)) {
ExReleaseResourceLite(&c->nonpaged->lock);
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length)) {
ExReleaseResourceLite(&c->lock);
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
return STATUS_SUCCESS;
}
}
ExReleaseResourceLite(&c->nonpaged->lock);
ExReleaseResourceLite(&c->lock);
le = le->Flink;
}
if ((c = alloc_chunk(fcb->Vcb, flags, rollback))) {
ExAcquireResourceExclusiveLite(&c->nonpaged->lock, TRUE);
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
ExAcquireResourceExclusiveLite(&fcb->Vcb->chunk_lock, TRUE);
if ((c = alloc_chunk(fcb->Vcb, flags))) {
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, NULL, rollback)) {
ExReleaseResourceLite(&c->nonpaged->lock);
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, length)) {
ExReleaseResourceLite(&c->lock);
return STATUS_SUCCESS;
}
}
ExReleaseResourceLite(&c->nonpaged->lock);
}
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
ExReleaseResourceLite(&c->lock);
} else
ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
WARN("couldn't find any data chunks with %llx bytes free\n", length);
return STATUS_DISK_FULL;
}
static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* changed, LIST_ENTRY* rollback) {
static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* changed, PIRP Irp, LIST_ENTRY* rollback) {
LIST_ENTRY* le;
NTSTATUS Status;
UINT64 num_entries, new_cache_size, i;
@ -669,7 +673,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
// create new inode
c->cache = create_fcb();
c->cache = create_fcb(PagedPool);
if (!c->cache) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
@ -691,7 +695,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
c->cache->subvol = Vcb->root_root;
if (Vcb->root_root->lastinode == 0)
get_last_inode(Vcb, Vcb->root_root);
get_last_inode(Vcb, Vcb->root_root, Irp);
c->cache->inode = Vcb->root_root->lastinode > 0x100 ? (Vcb->root_root->lastinode + 1) : 0x101;
@ -712,9 +716,12 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
searchkey.obj_type = 0;
searchkey.offset = c->offset;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
ExFreePool(fsi);
free_fcb(c->cache);
c->cache = NULL;
return Status;
}
@ -725,7 +732,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
fsi->key.obj_type = TYPE_INODE_ITEM;
fsi->key.offset = 0;
if (!insert_tree_item(Vcb, Vcb->root_root, FREE_SPACE_CACHE_ID, 0, c->offset, fsi, sizeof(FREE_SPACE_ITEM), NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->root_root, FREE_SPACE_CACHE_ID, 0, c->offset, fsi, sizeof(FREE_SPACE_ITEM), NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
free_fcb(c->cache);
c->cache = NULL;
@ -746,7 +753,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
Vcb->root_root->lastinode = c->cache->inode;
flush_fcb(c->cache, TRUE, rollback);
flush_fcb(c->cache, TRUE, Irp, rollback);
*changed = TRUE;
} else if (new_cache_size > c->cache->inode_item.st_size) {
@ -764,7 +771,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
searchkey.obj_type = 0;
searchkey.offset = c->offset;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -795,7 +802,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
c->cache->inode_item.st_size = new_cache_size;
c->cache->inode_item.st_blocks = new_cache_size;
flush_fcb(c->cache, TRUE, rollback);
flush_fcb(c->cache, TRUE, Irp, rollback);
*changed = TRUE;
} else {
@ -808,7 +815,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
searchkey.obj_type = TYPE_INODE_ITEM;
searchkey.offset = 0;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -820,10 +827,12 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
ii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG);
RtlCopyMemory(ii, &c->cache->inode_item, sizeof(INODE_ITEM));
if (!insert_tree_item(Vcb, Vcb->root_root, c->cache->inode, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, rollback)) {
if (!insert_tree_item(Vcb, Vcb->root_root, c->cache->inode, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, Irp, rollback)) {
ERR("insert_tree_item failed\n");
return STATUS_INTERNAL_ERROR;
}
*changed = TRUE;
} else {
if (tp.item->size < sizeof(INODE_ITEM)) {
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(INODE_ITEM));
@ -837,7 +846,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
searchkey.obj_type = 0;
searchkey.offset = c->offset;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -861,7 +870,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, BOOL* chan
return STATUS_SUCCESS;
}
NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, LIST_ENTRY* rollback) {
NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP Irp, LIST_ENTRY* rollback) {
LIST_ENTRY* le = Vcb->chunks_changed.Flink;
NTSTATUS Status;
@ -871,9 +880,9 @@ NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, LIST_ENTRY* rollba
BOOL b;
chunk* c = CONTAINING_RECORD(le, chunk, list_entry_changed);
ExAcquireResourceExclusiveLite(&c->nonpaged->lock, TRUE);
Status = allocate_cache_chunk(Vcb, c, &b, rollback);
ExReleaseResourceLite(&c->nonpaged->lock);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
Status = allocate_cache_chunk(Vcb, c, &b, Irp, rollback);
ExReleaseResourceLite(&c->lock);
if (b)
*changed = TRUE;
@ -889,7 +898,25 @@ NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, LIST_ENTRY* rollba
return STATUS_SUCCESS;
}
void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func) {
static void add_rollback_space(LIST_ENTRY* rollback, BOOL add, LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, chunk* c) {
rollback_space* rs;
rs = ExAllocatePoolWithTag(PagedPool, sizeof(rollback_space), ALLOC_TAG);
if (!rs) {
ERR("out of memory\n");
return;
}
rs->list = list;
rs->list_size = list_size;
rs->address = address;
rs->length = length;
rs->chunk = c;
add_rollback(rollback, add ? ROLLBACK_ADD_SPACE : ROLLBACK_SUBTRACT_SPACE, rs);
}
void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, chunk* c, LIST_ENTRY* rollback, const char* func) {
LIST_ENTRY* le;
space *s, *s2;
@ -912,7 +939,8 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
if (list_size)
InsertTailList(list_size, &s->list_entry_size);
// FIXME - insert rollback entry
if (rollback)
add_rollback_space(rollback, TRUE, list, list_size, address, length, c);
return;
}
@ -928,9 +956,11 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
// new entry envelops old one completely
if (address <= s2->address && address + length >= s2->address + s2->size) {
if (address < s2->address) {
if (rollback)
add_rollback_space(rollback, TRUE, list, list_size, address, s2->address - address, c);
s2->size += s2->address - address;
s2->address = address;
// FIXME - insert rollback
while (s2->list_entry.Blink != list) {
space* s3 = CONTAINING_RECORD(s2->list_entry.Blink, space, list_entry);
@ -951,8 +981,10 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
}
if (length > s2->size) {
if (rollback)
add_rollback_space(rollback, TRUE, list, list_size, s2->address + s2->size, address + length - s2->address - s2->size, c);
s2->size = length;
// FIXME - insert rollback
while (s2->list_entry.Flink != list) {
space* s3 = CONTAINING_RECORD(s2->list_entry.Flink, space, list_entry);
@ -981,9 +1013,11 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
// new entry overlaps start of old one
if (address < s2->address && address + length >= s2->address) {
if (rollback)
add_rollback_space(rollback, TRUE, list, list_size, address, s2->address - address, c);
s2->size += s2->address - address;
s2->address = address;
// FIXME - insert rollback
while (s2->list_entry.Blink != list) {
space* s3 = CONTAINING_RECORD(s2->list_entry.Blink, space, list_entry);
@ -1012,8 +1046,10 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
// new entry overlaps end of old one
if (address <= s2->address + s2->size && address + length > s2->address + s2->size) {
if (rollback)
add_rollback_space(rollback, TRUE, list, list_size, address, s2->address + s2->size - address, c);
s2->size = address + length - s2->address;
// FIXME - insert rollback
while (s2->list_entry.Flink != list) {
space* s3 = CONTAINING_RECORD(s2->list_entry.Flink, space, list_entry);
@ -1048,7 +1084,9 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
return;
}
// FIXME - insert rollback
if (rollback)
add_rollback_space(rollback, TRUE, list, list_size, address, length, c);
s->address = address;
s->size = length;
InsertHeadList(s2->list_entry.Blink, &s->list_entry);
@ -1065,7 +1103,6 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
// check if contiguous with last entry
if (s2->address + s2->size == address) {
s2->size += length;
// FIXME - insert rollback
if (list_size) {
RemoveEntryList(&s2->list_entry_size);
@ -1090,7 +1127,8 @@ void _space_list_add2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, U
if (list_size)
order_space_entry(s, list_size);
// FIXME - insert rollback
if (rollback)
add_rollback_space(rollback, TRUE, list, list_size, address, length, c);
}
static void space_list_merge(LIST_ENTRY* spacelist, LIST_ENTRY* spacelist_size, LIST_ENTRY* deleting) {
@ -1108,7 +1146,7 @@ static void space_list_merge(LIST_ENTRY* spacelist, LIST_ENTRY* spacelist_size,
}
}
static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME* now, LIST_ENTRY* rollback) {
static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME* now, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
KEY searchkey;
traverse_ptr tp;
@ -1159,7 +1197,7 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
c->cache->inode_item.sequence++;
c->cache->inode_item.st_ctime = *now;
flush_fcb(c->cache, TRUE, rollback);
flush_fcb(c->cache, TRUE, Irp, rollback);
// update free_space item
@ -1167,7 +1205,7 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
searchkey.obj_type = 0;
searchkey.offset = c->offset;
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -1211,9 +1249,9 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
// write cache
Status = do_nocow_write(Vcb, c->cache, 0, c->cache->inode_item.st_size, data, NULL, NULL, rollback);
Status = do_write_file(c->cache, 0, c->cache->inode_item.st_size, data, NULL, NULL, rollback);
if (!NT_SUCCESS(Status)) {
ERR("do_nocow_write returned %08x\n", Status);
ERR("do_write_file returned %08x\n", Status);
return Status;
}
@ -1222,7 +1260,7 @@ static NTSTATUS update_chunk_cache(device_extension* Vcb, chunk* c, BTRFS_TIME*
return STATUS_SUCCESS;
}
NTSTATUS update_chunk_caches(device_extension* Vcb, LIST_ENTRY* rollback) {
NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) {
LIST_ENTRY* le = Vcb->chunks_changed.Flink;
NTSTATUS Status;
chunk* c;
@ -1235,9 +1273,9 @@ NTSTATUS update_chunk_caches(device_extension* Vcb, LIST_ENTRY* rollback) {
while (le != &Vcb->chunks_changed) {
c = CONTAINING_RECORD(le, chunk, list_entry_changed);
ExAcquireResourceExclusiveLite(&c->nonpaged->lock, TRUE);
Status = update_chunk_cache(Vcb, c, &now, rollback);
ExReleaseResourceLite(&c->nonpaged->lock);
ExAcquireResourceExclusiveLite(&c->lock, TRUE);
Status = update_chunk_cache(Vcb, c, &now, Irp, rollback);
ExReleaseResourceLite(&c->lock);
if (!NT_SUCCESS(Status)) {
ERR("update_chunk_cache(%llx) returned %08x\n", c->offset, Status);
@ -1260,10 +1298,10 @@ void _space_list_add(device_extension* Vcb, chunk* c, BOOL deleting, UINT64 addr
if (!c->list_entry_changed.Flink)
InsertTailList(&Vcb->chunks_changed, &c->list_entry_changed);
_space_list_add2(list, deleting ? NULL : &c->space_size, address, length, rollback, func);
_space_list_add2(list, deleting ? NULL : &c->space_size, address, length, c, rollback, func);
}
void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, LIST_ENTRY* rollback, const char* func) {
void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 address, UINT64 length, chunk* c, LIST_ENTRY* rollback, const char* func) {
LIST_ENTRY *le, *le2;
space *s, *s2;
@ -1283,7 +1321,9 @@ void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 addre
return;
if (s2->address >= address && s2->address + s2->size <= address + length) { // remove entry entirely
// FIXME - insert rollback
if (rollback)
add_rollback_space(rollback, FALSE, list, list_size, s2->address, s2->size, c);
RemoveEntryList(&s2->list_entry);
if (list_size)
@ -1292,7 +1332,8 @@ void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 addre
ExFreePool(s2);
} else if (address + length > s2->address && address + length < s2->address + s2->size) {
if (address > s2->address) { // cut out hole
// FIXME - insert rollback
if (rollback)
add_rollback_space(rollback, FALSE, list, list_size, address, length, c);
s = ExAllocatePoolWithTag(PagedPool, sizeof(space), ALLOC_TAG);
@ -1316,9 +1357,11 @@ void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 addre
return;
} else { // remove start of entry
if (rollback)
add_rollback_space(rollback, FALSE, list, list_size, s2->address, address + length - s2->address, c);
s2->size -= address + length - s2->address;
s2->address = address + length;
// FIXME - insert rollback
if (list_size) {
RemoveEntryList(&s2->list_entry_size);
@ -1326,7 +1369,9 @@ void _space_list_subtract2(LIST_ENTRY* list, LIST_ENTRY* list_size, UINT64 addre
}
}
} else if (address > s2->address && address < s2->address + s2->size) { // remove end of entry
// FIXME - insert rollback
if (rollback)
add_rollback_space(rollback, FALSE, list, list_size, address, s2->address + s2->size - address, c);
s2->size = address - s2->address;
if (list_size) {
@ -1347,5 +1392,5 @@ void _space_list_subtract(device_extension* Vcb, chunk* c, BOOL deleting, UINT64
if (!c->list_entry_changed.Flink)
InsertTailList(&Vcb->chunks_changed, &c->list_entry_changed);
_space_list_subtract2(list, deleting ? NULL : &c->space_size, address, length, rollback, func);
_space_list_subtract2(list, deleting ? NULL : &c->space_size, address, length, c, rollback, func);
}

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,20 @@
/* Copyright (c) Mark Harmstone 2016
*
* This file is part of WinBtrfs.
*
* WinBtrfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation, either version 3 of the Licence, or
* (at your option) any later version.
*
* WinBtrfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public Licence for more details.
*
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
#include "btrfs_drv.h"
struct pnp_context;
@ -176,8 +193,8 @@ static NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
if (Vcb->need_write)
do_write(Vcb, &rollback);
if (Vcb->need_write && !Vcb->readonly)
do_write(Vcb, Irp, &rollback);
clear_rollback(&rollback);
@ -219,7 +236,14 @@ static NTSTATUS pnp_start_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
}
static NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
FIXME("STUB\n");
device_extension* Vcb = DeviceObject->DeviceExtension;
TRACE("(%p, %p)\n", DeviceObject, Irp);
if (DeviceObject->Vpb->Flags & VPB_MOUNTED) {
uninit(Vcb, FALSE);
Vcb->Vpb->Flags &= ~VPB_MOUNTED;
}
return STATUS_SUCCESS;
}

View file

@ -1,3 +1,20 @@
/* Copyright (c) Mark Harmstone 2016
*
* This file is part of WinBtrfs.
*
* WinBtrfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation, either version 3 of the Licence, or
* (at your option) any later version.
*
* WinBtrfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public Licence for more details.
*
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
#include "btrfs_drv.h"
enum read_data_status {
@ -159,6 +176,12 @@ NTSTATUS STDCALL read_data(device_extension* Vcb, UINT64 addr, UINT32 length, UI
UINT64 *stripestart = NULL, *stripeend = NULL;
UINT16 startoffstripe;
Status = verify_vcb(Vcb, Irp);
if (!NT_SUCCESS(Status)) {
ERR("verify_vcb returned %08x\n", Status);
return Status;
}
if (Vcb->log_to_phys_loaded) {
chunk* c = get_chunk_from_address(Vcb, addr);
@ -433,7 +456,23 @@ NTSTATUS STDCALL read_data(device_extension* Vcb, UINT64 addr, UINT32 length, UI
for (i = 0; i < ci->num_stripes; i++) {
if (context->stripes[i].status == ReadDataStatus_Error && IoIsErrorUserInduced(context->stripes[i].iosb.Status)) {
IoSetHardErrorOrVerifyDevice(context->stripes[i].Irp, devices[i]->devobj);
if (Irp && context->stripes[i].iosb.Status == STATUS_VERIFY_REQUIRED) {
PDEVICE_OBJECT dev;
dev = IoGetDeviceToVerify(Irp->Tail.Overlay.Thread);
IoSetDeviceToVerify(Irp->Tail.Overlay.Thread, NULL);
if (!dev) {
dev = IoGetDeviceToVerify(PsGetCurrentThread());
IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
}
dev = Vcb->Vpb ? Vcb->Vpb->RealDevice : NULL;
if (dev)
IoVerifyVolume(dev, FALSE);
}
// IoSetHardErrorOrVerifyDevice(context->stripes[i].Irp, devices[i]->devobj);
Status = context->stripes[i].iosb.Status;
goto exit;
@ -702,7 +741,7 @@ static NTSTATUS STDCALL read_stream(fcb* fcb, UINT8* data, UINT64 start, ULONG l
return Status;
}
static NTSTATUS load_csum_from_disk(device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length) {
static NTSTATUS load_csum_from_disk(device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length, PIRP Irp) {
NTSTATUS Status;
KEY searchkey;
traverse_ptr tp, next_tp;
@ -713,7 +752,7 @@ static NTSTATUS load_csum_from_disk(device_extension* Vcb, UINT32* csum, UINT64
searchkey.obj_type = TYPE_EXTENT_CSUM;
searchkey.offset = start;
Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, FALSE);
Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, FALSE, Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
return Status;
@ -742,7 +781,7 @@ static NTSTATUS load_csum_from_disk(device_extension* Vcb, UINT32* csum, UINT64
break;
}
b = find_next_item(Vcb, &tp, &next_tp, FALSE);
b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
if (b)
tp = next_tp;
@ -756,7 +795,7 @@ static NTSTATUS load_csum_from_disk(device_extension* Vcb, UINT32* csum, UINT64
return STATUS_SUCCESS;
}
static NTSTATUS load_csum(device_extension* Vcb, UINT64 start, UINT64 length, UINT32** pcsum) {
static NTSTATUS load_csum(device_extension* Vcb, UINT64 start, UINT64 length, UINT32** pcsum, PIRP Irp) {
UINT32* csum = NULL;
NTSTATUS Status;
UINT64 end;
@ -827,7 +866,7 @@ static NTSTATUS load_csum(device_extension* Vcb, UINT64 start, UINT64 length, UI
runlength = RtlFindFirstRunClear(&bmp, &index);
while (runlength != 0) {
Status = load_csum_from_disk(Vcb, &csum[index], start + (index * Vcb->superblock.sector_size), runlength);
Status = load_csum_from_disk(Vcb, &csum[index], start + (index * Vcb->superblock.sector_size), runlength, Irp);
if (!NT_SUCCESS(Status)) {
ERR("load_csum_from_disk returned %08x\n", Status);
goto end;
@ -854,72 +893,23 @@ NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, U
NTSTATUS Status;
EXTENT_DATA* ed;
UINT64 bytes_read = 0;
UINT64 last_end;
LIST_ENTRY* le;
TRACE("(%p, %p, %llx, %llx, %p)\n", fcb, data, start, length, pbr);
if (pbr)
*pbr = 0;
if (start >= fcb->inode_item.st_size) {
WARN("Tried to read beyond end of file\n");
Status = STATUS_END_OF_FILE;
goto exit;
}
le = fcb->extents.Flink;
while (le != &fcb->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (!ext->ignore) {
if (ext->offset == start)
break;
else if (ext->offset > start) {
LIST_ENTRY* le2 = le->Blink;
ext = NULL;
while (le2 != &fcb->extents) {
extent* ext2 = CONTAINING_RECORD(le2, extent, list_entry);
if (!ext2->ignore) {
le = le2;
ext = ext2;
break;
}
le2 = le2->Blink;
}
if (!ext) {
ERR("first extent was after offset\n");
Status = STATUS_INTERNAL_ERROR;
goto exit;
} else
break;
}
}
le = le->Flink;
}
if (le == &fcb->extents) {
LIST_ENTRY* le2 = le->Blink;
extent* ext = NULL;
while (le2 != &fcb->extents) {
extent* ext2 = CONTAINING_RECORD(le2, extent, list_entry);
if (!ext2->ignore) {
le = le2;
ext = ext2;
break;
}
le2 = le2->Blink;
}
if (!ext) {
ERR("could not find extent\n");
Status = STATUS_INTERNAL_ERROR;
goto exit;
}
}
last_end = start;
while (le != &fcb->extents) {
UINT64 len;
@ -929,33 +919,25 @@ NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, U
if (!ext->ignore) {
ed = ext->data;
if (ext->datalen < sizeof(EXTENT_DATA)) {
ERR("extent %llx was %u bytes, expected at least %u\n", ext->offset, ext->datalen, sizeof(EXTENT_DATA));
Status = STATUS_INTERNAL_ERROR;
goto exit;
ed2 = (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) ? (EXTENT_DATA2*)ed->data : NULL;
len = ed2 ? ed2->num_bytes : ed->decoded_size;
if (ext->offset + len <= start) {
last_end = ext->offset + len;
goto nextitem;
}
if ((ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) && ext->datalen < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
ERR("extent %llx was %u bytes, expected at least %u\n", ext->offset, ext->datalen, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
Status = STATUS_INTERNAL_ERROR;
goto exit;
if (ext->offset > last_end && ext->offset > start + bytes_read) {
UINT32 read = min(length, ext->offset - max(start, last_end));
RtlZeroMemory(data + bytes_read, read);
bytes_read += read;
length -= read;
}
ed2 = (EXTENT_DATA2*)ed->data;
len = ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes;
if (ext->offset + len < start) {
ERR("Tried to read beyond end of file\n");
Status = STATUS_END_OF_FILE;
goto exit;
}
if (ed->compression != BTRFS_COMPRESSION_NONE) {
FIXME("FIXME - compression not yet supported\n");
Status = STATUS_NOT_IMPLEMENTED;
goto exit;
}
if (length == 0 || ext->offset > start + bytes_read + length)
break;
if (ed->encryption != BTRFS_ENCRYPTION_NONE) {
WARN("Encryption not supported\n");
@ -979,6 +961,8 @@ NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, U
RtlCopyMemory(data + bytes_read, &ed->data[off], read);
// FIXME - can we have compressed inline extents?
bytes_read += read;
length -= read;
break;
@ -989,16 +973,13 @@ NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, U
UINT64 off = start + bytes_read - ext->offset;
UINT32 to_read, read;
UINT8* buf;
UINT32 *csum, bumpoff = 0;
UINT64 addr;
read = len - off;
if (read > length) read = length;
if (ed2->address == 0) {
RtlZeroMemory(data + bytes_read, read);
} else {
UINT32 *csum, bumpoff = 0;
UINT64 addr;
if (ed->compression == BTRFS_COMPRESSION_NONE) {
addr = ed2->address + ed2->offset + off;
to_read = sector_align(read, fcb->Vcb->superblock.sector_size);
@ -1007,41 +988,71 @@ NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, U
addr -= bumpoff;
to_read = sector_align(read + bumpoff, fcb->Vcb->superblock.sector_size);
}
} else {
addr = ed2->address;
to_read = sector_align(ed2->size, fcb->Vcb->superblock.sector_size);
}
buf = ExAllocatePoolWithTag(PagedPool, to_read, ALLOC_TAG);
if (!buf) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
Status = load_csum(fcb->Vcb, addr, to_read / fcb->Vcb->superblock.sector_size, &csum, Irp);
buf = ExAllocatePoolWithTag(PagedPool, to_read, ALLOC_TAG);
if (!NT_SUCCESS(Status)) {
ERR("load_csum returned %08x\n", Status);
ExFreePool(buf);
goto exit;
}
} else
csum = NULL;
Status = read_data(fcb->Vcb, addr, to_read, csum, FALSE, buf, NULL, Irp);
if (!NT_SUCCESS(Status)) {
ERR("read_data returned %08x\n", Status);
ExFreePool(buf);
goto exit;
}
if (ed->compression == BTRFS_COMPRESSION_NONE) {
RtlCopyMemory(data + bytes_read, buf + bumpoff, read);
} else {
UINT8* decomp = NULL;
if (!buf) {
// FIXME - don't mess around with decomp if we're reading the whole extent
decomp = ExAllocatePoolWithTag(PagedPool, ed->decoded_size, ALLOC_TAG);
if (!decomp) {
ERR("out of memory\n");
ExFreePool(buf);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM)) {
Status = load_csum(fcb->Vcb, addr, to_read / fcb->Vcb->superblock.sector_size, &csum);
if (!NT_SUCCESS(Status)) {
ERR("load_csum returned %08x\n", Status);
ExFreePool(buf);
goto exit;
}
} else
csum = NULL;
Status = decompress(ed->compression, buf, ed2->size, decomp, ed->decoded_size);
Status = read_data(fcb->Vcb, addr, to_read, csum, FALSE, buf, NULL, Irp);
if (!NT_SUCCESS(Status)) {
ERR("read_data returned %08x\n", Status);
ERR("decompress returned %08x\n", Status);
ExFreePool(buf);
ExFreePool(decomp);
goto exit;
}
RtlCopyMemory(data + bytes_read, buf + bumpoff, read);
RtlCopyMemory(data + bytes_read, decomp + ed2->offset + off, min(read, ed2->num_bytes - off));
ExFreePool(buf);
if (csum)
ExFreePool(csum);
ExFreePool(decomp);
}
ExFreePool(buf);
if (csum)
ExFreePool(csum);
bytes_read += read;
length -= read;
@ -1068,14 +1079,26 @@ NTSTATUS STDCALL read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64 length, U
Status = STATUS_NOT_IMPLEMENTED;
goto exit;
}
last_end = ext->offset + len;
if (length == 0)
break;
}
nextitem:
le = le->Flink;
}
if (length > 0 && start + bytes_read < fcb->inode_item.st_size) {
UINT32 read = min(fcb->inode_item.st_size - start - bytes_read, length);
RtlZeroMemory(data + bytes_read, read);
bytes_read += read;
length -= read;
}
Status = STATUS_SUCCESS;
if (pbr)
*pbr = bytes_read;
@ -1131,7 +1154,7 @@ NTSTATUS do_read(PIRP Irp, BOOL wait, ULONG* bytes_read) {
}
if (start >= fcb->Header.ValidDataLength.QuadPart) {
length = min(start + length, fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart;
length = min(length, min(start + length, fcb->Header.FileSize.QuadPart) - fcb->Header.ValidDataLength.QuadPart);
RtlZeroMemory(data, length);
Irp->IoStatus.Information = *bytes_read = length;
return STATUS_SUCCESS;
@ -1233,7 +1256,7 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
BOOL top_level;
fcb* fcb;
ccb* ccb;
BOOL tree_lock = FALSE, fcb_lock = FALSE;
BOOL tree_lock = FALSE, fcb_lock = FALSE, pagefile;
FsRtlEnterFileSystem();
@ -1266,6 +1289,12 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
goto exit;
}
if (fcb == Vcb->volume_fcb) {
TRACE("not allowing read of volume FCB\n");
Status = STATUS_INVALID_PARAMETER;
goto exit;
}
ccb = FileObject->FsContext2;
if (!ccb) {
@ -1280,14 +1309,18 @@ NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
goto exit;
}
pagefile = fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE && Irp->Flags & IRP_PAGING_IO;
if (Irp->Flags & IRP_NOCACHE) {
if (!ExAcquireResourceSharedLite(&Vcb->tree_lock, IoIsOperationSynchronous(Irp))) {
Status = STATUS_PENDING;
IoMarkIrpPending(Irp);
goto exit;
if (!pagefile) {
if (!ExAcquireResourceSharedLite(&Vcb->tree_lock, IoIsOperationSynchronous(Irp))) {
Status = STATUS_PENDING;
IoMarkIrpPending(Irp);
goto exit;
}
tree_lock = TRUE;
}
tree_lock = TRUE;
if (!ExAcquireResourceSharedLite(fcb->Header.Resource, IoIsOperationSynchronous(Irp))) {
Status = STATUS_PENDING;

View file

@ -1,20 +1,48 @@
/* Copyright (c) Mark Harmstone 2016
*
* This file is part of WinBtrfs.
*
* WinBtrfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation, either version 3 of the Licence, or
* (at your option) any later version.
*
* WinBtrfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public Licence for more details.
*
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
#include "btrfs_drv.h"
extern UNICODE_STRING log_device, log_file, registry_path;
static WCHAR option_mounted[] = L"Mounted";
static WCHAR option_ignore[] = L"Ignore";
#define hex_digit(c) ((c) >= 0 && (c) <= 9) ? ((c) + '0') : ((c) - 10 + 'a')
NTSTATUS registry_load_volume_options(BTRFS_UUID* uuid, mount_options* options) {
UNICODE_STRING path, ignoreus;
NTSTATUS registry_load_volume_options(device_extension* Vcb) {
BTRFS_UUID* uuid = &Vcb->superblock.uuid;
mount_options* options = &Vcb->options;
UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus,
maxinlineus, subvolidus;
OBJECT_ATTRIBUTES oa;
NTSTATUS Status;
ULONG i, j, kvfilen, index, retlen;
KEY_VALUE_FULL_INFORMATION* kvfi = NULL;
HANDLE h;
options->compress = mount_compress;
options->compress_force = mount_compress_force;
options->compress_type = mount_compress_type > BTRFS_COMPRESSION_LZO ? 0 : mount_compress_type;
options->readonly = FALSE;
options->zlib_level = mount_zlib_level;
options->flush_interval = mount_flush_interval;
options->max_inline = min(mount_max_inline, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
options->subvol_id = 0;
path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
@ -62,8 +90,15 @@ NTSTATUS registry_load_volume_options(BTRFS_UUID* uuid, mount_options* options)
index = 0;
ignoreus.Buffer = option_ignore;
ignoreus.Length = ignoreus.MaximumLength = wcslen(option_ignore) * sizeof(WCHAR);
RtlInitUnicodeString(&ignoreus, L"Ignore");
RtlInitUnicodeString(&compressus, L"Compress");
RtlInitUnicodeString(&compressforceus, L"CompressForce");
RtlInitUnicodeString(&compresstypeus, L"CompressType");
RtlInitUnicodeString(&readonlyus, L"Readonly");
RtlInitUnicodeString(&zliblevelus, L"ZlibLevel");
RtlInitUnicodeString(&flushintervalus, L"FlushInterval");
RtlInitUnicodeString(&maxinlineus, L"MaxInline");
RtlInitUnicodeString(&subvolidus, L"SubvolId");
do {
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
@ -80,12 +115,53 @@ NTSTATUS registry_load_volume_options(BTRFS_UUID* uuid, mount_options* options)
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->ignore = *val != 0 ? TRUE : FALSE;
} else if (FsRtlAreNamesEqual(&compressus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->compress = *val != 0 ? TRUE : FALSE;
} else if (FsRtlAreNamesEqual(&compressforceus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->compress_force = *val != 0 ? TRUE : FALSE;
} else if (FsRtlAreNamesEqual(&compresstypeus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->compress_type = *val > BTRFS_COMPRESSION_LZO ? 0 : *val;
} else if (FsRtlAreNamesEqual(&readonlyus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->readonly = *val != 0 ? TRUE : FALSE;
} else if (FsRtlAreNamesEqual(&zliblevelus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->zlib_level = *val;
} else if (FsRtlAreNamesEqual(&flushintervalus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->flush_interval = *val;
} else if (FsRtlAreNamesEqual(&maxinlineus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->max_inline = min(*val, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
} else if (FsRtlAreNamesEqual(&subvolidus, &us, TRUE, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_QWORD) {
UINT64* val = (UINT64*)((UINT8*)kvfi + kvfi->DataOffset);
options->subvol_id = *val;
}
} else if (Status != STATUS_NO_MORE_ENTRIES) {
ERR("ZwEnumerateValueKey returned %08x\n", Status);
goto end2;
}
} while (NT_SUCCESS(Status));
if (!options->compress && options->compress_force)
options->compress = TRUE;
if (options->zlib_level > 9)
options->zlib_level = 9;
if (options->flush_interval == 0)
options->flush_interval = mount_flush_interval;
Status = STATUS_SUCCESS;
@ -472,38 +548,13 @@ static void read_mappings(PUNICODE_STRING regpath) {
ExFreePool(path);
}
void STDCALL read_registry(PUNICODE_STRING regpath) {
#ifndef __REACTOS__
UNICODE_STRING us;
#endif
OBJECT_ATTRIBUTES oa;
NTSTATUS Status;
HANDLE h;
ULONG dispos;
#ifndef __REACTOS__
static void get_registry_value(HANDLE h, WCHAR* string, ULONG type, void* val, ULONG size) {
ULONG kvfilen;
KEY_VALUE_FULL_INFORMATION* kvfi;
#endif
UNICODE_STRING us;
NTSTATUS Status;
#ifndef __REACTOS__
static WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
#endif
read_mappings(regpath);
InitializeObjectAttributes(&oa, regpath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateKey(&h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
if (!NT_SUCCESS(Status)) {
ERR("ZwCreateKey returned %08x\n", Status);
return;
}
reset_subkeys(h, regpath);
#ifdef _DEBUG
RtlInitUnicodeString(&us, L"DebugLogLevel");
RtlInitUnicodeString(&us, string);
kvfi = NULL;
kvfilen = 0;
@ -521,31 +572,75 @@ void STDCALL read_registry(PUNICODE_STRING regpath) {
Status = ZwQueryValueKey(h, &us, KeyValueFullInformation, kvfi, kvfilen, &kvfilen);
if (NT_SUCCESS(Status)) {
if (kvfi->Type == REG_DWORD && kvfi->DataLength >= sizeof(UINT32)) {
RtlCopyMemory(&debug_log_level, ((UINT8*)kvfi) + kvfi->DataOffset, sizeof(UINT32));
if (kvfi->Type == type && kvfi->DataLength >= size) {
RtlCopyMemory(val, ((UINT8*)kvfi) + kvfi->DataOffset, size);
} else {
Status = ZwDeleteValueKey(h, &us);
if (!NT_SUCCESS(Status)) {
ERR("ZwDeleteValueKey returned %08x\n", Status);
}
Status = ZwSetValueKey(h, &us, 0, REG_DWORD, &debug_log_level, sizeof(debug_log_level));
Status = ZwSetValueKey(h, &us, 0, type, val, size);
if (!NT_SUCCESS(Status)) {
ERR("ZwSetValueKey reutrned %08x\n", Status);
ERR("ZwSetValueKey returned %08x\n", Status);
}
}
}
ExFreePool(kvfi);
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
Status = ZwSetValueKey(h, &us, 0, REG_DWORD, &debug_log_level, sizeof(debug_log_level));
Status = ZwSetValueKey(h, &us, 0, type, val, size);
if (!NT_SUCCESS(Status)) {
ERR("ZwSetValueKey reutrned %08x\n", Status);
ERR("ZwSetValueKey returned %08x\n", Status);
}
} else {
ERR("ZwQueryValueKey returned %08x\n", Status);
}
}
void STDCALL read_registry(PUNICODE_STRING regpath) {
#ifndef __REACTOS__
UNICODE_STRING us;
#endif
OBJECT_ATTRIBUTES oa;
NTSTATUS Status;
HANDLE h;
ULONG dispos;
#ifndef __REACTOS__
ULONG kvfilen;
KEY_VALUE_FULL_INFORMATION* kvfi;
#endif
#ifndef __REACTOS__
static WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
#endif
read_mappings(regpath);
InitializeObjectAttributes(&oa, regpath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateKey(&h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
if (!NT_SUCCESS(Status)) {
ERR("ZwCreateKey returned %08x\n", Status);
return;
}
reset_subkeys(h, regpath);
get_registry_value(h, L"Compress", REG_DWORD, &mount_compress, sizeof(mount_compress));
get_registry_value(h, L"CompressForce", REG_DWORD, &mount_compress_force, sizeof(mount_compress_force));
get_registry_value(h, L"CompressType", REG_DWORD, &mount_compress_type, sizeof(mount_compress_type));
get_registry_value(h, L"ZlibLevel", REG_DWORD, &mount_zlib_level, sizeof(mount_zlib_level));
get_registry_value(h, L"FlushInterval", REG_DWORD, &mount_flush_interval, sizeof(mount_flush_interval));
get_registry_value(h, L"MaxInline", REG_DWORD, &mount_max_inline, sizeof(mount_max_inline));
if (mount_flush_interval == 0)
mount_flush_interval = 1;
#ifdef _DEBUG
get_registry_value(h, L"DebugLogLevel", REG_DWORD, &debug_log_level, sizeof(debug_log_level));
RtlInitUnicodeString(&us, L"LogDevice");

View file

@ -26,8 +26,6 @@ NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
char* data;
NTSTATUS Status;
// FIXME - check permissions
TRACE("(%p, %p, %p, %x, %p)\n", DeviceObject, FileObject, buffer, buflen, retlen);
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
@ -134,6 +132,7 @@ end:
static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, REPARSE_DATA_BUFFER* rdb, ULONG buflen, LIST_ENTRY* rollback) {
NTSTATUS Status;
ULONG minlen;
ULONG tlength;
UNICODE_STRING subname;
ANSI_STRING target;
LARGE_INTEGER offset, time;
@ -155,7 +154,7 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, REPARSE_DATA_BUFFER* rd
fileref->fcb->inode_item.st_mode |= __S_IFLNK;
Status = truncate_file(fileref->fcb, 0, rollback);
Status = truncate_file(fileref->fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08x\n", Status);
return Status;
@ -187,7 +186,8 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, REPARSE_DATA_BUFFER* rd
}
offset.QuadPart = 0;
Status = write_file2(fileref->fcb->Vcb, Irp, offset, target.Buffer, (ULONG*)&target.Length, FALSE, TRUE,
tlength = target.Length;
Status = write_file2(fileref->fcb->Vcb, Irp, offset, target.Buffer, &tlength, FALSE, TRUE,
TRUE, FALSE, rollback);
ExFreePool(target.Buffer);
@ -221,9 +221,6 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ULONG tag;
LIST_ENTRY rollback;
// FIXME - send notification if this succeeds? The attributes will have changed.
// FIXME - check permissions
TRACE("(%p, %p)\n", DeviceObject, Irp);
InitializeListHead(&rollback);
@ -241,6 +238,13 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
return STATUS_INVALID_PARAMETER;
}
// It isn't documented what permissions FSCTL_SET_REPARSE_POINT needs, but CreateSymbolicLinkW
// creates a file with FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE.
if (!(ccb->access & FILE_WRITE_ATTRIBUTES)) {
WARN("insufficient privileges\n");
return STATUS_ACCESS_DENIED;
}
fileref = ccb->fileref;
if (!fileref) {
@ -300,7 +304,7 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Status = STATUS_SUCCESS;
} else { // otherwise, store as file data
Status = truncate_file(fcb, 0, &rollback);
Status = truncate_file(fcb, 0, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08x\n", Status);
goto end;
@ -356,8 +360,6 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
file_ref* fileref;
LIST_ENTRY rollback;
// FIXME - check permissions
TRACE("(%p, %p)\n", DeviceObject, Irp);
InitializeListHead(&rollback);
@ -368,13 +370,25 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
}
fcb = FileObject->FsContext;
if (!fcb) {
ERR("fcb was NULL\n");
return STATUS_INVALID_PARAMETER;
}
ccb = FileObject->FsContext2;
fileref = ccb ? ccb->fileref : NULL;
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (!ccb) {
ERR("ccb was NULL\n");
return STATUS_INVALID_PARAMETER;
}
TRACE("%S\n", file_desc(FileObject));
if (!(ccb->access & FILE_WRITE_ATTRIBUTES)) {
WARN("insufficient privileges\n");
return STATUS_ACCESS_DENIED;
}
fileref = ccb->fileref;
if (!fileref) {
ERR("fileref was NULL\n");
@ -382,6 +396,11 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
goto end;
}
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
TRACE("%S\n", file_desc(FileObject));
if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) {
ERR("buffer was too short\n");
Status = STATUS_INVALID_PARAMETER;
@ -433,7 +452,7 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
// FIXME - do we need to check that the reparse tags match?
Status = truncate_file(fcb, 0, &rollback);
Status = truncate_file(fcb, 0, Irp, &rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08x\n", Status);
goto end;

View file

@ -201,6 +201,7 @@ void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid) {
um = ExAllocatePoolWithTag(PagedPool, sizeof(uid_map), ALLOC_TAG);
if (!um) {
ERR("out of memory\n");
ExFreePool(sid);
return;
}
@ -210,7 +211,7 @@ void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, UINT32 uid) {
InsertTailList(&uid_map_list, &um->listentry);
}
static void uid_to_sid(UINT32 uid, PSID* sid) {
void uid_to_sid(UINT32 uid, PSID* sid) {
LIST_ENTRY* le;
uid_map* um;
sid_header* sh;
@ -400,12 +401,12 @@ static ACL* load_default_acl() {
// }
// }
static BOOL get_sd_from_xattr(fcb* fcb) {
static BOOL get_sd_from_xattr(fcb* fcb, PIRP Irp) {
ULONG buflen;
NTSTATUS Status;
PSID sid, usersid;
if (!get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_NTACL, EA_NTACL_HASH, (UINT8**)&fcb->sd, (UINT16*)&buflen))
if (!get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_NTACL, EA_NTACL_HASH, (UINT8**)&fcb->sd, (UINT16*)&buflen, Irp))
return FALSE;
TRACE("using xattr " EA_NTACL " for security descriptor\n");
@ -654,12 +655,12 @@ end:
ExFreePool(groupsid);
}
void fcb_get_sd(fcb* fcb, struct _fcb* parent) {
void fcb_get_sd(fcb* fcb, struct _fcb* parent, PIRP Irp) {
NTSTATUS Status;
PSID usersid = NULL, groupsid = NULL;
SECURITY_SUBJECT_CONTEXT subjcont;
if (get_sd_from_xattr(fcb))
if (get_sd_from_xattr(fcb, Irp))
return;
if (!parent) {
@ -833,8 +834,7 @@ static NTSTATUS STDCALL set_file_security(device_extension* Vcb, PFILE_OBJECT Fi
fcb = fileref->parent->fcb;
else {
ERR("could not find parent fcb for stream\n");
Status = STATUS_INTERNAL_ERROR;
goto end;
return STATUS_INTERNAL_ERROR;
}
}
@ -985,7 +985,7 @@ NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as) {
ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status);
fcb->inode_item.st_uid = UID_NOBODY;
} else {
fcb->inode_item.st_uid = sid_to_uid(&owner);
fcb->inode_item.st_uid = sid_to_uid(owner);
}
return STATUS_SUCCESS;

View file

@ -25,7 +25,7 @@ typedef struct {
LIST_ENTRY list_entry;
} rollback_item;
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, tree* parent, const char* func, const char* file, unsigned int line) {
NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree** pt, tree* parent, PIRP Irp, const char* func, const char* file, unsigned int line) {
UINT8* buf;
NTSTATUS Status;
tree_header* th;
@ -42,7 +42,7 @@ NTSTATUS STDCALL _load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = read_data(Vcb, addr, Vcb->superblock.node_size, NULL, TRUE, buf, &c, NULL);
Status = read_data(Vcb, addr, Vcb->superblock.node_size, NULL, TRUE, buf, &c, Irp);
if (!NT_SUCCESS(Status)) {
ERR("read_data returned 0x%08x\n", Status);
ExFreePool(buf);
@ -288,7 +288,8 @@ static tree* free_tree2(tree* t, const char* func, const char* file, unsigned in
return NULL;
}
NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, const char* func, const char* file, unsigned int line) {
NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r, tree* t, tree_data* td, BOOL* loaded, PIRP Irp,
const char* func, const char* file, unsigned int line) {
// KIRQL irql;
// tree_holder_nonpaged* thnp = th->nonpaged;
BOOL ret;
@ -325,7 +326,7 @@ NTSTATUS STDCALL _do_load_tree(device_extension* Vcb, tree_holder* th, root* r,
if (!th->tree) {
NTSTATUS Status;
Status = _load_tree(Vcb, th->address, r, &th->tree, t, func, file, line);
Status = _load_tree(Vcb, th->address, r, &th->tree, t, Irp, func, file, line);
if (!NT_SUCCESS(Status)) {
ERR("load_tree returned %08x\n", Status);
ExReleaseResourceLite(&r->nonpaged->load_tree_lock);
@ -389,7 +390,8 @@ static __inline tree_data* next_item(tree* t, tree_data* td) {
return CONTAINING_RECORD(le, tree_data, list_entry);
}
static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, const char* func, const char* file, unsigned int line) {
static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, PIRP Irp,
const char* func, const char* file, unsigned int line) {
int cmp;
tree_data *td, *lasttd;
@ -399,7 +401,7 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
td = first_item(t);
lasttd = NULL;
if (!td) return STATUS_INTERNAL_ERROR;
if (!td) return STATUS_NOT_FOUND;
do {
cmp = keycmp(searchkey, &td->key);
@ -437,7 +439,7 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
oldtp.tree = t;
oldtp.item = td;
while (_find_prev_item(Vcb, &oldtp, tp, TRUE, func, file, line)) {
while (_find_prev_item(Vcb, &oldtp, tp, TRUE, Irp, func, file, line)) {
if (!tp->item->ignore)
return STATUS_SUCCESS;
@ -449,14 +451,14 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
oldtp.tree = t;
oldtp.item = td;
while (_find_next_item(Vcb, &oldtp, tp, TRUE, func, file, line)) {
while (_find_next_item(Vcb, &oldtp, tp, TRUE, Irp, func, file, line)) {
if (!tp->item->ignore)
return STATUS_SUCCESS;
oldtp = *tp;
}
return STATUS_INTERNAL_ERROR;
return STATUS_NOT_FOUND;
} else {
tp->tree = t;
tp->item = td;
@ -472,24 +474,24 @@ static NTSTATUS STDCALL find_item_in_tree(device_extension* Vcb, tree* t, traver
}
if (!td)
return STATUS_INTERNAL_ERROR;
return STATUS_NOT_FOUND;
// if (i > 0)
// TRACE("entering tree from (%x,%x,%x) to (%x,%x,%x) (%p)\n", (UINT32)t->items[i].key.obj_id, t->items[i].key.obj_type, (UINT32)t->items[i].key.offset, (UINT32)t->items[i+1].key.obj_id, t->items[i+1].key.obj_type, (UINT32)t->items[i+1].key.offset, t->items[i].tree);
Status = _do_load_tree(Vcb, &td->treeholder, t->root, t, td, &loaded, func, file, line);
Status = _do_load_tree(Vcb, &td->treeholder, t->root, t, td, &loaded, Irp, func, file, line);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status);
return Status;
}
Status = find_item_in_tree(Vcb, td->treeholder.tree, tp, searchkey, ignore, func, file, line);
Status = find_item_in_tree(Vcb, td->treeholder.tree, tp, searchkey, ignore, Irp, func, file, line);
return Status;
}
}
NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, const char* func, const char* file, unsigned int line) {
NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, const KEY* searchkey, BOOL ignore, PIRP Irp, const char* func, const char* file, unsigned int line) {
NTSTATUS Status;
BOOL loaded;
// KIRQL irql;
@ -497,15 +499,15 @@ NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, co
TRACE("(%p, %p, %p, %p)\n", Vcb, r, tp, searchkey);
if (!r->treeholder.tree) {
Status = _do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, func, file, line);
Status = _do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, Irp, func, file, line);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status);
return Status;
}
}
Status = find_item_in_tree(Vcb, r->treeholder.tree, tp, searchkey, ignore, func, file, line);
if (!NT_SUCCESS(Status)) {
Status = find_item_in_tree(Vcb, r->treeholder.tree, tp, searchkey, ignore, Irp, func, file, line);
if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) {
ERR("find_item_in_tree returned %08x\n", Status);
}
@ -519,7 +521,8 @@ NTSTATUS STDCALL _find_item(device_extension* Vcb, root* r, traverse_ptr* tp, co
return Status;
}
BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, const char* func, const char* file, unsigned int line) {
BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* next_tp, BOOL ignore, PIRP Irp,
const char* func, const char* file, unsigned int line) {
tree* t;
tree_data *td, *next;
NTSTATUS Status;
@ -563,7 +566,7 @@ BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, trav
if (!t)
return FALSE;
Status = _do_load_tree(Vcb, &td->treeholder, t->parent->root, t->parent, td, &loaded, func, file, line);
Status = _do_load_tree(Vcb, &td->treeholder, t->parent->root, t->parent, td, &loaded, Irp, func, file, line);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status);
return FALSE;
@ -576,7 +579,7 @@ BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, trav
fi = first_item(t);
Status = _do_load_tree(Vcb, &fi->treeholder, t->parent->root, t, fi, &loaded, func, file, line);
Status = _do_load_tree(Vcb, &fi->treeholder, t->parent->root, t, fi, &loaded, Irp, func, file, line);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status);
return FALSE;
@ -592,7 +595,7 @@ BOOL STDCALL _find_next_item(device_extension* Vcb, const traverse_ptr* tp, trav
traverse_ptr ntp2;
BOOL b;
while ((b = _find_next_item(Vcb, next_tp, &ntp2, TRUE, func, file, line))) {
while ((b = _find_next_item(Vcb, next_tp, &ntp2, TRUE, Irp, func, file, line))) {
*next_tp = ntp2;
if (!next_tp->item->ignore)
@ -622,7 +625,8 @@ static __inline tree_data* last_item(tree* t) {
return CONTAINING_RECORD(le, tree_data, list_entry);
}
BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, const char* func, const char* file, unsigned int line) {
BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, traverse_ptr* prev_tp, BOOL ignore, PIRP Irp,
const char* func, const char* file, unsigned int line) {
tree* t;
tree_data* td;
NTSTATUS Status;
@ -649,7 +653,7 @@ BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, trav
td = prev_item(t->parent, t->paritem);
Status = _do_load_tree(Vcb, &td->treeholder, t->parent->root, t, td, &loaded, func, file, line);
Status = _do_load_tree(Vcb, &td->treeholder, t->parent->root, t, td, &loaded, Irp, func, file, line);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status);
return FALSE;
@ -662,7 +666,7 @@ BOOL STDCALL _find_prev_item(device_extension* Vcb, const traverse_ptr* tp, trav
li = last_item(t);
Status = _do_load_tree(Vcb, &li->treeholder, t->parent->root, t, li, &loaded, func, file, line);
Status = _do_load_tree(Vcb, &li->treeholder, t->parent->root, t, li, &loaded, Irp, func, file, line);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status);
return FALSE;
@ -793,7 +797,7 @@ void add_rollback(LIST_ENTRY* rollback, enum rollback_type type, void* ptr) {
InsertTailList(rollback, &ri->list_entry);
}
BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset, void* data, UINT32 size, traverse_ptr* ptp, LIST_ENTRY* rollback) {
BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset, void* data, UINT32 size, traverse_ptr* ptp, PIRP Irp, LIST_ENTRY* rollback) {
traverse_ptr tp;
KEY searchkey;
int cmp;
@ -820,13 +824,13 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
searchkey.obj_type = obj_type;
searchkey.offset = offset;
Status = find_item(Vcb, r, &tp, &searchkey, TRUE);
if (!NT_SUCCESS(Status)) {
Status = find_item(Vcb, r, &tp, &searchkey, TRUE, Irp);
if (Status == STATUS_NOT_FOUND) {
if (r) {
if (!r->treeholder.tree) {
BOOL loaded;
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded);
Status = do_load_tree(Vcb, &r->treeholder, r, NULL, NULL, &loaded, Irp);
if (!NT_SUCCESS(Status)) {
ERR("do_load_tree returned %08x\n", Status);
@ -845,6 +849,9 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
ERR("error: find_item returned %08x\n", Status);
goto end;
}
} else if (!NT_SUCCESS(Status)) {
ERR("find_item returned %08x\n", Status);
goto end;
}
TRACE("tp.item = %p\n", tp.item);
@ -855,6 +862,7 @@ BOOL STDCALL insert_tree_item(device_extension* Vcb, root* r, UINT64 obj_id, UIN
if (cmp == 0 && !tp.item->ignore) { // FIXME - look for all items of the same key to make sure none are non-ignored
ERR("error: key (%llx,%x,%llx) already present\n", obj_id, obj_type, offset);
int3;
goto end;
}
} else
@ -970,10 +978,10 @@ void STDCALL delete_tree_item(device_extension* Vcb, traverse_ptr* tp, LIST_ENTR
TRACE("deleting item %llx,%x,%llx (ignore = %s)\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset, tp->item->ignore ? "TRUE" : "FALSE");
#ifdef DEBUG_PARANOID
if (!ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock)) {
ERR("ERROR - tree_lock not held exclusively\n");
int3;
}
// if (!ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock)) {
// ERR("ERROR - tree_lock not held exclusively\n");
// int3;
// }
if (tp->item->ignore) {
ERR("trying to delete already-deleted item %llx,%x,%llx\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
@ -1025,6 +1033,10 @@ void clear_rollback(LIST_ENTRY* rollback) {
switch (ri->type) {
case ROLLBACK_INSERT_ITEM:
case ROLLBACK_DELETE_ITEM:
case ROLLBACK_ADD_SPACE:
case ROLLBACK_SUBTRACT_SPACE:
case ROLLBACK_INSERT_EXTENT:
case ROLLBACK_DELETE_EXTENT:
ExFreePool(ri->ptr);
break;
@ -1037,6 +1049,7 @@ void clear_rollback(LIST_ENTRY* rollback) {
}
void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
NTSTATUS Status;
rollback_item* ri;
while (!IsListEmpty(rollback)) {
@ -1082,17 +1095,105 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
case ROLLBACK_INSERT_EXTENT:
{
extent* ext = ri->ptr;
rollback_extent* re = ri->ptr;
ext->ignore = TRUE;
re->ext->ignore = TRUE;
if (re->ext->data->type == EXTENT_TYPE_REGULAR || re->ext->data->type == EXTENT_TYPE_PREALLOC) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->data->data;
if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (c) {
Status = update_changed_extent_ref(Vcb, c, ed2->address, ed2->size, re->fcb->subvol->id,
re->fcb->inode, re->ext->offset - ed2->offset, -1,
re->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, ed2->size, NULL);
if (!NT_SUCCESS(Status))
ERR("update_changed_extent_ref returned %08x\n", Status);
}
re->fcb->inode_item.st_blocks -= ed2->num_bytes;
}
}
ExFreePool(re);
break;
}
case ROLLBACK_DELETE_EXTENT:
{
extent* ext = ri->ptr;
rollback_extent* re = ri->ptr;
re->ext->ignore = FALSE;
if (re->ext->data->type == EXTENT_TYPE_REGULAR || re->ext->data->type == EXTENT_TYPE_PREALLOC) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)re->ext->data->data;
if (ed2->size != 0) {
chunk* c = get_chunk_from_address(Vcb, ed2->address);
if (c) {
Status = update_changed_extent_ref(Vcb, c, ed2->address, ed2->size, re->fcb->subvol->id,
re->fcb->inode, re->ext->offset - ed2->offset, 1,
re->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, ed2->size, NULL);
if (!NT_SUCCESS(Status))
ERR("update_changed_extent_ref returned %08x\n", Status);
}
re->fcb->inode_item.st_blocks += ed2->num_bytes;
}
}
ExFreePool(re);
break;
}
case ROLLBACK_ADD_SPACE:
case ROLLBACK_SUBTRACT_SPACE:
{
rollback_space* rs = ri->ptr;
if (rs->chunk)
ExAcquireResourceExclusiveLite(&rs->chunk->lock, TRUE);
if (ri->type == ROLLBACK_ADD_SPACE)
space_list_subtract2(rs->list, rs->list_size, rs->address, rs->length, NULL);
else
space_list_add2(rs->list, rs->list_size, rs->address, rs->length, NULL);
if (rs->chunk) {
LIST_ENTRY* le2 = le->Blink;
while (le2 != rollback) {
LIST_ENTRY* le3 = le2->Blink;
rollback_item* ri2 = CONTAINING_RECORD(le2, rollback_item, list_entry);
if (ri2->type == ROLLBACK_ADD_SPACE || ri2->type == ROLLBACK_SUBTRACT_SPACE) {
rollback_space* rs2 = ri2->ptr;
if (rs2->chunk == rs->chunk) {
if (ri2->type == ROLLBACK_ADD_SPACE)
space_list_subtract2(rs2->list, rs2->list_size, rs2->address, rs2->length, NULL);
else
space_list_add2(rs2->list, rs2->list_size, rs2->address, rs2->length, NULL);
ExFreePool(rs2);
RemoveEntryList(&ri2->list_entry);
ExFreePool(ri2);
}
}
le2 = le3;
}
ExReleaseResourceLite(&rs->chunk->lock);
}
ExFreePool(rs);
ext->ignore = FALSE;
break;
}
}

View file

@ -1,3 +1,20 @@
/* Copyright (c) Mark Harmstone 2016
*
* This file is part of WinBtrfs.
*
* WinBtrfs is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation, either version 3 of the Licence, or
* (at your option) any later version.
*
* WinBtrfs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public Licence for more details.
*
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
#include "btrfs_drv.h"
void do_read_job(PIRP Irp) {
@ -78,6 +95,7 @@ void STDCALL worker_thread(void* context) {
while (TRUE) {
LIST_ENTRY* le;
device_extension* Vcb = thread->DeviceObject->DeviceExtension;
KeAcquireSpinLock(&thread->spin_lock, &irql);
@ -91,6 +109,7 @@ void STDCALL worker_thread(void* context) {
KeReleaseSpinLock(&thread->spin_lock, irql);
InterlockedDecrement(&Vcb->threads.pending_jobs);
do_job(thread, le);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,17 @@
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib
inc)
list(APPEND SOURCE
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/adler32.c
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/crc32.c
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/deflate.c
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/inffast.c
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/inflate.c
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/inftrees.c
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/trees.c
${REACTOS_SOURCE_DIR}/sdk/lib/3rdparty/zlib/zutil.c)
add_library(zlib_solo ${SOURCE})
add_definitions(-DZ_SOLO)

View file

@ -3,7 +3,7 @@
The following FSD are shared with: https://github.com/maharmstone/btrfs.
reactos/drivers/filesystems/btrfs # Synced to 0.5
reactos/drivers/filesystems/btrfs # Synced to 0.6
The following FSD are shared with: http://www.ext2fsd.com/