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 *****************************************************************/
18 /* FUNCTIONS ****************************************************************/
20 /* Function like DosDateTimeToFileTime */
22 FsdDosDateTimeToSystemTime(
23 PDEVICE_EXTENSION DeviceExt
,
26 PLARGE_INTEGER SystemTime
)
28 PDOSTIME pdtime
= (PDOSTIME
)&DosTime
;
29 PDOSDATE pddate
= (PDOSDATE
)&DosDate
;
30 TIME_FIELDS TimeFields
;
31 LARGE_INTEGER LocalTime
;
33 if (SystemTime
== NULL
)
36 TimeFields
.Milliseconds
= 0;
37 TimeFields
.Second
= pdtime
->Second
* 2;
38 TimeFields
.Minute
= pdtime
->Minute
;
39 TimeFields
.Hour
= pdtime
->Hour
;
41 TimeFields
.Day
= pddate
->Day
;
42 TimeFields
.Month
= pddate
->Month
;
43 TimeFields
.Year
= (CSHORT
)(DeviceExt
->BaseDateYear
+ pddate
->Year
);
45 RtlTimeFieldsToTime(&TimeFields
, &LocalTime
);
46 ExLocalTimeToSystemTime(&LocalTime
, SystemTime
);
51 /* Function like FileTimeToDosDateTime */
53 FsdSystemTimeToDosDateTime(
54 PDEVICE_EXTENSION DeviceExt
,
55 PLARGE_INTEGER SystemTime
,
59 PDOSTIME pdtime
= (PDOSTIME
)pDosTime
;
60 PDOSDATE pddate
= (PDOSDATE
)pDosDate
;
61 TIME_FIELDS TimeFields
;
62 LARGE_INTEGER LocalTime
;
64 if (SystemTime
== NULL
)
67 ExSystemTimeToLocalTime(SystemTime
, &LocalTime
);
68 RtlTimeToTimeFields(&LocalTime
, &TimeFields
);
72 pdtime
->Second
= TimeFields
.Second
/ 2;
73 pdtime
->Minute
= TimeFields
.Minute
;
74 pdtime
->Hour
= TimeFields
.Hour
;
79 pddate
->Day
= TimeFields
.Day
;
80 pddate
->Month
= TimeFields
.Month
;
81 pddate
->Year
= (USHORT
) (TimeFields
.Year
- DeviceExt
->BaseDateYear
);
87 #define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG)))
91 VfatGetFileNamesInformation(
92 PVFAT_DIRENTRY_CONTEXT DirContext
,
93 PFILE_NAMES_INFORMATION pInfo
,
99 ULONG BytesToCopy
= 0;
102 Status
= STATUS_BUFFER_OVERFLOW
;
104 if (FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
) > BufferLength
)
107 if (First
|| (BufferLength
> FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
109 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
111 *Written
= FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
);
112 pInfo
->NextEntryOffset
= 0;
113 if (BufferLength
> FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
))
115 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
));
116 RtlCopyMemory(pInfo
->FileName
,
117 DirContext
->LongNameU
.Buffer
,
119 *Written
+= BytesToCopy
;
121 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
123 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_NAMES_INFORMATION
) +
125 Status
= STATUS_SUCCESS
;
135 VfatGetFileDirectoryInformation(
136 PVFAT_DIRENTRY_CONTEXT DirContext
,
137 PDEVICE_EXTENSION DeviceExt
,
138 PFILE_DIRECTORY_INFORMATION pInfo
,
144 ULONG BytesToCopy
= 0;
147 Status
= STATUS_BUFFER_OVERFLOW
;
149 if (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
) > BufferLength
)
152 if (First
|| (BufferLength
> FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
154 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
155 /* pInfo->FileIndex = ; */
157 *Written
= FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
);
158 pInfo
->NextEntryOffset
= 0;
159 if (BufferLength
> FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
))
161 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
));
162 RtlCopyMemory(pInfo
->FileName
,
163 DirContext
->LongNameU
.Buffer
,
165 *Written
+= BytesToCopy
;
167 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
169 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) +
171 Status
= STATUS_SUCCESS
;
177 if (vfatVolumeIsFatX(DeviceExt
))
179 FsdDosDateTimeToSystemTime(DeviceExt
,
180 DirContext
->DirEntry
.FatX
.CreationDate
,
181 DirContext
->DirEntry
.FatX
.CreationTime
,
182 &pInfo
->CreationTime
);
183 FsdDosDateTimeToSystemTime(DeviceExt
,
184 DirContext
->DirEntry
.FatX
.AccessDate
,
185 DirContext
->DirEntry
.FatX
.AccessTime
,
186 &pInfo
->LastAccessTime
);
187 FsdDosDateTimeToSystemTime(DeviceExt
,
188 DirContext
->DirEntry
.FatX
.UpdateDate
,
189 DirContext
->DirEntry
.FatX
.UpdateTime
,
190 &pInfo
->LastWriteTime
);
192 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
194 if (BooleanFlagOn(DirContext
->DirEntry
.FatX
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
196 pInfo
->EndOfFile
.QuadPart
= 0;
197 pInfo
->AllocationSize
.QuadPart
= 0;
201 pInfo
->EndOfFile
.u
.HighPart
= 0;
202 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
203 /* Make allocsize a rounded up multiple of BytesPerCluster */
204 pInfo
->AllocationSize
.u
.HighPart
= 0;
205 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
206 DeviceExt
->FatInfo
.BytesPerCluster
);
209 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
213 FsdDosDateTimeToSystemTime(DeviceExt
,
214 DirContext
->DirEntry
.Fat
.CreationDate
,
215 DirContext
->DirEntry
.Fat
.CreationTime
,
216 &pInfo
->CreationTime
);
217 FsdDosDateTimeToSystemTime(DeviceExt
,
218 DirContext
->DirEntry
.Fat
.AccessDate
,
220 &pInfo
->LastAccessTime
);
221 FsdDosDateTimeToSystemTime(DeviceExt
,
222 DirContext
->DirEntry
.Fat
.UpdateDate
,
223 DirContext
->DirEntry
.Fat
.UpdateTime
,
224 &pInfo
->LastWriteTime
);
226 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
228 if (BooleanFlagOn(DirContext
->DirEntry
.Fat
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
230 pInfo
->EndOfFile
.QuadPart
= 0;
231 pInfo
->AllocationSize
.QuadPart
= 0;
235 pInfo
->EndOfFile
.u
.HighPart
= 0;
236 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
237 /* Make allocsize a rounded up multiple of BytesPerCluster */
238 pInfo
->AllocationSize
.u
.HighPart
= 0;
239 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
,
240 DeviceExt
->FatInfo
.BytesPerCluster
);
243 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
252 VfatGetFileFullDirectoryInformation(
253 PVFAT_DIRENTRY_CONTEXT DirContext
,
254 PDEVICE_EXTENSION DeviceExt
,
255 PFILE_FULL_DIR_INFORMATION pInfo
,
261 ULONG BytesToCopy
= 0;
264 Status
= STATUS_BUFFER_OVERFLOW
;
266 if (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
) > BufferLength
)
269 if (First
|| (BufferLength
> FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
271 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
272 /* pInfo->FileIndex = ; */
275 *Written
= FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
);
276 pInfo
->NextEntryOffset
= 0;
277 if (BufferLength
> FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
))
279 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
));
280 RtlCopyMemory(pInfo
->FileName
,
281 DirContext
->LongNameU
.Buffer
,
283 *Written
+= BytesToCopy
;
285 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
287 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION
) +
289 Status
= STATUS_SUCCESS
;
293 if (vfatVolumeIsFatX(DeviceExt
))
295 FsdDosDateTimeToSystemTime(DeviceExt
,
296 DirContext
->DirEntry
.FatX
.CreationDate
,
297 DirContext
->DirEntry
.FatX
.CreationTime
,
298 &pInfo
->CreationTime
);
299 FsdDosDateTimeToSystemTime(DeviceExt
,
300 DirContext
->DirEntry
.FatX
.AccessDate
,
301 DirContext
->DirEntry
.FatX
.AccessTime
,
302 &pInfo
->LastAccessTime
);
303 FsdDosDateTimeToSystemTime(DeviceExt
,
304 DirContext
->DirEntry
.FatX
.UpdateDate
,
305 DirContext
->DirEntry
.FatX
.UpdateTime
,
306 &pInfo
->LastWriteTime
);
308 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
309 pInfo
->EndOfFile
.u
.HighPart
= 0;
310 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
311 /* Make allocsize a rounded up multiple of BytesPerCluster */
312 pInfo
->AllocationSize
.u
.HighPart
= 0;
313 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
314 DeviceExt
->FatInfo
.BytesPerCluster
);
315 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
319 FsdDosDateTimeToSystemTime(DeviceExt
,
320 DirContext
->DirEntry
.Fat
.CreationDate
,
321 DirContext
->DirEntry
.Fat
.CreationTime
,
322 &pInfo
->CreationTime
);
323 FsdDosDateTimeToSystemTime(DeviceExt
,
324 DirContext
->DirEntry
.Fat
.AccessDate
,
326 &pInfo
->LastAccessTime
);
327 FsdDosDateTimeToSystemTime(DeviceExt
,
328 DirContext
->DirEntry
.Fat
.UpdateDate
,
329 DirContext
->DirEntry
.Fat
.UpdateTime
,
330 &pInfo
->LastWriteTime
);
332 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
333 pInfo
->EndOfFile
.u
.HighPart
= 0;
334 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
335 /* Make allocsize a rounded up multiple of BytesPerCluster */
336 pInfo
->AllocationSize
.u
.HighPart
= 0;
337 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
,
338 DeviceExt
->FatInfo
.BytesPerCluster
);
339 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
348 VfatGetFileBothInformation(
349 PVFAT_DIRENTRY_CONTEXT DirContext
,
350 PDEVICE_EXTENSION DeviceExt
,
351 PFILE_BOTH_DIR_INFORMATION pInfo
,
357 ULONG BytesToCopy
= 0;
360 Status
= STATUS_BUFFER_OVERFLOW
;
362 if (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
) > BufferLength
)
365 if (First
|| (BufferLength
> FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
367 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
370 *Written
= FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
);
371 pInfo
->NextEntryOffset
= 0;
372 if (BufferLength
> FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
))
374 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
));
375 RtlCopyMemory(pInfo
->FileName
,
376 DirContext
->LongNameU
.Buffer
,
378 *Written
+= BytesToCopy
;
380 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
382 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION
) +
384 Status
= STATUS_SUCCESS
;
388 if (vfatVolumeIsFatX(DeviceExt
))
390 pInfo
->ShortName
[0] = 0;
391 pInfo
->ShortNameLength
= 0;
392 /* pInfo->FileIndex = ; */
394 FsdDosDateTimeToSystemTime(DeviceExt
,
395 DirContext
->DirEntry
.FatX
.CreationDate
,
396 DirContext
->DirEntry
.FatX
.CreationTime
,
397 &pInfo
->CreationTime
);
398 FsdDosDateTimeToSystemTime(DeviceExt
,
399 DirContext
->DirEntry
.FatX
.AccessDate
,
400 DirContext
->DirEntry
.FatX
.AccessTime
,
401 &pInfo
->LastAccessTime
);
402 FsdDosDateTimeToSystemTime(DeviceExt
,
403 DirContext
->DirEntry
.FatX
.UpdateDate
,
404 DirContext
->DirEntry
.FatX
.UpdateTime
,
405 &pInfo
->LastWriteTime
);
407 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
409 if (BooleanFlagOn(DirContext
->DirEntry
.FatX
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
411 pInfo
->EndOfFile
.QuadPart
= 0;
412 pInfo
->AllocationSize
.QuadPart
= 0;
416 pInfo
->EndOfFile
.u
.HighPart
= 0;
417 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
418 /* Make allocsize a rounded up multiple of BytesPerCluster */
419 pInfo
->AllocationSize
.u
.HighPart
= 0;
420 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
421 DeviceExt
->FatInfo
.BytesPerCluster
);
424 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
428 pInfo
->ShortNameLength
= (CCHAR
)DirContext
->ShortNameU
.Length
;
430 ASSERT(pInfo
->ShortNameLength
/ sizeof(WCHAR
) <= 12);
431 RtlCopyMemory(pInfo
->ShortName
,
432 DirContext
->ShortNameU
.Buffer
,
433 DirContext
->ShortNameU
.Length
);
435 /* pInfo->FileIndex = ; */
437 FsdDosDateTimeToSystemTime(DeviceExt
,
438 DirContext
->DirEntry
.Fat
.CreationDate
,
439 DirContext
->DirEntry
.Fat
.CreationTime
,
440 &pInfo
->CreationTime
);
441 FsdDosDateTimeToSystemTime(DeviceExt
,
442 DirContext
->DirEntry
.Fat
.AccessDate
,
444 &pInfo
->LastAccessTime
);
445 FsdDosDateTimeToSystemTime(DeviceExt
,
446 DirContext
->DirEntry
.Fat
.UpdateDate
,
447 DirContext
->DirEntry
.Fat
.UpdateTime
,
448 &pInfo
->LastWriteTime
);
450 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
452 if (BooleanFlagOn(DirContext
->DirEntry
.Fat
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
454 pInfo
->EndOfFile
.QuadPart
= 0;
455 pInfo
->AllocationSize
.QuadPart
= 0;
459 pInfo
->EndOfFile
.u
.HighPart
= 0;
460 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
461 /* Make allocsize a rounded up multiple of BytesPerCluster */
462 pInfo
->AllocationSize
.u
.HighPart
= 0;
463 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
, DeviceExt
->FatInfo
.BytesPerCluster
);
466 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
476 PVFAT_IRP_CONTEXT IrpContext
)
478 NTSTATUS Status
= STATUS_SUCCESS
;
479 LONG BufferLength
= 0;
480 PUNICODE_STRING pSearchPattern
= NULL
;
481 FILE_INFORMATION_CLASS FileInformationClass
;
482 PUCHAR Buffer
= NULL
;
483 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
486 BOOLEAN FirstQuery
= FALSE
;
487 BOOLEAN FirstCall
= TRUE
;
488 VFAT_DIRENTRY_CONTEXT DirContext
;
489 WCHAR LongNameBuffer
[LONGNAME_MAX_LENGTH
+ 1];
490 WCHAR ShortNameBuffer
[13];
493 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
495 pCcb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
496 pFcb
= (PVFATFCB
)IrpContext
->FileObject
->FsContext
;
498 /* Determine Buffer for result : */
499 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
501 /* Do not probe the user buffer until SEH is available */
502 if (IrpContext
->Irp
->RequestorMode
!= KernelMode
&&
503 IrpContext
->Irp
->MdlAddress
== NULL
&&
504 IrpContext
->Irp
->UserBuffer
!= NULL
)
506 ProbeForWrite(IrpContext
->Irp
->UserBuffer
, BufferLength
, 1);
509 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, FALSE
);
511 if (!ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
,
512 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
514 Status
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
515 if (NT_SUCCESS(Status
))
516 Status
= STATUS_PENDING
;
521 if (!ExAcquireResourceSharedLite(&pFcb
->MainResource
,
522 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
524 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
525 Status
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
526 if (NT_SUCCESS(Status
))
527 Status
= STATUS_PENDING
;
532 /* Obtain the callers parameters */
533 pSearchPattern
= (PUNICODE_STRING
)Stack
->Parameters
.QueryDirectory
.FileName
;
534 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
536 /* Allocate search pattern in case:
537 * -> We don't have one already in context
538 * -> We have been given an input pattern
539 * -> The pattern length is not null
540 * -> The pattern buffer is not null
541 * Otherwise, we'll fall later and allocate a match all (*) pattern
543 if (pSearchPattern
&&
544 pSearchPattern
->Length
!= 0 && pSearchPattern
->Buffer
!= NULL
)
546 if (!pCcb
->SearchPattern
.Buffer
)
549 pCcb
->SearchPattern
.MaximumLength
= pSearchPattern
->Length
+ sizeof(WCHAR
);
550 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
551 pCcb
->SearchPattern
.MaximumLength
,
553 if (!pCcb
->SearchPattern
.Buffer
)
555 ExReleaseResourceLite(&pFcb
->MainResource
);
556 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
557 return STATUS_INSUFFICIENT_RESOURCES
;
559 RtlCopyUnicodeString(&pCcb
->SearchPattern
, pSearchPattern
);
560 pCcb
->SearchPattern
.Buffer
[pCcb
->SearchPattern
.Length
/ sizeof(WCHAR
)] = 0;
563 else if (!pCcb
->SearchPattern
.Buffer
)
566 pCcb
->SearchPattern
.MaximumLength
= 2 * sizeof(WCHAR
);
567 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
570 if (!pCcb
->SearchPattern
.Buffer
)
572 ExReleaseResourceLite(&pFcb
->MainResource
);
573 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
574 return STATUS_INSUFFICIENT_RESOURCES
;
576 pCcb
->SearchPattern
.Buffer
[0] = L
'*';
577 pCcb
->SearchPattern
.Buffer
[1] = 0;
578 pCcb
->SearchPattern
.Length
= sizeof(WCHAR
);
581 if (BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_INDEX_SPECIFIED
))
583 DirContext
.DirIndex
= pCcb
->Entry
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
585 else if (FirstQuery
|| BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_RESTART_SCAN
))
587 DirContext
.DirIndex
= pCcb
->Entry
= 0;
591 DirContext
.DirIndex
= pCcb
->Entry
;
594 DPRINT("Buffer=%p tofind=%wZ\n", Buffer
, &pCcb
->SearchPattern
);
596 DirContext
.DeviceExt
= IrpContext
->DeviceExt
;
597 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
598 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
599 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
600 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
603 while ((Status
== STATUS_SUCCESS
) && (BufferLength
> 0))
605 Status
= FindFile(IrpContext
->DeviceExt
,
607 &pCcb
->SearchPattern
,
610 pCcb
->Entry
= DirContext
.DirIndex
;
612 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext
.LongNameU
, Status
, pCcb
->Entry
);
615 if (NT_SUCCESS(Status
))
617 switch (FileInformationClass
)
619 case FileDirectoryInformation
:
620 Status
= VfatGetFileDirectoryInformation(&DirContext
,
621 IrpContext
->DeviceExt
,
622 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
628 case FileFullDirectoryInformation
:
629 Status
= VfatGetFileFullDirectoryInformation(&DirContext
,
630 IrpContext
->DeviceExt
,
631 (PFILE_FULL_DIR_INFORMATION
)Buffer
,
637 case FileBothDirectoryInformation
:
638 Status
= VfatGetFileBothInformation(&DirContext
,
639 IrpContext
->DeviceExt
,
640 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
646 case FileNamesInformation
:
647 Status
= VfatGetFileNamesInformation(&DirContext
,
648 (PFILE_NAMES_INFORMATION
)Buffer
,
655 Status
= STATUS_INVALID_INFO_CLASS
;
659 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_INVALID_INFO_CLASS
)
664 Status
= (FirstQuery
? STATUS_NO_SUCH_FILE
: STATUS_NO_MORE_FILES
);
668 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
669 Buffer0
->FileIndex
= DirContext
.DirIndex
;
670 pCcb
->Entry
= ++DirContext
.DirIndex
;
671 BufferLength
-= Buffer0
->NextEntryOffset
;
673 if (BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_RETURN_SINGLE_ENTRY
))
676 Buffer
+= Buffer0
->NextEntryOffset
;
681 Buffer0
->NextEntryOffset
= 0;
682 Status
= STATUS_SUCCESS
;
683 IrpContext
->Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryDirectory
.Length
- BufferLength
;
687 ASSERT(Status
!= STATUS_SUCCESS
|| BufferLength
== 0);
688 ASSERT(Written
<= Stack
->Parameters
.QueryDirectory
.Length
);
689 IrpContext
->Irp
->IoStatus
.Information
= Written
;
692 ExReleaseResourceLite(&pFcb
->MainResource
);
693 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
698 NTSTATUS
VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext
)
702 PIO_STACK_LOCATION Stack
;
703 Stack
= IrpContext
->Stack
;
704 pVcb
= IrpContext
->DeviceExt
;
705 pFcb
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
707 FsRtlNotifyFullChangeDirectory(pVcb
->NotifySync
,
709 IrpContext
->FileObject
->FsContext2
,
710 (PSTRING
)&(pFcb
->PathNameU
),
711 BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
),
713 Stack
->Parameters
.NotifyDirectory
.CompletionFilter
,
718 /* We won't handle IRP completion */
719 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
721 return STATUS_PENDING
;
725 * FUNCTION: directory control : read/write directory informations
728 VfatDirectoryControl(
729 PVFAT_IRP_CONTEXT IrpContext
)
731 NTSTATUS Status
= STATUS_SUCCESS
;
733 IrpContext
->Irp
->IoStatus
.Information
= 0;
735 switch (IrpContext
->MinorFunction
)
737 case IRP_MN_QUERY_DIRECTORY
:
738 Status
= DoQuery (IrpContext
);
741 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
742 Status
= VfatNotifyChangeDirectory(IrpContext
);
747 DPRINT("Unexpected minor function %x in VFAT driver\n",
748 IrpContext
->MinorFunction
);
749 Status
= STATUS_INVALID_DEVICE_REQUEST
;
753 if (Status
== STATUS_PENDING
&& BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_COMPLETE
))
755 return VfatMarkIrpContextForQueue(IrpContext
);