update for HEAD-2003050101
[reactos.git] / drivers / fs / vfat / misc.c
1 /* $Id$
2  *
3  * COPYRIGHT:        See COPYING in the top level directory
4  * PROJECT:          ReactOS kernel
5  * FILE:             services/fs/vfat/misc.c
6  * PURPOSE:          VFAT Filesystem
7  * PROGRAMMER:       Hartmut Birr
8  *
9  */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <wchar.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 #include "vfat.h"
20
21 /* FUNCTIONS ****************************************************************/
22
23 static LONG QueueCount = 0;
24
25 NTSTATUS VfatDispatchRequest (
26         IN PVFAT_IRP_CONTEXT IrpContext)
27 {
28    DPRINT ("VfatDispatchRequest (IrpContext %x), MajorFunction %x\n", IrpContext, IrpContext->MajorFunction);
29
30    assert (IrpContext);
31
32    switch (IrpContext->MajorFunction)
33    {
34       case IRP_MJ_CLOSE:
35          return VfatClose (IrpContext);
36       case IRP_MJ_CREATE:
37          return VfatCreate (IrpContext);
38       case IRP_MJ_READ:
39          return VfatRead (IrpContext);
40       case IRP_MJ_WRITE:
41          return VfatWrite (IrpContext);
42       case IRP_MJ_FILE_SYSTEM_CONTROL:
43          return VfatFileSystemControl(IrpContext);
44       case IRP_MJ_QUERY_INFORMATION:
45          return VfatQueryInformation (IrpContext);
46       case IRP_MJ_SET_INFORMATION:
47          return VfatSetInformation (IrpContext);
48       case IRP_MJ_DIRECTORY_CONTROL:
49          return VfatDirectoryControl(IrpContext);
50       case IRP_MJ_QUERY_VOLUME_INFORMATION:
51          return VfatQueryVolumeInformation(IrpContext);
52       case IRP_MJ_SET_VOLUME_INFORMATION:
53          return VfatSetVolumeInformation(IrpContext);
54       case IRP_MJ_LOCK_CONTROL:
55          return VfatLockControl(IrpContext);
56       case IRP_MJ_CLEANUP:
57          return VfatCleanup(IrpContext);
58       case IRP_MJ_FLUSH_BUFFERS:
59          return VfatFlush(IrpContext);
60       default:
61          DPRINT1 ("Unexpected major function %x\n", IrpContext->MajorFunction);
62          IrpContext->Irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
63          IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
64          VfatFreeIrpContext(IrpContext);
65          return STATUS_DRIVER_INTERNAL_ERROR;
66    }
67 }
68
69 NTSTATUS VfatLockControl(
70    IN PVFAT_IRP_CONTEXT IrpContext
71    )
72 {
73    PVFATFCB Fcb;
74    NTSTATUS Status;
75
76    DPRINT("VfatLockControl(IrpContext %x)\n", IrpContext);
77  
78    assert(IrpContext);
79
80    Fcb = (PVFATFCB)IrpContext->FileObject->FsContext;
81
82    if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
83    {
84       Status = STATUS_INVALID_DEVICE_REQUEST;
85       goto Fail;
86    }
87
88    if (Fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
89    {
90       Status = STATUS_INVALID_PARAMETER;
91       goto Fail;
92    }
93
94    Status = FsRtlProcessFileLock(&Fcb->FileLock,
95                                  IrpContext->Irp,
96                                  NULL
97                                  );
98
99    VfatFreeIrpContext(IrpContext);
100    return Status;
101
102 Fail:;
103    IrpContext->Irp->IoStatus.Status = Status;
104    IofCompleteRequest(IrpContext->Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
105    VfatFreeIrpContext(IrpContext);
106    return Status;
107 }
108
109 NTSTATUS STDCALL VfatBuildRequest (
110         IN PDEVICE_OBJECT DeviceObject,
111         IN PIRP Irp)
112 {
113    NTSTATUS Status;
114    PVFAT_IRP_CONTEXT IrpContext;
115
116    DPRINT ("VfatBuildRequest (DeviceObject %x, Irp %x)\n", DeviceObject, Irp);
117
118    assert (DeviceObject);
119    assert (Irp);
120    IrpContext = VfatAllocateIrpContext(DeviceObject, Irp);
121    if (IrpContext == NULL)
122    {
123       Status = STATUS_INSUFFICIENT_RESOURCES;
124       Irp->IoStatus.Status = Status;
125       IoCompleteRequest (Irp, IO_NO_INCREMENT);
126    }
127    else
128    {
129       if (KeGetCurrentIrql() <= PASSIVE_LEVEL)
130       {
131          FsRtlEnterFileSystem();
132       }
133       else
134       {
135          DPRINT1("Vfat is entered at irql = %d\n", KeGetCurrentIrql());
136       }
137       Status = VfatDispatchRequest (IrpContext);
138       if (KeGetCurrentIrql() <= PASSIVE_LEVEL)
139       {
140          FsRtlExitFileSystem();
141       }
142    }
143    return Status;
144 }
145
146 VOID VfatFreeIrpContext (PVFAT_IRP_CONTEXT IrpContext)
147 {
148    assert (IrpContext);
149    ExFreeToNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList, IrpContext);
150 }
151
152 PVFAT_IRP_CONTEXT VfatAllocateIrpContext(PDEVICE_OBJECT DeviceObject, PIRP Irp)
153 {
154    PVFAT_IRP_CONTEXT IrpContext;
155    PIO_STACK_LOCATION Stack;
156    UCHAR MajorFunction;
157    DPRINT ("VfatAllocateIrpContext(DeviceObject %x, Irp %x)\n", DeviceObject, Irp);
158
159    assert (DeviceObject);
160    assert (Irp);
161
162    IrpContext = ExAllocateFromNPagedLookasideList(&VfatGlobalData->IrpContextLookasideList);
163    if (IrpContext)
164    {
165       RtlZeroMemory(IrpContext, sizeof(IrpContext));
166       IrpContext->Irp = Irp;
167       IrpContext->DeviceObject = DeviceObject;
168       IrpContext->DeviceExt = DeviceObject->DeviceExtension;
169       IrpContext->Stack = IoGetCurrentIrpStackLocation(Irp);
170       assert (IrpContext->Stack);
171       MajorFunction = IrpContext->MajorFunction = IrpContext->Stack->MajorFunction;
172       IrpContext->MinorFunction = IrpContext->Stack->MinorFunction;
173       IrpContext->FileObject = IrpContext->Stack->FileObject;
174       if (MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
175           MajorFunction == IRP_MJ_DEVICE_CONTROL ||
176           MajorFunction == IRP_MJ_SHUTDOWN)
177       {
178          IrpContext->Flags |= IRPCONTEXT_CANWAIT;
179       }
180       else if (MajorFunction != IRP_MJ_CLEANUP &&
181                MajorFunction != IRP_MJ_CLOSE &&
182                IoIsOperationSynchronous(Irp))
183       {
184          IrpContext->Flags |= IRPCONTEXT_CANWAIT;
185       }
186    }
187    return IrpContext;
188 }
189
190 VOID STDCALL VfatDoRequest (PVOID IrpContext)
191 {
192    ULONG Count = InterlockedDecrement(&QueueCount);
193    DPRINT ("VfatDoRequest (IrpContext %x), MajorFunction %x, %d\n", IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, Count);
194    VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
195
196 }
197
198 NTSTATUS VfatQueueRequest(PVFAT_IRP_CONTEXT IrpContext)
199 {
200    ULONG Count = InterlockedIncrement(&QueueCount);
201    DPRINT ("VfatQueueRequest (IrpContext %x), %d\n", IrpContext, Count);
202
203    assert (IrpContext != NULL);
204    assert (IrpContext->Irp != NULL);
205
206    IrpContext->Flags |= IRPCONTEXT_CANWAIT;
207    IoMarkIrpPending (IrpContext->Irp);
208    ExInitializeWorkItem (&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext);
209    ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
210    return STATUS_PENDING;
211 }
212
213 PVOID VfatGetUserBuffer(IN PIRP Irp)
214 {
215    assert(Irp);
216
217    if (Irp->MdlAddress)
218    {
219       return MmGetSystemAddressForMdl(Irp->MdlAddress);
220    }
221    else
222    {
223       return Irp->UserBuffer;
224    }
225 }
226
227 NTSTATUS VfatLockUserBuffer(IN PIRP Irp, IN ULONG Length, IN LOCK_OPERATION Operation)
228 {
229    assert(Irp);
230
231    if (Irp->MdlAddress)
232    {
233       return STATUS_SUCCESS;
234    }
235
236    IoAllocateMdl(Irp->UserBuffer, Length, FALSE, FALSE, Irp);
237
238    if (!Irp->MdlAddress)
239    {
240       return STATUS_INSUFFICIENT_RESOURCES;
241    }
242
243    MmProbeAndLockPages(Irp->MdlAddress, Irp->RequestorMode, Operation);
244
245    return STATUS_SUCCESS;
246 }
247
248