1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: Env_Spec.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 *   Contains environment-secific code to handle physical
14 *   operations: read, write and device IOCTLS
15 *
16 *************************************************************************/
17 
18 #include "udffs.h"
19 // define the file specific bug-check id
20 #define         UDF_BUG_CHECK_ID        UDF_FILE_ENV_SPEC
21 
22 #define MEASURE_IO_PERFORMANCE
23 
24 #ifdef MEASURE_IO_PERFORMANCE
25 LONGLONG IoReadTime=0;
26 LONGLONG IoWriteTime=0;
27 LONGLONG WrittenData=0;
28 LONGLONG IoRelWriteTime=0;
29 #endif //MEASURE_IO_PERFORMANCE
30 
31 #ifdef DBG
32 ULONG UDF_SIMULATE_WRITES=0;
33 #endif //DBG
34 
35 /*
36 
37  */
38 NTSTATUS
39 NTAPI
40 UDFAsyncCompletionRoutine(
41     IN PDEVICE_OBJECT DeviceObject,
42     IN PIRP Irp,
43     IN PVOID Contxt
44     )
45 {
46     UDFPrint(("UDFAsyncCompletionRoutine ctx=%x\n", Contxt));
47     PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt;
48     PMDL Mdl, NextMdl;
49 
50     Context->IosbToUse = Irp->IoStatus;
51 #if 1
52     // Unlock pages that are described by MDL (if any)...
53     Mdl = Irp->MdlAddress;
54     while(Mdl) {
55         MmPrint(("    Unlock MDL=%x\n", Mdl));
56         MmUnlockPages(Mdl);
57         Mdl = Mdl->Next;
58     }
59     // ... and free MDL
60     Mdl = Irp->MdlAddress;
61     while(Mdl) {
62         MmPrint(("    Free MDL=%x\n", Mdl));
63         NextMdl = Mdl->Next;
64         IoFreeMdl(Mdl);
65         Mdl = NextMdl;
66     }
67     Irp->MdlAddress = NULL;
68     IoFreeIrp(Irp);
69 
70     KeSetEvent( &(Context->event), 0, FALSE );
71 
72     return STATUS_MORE_PROCESSING_REQUIRED;
73 #else
74     KeSetEvent( &(Context->event), 0, FALSE );
75 
76     return STATUS_SUCCESS;
77 #endif
78 } // end UDFAsyncCompletionRoutine()
79 
80 NTSTATUS
81 NTAPI
82 UDFSyncCompletionRoutine(
83     IN PDEVICE_OBJECT DeviceObject,
84     IN PIRP Irp,
85     IN PVOID Contxt
86     )
87 {
88     UDFPrint(("UDFSyncCompletionRoutine ctx=%x\n", Contxt));
89     PUDF_PH_CALL_CONTEXT Context = (PUDF_PH_CALL_CONTEXT)Contxt;
90 
91     Context->IosbToUse = Irp->IoStatus;
92     //KeSetEvent( &(Context->event), 0, FALSE );
93 
94     return STATUS_SUCCESS;
95 } // end UDFSyncCompletionRoutine()
96 
97 /*
98 NTSTATUS
99 UDFSyncCompletionRoutine2(
100     IN PDEVICE_OBJECT DeviceObject,
101     IN PIRP Irp,
102     IN PVOID Contxt
103     )
104 {
105     UDFPrint(("UDFSyncCompletionRoutine2\n"));
106     PKEVENT SyncEvent = (PKEVENT)Contxt;
107 
108     KeSetEvent( SyncEvent, 0, FALSE );
109 
110     return STATUS_SUCCESS;
111 } // end UDFSyncCompletionRoutine2()
112 */
113 
114 /*
115 
116  Function: UDFPhReadSynchronous()
117 
118  Description:
119     UDFFSD will invoke this rotine to read physical device synchronously/asynchronously
120 
121  Expected Interrupt Level (for execution) :
122 
123   <= IRQL_DISPATCH_LEVEL
124 
125  Return Value: STATUS_SUCCESS/Error
126 
127 */
128 NTSTATUS
129 NTAPI
130 UDFPhReadSynchronous(
131     PDEVICE_OBJECT      DeviceObject,   // the physical device object
132     PVOID               Buffer,
133     ULONG               Length,
134     LONGLONG            Offset,
135     PULONG              ReadBytes,
136     ULONG               Flags
137     )
138 {
139     NTSTATUS            RC = STATUS_SUCCESS;
140     LARGE_INTEGER       ROffset;
141     PUDF_PH_CALL_CONTEXT Context;
142     PIRP                irp;
143     KIRQL               CurIrql = KeGetCurrentIrql();
144     PVOID               IoBuf = NULL;
145 //    ULONG i;
146 #ifdef MEASURE_IO_PERFORMANCE
147     LONGLONG IoEnterTime;
148     LONGLONG IoExitTime;
149     ULONG dt;
150     ULONG dtm;
151 #endif //MEASURE_IO_PERFORMANCE
152 #ifdef _BROWSE_UDF_
153     PVCB Vcb = NULL;
154     if(Flags & PH_VCB_IN_RETLEN) {
155         Vcb = (PVCB)(*ReadBytes);
156     }
157 #endif //_BROWSE_UDF_
158 
159 #ifdef MEASURE_IO_PERFORMANCE
160     KeQuerySystemTime((PLARGE_INTEGER)&IoEnterTime);
161 #endif //MEASURE_IO_PERFORMANCE
162 
163     UDFPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0xb,Offset>>0xb));
164 //    UDFPrint(("UDFPhRead: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));
165 
166     ROffset.QuadPart = Offset;
167     (*ReadBytes) = 0;
168 /*
169     // DEBUG !!!
170     Flags |= PH_TMP_BUFFER;
171 */
172     if(Flags & PH_TMP_BUFFER) {
173         IoBuf = Buffer;
174     } else {
175         IoBuf = DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD');
176     }
177     if (!IoBuf) {
178         UDFPrint(("    !IoBuf\n"));
179         return STATUS_INSUFFICIENT_RESOURCES;
180     }
181     Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) );
182     if (!Context) {
183         UDFPrint(("    !Context\n"));
184         try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
185     }
186     // Create notification event object to be used to signal the request completion.
187     KeInitializeEvent(&(Context->event), NotificationEvent, FALSE);
188 
189     if (CurIrql > PASSIVE_LEVEL) {
190         irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf,
191                                                Length, &ROffset, &(Context->IosbToUse) );
192         if (!irp) {
193             UDFPrint(("    !irp Async\n"));
194             try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
195         }
196         MmPrint(("    Alloc async Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context));
197         IoSetCompletionRoutine( irp, &UDFAsyncCompletionRoutine,
198                                 Context, TRUE, TRUE, TRUE );
199     } else {
200         irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, IoBuf,
201                                                Length, &ROffset, &(Context->event), &(Context->IosbToUse) );
202         if (!irp) {
203             UDFPrint(("    !irp Sync\n"));
204             try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
205         }
206         MmPrint(("    Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context));
207     }
208 
209     (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
210     RC = IoCallDriver(DeviceObject, irp);
211 
212     if (RC == STATUS_PENDING) {
213         DbgWaitForSingleObject(&(Context->event), NULL);
214         if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) {
215             RC = STATUS_SUCCESS;
216         }
217 //        *ReadBytes = Context->IosbToUse.Information;
218     } else {
219 //        *ReadBytes = irp->IoStatus.Information;
220     }
221     if(NT_SUCCESS(RC)) {
222         (*ReadBytes) = Context->IosbToUse.Information;
223     }
224     if(!(Flags & PH_TMP_BUFFER)) {
225         RtlCopyMemory(Buffer, IoBuf, *ReadBytes);
226     }
227 
228     if(NT_SUCCESS(RC)) {
229 /*
230         for(i=0; i<(*ReadBytes); i+=2048) {
231             UDFPrint(("IOCRC %8.8x R %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) ));
232         }
233 */
234 #ifdef _BROWSE_UDF_
235         if(Vcb) {
236             RC = UDFVRead(Vcb, IoBuf, Length >> Vcb->BlockSizeBits, (ULONG)(Offset >> Vcb->BlockSizeBits), Flags);
237         }
238 #endif //_BROWSE_UDF_
239     }
240 
241 try_exit: NOTHING;
242 
243     if(Context) MyFreePool__(Context);
244     if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf);
245 
246 #ifdef MEASURE_IO_PERFORMANCE
247     KeQuerySystemTime((PLARGE_INTEGER)&IoExitTime);
248     IoReadTime += (IoExitTime-IoEnterTime);
249     dt = (ULONG)((IoExitTime-IoEnterTime)/10/1000);
250     dtm = (ULONG)(((IoExitTime-IoEnterTime)/10)%1000);
251     PerfPrint(("\nUDFPhReadSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC, dt, dtm));
252 #else
253     UDFPrint(("UDFPhReadSynchronous() exit: %08X\n", RC));
254 #endif //MEASURE_IO_PERFORMANCE
255 
256     return(RC);
257 } // end UDFPhReadSynchronous()
258 
259 
260 /*
261 
262  Function: UDFPhWriteSynchronous()
263 
264  Description:
265     UDFFSD will invoke this rotine to write physical device synchronously
266 
267  Expected Interrupt Level (for execution) :
268 
269   <= IRQL_DISPATCH_LEVEL
270 
271  Return Value: STATUS_SUCCESS/Error
272 
273 */
274 NTSTATUS
275 NTAPI
276 UDFPhWriteSynchronous(
277     PDEVICE_OBJECT  DeviceObject,   // the physical device object
278     PVOID           Buffer,
279     ULONG           Length,
280     LONGLONG        Offset,
281     PULONG          WrittenBytes,
282     ULONG           Flags
283     )
284 {
285     NTSTATUS            RC = STATUS_SUCCESS;
286     LARGE_INTEGER       ROffset;
287     PUDF_PH_CALL_CONTEXT Context;
288     PIRP                irp;
289 //    LARGE_INTEGER       timeout;
290     KIRQL               CurIrql = KeGetCurrentIrql();
291     PVOID               IoBuf = NULL;
292 //    ULONG i;
293 #ifdef MEASURE_IO_PERFORMANCE
294     LONGLONG IoEnterTime;
295     LONGLONG IoExitTime;
296     ULONG dt;
297     ULONG dtm;
298 #endif //MEASURE_IO_PERFORMANCE
299 #ifdef _BROWSE_UDF_
300     PVCB Vcb = NULL;
301     if(Flags & PH_VCB_IN_RETLEN) {
302         Vcb = (PVCB)(*WrittenBytes);
303     }
304 #endif //_BROWSE_UDF_
305 
306 #ifdef MEASURE_IO_PERFORMANCE
307     KeQuerySystemTime((PLARGE_INTEGER)&IoEnterTime);
308 #endif //MEASURE_IO_PERFORMANCE
309 
310 #if defined UDF_DBG || defined USE_PERF_PRINT
311     ULONG Lba = (ULONG)(Offset>>0xb);
312 //    ASSERT(!(Lba & (32-1)));
313     PerfPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0xb,Lba));
314 //    UDFPrint(("UDFPhWrite: Length: %x Lba: %lx\n",Length>>0x9,Offset>>0x9));
315 #endif //DBG
316 
317 #ifdef DBG
318     if(UDF_SIMULATE_WRITES) {
319 /* FIXME ReactOS
320    If this function is to force a read from the bufffer to simulate any segfaults, then it makes sense.
321    Else, this forloop is useless.
322         UCHAR a;
323         for(ULONG i=0; i<Length; i++) {
324             a = ((PUCHAR)Buffer)[i];
325         }
326 */
327         *WrittenBytes = Length;
328         return STATUS_SUCCESS;
329     }
330 #endif //DBG
331 
332     ROffset.QuadPart = Offset;
333     (*WrittenBytes) = 0;
334 
335 /*    IoBuf = ExAllocatePool(NonPagedPool, Length);
336     if (!IoBuf) return STATUS_INSUFFICIENT_RESOURCES;
337     RtlCopyMemory(IoBuf, Buffer, Length);*/
338     IoBuf = Buffer;
339 
340 /*    if(Flags & PH_TMP_BUFFER) {
341         IoBuf = Buffer;
342     } else {
343         IoBuf = DbgAllocatePool(NonPagedPool, Length);
344         RtlCopyMemory(IoBuf, Buffer, Length);
345     }*/
346 
347     Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) );
348     if (!Context) try_return (RC = STATUS_INSUFFICIENT_RESOURCES);
349     // Create notification event object to be used to signal the request completion.
350     KeInitializeEvent(&(Context->event), NotificationEvent, FALSE);
351 
352     if (CurIrql > PASSIVE_LEVEL) {
353         irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf,
354                                                Length, &ROffset, &(Context->IosbToUse) );
355         if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
356         MmPrint(("    Alloc async Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context));
357         IoSetCompletionRoutine( irp, &UDFAsyncCompletionRoutine,
358                                 Context, TRUE, TRUE, TRUE );
359     } else {
360         irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE, DeviceObject, IoBuf,
361                                                Length, &ROffset, &(Context->event), &(Context->IosbToUse) );
362         if (!irp) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
363         MmPrint(("    Alloc Irp MDL=%x\n, ctx=%x", irp->MdlAddress, Context));
364     }
365 
366     (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
367     RC = IoCallDriver(DeviceObject, irp);
368 /*
369     for(i=0; i<Length; i+=2048) {
370         UDFPrint(("IOCRC %8.8x W %x\n", crc32((PUCHAR)Buffer+i, 2048), (ULONG)((Offset+i)/2048) ));
371     }
372 */
373 #ifdef _BROWSE_UDF_
374     if(Vcb) {
375         UDFVWrite(Vcb, IoBuf, Length >> Vcb->BlockSizeBits, (ULONG)(Offset >> Vcb->BlockSizeBits), Flags);
376     }
377 #endif //_BROWSE_UDF_
378 
379     if (RC == STATUS_PENDING) {
380         DbgWaitForSingleObject(&(Context->event), NULL);
381         if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) {
382             RC = STATUS_SUCCESS;
383         }
384 //        *WrittenBytes = Context->IosbToUse.Information;
385     } else {
386 //        *WrittenBytes = irp->IoStatus.Information;
387     }
388     if(NT_SUCCESS(RC)) {
389         (*WrittenBytes) = Context->IosbToUse.Information;
390     }
391 
392 try_exit: NOTHING;
393 
394     if(Context) MyFreePool__(Context);
395 //    if(IoBuf) ExFreePool(IoBuf);
396 //    if(IoBuf && !(Flags & PH_TMP_BUFFER)) DbgFreePool(IoBuf);
397     if(!NT_SUCCESS(RC)) {
398         UDFPrint(("WriteError\n"));
399     }
400 
401 #ifdef MEASURE_IO_PERFORMANCE
402     KeQuerySystemTime((PLARGE_INTEGER)&IoExitTime);
403     IoWriteTime += (IoExitTime-IoEnterTime);
404     if (WrittenData > 1024*1024*8) {
405         PerfPrint(("\nUDFPhWriteSynchronous() Relative size=%I64d, time=%I64d.\n", WrittenData, IoRelWriteTime));
406         WrittenData = IoRelWriteTime = 0;
407     }
408     WrittenData += Length;
409     IoRelWriteTime += (IoExitTime-IoEnterTime);
410     dt = (ULONG)((IoExitTime-IoEnterTime)/10/1000);
411     dtm = (ULONG)(((IoExitTime-IoEnterTime)/10)%1000);
412     PerfPrint(("\nUDFPhWriteSynchronous() exit: %08X, after %d.%4.4d msec.\n", RC, dt, dtm));
413 #else
414     UDFPrint(("nUDFPhWriteSynchronous() exit: %08X\n", RC));
415 #endif //MEASURE_IO_PERFORMANCE
416 
417     return(RC);
418 } // end UDFPhWriteSynchronous()
419 
420 #if 0
421 NTSTATUS
422 UDFPhWriteVerifySynchronous(
423     PDEVICE_OBJECT  DeviceObject,   // the physical device object
424     PVOID           Buffer,
425     ULONG           Length,
426     LONGLONG        Offset,
427     PULONG          WrittenBytes,
428     ULONG           Flags
429     )
430 {
431     NTSTATUS RC;
432     //PUCHAR v_buff = NULL;
433     //ULONG ReadBytes;
434 
435     RC = UDFPhWriteSynchronous(DeviceObject, Buffer, Length, Offset, WrittenBytes, Flags);
436 /*
437     if(!Verify)
438         return RC;
439     v_buff = (PUCHAR)DbgAllocatePoolWithTag(NonPagedPool, Length, 'bNWD');
440     if(!v_buff)
441         return RC;
442     RC = UDFPhReadSynchronous(DeviceObject, v_buff, Length, Offset, &ReadBytes, Flags);
443     if(!NT_SUCCESS(RC)) {
444         BrutePoint();
445         DbgFreePool(v_buff);
446         return RC;
447     }
448     if(RtlCompareMemory(v_buff, Buffer, ReadBytes) == Length) {
449         DbgFreePool(v_buff);
450         return RC;
451     }
452     BrutePoint();
453     DbgFreePool(v_buff);
454     return STATUS_LOST_WRITEBEHIND_DATA;
455 */
456     return RC;
457 } // end UDFPhWriteVerifySynchronous()
458 #endif //0
459 
460 NTSTATUS
461 NTAPI
462 UDFTSendIOCTL(
463     IN ULONG IoControlCode,
464     IN PVCB Vcb,
465     IN PVOID InputBuffer ,
466     IN ULONG InputBufferLength,
467     OUT PVOID OutputBuffer ,
468     IN ULONG OutputBufferLength,
469     IN BOOLEAN OverrideVerify,
470     OUT PIO_STATUS_BLOCK Iosb OPTIONAL
471     )
472 {
473     NTSTATUS            RC = STATUS_SUCCESS;
474     BOOLEAN Acquired;
475 
476     Acquired = UDFAcquireResourceExclusiveWithCheck(&(Vcb->IoResource));
477 
478     _SEH2_TRY {
479 
480         RC = UDFPhSendIOCTL(IoControlCode,
481                             Vcb->TargetDeviceObject,
482                             InputBuffer ,
483                             InputBufferLength,
484                             OutputBuffer ,
485                             OutputBufferLength,
486                             OverrideVerify,
487                             Iosb
488                             );
489 
490     } _SEH2_FINALLY {
491         if(Acquired)
492             UDFReleaseResource(&(Vcb->IoResource));
493     } _SEH2_END;
494 
495     return RC;
496 } // end UDFTSendIOCTL()
497 
498 /*
499 
500  Function: UDFPhSendIOCTL()
501 
502  Description:
503     UDF FSD will invoke this rotine to send IOCTL's to physical
504     device
505 
506  Return Value: STATUS_SUCCESS/Error
507 
508 */
509 NTSTATUS
510 NTAPI
511 UDFPhSendIOCTL(
512     IN ULONG IoControlCode,
513     IN PDEVICE_OBJECT DeviceObject,
514     IN PVOID InputBuffer ,
515     IN ULONG InputBufferLength,
516     OUT PVOID OutputBuffer ,
517     IN ULONG OutputBufferLength,
518     IN BOOLEAN OverrideVerify,
519     OUT PIO_STATUS_BLOCK Iosb OPTIONAL
520     )
521 {
522     NTSTATUS            RC = STATUS_SUCCESS;
523     PIRP                irp;
524     PUDF_PH_CALL_CONTEXT Context;
525     LARGE_INTEGER timeout;
526 
527     UDFPrint(("UDFPhDevIOCTL: Code %8x  \n",IoControlCode));
528 
529     Context = (PUDF_PH_CALL_CONTEXT)MyAllocatePool__( NonPagedPool, sizeof(UDF_PH_CALL_CONTEXT) );
530     if (!Context) return STATUS_INSUFFICIENT_RESOURCES;
531     //  Check if the user gave us an Iosb.
532 
533     // Create notification event object to be used to signal the request completion.
534     KeInitializeEvent(&(Context->event), NotificationEvent, FALSE);
535 
536     irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer ,
537         InputBufferLength, OutputBuffer, OutputBufferLength,FALSE,&(Context->event),&(Context->IosbToUse));
538 
539     if (!irp) try_return (RC = STATUS_INSUFFICIENT_RESOURCES);
540     MmPrint(("    Alloc Irp MDL=%x, ctx=%x\n", irp->MdlAddress, Context));
541 /*
542     if (KeGetCurrentIrql() > PASSIVE_LEVEL) {
543         UDFPrint(("Setting completion routine\n"));
544         IoSetCompletionRoutine( irp, &UDFSyncCompletionRoutine,
545                                 Context, TRUE, TRUE, TRUE );
546     }
547 */
548     if(OverrideVerify) {
549         (IoGetNextIrpStackLocation(irp))->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
550     }
551 
552     RC = IoCallDriver(DeviceObject, irp);
553 
554     if (RC == STATUS_PENDING) {
555         ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
556         UDFPrint(("Enter wait state on evt %x\n", Context));
557 
558         if (KeGetCurrentIrql() > PASSIVE_LEVEL) {
559             timeout.QuadPart = -1000;
560             UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart));
561             RC = DbgWaitForSingleObject(&(Context->event), &timeout);
562             while(RC == STATUS_TIMEOUT) {
563                 timeout.QuadPart *= 2;
564                 UDFPrint(("waiting, TO=%I64d\n", timeout.QuadPart));
565                 RC = DbgWaitForSingleObject(&(Context->event), &timeout);
566             }
567 
568         } else {
569             DbgWaitForSingleObject(&(Context->event), NULL);
570         }
571         if ((RC = Context->IosbToUse.Status) == STATUS_DATA_OVERRUN) {
572             RC = STATUS_SUCCESS;
573         }
574         UDFPrint(("Exit wait state on evt %x, status %8.8x\n", Context, RC));
575 /*        if(Iosb) {
576             (*Iosb) = Context->IosbToUse;
577         }*/
578     } else {
579         UDFPrint(("No wait completion on evt %x\n", Context));
580 /*        if(Iosb) {
581             (*Iosb) = irp->IoStatus;
582         }*/
583     }
584 
585     if(Iosb) {
586         (*Iosb) = Context->IosbToUse;
587     }
588 
589 try_exit: NOTHING;
590 
591     if(Context) MyFreePool__(Context);
592     return(RC);
593 } // end UDFPhSendIOCTL()
594 
595 
596 #ifdef UDF_DBG
597 VOID
598 UDFNotifyFullReportChange(
599     PVCB V,
600     PUDF_FILE_INFO FI,
601     ULONG E,
602     ULONG A
603     )
604 {
605     if((FI)->ParentFile) {
606         FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP),
607                                      (PSTRING)&((FI)->Fcb->FCBName->ObjectName),
608                                      ((FI)->ParentFile->Fcb->FCBName->ObjectName.Length + sizeof(WCHAR)),
609                                      NULL,NULL,
610                                      E, A,
611                                      NULL);
612     } else {
613         FsRtlNotifyFullReportChange( (V)->NotifyIRPMutex, &((V)->NextNotifyIRP),
614                                      (PSTRING)&((FI)->Fcb->FCBName->ObjectName),
615                                      0,
616                                      NULL,NULL,
617                                      E, A,
618                                      NULL);
619     }
620 } // end UDFNotifyFullReportChange()
621 
622 VOID
623 UDFNotifyVolumeEvent(
624     IN PFILE_OBJECT FileObject,
625     IN ULONG EventCode
626     )
627 {
628 /* ReactOS FIXME This is always true, and we return anyway. */
629 //    if(!FsRtlNotifyVolumeEvent)
630         return;
631     //FsRtlNotifyVolumeEvent(FileObject, EventCode);
632 } // end UDFNotifyVolumeEvent()
633 #endif // UDF_DBG
634 
635