Revert "[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)" (#6800)
[reactos.git] / 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 VfatGetFileNamesInformation(
92 PVFAT_DIRENTRY_CONTEXT DirContext,
93 PFILE_NAMES_INFORMATION pInfo,
94 ULONG BufferLength,
95 PULONG Written,
96 BOOLEAN First)
97 {
98 NTSTATUS Status;
99 ULONG BytesToCopy = 0;
100
101 *Written = 0;
102 Status = STATUS_BUFFER_OVERFLOW;
103
104 if (FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) > BufferLength)
105 return Status;
106
107 if (First || (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) + DirContext->LongNameU.Length))
108 {
109 pInfo->FileNameLength = DirContext->LongNameU.Length;
110
111 *Written = FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName);
112 pInfo->NextEntryOffset = 0;
113 if (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName))
114 {
115 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName));
116 RtlCopyMemory(pInfo->FileName,
117 DirContext->LongNameU.Buffer,
118 BytesToCopy);
119 *Written += BytesToCopy;
120
121 if (BytesToCopy == DirContext->LongNameU.Length)
122 {
123 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_NAMES_INFORMATION) +
124 BytesToCopy);
125 Status = STATUS_SUCCESS;
126 }
127 }
128 }
129
130 return Status;
131 }
132
133 static
134 NTSTATUS
135 VfatGetFileDirectoryInformation(
136 PVFAT_DIRENTRY_CONTEXT DirContext,
137 PDEVICE_EXTENSION DeviceExt,
138 PFILE_DIRECTORY_INFORMATION pInfo,
139 ULONG BufferLength,
140 PULONG Written,
141 BOOLEAN First)
142 {
143 NTSTATUS Status;
144 ULONG BytesToCopy = 0;
145
146 *Written = 0;
147 Status = STATUS_BUFFER_OVERFLOW;
148
149 if (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) > BufferLength)
150 return Status;
151
152 if (First || (BufferLength > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) + DirContext->LongNameU.Length))
153 {
154 pInfo->FileNameLength = DirContext->LongNameU.Length;
155 /* pInfo->FileIndex = ; */
156
157 *Written = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName);
158 pInfo->NextEntryOffset = 0;
159 if (BufferLength > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName))
160 {
161 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName));
162 RtlCopyMemory(pInfo->FileName,
163 DirContext->LongNameU.Buffer,
164 BytesToCopy);
165 *Written += BytesToCopy;
166
167 if (BytesToCopy == DirContext->LongNameU.Length)
168 {
169 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
170 BytesToCopy);
171 Status = STATUS_SUCCESS;
172 }
173 }
174
175
176
177 if (vfatVolumeIsFatX(DeviceExt))
178 {
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);
191
192 pInfo->ChangeTime = pInfo->LastWriteTime;
193
194 if (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY))
195 {
196 pInfo->EndOfFile.QuadPart = 0;
197 pInfo->AllocationSize.QuadPart = 0;
198 }
199 else
200 {
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);
207 }
208
209 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
210 }
211 else
212 {
213 FsdDosDateTimeToSystemTime(DeviceExt,
214 DirContext->DirEntry.Fat.CreationDate,
215 DirContext->DirEntry.Fat.CreationTime,
216 &pInfo->CreationTime);
217 FsdDosDateTimeToSystemTime(DeviceExt,
218 DirContext->DirEntry.Fat.AccessDate,
219 0,
220 &pInfo->LastAccessTime);
221 FsdDosDateTimeToSystemTime(DeviceExt,
222 DirContext->DirEntry.Fat.UpdateDate,
223 DirContext->DirEntry.Fat.UpdateTime,
224 &pInfo->LastWriteTime);
225
226 pInfo->ChangeTime = pInfo->LastWriteTime;
227
228 if (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY))
229 {
230 pInfo->EndOfFile.QuadPart = 0;
231 pInfo->AllocationSize.QuadPart = 0;
232 }
233 else
234 {
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);
241 }
242
243 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
244 }
245 }
246
247 return Status;
248 }
249
250 static
251 NTSTATUS
252 VfatGetFileFullDirectoryInformation(
253 PVFAT_DIRENTRY_CONTEXT DirContext,
254 PDEVICE_EXTENSION DeviceExt,
255 PFILE_FULL_DIR_INFORMATION pInfo,
256 ULONG BufferLength,
257 PULONG Written,
258 BOOLEAN First)
259 {
260 NTSTATUS Status;
261 ULONG BytesToCopy = 0;
262
263 *Written = 0;
264 Status = STATUS_BUFFER_OVERFLOW;
265
266 if (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) > BufferLength)
267 return Status;
268
269 if (First || (BufferLength > FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length))
270 {
271 pInfo->FileNameLength = DirContext->LongNameU.Length;
272 /* pInfo->FileIndex = ; */
273 pInfo->EaSize = 0;
274
275 *Written = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName);
276 pInfo->NextEntryOffset = 0;
277 if (BufferLength > FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName))
278 {
279 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName));
280 RtlCopyMemory(pInfo->FileName,
281 DirContext->LongNameU.Buffer,
282 BytesToCopy);
283 *Written += BytesToCopy;
284
285 if (BytesToCopy == DirContext->LongNameU.Length)
286 {
287 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) +
288 BytesToCopy);
289 Status = STATUS_SUCCESS;
290 }
291 }
292
293 if (vfatVolumeIsFatX(DeviceExt))
294 {
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);
307
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;
316 }
317 else
318 {
319 FsdDosDateTimeToSystemTime(DeviceExt,
320 DirContext->DirEntry.Fat.CreationDate,
321 DirContext->DirEntry.Fat.CreationTime,
322 &pInfo->CreationTime);
323 FsdDosDateTimeToSystemTime(DeviceExt,
324 DirContext->DirEntry.Fat.AccessDate,
325 0,
326 &pInfo->LastAccessTime);
327 FsdDosDateTimeToSystemTime(DeviceExt,
328 DirContext->DirEntry.Fat.UpdateDate,
329 DirContext->DirEntry.Fat.UpdateTime,
330 &pInfo->LastWriteTime);
331
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;
340 }
341 }
342
343 return Status;
344 }
345
346 static
347 NTSTATUS
348 VfatGetFileBothInformation(
349 PVFAT_DIRENTRY_CONTEXT DirContext,
350 PDEVICE_EXTENSION DeviceExt,
351 PFILE_BOTH_DIR_INFORMATION pInfo,
352 ULONG BufferLength,
353 PULONG Written,
354 BOOLEAN First)
355 {
356 NTSTATUS Status;
357 ULONG BytesToCopy = 0;
358
359 *Written = 0;
360 Status = STATUS_BUFFER_OVERFLOW;
361
362 if (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) > BufferLength)
363 return Status;
364
365 if (First || (BufferLength > FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length))
366 {
367 pInfo->FileNameLength = DirContext->LongNameU.Length;
368 pInfo->EaSize = 0;
369
370 *Written = FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName);
371 pInfo->NextEntryOffset = 0;
372 if (BufferLength > FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName))
373 {
374 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName));
375 RtlCopyMemory(pInfo->FileName,
376 DirContext->LongNameU.Buffer,
377 BytesToCopy);
378 *Written += BytesToCopy;
379
380 if (BytesToCopy == DirContext->LongNameU.Length)
381 {
382 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
383 BytesToCopy);
384 Status = STATUS_SUCCESS;
385 }
386 }
387
388 if (vfatVolumeIsFatX(DeviceExt))
389 {
390 pInfo->ShortName[0] = 0;
391 pInfo->ShortNameLength = 0;
392 /* pInfo->FileIndex = ; */
393
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);
406
407 pInfo->ChangeTime = pInfo->LastWriteTime;
408
409 if (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY))
410 {
411 pInfo->EndOfFile.QuadPart = 0;
412 pInfo->AllocationSize.QuadPart = 0;
413 }
414 else
415 {
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);
422 }
423
424 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
425 }
426 else
427 {
428 pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
429
430 ASSERT(pInfo->ShortNameLength / sizeof(WCHAR) <= 12);
431 RtlCopyMemory(pInfo->ShortName,
432 DirContext->ShortNameU.Buffer,
433 DirContext->ShortNameU.Length);
434
435 /* pInfo->FileIndex = ; */
436
437 FsdDosDateTimeToSystemTime(DeviceExt,
438 DirContext->DirEntry.Fat.CreationDate,
439 DirContext->DirEntry.Fat.CreationTime,
440 &pInfo->CreationTime);
441 FsdDosDateTimeToSystemTime(DeviceExt,
442 DirContext->DirEntry.Fat.AccessDate,
443 0,
444 &pInfo->LastAccessTime);
445 FsdDosDateTimeToSystemTime(DeviceExt,
446 DirContext->DirEntry.Fat.UpdateDate,
447 DirContext->DirEntry.Fat.UpdateTime,
448 &pInfo->LastWriteTime);
449
450 pInfo->ChangeTime = pInfo->LastWriteTime;
451
452 if (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY))
453 {
454 pInfo->EndOfFile.QuadPart = 0;
455 pInfo->AllocationSize.QuadPart = 0;
456 }
457 else
458 {
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);
464 }
465
466 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
467 }
468 }
469
470 return Status;
471 }
472
473 static
474 NTSTATUS
475 DoQuery(
476 PVFAT_IRP_CONTEXT IrpContext)
477 {
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;
484 PVFATFCB pFcb;
485 PVFATCCB pCcb;
486 BOOLEAN FirstQuery = FALSE;
487 BOOLEAN FirstCall = TRUE;
488 VFAT_DIRENTRY_CONTEXT DirContext;
489 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
490 WCHAR ShortNameBuffer[13];
491 ULONG Written;
492
493 PIO_STACK_LOCATION Stack = IrpContext->Stack;
494
495 pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2;
496 pFcb = (PVFATFCB)IrpContext->FileObject->FsContext;
497
498 /* Determine Buffer for result : */
499 BufferLength = Stack->Parameters.QueryDirectory.Length;
500 #if 0
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)
505 {
506 ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
507 }
508 #endif
509 Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE);
510
511 if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
512 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
513 {
514 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
515 if (NT_SUCCESS(Status))
516 Status = STATUS_PENDING;
517
518 return Status;
519 }
520
521 if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
522 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
523 {
524 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
525 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
526 if (NT_SUCCESS(Status))
527 Status = STATUS_PENDING;
528
529 return Status;
530 }
531
532 /* Obtain the callers parameters */
533 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
534 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
535
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
542 */
543 if (pSearchPattern &&
544 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
545 {
546 if (!pCcb->SearchPattern.Buffer)
547 {
548 FirstQuery = TRUE;
549 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
550 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
551 pCcb->SearchPattern.MaximumLength,
552 TAG_SEARCH);
553 if (!pCcb->SearchPattern.Buffer)
554 {
555 ExReleaseResourceLite(&pFcb->MainResource);
556 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
557 return STATUS_INSUFFICIENT_RESOURCES;
558 }
559 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
560 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
561 }
562 }
563 else if (!pCcb->SearchPattern.Buffer)
564 {
565 FirstQuery = TRUE;
566 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
567 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
568 2 * sizeof(WCHAR),
569 TAG_SEARCH);
570 if (!pCcb->SearchPattern.Buffer)
571 {
572 ExReleaseResourceLite(&pFcb->MainResource);
573 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
574 return STATUS_INSUFFICIENT_RESOURCES;
575 }
576 pCcb->SearchPattern.Buffer[0] = L'*';
577 pCcb->SearchPattern.Buffer[1] = 0;
578 pCcb->SearchPattern.Length = sizeof(WCHAR);
579 }
580
581 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_INDEX_SPECIFIED))
582 {
583 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
584 }
585 else if (FirstQuery || BooleanFlagOn(IrpContext->Stack->Flags, SL_RESTART_SCAN))
586 {
587 DirContext.DirIndex = pCcb->Entry = 0;
588 }
589 else
590 {
591 DirContext.DirIndex = pCcb->Entry;
592 }
593
594 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
595
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);
601
602 Written = 0;
603 while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
604 {
605 Status = FindFile(IrpContext->DeviceExt,
606 pFcb,
607 &pCcb->SearchPattern,
608 &DirContext,
609 FirstCall);
610 pCcb->Entry = DirContext.DirIndex;
611
612 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);
613
614 FirstCall = FALSE;
615 if (NT_SUCCESS(Status))
616 {
617 switch (FileInformationClass)
618 {
619 case FileDirectoryInformation:
620 Status = VfatGetFileDirectoryInformation(&DirContext,
621 IrpContext->DeviceExt,
622 (PFILE_DIRECTORY_INFORMATION)Buffer,
623 BufferLength,
624 &Written,
625 Buffer0 == NULL);
626 break;
627
628 case FileFullDirectoryInformation:
629 Status = VfatGetFileFullDirectoryInformation(&DirContext,
630 IrpContext->DeviceExt,
631 (PFILE_FULL_DIR_INFORMATION)Buffer,
632 BufferLength,
633 &Written,
634 Buffer0 == NULL);
635 break;
636
637 case FileBothDirectoryInformation:
638 Status = VfatGetFileBothInformation(&DirContext,
639 IrpContext->DeviceExt,
640 (PFILE_BOTH_DIR_INFORMATION)Buffer,
641 BufferLength,
642 &Written,
643 Buffer0 == NULL);
644 break;
645
646 case FileNamesInformation:
647 Status = VfatGetFileNamesInformation(&DirContext,
648 (PFILE_NAMES_INFORMATION)Buffer,
649 BufferLength,
650 &Written,
651 Buffer0 == NULL);
652 break;
653
654 default:
655 Status = STATUS_INVALID_INFO_CLASS;
656 break;
657 }
658
659 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
660 break;
661 }
662 else
663 {
664 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
665 break;
666 }
667
668 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
669 Buffer0->FileIndex = DirContext.DirIndex;
670 pCcb->Entry = ++DirContext.DirIndex;
671 BufferLength -= Buffer0->NextEntryOffset;
672
673 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_RETURN_SINGLE_ENTRY))
674 break;
675
676 Buffer += Buffer0->NextEntryOffset;
677 }
678
679 if (Buffer0)
680 {
681 Buffer0->NextEntryOffset = 0;
682 Status = STATUS_SUCCESS;
683 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
684 }
685 else
686 {
687 ASSERT(Status != STATUS_SUCCESS || BufferLength == 0);
688 ASSERT(Written <= Stack->Parameters.QueryDirectory.Length);
689 IrpContext->Irp->IoStatus.Information = Written;
690 }
691
692 ExReleaseResourceLite(&pFcb->MainResource);
693 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
694
695 return Status;
696 }
697
698 NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
699 {
700 PVCB pVcb;
701 PVFATFCB pFcb;
702 PIO_STACK_LOCATION Stack;
703 Stack = IrpContext->Stack;
704 pVcb = IrpContext->DeviceExt;
705 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
706
707 FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
708 &(pVcb->NotifyList),
709 IrpContext->FileObject->FsContext2,
710 (PSTRING)&(pFcb->PathNameU),
711 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
712 FALSE,
713 Stack->Parameters.NotifyDirectory.CompletionFilter,
714 IrpContext->Irp,
715 NULL,
716 NULL);
717
718 /* We won't handle IRP completion */
719 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
720
721 return STATUS_PENDING;
722 }
723
724 /*
725 * FUNCTION: directory control : read/write directory informations
726 */
727 NTSTATUS
728 VfatDirectoryControl(
729 PVFAT_IRP_CONTEXT IrpContext)
730 {
731 NTSTATUS Status = STATUS_SUCCESS;
732
733 IrpContext->Irp->IoStatus.Information = 0;
734
735 switch (IrpContext->MinorFunction)
736 {
737 case IRP_MN_QUERY_DIRECTORY:
738 Status = DoQuery (IrpContext);
739 break;
740
741 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
742 Status = VfatNotifyChangeDirectory(IrpContext);
743 break;
744
745 default:
746 /* Error */
747 DPRINT("Unexpected minor function %x in VFAT driver\n",
748 IrpContext->MinorFunction);
749 Status = STATUS_INVALID_DEVICE_REQUEST;
750 break;
751 }
752
753 if (Status == STATUS_PENDING && BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE))
754 {
755 return VfatMarkIrpContextForQueue(IrpContext);
756 }
757
758 return Status;
759 }
760
761 /* EOF */