static NTSTATUS query_directory(PIRP Irp) { PIO_STACK_LOCATION IrpSp; NTSTATUS Status, status2; fcb* fcb; ccb* ccb; file_ref* fileref; device_extension* Vcb; void* buf; UINT8 *curitem, *lastitem; LONG length; ULONG count; BOOL has_wildcard = FALSE, specific_file = FALSE, initial; dir_entry de; UINT64 newoffset; dir_child* dc = NULL; TRACE("query directory\n"); IrpSp = IoGetCurrentIrpStackLocation(Irp); fcb = IrpSp->FileObject->FsContext; ccb = IrpSp->FileObject->FsContext2; fileref = ccb ? ccb->fileref : NULL; if (!fileref) return STATUS_INVALID_PARAMETER; if (!ccb) { ERR("ccb was NULL\n"); return STATUS_INVALID_PARAMETER; } if (!fcb) { ERR("fcb was NULL\n"); return STATUS_INVALID_PARAMETER; } if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_LIST_DIRECTORY)) { WARN("insufficient privileges\n"); return STATUS_ACCESS_DENIED; } Vcb = fcb->Vcb; if (!Vcb) { ERR("Vcb was NULL\n"); return STATUS_INVALID_PARAMETER; } if (fileref->fcb == Vcb->dummy_fcb) return STATUS_NO_MORE_FILES; if (IrpSp->Flags == 0) { TRACE("QD flags: (none)\n"); } else { ULONG flags = IrpSp->Flags; TRACE("QD flags:\n"); if (flags & SL_INDEX_SPECIFIED) { TRACE(" SL_INDEX_SPECIFIED\n"); flags &= ~SL_INDEX_SPECIFIED; } if (flags & SL_RESTART_SCAN) { TRACE(" SL_RESTART_SCAN\n"); flags &= ~SL_RESTART_SCAN; } if (flags & SL_RETURN_SINGLE_ENTRY) { TRACE(" SL_RETURN_SINGLE_ENTRY\n"); flags &= ~SL_RETURN_SINGLE_ENTRY; } if (flags != 0) TRACE(" unknown flags: %u\n", flags); } if (IrpSp->Flags & SL_RESTART_SCAN) { ccb->query_dir_offset = 0; if (ccb->query_string.Buffer) { RtlFreeUnicodeString(&ccb->query_string); ccb->query_string.Buffer = NULL; } ccb->has_wildcard = FALSE; ccb->specific_file = FALSE; } initial = !ccb->query_string.Buffer; if (IrpSp->Parameters.QueryDirectory.FileName && IrpSp->Parameters.QueryDirectory.FileName->Length > 1) { TRACE("QD filename: %.*S\n", IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR), IrpSp->Parameters.QueryDirectory.FileName->Buffer); if (IrpSp->Parameters.QueryDirectory.FileName->Length > sizeof(WCHAR) || IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != L'*') { specific_file = TRUE; if (FsRtlDoesNameContainWildCards(IrpSp->Parameters.QueryDirectory.FileName)) { has_wildcard = TRUE; specific_file = FALSE; } } if (ccb->query_string.Buffer) RtlFreeUnicodeString(&ccb->query_string); if (has_wildcard) RtlUpcaseUnicodeString(&ccb->query_string, IrpSp->Parameters.QueryDirectory.FileName, TRUE); else { ccb->query_string.Buffer = ExAllocatePoolWithTag(PagedPool, IrpSp->Parameters.QueryDirectory.FileName->Length, ALLOC_TAG); if (!ccb->query_string.Buffer) { ERR("out of memory\n"); return STATUS_INSUFFICIENT_RESOURCES; } ccb->query_string.Length = ccb->query_string.MaximumLength = IrpSp->Parameters.QueryDirectory.FileName->Length; RtlCopyMemory(ccb->query_string.Buffer, IrpSp->Parameters.QueryDirectory.FileName->Buffer, IrpSp->Parameters.QueryDirectory.FileName->Length); } ccb->has_wildcard = has_wildcard; ccb->specific_file = specific_file; } else { has_wildcard = ccb->has_wildcard; specific_file = ccb->specific_file; if (!(IrpSp->Flags & SL_RESTART_SCAN)) { initial = FALSE; if (specific_file) return STATUS_NO_MORE_FILES; } } if (ccb->query_string.Buffer) { TRACE("query string = %.*S\n", ccb->query_string.Length / sizeof(WCHAR), ccb->query_string.Buffer); } newoffset = ccb->query_dir_offset; ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE); Status = next_dir_entry(fileref, &newoffset, &de, &dc); if (!NT_SUCCESS(Status)) { if (Status == STATUS_NO_MORE_FILES && initial) Status = STATUS_NO_SUCH_FILE; goto end; } ccb->query_dir_offset = newoffset; buf = map_user_buffer(Irp, NormalPagePriority); if (Irp->MdlAddress && !buf) { ERR("MmGetSystemAddressForMdlSafe returned NULL\n"); Status = STATUS_INSUFFICIENT_RESOURCES; goto end; } length = IrpSp->Parameters.QueryDirectory.Length; if (specific_file) { BOOL found = FALSE; UNICODE_STRING us; LIST_ENTRY* le; UINT32 hash; UINT8 c; us.Buffer = NULL; if (!ccb->case_sensitive) { Status = RtlUpcaseUnicodeString(&us, &ccb->query_string, TRUE); if (!NT_SUCCESS(Status)) { ERR("RtlUpcaseUnicodeString returned %08x\n", Status); goto end; } hash = calc_crc32c(0xffffffff, (UINT8*)us.Buffer, us.Length); } else hash = calc_crc32c(0xffffffff, (UINT8*)ccb->query_string.Buffer, ccb->query_string.Length); c = hash >> 24; if (ccb->case_sensitive) { if (fileref->fcb->hash_ptrs[c]) { le = fileref->fcb->hash_ptrs[c]; while (le != &fileref->fcb->dir_children_hash) { dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash); if (dc2->hash == hash) { if (dc2->name.Length == ccb->query_string.Length && RtlCompareMemory(dc2->name.Buffer, ccb->query_string.Buffer, ccb->query_string.Length) == ccb->query_string.Length) { found = TRUE; de.key = dc2->key; de.name = dc2->name; de.type = dc2->type; de.dir_entry_type = DirEntryType_File; de.dc = dc2; break; } } else if (dc2->hash > hash) break; le = le->Flink; } } } else { if (fileref->fcb->hash_ptrs_uc[c]) { le = fileref->fcb->hash_ptrs_uc[c]; while (le != &fileref->fcb->dir_children_hash_uc) { dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc); if (dc2->hash_uc == hash) { if (dc2->name_uc.Length == us.Length && RtlCompareMemory(dc2->name_uc.Buffer, us.Buffer, us.Length) == us.Length) { found = TRUE; de.key = dc2->key; de.name = dc2->name; de.type = dc2->type; de.dir_entry_type = DirEntryType_File; de.dc = dc2; break; } } else if (dc2->hash_uc > hash) break; le = le->Flink; } } } if (us.Buffer) ExFreePool(us.Buffer); if (!found) { Status = STATUS_NO_SUCH_FILE; goto end; } } else if (has_wildcard) {
NTSTATUS STDCALL drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); UINT8* data; PFILE_OBJECT FileObject = IrpSp->FileObject; fcb* fcb = FileObject->FsContext; UINT64 start; ULONG length, bytes_read; NTSTATUS Status; BOOL top_level; FsRtlEnterFileSystem(); top_level = is_top_level(Irp); TRACE("read\n"); Irp->IoStatus.Information = 0; if (IrpSp->MinorFunction & IRP_MN_COMPLETE) { CcMdlReadComplete(IrpSp->FileObject, Irp->MdlAddress); Irp->MdlAddress = NULL; Status = STATUS_SUCCESS; bytes_read = 0; goto exit; } start = IrpSp->Parameters.Read.ByteOffset.QuadPart; length = IrpSp->Parameters.Read.Length; bytes_read = 0; if (!fcb || !fcb->Vcb || !fcb->subvol) { Status = STATUS_INTERNAL_ERROR; // FIXME - invalid param error? goto exit; } TRACE("file = %S (fcb = %p)\n", file_desc(FileObject), fcb); TRACE("offset = %llx, length = %x\n", start, length); TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO ? "TRUE" : "FALSE", Irp->Flags & IRP_NOCACHE ? "TRUE" : "FALSE"); if (fcb->type == BTRFS_TYPE_DIRECTORY) { Status = STATUS_INVALID_DEVICE_REQUEST; goto exit; } if (!(Irp->Flags & IRP_PAGING_IO) && !FsRtlCheckLockForReadAccess(&fcb->lock, Irp)) { WARN("tried to read locked region\n"); Status = STATUS_FILE_LOCK_CONFLICT; goto exit; } if (length == 0) { WARN("tried to read zero bytes\n"); Status = STATUS_SUCCESS; goto exit; } if (start >= fcb->Header.FileSize.QuadPart) { TRACE("tried to read with offset after file end (%llx >= %llx)\n", start, fcb->Header.FileSize.QuadPart); Status = STATUS_END_OF_FILE; goto exit; } TRACE("FileObject %p fcb %p FileSize = %llx st_size = %llx (%p)\n", FileObject, fcb, fcb->Header.FileSize.QuadPart, fcb->inode_item.st_size, &fcb->inode_item.st_size); // int3; if (Irp->Flags & IRP_NOCACHE || !(IrpSp->MinorFunction & IRP_MN_MDL)) { data = map_user_buffer(Irp); if (Irp->MdlAddress && !data) { ERR("MmGetSystemAddressForMdlSafe returned NULL\n"); Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } if (length + start > fcb->Header.ValidDataLength.QuadPart) { RtlZeroMemory(data + (fcb->Header.ValidDataLength.QuadPart - start), length - (fcb->Header.ValidDataLength.QuadPart - start)); length = fcb->Header.ValidDataLength.QuadPart - start; } } if (!(Irp->Flags & IRP_NOCACHE)) { BOOL wait; Status = STATUS_SUCCESS; _SEH2_TRY { if (!FileObject->PrivateCacheMap) { CC_FILE_SIZES ccfs; ccfs.AllocationSize = fcb->Header.AllocationSize; ccfs.FileSize = fcb->Header.FileSize; ccfs.ValidDataLength = fcb->Header.ValidDataLength; TRACE("calling CcInitializeCacheMap (%llx, %llx, %llx)\n", ccfs.AllocationSize.QuadPart, ccfs.FileSize.QuadPart, ccfs.ValidDataLength.QuadPart); CcInitializeCacheMap(FileObject, &ccfs, FALSE, cache_callbacks, FileObject); CcSetReadAheadGranularity(FileObject, READ_AHEAD_GRANULARITY); } // FIXME - uncomment this when async is working // wait = IoIsOperationSynchronous(Irp) ? TRUE : FALSE; wait = TRUE; if (IrpSp->MinorFunction & IRP_MN_MDL) { CcMdlRead(FileObject,&IrpSp->Parameters.Read.ByteOffset, length, &Irp->MdlAddress, &Irp->IoStatus); } else { TRACE("CcCopyRead(%p, %llx, %x, %u, %p, %p)\n", FileObject, IrpSp->Parameters.Read.ByteOffset.QuadPart, length, wait, data, &Irp->IoStatus); TRACE("sizes = %llx, %llx, %llx\n", fcb->Header.AllocationSize, fcb->Header.FileSize, fcb->Header.ValidDataLength); if (!CcCopyRead(FileObject, &IrpSp->Parameters.Read.ByteOffset, length, wait, data, &Irp->IoStatus)) { TRACE("CcCopyRead failed\n"); IoMarkIrpPending(Irp); Status = STATUS_PENDING; goto exit; } TRACE("CcCopyRead finished\n"); } } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (NT_SUCCESS(Status)) { Status = Irp->IoStatus.Status; bytes_read = Irp->IoStatus.Information; } else ERR("EXCEPTION - %08x\n", Status); } else {