[FASTFAT]
[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 /* FUNCTIONS ****************************************************************/
55
56 static
57 NTSTATUS
58 VfatLockControl(
59 IN PVFAT_IRP_CONTEXT IrpContext)
60 {
61 PVFATFCB Fcb;
62 NTSTATUS Status;
63
64 DPRINT("VfatLockControl(IrpContext %p)\n", IrpContext);
65
66 ASSERT(IrpContext);
67
68 Fcb = (PVFATFCB)IrpContext->FileObject->FsContext;
69
70 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
71 {
72 Status = STATUS_INVALID_DEVICE_REQUEST;
73 goto Fail;
74 }
75
76 if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
77 {
78 Status = STATUS_INVALID_PARAMETER;
79 goto Fail;
80 }
81
82 Status = FsRtlProcessFileLock(&Fcb->FileLock,
83 IrpContext->Irp,
84 NULL);
85
86 VfatFreeIrpContext(IrpContext);
87 return Status;
88
89 Fail:
90 IrpContext->Irp->IoStatus.Status = Status;
91 IoCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
92 VfatFreeIrpContext(IrpContext);
93 return Status;
94 }
95
96 static
97 NTSTATUS
98 VfatDeviceControl(
99 IN PVFAT_IRP_CONTEXT IrpContext)
100 {
101 IoSkipCurrentIrpStackLocation(IrpContext->Irp);
102
103 return IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
104 }
105
106 static
107 NTSTATUS
108 VfatDispatchRequest(
109 IN PVFAT_IRP_CONTEXT IrpContext)
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 switch (IrpContext->MajorFunction)
117 {
118 case IRP_MJ_CLOSE:
119 return VfatClose(IrpContext);
120 case IRP_MJ_CREATE:
121 return VfatCreate(IrpContext);
122 case IRP_MJ_READ:
123 return VfatRead (IrpContext);
124 case IRP_MJ_WRITE:
125 return VfatWrite (IrpContext);
126 case IRP_MJ_FILE_SYSTEM_CONTROL:
127 return VfatFileSystemControl(IrpContext);
128 case IRP_MJ_QUERY_INFORMATION:
129 return VfatQueryInformation (IrpContext);
130 case IRP_MJ_SET_INFORMATION:
131 return VfatSetInformation (IrpContext);
132 case IRP_MJ_DIRECTORY_CONTROL:
133 return VfatDirectoryControl(IrpContext);
134 case IRP_MJ_QUERY_VOLUME_INFORMATION:
135 return VfatQueryVolumeInformation(IrpContext);
136 case IRP_MJ_SET_VOLUME_INFORMATION:
137 return VfatSetVolumeInformation(IrpContext);
138 case IRP_MJ_LOCK_CONTROL:
139 return VfatLockControl(IrpContext);
140 case IRP_MJ_DEVICE_CONTROL:
141 return VfatDeviceControl(IrpContext);
142 case IRP_MJ_CLEANUP:
143 return VfatCleanup(IrpContext);
144 case IRP_MJ_FLUSH_BUFFERS:
145 return VfatFlush(IrpContext);
146 case IRP_MJ_PNP:
147 return VfatPnp(IrpContext);
148 default:
149 DPRINT1("Unexpected major function %x\n", IrpContext->MajorFunction);
150 IrpContext->Irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
151 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
152 VfatFreeIrpContext(IrpContext);
153 return STATUS_DRIVER_INTERNAL_ERROR;
154 }
155 }
156
157 NTSTATUS
158 NTAPI
159 VfatBuildRequest(
160 IN PDEVICE_OBJECT DeviceObject,
161 IN PIRP Irp)
162 {
163 NTSTATUS Status;
164 PVFAT_IRP_CONTEXT IrpContext;
165
166 DPRINT("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
167
168 ASSERT(DeviceObject);
169 ASSERT(Irp);
170
171 IrpContext = VfatAllocateIrpContext(DeviceObject, Irp);
172 if (IrpContext == NULL)
173 {
174 Status = STATUS_INSUFFICIENT_RESOURCES;
175 Irp->IoStatus.Status = Status;
176 IoCompleteRequest(Irp, IO_NO_INCREMENT);
177 }
178 else
179 {
180 FsRtlEnterFileSystem();
181 Status = VfatDispatchRequest(IrpContext);
182 FsRtlExitFileSystem();
183 }
184 return Status;
185 }
186
187 VOID
188 VfatFreeIrpContext(
189 PVFAT_IRP_CONTEXT IrpContext)
190 {
191 ASSERT(IrpContext);
192 ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext);
193 }
194
195 PVFAT_IRP_CONTEXT
196 VfatAllocateIrpContext(
197 PDEVICE_OBJECT DeviceObject,
198 PIRP Irp)
199 {
200 PVFAT_IRP_CONTEXT IrpContext;
201 /*PIO_STACK_LOCATION Stack;*/
202 UCHAR MajorFunction;
203
204 DPRINT("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
205
206 ASSERT(DeviceObject);
207 ASSERT(Irp);
208
209 IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList);
210 if (IrpContext)
211 {
212 RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT));
213 IrpContext->Irp = Irp;
214 IrpContext->DeviceObject = DeviceObject;
215 IrpContext->DeviceExt = DeviceObject->DeviceExtension;
216 IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp);
217 ASSERT(IrpContext->Stack);
218 MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
219 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
220 IrpContext->FileObject = IrpContext->Stack->FileObject;
221 IrpContext->Flags = 0;
222 if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
223 MajorFunction == IRP_MJ_DEVICE_CONTROL ||
224 MajorFunction == IRP_MJ_SHUTDOWN)
225 {
226 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
227 }
228 else if (MajorFunction != IRP_MJ_CLEANUP &&
229 MajorFunction != IRP_MJ_CLOSE &&
230 IoIsOperationSynchronous(Irp))
231 {
232 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
233 }
234 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
235 IrpContext->RefCount = 0;
236 }
237 return IrpContext;
238 }
239
240 static WORKER_THREAD_ROUTINE VfatDoRequest;
241
242 static
243 VOID
244 NTAPI
245 VfatDoRequest(
246 PVOID IrpContext)
247 {
248 InterlockedDecrement(&QueueCount);
249 DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
250 IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount);
251 FsRtlEnterFileSystem();
252 VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
253 FsRtlExitFileSystem();
254 }
255
256 NTSTATUS
257 VfatQueueRequest(
258 PVFAT_IRP_CONTEXT IrpContext)
259 {
260 InterlockedIncrement(&QueueCount);
261 DPRINT("VfatQueueRequest(IrpContext %p), %d\n", IrpContext, QueueCount);
262
263 ASSERT(IrpContext != NULL);
264 ASSERT(IrpContext->Irp != NULL);
265
266 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
267 IoMarkIrpPending(IrpContext->Irp);
268 ExInitializeWorkItem(&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext);
269 ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
270 return STATUS_PENDING;
271 }
272
273 PVOID
274 VfatGetUserBuffer(
275 IN PIRP Irp)
276 {
277 ASSERT(Irp);
278
279 if (Irp->MdlAddress)
280 {
281 /* This call may be in the paging path, so use maximum priority */
282 /* FIXME: call with normal priority in the non-paging path */
283 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
284 }
285 else
286 {
287 return Irp->UserBuffer;
288 }
289 }
290
291 NTSTATUS
292 VfatLockUserBuffer(
293 IN PIRP Irp,
294 IN ULONG Length,
295 IN LOCK_OPERATION Operation)
296 {
297 ASSERT(Irp);
298
299 if (Irp->MdlAddress)
300 {
301 return STATUS_SUCCESS;
302 }
303
304 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
305
306 if (!Irp->MdlAddress)
307 {
308 return STATUS_INSUFFICIENT_RESOURCES;
309 }
310
311 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
312
313 return STATUS_SUCCESS;
314 }
315
316 BOOLEAN
317 VfatCheckForDismount(
318 IN PDEVICE_EXTENSION DeviceExt,
319 IN BOOLEAN Create)
320 {
321 KIRQL OldIrql;
322 PVPB Vpb;
323 BOOLEAN Delete;
324
325 DPRINT1("VfatCheckForDismount(%p, %u)\n", DeviceExt, Create);
326
327 /* Lock VPB */
328 IoAcquireVpbSpinLock(&OldIrql);
329
330 /* Reference it and check if a create is being done */
331 Vpb = DeviceExt->IoVPB;
332 if (Vpb->ReferenceCount != Create)
333 {
334 /* Copy the VPB to our local own to prepare later dismount */
335 if (DeviceExt->SpareVPB != NULL)
336 {
337 RtlZeroMemory(DeviceExt->SpareVPB, sizeof(VPB));
338 DeviceExt->SpareVPB->Type = IO_TYPE_VPB;
339 DeviceExt->SpareVPB->Size = sizeof(VPB);
340 DeviceExt->SpareVPB->RealDevice = DeviceExt->IoVPB->RealDevice;
341 DeviceExt->SpareVPB->DeviceObject = NULL;
342 DeviceExt->SpareVPB->Flags = DeviceExt->IoVPB->Flags & VPB_REMOVE_PENDING;
343 DeviceExt->IoVPB->RealDevice->Vpb = DeviceExt->SpareVPB;
344 DeviceExt->SpareVPB = NULL;
345 DeviceExt->IoVPB->Flags |= VPB_PERSISTENT;
346 }
347
348 /* Don't do anything */
349 Delete = FALSE;
350 }
351 else
352 {
353 /* Otherwise, delete the volume */
354 Delete = TRUE;
355
356 /* Check if it has a VPB and unmount it */
357 if (Vpb->RealDevice->Vpb == Vpb)
358 {
359 Vpb->DeviceObject = NULL;
360 Vpb->Flags &= ~VPB_MOUNTED;
361 }
362 }
363
364 /* Release lock and return status */
365 IoReleaseVpbSpinLock(OldIrql);
366
367 /* If we were to delete, delete volume */
368 if (Delete)
369 {
370 PVPB DelVpb;
371
372 /* If we have a local VPB, we'll have to delete it
373 * but we won't dismount us - something went bad before
374 */
375 if (DeviceExt->SpareVPB)
376 {
377 DelVpb = DeviceExt->SpareVPB;
378 }
379 /* Otherwise, dismount our device if possible */
380 else
381 {
382 if (DeviceExt->IoVPB->ReferenceCount)
383 {
384 ObfDereferenceObject(DeviceExt->StorageDevice);
385 IoDeleteDevice(DeviceExt->VolumeDevice);
386 return Delete;
387 }
388
389 DelVpb = DeviceExt->IoVPB;
390 }
391
392 /* Delete any of the available VPB and dismount */
393 ExFreePool(DelVpb);
394 ObfDereferenceObject(DeviceExt->StorageDevice);
395 IoDeleteDevice(DeviceExt->VolumeDevice);
396
397 return Delete;
398 }
399
400 return Delete;
401 }