1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     DevCtrl.c
8 
9 Abstract:
10 
11     This module implements the File System Device Control routines for Fat
12     called by the dispatch driver.
13 
14 
15 --*/
16 
17 #include "fatprocs.h"
18 
19 //
20 //  The local debug trace level
21 //
22 
23 #define Dbg                              (DEBUG_TRACE_DEVCTRL)
24 
25 //
26 //  Local procedure prototypes
27 //
28 
29 //
30 //  Tell prefast this is an IO_COMPLETION_ROUTINE
31 //
32 IO_COMPLETION_ROUTINE FatDeviceControlCompletionRoutine;
33 
34 NTSTATUS
35 NTAPI
36 FatDeviceControlCompletionRoutine(
37     IN PDEVICE_OBJECT DeviceObject,
38     IN PIRP Irp,
39     IN PVOID Contxt
40     );
41 
42 #ifdef ALLOC_PRAGMA
43 #pragma alloc_text(PAGE, FatCommonDeviceControl)
44 #pragma alloc_text(PAGE, FatFsdDeviceControl)
45 #endif
46 
47 
48 _Function_class_(IRP_MJ_DEVICE_CONTROL)
49 _Function_class_(DRIVER_DISPATCH)
50 NTSTATUS
51 NTAPI
52 FatFsdDeviceControl (
53     _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
54     _Inout_ PIRP Irp
55     )
56 
57 /*++
58 
59 Routine Description:
60 
61     This routine implements the FSD part of Device control operations
62 
63 Arguments:
64 
65     VolumeDeviceObject - Supplies the volume device object where the
66         file exists
67 
68     Irp - Supplies the Irp being processed
69 
70 Return Value:
71 
72     NTSTATUS - The FSD status for the IRP
73 
74 --*/
75 
76 {
77     NTSTATUS Status;
78     PIRP_CONTEXT IrpContext = NULL;
79 
80     BOOLEAN TopLevel;
81 
82     PAGED_CODE();
83 
84     DebugTrace(+1, Dbg, "FatFsdDeviceControl\n", 0);
85 
86     FsRtlEnterFileSystem();
87 
88     TopLevel = FatIsIrpTopLevel( Irp );
89 
90     _SEH2_TRY {
91 
92         IrpContext = FatCreateIrpContext( Irp, CanFsdWait( Irp ));
93 
94         Status = FatCommonDeviceControl( IrpContext, Irp );
95 
96     } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) {
97 
98         //
99         //  We had some trouble trying to perform the requested
100         //  operation, so we'll abort the I/O request with
101         //  the error status that we get back from the
102         //  exception code
103         //
104 
105         Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() );
106     } _SEH2_END;
107 
108     if (TopLevel) { IoSetTopLevelIrp( NULL ); }
109 
110     FsRtlExitFileSystem();
111 
112     //
113     //  And return to our caller
114     //
115 
116     DebugTrace(-1, Dbg, "FatFsdDeviceControl -> %08lx\n", Status);
117 
118     UNREFERENCED_PARAMETER( VolumeDeviceObject );
119 
120     return Status;
121 }
122 
123 
124 _Requires_lock_held_(_Global_critical_region_)
125 NTSTATUS
126 FatCommonDeviceControl (
127     IN PIRP_CONTEXT IrpContext,
128     IN PIRP Irp
129     )
130 
131 /*++
132 
133 Routine Description:
134 
135     This is the common routine for doing Device control operations called
136     by both the fsd and fsp threads
137 
138 Arguments:
139 
140     Irp - Supplies the Irp to process
141 
142     InFsp - Indicates if this is the fsp thread or someother thread
143 
144 Return Value:
145 
146     NTSTATUS - The return status for the operation
147 
148 --*/
149 
150 {
151     NTSTATUS Status;
152     PIO_STACK_LOCATION IrpSp;
153     KEVENT WaitEvent;
154     PVOID CompletionContext = NULL;
155 
156     PVCB Vcb;
157     PFCB Fcb;
158     PCCB Ccb;
159 
160     PAGED_CODE();
161 
162     //
163     //  Get a pointer to the current Irp stack location
164     //
165 
166     IrpSp = IoGetCurrentIrpStackLocation( Irp );
167 
168     DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0);
169     DebugTrace( 0, Dbg, "Irp           = %p\n", Irp);
170     DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);
171 
172     //
173     //  Decode the file object, the only type of opens we accept are
174     //  user volume opens.
175     //
176 
177     if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) {
178 
179         FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
180 
181         DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER);
182         return STATUS_INVALID_PARAMETER;
183     }
184 
185     //
186     //  A few IOCTLs actually require some intervention on our part
187     //
188 
189     switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
190 
191     case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:
192 
193         //
194         //  This is sent by the Volume Snapshot driver (Lovelace).
195         //  We flush the volume, and hold all file resources
196         //  to make sure that nothing more gets dirty. Then we wait
197         //  for the IRP to complete or cancel.
198         //
199 
200         SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
201         FatAcquireExclusiveVolume( IrpContext, Vcb );
202 
203         FatFlushAndCleanVolume( IrpContext,
204                                 Irp,
205                                 Vcb,
206                                 FlushWithoutPurge );
207 
208         KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE );
209         CompletionContext = &WaitEvent;
210 
211         //
212         //  Get the next stack location, and copy over the stack location
213         //
214 
215         IoCopyCurrentIrpStackLocationToNext( Irp );
216 
217         //
218         //  Set up the completion routine
219         //
220 
221         IoSetCompletionRoutine( Irp,
222                                 FatDeviceControlCompletionRoutine,
223                                 CompletionContext,
224                                 TRUE,
225                                 TRUE,
226                                 TRUE );
227         break;
228 
229     case IOCTL_DISK_COPY_DATA:
230 
231         //
232         //  We cannot allow this IOCTL to be sent unless the volume is locked,
233         //  since this IOCTL allows direct writing of data to the volume.
234         //  We do allow kernel callers to force access via a flag.  A handle that
235         //  issued a dismount can send this IOCTL as well.
236         //
237 
238         if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) &&
239             !FlagOn( IrpSp->Flags, SL_FORCE_DIRECT_WRITE ) &&
240             !FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) {
241 
242             FatCompleteRequest( IrpContext,
243                                 Irp,
244                                 STATUS_ACCESS_DENIED );
245 
246             DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_ACCESS_DENIED);
247             return STATUS_ACCESS_DENIED;
248         }
249 
250         break;
251 
252     case IOCTL_SCSI_PASS_THROUGH:
253     case IOCTL_SCSI_PASS_THROUGH_DIRECT:
254     case IOCTL_SCSI_PASS_THROUGH_EX:
255     case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX:
256 
257         //
258         //  If someone is issuing a format unit command underneath us, then make
259         //  sure we mark the device as needing verification when they close their
260         //  handle.
261         //
262 
263         if ((!FlagOn( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ) ||
264              !FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) &&
265              (Irp->AssociatedIrp.SystemBuffer != NULL)) {
266 
267             PCDB  Cdb = NULL;
268 
269             //
270             //  If this is a 32 bit application running on 64 bit then thunk the
271             //  input structures to grab the Cdb.
272             //
273 
274 #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED)
275             if (IoIs32bitProcess(Irp)) {
276 
277                 if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) ||
278                      (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) {
279 
280                     if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32 )) {
281 
282                         Cdb = (PCDB)((PSCSI_PASS_THROUGH32)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
283                     }
284                 } else {
285 
286                     if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32_EX )) {
287 
288                         Cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
289                     }
290                 }
291 
292             } else {
293 #endif
294                 if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) ||
295                      (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) {
296 
297                     if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH )) {
298 
299                         Cdb = (PCDB)((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
300                     }
301                 } else {
302 
303                     if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH_EX )) {
304 
305                         Cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb;
306                     }
307                 }
308 
309 #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED)
310             }
311 #endif
312 
313             if ((Cdb != NULL) && (Cdb->AsByte[0] == SCSIOP_FORMAT_UNIT)) {
314 
315                 SetFlag( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT );
316                 SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED );
317             }
318         }
319 
320         //
321         //  Fall through as we do not need to know the outcome of this operation.
322         //
323 
324     default:
325 
326         //
327         //  FAT doesn't need to see this on the way back, so skip ourselves.
328         //
329 
330         IoSkipCurrentIrpStackLocation( Irp );
331         break;
332     }
333 
334     //
335     //  Send the request.
336     //
337 
338     Status = IoCallDriver(Vcb->TargetDeviceObject, Irp);
339 
340     if (Status == STATUS_PENDING && CompletionContext) {
341 
342         KeWaitForSingleObject( &WaitEvent,
343                                Executive,
344                                KernelMode,
345                                FALSE,
346                                NULL );
347 
348         Status = Irp->IoStatus.Status;
349     }
350 
351     //
352     //  If we had a context, the IRP remains for us and we will complete it.
353     //  Handle it appropriately.
354     //
355 
356     if (CompletionContext) {
357 
358         //
359         //  Release all the resources that we held because of a
360         //  VOLSNAP_FLUSH_AND_HOLD.
361         //
362 
363         NT_ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES );
364 
365         FatReleaseVolume( IrpContext, Vcb );
366 
367         //
368         //  If we had no context, the IRP will complete asynchronously.
369         //
370 
371     } else {
372 
373         Irp = NULL;
374     }
375 
376     FatCompleteRequest( IrpContext, Irp, Status );
377 
378     DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", Status);
379 
380     return Status;
381 }
382 
383 
384 //
385 //  Local support routine
386 //
387 
388 NTSTATUS
389 NTAPI
390 FatDeviceControlCompletionRoutine(
391     _In_ PDEVICE_OBJECT DeviceObject,
392     _In_ PIRP Irp,
393     _In_reads_opt_(_Inexpressible_("varies")) PVOID Contxt
394     )
395 
396 {
397     PKEVENT Event = (PKEVENT) Contxt;
398 
399     //
400     //  If there is an event, this is a synch request. Signal and
401     //  let I/O know this isn't done yet.
402     //
403 
404     if (Event) {
405 
406         KeSetEvent( Event, 0, FALSE );
407         return STATUS_MORE_PROCESSING_REQUIRED;
408     }
409 
410     UNREFERENCED_PARAMETER( DeviceObject );
411     UNREFERENCED_PARAMETER( Irp );
412 
413     return STATUS_SUCCESS;
414 }
415 
416