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 VfatGetFileNameInformation(
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 RtlCopyMemory(pInfo
->FileName
,
431 DirContext
->LongNameU
.Buffer
,
432 DirContext
->LongNameU
.Length
);
434 /* pInfo->FileIndex = ; */
436 FsdDosDateTimeToSystemTime(DeviceExt
,
437 DirContext
->DirEntry
.Fat
.CreationDate
,
438 DirContext
->DirEntry
.Fat
.CreationTime
,
439 &pInfo
->CreationTime
);
440 FsdDosDateTimeToSystemTime(DeviceExt
,
441 DirContext
->DirEntry
.Fat
.AccessDate
,
443 &pInfo
->LastAccessTime
);
444 FsdDosDateTimeToSystemTime(DeviceExt
,
445 DirContext
->DirEntry
.Fat
.UpdateDate
,
446 DirContext
->DirEntry
.Fat
.UpdateTime
,
447 &pInfo
->LastWriteTime
);
449 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
451 if (BooleanFlagOn(DirContext
->DirEntry
.Fat
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
453 pInfo
->EndOfFile
.QuadPart
= 0;
454 pInfo
->AllocationSize
.QuadPart
= 0;
458 pInfo
->EndOfFile
.u
.HighPart
= 0;
459 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
460 /* Make allocsize a rounded up multiple of BytesPerCluster */
461 pInfo
->AllocationSize
.u
.HighPart
= 0;
462 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
, DeviceExt
->FatInfo
.BytesPerCluster
);
465 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
475 PVFAT_IRP_CONTEXT IrpContext
)
477 NTSTATUS Status
= STATUS_SUCCESS
;
478 LONG BufferLength
= 0;
479 PUNICODE_STRING pSearchPattern
= NULL
;
480 FILE_INFORMATION_CLASS FileInformationClass
;
481 PUCHAR Buffer
= NULL
;
482 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
485 BOOLEAN FirstQuery
= FALSE
;
486 BOOLEAN FirstCall
= TRUE
;
487 VFAT_DIRENTRY_CONTEXT DirContext
;
488 WCHAR LongNameBuffer
[LONGNAME_MAX_LENGTH
+ 1];
489 WCHAR ShortNameBuffer
[13];
492 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
494 pCcb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
495 pFcb
= (PVFATFCB
)IrpContext
->FileObject
->FsContext
;
497 /* Determine Buffer for result : */
498 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
500 /* Do not probe the user buffer until SEH is available */
501 if (IrpContext
->Irp
->RequestorMode
!= KernelMode
&&
502 IrpContext
->Irp
->MdlAddress
== NULL
&&
503 IrpContext
->Irp
->UserBuffer
!= NULL
)
505 ProbeForWrite(IrpContext
->Irp
->UserBuffer
, BufferLength
, 1);
508 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, FALSE
);
510 if (!ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
,
511 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
513 Status
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
514 if (NT_SUCCESS(Status
))
515 Status
= STATUS_PENDING
;
520 if (!ExAcquireResourceSharedLite(&pFcb
->MainResource
,
521 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
523 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
524 Status
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
525 if (NT_SUCCESS(Status
))
526 Status
= STATUS_PENDING
;
531 /* Obtain the callers parameters */
533 /* HACKHACK: Bug in the MS ntifs.h header:
534 * FileName is really a PUNICODE_STRING, not a PSTRING */
535 pSearchPattern
= (PUNICODE_STRING
)Stack
->Parameters
.QueryDirectory
.FileName
;
537 pSearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
539 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
541 /* Allocate search pattern in case:
542 * -> We don't have one already in context
543 * -> We have been given an input pattern
544 * -> The pattern length is not null
545 * -> The pattern buffer is not null
546 * Otherwise, we'll fall later and allocate a match all (*) pattern
548 if (pSearchPattern
&&
549 pSearchPattern
->Length
!= 0 && pSearchPattern
->Buffer
!= NULL
)
551 if (!pCcb
->SearchPattern
.Buffer
)
554 pCcb
->SearchPattern
.MaximumLength
= pSearchPattern
->Length
+ sizeof(WCHAR
);
555 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
556 pCcb
->SearchPattern
.MaximumLength
,
558 if (!pCcb
->SearchPattern
.Buffer
)
560 ExReleaseResourceLite(&pFcb
->MainResource
);
561 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
562 return STATUS_INSUFFICIENT_RESOURCES
;
564 RtlCopyUnicodeString(&pCcb
->SearchPattern
, pSearchPattern
);
565 pCcb
->SearchPattern
.Buffer
[pCcb
->SearchPattern
.Length
/ sizeof(WCHAR
)] = 0;
568 else if (!pCcb
->SearchPattern
.Buffer
)
571 pCcb
->SearchPattern
.MaximumLength
= 2 * sizeof(WCHAR
);
572 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
575 if (!pCcb
->SearchPattern
.Buffer
)
577 ExReleaseResourceLite(&pFcb
->MainResource
);
578 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
579 return STATUS_INSUFFICIENT_RESOURCES
;
581 pCcb
->SearchPattern
.Buffer
[0] = L
'*';
582 pCcb
->SearchPattern
.Buffer
[1] = 0;
583 pCcb
->SearchPattern
.Length
= sizeof(WCHAR
);
586 if (BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_INDEX_SPECIFIED
))
588 DirContext
.DirIndex
= pCcb
->Entry
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
590 else if (FirstQuery
|| BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_RESTART_SCAN
))
592 DirContext
.DirIndex
= pCcb
->Entry
= 0;
596 DirContext
.DirIndex
= pCcb
->Entry
;
599 DPRINT("Buffer=%p tofind=%wZ\n", Buffer
, &pCcb
->SearchPattern
);
601 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
602 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
603 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
604 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
607 while ((Status
== STATUS_SUCCESS
) && (BufferLength
> 0))
609 Status
= FindFile(IrpContext
->DeviceExt
,
611 &pCcb
->SearchPattern
,
614 pCcb
->Entry
= DirContext
.DirIndex
;
616 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext
.LongNameU
, Status
, pCcb
->Entry
);
619 if (NT_SUCCESS(Status
))
621 switch (FileInformationClass
)
623 case FileNameInformation
:
624 Status
= VfatGetFileNameInformation(&DirContext
,
625 (PFILE_NAMES_INFORMATION
)Buffer
,
631 case FileDirectoryInformation
:
632 Status
= VfatGetFileDirectoryInformation(&DirContext
,
633 IrpContext
->DeviceExt
,
634 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
640 case FileFullDirectoryInformation
:
641 Status
= VfatGetFileFullDirectoryInformation(&DirContext
,
642 IrpContext
->DeviceExt
,
643 (PFILE_FULL_DIR_INFORMATION
)Buffer
,
649 case FileBothDirectoryInformation
:
650 Status
= VfatGetFileBothInformation(&DirContext
,
651 IrpContext
->DeviceExt
,
652 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
659 Status
= STATUS_INVALID_INFO_CLASS
;
663 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_INVALID_INFO_CLASS
)
668 Status
= (FirstQuery
? STATUS_NO_SUCH_FILE
: STATUS_NO_MORE_FILES
);
672 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
673 Buffer0
->FileIndex
= DirContext
.DirIndex
;
674 pCcb
->Entry
= ++DirContext
.DirIndex
;
675 BufferLength
-= Buffer0
->NextEntryOffset
;
677 if (BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_RETURN_SINGLE_ENTRY
))
680 Buffer
+= Buffer0
->NextEntryOffset
;
685 Buffer0
->NextEntryOffset
= 0;
686 Status
= STATUS_SUCCESS
;
687 IrpContext
->Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryDirectory
.Length
- BufferLength
;
691 ASSERT(Status
!= STATUS_SUCCESS
|| BufferLength
== 0);
692 ASSERT(Written
<= Stack
->Parameters
.QueryDirectory
.Length
);
693 IrpContext
->Irp
->IoStatus
.Information
= Written
;
696 ExReleaseResourceLite(&pFcb
->MainResource
);
697 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
702 NTSTATUS
VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext
)
706 PIO_STACK_LOCATION Stack
;
707 Stack
= IrpContext
->Stack
;
708 pVcb
= IrpContext
->DeviceExt
;
709 pFcb
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
711 FsRtlNotifyFullChangeDirectory(pVcb
->NotifySync
,
713 IrpContext
->FileObject
->FsContext2
,
714 (PSTRING
)&(pFcb
->PathNameU
),
715 BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
),
717 Stack
->Parameters
.NotifyDirectory
.CompletionFilter
,
722 /* We won't handle IRP completion */
723 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
725 return STATUS_PENDING
;
729 * FUNCTION: directory control : read/write directory informations
732 VfatDirectoryControl(
733 PVFAT_IRP_CONTEXT IrpContext
)
735 NTSTATUS Status
= STATUS_SUCCESS
;
737 IrpContext
->Irp
->IoStatus
.Information
= 0;
739 switch (IrpContext
->MinorFunction
)
741 case IRP_MN_QUERY_DIRECTORY
:
742 Status
= DoQuery (IrpContext
);
745 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
746 Status
= VfatNotifyChangeDirectory(IrpContext
);
751 DPRINT("Unexpected minor function %x in VFAT driver\n",
752 IrpContext
->MinorFunction
);
753 Status
= STATUS_INVALID_DEVICE_REQUEST
;
757 if (Status
== STATUS_PENDING
&& BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_COMPLETE
))
759 return VfatMarkIrpContextForQueue(IrpContext
);