2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/dir.c
5 * PURPOSE: VFAT Filesystem : directory control
11 /* INCLUDES *****************************************************************/
16 /* FUNCTIONS ****************************************************************/
18 /* Function like DosDateTimeToFileTime */
20 FsdDosDateTimeToSystemTime(PDEVICE_EXTENSION DeviceExt
,
23 PLARGE_INTEGER SystemTime
)
25 PDOSTIME pdtime
= (PDOSTIME
)&DosTime
;
26 PDOSDATE pddate
= (PDOSDATE
)&DosDate
;
27 TIME_FIELDS TimeFields
;
28 LARGE_INTEGER LocalTime
;
30 if (SystemTime
== NULL
)
33 TimeFields
.Milliseconds
= 0;
34 TimeFields
.Second
= pdtime
->Second
* 2;
35 TimeFields
.Minute
= pdtime
->Minute
;
36 TimeFields
.Hour
= pdtime
->Hour
;
38 TimeFields
.Day
= pddate
->Day
;
39 TimeFields
.Month
= pddate
->Month
;
40 TimeFields
.Year
= (CSHORT
)(DeviceExt
->BaseDateYear
+ pddate
->Year
);
42 RtlTimeFieldsToTime(&TimeFields
, &LocalTime
);
43 ExLocalTimeToSystemTime(&LocalTime
, SystemTime
);
48 /* Function like FileTimeToDosDateTime */
50 FsdSystemTimeToDosDateTime(PDEVICE_EXTENSION DeviceExt
,
51 PLARGE_INTEGER SystemTime
,
55 PDOSTIME pdtime
= (PDOSTIME
)pDosTime
;
56 PDOSDATE pddate
= (PDOSDATE
)pDosDate
;
57 TIME_FIELDS TimeFields
;
58 LARGE_INTEGER LocalTime
;
60 if (SystemTime
== NULL
)
63 ExSystemTimeToLocalTime(SystemTime
, &LocalTime
);
64 RtlTimeToTimeFields(&LocalTime
, &TimeFields
);
68 pdtime
->Second
= TimeFields
.Second
/ 2;
69 pdtime
->Minute
= TimeFields
.Minute
;
70 pdtime
->Hour
= TimeFields
.Hour
;
75 pddate
->Day
= TimeFields
.Day
;
76 pddate
->Month
= TimeFields
.Month
;
77 pddate
->Year
= (USHORT
) (TimeFields
.Year
- DeviceExt
->BaseDateYear
);
83 #define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG)))
86 VfatGetFileNameInformation(PVFAT_DIRENTRY_CONTEXT DirContext
,
87 PFILE_NAMES_INFORMATION pInfo
,
90 if ((sizeof(FILE_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
91 return STATUS_BUFFER_OVERFLOW
;
93 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
94 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) +
95 DirContext
->LongNameU
.Length
);
97 RtlCopyMemory(pInfo
->FileName
,
98 DirContext
->LongNameU
.Buffer
,
99 DirContext
->LongNameU
.Length
);
101 return STATUS_SUCCESS
;
105 VfatGetFileDirectoryInformation(PVFAT_DIRENTRY_CONTEXT DirContext
,
106 PDEVICE_EXTENSION DeviceExt
,
107 PFILE_DIRECTORY_INFORMATION pInfo
,
110 if ((sizeof(FILE_DIRECTORY_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
111 return STATUS_BUFFER_OVERFLOW
;
113 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
114 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) +
115 DirContext
->LongNameU
.Length
);
116 /* pInfo->FileIndex = ; */
118 RtlCopyMemory(pInfo
->FileName
,
119 DirContext
->LongNameU
.Buffer
,
120 DirContext
->LongNameU
.Length
);
122 if (DeviceExt
->Flags
& VCB_IS_FATX
)
124 FsdDosDateTimeToSystemTime(DeviceExt
,
125 DirContext
->DirEntry
.FatX
.CreationDate
,
126 DirContext
->DirEntry
.FatX
.CreationTime
,
127 &pInfo
->CreationTime
);
128 FsdDosDateTimeToSystemTime(DeviceExt
,
129 DirContext
->DirEntry
.FatX
.AccessDate
,
130 DirContext
->DirEntry
.FatX
.AccessTime
,
131 &pInfo
->LastAccessTime
);
132 FsdDosDateTimeToSystemTime(DeviceExt
,
133 DirContext
->DirEntry
.FatX
.UpdateDate
,
134 DirContext
->DirEntry
.FatX
.UpdateTime
,
135 &pInfo
->LastWriteTime
);
137 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
139 if (DirContext
->DirEntry
.FatX
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
141 pInfo
->EndOfFile
.QuadPart
= 0;
142 pInfo
->AllocationSize
.QuadPart
= 0;
146 pInfo
->EndOfFile
.u
.HighPart
= 0;
147 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
148 /* Make allocsize a rounded up multiple of BytesPerCluster */
149 pInfo
->AllocationSize
.u
.HighPart
= 0;
150 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
151 DeviceExt
->FatInfo
.BytesPerCluster
);
154 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
158 FsdDosDateTimeToSystemTime(DeviceExt
,
159 DirContext
->DirEntry
.Fat
.CreationDate
,
160 DirContext
->DirEntry
.Fat
.CreationTime
,
161 &pInfo
->CreationTime
);
162 FsdDosDateTimeToSystemTime(DeviceExt
,
163 DirContext
->DirEntry
.Fat
.AccessDate
,
165 &pInfo
->LastAccessTime
);
166 FsdDosDateTimeToSystemTime(DeviceExt
,
167 DirContext
->DirEntry
.Fat
.UpdateDate
,
168 DirContext
->DirEntry
.Fat
.UpdateTime
,
169 &pInfo
->LastWriteTime
);
171 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
173 if (DirContext
->DirEntry
.Fat
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
175 pInfo
->EndOfFile
.QuadPart
= 0;
176 pInfo
->AllocationSize
.QuadPart
= 0;
180 pInfo
->EndOfFile
.u
.HighPart
= 0;
181 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
182 /* Make allocsize a rounded up multiple of BytesPerCluster */
183 pInfo
->AllocationSize
.u
.HighPart
= 0;
184 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
,
185 DeviceExt
->FatInfo
.BytesPerCluster
);
188 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
191 return STATUS_SUCCESS
;
195 VfatGetFileFullDirectoryInformation(PVFAT_DIRENTRY_CONTEXT DirContext
,
196 PDEVICE_EXTENSION DeviceExt
,
197 PFILE_FULL_DIR_INFORMATION pInfo
,
200 if ((sizeof(FILE_FULL_DIR_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
201 return STATUS_BUFFER_OVERFLOW
;
203 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
204 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION
) +
205 DirContext
->LongNameU
.Length
);
206 /* pInfo->FileIndex = ; */
207 /* pInfo->EaSize = ; */
209 RtlCopyMemory(pInfo
->FileName
,
210 DirContext
->LongNameU
.Buffer
,
211 DirContext
->LongNameU
.Length
);
213 if (DeviceExt
->Flags
& VCB_IS_FATX
)
215 FsdDosDateTimeToSystemTime(DeviceExt
,
216 DirContext
->DirEntry
.FatX
.CreationDate
,
217 DirContext
->DirEntry
.FatX
.CreationTime
,
218 &pInfo
->CreationTime
);
219 FsdDosDateTimeToSystemTime(DeviceExt
,
220 DirContext
->DirEntry
.FatX
.AccessDate
,
221 DirContext
->DirEntry
.FatX
.AccessTime
,
222 &pInfo
->LastAccessTime
);
223 FsdDosDateTimeToSystemTime(DeviceExt
,
224 DirContext
->DirEntry
.FatX
.UpdateDate
,
225 DirContext
->DirEntry
.FatX
.UpdateTime
,
226 &pInfo
->LastWriteTime
);
228 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
229 pInfo
->EndOfFile
.u
.HighPart
= 0;
230 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
231 /* Make allocsize a rounded up multiple of BytesPerCluster */
232 pInfo
->AllocationSize
.u
.HighPart
= 0;
233 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
234 DeviceExt
->FatInfo
.BytesPerCluster
);
235 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
239 FsdDosDateTimeToSystemTime(DeviceExt
,
240 DirContext
->DirEntry
.Fat
.CreationDate
,
241 DirContext
->DirEntry
.Fat
.CreationTime
,
242 &pInfo
->CreationTime
);
243 FsdDosDateTimeToSystemTime(DeviceExt
,
244 DirContext
->DirEntry
.Fat
.AccessDate
,
246 &pInfo
->LastAccessTime
);
247 FsdDosDateTimeToSystemTime(DeviceExt
,
248 DirContext
->DirEntry
.Fat
.UpdateDate
,
249 DirContext
->DirEntry
.Fat
.UpdateTime
,
250 &pInfo
->LastWriteTime
);
252 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
253 pInfo
->EndOfFile
.u
.HighPart
= 0;
254 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
255 /* Make allocsize a rounded up multiple of BytesPerCluster */
256 pInfo
->AllocationSize
.u
.HighPart
= 0;
257 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
,
258 DeviceExt
->FatInfo
.BytesPerCluster
);
259 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
262 return STATUS_SUCCESS
;
266 VfatGetFileBothInformation(PVFAT_DIRENTRY_CONTEXT DirContext
,
267 PDEVICE_EXTENSION DeviceExt
,
268 PFILE_BOTH_DIR_INFORMATION pInfo
,
271 if ((sizeof(FILE_BOTH_DIR_INFORMATION
) + DirContext
->LongNameU
.Length
) > BufferLength
)
272 return STATUS_BUFFER_OVERFLOW
;
276 if (DeviceExt
->Flags
& VCB_IS_FATX
)
278 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
280 RtlCopyMemory(pInfo
->FileName
,
281 DirContext
->LongNameU
.Buffer
,
282 DirContext
->LongNameU
.Length
);
284 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION
) +
285 DirContext
->LongNameU
.Length
);
286 pInfo
->ShortName
[0] = 0;
287 pInfo
->ShortNameLength
= 0;
288 /* pInfo->FileIndex = ; */
290 FsdDosDateTimeToSystemTime(DeviceExt
,
291 DirContext
->DirEntry
.FatX
.CreationDate
,
292 DirContext
->DirEntry
.FatX
.CreationTime
,
293 &pInfo
->CreationTime
);
294 FsdDosDateTimeToSystemTime(DeviceExt
,
295 DirContext
->DirEntry
.FatX
.AccessDate
,
296 DirContext
->DirEntry
.FatX
.AccessTime
,
297 &pInfo
->LastAccessTime
);
298 FsdDosDateTimeToSystemTime(DeviceExt
,
299 DirContext
->DirEntry
.FatX
.UpdateDate
,
300 DirContext
->DirEntry
.FatX
.UpdateTime
,
301 &pInfo
->LastWriteTime
);
303 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
305 if (DirContext
->DirEntry
.FatX
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
307 pInfo
->EndOfFile
.QuadPart
= 0;
308 pInfo
->AllocationSize
.QuadPart
= 0;
312 pInfo
->EndOfFile
.u
.HighPart
= 0;
313 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
314 /* Make allocsize a rounded up multiple of BytesPerCluster */
315 pInfo
->AllocationSize
.u
.HighPart
= 0;
316 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
317 DeviceExt
->FatInfo
.BytesPerCluster
);
320 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
324 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
325 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION
) +
326 DirContext
->LongNameU
.Length
);
328 RtlCopyMemory(pInfo
->ShortName
,
329 DirContext
->ShortNameU
.Buffer
,
330 DirContext
->ShortNameU
.Length
);
332 pInfo
->ShortNameLength
= (CCHAR
)DirContext
->ShortNameU
.Length
;
334 RtlCopyMemory(pInfo
->FileName
,
335 DirContext
->LongNameU
.Buffer
,
336 DirContext
->LongNameU
.Length
);
338 /* pInfo->FileIndex = ; */
340 FsdDosDateTimeToSystemTime(DeviceExt
,
341 DirContext
->DirEntry
.Fat
.CreationDate
,
342 DirContext
->DirEntry
.Fat
.CreationTime
,
343 &pInfo
->CreationTime
);
344 FsdDosDateTimeToSystemTime(DeviceExt
,
345 DirContext
->DirEntry
.Fat
.AccessDate
,
347 &pInfo
->LastAccessTime
);
348 FsdDosDateTimeToSystemTime(DeviceExt
,
349 DirContext
->DirEntry
.Fat
.UpdateDate
,
350 DirContext
->DirEntry
.Fat
.UpdateTime
,
351 &pInfo
->LastWriteTime
);
353 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
355 if (DirContext
->DirEntry
.Fat
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
357 pInfo
->EndOfFile
.QuadPart
= 0;
358 pInfo
->AllocationSize
.QuadPart
= 0;
362 pInfo
->EndOfFile
.u
.HighPart
= 0;
363 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
364 /* Make allocsize a rounded up multiple of BytesPerCluster */
365 pInfo
->AllocationSize
.u
.HighPart
= 0;
366 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
, DeviceExt
->FatInfo
.BytesPerCluster
);
369 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
372 return STATUS_SUCCESS
;
376 DoQuery(PVFAT_IRP_CONTEXT IrpContext
)
378 NTSTATUS Status
= STATUS_SUCCESS
;
379 LONG BufferLength
= 0;
380 PUNICODE_STRING pSearchPattern
= NULL
;
381 FILE_INFORMATION_CLASS FileInformationClass
;
382 PUCHAR Buffer
= NULL
;
383 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
386 BOOLEAN FirstQuery
= FALSE
;
387 BOOLEAN FirstCall
= TRUE
;
388 VFAT_DIRENTRY_CONTEXT DirContext
;
389 WCHAR LongNameBuffer
[LONGNAME_MAX_LENGTH
+ 1];
390 WCHAR ShortNameBuffer
[13];
392 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
394 pCcb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
395 pFcb
= (PVFATFCB
)IrpContext
->FileObject
->FsContext
;
397 /* Determine Buffer for result : */
398 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
400 /* Do not probe the user buffer until SEH is available */
401 if (IrpContext
->Irp
->RequestorMode
!= KernelMode
&&
402 IrpContext
->Irp
->MdlAddress
== NULL
&&
403 IrpContext
->Irp
->UserBuffer
!= NULL
)
405 ProbeForWrite(IrpContext
->Irp
->UserBuffer
, BufferLength
, 1);
408 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
);
410 if (!ExAcquireResourceSharedLite(&pFcb
->MainResource
,
411 (BOOLEAN
)(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
)))
413 Status
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
414 if (NT_SUCCESS(Status
))
415 Status
= STATUS_PENDING
;
420 /* Obtain the callers parameters */
422 /* HACKHACK: Bug in the MS ntifs.h header:
423 * FileName is really a PUNICODE_STRING, not a PSTRING */
424 pSearchPattern
= (PUNICODE_STRING
)Stack
->Parameters
.QueryDirectory
.FileName
;
426 pSearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
428 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
430 /* Allocate search pattern in case:
431 * -> We don't have one already in context
432 * -> We have been given an input pattern
433 * -> The pattern length is not null
434 * -> The pattern buffer is not null
435 * Otherwise, we'll fall later and allocate a match all (*) pattern
437 if (pSearchPattern
&&
438 pSearchPattern
->Length
!= 0 && pSearchPattern
->Buffer
!= NULL
)
440 if (!pCcb
->SearchPattern
.Buffer
)
443 pCcb
->SearchPattern
.MaximumLength
= pSearchPattern
->Length
+ sizeof(WCHAR
);
444 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
445 pCcb
->SearchPattern
.MaximumLength
,
447 if (!pCcb
->SearchPattern
.Buffer
)
449 ExReleaseResourceLite(&pFcb
->MainResource
);
450 return STATUS_INSUFFICIENT_RESOURCES
;
452 RtlCopyUnicodeString(&pCcb
->SearchPattern
, pSearchPattern
);
453 pCcb
->SearchPattern
.Buffer
[pCcb
->SearchPattern
.Length
/ sizeof(WCHAR
)] = 0;
456 else if (!pCcb
->SearchPattern
.Buffer
)
459 pCcb
->SearchPattern
.MaximumLength
= 2 * sizeof(WCHAR
);
460 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
463 if (!pCcb
->SearchPattern
.Buffer
)
465 ExReleaseResourceLite(&pFcb
->MainResource
);
466 return STATUS_INSUFFICIENT_RESOURCES
;
468 pCcb
->SearchPattern
.Buffer
[0] = L
'*';
469 pCcb
->SearchPattern
.Buffer
[1] = 0;
470 pCcb
->SearchPattern
.Length
= sizeof(WCHAR
);
473 if (IrpContext
->Stack
->Flags
& SL_INDEX_SPECIFIED
)
475 DirContext
.DirIndex
= pCcb
->Entry
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
477 else if (FirstQuery
|| (IrpContext
->Stack
->Flags
& SL_RESTART_SCAN
))
479 DirContext
.DirIndex
= pCcb
->Entry
= 0;
483 DirContext
.DirIndex
= pCcb
->Entry
;
486 DPRINT("Buffer=%p tofind=%wZ\n", Buffer
, &pCcb
->SearchPattern
);
488 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
489 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
490 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
491 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
493 while ((Status
== STATUS_SUCCESS
) && (BufferLength
> 0))
495 Status
= FindFile(IrpContext
->DeviceExt
,
497 &pCcb
->SearchPattern
,
500 pCcb
->Entry
= DirContext
.DirIndex
;
502 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext
.LongNameU
, Status
, pCcb
->Entry
);
505 if (NT_SUCCESS(Status
))
507 switch (FileInformationClass
)
509 case FileNameInformation
:
510 Status
= VfatGetFileNameInformation(&DirContext
,
511 (PFILE_NAMES_INFORMATION
)Buffer
,
515 case FileDirectoryInformation
:
516 Status
= VfatGetFileDirectoryInformation(&DirContext
,
517 IrpContext
->DeviceExt
,
518 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
522 case FileFullDirectoryInformation
:
523 Status
= VfatGetFileFullDirectoryInformation(&DirContext
,
524 IrpContext
->DeviceExt
,
525 (PFILE_FULL_DIR_INFORMATION
)Buffer
,
529 case FileBothDirectoryInformation
:
530 Status
= VfatGetFileBothInformation(&DirContext
,
531 IrpContext
->DeviceExt
,
532 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
537 Status
= STATUS_INVALID_INFO_CLASS
;
541 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_INVALID_INFO_CLASS
)
546 Status
= (FirstQuery
? STATUS_NO_SUCH_FILE
: STATUS_NO_MORE_FILES
);
550 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
551 Buffer0
->FileIndex
= DirContext
.DirIndex
;
552 pCcb
->Entry
= ++DirContext
.DirIndex
;
553 BufferLength
-= Buffer0
->NextEntryOffset
;
555 if (IrpContext
->Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
558 Buffer
+= Buffer0
->NextEntryOffset
;
563 Buffer0
->NextEntryOffset
= 0;
564 Status
= STATUS_SUCCESS
;
565 IrpContext
->Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryDirectory
.Length
- BufferLength
;
568 ExReleaseResourceLite(&pFcb
->MainResource
);
575 * FUNCTION: directory control : read/write directory informations
578 VfatDirectoryControl(PVFAT_IRP_CONTEXT IrpContext
)
580 NTSTATUS Status
= STATUS_SUCCESS
;
582 IrpContext
->Irp
->IoStatus
.Information
= 0;
584 switch (IrpContext
->MinorFunction
)
586 case IRP_MN_QUERY_DIRECTORY
:
587 Status
= DoQuery (IrpContext
);
590 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
591 DPRINT("VFAT, dir : change\n");
592 Status
= STATUS_NOT_IMPLEMENTED
;
597 DPRINT("Unexpected minor function %x in VFAT driver\n",
598 IrpContext
->MinorFunction
);
599 Status
= STATUS_INVALID_DEVICE_REQUEST
;
603 if (Status
== STATUS_PENDING
)
605 Status
= VfatQueueRequest(IrpContext
);
609 IrpContext
->Irp
->IoStatus
.Status
= Status
;
610 IoCompleteRequest (IrpContext
->Irp
, IO_NO_INCREMENT
);
611 VfatFreeIrpContext(IrpContext
);