[FASTFAT] Fix size checking in VfatGetFileNameInformation()
[reactos.git] / 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 (vfatFCBIsDirectory(Fcb))
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 BOOLEAN QueueIrp, CompleteIrp;
110
111 DPRINT("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext,
112 IrpContext->MajorFunction >= IRP_MJ_MAXIMUM_FUNCTION ? "????" : MajorFunctionNames[IrpContext->MajorFunction]);
113
114 ASSERT(IrpContext);
115
116 FsRtlEnterFileSystem();
117
118 switch (IrpContext->MajorFunction)
119 {
120 case IRP_MJ_CLOSE:
121 Status = VfatClose(IrpContext);
122 break;
123
124 case IRP_MJ_CREATE:
125 Status = VfatCreate(IrpContext);
126 break;
127
128 case IRP_MJ_READ:
129 Status = VfatRead(IrpContext);
130 break;
131
132 case IRP_MJ_WRITE:
133 Status = VfatWrite (IrpContext);
134 break;
135
136 case IRP_MJ_FILE_SYSTEM_CONTROL:
137 Status = VfatFileSystemControl(IrpContext);
138 break;
139
140 case IRP_MJ_QUERY_INFORMATION:
141 Status = VfatQueryInformation (IrpContext);
142 break;
143
144 case IRP_MJ_SET_INFORMATION:
145 Status = VfatSetInformation (IrpContext);
146 break;
147
148 case IRP_MJ_DIRECTORY_CONTROL:
149 Status = VfatDirectoryControl(IrpContext);
150 break;
151
152 case IRP_MJ_QUERY_VOLUME_INFORMATION:
153 Status = VfatQueryVolumeInformation(IrpContext);
154 break;
155
156 case IRP_MJ_SET_VOLUME_INFORMATION:
157 Status = VfatSetVolumeInformation(IrpContext);
158 break;
159
160 case IRP_MJ_LOCK_CONTROL:
161 Status = VfatLockControl(IrpContext);
162 break;
163
164 case IRP_MJ_DEVICE_CONTROL:
165 Status = VfatDeviceControl(IrpContext);
166 break;
167
168 case IRP_MJ_CLEANUP:
169 Status = VfatCleanup(IrpContext);
170 break;
171
172 case IRP_MJ_FLUSH_BUFFERS:
173 Status = VfatFlush(IrpContext);
174 break;
175
176 case IRP_MJ_PNP:
177 Status = VfatPnp(IrpContext);
178 break;
179
180 default:
181 DPRINT1("Unexpected major function %x\n", IrpContext->MajorFunction);
182 Status = STATUS_DRIVER_INTERNAL_ERROR;
183 }
184
185 QueueIrp = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_QUEUE);
186 CompleteIrp = BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE);
187
188 ASSERT((!CompleteIrp && !QueueIrp) ||
189 (CompleteIrp && !QueueIrp) ||
190 (!CompleteIrp && QueueIrp));
191
192 if (CompleteIrp)
193 {
194 IrpContext->Irp->IoStatus.Status = Status;
195 IoCompleteRequest(IrpContext->Irp, IrpContext->PriorityBoost);
196 }
197
198 if (QueueIrp)
199 {
200 /* Reset our status flags before queueing the IRP */
201 IrpContext->Flags |= IRPCONTEXT_COMPLETE;
202 IrpContext->Flags &= ~IRPCONTEXT_QUEUE;
203 Status = VfatQueueRequest(IrpContext);
204 }
205 else
206 {
207 /* Unless the IRP was queued, always free the IRP context */
208 VfatFreeIrpContext(IrpContext);
209 }
210
211 FsRtlExitFileSystem();
212
213 return Status;
214 }
215
216 NTSTATUS
217 NTAPI
218 VfatBuildRequest(
219 IN PDEVICE_OBJECT DeviceObject,
220 IN PIRP Irp)
221 {
222 NTSTATUS Status;
223 PVFAT_IRP_CONTEXT IrpContext;
224
225 DPRINT("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
226
227 ASSERT(DeviceObject);
228 ASSERT(Irp);
229
230 IrpContext = VfatAllocateIrpContext(DeviceObject, Irp);
231 if (IrpContext == NULL)
232 {
233 Status = STATUS_INSUFFICIENT_RESOURCES;
234 Irp->IoStatus.Status = Status;
235 IoCompleteRequest(Irp, IO_NO_INCREMENT);
236 }
237 else
238 {
239 Status = VfatDispatchRequest(IrpContext);
240 }
241 return Status;
242 }
243
244 static
245 VOID
246 VfatFreeIrpContext(
247 PVFAT_IRP_CONTEXT IrpContext)
248 {
249 ASSERT(IrpContext);
250 ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext);
251 }
252
253 static
254 PVFAT_IRP_CONTEXT
255 VfatAllocateIrpContext(
256 PDEVICE_OBJECT DeviceObject,
257 PIRP Irp)
258 {
259 PVFAT_IRP_CONTEXT IrpContext;
260 /*PIO_STACK_LOCATION Stack;*/
261 UCHAR MajorFunction;
262
263 DPRINT("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
264
265 ASSERT(DeviceObject);
266 ASSERT(Irp);
267
268 IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList);
269 if (IrpContext)
270 {
271 RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT));
272 IrpContext->Irp = Irp;
273 IrpContext->DeviceObject = DeviceObject;
274 IrpContext->DeviceExt = DeviceObject->DeviceExtension;
275 IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp);
276 ASSERT(IrpContext->Stack);
277 MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
278 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
279 IrpContext->FileObject = IrpContext->Stack->FileObject;
280 IrpContext->Flags = IRPCONTEXT_COMPLETE;
281 if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
282 MajorFunction == IRP_MJ_DEVICE_CONTROL ||
283 MajorFunction == IRP_MJ_SHUTDOWN)
284 {
285 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
286 }
287 else if (MajorFunction != IRP_MJ_CLEANUP &&
288 MajorFunction != IRP_MJ_CLOSE &&
289 IoIsOperationSynchronous(Irp))
290 {
291 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
292 }
293 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
294 IrpContext->RefCount = 0;
295 IrpContext->PriorityBoost = IO_NO_INCREMENT;
296 }
297 return IrpContext;
298 }
299
300 static WORKER_THREAD_ROUTINE VfatDoRequest;
301
302 static
303 VOID
304 NTAPI
305 VfatDoRequest(
306 PVOID IrpContext)
307 {
308 InterlockedDecrement(&QueueCount);
309 DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
310 IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount);
311 VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
312 }
313
314 static
315 NTSTATUS
316 VfatQueueRequest(
317 PVFAT_IRP_CONTEXT IrpContext)
318 {
319 InterlockedIncrement(&QueueCount);
320 DPRINT("VfatQueueRequest(IrpContext %p), %d\n", IrpContext, QueueCount);
321
322 ASSERT(IrpContext != NULL);
323 ASSERT(IrpContext->Irp != NULL);
324 ASSERT(!(IrpContext->Flags & IRPCONTEXT_QUEUE) &&
325 (IrpContext->Flags & IRPCONTEXT_COMPLETE));
326
327 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
328 IoMarkIrpPending(IrpContext->Irp);
329 ExInitializeWorkItem(&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext);
330 ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
331 return STATUS_PENDING;
332 }
333
334 PVOID
335 VfatGetUserBuffer(
336 IN PIRP Irp,
337 IN BOOLEAN Paging)
338 {
339 ASSERT(Irp);
340
341 if (Irp->MdlAddress)
342 {
343 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, (Paging ? HighPagePriority : NormalPagePriority));
344 }
345 else
346 {
347 return Irp->UserBuffer;
348 }
349 }
350
351 NTSTATUS
352 VfatLockUserBuffer(
353 IN PIRP Irp,
354 IN ULONG Length,
355 IN LOCK_OPERATION Operation)
356 {
357 ASSERT(Irp);
358
359 if (Irp->MdlAddress)
360 {
361 return STATUS_SUCCESS;
362 }
363
364 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
365
366 if (!Irp->MdlAddress)
367 {
368 return STATUS_INSUFFICIENT_RESOURCES;
369 }
370
371 _SEH2_TRY
372 {
373 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
374 }
375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
376 {
377 IoFreeMdl(Irp->MdlAddress);
378 Irp->MdlAddress = NULL;
379 _SEH2_YIELD(return _SEH2_GetExceptionCode());
380 }
381 _SEH2_END;
382
383 return STATUS_SUCCESS;
384 }
385
386 BOOLEAN
387 VfatCheckForDismount(
388 IN PDEVICE_EXTENSION DeviceExt,
389 IN BOOLEAN Create)
390 {
391 KIRQL OldIrql;
392 PVPB Vpb;
393 BOOLEAN Delete;
394
395 DPRINT1("VfatCheckForDismount(%p, %u)\n", DeviceExt, Create);
396
397 /* Lock VPB */
398 IoAcquireVpbSpinLock(&OldIrql);
399
400 /* Reference it and check if a create is being done */
401 Vpb = DeviceExt->IoVPB;
402 if (Vpb->ReferenceCount != Create)
403 {
404 /* Copy the VPB to our local own to prepare later dismount */
405 if (DeviceExt->SpareVPB != NULL)
406 {
407 RtlZeroMemory(DeviceExt->SpareVPB, sizeof(VPB));
408 DeviceExt->SpareVPB->Type = IO_TYPE_VPB;
409 DeviceExt->SpareVPB->Size = sizeof(VPB);
410 DeviceExt->SpareVPB->RealDevice = DeviceExt->IoVPB->RealDevice;
411 DeviceExt->SpareVPB->DeviceObject = NULL;
412 DeviceExt->SpareVPB->Flags = DeviceExt->IoVPB->Flags & VPB_REMOVE_PENDING;
413 DeviceExt->IoVPB->RealDevice->Vpb = DeviceExt->SpareVPB;
414 DeviceExt->SpareVPB = NULL;
415 DeviceExt->IoVPB->Flags |= VPB_PERSISTENT;
416 }
417
418 /* Don't do anything */
419 Delete = FALSE;
420 }
421 else
422 {
423 /* Otherwise, delete the volume */
424 Delete = TRUE;
425
426 /* Check if it has a VPB and unmount it */
427 if (Vpb->RealDevice->Vpb == Vpb)
428 {
429 Vpb->DeviceObject = NULL;
430 Vpb->Flags &= ~VPB_MOUNTED;
431 }
432 }
433
434 /* Release lock and return status */
435 IoReleaseVpbSpinLock(OldIrql);
436
437 /* If we were to delete, delete volume */
438 if (Delete)
439 {
440 PVPB DelVpb;
441
442 /* If we have a local VPB, we'll have to delete it
443 * but we won't dismount us - something went bad before
444 */
445 if (DeviceExt->SpareVPB)
446 {
447 DelVpb = DeviceExt->SpareVPB;
448 }
449 /* Otherwise, dismount our device if possible */
450 else
451 {
452 if (DeviceExt->IoVPB->ReferenceCount)
453 {
454 ObfDereferenceObject(DeviceExt->StorageDevice);
455 IoDeleteDevice(DeviceExt->VolumeDevice);
456 return Delete;
457 }
458
459 DelVpb = DeviceExt->IoVPB;
460 }
461
462 /* Delete any of the available VPB and dismount */
463 ExFreePool(DelVpb);
464 ObfDereferenceObject(DeviceExt->StorageDevice);
465 IoDeleteDevice(DeviceExt->VolumeDevice);
466
467 return Delete;
468 }
469
470 return Delete;
471 }