/* * @implemented */ BOOLEAN NTAPI FsRtlLookupMcbEntry(IN PMCB Mcb, IN VBN Vbn, OUT PLBN Lbn, OUT PULONG SectorCount OPTIONAL, OUT PULONG Index) { BOOLEAN Return = FALSE; LONGLONG llLbn; LONGLONG llSectorCount; /* Call the Large version */ Return = FsRtlLookupLargeMcbEntry(&Mcb-> DummyFieldThatSizesThisStructureCorrectly, (LONGLONG)Vbn, &llLbn, &llSectorCount, NULL, NULL, Index); /* Return the lower 32-bits */ *Lbn = (ULONG)llLbn; if (SectorCount) *SectorCount = (ULONG)llSectorCount; /* And return the original value */ return Return; }
BOOLEAN UdfLookupAllocation ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN LONGLONG FileOffset, OUT PLONGLONG DiskOffset, OUT PULONG ByteCount ) /*++ Routine Description: This routine looks through the mapping information for the file to find the logical diskoffset and number of bytes at that offset. This routine assumes we are looking up a valid range in the file. If a mapping does not exist, Arguments: Fcb - Fcb representing this stream. FileOffset - Lookup the allocation beginning at this point. DiskOffset - Address to store the logical disk offset. ByteCount - Address to store the number of contiguous bytes beginning at DiskOffset above. Return Value: BOOLEAN - whether the extent is unrecorded data --*/ { PVCB Vcb; BOOLEAN Recorded = TRUE; BOOLEAN Result; LARGE_INTEGER LocalPsn; LARGE_INTEGER LocalSectorCount; PAGED_CODE(); // // Check inputs // ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_FCB( Fcb ); // // We will never be looking up the allocations of embedded objects. // ASSERT( !FlagOn( Fcb->FcbState, FCB_STATE_EMBEDDED_DATA )); Vcb = Fcb->Vcb; LocalPsn.QuadPart = LocalSectorCount.QuadPart = 0; // // Lookup the entry containing this file offset. // if (FlagOn( Fcb->FcbState, FCB_STATE_VMCB_MAPPING )) { // // Map this offset into the metadata stream. // ASSERT( SectorOffset( Vcb, FileOffset ) == 0 ); Result = UdfVmcbVbnToLbn( &Vcb->Vmcb, SectorsFromBytes( Vcb, FileOffset ), &LocalPsn.LowPart, &LocalSectorCount.LowPart ); ASSERT( Result ); } else { // // Map this offset in a regular stream. // ASSERT( FlagOn( Fcb->FcbState, FCB_STATE_MCB_INITIALIZED )); Result = FsRtlLookupLargeMcbEntry( &Fcb->Mcb, LlSectorsFromBytes( Vcb, FileOffset ), &LocalPsn.QuadPart, &LocalSectorCount.QuadPart, NULL, NULL, NULL ); } // // If within the Mcb then we use the data out of this entry and are nearly done. // if (Result) { if ( LocalPsn.QuadPart == -1 ) { // // Regular files can have holey allocations which represent unrecorded extents. For // such extents which are sandwiched in between recorded extents of the file, the Mcb // package tells us that it found a valid mapping but that it doesn't correspond to // any extents on the media yet. In this case, simply fake the disk offset. The // returned sector count is accurate. // *DiskOffset = 0; Recorded = FALSE; } else { // // Now mimic the effects of physical sector sparing. This may shrink the size of the // returned run if sparing interrupted the extent on disc. // ASSERT( LocalPsn.HighPart == 0 ); if (Vcb->Pcb->SparingMcb) { LONGLONG SparingPsn; LONGLONG SparingSectorCount; if (FsRtlLookupLargeMcbEntry( Vcb->Pcb->SparingMcb, LocalPsn.LowPart, &SparingPsn, &SparingSectorCount, NULL, NULL, NULL )) { // // Only emit noise if we will really change anything as a result // of the sparing table. // if (SparingPsn != -1 || SparingSectorCount < LocalSectorCount.QuadPart) { DebugTrace(( 0, Dbg, "UdfLookupAllocation, spared [%x, +%x) onto [%x, +%x)\n", LocalPsn.LowPart, LocalSectorCount.LowPart, (ULONG) SparingPsn, (ULONG) SparingSectorCount )); } // // If we did not land in a hole, map the sector. // if (SparingPsn != -1) { LocalPsn.QuadPart = SparingPsn; } // // The returned sector count now reduces the previous sector count. // If we landed in a hole, this indicates that the trailing edge of // the extent is spared, if not this indicates that the leading // edge is spared. // if (SparingSectorCount < LocalSectorCount.QuadPart) { LocalSectorCount.QuadPart = SparingSectorCount; } } } *DiskOffset = LlBytesFromSectors( Vcb, LocalPsn.QuadPart ) + SectorOffset( Vcb, FileOffset ); // // Now we can apply method 2 fixups, which will again interrupt the size of the extent. // if (FlagOn( Vcb->VcbState, VCB_STATE_METHOD_2_FIXUP )) { LARGE_INTEGER SectorsToRunout; SectorsToRunout.QuadPart= UdfMethod2NextRunoutInSectors( Vcb, *DiskOffset ); if (SectorsToRunout.QuadPart < LocalSectorCount.QuadPart) { LocalSectorCount.QuadPart = SectorsToRunout.QuadPart; } *DiskOffset = UdfMethod2TransformByteOffset( Vcb, *DiskOffset ); } } } else { // // We know that prior to this call the system has restricted IO to points within the // the file data. Since we failed to find a mapping this is an unrecorded extent at // the end of the file, so just conjure up a proper representation. // ASSERT( FileOffset < Fcb->FileSize.QuadPart ); *DiskOffset = 0; LocalSectorCount.QuadPart = LlSectorsFromBytes( Vcb, Fcb->FileSize.QuadPart ) - LlSectorsFromBytes( Vcb, FileOffset ) + 1; Recorded = FALSE; } // // Restrict to MAXULONG bytes of allocation // if (LocalSectorCount.QuadPart > SectorsFromBytes( Vcb, MAXULONG )) { *ByteCount = MAXULONG; } else { *ByteCount = BytesFromSectors( Vcb, LocalSectorCount.LowPart ); } *ByteCount -= SectorOffset( Vcb, FileOffset ); return Recorded; }
NTSTATUS UdfDvdReadStructure ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN PFCB Fcb ) /*++ Routine Description: This routine handles the special form of the Dvd structure reading IOCTLs performed in the context of a file. For these IOCTLs, the incoming parameter is in file-relative form, which must be translated to a device-relatvie form before it can continue. Arguments: Irp - Supplies the Irp to process Fcb - Supplies the file being operated with Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status = STATUS_INVALID_PARAMETER; PDVD_READ_STRUCTURE ReadStructure; LARGE_INTEGER Offset; BOOLEAN Result; PIO_STACK_LOCATION IrpSp; // // Grab the input buffer and confirm basic validity. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); ReadStructure = (PDVD_READ_STRUCTURE) Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(DVD_READ_STRUCTURE)) { UdfCompleteRequest( IrpContext, Irp, Status ); return Status; } // // Now, convert the file byte offset in the structure to a physical sector. // Result = FsRtlLookupLargeMcbEntry( &Fcb->Mcb, LlSectorsFromBytes( Fcb->Vcb, ReadStructure->BlockByteOffset.QuadPart ), &Offset.QuadPart, NULL, NULL, NULL, NULL ); // // If we failed the lookup, we know that this must be some form of unrecorded // extent on the media. This IOCTL is ill-defined at this point, so we have // to give up. // if (!Result || Offset.QuadPart == -1) { UdfCompleteRequest( IrpContext, Irp, Status ); return Status; } // // The input is buffered from user space, so we know we can just rewrite it. // ReadStructure->BlockByteOffset.QuadPart = LlBytesFromSectors( Fcb->Vcb, Offset.QuadPart ); // // Copy the arguments and set up the completion routine // IoCopyCurrentIrpStackLocationToNext( Irp ); IoSetCompletionRoutine( Irp, UdfDevCtrlCompletionRoutine, NULL, TRUE, TRUE, TRUE ); // // Send the request. // Status = IoCallDriver( IrpContext->Vcb->TargetDeviceObject, Irp ); // // Cleanup our Irp Context. The driver has completed the Irp. // UdfCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); return Status; }