Something went wrong. Try again.
Reactos
Something went wrong. Try again.
19 kB · 634 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635////////////////////////////////////////////////////////////////////// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine// All rights reserved// This file was released under the GPLv2 on June 2015./////////////////////////////////////////////////////////////////////*************************************************************************** File: Env_Spec.cpp** Module: UDF File System Driver (Kernel mode execution only)** Description:* Contains environment-secific code to handle physical* operations: read, write and device IOCTLS**************************************************************************/
#include "udffs.h"// define the file specific bug-check id#define UDF_BUG_CHECK_ID UDF_FILE_ENV_SPEC
#define MEASURE_IO_PERFORMANCE
#ifdef MEASURE_IO_PERFORMANCELONGLONG IoReadTime=0;LONGLONG IoWriteTime=0;LONGLONG WrittenData=0;LONGLONG IoRelWriteTime=0;#endif //MEASURE_IO_PERFORMANCE
#ifdef DBGULONG UDF_SIMULATE_WRITES=0;#endif //DBG
/*
*/NTSTATUSNTAPIUDFAsyncCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Contxt ){ UDFPrint(("UDFAsyncCompletionRoutine ctx=%x\n", Contxt)); PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt; PMDL Mdl, NextMdl;
Context->IosbToUse = Irp->IoStatus;#if 1 // Unlock pages that are described by MDL (if any)... Mdl = Irp->MdlAddress; while(Mdl) { MmPrint((" Unlock MDL=%x\n", Mdl)); MmUnlockPages(Mdl); Mdl = Mdl->Next; } // ... and free MDL Mdl = Irp->MdlAddress; while(Mdl) { MmPrint((" Free MDL=%x\n", Mdl)); NextMdl = Mdl->Next; IoFreeMdl(Mdl); Mdl = NextMdl; } Irp->MdlAddress = NULL; IoFreeIrp(Irp);
KeSetEvent( &(Context->event), 0, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED;#else KeSetEvent( &(Context->event), 0, FALSE );
return STATUS_SUCCESS;#endif} // end UDFAsyncCompletionRoutine()
NTSTATUSNTAPIUDFSyncCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Contxt ){ UDFPrint(("UDFSyncCompletionRoutine ctx=%x\n", Contxt)); PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt;
Context->IosbToUse = Irp->IoStatus; //KeSetEvent( &(Context->event), 0, FALSE );
return STATUS_SUCCESS;} // end UDFSyncCompletionRoutine()
/*NTSTATUSUDFSyncCompletionRoutine2( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Contxt ){ UDFPrint(("UDFSyncCompletionRoutine2\n")); PKEVENT SyncEvent = (PKEVENT)Contxt;
KeSetEvent( SyncEvent, 0, FALSE );
return STATUS_SUCCESS;} // end UDFSyncCompletionRoutine2()*/
/*
Function: UDFPhReadSynchronous()
Description: UDFFSD will invoke this rotine to read physical device synchronously/asynchronously
Expected Interrupt Level (for execution) :
<= IRQL_DISPATCH_LEVEL
Return Value: STATUS_SUCCESS/Error
*/NTSTATUSNTAPIUDFPhReadSynchronous( PDEVICE_OBJECT DeviceObject, // the physical device object PVOID Buffer, SIZE_T Length, LONGLONG Offset, PSIZE_T ReadBytes, ULONG Flags ){ NTSTATUS RC = STATUS_SUCCESS; LARGE_INTEGER ROffset; PUDF_PH_CALL_CONTEXT Context; PIRP irp; KIRQL CurIrql = KeGetCurrentIrql(); PVOID IoBuf = NULL;// ULONG i;#ifdef MEASURE_IO_PERFORMANCE LONGLONG IoEnterTime; LONGLONG IoExitTime; ULONG dt; ULONG dtm;#endif //MEASURE_IO_PERFORMANCE#ifdef _BROWSE_UDF_ PVCB Vcb = NULL; if(Flags & PH_VCB_IN_RETLEN) { Vcb = (PVCB)(*ReadBytes); }#endif //_BROWSE_UDF_
#ifdef MEASURE_IO_PERFORMANCE KeQuerySystemTime((PLARGE_INTEGER)&IoEnterTime);#endif //MEASURE_IO_PERFORMANCE
UDFPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0xb,Offset>>0xb));// UDFPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));
ROffset.QuadPart = Offset; (*ReadBytes) = 0;/* // DEBUG !!! Flags |= PH_TMP_BUFFER;*/ if(Flags & PH_TMP_BUFFER) { IoBuf = Buffer; } else { IoBuf = DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD'); } if (!IoBuf) { UDFPrint((" !IoBuf\n")); return STATUS_INSUFFICIENT_RESOURCES; } Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); if (!Context) { UDFPrint((" !Context\n")); try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } // Create notification event object to be used to signal the request completion. KeInitializeEvent(&(Context->event), NotificationEvent, FALSE);
if (CurIrql > PASSIVE_LEVEL) { irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf, Length, &ROffset, &(Context->IosbToUse) ); if (!irp) { UDFPrint((" !irp Async\n")); try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); IoSetCompletionRoutine( irp, &UDFAsyncCompletionRoutine, Context, TRUE, TRUE, TRUE ); } else { irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf, Length, &ROffset, &(Context->event), &(Context->IosbToUse) ); if (!irp) { UDFPrint((" !irp Sync\n")); try_return(RC = STATUS_INSUFFICIENT_RESOURCES); } MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); }
(IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; RC = IoCallDriver(DeviceObject, irp);
if (RC == STATUS_PENDING) { DbgWaitForSingleObject(&(Context->event), NULL); if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { RC = STATUS_SUCCESS; }// *ReadBytes = Context->IosbToUse.Information; } else {// *ReadBytes = irp->IoStatus.Information; } if(NT_SUCCESS(RC)) { (*ReadBytes) = Context->IosbToUse.Information; } if(!(Flags & PH_TMP_BUFFER)) { RtlCopyMemory(Buffer, IoBuf, *ReadBytes); }
if(NT_SUCCESS(RC)) {/* for(i=0; i<(*ReadBytes); i+=2048) { UDFPrint(("IOCRC %8.8x R %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) )); }*/#ifdef _BROWSE_UDF_ if(Vcb) { RC = UDFVRead(Vcb, IoBuf, Length >> Vcb->BlockSizeBits, (ULONG)(Offset >> Vcb->BlockSizeBits), Flags); }#endif //_BROWSE_UDF_ }
try_exit: NOTHING;
if(Context) MyFreePool__(Context); if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf);
#ifdef MEASURE_IO_PERFORMANCE KeQuerySystemTime((PLARGE_INTEGER)&IoExitTime); IoReadTime += (IoExitTime-IoEnterTime); dt = (ULONG)((IoExitTime-IoEnterTime)/10/1000); dtm = (ULONG)(((IoExitTime-IoEnterTime)/10)%1000); PerfPrint(("\nUDFPhReadSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC, dt, dtm));#else UDFPrint(("UDFPhReadSynchronous() exit: %08X\n", RC));#endif //MEASURE_IO_PERFORMANCE
return(RC);} // end UDFPhReadSynchronous()
/*
Function: UDFPhWriteSynchronous()
Description: UDFFSD will invoke this rotine to write physical device synchronously
Expected Interrupt Level (for execution) :
<= IRQL_DISPATCH_LEVEL
Return Value: STATUS_SUCCESS/Error
*/NTSTATUSNTAPIUDFPhWriteSynchronous( PDEVICE_OBJECT DeviceObject, // the physical device object PVOID Buffer, SIZE_T Length, LONGLONG Offset, PSIZE_T WrittenBytes, ULONG Flags ){ NTSTATUS RC = STATUS_SUCCESS; LARGE_INTEGER ROffset; PUDF_PH_CALL_CONTEXT Context; PIRP irp;// LARGE_INTEGER timeout; KIRQL CurIrql = KeGetCurrentIrql(); PVOID IoBuf = NULL;// ULONG i;#ifdef MEASURE_IO_PERFORMANCE LONGLONG IoEnterTime; LONGLONG IoExitTime; ULONG dt; ULONG dtm;#endif //MEASURE_IO_PERFORMANCE#ifdef _BROWSE_UDF_ PVCB Vcb = NULL; if(Flags & PH_VCB_IN_RETLEN) { Vcb = (PVCB)(*WrittenBytes); }#endif //_BROWSE_UDF_
#ifdef MEASURE_IO_PERFORMANCE KeQuerySystemTime((PLARGE_INTEGER)&IoEnterTime);#endif //MEASURE_IO_PERFORMANCE
#ifdef USE_PERF_PRINT ULONG Lba = (ULONG)(Offset>>0xb);// ASSERT(!(Lba & (32-1))); PerfPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0xb,Lba));// UDFPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));#endif //DBG
#ifdef DBG if(UDF_SIMULATE_WRITES) {/* FIXME ReactOS If this function is to force a read from the bufffer to simulate any segfaults, then it makes sense. Else, this forloop is useless. UCHAR a; for(ULONG i=0; i<Length; i++) { a = ((PUCHAR)Buffer)[i]; }*/ *WrittenBytes = Length; return STATUS_SUCCESS; }#endif //DBG
ROffset.QuadPart = Offset; (*WrittenBytes) = 0;
/* IoBuf = ExAllocatePool(NonPagedPool, Length); if (!IoBuf) return STATUS_INSUFFICIENT_RESOURCES; RtlCopyMemory(IoBuf, Buffer, Length);*/ IoBuf = Buffer;
/* if(Flags & PH_TMP_BUFFER) { IoBuf = Buffer; } else { IoBuf = DbgAllocatePool(NonPagedPool, Length); RtlCopyMemory(IoBuf, Buffer, Length); }*/
Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); if (!Context) try_return (RC = STATUS_INSUFFICIENT_RESOURCES); // Create notification event object to be used to signal the request completion. KeInitializeEvent(&(Context->event), NotificationEvent, FALSE);
if (CurIrql > PASSIVE_LEVEL) { irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf, Length, &ROffset, &(Context->IosbToUse) ); if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); MmPrint((" Alloc async Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context)); IoSetCompletionRoutine( irp, &UDFAsyncCompletionRoutine, Context, TRUE, TRUE, TRUE ); } else { irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf, Length, &ROffset, &(Context->event), &(Context->IosbToUse) ); if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); MmPrint((" Alloc Irp MDL=%x\n, ctx=%x", irp->MdlAddress, Context)); }
(IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; RC = IoCallDriver(DeviceObject, irp);/* for(i=0; i<Length; i+=2048) { UDFPrint(("IOCRC %8.8x W %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) )); }*/#ifdef _BROWSE_UDF_ if(Vcb) { UDFVWrite(Vcb, IoBuf, Length >> Vcb->BlockSizeBits, (ULONG)(Offset >> Vcb->BlockSizeBits), Flags); }#endif //_BROWSE_UDF_
if (RC == STATUS_PENDING) { DbgWaitForSingleObject(&(Context->event), NULL); if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { RC = STATUS_SUCCESS; }// *WrittenBytes = Context->IosbToUse.Information; } else {// *WrittenBytes = irp->IoStatus.Information; } if(NT_SUCCESS(RC)) { (*WrittenBytes) = Context->IosbToUse.Information; }
try_exit: NOTHING;
if(Context) MyFreePool__(Context);// if(IoBuf) ExFreePool(IoBuf);// if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf); if(!NT_SUCCESS(RC)) { UDFPrint(("WriteError\n")); }
#ifdef MEASURE_IO_PERFORMANCE KeQuerySystemTime((PLARGE_INTEGER)&IoExitTime); IoWriteTime += (IoExitTime-IoEnterTime); if (WrittenData > 1024*1024*8) { PerfPrint(("\nUDFPhWriteSynchronous() Relative size=%I64d, time=%I64d.\n", WrittenData, IoRelWriteTime)); WrittenData = IoRelWriteTime = 0; } WrittenData += Length; IoRelWriteTime += (IoExitTime-IoEnterTime); dt = (ULONG)((IoExitTime-IoEnterTime)/10/1000); dtm = (ULONG)(((IoExitTime-IoEnterTime)/10)%1000); PerfPrint(("\nUDFPhWriteSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC, dt, dtm));#else UDFPrint(("nUDFPhWriteSynchronous() exit: %08X\n", RC));#endif //MEASURE_IO_PERFORMANCE
return(RC);} // end UDFPhWriteSynchronous()
#if 0NTSTATUSUDFPhWriteVerifySynchronous( PDEVICE_OBJECT DeviceObject, // the physical device object PVOID Buffer, SIZE_T Length, LONGLONG Offset, PSIZE_T WrittenBytes, ULONG Flags ){ NTSTATUS RC; //PUCHAR v_buff = NULL; //ULONG ReadBytes;
RC = UDFPhWriteSynchronous(DeviceObject, Buffer, Length, Offset, WrittenBytes, Flags);/* if(!Verify) return RC; v_buff = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD'); if(!v_buff) return RC; RC = UDFPhReadSynchronous(DeviceObject, v_buff, Length, Offset, &ReadBytes, Flags); if(!NT_SUCCESS(RC)) { BrutePoint(); DbgFreePool(v_buff); return RC; } if(RtlCompareMemory(v_buff, Buffer, ReadBytes) == Length) { DbgFreePool(v_buff); return RC; } BrutePoint(); DbgFreePool(v_buff); return STATUS_LOST_WRITEBEHIND_DATA;*/ return RC;} // end UDFPhWriteVerifySynchronous()#endif //0
NTSTATUSNTAPIUDFTSendIOCTL( IN ULONG IoControlCode, IN PVCB Vcb, IN PVOID InputBuffer , IN ULONG InputBufferLength, OUT PVOID OutputBuffer , IN ULONG OutputBufferLength, IN BOOLEAN OverrideVerify, OUT PIO_STATUS_BLOCK Iosb OPTIONAL ){ NTSTATUS RC = STATUS_SUCCESS; BOOLEAN Acquired;
Acquired = UDFAcquireResourceExclusiveWithCheck(&(Vcb->IoResource));
_SEH2_TRY {
RC = UDFPhSendIOCTL(IoControlCode, Vcb->TargetDeviceObject, InputBuffer , InputBufferLength, OutputBuffer , OutputBufferLength, OverrideVerify, Iosb );
} _SEH2_FINALLY { if(Acquired) UDFReleaseResource(&(Vcb->IoResource)); } _SEH2_END;
return RC;} // end UDFTSendIOCTL()
/*
Function: UDFPhSendIOCTL()
Description: UDF FSD will invoke this rotine to send IOCTL's to physical device
Return Value: STATUS_SUCCESS/Error
*/NTSTATUSNTAPIUDFPhSendIOCTL( IN ULONG IoControlCode, IN PDEVICE_OBJECT DeviceObject, IN PVOID InputBuffer , IN ULONG InputBufferLength, OUT PVOID OutputBuffer , IN ULONG OutputBufferLength, IN BOOLEAN OverrideVerify, OUT PIO_STATUS_BLOCK Iosb OPTIONAL ){ NTSTATUS RC = STATUS_SUCCESS; PIRP irp; PUDF_PH_CALL_CONTEXT Context; LARGE_INTEGER timeout;
UDFPrint(("UDFPhDevIOCTL: Code %8x \n",IoControlCode));
Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) ); if (!Context) return STATUS_INSUFFICIENT_RESOURCES; // Check if the user gave us an Iosb.
// Create notification event object to be used to signal the request completion. KeInitializeEvent(&(Context->event), NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer , InputBufferLength, OutputBuffer, OutputBufferLength,FALSE,&(Context->event),&(Context->IosbToUse));
if (!irp) try_return (RC = STATUS_INSUFFICIENT_RESOURCES); MmPrint((" Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context));/* if (KeGetCurrentIrql() > PASSIVE_LEVEL) { UDFPrint(("Setting completion routine\n")); IoSetCompletionRoutine( irp, &UDFSyncCompletionRoutine, Context, TRUE, TRUE, TRUE ); }*/ if(OverrideVerify) { (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME; }
RC = IoCallDriver(DeviceObject, irp);
if (RC == STATUS_PENDING) { ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); UDFPrint(("Enter wait state on evt %x\n", Context));
if (KeGetCurrentIrql() > PASSIVE_LEVEL) { timeout.QuadPart = -1000; UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); RC = DbgWaitForSingleObject(&(Context->event), &timeout); while(RC == STATUS_TIMEOUT) { timeout.QuadPart *= 2; UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart)); RC = DbgWaitForSingleObject(&(Context->event), &timeout); }
} else { DbgWaitForSingleObject(&(Context->event), NULL); } if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) { RC = STATUS_SUCCESS; } UDFPrint(("Exit wait state on evt %x, status %8.8x\n", Context, RC));/* if(Iosb) { (*Iosb) = Context->IosbToUse; }*/ } else { UDFPrint(("No wait completion on evt %x\n", Context));/* if(Iosb) { (*Iosb) = irp->IoStatus; }*/ }
if(Iosb) { (*Iosb) = Context->IosbToUse; }
try_exit: NOTHING;
if(Context) MyFreePool__(Context); return(RC);} // end UDFPhSendIOCTL()
#ifdef UDF_DBGVOIDUDFNotifyFullReportChange( PVCB V, PUDF_FILE_INFO FI, ULONG E, ULONG A ){ if((FI)->ParentFile) { FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP), (PSTRING)&((FI)->Fcb->FCBName->ObjectName), ((FI)->ParentFile->Fcb->FCBName->ObjectName.Length + sizeof(WCHAR)), NULL,NULL, E, A, NULL); } else { FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP), (PSTRING)&((FI)->Fcb->FCBName->ObjectName), 0, NULL,NULL, E, A, NULL); }} // end UDFNotifyFullReportChange()
VOIDUDFNotifyVolumeEvent( IN PFILE_OBJECT FileObject, IN ULONG EventCode ){/* ReactOS FIXME This is always true, and we return anyway. */// if(!FsRtlNotifyVolumeEvent) return; //FsRtlNotifyVolumeEvent(FileObject, EventCode);} // end UDFNotifyVolumeEvent()#endif // UDF_DBG