Sync with trunk head.
[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 #define NDEBUG
13 #include "vfat.h"
14
15 /* GLOBALS ******************************************************************/
16
17 const char* MajorFunctionNames[] =
18 {
19 "IRP_MJ_CREATE",
20 "IRP_MJ_CREATE_NAMED_PIPE",
21 "IRP_MJ_CLOSE",
22 "IRP_MJ_READ",
23 "IRP_MJ_WRITE",
24 "IRP_MJ_QUERY_INFORMATION",
25 "IRP_MJ_SET_INFORMATION",
26 "IRP_MJ_QUERY_EA",
27 "IRP_MJ_SET_EA",
28 "IRP_MJ_FLUSH_BUFFERS",
29 "IRP_MJ_QUERY_VOLUME_INFORMATION",
30 "IRP_MJ_SET_VOLUME_INFORMATION",
31 "IRP_MJ_DIRECTORY_CONTROL",
32 "IRP_MJ_FILE_SYSTEM_CONTROL",
33 "IRP_MJ_DEVICE_CONTROL",
34 "IRP_MJ_INTERNAL_DEVICE_CONTROL",
35 "IRP_MJ_SHUTDOWN",
36 "IRP_MJ_LOCK_CONTROL",
37 "IRP_MJ_CLEANUP",
38 "IRP_MJ_CREATE_MAILSLOT",
39 "IRP_MJ_QUERY_SECURITY",
40 "IRP_MJ_SET_SECURITY",
41 "IRP_MJ_POWER",
42 "IRP_MJ_SYSTEM_CONTROL",
43 "IRP_MJ_DEVICE_CHANGE",
44 "IRP_MJ_QUERY_QUOTA",
45 "IRP_MJ_SET_QUOTA",
46 "IRP_MJ_PNP",
47 "IRP_MJ_MAXIMUM_FUNCTION"
48 };
49
50 /* FUNCTIONS ****************************************************************/
51
52 static LONG QueueCount = 0;
53
54 static NTSTATUS VfatLockControl(
55 IN PVFAT_IRP_CONTEXT IrpContext
56 )
57 {
58 PVFATFCB Fcb;
59 NTSTATUS Status;
60
61 DPRINT("VfatLockControl(IrpContext %p)\n", IrpContext);
62
63 ASSERT(IrpContext);
64
65 Fcb = (PVFATFCB)IrpContext->FileObject->FsContext;
66
67 if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
68 {
69 Status = STATUS_INVALID_DEVICE_REQUEST;
70 goto Fail;
71 }
72
73 if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
74 {
75 Status = STATUS_INVALID_PARAMETER;
76 goto Fail;
77 }
78
79 Status = FsRtlProcessFileLock(&Fcb->FileLock,
80 IrpContext->Irp,
81 NULL
82 );
83
84 VfatFreeIrpContext(IrpContext);
85 return Status;
86
87 Fail:;
88 IrpContext->Irp->IoStatus.Status = Status;
89 IoCompleteRequest(IrpContext->Irp, (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
90 VfatFreeIrpContext(IrpContext);
91 return Status;
92 }
93
94 static NTSTATUS
95 VfatDispatchRequest (IN PVFAT_IRP_CONTEXT IrpContext)
96 {
97 DPRINT ("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext,
98 IrpContext->MajorFunction >= IRP_MJ_MAXIMUM_FUNCTION ? "????" : MajorFunctionNames[IrpContext->MajorFunction]);
99
100 ASSERT(IrpContext);
101
102 switch (IrpContext->MajorFunction)
103 {
104 case IRP_MJ_CLOSE:
105 return VfatClose (IrpContext);
106 case IRP_MJ_CREATE:
107 return VfatCreate (IrpContext);
108 case IRP_MJ_READ:
109 return VfatRead (IrpContext);
110 case IRP_MJ_WRITE:
111 return VfatWrite (IrpContext);
112 case IRP_MJ_FILE_SYSTEM_CONTROL:
113 return VfatFileSystemControl(IrpContext);
114 case IRP_MJ_QUERY_INFORMATION:
115 return VfatQueryInformation (IrpContext);
116 case IRP_MJ_SET_INFORMATION:
117 return VfatSetInformation (IrpContext);
118 case IRP_MJ_DIRECTORY_CONTROL:
119 return VfatDirectoryControl(IrpContext);
120 case IRP_MJ_QUERY_VOLUME_INFORMATION:
121 return VfatQueryVolumeInformation(IrpContext);
122 case IRP_MJ_SET_VOLUME_INFORMATION:
123 return VfatSetVolumeInformation(IrpContext);
124 case IRP_MJ_LOCK_CONTROL:
125 return VfatLockControl(IrpContext);
126 case IRP_MJ_CLEANUP:
127 return VfatCleanup(IrpContext);
128 case IRP_MJ_FLUSH_BUFFERS:
129 return VfatFlush(IrpContext);
130 default:
131 DPRINT1 ("Unexpected major function %x\n", IrpContext->MajorFunction);
132 IrpContext->Irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
133 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
134 VfatFreeIrpContext(IrpContext);
135 return STATUS_DRIVER_INTERNAL_ERROR;
136 }
137 }
138
139 NTSTATUS NTAPI VfatBuildRequest (
140 IN PDEVICE_OBJECT DeviceObject,
141 IN PIRP Irp)
142 {
143 NTSTATUS Status;
144 PVFAT_IRP_CONTEXT IrpContext;
145
146 DPRINT ("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
147
148 ASSERT(DeviceObject);
149 ASSERT(Irp);
150 IrpContext = VfatAllocateIrpContext(DeviceObject, Irp);
151 if (IrpContext == NULL)
152 {
153 Status = STATUS_INSUFFICIENT_RESOURCES;
154 Irp->IoStatus.Status = Status;
155 IoCompleteRequest (Irp, IO_NO_INCREMENT);
156 }
157 else
158 {
159 FsRtlEnterFileSystem();
160 Status = VfatDispatchRequest (IrpContext);
161 FsRtlExitFileSystem();
162 }
163 return Status;
164 }
165
166 VOID VfatFreeIrpContext (PVFAT_IRP_CONTEXT IrpContext)
167 {
168 ASSERT(IrpContext);
169 ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext);
170 }
171
172 PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT DeviceObject, PIRP Irp)
173 {
174 PVFAT_IRP_CONTEXT IrpContext;
175 /*PIO_STACK_LOCATION Stack;*/
176 UCHAR MajorFunction;
177 DPRINT ("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
178
179 ASSERT(DeviceObject);
180 ASSERT(Irp);
181
182 IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList);
183 if (IrpContext)
184 {
185 RtlZeroMemory(IrpContext, sizeof(VFAT_IRP_CONTEXT));
186 IrpContext->Irp = Irp;
187 IrpContext->DeviceObject = DeviceObject;
188 IrpContext->DeviceExt = DeviceObject->DeviceExtension;
189 IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp);
190 ASSERT(IrpContext->Stack);
191 MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
192 IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
193 IrpContext->FileObject = IrpContext->Stack->FileObject;
194 IrpContext->Flags = 0;
195 if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
196 MajorFunction == IRP_MJ_DEVICE_CONTROL ||
197 MajorFunction == IRP_MJ_SHUTDOWN)
198 {
199 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
200 }
201 else if (MajorFunction != IRP_MJ_CLEANUP &&
202 MajorFunction != IRP_MJ_CLOSE &&
203 IoIsOperationSynchronous(Irp))
204 {
205 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
206 }
207 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
208 IrpContext->RefCount = 0;
209 }
210 return IrpContext;
211 }
212
213 static VOID NTAPI VfatDoRequest (PVOID IrpContext)
214 {
215 InterlockedDecrement(&QueueCount);
216 DPRINT ("VfatDoRequest (IrpContext %p), MajorFunction %x, %d\n", IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount);
217 FsRtlEnterFileSystem();
218 VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
219 FsRtlExitFileSystem();
220
221 }
222
223 NTSTATUS VfatQueueRequest(PVFAT_IRP_CONTEXT IrpContext)
224 {
225 InterlockedIncrement(&QueueCount);
226 DPRINT ("VfatQueueRequest (IrpContext %p), %d\n", IrpContext, QueueCount);
227
228 ASSERT(IrpContext != NULL);
229 ASSERT(IrpContext->Irp != NULL);
230
231 IrpContext->Flags |= IRPCONTEXT_CANWAIT;
232 IoMarkIrpPending (IrpContext->Irp);
233 ExInitializeWorkItem (&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext);
234 ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
235 return STATUS_PENDING;
236 }
237
238 PVOID VfatGetUserBuffer(IN PIRP Irp)
239 {
240 ASSERT(Irp);
241
242 if (Irp->MdlAddress)
243 {
244 /* This call may be in the paging path, so use maximum priority */
245 /* FIXME: call with normal priority in the non-paging path */
246 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
247 }
248 else
249 {
250 return Irp->UserBuffer;
251 }
252 }
253
254 NTSTATUS VfatLockUserBuffer(IN PIRP Irp, IN ULONG Length, IN LOCK_OPERATION Operation)
255 {
256 ASSERT(Irp);
257
258 if (Irp->MdlAddress)
259 {
260 return STATUS_SUCCESS;
261 }
262
263 IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
264
265 if (!Irp->MdlAddress)
266 {
267 return STATUS_INSUFFICIENT_RESOURCES;
268 }
269
270 MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
271
272 return STATUS_SUCCESS;
273 }
274
275