1e97d7a82fbbdf7dcd02683c01fb07cc78bedff7
[reactos.git] / reactos / drivers / filesystems / fastfat / misc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/misc.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER:
7 *
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "vfat.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 const char* MajorFunctionNames[] =
20 {
21 "IRP_MJ_CREATE",
22 "IRP_MJ_CREATE_NAMED_PIPE",
23 "IRP_MJ_CLOSE",
24 "IRP_MJ_READ",
25 "IRP_MJ_WRITE",
26 "IRP_MJ_QUERY_INFORMATION",
27 "IRP_MJ_SET_INFORMATION",
28 "IRP_MJ_QUERY_EA",
29 "IRP_MJ_SET_EA",
30 "IRP_MJ_FLUSH_BUFFERS",
31 "IRP_MJ_QUERY_VOLUME_INFORMATION",
32 "IRP_MJ_SET_VOLUME_INFORMATION",
33 "IRP_MJ_DIRECTORY_CONTROL",
34 "IRP_MJ_FILE_SYSTEM_CONTROL",
35 "IRP_MJ_DEVICE_CONTROL",
36 "IRP_MJ_INTERNAL_DEVICE_CONTROL",
37 "IRP_MJ_SHUTDOWN",
38 "IRP_MJ_LOCK_CONTROL",
39 "IRP_MJ_CLEANUP",
40 "IRP_MJ_CREATE_MAILSLOT",
41 "IRP_MJ_QUERY_SECURITY",
42 "IRP_MJ_SET_SECURITY",
43 "IRP_MJ_POWER",
44 "IRP_MJ_SYSTEM_CONTROL",
45 "IRP_MJ_DEVICE_CHANGE",
46 "IRP_MJ_QUERY_QUOTA",
47 "IRP_MJ_SET_QUOTA",
48 "IRP_MJ_PNP",
49 "IRP_MJ_MAXIMUM_FUNCTION"
50 };
51
52 static LONG QueueCount = 0;
53
54 static VOID VfatFreeIrpContext(PVFAT_IRP_CONTEXT);
55 static PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT, PIRP);
56 static NTSTATUS VfatQueueRequest(PVFAT_IRP_CONTEXT);
57
58 /* FUNCTIONS ****************************************************************/
59
60 static
61 NTSTATUS
62 VfatLockControl(
63 IN PVFAT_IRP_CONTEXT IrpContext)
64 {
65 PVFATFCB Fcb;
66 NTSTATUS Status;
67
68 DPRINT("VfatLockControl(IrpContext %p)\n", IrpContext);
69
70 ASSERT(IrpContext);
71
72 Fcb = (PVFATFCB)IrpContext->FileObject->FsContext;
73
74 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
75 {
76 return STATUS_INVALID_DEVICE_REQUEST;
77 }
78
79 if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
80 {
81 return STATUS_INVALID_PARAMETER;
82 }
83
84 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
85 Status = FsRtlProcessFileLock(&Fcb->FileLock,
86 IrpContext->Irp,
87 NULL);
88 return Status;
89 }
90
91 static
92 NTSTATUS
93 VfatDeviceControl(
94 IN PVFAT_IRP_CONTEXT IrpContext)
95 {
96 IoSkipCurrentIrpStackLocation(IrpContext->Irp);
97
98 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
99
100 return IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
101 }
102
103 static
104 NTSTATUS
105 VfatDispatchRequest(
106 IN PVFAT_IRP_CONTEXT IrpContext)
107 {
108 NTSTATUS Status;
109
110 DPRINT("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext,
111 IrpContext->MajorFunction >= IRP_MJ_MAXIMUM_FUNCTION ? "????" : MajorFunctionNames[IrpContext->MajorFunction]);
112
113 ASSERT(IrpContext);
114
115 switch (IrpContext->MajorFunction)
116 {
117 case IRP_MJ_CLOSE:
118 Status = VfatClose(IrpContext);
119 break;
120
121 case IRP_MJ_CREATE:
122 Status = VfatCreate(IrpContext);
123 break;
124
125 case IRP_MJ_READ:
126 Status = VfatRead(IrpContext);
127 break;
128
129 case IRP_MJ_WRITE:
130 Status = VfatWrite (IrpContext);
131 break;
132
133 case IRP_MJ_FILE_SYSTEM_CONTROL:
134 Status = VfatFileSystemControl(IrpContext);
135 break;
136
137 case IRP_MJ_QUERY_INFORMATION:
138 Status = VfatQueryInformation (IrpContext);
139 break;
140
141 case IRP_MJ_SET_INFORMATION:
142 Status = VfatSetInformation (IrpContext);
143 break;
144
145 case IRP_MJ_DIRECTORY_CONTROL:
146 Status = VfatDirectoryControl(IrpContext);
147 break;
148
149 case IRP_MJ_QUERY_VOLUME_INFORMATION:
150 Status = VfatQueryVolumeInformation(IrpContext);
151 break;
152
153 case IRP_MJ_SET_VOLUME_INFORMATION:
154 Status = VfatSetVolumeInformation(IrpContext);
155 break;
156
157 case IRP_MJ_LOCK_CONTROL:
158 Status = VfatLockControl(IrpContext);
159 break;
160
161 case IRP_MJ_DEVICE_CONTROL:
162 Status = VfatDeviceControl(IrpContext);
163 break;
164
165 case IRP_MJ_CLEANUP:
166 Status = VfatCleanup(IrpContext);
167 break;
168
169 case IRP_MJ_FLUSH_BUFFERS:
170 Status = VfatFlush(IrpContext);
171 break;
172
173 case IRP_MJ_PNP:
174 Status = VfatPnp(IrpContext);
175 break;
176
177 default:
178 DPRINT1("Unexpected major function %x\n", IrpContext->MajorFunction);
179 Status = STATUS_DRIVER_INTERNAL_ERROR;
180 }
181
182 ASSERT((!(IrpContext->Flags & IRPCONTEXT_COMPLETE) && !(IrpContext->Flags & IRPCONTEXT_QUEUE)) ||
183 ((IrpContext->Flags & IRPCONTEXT_COMPLETE) && !(IrpContext->Flags & IRPCONTEXT_QUEUE)) ||
184 (!(IrpContext->Flags & IRPCONTEXT_COMPLETE) && (IrpContext->Flags & IRPCONTEXT_QUEUE)));
185
186 if (IrpContext->Flags & IRPCONTEXT_COMPLETE)
187 {
188 IrpContext->Irp->IoStatus.Status = Status;
189 IoCompleteRequest(IrpContext->Irp, IrpContext->PriorityBoost);
190 }
191
192 if (IrpContext->Flags & IRPCONTEXT_QUEUE)
193 {
194 /* Reset our status flags before queueing the IRP */
195 IrpContext->Flags |= IRPCONTEXT_COMPLETE;
196 IrpContext->Flags &= ~IRPCONTEXT_QUEUE;
197 Status = VfatQueueRequest(IrpContext);
198 }
199 else
200 {
201 /* Unless the IRP was queued, always free the IRP context */
202 VfatFreeIrpContext(IrpContext);
203 }
204
205 return Status;
206 }
207
208 NTSTATUS
209 NTAPI
210 VfatBuildRequest(
211 IN PDEVICE_OBJECT DeviceObject,
212 IN PIRP Irp)
213 {
214 NTSTATUS Status;
215 PVFAT_IRP_CONTEXT IrpContext;
216
217 DPRINT("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
218
219 ASSERT(DeviceObject);
220 ASSERT(Irp);
221
222 IrpContext = VfatAllocateIrpContext(DeviceObject, Irp);
223 if (IrpContext == NULL)
224 {
225 Status = STATUS_INSUFFICIENT_RESOURCES;
226 Irp->IoStatus.Status = Status;
227 IoCompleteRequest(Irp, IO_NO_INCREMENT);
228 }
229 else
230 {
231 FsRtlEnterFileSystem();
232 Status = VfatDispatchRequest(IrpContext);
233 FsRtlExitFileSystem();
234 }
235 return Status;
236 }
237
238 static
239 VOID
240 VfatFreeIrpContext(
241 PVFAT_IRP_CONTEXT IrpContext)
242 {
243 ASSERT(IrpContext);
244 ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext);
245 }
246
247 static
248 PVFAT_IRP_CONTEXT
249 VfatAllocateIrpContext(
250 PDEVICE_OBJECT DeviceObject,
251 PIRP Irp)
252 {
253 PVFAT_IRP_CONTEXT IrpContext;
254 /*PIO_STACK_LOCATION Stack;*/
255 UCHAR MajorFunction;
256
257 DPRINT("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
258
259 ASSERT(DeviceObject);
260 ASSERT(Irp);
261
262 IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList);
263 if (IrpContext)
264 {
265 RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT));
266 IrpContext->Irp = Irp;
267 IrpContext->DeviceObject = DeviceObject;
268 IrpContext->DeviceExt = DeviceObject->DeviceExtension;
269 IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp);
270 ASSERT(IrpContext->Stack);
271 MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
272 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
273 IrpContext->FileObject = IrpContext->Stack->FileObject;
274 IrpContext->Flags = IRPCONTEXT_COMPLETE;
275 if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
276 MajorFunction == IRP_MJ_DEVICE_CONTROL ||
277 MajorFunction == IRP_MJ_SHUTDOWN)
278 {
279 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
280 }
281 else if (MajorFunction != IRP_MJ_CLEANUP &&
282 MajorFunction != IRP_MJ_CLOSE &&
283 IoIsOperationSynchronous(Irp))
284 {
285 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
286 }
287 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
288 IrpContext->RefCount = 0;
289 IrpContext->PriorityBoost = IO_NO_INCREMENT;
290 }
291 return IrpContext;
292 }
293
294 static WORKER_THREAD_ROUTINE VfatDoRequest;
295
296 static
297 VOID
298 NTAPI
299 VfatDoRequest(
300 PVOID IrpContext)
301 {
302 InterlockedDecrement(&QueueCount);
303 DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
304 IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount);
305 FsRtlEnterFileSystem();
306 VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
307 FsRtlExitFileSystem();
308 }
309
310 static
311 NTSTATUS
312 VfatQueueRequest(
313 PVFAT_IRP_CONTEXT IrpContext)
314 {
315 InterlockedIncrement(&QueueCount);
316 DPRINT("VfatQueueRequest(IrpContext %p), %d\n", IrpContext, QueueCount);
317
318 ASSERT(IrpContext != NULL);
319 ASSERT(IrpContext->Irp != NULL);
320
321 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
322 IoMarkIrpPending(IrpContext->Irp);
323 ExInitializeWorkItem(&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext);
324 ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
325 return STATUS_PENDING;
326 }
327
328 PVOID
329 VfatGetUserBuffer(
330 IN PIRP Irp,
331 IN BOOLEAN Paging)
332 {
333 ASSERT(Irp);
334
335 if (Irp->MdlAddress)
336 {
337 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, (Paging ? HighPagePriority : NormalPagePriority));
338 }
339 else
340 {
341 return Irp->UserBuffer;
342 }
343 }
344
345 NTSTATUS
346 VfatLockUserBuffer(
347 IN PIRP Irp,
348 IN ULONG Length,
349 IN LOCK_OPERATION Operation)
350 {
351 ASSERT(Irp);
352
353 if (Irp->MdlAddress)
354 {
355 return STATUS_SUCCESS;
356 }
357
358 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
359
360 if (!Irp->MdlAddress)
361 {
362 return STATUS_INSUFFICIENT_RESOURCES;
363 }
364
365 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
366
367 return STATUS_SUCCESS;
368 }
369
370 BOOLEAN
371 VfatCheckForDismount(
372 IN PDEVICE_EXTENSION DeviceExt,
373 IN BOOLEAN Create)
374 {
375 KIRQL OldIrql;
376 PVPB Vpb;
377 BOOLEAN Delete;
378
379 DPRINT1("VfatCheckForDismount(%p, %u)\n", DeviceExt, Create);
380
381 /* Lock VPB */
382 IoAcquireVpbSpinLock(&OldIrql);
383
384 /* Reference it and check if a create is being done */
385 Vpb = DeviceExt->IoVPB;
386 if (Vpb->ReferenceCount != Create)
387 {
388 /* Copy the VPB to our local own to prepare later dismount */
389 if (DeviceExt->SpareVPB != NULL)
390 {
391 RtlZeroMemory(DeviceExt->SpareVPB, sizeof(VPB));
392 DeviceExt->SpareVPB->Type = IO_TYPE_VPB;
393 DeviceExt->SpareVPB->Size = sizeof(VPB);
394 DeviceExt->SpareVPB->RealDevice = DeviceExt->IoVPB->RealDevice;
395 DeviceExt->SpareVPB->DeviceObject = NULL;
396 DeviceExt->SpareVPB->Flags = DeviceExt->IoVPB->Flags & VPB_REMOVE_PENDING;
397 DeviceExt->IoVPB->RealDevice->Vpb = DeviceExt->SpareVPB;
398 DeviceExt->SpareVPB = NULL;
399 DeviceExt->IoVPB->Flags |= VPB_PERSISTENT;
400 }
401
402 /* Don't do anything */
403 Delete = FALSE;
404 }
405 else
406 {
407 /* Otherwise, delete the volume */
408 Delete = TRUE;
409
410 /* Check if it has a VPB and unmount it */
411 if (Vpb->RealDevice->Vpb == Vpb)
412 {
413 Vpb->DeviceObject = NULL;
414 Vpb->Flags &= ~VPB_MOUNTED;
415 }
416 }
417
418 /* Release lock and return status */
419 IoReleaseVpbSpinLock(OldIrql);
420
421 /* If we were to delete, delete volume */
422 if (Delete)
423 {
424 PVPB DelVpb;
425
426 /* If we have a local VPB, we'll have to delete it
427 * but we won't dismount us - something went bad before
428 */
429 if (DeviceExt->SpareVPB)
430 {
431 DelVpb = DeviceExt->SpareVPB;
432 }
433 /* Otherwise, dismount our device if possible */
434 else
435 {
436 if (DeviceExt->IoVPB->ReferenceCount)
437 {
438 ObfDereferenceObject(DeviceExt->StorageDevice);
439 IoDeleteDevice(DeviceExt->VolumeDevice);
440 return Delete;
441 }
442
443 DelVpb = DeviceExt->IoVPB;
444 }
445
446 /* Delete any of the available VPB and dismount */
447 ExFreePool(DelVpb);
448 ObfDereferenceObject(DeviceExt->StorageDevice);
449 IoDeleteDevice(DeviceExt->VolumeDevice);
450
451 return Delete;
452 }
453
454 return Delete;
455 }