[THEMES]
[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 VfatDispatchRequest(
99 IN PVFAT_IRP_CONTEXT IrpContext)
100 {
101 DPRINT("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext,
102 IrpContext->MajorFunction >= IRP_MJ_MAXIMUM_FUNCTION ? "????" : MajorFunctionNames[IrpContext->MajorFunction]);
103
104 ASSERT(IrpContext);
105
106 switch (IrpContext->MajorFunction)
107 {
108 case IRP_MJ_CLOSE:
109 return VfatClose(IrpContext);
110 case IRP_MJ_CREATE:
111 return VfatCreate(IrpContext);
112 case IRP_MJ_READ:
113 return VfatRead (IrpContext);
114 case IRP_MJ_WRITE:
115 return VfatWrite (IrpContext);
116 case IRP_MJ_FILE_SYSTEM_CONTROL:
117 return VfatFileSystemControl(IrpContext);
118 case IRP_MJ_QUERY_INFORMATION:
119 return VfatQueryInformation (IrpContext);
120 case IRP_MJ_SET_INFORMATION:
121 return VfatSetInformation (IrpContext);
122 case IRP_MJ_DIRECTORY_CONTROL:
123 return VfatDirectoryControl(IrpContext);
124 case IRP_MJ_QUERY_VOLUME_INFORMATION:
125 return VfatQueryVolumeInformation(IrpContext);
126 case IRP_MJ_SET_VOLUME_INFORMATION:
127 return VfatSetVolumeInformation(IrpContext);
128 case IRP_MJ_LOCK_CONTROL:
129 return VfatLockControl(IrpContext);
130 case IRP_MJ_CLEANUP:
131 return VfatCleanup(IrpContext);
132 case IRP_MJ_FLUSH_BUFFERS:
133 return VfatFlush(IrpContext);
134 case IRP_MJ_PNP:
135 return VfatPnp(IrpContext);
136 default:
137 DPRINT1("Unexpected major function %x\n", IrpContext->MajorFunction);
138 IrpContext->Irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
139 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
140 VfatFreeIrpContext(IrpContext);
141 return STATUS_DRIVER_INTERNAL_ERROR;
142 }
143 }
144
145 NTSTATUS
146 NTAPI
147 VfatBuildRequest(
148 IN PDEVICE_OBJECT DeviceObject,
149 IN PIRP Irp)
150 {
151 NTSTATUS Status;
152 PVFAT_IRP_CONTEXT IrpContext;
153
154 DPRINT("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
155
156 ASSERT(DeviceObject);
157 ASSERT(Irp);
158
159 IrpContext = VfatAllocateIrpContext(DeviceObject, Irp);
160 if (IrpContext == NULL)
161 {
162 Status = STATUS_INSUFFICIENT_RESOURCES;
163 Irp->IoStatus.Status = Status;
164 IoCompleteRequest(Irp, IO_NO_INCREMENT);
165 }
166 else
167 {
168 FsRtlEnterFileSystem();
169 Status = VfatDispatchRequest(IrpContext);
170 FsRtlExitFileSystem();
171 }
172 return Status;
173 }
174
175 VOID
176 VfatFreeIrpContext(
177 PVFAT_IRP_CONTEXT IrpContext)
178 {
179 ASSERT(IrpContext);
180 ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext);
181 }
182
183 PVFAT_IRP_CONTEXT
184 VfatAllocateIrpContext(
185 PDEVICE_OBJECT DeviceObject,
186 PIRP Irp)
187 {
188 PVFAT_IRP_CONTEXT IrpContext;
189 /*PIO_STACK_LOCATION Stack;*/
190 UCHAR MajorFunction;
191
192 DPRINT("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
193
194 ASSERT(DeviceObject);
195 ASSERT(Irp);
196
197 IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList);
198 if (IrpContext)
199 {
200 RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT));
201 IrpContext->Irp = Irp;
202 IrpContext->DeviceObject = DeviceObject;
203 IrpContext->DeviceExt = DeviceObject->DeviceExtension;
204 IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp);
205 ASSERT(IrpContext->Stack);
206 MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
207 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
208 IrpContext->FileObject = IrpContext->Stack->FileObject;
209 IrpContext->Flags = 0;
210 if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
211 MajorFunction == IRP_MJ_DEVICE_CONTROL ||
212 MajorFunction == IRP_MJ_SHUTDOWN)
213 {
214 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
215 }
216 else if (MajorFunction != IRP_MJ_CLEANUP &&
217 MajorFunction != IRP_MJ_CLOSE &&
218 IoIsOperationSynchronous(Irp))
219 {
220 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
221 }
222 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
223 IrpContext->RefCount = 0;
224 }
225 return IrpContext;
226 }
227
228 static WORKER_THREAD_ROUTINE VfatDoRequest;
229
230 static
231 VOID
232 NTAPI
233 VfatDoRequest(
234 PVOID IrpContext)
235 {
236 InterlockedDecrement(&QueueCount);
237 DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
238 IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount);
239 FsRtlEnterFileSystem();
240 VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
241 FsRtlExitFileSystem();
242 }
243
244 NTSTATUS
245 VfatQueueRequest(
246 PVFAT_IRP_CONTEXT IrpContext)
247 {
248 InterlockedIncrement(&QueueCount);
249 DPRINT("VfatQueueRequest(IrpContext %p), %d\n", IrpContext, QueueCount);
250
251 ASSERT(IrpContext != NULL);
252 ASSERT(IrpContext->Irp != NULL);
253
254 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
255 IoMarkIrpPending(IrpContext->Irp);
256 ExInitializeWorkItem(&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext);
257 ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
258 return STATUS_PENDING;
259 }
260
261 PVOID
262 VfatGetUserBuffer(
263 IN PIRP Irp)
264 {
265 ASSERT(Irp);
266
267 if (Irp->MdlAddress)
268 {
269 /* This call may be in the paging path, so use maximum priority */
270 /* FIXME: call with normal priority in the non-paging path */
271 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
272 }
273 else
274 {
275 return Irp->UserBuffer;
276 }
277 }
278
279 NTSTATUS
280 VfatLockUserBuffer(
281 IN PIRP Irp,
282 IN ULONG Length,
283 IN LOCK_OPERATION Operation)
284 {
285 ASSERT(Irp);
286
287 if (Irp->MdlAddress)
288 {
289 return STATUS_SUCCESS;
290 }
291
292 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
293
294 if (!Irp->MdlAddress)
295 {
296 return STATUS_INSUFFICIENT_RESOURCES;
297 }
298
299 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
300
301 return STATUS_SUCCESS;
302 }
303