61e44cd45a61f46d97d11bd33f696a44a03ec77a
[reactos.git] / reactos / drivers / filesystems / fastfat / dir.c
1 /*
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
6 * UPDATE HISTORY:
7 19-12-1998 : created
8
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include "vfat.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* FUNCTIONS ****************************************************************/
19
20 /* Function like DosDateTimeToFileTime */
21 BOOLEAN
22 FsdDosDateTimeToSystemTime(
23 PDEVICE_EXTENSION DeviceExt,
24 USHORT DosDate,
25 USHORT DosTime,
26 PLARGE_INTEGER SystemTime)
27 {
28 PDOSTIME pdtime = (PDOSTIME)&DosTime;
29 PDOSDATE pddate = (PDOSDATE)&DosDate;
30 TIME_FIELDS TimeFields;
31 LARGE_INTEGER LocalTime;
32
33 if (SystemTime == NULL)
34 return FALSE;
35
36 TimeFields.Milliseconds = 0;
37 TimeFields.Second = pdtime->Second * 2;
38 TimeFields.Minute = pdtime->Minute;
39 TimeFields.Hour = pdtime->Hour;
40
41 TimeFields.Day = pddate->Day;
42 TimeFields.Month = pddate->Month;
43 TimeFields.Year = (CSHORT)(DeviceExt->BaseDateYear + pddate->Year);
44
45 RtlTimeFieldsToTime(&TimeFields, &LocalTime);
46 ExLocalTimeToSystemTime(&LocalTime, SystemTime);
47
48 return TRUE;
49 }
50
51 /* Function like FileTimeToDosDateTime */
52 BOOLEAN
53 FsdSystemTimeToDosDateTime(
54 PDEVICE_EXTENSION DeviceExt,
55 PLARGE_INTEGER SystemTime,
56 PUSHORT pDosDate,
57 PUSHORT pDosTime)
58 {
59 PDOSTIME pdtime = (PDOSTIME)pDosTime;
60 PDOSDATE pddate = (PDOSDATE)pDosDate;
61 TIME_FIELDS TimeFields;
62 LARGE_INTEGER LocalTime;
63
64 if (SystemTime == NULL)
65 return FALSE;
66
67 ExSystemTimeToLocalTime(SystemTime, &LocalTime);
68 RtlTimeToTimeFields(&LocalTime, &TimeFields);
69
70 if (pdtime)
71 {
72 pdtime->Second = TimeFields.Second / 2;
73 pdtime->Minute = TimeFields.Minute;
74 pdtime->Hour = TimeFields.Hour;
75 }
76
77 if (pddate)
78 {
79 pddate->Day = TimeFields.Day;
80 pddate->Month = TimeFields.Month;
81 pddate->Year = (USHORT) (TimeFields.Year - DeviceExt->BaseDateYear);
82 }
83
84 return TRUE;
85 }
86
87 #define ULONG_ROUND_UP(x) ROUND_UP((x), (sizeof(ULONG)))
88
89 static
90 NTSTATUS
91 VfatGetFileNameInformation(
92 PVFAT_DIRENTRY_CONTEXT DirContext,
93 PFILE_NAMES_INFORMATION pInfo,
94 ULONG BufferLength)
95 {
96 if ((sizeof(FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
97 return STATUS_BUFFER_OVERFLOW;
98
99 pInfo->FileNameLength = DirContext->LongNameU.Length;
100 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
101 DirContext->LongNameU.Length);
102
103 RtlCopyMemory(pInfo->FileName,
104 DirContext->LongNameU.Buffer,
105 DirContext->LongNameU.Length);
106
107 return STATUS_SUCCESS;
108 }
109
110 static
111 NTSTATUS
112 VfatGetFileDirectoryInformation(
113 PVFAT_DIRENTRY_CONTEXT DirContext,
114 PDEVICE_EXTENSION DeviceExt,
115 PFILE_DIRECTORY_INFORMATION pInfo,
116 ULONG BufferLength)
117 {
118 if ((sizeof(FILE_DIRECTORY_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
119 return STATUS_BUFFER_OVERFLOW;
120
121 pInfo->FileNameLength = DirContext->LongNameU.Length;
122 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
123 DirContext->LongNameU.Length);
124 /* pInfo->FileIndex = ; */
125
126 RtlCopyMemory(pInfo->FileName,
127 DirContext->LongNameU.Buffer,
128 DirContext->LongNameU.Length);
129
130 if (DeviceExt->Flags & VCB_IS_FATX)
131 {
132 FsdDosDateTimeToSystemTime(DeviceExt,
133 DirContext->DirEntry.FatX.CreationDate,
134 DirContext->DirEntry.FatX.CreationTime,
135 &pInfo->CreationTime);
136 FsdDosDateTimeToSystemTime(DeviceExt,
137 DirContext->DirEntry.FatX.AccessDate,
138 DirContext->DirEntry.FatX.AccessTime,
139 &pInfo->LastAccessTime);
140 FsdDosDateTimeToSystemTime(DeviceExt,
141 DirContext->DirEntry.FatX.UpdateDate,
142 DirContext->DirEntry.FatX.UpdateTime,
143 &pInfo->LastWriteTime);
144
145 pInfo->ChangeTime = pInfo->LastWriteTime;
146
147 if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
148 {
149 pInfo->EndOfFile.QuadPart = 0;
150 pInfo->AllocationSize.QuadPart = 0;
151 }
152 else
153 {
154 pInfo->EndOfFile.u.HighPart = 0;
155 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
156 /* Make allocsize a rounded up multiple of BytesPerCluster */
157 pInfo->AllocationSize.u.HighPart = 0;
158 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
159 DeviceExt->FatInfo.BytesPerCluster);
160 }
161
162 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
163 }
164 else
165 {
166 FsdDosDateTimeToSystemTime(DeviceExt,
167 DirContext->DirEntry.Fat.CreationDate,
168 DirContext->DirEntry.Fat.CreationTime,
169 &pInfo->CreationTime);
170 FsdDosDateTimeToSystemTime(DeviceExt,
171 DirContext->DirEntry.Fat.AccessDate,
172 0,
173 &pInfo->LastAccessTime);
174 FsdDosDateTimeToSystemTime(DeviceExt,
175 DirContext->DirEntry.Fat.UpdateDate,
176 DirContext->DirEntry.Fat.UpdateTime,
177 &pInfo->LastWriteTime);
178
179 pInfo->ChangeTime = pInfo->LastWriteTime;
180
181 if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
182 {
183 pInfo->EndOfFile.QuadPart = 0;
184 pInfo->AllocationSize.QuadPart = 0;
185 }
186 else
187 {
188 pInfo->EndOfFile.u.HighPart = 0;
189 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
190 /* Make allocsize a rounded up multiple of BytesPerCluster */
191 pInfo->AllocationSize.u.HighPart = 0;
192 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize,
193 DeviceExt->FatInfo.BytesPerCluster);
194 }
195
196 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
197 }
198
199 return STATUS_SUCCESS;
200 }
201
202 static
203 NTSTATUS
204 VfatGetFileFullDirectoryInformation(
205 PVFAT_DIRENTRY_CONTEXT DirContext,
206 PDEVICE_EXTENSION DeviceExt,
207 PFILE_FULL_DIR_INFORMATION pInfo,
208 ULONG BufferLength)
209 {
210 if ((sizeof(FILE_FULL_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
211 return STATUS_BUFFER_OVERFLOW;
212
213 pInfo->FileNameLength = DirContext->LongNameU.Length;
214 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) +
215 DirContext->LongNameU.Length);
216 /* pInfo->FileIndex = ; */
217 /* pInfo->EaSize = ; */
218
219 RtlCopyMemory(pInfo->FileName,
220 DirContext->LongNameU.Buffer,
221 DirContext->LongNameU.Length);
222
223 if (DeviceExt->Flags & VCB_IS_FATX)
224 {
225 FsdDosDateTimeToSystemTime(DeviceExt,
226 DirContext->DirEntry.FatX.CreationDate,
227 DirContext->DirEntry.FatX.CreationTime,
228 &pInfo->CreationTime);
229 FsdDosDateTimeToSystemTime(DeviceExt,
230 DirContext->DirEntry.FatX.AccessDate,
231 DirContext->DirEntry.FatX.AccessTime,
232 &pInfo->LastAccessTime);
233 FsdDosDateTimeToSystemTime(DeviceExt,
234 DirContext->DirEntry.FatX.UpdateDate,
235 DirContext->DirEntry.FatX.UpdateTime,
236 &pInfo->LastWriteTime);
237
238 pInfo->ChangeTime = pInfo->LastWriteTime;
239 pInfo->EndOfFile.u.HighPart = 0;
240 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
241 /* Make allocsize a rounded up multiple of BytesPerCluster */
242 pInfo->AllocationSize.u.HighPart = 0;
243 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
244 DeviceExt->FatInfo.BytesPerCluster);
245 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
246 }
247 else
248 {
249 FsdDosDateTimeToSystemTime(DeviceExt,
250 DirContext->DirEntry.Fat.CreationDate,
251 DirContext->DirEntry.Fat.CreationTime,
252 &pInfo->CreationTime);
253 FsdDosDateTimeToSystemTime(DeviceExt,
254 DirContext->DirEntry.Fat.AccessDate,
255 0,
256 &pInfo->LastAccessTime);
257 FsdDosDateTimeToSystemTime(DeviceExt,
258 DirContext->DirEntry.Fat.UpdateDate,
259 DirContext->DirEntry.Fat.UpdateTime,
260 &pInfo->LastWriteTime);
261
262 pInfo->ChangeTime = pInfo->LastWriteTime;
263 pInfo->EndOfFile.u.HighPart = 0;
264 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
265 /* Make allocsize a rounded up multiple of BytesPerCluster */
266 pInfo->AllocationSize.u.HighPart = 0;
267 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize,
268 DeviceExt->FatInfo.BytesPerCluster);
269 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
270 }
271
272 return STATUS_SUCCESS;
273 }
274
275 static
276 NTSTATUS
277 VfatGetFileBothInformation(
278 PVFAT_DIRENTRY_CONTEXT DirContext,
279 PDEVICE_EXTENSION DeviceExt,
280 PFILE_BOTH_DIR_INFORMATION pInfo,
281 ULONG BufferLength)
282 {
283 if ((sizeof(FILE_BOTH_DIR_INFORMATION) + DirContext->LongNameU.Length) > BufferLength)
284 return STATUS_BUFFER_OVERFLOW;
285
286 pInfo->EaSize = 0;
287
288 if (DeviceExt->Flags & VCB_IS_FATX)
289 {
290 pInfo->FileNameLength = DirContext->LongNameU.Length;
291
292 RtlCopyMemory(pInfo->FileName,
293 DirContext->LongNameU.Buffer,
294 DirContext->LongNameU.Length);
295
296 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
297 DirContext->LongNameU.Length);
298 pInfo->ShortName[0] = 0;
299 pInfo->ShortNameLength = 0;
300 /* pInfo->FileIndex = ; */
301
302 FsdDosDateTimeToSystemTime(DeviceExt,
303 DirContext->DirEntry.FatX.CreationDate,
304 DirContext->DirEntry.FatX.CreationTime,
305 &pInfo->CreationTime);
306 FsdDosDateTimeToSystemTime(DeviceExt,
307 DirContext->DirEntry.FatX.AccessDate,
308 DirContext->DirEntry.FatX.AccessTime,
309 &pInfo->LastAccessTime);
310 FsdDosDateTimeToSystemTime(DeviceExt,
311 DirContext->DirEntry.FatX.UpdateDate,
312 DirContext->DirEntry.FatX.UpdateTime,
313 &pInfo->LastWriteTime);
314
315 pInfo->ChangeTime = pInfo->LastWriteTime;
316
317 if (DirContext->DirEntry.FatX.Attrib & FILE_ATTRIBUTE_DIRECTORY)
318 {
319 pInfo->EndOfFile.QuadPart = 0;
320 pInfo->AllocationSize.QuadPart = 0;
321 }
322 else
323 {
324 pInfo->EndOfFile.u.HighPart = 0;
325 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
326 /* Make allocsize a rounded up multiple of BytesPerCluster */
327 pInfo->AllocationSize.u.HighPart = 0;
328 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
329 DeviceExt->FatInfo.BytesPerCluster);
330 }
331
332 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
333 }
334 else
335 {
336 pInfo->FileNameLength = DirContext->LongNameU.Length;
337 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
338 DirContext->LongNameU.Length);
339
340 RtlCopyMemory(pInfo->ShortName,
341 DirContext->ShortNameU.Buffer,
342 DirContext->ShortNameU.Length);
343
344 pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
345
346 RtlCopyMemory(pInfo->FileName,
347 DirContext->LongNameU.Buffer,
348 DirContext->LongNameU.Length);
349
350 /* pInfo->FileIndex = ; */
351
352 FsdDosDateTimeToSystemTime(DeviceExt,
353 DirContext->DirEntry.Fat.CreationDate,
354 DirContext->DirEntry.Fat.CreationTime,
355 &pInfo->CreationTime);
356 FsdDosDateTimeToSystemTime(DeviceExt,
357 DirContext->DirEntry.Fat.AccessDate,
358 0,
359 &pInfo->LastAccessTime);
360 FsdDosDateTimeToSystemTime(DeviceExt,
361 DirContext->DirEntry.Fat.UpdateDate,
362 DirContext->DirEntry.Fat.UpdateTime,
363 &pInfo->LastWriteTime);
364
365 pInfo->ChangeTime = pInfo->LastWriteTime;
366
367 if (DirContext->DirEntry.Fat.Attrib & FILE_ATTRIBUTE_DIRECTORY)
368 {
369 pInfo->EndOfFile.QuadPart = 0;
370 pInfo->AllocationSize.QuadPart = 0;
371 }
372 else
373 {
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, DeviceExt->FatInfo.BytesPerCluster);
379 }
380
381 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
382 }
383
384 return STATUS_SUCCESS;
385 }
386
387 static
388 NTSTATUS
389 DoQuery(
390 PVFAT_IRP_CONTEXT IrpContext)
391 {
392 NTSTATUS Status = STATUS_SUCCESS;
393 LONG BufferLength = 0;
394 PUNICODE_STRING pSearchPattern = NULL;
395 FILE_INFORMATION_CLASS FileInformationClass;
396 PUCHAR Buffer = NULL;
397 PFILE_NAMES_INFORMATION Buffer0 = NULL;
398 PVFATFCB pFcb;
399 PVFATCCB pCcb;
400 BOOLEAN FirstQuery = FALSE;
401 BOOLEAN FirstCall = TRUE;
402 VFAT_DIRENTRY_CONTEXT DirContext;
403 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
404 WCHAR ShortNameBuffer[13];
405
406 PIO_STACK_LOCATION Stack = IrpContext->Stack;
407
408 pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2;
409 pFcb = (PVFATFCB)IrpContext->FileObject->FsContext;
410
411 /* Determine Buffer for result : */
412 BufferLength = Stack->Parameters.QueryDirectory.Length;
413 #if 0
414 /* Do not probe the user buffer until SEH is available */
415 if (IrpContext->Irp->RequestorMode != KernelMode &&
416 IrpContext->Irp->MdlAddress == NULL &&
417 IrpContext->Irp->UserBuffer != NULL)
418 {
419 ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
420 }
421 #endif
422 Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE);
423
424 if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
425 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
426 {
427 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
428 if (NT_SUCCESS(Status))
429 Status = STATUS_PENDING;
430
431 return Status;
432 }
433
434 /* Obtain the callers parameters */
435 #ifdef _MSC_VER
436 /* HACKHACK: Bug in the MS ntifs.h header:
437 * FileName is really a PUNICODE_STRING, not a PSTRING */
438 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
439 #else
440 pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
441 #endif
442 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
443
444 /* Allocate search pattern in case:
445 * -> We don't have one already in context
446 * -> We have been given an input pattern
447 * -> The pattern length is not null
448 * -> The pattern buffer is not null
449 * Otherwise, we'll fall later and allocate a match all (*) pattern
450 */
451 if (pSearchPattern &&
452 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
453 {
454 if (!pCcb->SearchPattern.Buffer)
455 {
456 FirstQuery = TRUE;
457 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
458 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
459 pCcb->SearchPattern.MaximumLength,
460 TAG_VFAT);
461 if (!pCcb->SearchPattern.Buffer)
462 {
463 ExReleaseResourceLite(&pFcb->MainResource);
464 return STATUS_INSUFFICIENT_RESOURCES;
465 }
466 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
467 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
468 }
469 }
470 else if (!pCcb->SearchPattern.Buffer)
471 {
472 FirstQuery = TRUE;
473 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
474 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
475 2 * sizeof(WCHAR),
476 TAG_VFAT);
477 if (!pCcb->SearchPattern.Buffer)
478 {
479 ExReleaseResourceLite(&pFcb->MainResource);
480 return STATUS_INSUFFICIENT_RESOURCES;
481 }
482 pCcb->SearchPattern.Buffer[0] = L'*';
483 pCcb->SearchPattern.Buffer[1] = 0;
484 pCcb->SearchPattern.Length = sizeof(WCHAR);
485 }
486
487 if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
488 {
489 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
490 }
491 else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
492 {
493 DirContext.DirIndex = pCcb->Entry = 0;
494 }
495 else
496 {
497 DirContext.DirIndex = pCcb->Entry;
498 }
499
500 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
501
502 DirContext.LongNameU.Buffer = LongNameBuffer;
503 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
504 DirContext.ShortNameU.Buffer = ShortNameBuffer;
505 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
506
507 if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
508 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
509 {
510 ExReleaseResourceLite(&pFcb->MainResource);
511 return VfatMarkIrpContextForQueue(IrpContext);
512 }
513
514 while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
515 {
516 Status = FindFile(IrpContext->DeviceExt,
517 pFcb,
518 &pCcb->SearchPattern,
519 &DirContext,
520 FirstCall);
521 pCcb->Entry = DirContext.DirIndex;
522
523 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);
524
525 FirstCall = FALSE;
526 if (NT_SUCCESS(Status))
527 {
528 switch (FileInformationClass)
529 {
530 case FileNameInformation:
531 Status = VfatGetFileNameInformation(&DirContext,
532 (PFILE_NAMES_INFORMATION)Buffer,
533 BufferLength);
534 break;
535
536 case FileDirectoryInformation:
537 Status = VfatGetFileDirectoryInformation(&DirContext,
538 IrpContext->DeviceExt,
539 (PFILE_DIRECTORY_INFORMATION)Buffer,
540 BufferLength);
541 break;
542
543 case FileFullDirectoryInformation:
544 Status = VfatGetFileFullDirectoryInformation(&DirContext,
545 IrpContext->DeviceExt,
546 (PFILE_FULL_DIR_INFORMATION)Buffer,
547 BufferLength);
548 break;
549
550 case FileBothDirectoryInformation:
551 Status = VfatGetFileBothInformation(&DirContext,
552 IrpContext->DeviceExt,
553 (PFILE_BOTH_DIR_INFORMATION)Buffer,
554 BufferLength);
555 break;
556
557 default:
558 Status = STATUS_INVALID_INFO_CLASS;
559 break;
560 }
561
562 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
563 break;
564 }
565 else
566 {
567 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
568 break;
569 }
570
571 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
572 Buffer0->FileIndex = DirContext.DirIndex;
573 pCcb->Entry = ++DirContext.DirIndex;
574 BufferLength -= Buffer0->NextEntryOffset;
575
576 if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
577 break;
578
579 Buffer += Buffer0->NextEntryOffset;
580 }
581
582 if (Buffer0)
583 {
584 Buffer0->NextEntryOffset = 0;
585 Status = STATUS_SUCCESS;
586 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
587 }
588
589 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
590 ExReleaseResourceLite(&pFcb->MainResource);
591
592 return Status;
593 }
594
595 NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
596 {
597 PVCB pVcb;
598 PVFATFCB pFcb;
599 PIO_STACK_LOCATION Stack;
600 Stack = IrpContext->Stack;
601 pVcb = IrpContext->DeviceExt;
602 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
603
604 FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
605 &(pVcb->NotifyList),
606 IrpContext->FileObject->FsContext2,
607 (PSTRING)&(pFcb->PathNameU),
608 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
609 FALSE,
610 Stack->Parameters.NotifyDirectory.CompletionFilter,
611 IrpContext->Irp,
612 NULL,
613 NULL);
614
615 /* We won't handle IRP completion */
616 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
617
618 return STATUS_PENDING;
619 }
620
621 /*
622 * FUNCTION: directory control : read/write directory informations
623 */
624 NTSTATUS
625 VfatDirectoryControl(
626 PVFAT_IRP_CONTEXT IrpContext)
627 {
628 NTSTATUS Status = STATUS_SUCCESS;
629
630 IrpContext->Irp->IoStatus.Information = 0;
631
632 switch (IrpContext->MinorFunction)
633 {
634 case IRP_MN_QUERY_DIRECTORY:
635 Status = DoQuery (IrpContext);
636 break;
637
638 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
639 Status = VfatNotifyChangeDirectory(IrpContext);
640 break;
641
642 default:
643 /* Error */
644 DPRINT("Unexpected minor function %x in VFAT driver\n",
645 IrpContext->MinorFunction);
646 Status = STATUS_INVALID_DEVICE_REQUEST;
647 break;
648 }
649
650 if (Status == STATUS_PENDING && IrpContext->Flags & IRPCONTEXT_COMPLETE)
651 {
652 return VfatMarkIrpContextForQueue(IrpContext);
653 }
654
655 return Status;
656 }
657
658 /* EOF */