dd53080cdaf1aa848bf0d7fb025b9de75e42f924
[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 #ifdef _MSC_VER
534 /* HACKHACK: Bug in the MS ntifs.h header:
535 * FileName is really a PUNICODE_STRING, not a PSTRING */
536 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
537 #else
538 pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
539 #endif
540 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
541
542 /* Allocate search pattern in case:
543 * -> We don't have one already in context
544 * -> We have been given an input pattern
545 * -> The pattern length is not null
546 * -> The pattern buffer is not null
547 * Otherwise, we'll fall later and allocate a match all (*) pattern
548 */
549 if (pSearchPattern &&
550 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
551 {
552 if (!pCcb->SearchPattern.Buffer)
553 {
554 FirstQuery = TRUE;
555 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
556 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
557 pCcb->SearchPattern.MaximumLength,
558 TAG_VFAT);
559 if (!pCcb->SearchPattern.Buffer)
560 {
561 ExReleaseResourceLite(&pFcb->MainResource);
562 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
563 return STATUS_INSUFFICIENT_RESOURCES;
564 }
565 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
566 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
567 }
568 }
569 else if (!pCcb->SearchPattern.Buffer)
570 {
571 FirstQuery = TRUE;
572 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
573 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
574 2 * sizeof(WCHAR),
575 TAG_VFAT);
576 if (!pCcb->SearchPattern.Buffer)
577 {
578 ExReleaseResourceLite(&pFcb->MainResource);
579 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
580 return STATUS_INSUFFICIENT_RESOURCES;
581 }
582 pCcb->SearchPattern.Buffer[0] = L'*';
583 pCcb->SearchPattern.Buffer[1] = 0;
584 pCcb->SearchPattern.Length = sizeof(WCHAR);
585 }
586
587 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_INDEX_SPECIFIED))
588 {
589 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
590 }
591 else if (FirstQuery || BooleanFlagOn(IrpContext->Stack->Flags, SL_RESTART_SCAN))
592 {
593 DirContext.DirIndex = pCcb->Entry = 0;
594 }
595 else
596 {
597 DirContext.DirIndex = pCcb->Entry;
598 }
599
600 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
601
602 DirContext.LongNameU.Buffer = LongNameBuffer;
603 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
604 DirContext.ShortNameU.Buffer = ShortNameBuffer;
605 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
606
607 Written = 0;
608 while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
609 {
610 Status = FindFile(IrpContext->DeviceExt,
611 pFcb,
612 &pCcb->SearchPattern,
613 &DirContext,
614 FirstCall);
615 pCcb->Entry = DirContext.DirIndex;
616
617 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);
618
619 FirstCall = FALSE;
620 if (NT_SUCCESS(Status))
621 {
622 switch (FileInformationClass)
623 {
624 case FileDirectoryInformation:
625 Status = VfatGetFileDirectoryInformation(&DirContext,
626 IrpContext->DeviceExt,
627 (PFILE_DIRECTORY_INFORMATION)Buffer,
628 BufferLength,
629 &Written,
630 Buffer0 == NULL);
631 break;
632
633 case FileFullDirectoryInformation:
634 Status = VfatGetFileFullDirectoryInformation(&DirContext,
635 IrpContext->DeviceExt,
636 (PFILE_FULL_DIR_INFORMATION)Buffer,
637 BufferLength,
638 &Written,
639 Buffer0 == NULL);
640 break;
641
642 case FileBothDirectoryInformation:
643 Status = VfatGetFileBothInformation(&DirContext,
644 IrpContext->DeviceExt,
645 (PFILE_BOTH_DIR_INFORMATION)Buffer,
646 BufferLength,
647 &Written,
648 Buffer0 == NULL);
649 break;
650
651 case FileNamesInformation:
652 Status = VfatGetFileNamesInformation(&DirContext,
653 (PFILE_NAMES_INFORMATION)Buffer,
654 BufferLength,
655 &Written,
656 Buffer0 == NULL);
657 break;
658
659 default:
660 Status = STATUS_INVALID_INFO_CLASS;
661 break;
662 }
663
664 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
665 break;
666 }
667 else
668 {
669 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
670 break;
671 }
672
673 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
674 Buffer0->FileIndex = DirContext.DirIndex;
675 pCcb->Entry = ++DirContext.DirIndex;
676 BufferLength -= Buffer0->NextEntryOffset;
677
678 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_RETURN_SINGLE_ENTRY))
679 break;
680
681 Buffer += Buffer0->NextEntryOffset;
682 }
683
684 if (Buffer0)
685 {
686 Buffer0->NextEntryOffset = 0;
687 Status = STATUS_SUCCESS;
688 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
689 }
690 else
691 {
692 ASSERT(Status != STATUS_SUCCESS || BufferLength == 0);
693 ASSERT(Written <= Stack->Parameters.QueryDirectory.Length);
694 IrpContext->Irp->IoStatus.Information = Written;
695 }
696
697 ExReleaseResourceLite(&pFcb->MainResource);
698 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
699
700 return Status;
701 }
702
703 NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
704 {
705 PVCB pVcb;
706 PVFATFCB pFcb;
707 PIO_STACK_LOCATION Stack;
708 Stack = IrpContext->Stack;
709 pVcb = IrpContext->DeviceExt;
710 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
711
712 FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
713 &(pVcb->NotifyList),
714 IrpContext->FileObject->FsContext2,
715 (PSTRING)&(pFcb->PathNameU),
716 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
717 FALSE,
718 Stack->Parameters.NotifyDirectory.CompletionFilter,
719 IrpContext->Irp,
720 NULL,
721 NULL);
722
723 /* We won't handle IRP completion */
724 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
725
726 return STATUS_PENDING;
727 }
728
729 /*
730 * FUNCTION: directory control : read/write directory informations
731 */
732 NTSTATUS
733 VfatDirectoryControl(
734 PVFAT_IRP_CONTEXT IrpContext)
735 {
736 NTSTATUS Status = STATUS_SUCCESS;
737
738 IrpContext->Irp->IoStatus.Information = 0;
739
740 switch (IrpContext->MinorFunction)
741 {
742 case IRP_MN_QUERY_DIRECTORY:
743 Status = DoQuery (IrpContext);
744 break;
745
746 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
747 Status = VfatNotifyChangeDirectory(IrpContext);
748 break;
749
750 default:
751 /* Error */
752 DPRINT("Unexpected minor function %x in VFAT driver\n",
753 IrpContext->MinorFunction);
754 Status = STATUS_INVALID_DEVICE_REQUEST;
755 break;
756 }
757
758 if (Status == STATUS_PENDING && BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE))
759 {
760 return VfatMarkIrpContextForQueue(IrpContext);
761 }
762
763 return Status;
764 }
765
766 /* EOF */