c664af13a6638cf163d8879ae1626b301a4e87c2
[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 (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
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 if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
435 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
436 {
437 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
438 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
439 if (NT_SUCCESS(Status))
440 Status = STATUS_PENDING;
441
442 return Status;
443 }
444
445 /* Obtain the callers parameters */
446 #ifdef _MSC_VER
447 /* HACKHACK: Bug in the MS ntifs.h header:
448 * FileName is really a PUNICODE_STRING, not a PSTRING */
449 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
450 #else
451 pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
452 #endif
453 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
454
455 /* Allocate search pattern in case:
456 * -> We don't have one already in context
457 * -> We have been given an input pattern
458 * -> The pattern length is not null
459 * -> The pattern buffer is not null
460 * Otherwise, we'll fall later and allocate a match all (*) pattern
461 */
462 if (pSearchPattern &&
463 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
464 {
465 if (!pCcb->SearchPattern.Buffer)
466 {
467 FirstQuery = TRUE;
468 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
469 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
470 pCcb->SearchPattern.MaximumLength,
471 TAG_VFAT);
472 if (!pCcb->SearchPattern.Buffer)
473 {
474 ExReleaseResourceLite(&pFcb->MainResource);
475 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
476 return STATUS_INSUFFICIENT_RESOURCES;
477 }
478 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
479 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
480 }
481 }
482 else if (!pCcb->SearchPattern.Buffer)
483 {
484 FirstQuery = TRUE;
485 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
486 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
487 2 * sizeof(WCHAR),
488 TAG_VFAT);
489 if (!pCcb->SearchPattern.Buffer)
490 {
491 ExReleaseResourceLite(&pFcb->MainResource);
492 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
493 return STATUS_INSUFFICIENT_RESOURCES;
494 }
495 pCcb->SearchPattern.Buffer[0] = L'*';
496 pCcb->SearchPattern.Buffer[1] = 0;
497 pCcb->SearchPattern.Length = sizeof(WCHAR);
498 }
499
500 if (IrpContext->Stack->Flags & SL_INDEX_SPECIFIED)
501 {
502 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
503 }
504 else if (FirstQuery || (IrpContext->Stack->Flags & SL_RESTART_SCAN))
505 {
506 DirContext.DirIndex = pCcb->Entry = 0;
507 }
508 else
509 {
510 DirContext.DirIndex = pCcb->Entry;
511 }
512
513 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
514
515 DirContext.LongNameU.Buffer = LongNameBuffer;
516 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
517 DirContext.ShortNameU.Buffer = ShortNameBuffer;
518 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
519
520 while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
521 {
522 Status = FindFile(IrpContext->DeviceExt,
523 pFcb,
524 &pCcb->SearchPattern,
525 &DirContext,
526 FirstCall);
527 pCcb->Entry = DirContext.DirIndex;
528
529 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);
530
531 FirstCall = FALSE;
532 if (NT_SUCCESS(Status))
533 {
534 switch (FileInformationClass)
535 {
536 case FileNameInformation:
537 Status = VfatGetFileNameInformation(&DirContext,
538 (PFILE_NAMES_INFORMATION)Buffer,
539 BufferLength);
540 break;
541
542 case FileDirectoryInformation:
543 Status = VfatGetFileDirectoryInformation(&DirContext,
544 IrpContext->DeviceExt,
545 (PFILE_DIRECTORY_INFORMATION)Buffer,
546 BufferLength);
547 break;
548
549 case FileFullDirectoryInformation:
550 Status = VfatGetFileFullDirectoryInformation(&DirContext,
551 IrpContext->DeviceExt,
552 (PFILE_FULL_DIR_INFORMATION)Buffer,
553 BufferLength);
554 break;
555
556 case FileBothDirectoryInformation:
557 Status = VfatGetFileBothInformation(&DirContext,
558 IrpContext->DeviceExt,
559 (PFILE_BOTH_DIR_INFORMATION)Buffer,
560 BufferLength);
561 break;
562
563 default:
564 Status = STATUS_INVALID_INFO_CLASS;
565 break;
566 }
567
568 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
569 break;
570 }
571 else
572 {
573 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
574 break;
575 }
576
577 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
578 Buffer0->FileIndex = DirContext.DirIndex;
579 pCcb->Entry = ++DirContext.DirIndex;
580 BufferLength -= Buffer0->NextEntryOffset;
581
582 if (IrpContext->Stack->Flags & SL_RETURN_SINGLE_ENTRY)
583 break;
584
585 Buffer += Buffer0->NextEntryOffset;
586 }
587
588 if (Buffer0)
589 {
590 Buffer0->NextEntryOffset = 0;
591 Status = STATUS_SUCCESS;
592 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
593 }
594
595 ExReleaseResourceLite(&pFcb->MainResource);
596 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
597
598 return Status;
599 }
600
601 NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
602 {
603 PVCB pVcb;
604 PVFATFCB pFcb;
605 PIO_STACK_LOCATION Stack;
606 Stack = IrpContext->Stack;
607 pVcb = IrpContext->DeviceExt;
608 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
609
610 FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
611 &(pVcb->NotifyList),
612 IrpContext->FileObject->FsContext2,
613 (PSTRING)&(pFcb->PathNameU),
614 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
615 FALSE,
616 Stack->Parameters.NotifyDirectory.CompletionFilter,
617 IrpContext->Irp,
618 NULL,
619 NULL);
620
621 /* We won't handle IRP completion */
622 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
623
624 return STATUS_PENDING;
625 }
626
627 /*
628 * FUNCTION: directory control : read/write directory informations
629 */
630 NTSTATUS
631 VfatDirectoryControl(
632 PVFAT_IRP_CONTEXT IrpContext)
633 {
634 NTSTATUS Status = STATUS_SUCCESS;
635
636 IrpContext->Irp->IoStatus.Information = 0;
637
638 switch (IrpContext->MinorFunction)
639 {
640 case IRP_MN_QUERY_DIRECTORY:
641 Status = DoQuery (IrpContext);
642 break;
643
644 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
645 Status = VfatNotifyChangeDirectory(IrpContext);
646 break;
647
648 default:
649 /* Error */
650 DPRINT("Unexpected minor function %x in VFAT driver\n",
651 IrpContext->MinorFunction);
652 Status = STATUS_INVALID_DEVICE_REQUEST;
653 break;
654 }
655
656 if (Status == STATUS_PENDING && IrpContext->Flags & IRPCONTEXT_COMPLETE)
657 {
658 return VfatMarkIrpContextForQueue(IrpContext);
659 }
660
661 return Status;
662 }
663
664 /* EOF */