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_NAME_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 if (BufferLength
> FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
))
114 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
));
115 RtlCopyMemory(pInfo
->FileName
,
116 DirContext
->LongNameU
.Buffer
,
118 *Written
+= BytesToCopy
;
120 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
122 Status
= STATUS_SUCCESS
;
132 VfatGetFileNamesInformation(
133 PVFAT_DIRENTRY_CONTEXT DirContext
,
134 PFILE_NAMES_INFORMATION pInfo
,
140 ULONG BytesToCopy
= 0;
143 Status
= STATUS_BUFFER_OVERFLOW
;
145 if (FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
) > BufferLength
)
148 if (First
|| (BufferLength
>= FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
150 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
152 *Written
= FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
);
153 pInfo
->NextEntryOffset
= 0;
154 if (BufferLength
> FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
))
156 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
));
157 RtlCopyMemory(pInfo
->FileName
,
158 DirContext
->LongNameU
.Buffer
,
160 *Written
+= BytesToCopy
;
162 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
164 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_NAMES_INFORMATION
) +
166 Status
= STATUS_SUCCESS
;
176 VfatGetFileDirectoryInformation(
177 PVFAT_DIRENTRY_CONTEXT DirContext
,
178 PDEVICE_EXTENSION DeviceExt
,
179 PFILE_DIRECTORY_INFORMATION pInfo
,
185 ULONG BytesToCopy
= 0;
188 Status
= STATUS_BUFFER_OVERFLOW
;
190 if (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
) > BufferLength
)
193 if (First
|| (BufferLength
>= FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
195 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
196 /* pInfo->FileIndex = ; */
198 *Written
= FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
);
199 pInfo
->NextEntryOffset
= 0;
200 if (BufferLength
> FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
))
202 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
));
203 RtlCopyMemory(pInfo
->FileName
,
204 DirContext
->LongNameU
.Buffer
,
206 *Written
+= BytesToCopy
;
208 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
210 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) +
212 Status
= STATUS_SUCCESS
;
218 if (vfatVolumeIsFatX(DeviceExt
))
220 FsdDosDateTimeToSystemTime(DeviceExt
,
221 DirContext
->DirEntry
.FatX
.CreationDate
,
222 DirContext
->DirEntry
.FatX
.CreationTime
,
223 &pInfo
->CreationTime
);
224 FsdDosDateTimeToSystemTime(DeviceExt
,
225 DirContext
->DirEntry
.FatX
.AccessDate
,
226 DirContext
->DirEntry
.FatX
.AccessTime
,
227 &pInfo
->LastAccessTime
);
228 FsdDosDateTimeToSystemTime(DeviceExt
,
229 DirContext
->DirEntry
.FatX
.UpdateDate
,
230 DirContext
->DirEntry
.FatX
.UpdateTime
,
231 &pInfo
->LastWriteTime
);
233 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
235 if (BooleanFlagOn(DirContext
->DirEntry
.FatX
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
237 pInfo
->EndOfFile
.QuadPart
= 0;
238 pInfo
->AllocationSize
.QuadPart
= 0;
242 pInfo
->EndOfFile
.u
.HighPart
= 0;
243 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
244 /* Make allocsize a rounded up multiple of BytesPerCluster */
245 pInfo
->AllocationSize
.u
.HighPart
= 0;
246 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
247 DeviceExt
->FatInfo
.BytesPerCluster
);
250 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
254 FsdDosDateTimeToSystemTime(DeviceExt
,
255 DirContext
->DirEntry
.Fat
.CreationDate
,
256 DirContext
->DirEntry
.Fat
.CreationTime
,
257 &pInfo
->CreationTime
);
258 FsdDosDateTimeToSystemTime(DeviceExt
,
259 DirContext
->DirEntry
.Fat
.AccessDate
,
261 &pInfo
->LastAccessTime
);
262 FsdDosDateTimeToSystemTime(DeviceExt
,
263 DirContext
->DirEntry
.Fat
.UpdateDate
,
264 DirContext
->DirEntry
.Fat
.UpdateTime
,
265 &pInfo
->LastWriteTime
);
267 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
269 if (BooleanFlagOn(DirContext
->DirEntry
.Fat
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
271 pInfo
->EndOfFile
.QuadPart
= 0;
272 pInfo
->AllocationSize
.QuadPart
= 0;
276 pInfo
->EndOfFile
.u
.HighPart
= 0;
277 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
278 /* Make allocsize a rounded up multiple of BytesPerCluster */
279 pInfo
->AllocationSize
.u
.HighPart
= 0;
280 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
,
281 DeviceExt
->FatInfo
.BytesPerCluster
);
284 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
293 VfatGetFileFullDirectoryInformation(
294 PVFAT_DIRENTRY_CONTEXT DirContext
,
295 PDEVICE_EXTENSION DeviceExt
,
296 PFILE_FULL_DIR_INFORMATION pInfo
,
302 ULONG BytesToCopy
= 0;
305 Status
= STATUS_BUFFER_OVERFLOW
;
307 if (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
) > BufferLength
)
310 if (First
|| (BufferLength
>= FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
312 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
313 /* pInfo->FileIndex = ; */
316 *Written
= FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
);
317 pInfo
->NextEntryOffset
= 0;
318 if (BufferLength
> FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
))
320 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
));
321 RtlCopyMemory(pInfo
->FileName
,
322 DirContext
->LongNameU
.Buffer
,
324 *Written
+= BytesToCopy
;
326 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
328 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION
) +
330 Status
= STATUS_SUCCESS
;
334 if (vfatVolumeIsFatX(DeviceExt
))
336 FsdDosDateTimeToSystemTime(DeviceExt
,
337 DirContext
->DirEntry
.FatX
.CreationDate
,
338 DirContext
->DirEntry
.FatX
.CreationTime
,
339 &pInfo
->CreationTime
);
340 FsdDosDateTimeToSystemTime(DeviceExt
,
341 DirContext
->DirEntry
.FatX
.AccessDate
,
342 DirContext
->DirEntry
.FatX
.AccessTime
,
343 &pInfo
->LastAccessTime
);
344 FsdDosDateTimeToSystemTime(DeviceExt
,
345 DirContext
->DirEntry
.FatX
.UpdateDate
,
346 DirContext
->DirEntry
.FatX
.UpdateTime
,
347 &pInfo
->LastWriteTime
);
349 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
350 pInfo
->EndOfFile
.u
.HighPart
= 0;
351 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
352 /* Make allocsize a rounded up multiple of BytesPerCluster */
353 pInfo
->AllocationSize
.u
.HighPart
= 0;
354 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
355 DeviceExt
->FatInfo
.BytesPerCluster
);
356 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
360 FsdDosDateTimeToSystemTime(DeviceExt
,
361 DirContext
->DirEntry
.Fat
.CreationDate
,
362 DirContext
->DirEntry
.Fat
.CreationTime
,
363 &pInfo
->CreationTime
);
364 FsdDosDateTimeToSystemTime(DeviceExt
,
365 DirContext
->DirEntry
.Fat
.AccessDate
,
367 &pInfo
->LastAccessTime
);
368 FsdDosDateTimeToSystemTime(DeviceExt
,
369 DirContext
->DirEntry
.Fat
.UpdateDate
,
370 DirContext
->DirEntry
.Fat
.UpdateTime
,
371 &pInfo
->LastWriteTime
);
373 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
374 pInfo
->EndOfFile
.u
.HighPart
= 0;
375 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
376 /* Make allocsize a rounded up multiple of BytesPerCluster */
377 pInfo
->AllocationSize
.u
.HighPart
= 0;
378 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
,
379 DeviceExt
->FatInfo
.BytesPerCluster
);
380 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
389 VfatGetFileBothInformation(
390 PVFAT_DIRENTRY_CONTEXT DirContext
,
391 PDEVICE_EXTENSION DeviceExt
,
392 PFILE_BOTH_DIR_INFORMATION pInfo
,
398 ULONG BytesToCopy
= 0;
401 Status
= STATUS_BUFFER_OVERFLOW
;
403 if (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
) > BufferLength
)
406 if (First
|| (BufferLength
>= FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
) + DirContext
->LongNameU
.Length
))
408 pInfo
->FileNameLength
= DirContext
->LongNameU
.Length
;
411 *Written
= FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
);
412 pInfo
->NextEntryOffset
= 0;
413 if (BufferLength
> FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
))
415 BytesToCopy
= min(DirContext
->LongNameU
.Length
, BufferLength
- FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
));
416 RtlCopyMemory(pInfo
->FileName
,
417 DirContext
->LongNameU
.Buffer
,
419 *Written
+= BytesToCopy
;
421 if (BytesToCopy
== DirContext
->LongNameU
.Length
)
423 pInfo
->NextEntryOffset
= ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION
) +
425 Status
= STATUS_SUCCESS
;
429 if (vfatVolumeIsFatX(DeviceExt
))
431 pInfo
->ShortName
[0] = 0;
432 pInfo
->ShortNameLength
= 0;
433 /* pInfo->FileIndex = ; */
435 FsdDosDateTimeToSystemTime(DeviceExt
,
436 DirContext
->DirEntry
.FatX
.CreationDate
,
437 DirContext
->DirEntry
.FatX
.CreationTime
,
438 &pInfo
->CreationTime
);
439 FsdDosDateTimeToSystemTime(DeviceExt
,
440 DirContext
->DirEntry
.FatX
.AccessDate
,
441 DirContext
->DirEntry
.FatX
.AccessTime
,
442 &pInfo
->LastAccessTime
);
443 FsdDosDateTimeToSystemTime(DeviceExt
,
444 DirContext
->DirEntry
.FatX
.UpdateDate
,
445 DirContext
->DirEntry
.FatX
.UpdateTime
,
446 &pInfo
->LastWriteTime
);
448 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
450 if (BooleanFlagOn(DirContext
->DirEntry
.FatX
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
452 pInfo
->EndOfFile
.QuadPart
= 0;
453 pInfo
->AllocationSize
.QuadPart
= 0;
457 pInfo
->EndOfFile
.u
.HighPart
= 0;
458 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.FatX
.FileSize
;
459 /* Make allocsize a rounded up multiple of BytesPerCluster */
460 pInfo
->AllocationSize
.u
.HighPart
= 0;
461 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.FatX
.FileSize
,
462 DeviceExt
->FatInfo
.BytesPerCluster
);
465 pInfo
->FileAttributes
= DirContext
->DirEntry
.FatX
.Attrib
& 0x3f;
469 pInfo
->ShortNameLength
= (CCHAR
)DirContext
->ShortNameU
.Length
;
471 RtlCopyMemory(pInfo
->FileName
,
472 DirContext
->LongNameU
.Buffer
,
473 DirContext
->LongNameU
.Length
);
475 /* pInfo->FileIndex = ; */
477 FsdDosDateTimeToSystemTime(DeviceExt
,
478 DirContext
->DirEntry
.Fat
.CreationDate
,
479 DirContext
->DirEntry
.Fat
.CreationTime
,
480 &pInfo
->CreationTime
);
481 FsdDosDateTimeToSystemTime(DeviceExt
,
482 DirContext
->DirEntry
.Fat
.AccessDate
,
484 &pInfo
->LastAccessTime
);
485 FsdDosDateTimeToSystemTime(DeviceExt
,
486 DirContext
->DirEntry
.Fat
.UpdateDate
,
487 DirContext
->DirEntry
.Fat
.UpdateTime
,
488 &pInfo
->LastWriteTime
);
490 pInfo
->ChangeTime
= pInfo
->LastWriteTime
;
492 if (BooleanFlagOn(DirContext
->DirEntry
.Fat
.Attrib
, FILE_ATTRIBUTE_DIRECTORY
))
494 pInfo
->EndOfFile
.QuadPart
= 0;
495 pInfo
->AllocationSize
.QuadPart
= 0;
499 pInfo
->EndOfFile
.u
.HighPart
= 0;
500 pInfo
->EndOfFile
.u
.LowPart
= DirContext
->DirEntry
.Fat
.FileSize
;
501 /* Make allocsize a rounded up multiple of BytesPerCluster */
502 pInfo
->AllocationSize
.u
.HighPart
= 0;
503 pInfo
->AllocationSize
.u
.LowPart
= ROUND_UP(DirContext
->DirEntry
.Fat
.FileSize
, DeviceExt
->FatInfo
.BytesPerCluster
);
506 pInfo
->FileAttributes
= DirContext
->DirEntry
.Fat
.Attrib
& 0x3f;
516 PVFAT_IRP_CONTEXT IrpContext
)
518 NTSTATUS Status
= STATUS_SUCCESS
;
519 LONG BufferLength
= 0;
520 PUNICODE_STRING pSearchPattern
= NULL
;
521 FILE_INFORMATION_CLASS FileInformationClass
;
522 PUCHAR Buffer
= NULL
;
523 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
526 BOOLEAN FirstQuery
= FALSE
;
527 BOOLEAN FirstCall
= TRUE
;
528 VFAT_DIRENTRY_CONTEXT DirContext
;
529 WCHAR LongNameBuffer
[LONGNAME_MAX_LENGTH
+ 1];
530 WCHAR ShortNameBuffer
[13];
533 PIO_STACK_LOCATION Stack
= IrpContext
->Stack
;
535 pCcb
= (PVFATCCB
)IrpContext
->FileObject
->FsContext2
;
536 pFcb
= (PVFATFCB
)IrpContext
->FileObject
->FsContext
;
538 /* Determine Buffer for result : */
539 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
541 /* Do not probe the user buffer until SEH is available */
542 if (IrpContext
->Irp
->RequestorMode
!= KernelMode
&&
543 IrpContext
->Irp
->MdlAddress
== NULL
&&
544 IrpContext
->Irp
->UserBuffer
!= NULL
)
546 ProbeForWrite(IrpContext
->Irp
->UserBuffer
, BufferLength
, 1);
549 Buffer
= VfatGetUserBuffer(IrpContext
->Irp
, FALSE
);
551 if (!ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
,
552 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
554 Status
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
555 if (NT_SUCCESS(Status
))
556 Status
= STATUS_PENDING
;
561 if (!ExAcquireResourceSharedLite(&pFcb
->MainResource
,
562 BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
)))
564 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
565 Status
= VfatLockUserBuffer(IrpContext
->Irp
, BufferLength
, IoWriteAccess
);
566 if (NT_SUCCESS(Status
))
567 Status
= STATUS_PENDING
;
572 /* Obtain the callers parameters */
574 /* HACKHACK: Bug in the MS ntifs.h header:
575 * FileName is really a PUNICODE_STRING, not a PSTRING */
576 pSearchPattern
= (PUNICODE_STRING
)Stack
->Parameters
.QueryDirectory
.FileName
;
578 pSearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
580 FileInformationClass
= Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
582 /* Allocate search pattern in case:
583 * -> We don't have one already in context
584 * -> We have been given an input pattern
585 * -> The pattern length is not null
586 * -> The pattern buffer is not null
587 * Otherwise, we'll fall later and allocate a match all (*) pattern
589 if (pSearchPattern
&&
590 pSearchPattern
->Length
!= 0 && pSearchPattern
->Buffer
!= NULL
)
592 if (!pCcb
->SearchPattern
.Buffer
)
595 pCcb
->SearchPattern
.MaximumLength
= pSearchPattern
->Length
+ sizeof(WCHAR
);
596 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
597 pCcb
->SearchPattern
.MaximumLength
,
599 if (!pCcb
->SearchPattern
.Buffer
)
601 ExReleaseResourceLite(&pFcb
->MainResource
);
602 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
603 return STATUS_INSUFFICIENT_RESOURCES
;
605 RtlCopyUnicodeString(&pCcb
->SearchPattern
, pSearchPattern
);
606 pCcb
->SearchPattern
.Buffer
[pCcb
->SearchPattern
.Length
/ sizeof(WCHAR
)] = 0;
609 else if (!pCcb
->SearchPattern
.Buffer
)
612 pCcb
->SearchPattern
.MaximumLength
= 2 * sizeof(WCHAR
);
613 pCcb
->SearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
,
616 if (!pCcb
->SearchPattern
.Buffer
)
618 ExReleaseResourceLite(&pFcb
->MainResource
);
619 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
620 return STATUS_INSUFFICIENT_RESOURCES
;
622 pCcb
->SearchPattern
.Buffer
[0] = L
'*';
623 pCcb
->SearchPattern
.Buffer
[1] = 0;
624 pCcb
->SearchPattern
.Length
= sizeof(WCHAR
);
627 if (BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_INDEX_SPECIFIED
))
629 DirContext
.DirIndex
= pCcb
->Entry
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
631 else if (FirstQuery
|| BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_RESTART_SCAN
))
633 DirContext
.DirIndex
= pCcb
->Entry
= 0;
637 DirContext
.DirIndex
= pCcb
->Entry
;
640 DPRINT("Buffer=%p tofind=%wZ\n", Buffer
, &pCcb
->SearchPattern
);
642 DirContext
.LongNameU
.Buffer
= LongNameBuffer
;
643 DirContext
.LongNameU
.MaximumLength
= sizeof(LongNameBuffer
);
644 DirContext
.ShortNameU
.Buffer
= ShortNameBuffer
;
645 DirContext
.ShortNameU
.MaximumLength
= sizeof(ShortNameBuffer
);
648 while ((Status
== STATUS_SUCCESS
) && (BufferLength
> 0))
650 Status
= FindFile(IrpContext
->DeviceExt
,
652 &pCcb
->SearchPattern
,
655 pCcb
->Entry
= DirContext
.DirIndex
;
657 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext
.LongNameU
, Status
, pCcb
->Entry
);
660 if (NT_SUCCESS(Status
))
662 switch (FileInformationClass
)
664 case FileNameInformation
:
665 Status
= VfatGetFileNameInformation(&DirContext
,
666 (PFILE_NAME_INFORMATION
)Buffer
,
672 case FileDirectoryInformation
:
673 Status
= VfatGetFileDirectoryInformation(&DirContext
,
674 IrpContext
->DeviceExt
,
675 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
681 case FileFullDirectoryInformation
:
682 Status
= VfatGetFileFullDirectoryInformation(&DirContext
,
683 IrpContext
->DeviceExt
,
684 (PFILE_FULL_DIR_INFORMATION
)Buffer
,
690 case FileBothDirectoryInformation
:
691 Status
= VfatGetFileBothInformation(&DirContext
,
692 IrpContext
->DeviceExt
,
693 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
699 case FileNamesInformation
:
700 Status
= VfatGetFileNamesInformation(&DirContext
,
701 (PFILE_NAMES_INFORMATION
)Buffer
,
708 Status
= STATUS_INVALID_INFO_CLASS
;
712 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_INVALID_INFO_CLASS
)
717 Status
= (FirstQuery
? STATUS_NO_SUCH_FILE
: STATUS_NO_MORE_FILES
);
721 Buffer0
= (PFILE_NAMES_INFORMATION
) Buffer
;
722 Buffer0
->FileIndex
= DirContext
.DirIndex
;
723 pCcb
->Entry
= ++DirContext
.DirIndex
;
724 BufferLength
-= Buffer0
->NextEntryOffset
;
726 if (BooleanFlagOn(IrpContext
->Stack
->Flags
, SL_RETURN_SINGLE_ENTRY
))
729 Buffer
+= Buffer0
->NextEntryOffset
;
734 Buffer0
->NextEntryOffset
= 0;
735 Status
= STATUS_SUCCESS
;
736 IrpContext
->Irp
->IoStatus
.Information
= Stack
->Parameters
.QueryDirectory
.Length
- BufferLength
;
740 ASSERT(Status
!= STATUS_SUCCESS
|| BufferLength
== 0);
741 ASSERT(Written
<= Stack
->Parameters
.QueryDirectory
.Length
);
742 IrpContext
->Irp
->IoStatus
.Information
= Written
;
745 ExReleaseResourceLite(&pFcb
->MainResource
);
746 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
751 NTSTATUS
VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext
)
755 PIO_STACK_LOCATION Stack
;
756 Stack
= IrpContext
->Stack
;
757 pVcb
= IrpContext
->DeviceExt
;
758 pFcb
= (PVFATFCB
) IrpContext
->FileObject
->FsContext
;
760 FsRtlNotifyFullChangeDirectory(pVcb
->NotifySync
,
762 IrpContext
->FileObject
->FsContext2
,
763 (PSTRING
)&(pFcb
->PathNameU
),
764 BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
),
766 Stack
->Parameters
.NotifyDirectory
.CompletionFilter
,
771 /* We won't handle IRP completion */
772 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
774 return STATUS_PENDING
;
778 * FUNCTION: directory control : read/write directory informations
781 VfatDirectoryControl(
782 PVFAT_IRP_CONTEXT IrpContext
)
784 NTSTATUS Status
= STATUS_SUCCESS
;
786 IrpContext
->Irp
->IoStatus
.Information
= 0;
788 switch (IrpContext
->MinorFunction
)
790 case IRP_MN_QUERY_DIRECTORY
:
791 Status
= DoQuery (IrpContext
);
794 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
795 Status
= VfatNotifyChangeDirectory(IrpContext
);
800 DPRINT("Unexpected minor function %x in VFAT driver\n",
801 IrpContext
->MinorFunction
);
802 Status
= STATUS_INVALID_DEVICE_REQUEST
;
806 if (Status
== STATUS_PENDING
&& BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_COMPLETE
))
808 return VfatMarkIrpContextForQueue(IrpContext
);