NTSTATUS VfatWrite( PVFAT_IRP_CONTEXT IrpContext) { PVFATFCB Fcb; PERESOURCE Resource = NULL; LARGE_INTEGER ByteOffset; LARGE_INTEGER OldFileSize; NTSTATUS Status = STATUS_SUCCESS; ULONG Length = 0; PVOID Buffer; ULONG BytesPerSector; ASSERT(IrpContext); DPRINT("VfatWrite(IrpContext %p)\n", IrpContext); ASSERT(IrpContext->DeviceObject); // This request is not allowed on the main device object if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { DPRINT("VfatWrite is called with the main device object.\n"); Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } ASSERT(IrpContext->DeviceExt); ASSERT(IrpContext->FileObject); Fcb = IrpContext->FileObject->FsContext; ASSERT(Fcb); if (Fcb->Flags & FCB_IS_PAGE_FILE) { PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; IoSkipCurrentIrpStackLocation(IrpContext->Irp); DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart); Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); VfatFreeIrpContext(IrpContext); return Status; } DPRINT("<%wZ>\n", &Fcb->PathNameU); /* fail if file is a directory and no paged read */ if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset; if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE && ByteOffset.u.HighPart == -1) { ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart; } Length = IrpContext->Stack->Parameters.Write.Length; BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) || vfatDirEntryGetFirstCluster(IrpContext->DeviceExt, &Fcb->entry) == 1) { if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart) { // we can't extend the FAT, the volume or the root on FAT12/FAT16 Status = STATUS_END_OF_FILE; goto ByeBye; } } if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) { // non cached write must be sector aligned Status = STATUS_INVALID_PARAMETER; goto ByeBye; } } if (Length == 0) { /* FIXME: Update last write time */ IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; goto ByeBye; } if (IrpContext->Irp->Flags & IRP_PAGING_IO) { if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector)) { Length = ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart; } } if (Fcb->Flags & FCB_IS_VOLUME) { Resource = &IrpContext->DeviceExt->DirResource; } else if (IrpContext->Irp->Flags & IRP_PAGING_IO) { Resource = &Fcb->PagingIoResource; } else { Resource = &Fcb->MainResource; } if (Fcb->Flags & FCB_IS_PAGE_FILE) { if (!ExAcquireResourceSharedLite(Resource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } } else { if (!ExAcquireResourceExclusiveLite(Resource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) { if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; goto ByeBye; } } if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart) { Status = STATUS_PENDING; goto ByeBye; } } OldFileSize = Fcb->RFCB.FileSize; Buffer = VfatGetUserBuffer(IrpContext->Irp); if (!Buffer) { Status = STATUS_INVALID_USER_BUFFER; goto ByeBye; } if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) && !(IrpContext->Irp->Flags & IRP_PAGING_IO) && ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) { LARGE_INTEGER AllocationSize; AllocationSize.QuadPart = ByteOffset.u.LowPart + Length; Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb, IrpContext->DeviceExt, &AllocationSize); if (!NT_SUCCESS (Status)) { goto ByeBye; } } if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) { // cached write if (IrpContext->FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(IrpContext->FileObject, (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), FALSE, &VfatGlobalData->CacheMgrCallbacks, Fcb); } if (ByteOffset.QuadPart > OldFileSize.QuadPart) { CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); } if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length, 1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer)) { IrpContext->Irp->IoStatus.Information = Length; Status = STATUS_SUCCESS; } else { Status = STATUS_UNSUCCESSFUL; } } else { // non cached write if (ByteOffset.QuadPart > OldFileSize.QuadPart) { CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE); } Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (!NT_SUCCESS(Status)) { goto ByeBye; } Status = VfatWriteFileData(IrpContext, Length, ByteOffset); if (NT_SUCCESS(Status)) { IrpContext->Irp->IoStatus.Information = Length; } } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME))) { if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)) { LARGE_INTEGER SystemTime; // set dates and times KeQuerySystemTime (&SystemTime); if (Fcb->Flags & FCB_IS_FATX_ENTRY) { FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, &SystemTime, &Fcb->entry.FatX.UpdateDate, &Fcb->entry.FatX.UpdateTime); Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate; Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime; } else { FsdSystemTimeToDosDateTime(IrpContext->DeviceExt, &SystemTime, &Fcb->entry.Fat.UpdateDate, &Fcb->entry.Fat.UpdateTime); Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate; } /* set date and times to dirty */ Fcb->Flags |= FCB_IS_DIRTY; } } ByeBye: if (Resource) { ExReleaseResourceLite(Resource); } if (Status == STATUS_PENDING) { Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess); if (NT_SUCCESS(Status)) { Status = VfatQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); } } else { IrpContext->Irp->IoStatus.Status = Status; if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status)) { IrpContext->FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; } IoCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); VfatFreeIrpContext(IrpContext); } DPRINT("%x\n", Status); return Status; }
static NTSTATUS DoQuery (PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS RC = STATUS_SUCCESS; long BufferLength = 0; PUNICODE_STRING pSearchPattern = NULL; FILE_INFORMATION_CLASS FileInformationClass; unsigned char *Buffer = NULL; PFILE_NAMES_INFORMATION Buffer0 = NULL; PVFATFCB pFcb; PVFATCCB pCcb; BOOLEAN FirstQuery = FALSE; BOOLEAN FirstCall = TRUE; VFAT_DIRENTRY_CONTEXT DirContext; WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1]; WCHAR ShortNameBuffer[13]; PIO_STACK_LOCATION Stack = IrpContext->Stack; pCcb = (PVFATCCB) IrpContext->FileObject->FsContext2; pFcb = (PVFATFCB) IrpContext->FileObject->FsContext; // determine Buffer for result : BufferLength = Stack->Parameters.QueryDirectory.Length; #if 0 /* Do not probe the user buffer until SEH is available */ if (IrpContext->Irp->RequestorMode != KernelMode && IrpContext->Irp->MdlAddress == NULL && IrpContext->Irp->UserBuffer != NULL) { ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1); } #endif Buffer = VfatGetUserBuffer(IrpContext->Irp); if (!ExAcquireResourceSharedLite(&pFcb->MainResource, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT))) { RC = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess); if (NT_SUCCESS(RC)) { RC = STATUS_PENDING; } return RC; } /* Obtain the callers parameters */ #ifdef _MSC_VER /* HACKHACK: Bug in the MS ntifs.h header: * FileName is really a PUNICODE_STRING, not a PSTRING */ pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName; #else pSearchPattern = Stack->Parameters.QueryDirectory.FileName; #endif FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass; if (pSearchPattern) { if (!pCcb->SearchPattern.Buffer) { FirstQuery = TRUE; pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR); pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, pCcb->SearchPattern.MaximumLength, TAG_VFAT); if (!pCcb->SearchPattern.Buffer) { ExReleaseResourceLite(&pFcb->MainResource); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern); pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0; } } else if (!pCcb->SearchPattern.Buffer) { FirstQuery = TRUE; pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR); pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_VFAT); if (!pCcb->SearchPattern.Buffer) { ExReleaseResourceLite(&pFcb->MainResource); return STATUS_INSUFFICIENT_RESOURCES; } pCcb->SearchPattern.Buffer[0] = L'*'; pCcb->SearchPattern.Buffer[1] = 0; pCcb->SearchPattern.Length = sizeof(WCHAR); } if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED) { DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex; } else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN)) { DirContext.DirIndex = pCcb->Entry = 0; } else { DirContext.DirIndex = pCcb->Entry; } DPRINT ("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern); DirContext.LongNameU.Buffer = LongNameBuffer; DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer); DirContext.ShortNameU.Buffer = ShortNameBuffer; DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer); while (RC == STATUS_SUCCESS && BufferLength > 0) { RC = FindFile (IrpContext->DeviceExt, pFcb, &pCcb->SearchPattern, &DirContext, FirstCall); pCcb->Entry = DirContext.DirIndex; DPRINT ("Found %wZ, RC=%x, entry %x\n", &DirContext.LongNameU, RC, pCcb->Entry); FirstCall = FALSE; if (NT_SUCCESS (RC)) { switch (FileInformationClass) { case FileNameInformation: RC = VfatGetFileNameInformation (&DirContext, (PFILE_NAMES_INFORMATION) Buffer, BufferLength); break; case FileDirectoryInformation: RC = VfatGetFileDirectoryInformation (&DirContext, IrpContext->DeviceExt, (PFILE_DIRECTORY_INFORMATION) Buffer, BufferLength); break; case FileFullDirectoryInformation: RC = VfatGetFileFullDirectoryInformation (&DirContext, IrpContext->DeviceExt, (PFILE_FULL_DIR_INFORMATION) Buffer, BufferLength); break; case FileBothDirectoryInformation: RC = VfatGetFileBothInformation (&DirContext, IrpContext->DeviceExt, (PFILE_BOTH_DIR_INFORMATION) Buffer, BufferLength); break; default: RC = STATUS_INVALID_INFO_CLASS; } if (RC == STATUS_BUFFER_OVERFLOW) { break; } } else { if (FirstQuery) { RC = STATUS_NO_SUCH_FILE; } else { RC = STATUS_NO_MORE_FILES; } break; } Buffer0 = (PFILE_NAMES_INFORMATION) Buffer; Buffer0->FileIndex = DirContext.DirIndex; pCcb->Entry = ++DirContext.DirIndex; BufferLength -= Buffer0->NextEntryOffset; if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY) { break; } Buffer += Buffer0->NextEntryOffset; } if (Buffer0) { Buffer0->NextEntryOffset = 0; RC = STATUS_SUCCESS; IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength; } ExReleaseResourceLite(&pFcb->MainResource); return RC; }
NTSTATUS VfatRead( PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS Status; PVFATFCB Fcb; ULONG Length = 0; ULONG ReturnedLength = 0; PERESOURCE Resource = NULL; LARGE_INTEGER ByteOffset; PVOID Buffer; ULONG BytesPerSector; ASSERT(IrpContext); DPRINT("VfatRead(IrpContext %p)\n", IrpContext); ASSERT(IrpContext->DeviceObject); // This request is not allowed on the main device object if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { DPRINT("VfatRead is called with the main device object.\n"); Status = STATUS_INVALID_DEVICE_REQUEST; goto ByeBye; } ASSERT(IrpContext->DeviceExt); ASSERT(IrpContext->FileObject); Fcb = IrpContext->FileObject->FsContext; ASSERT(Fcb); if (Fcb->Flags & FCB_IS_PAGE_FILE) { PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo; IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector; IoSkipCurrentIrpStackLocation(IrpContext->Irp); DPRINT("Read from page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Read.ByteOffset.QuadPart); Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp); VfatFreeIrpContext(IrpContext); return Status; } DPRINT("<%wZ>\n", &Fcb->PathNameU); ByteOffset = IrpContext->Stack->Parameters.Read.ByteOffset; Length = IrpContext->Stack->Parameters.Read.Length; BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector; /* fail if file is a directory and no paged read */ if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } DPRINT("'%wZ', Offset: %u, Length %u\n", &Fcb->PathNameU, ByteOffset.u.LowPart, Length); if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME)) { Status = STATUS_INVALID_PARAMETER; goto ByeBye; } if (ByteOffset.QuadPart >= Fcb->RFCB.FileSize.QuadPart) { IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_END_OF_FILE; goto ByeBye; } if (IrpContext->Irp->Flags & (IRP_PAGING_IO | IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME)) { if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0) { DPRINT("%u %u\n", ByteOffset.u.LowPart, Length); // non cached read must be sector aligned Status = STATUS_INVALID_PARAMETER; goto ByeBye; } } if (Length == 0) { IrpContext->Irp->IoStatus.Information = 0; Status = STATUS_SUCCESS; goto ByeBye; } if (Fcb->Flags & FCB_IS_VOLUME) { Resource = &IrpContext->DeviceExt->DirResource; } else if (IrpContext->Irp->Flags & IRP_PAGING_IO) { Resource = &Fcb->PagingIoResource; } else { Resource = &Fcb->MainResource; } if (!ExAcquireResourceSharedLite(Resource, IrpContext->Flags & IRPCONTEXT_CANWAIT ? TRUE : FALSE)) { Resource = NULL; Status = STATUS_PENDING; goto ByeBye; } if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) && FsRtlAreThereCurrentFileLocks(&Fcb->FileLock)) { if (!FsRtlCheckLockForReadAccess(&Fcb->FileLock, IrpContext->Irp)) { Status = STATUS_FILE_LOCK_CONFLICT; goto ByeBye; } } Buffer = VfatGetUserBuffer(IrpContext->Irp); if (!Buffer) { Status = STATUS_INVALID_USER_BUFFER; goto ByeBye; } if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) && !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME))) { // cached read Status = STATUS_SUCCESS; if (ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart) { Length = Fcb->RFCB.FileSize.u.LowPart - ByteOffset.u.LowPart; Status = /*STATUS_END_OF_FILE*/STATUS_SUCCESS; } if (IrpContext->FileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap(IrpContext->FileObject, (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize), FALSE, &(VfatGlobalData->CacheMgrCallbacks), Fcb); } if (!CcCopyRead(IrpContext->FileObject, &ByteOffset, Length, (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT), Buffer, &IrpContext->Irp->IoStatus)) { Status = STATUS_PENDING; goto ByeBye; } if (!NT_SUCCESS(IrpContext->Irp->IoStatus.Status)) { Status = IrpContext->Irp->IoStatus.Status; } } else { // non cached read if (ByteOffset.QuadPart + Length > ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector)) { Length = (ULONG)(ROUND_UP(Fcb->RFCB.FileSize.QuadPart, BytesPerSector) - ByteOffset.QuadPart); } Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess); if (!NT_SUCCESS(Status)) { goto ByeBye; } Status = VfatReadFileData(IrpContext, Length, ByteOffset, &ReturnedLength); if (NT_SUCCESS(Status)) { IrpContext->Irp->IoStatus.Information = ReturnedLength; } } ByeBye: if (Resource) { ExReleaseResourceLite(Resource); } if (Status == STATUS_PENDING) { Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoWriteAccess); if (NT_SUCCESS(Status)) { Status = VfatQueueRequest(IrpContext); } else { IrpContext->Irp->IoStatus.Status = Status; IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT); VfatFreeIrpContext(IrpContext); } } else { IrpContext->Irp->IoStatus.Status = Status; if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO && !(IrpContext->Irp->Flags & IRP_PAGING_IO) && (NT_SUCCESS(Status) || Status == STATUS_END_OF_FILE)) { IrpContext->FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information; } IoCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT)); VfatFreeIrpContext(IrpContext); } DPRINT("%x\n", Status); return Status; }
static NTSTATUS DoQuery( PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS Status = STATUS_SUCCESS; LONG BufferLength = 0; PUNICODE_STRING pSearchPattern = NULL; FILE_INFORMATION_CLASS FileInformationClass; PUCHAR Buffer = NULL; PFILE_NAMES_INFORMATION Buffer0 = NULL; PVFATFCB pFcb; PVFATCCB pCcb; BOOLEAN FirstQuery = FALSE; BOOLEAN FirstCall = TRUE; VFAT_DIRENTRY_CONTEXT DirContext; WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1]; WCHAR ShortNameBuffer[13]; PIO_STACK_LOCATION Stack = IrpContext->Stack; pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2; pFcb = (PVFATFCB)IrpContext->FileObject->FsContext; /* Determine Buffer for result : */ BufferLength = Stack->Parameters.QueryDirectory.Length; #if 0 /* Do not probe the user buffer until SEH is available */ if (IrpContext->Irp->RequestorMode != KernelMode && IrpContext->Irp->MdlAddress == NULL && IrpContext->Irp->UserBuffer != NULL) { ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1); } #endif Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE); if (!ExAcquireResourceSharedLite(&pFcb->MainResource, BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) { Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess); if (NT_SUCCESS(Status)) Status = STATUS_PENDING; return Status; } /* Obtain the callers parameters */ #ifdef _MSC_VER /* HACKHACK: Bug in the MS ntifs.h header: * FileName is really a PUNICODE_STRING, not a PSTRING */ pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName; #else pSearchPattern = Stack->Parameters.QueryDirectory.FileName; #endif FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass; /* Allocate search pattern in case: * -> We don't have one already in context * -> We have been given an input pattern * -> The pattern length is not null * -> The pattern buffer is not null * Otherwise, we'll fall later and allocate a match all (*) pattern */ if (pSearchPattern && pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL) { if (!pCcb->SearchPattern.Buffer) { FirstQuery = TRUE; pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR); pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, pCcb->SearchPattern.MaximumLength, TAG_VFAT); if (!pCcb->SearchPattern.Buffer) { ExReleaseResourceLite(&pFcb->MainResource); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern); pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0; } } else if (!pCcb->SearchPattern.Buffer) { FirstQuery = TRUE; pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR); pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_VFAT); if (!pCcb->SearchPattern.Buffer) { ExReleaseResourceLite(&pFcb->MainResource); return STATUS_INSUFFICIENT_RESOURCES; } pCcb->SearchPattern.Buffer[0] = L'*'; pCcb->SearchPattern.Buffer[1] = 0; pCcb->SearchPattern.Length = sizeof(WCHAR); } if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED) { DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex; } else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN)) { DirContext.DirIndex = pCcb->Entry = 0; } else { DirContext.DirIndex = pCcb->Entry; } DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern); DirContext.LongNameU.Buffer = LongNameBuffer; DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer); DirContext.ShortNameU.Buffer = ShortNameBuffer; DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer); if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))) { ExReleaseResourceLite(&pFcb->MainResource); return VfatMarkIrpContextForQueue(IrpContext); } while ((Status == STATUS_SUCCESS) && (BufferLength > 0)) { Status = FindFile(IrpContext->DeviceExt, pFcb, &pCcb->SearchPattern, &DirContext, FirstCall); pCcb->Entry = DirContext.DirIndex; DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry); FirstCall = FALSE; if (NT_SUCCESS(Status)) { switch (FileInformationClass) { case FileNameInformation: Status = VfatGetFileNameInformation(&DirContext, (PFILE_NAMES_INFORMATION)Buffer, BufferLength); break; case FileDirectoryInformation: Status = VfatGetFileDirectoryInformation(&DirContext, IrpContext->DeviceExt, (PFILE_DIRECTORY_INFORMATION)Buffer, BufferLength); break; case FileFullDirectoryInformation: Status = VfatGetFileFullDirectoryInformation(&DirContext, IrpContext->DeviceExt, (PFILE_FULL_DIR_INFORMATION)Buffer, BufferLength); break; case FileBothDirectoryInformation: Status = VfatGetFileBothInformation(&DirContext, IrpContext->DeviceExt, (PFILE_BOTH_DIR_INFORMATION)Buffer, BufferLength); break; default: Status = STATUS_INVALID_INFO_CLASS; break; } if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS) break; } else { Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES); break; } Buffer0 = (PFILE_NAMES_INFORMATION) Buffer; Buffer0->FileIndex = DirContext.DirIndex; pCcb->Entry = ++DirContext.DirIndex; BufferLength -= Buffer0->NextEntryOffset; if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY) break; Buffer += Buffer0->NextEntryOffset; } if (Buffer0) { Buffer0->NextEntryOffset = 0; Status = STATUS_SUCCESS; IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength; } ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); ExReleaseResourceLite(&pFcb->MainResource); return Status; }