All:
[reactos.git] / reactos / drivers / fs / vfat / finfo.c
1 /* $Id: finfo.c,v 1.12 2002/03/18 22:37:12 hbirr Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/finfo.c
6 * PURPOSE: VFAT Filesystem
7 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
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 NTSTATUS
24 VfatGetStandardInformation(PVFATFCB FCB,
25 PDEVICE_OBJECT DeviceObject,
26 PFILE_STANDARD_INFORMATION StandardInfo,
27 PULONG BufferLength)
28 /*
29 * FUNCTION: Retrieve the standard file information
30 */
31 {
32 PDEVICE_EXTENSION DeviceExtension;
33
34 if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
35 return STATUS_BUFFER_OVERFLOW;
36
37 DeviceExtension = DeviceObject->DeviceExtension;
38 /* PRECONDITION */
39 assert (DeviceExtension != NULL);
40 assert (DeviceExtension->FatInfo.BytesPerCluster != 0);
41 assert (StandardInfo != NULL);
42 assert (FCB != NULL);
43
44 RtlZeroMemory(StandardInfo,
45 sizeof(FILE_STANDARD_INFORMATION));
46
47 StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
48 StandardInfo->EndOfFile = FCB->RFCB.FileSize;
49 StandardInfo->NumberOfLinks = 0;
50 StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
51 StandardInfo->Directory = FCB->entry.Attrib & 0x10 ? TRUE : FALSE;
52
53 *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
54 return(STATUS_SUCCESS);
55 }
56
57 static NTSTATUS
58 VfatSetPositionInformation(PFILE_OBJECT FileObject,
59 PVFATFCB FCB,
60 PDEVICE_OBJECT DeviceObject,
61 PFILE_POSITION_INFORMATION PositionInfo)
62 {
63 DPRINT ("FsdSetPositionInformation()\n");
64
65 DPRINT ("PositionInfo %x\n", PositionInfo);
66 DPRINT ("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart);
67 memcpy (&FileObject->CurrentByteOffset, &PositionInfo->CurrentByteOffset,
68 sizeof (LARGE_INTEGER));
69
70 return (STATUS_SUCCESS);
71 }
72
73 static NTSTATUS
74 VfatGetPositionInformation(PFILE_OBJECT FileObject,
75 PVFATFCB FCB,
76 PDEVICE_OBJECT DeviceObject,
77 PFILE_POSITION_INFORMATION PositionInfo,
78 PULONG BufferLength)
79 {
80 DPRINT ("VfatGetPositionInformation()\n");
81
82 if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
83 return STATUS_BUFFER_OVERFLOW;
84
85 PositionInfo->CurrentByteOffset.QuadPart =
86 FileObject->CurrentByteOffset.QuadPart;
87
88 DPRINT("Getting position %I64x\n",
89 PositionInfo->CurrentByteOffset.QuadPart);
90
91 *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
92 return(STATUS_SUCCESS);
93 }
94
95 static NTSTATUS
96 VfatGetBasicInformation(PFILE_OBJECT FileObject,
97 PVFATFCB FCB,
98 PDEVICE_OBJECT DeviceObject,
99 PFILE_BASIC_INFORMATION BasicInfo,
100 PULONG BufferLength)
101 {
102 DPRINT("VfatGetBasicInformation()\n");
103
104 if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
105 return STATUS_BUFFER_OVERFLOW;
106
107 FsdDosDateTimeToFileTime(FCB->entry.CreationDate,
108 FCB->entry.CreationTime,
109 &BasicInfo->CreationTime);
110 FsdDosDateTimeToFileTime(FCB->entry.AccessDate,
111 0,
112 &BasicInfo->LastAccessTime);
113 FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,
114 FCB->entry.UpdateTime,
115 &BasicInfo->LastWriteTime);
116 FsdDosDateTimeToFileTime(FCB->entry.UpdateDate,
117 FCB->entry.UpdateTime,
118 &BasicInfo->ChangeTime);
119
120 BasicInfo->FileAttributes = FCB->entry.Attrib;
121 DPRINT("Getting attributes %x\n", BasicInfo->FileAttributes);
122
123 *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
124 return(STATUS_SUCCESS);
125 }
126
127
128 static NTSTATUS
129 VfatSetDispositionInformation(PFILE_OBJECT FileObject,
130 PVFATFCB FCB,
131 PDEVICE_OBJECT DeviceObject,
132 PFILE_DISPOSITION_INFORMATION DispositionInfo)
133 {
134 KIRQL oldIrql;
135 VFATFCB tmpFcb;
136 WCHAR star[2];
137 ULONG Index;
138 NTSTATUS Status = STATUS_SUCCESS;
139 int count;
140
141 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
142
143 DPRINT ("FsdSetDispositionInformation()\n");
144
145 assert (DeviceExt != NULL);
146 assert (DeviceExt->FatInfo.BytesPerCluster != 0);
147 assert (FCB != NULL);
148
149 if (!wcscmp(FCB->PathName, L"\\") || !wcscmp(FCB->ObjectName, L"..")
150 || !wcscmp(FCB->ObjectName, L"."))
151 {
152 // we cannot delete a '.', '..' or the root directory
153 return STATUS_ACCESS_DENIED;
154 }
155 if (DispositionInfo->DoDeleteFile)
156 {
157 KeAcquireSpinLock (&DeviceExt->FcbListLock, &oldIrql);
158 count = FCB->RefCount;
159 if (FCB->RefCount > 1)
160 Status = STATUS_ACCESS_DENIED;
161 else
162 {
163 FCB->Flags |= FCB_DELETE_PENDING;
164 FileObject->DeletePending = TRUE;
165 }
166 KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
167 DPRINT("RefCount:%d\n", count);
168 if (NT_SUCCESS(Status) && vfatFCBIsDirectory(DeviceExt, FCB))
169 {
170 memset (&tmpFcb, 0, sizeof(VFATFCB));
171 tmpFcb.ObjectName = tmpFcb.PathName;
172 star[0] = L'*';
173 star[1] = 0;
174 // skip '.' and '..', start by 2
175 Index = 2;
176 Status = FindFile (DeviceExt, &tmpFcb, FCB, star, &Index, NULL);
177 if (NT_SUCCESS(Status))
178 {
179 DPRINT1("found: \'%S\'\n", tmpFcb.PathName);
180 Status = STATUS_DIRECTORY_NOT_EMPTY;
181 FCB->Flags &= ~FCB_DELETE_PENDING;
182 FileObject->DeletePending = FALSE;
183 }
184 else
185 {
186 Status = STATUS_SUCCESS;
187 }
188 }
189 }
190 else
191 FileObject->DeletePending = FALSE;
192 return Status;
193 }
194
195 static NTSTATUS
196 VfatGetNameInformation(PFILE_OBJECT FileObject,
197 PVFATFCB FCB,
198 PDEVICE_OBJECT DeviceObject,
199 PFILE_NAME_INFORMATION NameInfo,
200 PULONG BufferLength)
201 /*
202 * FUNCTION: Retrieve the file name information
203 */
204 {
205 ULONG NameLength;
206
207 assert (NameInfo != NULL);
208 assert (FCB != NULL);
209
210 NameLength = wcslen(FCB->PathName) * sizeof(WCHAR);
211 if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + NameLength)
212 return STATUS_BUFFER_OVERFLOW;
213
214 NameInfo->FileNameLength = NameLength;
215 memcpy(NameInfo->FileName,
216 FCB->PathName,
217 NameLength + sizeof(WCHAR));
218
219 *BufferLength -=
220 (sizeof(FILE_NAME_INFORMATION) + NameLength + sizeof(WCHAR));
221
222 return STATUS_SUCCESS;
223 }
224
225 static NTSTATUS
226 VfatGetInternalInformation(PVFATFCB Fcb,
227 PFILE_INTERNAL_INFORMATION InternalInfo,
228 PULONG BufferLength)
229 {
230 assert (InternalInfo);
231 assert (Fcb);
232
233 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
234 return STATUS_BUFFER_OVERFLOW;
235 // FIXME: get a real index, that can be used in a create operation
236 InternalInfo->IndexNumber.QuadPart = 0;
237 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
238 return STATUS_SUCCESS;
239 }
240
241
242
243 NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
244 /*
245 * FUNCTION: Retrieve the specified file information
246 */
247 {
248 FILE_INFORMATION_CLASS FileInformationClass;
249 PVFATFCB FCB = NULL;
250
251 NTSTATUS RC = STATUS_SUCCESS;
252 PVOID SystemBuffer;
253 ULONG BufferLength;
254
255 /* PRECONDITION */
256 assert (IrpContext);
257
258 /* INITIALIZATION */
259 FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
260 FCB = ((PVFATCCB) IrpContext->FileObject->FsContext2)->pFcb;
261
262 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
263 BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
264
265 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
266 {
267 if (!ExAcquireResourceSharedLite(&FCB->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
268 {
269 return VfatQueueRequest (IrpContext);
270 }
271 }
272
273
274 switch (FileInformationClass)
275 {
276 case FileStandardInformation:
277 RC = VfatGetStandardInformation(FCB,
278 IrpContext->DeviceObject,
279 SystemBuffer,
280 &BufferLength);
281 break;
282 case FilePositionInformation:
283 RC = VfatGetPositionInformation(IrpContext->FileObject,
284 FCB,
285 IrpContext->DeviceObject,
286 SystemBuffer,
287 &BufferLength);
288 break;
289 case FileBasicInformation:
290 RC = VfatGetBasicInformation(IrpContext->FileObject,
291 FCB,
292 IrpContext->DeviceObject,
293 SystemBuffer,
294 &BufferLength);
295 break;
296 case FileNameInformation:
297 RC = VfatGetNameInformation(IrpContext->FileObject,
298 FCB,
299 IrpContext->DeviceObject,
300 SystemBuffer,
301 &BufferLength);
302 break;
303 case FileInternalInformation:
304 RC = VfatGetInternalInformation(FCB,
305 SystemBuffer,
306 &BufferLength);
307 break;
308 case FileAlternateNameInformation:
309 case FileAllInformation:
310 RC = STATUS_NOT_IMPLEMENTED;
311 break;
312 default:
313 RC = STATUS_NOT_SUPPORTED;
314 }
315
316 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
317 {
318 ExReleaseResourceLite(&FCB->MainResource);
319 }
320 IrpContext->Irp->IoStatus.Status = RC;
321 if (NT_SUCCESS(RC))
322 IrpContext->Irp->IoStatus.Information =
323 IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
324 else
325 IrpContext->Irp->IoStatus.Information = 0;
326 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
327 VfatFreeIrpContext(IrpContext);
328
329 return RC;
330 }
331
332 NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
333 /*
334 * FUNCTION: Retrieve the specified file information
335 */
336 {
337 FILE_INFORMATION_CLASS FileInformationClass;
338 PVFATFCB FCB = NULL;
339 NTSTATUS RC = STATUS_SUCCESS;
340 PVOID SystemBuffer;
341
342 /* PRECONDITION */
343 assert(IrpContext);
344
345 DPRINT("VfatSetInformation(IrpContext %x)\n", IrpContext);
346
347 /* INITIALIZATION */
348 FileInformationClass = IrpContext->Stack->Parameters.SetFile.FileInformationClass;
349 FCB = ((PVFATCCB) IrpContext->FileObject->FsContext2)->pFcb;
350 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
351
352 DPRINT("FileInformationClass %d\n", FileInformationClass);
353 DPRINT("SystemBuffer %x\n", SystemBuffer);
354
355 if (FCB->Flags & FCB_IS_PAGE_FILE)
356 {
357 if (!ExAcquireResourceExclusiveLite(&FCB->PagingIoResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
358 {
359 return VfatQueueRequest (IrpContext);
360 }
361 }
362 else
363 {
364 if (!ExAcquireResourceExclusiveLite(&FCB->MainResource, IrpContext->Flags & IRPCONTEXT_CANWAIT))
365 {
366 return VfatQueueRequest (IrpContext);
367 }
368 }
369
370 switch (FileInformationClass)
371 {
372 case FilePositionInformation:
373 RC = VfatSetPositionInformation(IrpContext->FileObject,
374 FCB,
375 IrpContext->DeviceObject,
376 SystemBuffer);
377 break;
378 case FileDispositionInformation:
379 RC = VfatSetDispositionInformation(IrpContext->FileObject,
380 FCB,
381 IrpContext->DeviceObject,
382 SystemBuffer);
383 break;
384 case FileBasicInformation:
385 case FileAllocationInformation:
386 case FileEndOfFileInformation:
387 case FileRenameInformation:
388 RC = STATUS_NOT_IMPLEMENTED;
389 break;
390 default:
391 RC = STATUS_NOT_SUPPORTED;
392 }
393
394 if (FCB->Flags & FCB_IS_PAGE_FILE)
395 {
396 ExReleaseResourceLite(&FCB->PagingIoResource);
397 }
398 else
399 {
400 ExReleaseResourceLite(&FCB->MainResource);
401 }
402
403 IrpContext->Irp->IoStatus.Status = RC;
404 IrpContext->Irp->IoStatus.Information = 0;
405 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
406 VfatFreeIrpContext(IrpContext);
407
408 return RC;
409 }
410
411 /* EOF */