db962572819d67e64fb781f7aad1e15b0f7e3f16
[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 VfatGetFileNameInformation(
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 RtlCopyMemory(pInfo->FileName,
431 DirContext->LongNameU.Buffer,
432 DirContext->LongNameU.Length);
433
434 /* pInfo->FileIndex = ; */
435
436 FsdDosDateTimeToSystemTime(DeviceExt,
437 DirContext->DirEntry.Fat.CreationDate,
438 DirContext->DirEntry.Fat.CreationTime,
439 &pInfo->CreationTime);
440 FsdDosDateTimeToSystemTime(DeviceExt,
441 DirContext->DirEntry.Fat.AccessDate,
442 0,
443 &pInfo->LastAccessTime);
444 FsdDosDateTimeToSystemTime(DeviceExt,
445 DirContext->DirEntry.Fat.UpdateDate,
446 DirContext->DirEntry.Fat.UpdateTime,
447 &pInfo->LastWriteTime);
448
449 pInfo->ChangeTime = pInfo->LastWriteTime;
450
451 if (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY))
452 {
453 pInfo->EndOfFile.QuadPart = 0;
454 pInfo->AllocationSize.QuadPart = 0;
455 }
456 else
457 {
458 pInfo->EndOfFile.u.HighPart = 0;
459 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
460 /* Make allocsize a rounded up multiple of BytesPerCluster */
461 pInfo->AllocationSize.u.HighPart = 0;
462 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
463 }
464
465 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
466 }
467 }
468
469 return Status;
470 }
471
472 static
473 NTSTATUS
474 DoQuery(
475 PVFAT_IRP_CONTEXT IrpContext)
476 {
477 NTSTATUS Status = STATUS_SUCCESS;
478 LONG BufferLength = 0;
479 PUNICODE_STRING pSearchPattern = NULL;
480 FILE_INFORMATION_CLASS FileInformationClass;
481 PUCHAR Buffer = NULL;
482 PFILE_NAMES_INFORMATION Buffer0 = NULL;
483 PVFATFCB pFcb;
484 PVFATCCB pCcb;
485 BOOLEAN FirstQuery = FALSE;
486 BOOLEAN FirstCall = TRUE;
487 VFAT_DIRENTRY_CONTEXT DirContext;
488 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
489 WCHAR ShortNameBuffer[13];
490 ULONG Written;
491
492 PIO_STACK_LOCATION Stack = IrpContext->Stack;
493
494 pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2;
495 pFcb = (PVFATFCB)IrpContext->FileObject->FsContext;
496
497 /* Determine Buffer for result : */
498 BufferLength = Stack->Parameters.QueryDirectory.Length;
499 #if 0
500 /* Do not probe the user buffer until SEH is available */
501 if (IrpContext->Irp->RequestorMode != KernelMode &&
502 IrpContext->Irp->MdlAddress == NULL &&
503 IrpContext->Irp->UserBuffer != NULL)
504 {
505 ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
506 }
507 #endif
508 Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE);
509
510 if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
511 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
512 {
513 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
514 if (NT_SUCCESS(Status))
515 Status = STATUS_PENDING;
516
517 return Status;
518 }
519
520 if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
521 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
522 {
523 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
524 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
525 if (NT_SUCCESS(Status))
526 Status = STATUS_PENDING;
527
528 return Status;
529 }
530
531 /* Obtain the callers parameters */
532 #ifdef _MSC_VER
533 /* HACKHACK: Bug in the MS ntifs.h header:
534 * FileName is really a PUNICODE_STRING, not a PSTRING */
535 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
536 #else
537 pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
538 #endif
539 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
540
541 /* Allocate search pattern in case:
542 * -> We don't have one already in context
543 * -> We have been given an input pattern
544 * -> The pattern length is not null
545 * -> The pattern buffer is not null
546 * Otherwise, we'll fall later and allocate a match all (*) pattern
547 */
548 if (pSearchPattern &&
549 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
550 {
551 if (!pCcb->SearchPattern.Buffer)
552 {
553 FirstQuery = TRUE;
554 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
555 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
556 pCcb->SearchPattern.MaximumLength,
557 TAG_VFAT);
558 if (!pCcb->SearchPattern.Buffer)
559 {
560 ExReleaseResourceLite(&pFcb->MainResource);
561 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
562 return STATUS_INSUFFICIENT_RESOURCES;
563 }
564 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
565 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
566 }
567 }
568 else if (!pCcb->SearchPattern.Buffer)
569 {
570 FirstQuery = TRUE;
571 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
572 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
573 2 * sizeof(WCHAR),
574 TAG_VFAT);
575 if (!pCcb->SearchPattern.Buffer)
576 {
577 ExReleaseResourceLite(&pFcb->MainResource);
578 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
579 return STATUS_INSUFFICIENT_RESOURCES;
580 }
581 pCcb->SearchPattern.Buffer[0] = L'*';
582 pCcb->SearchPattern.Buffer[1] = 0;
583 pCcb->SearchPattern.Length = sizeof(WCHAR);
584 }
585
586 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_INDEX_SPECIFIED))
587 {
588 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
589 }
590 else if (FirstQuery || BooleanFlagOn(IrpContext->Stack->Flags, SL_RESTART_SCAN))
591 {
592 DirContext.DirIndex = pCcb->Entry = 0;
593 }
594 else
595 {
596 DirContext.DirIndex = pCcb->Entry;
597 }
598
599 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
600
601 DirContext.LongNameU.Buffer = LongNameBuffer;
602 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
603 DirContext.ShortNameU.Buffer = ShortNameBuffer;
604 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
605
606 Written = 0;
607 while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
608 {
609 Status = FindFile(IrpContext->DeviceExt,
610 pFcb,
611 &pCcb->SearchPattern,
612 &DirContext,
613 FirstCall);
614 pCcb->Entry = DirContext.DirIndex;
615
616 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);
617
618 FirstCall = FALSE;
619 if (NT_SUCCESS(Status))
620 {
621 switch (FileInformationClass)
622 {
623 case FileNameInformation:
624 Status = VfatGetFileNameInformation(&DirContext,
625 (PFILE_NAMES_INFORMATION)Buffer,
626 BufferLength,
627 &Written,
628 Buffer0 == NULL);
629 break;
630
631 case FileDirectoryInformation:
632 Status = VfatGetFileDirectoryInformation(&DirContext,
633 IrpContext->DeviceExt,
634 (PFILE_DIRECTORY_INFORMATION)Buffer,
635 BufferLength,
636 &Written,
637 Buffer0 == NULL);
638 break;
639
640 case FileFullDirectoryInformation:
641 Status = VfatGetFileFullDirectoryInformation(&DirContext,
642 IrpContext->DeviceExt,
643 (PFILE_FULL_DIR_INFORMATION)Buffer,
644 BufferLength,
645 &Written,
646 Buffer0 == NULL);
647 break;
648
649 case FileBothDirectoryInformation:
650 Status = VfatGetFileBothInformation(&DirContext,
651 IrpContext->DeviceExt,
652 (PFILE_BOTH_DIR_INFORMATION)Buffer,
653 BufferLength,
654 &Written,
655 Buffer0 == NULL);
656 break;
657
658 default:
659 Status = STATUS_INVALID_INFO_CLASS;
660 break;
661 }
662
663 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
664 break;
665 }
666 else
667 {
668 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
669 break;
670 }
671
672 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
673 Buffer0->FileIndex = DirContext.DirIndex;
674 pCcb->Entry = ++DirContext.DirIndex;
675 BufferLength -= Buffer0->NextEntryOffset;
676
677 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_RETURN_SINGLE_ENTRY))
678 break;
679
680 Buffer += Buffer0->NextEntryOffset;
681 }
682
683 if (Buffer0)
684 {
685 Buffer0->NextEntryOffset = 0;
686 Status = STATUS_SUCCESS;
687 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
688 }
689 else
690 {
691 ASSERT(Status != STATUS_SUCCESS || BufferLength == 0);
692 ASSERT(Written <= Stack->Parameters.QueryDirectory.Length);
693 IrpContext->Irp->IoStatus.Information = Written;
694 }
695
696 ExReleaseResourceLite(&pFcb->MainResource);
697 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
698
699 return Status;
700 }
701
702 NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
703 {
704 PVCB pVcb;
705 PVFATFCB pFcb;
706 PIO_STACK_LOCATION Stack;
707 Stack = IrpContext->Stack;
708 pVcb = IrpContext->DeviceExt;
709 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
710
711 FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
712 &(pVcb->NotifyList),
713 IrpContext->FileObject->FsContext2,
714 (PSTRING)&(pFcb->PathNameU),
715 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
716 FALSE,
717 Stack->Parameters.NotifyDirectory.CompletionFilter,
718 IrpContext->Irp,
719 NULL,
720 NULL);
721
722 /* We won't handle IRP completion */
723 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
724
725 return STATUS_PENDING;
726 }
727
728 /*
729 * FUNCTION: directory control : read/write directory informations
730 */
731 NTSTATUS
732 VfatDirectoryControl(
733 PVFAT_IRP_CONTEXT IrpContext)
734 {
735 NTSTATUS Status = STATUS_SUCCESS;
736
737 IrpContext->Irp->IoStatus.Information = 0;
738
739 switch (IrpContext->MinorFunction)
740 {
741 case IRP_MN_QUERY_DIRECTORY:
742 Status = DoQuery (IrpContext);
743 break;
744
745 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
746 Status = VfatNotifyChangeDirectory(IrpContext);
747 break;
748
749 default:
750 /* Error */
751 DPRINT("Unexpected minor function %x in VFAT driver\n",
752 IrpContext->MinorFunction);
753 Status = STATUS_INVALID_DEVICE_REQUEST;
754 break;
755 }
756
757 if (Status == STATUS_PENDING && BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE))
758 {
759 return VfatMarkIrpContextForQueue(IrpContext);
760 }
761
762 return Status;
763 }
764
765 /* EOF */