[FASTFAT] Implement delayed close
[reactos.git] / drivers / filesystems / fastfat_new / devctrl.c
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 \f
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 // execption 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 \f
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 \f
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