[FASTFAT] Don't mix FileNameInformation and FileNamesInformation (and support the...
[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_NAME_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 if (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName))
113 {
114 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName));
115 RtlCopyMemory(pInfo->FileName,
116 DirContext->LongNameU.Buffer,
117 BytesToCopy);
118 *Written += BytesToCopy;
119
120 if (BytesToCopy == DirContext->LongNameU.Length)
121 {
122 Status = STATUS_SUCCESS;
123 }
124 }
125 }
126
127 return Status;
128 }
129
130 static
131 NTSTATUS
132 VfatGetFileNamesInformation(
133 PVFAT_DIRENTRY_CONTEXT DirContext,
134 PFILE_NAMES_INFORMATION pInfo,
135 ULONG BufferLength,
136 PULONG Written,
137 BOOLEAN First)
138 {
139 NTSTATUS Status;
140 ULONG BytesToCopy = 0;
141
142 *Written = 0;
143 Status = STATUS_BUFFER_OVERFLOW;
144
145 if (FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) > BufferLength)
146 return Status;
147
148 if (First || (BufferLength >= FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName) + DirContext->LongNameU.Length))
149 {
150 pInfo->FileNameLength = DirContext->LongNameU.Length;
151
152 *Written = FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName);
153 pInfo->NextEntryOffset = 0;
154 if (BufferLength > FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName))
155 {
156 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName));
157 RtlCopyMemory(pInfo->FileName,
158 DirContext->LongNameU.Buffer,
159 BytesToCopy);
160 *Written += BytesToCopy;
161
162 if (BytesToCopy == DirContext->LongNameU.Length)
163 {
164 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_NAMES_INFORMATION) +
165 BytesToCopy);
166 Status = STATUS_SUCCESS;
167 }
168 }
169 }
170
171 return Status;
172 }
173
174 static
175 NTSTATUS
176 VfatGetFileDirectoryInformation(
177 PVFAT_DIRENTRY_CONTEXT DirContext,
178 PDEVICE_EXTENSION DeviceExt,
179 PFILE_DIRECTORY_INFORMATION pInfo,
180 ULONG BufferLength,
181 PULONG Written,
182 BOOLEAN First)
183 {
184 NTSTATUS Status;
185 ULONG BytesToCopy = 0;
186
187 *Written = 0;
188 Status = STATUS_BUFFER_OVERFLOW;
189
190 if (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) > BufferLength)
191 return Status;
192
193 if (First || (BufferLength >= FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName) + DirContext->LongNameU.Length))
194 {
195 pInfo->FileNameLength = DirContext->LongNameU.Length;
196 /* pInfo->FileIndex = ; */
197
198 *Written = FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName);
199 pInfo->NextEntryOffset = 0;
200 if (BufferLength > FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName))
201 {
202 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName));
203 RtlCopyMemory(pInfo->FileName,
204 DirContext->LongNameU.Buffer,
205 BytesToCopy);
206 *Written += BytesToCopy;
207
208 if (BytesToCopy == DirContext->LongNameU.Length)
209 {
210 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) +
211 BytesToCopy);
212 Status = STATUS_SUCCESS;
213 }
214 }
215
216
217
218 if (vfatVolumeIsFatX(DeviceExt))
219 {
220 FsdDosDateTimeToSystemTime(DeviceExt,
221 DirContext->DirEntry.FatX.CreationDate,
222 DirContext->DirEntry.FatX.CreationTime,
223 &pInfo->CreationTime);
224 FsdDosDateTimeToSystemTime(DeviceExt,
225 DirContext->DirEntry.FatX.AccessDate,
226 DirContext->DirEntry.FatX.AccessTime,
227 &pInfo->LastAccessTime);
228 FsdDosDateTimeToSystemTime(DeviceExt,
229 DirContext->DirEntry.FatX.UpdateDate,
230 DirContext->DirEntry.FatX.UpdateTime,
231 &pInfo->LastWriteTime);
232
233 pInfo->ChangeTime = pInfo->LastWriteTime;
234
235 if (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY))
236 {
237 pInfo->EndOfFile.QuadPart = 0;
238 pInfo->AllocationSize.QuadPart = 0;
239 }
240 else
241 {
242 pInfo->EndOfFile.u.HighPart = 0;
243 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
244 /* Make allocsize a rounded up multiple of BytesPerCluster */
245 pInfo->AllocationSize.u.HighPart = 0;
246 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
247 DeviceExt->FatInfo.BytesPerCluster);
248 }
249
250 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
251 }
252 else
253 {
254 FsdDosDateTimeToSystemTime(DeviceExt,
255 DirContext->DirEntry.Fat.CreationDate,
256 DirContext->DirEntry.Fat.CreationTime,
257 &pInfo->CreationTime);
258 FsdDosDateTimeToSystemTime(DeviceExt,
259 DirContext->DirEntry.Fat.AccessDate,
260 0,
261 &pInfo->LastAccessTime);
262 FsdDosDateTimeToSystemTime(DeviceExt,
263 DirContext->DirEntry.Fat.UpdateDate,
264 DirContext->DirEntry.Fat.UpdateTime,
265 &pInfo->LastWriteTime);
266
267 pInfo->ChangeTime = pInfo->LastWriteTime;
268
269 if (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY))
270 {
271 pInfo->EndOfFile.QuadPart = 0;
272 pInfo->AllocationSize.QuadPart = 0;
273 }
274 else
275 {
276 pInfo->EndOfFile.u.HighPart = 0;
277 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
278 /* Make allocsize a rounded up multiple of BytesPerCluster */
279 pInfo->AllocationSize.u.HighPart = 0;
280 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize,
281 DeviceExt->FatInfo.BytesPerCluster);
282 }
283
284 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
285 }
286 }
287
288 return Status;
289 }
290
291 static
292 NTSTATUS
293 VfatGetFileFullDirectoryInformation(
294 PVFAT_DIRENTRY_CONTEXT DirContext,
295 PDEVICE_EXTENSION DeviceExt,
296 PFILE_FULL_DIR_INFORMATION pInfo,
297 ULONG BufferLength,
298 PULONG Written,
299 BOOLEAN First)
300 {
301 NTSTATUS Status;
302 ULONG BytesToCopy = 0;
303
304 *Written = 0;
305 Status = STATUS_BUFFER_OVERFLOW;
306
307 if (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) > BufferLength)
308 return Status;
309
310 if (First || (BufferLength >= FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length))
311 {
312 pInfo->FileNameLength = DirContext->LongNameU.Length;
313 /* pInfo->FileIndex = ; */
314 pInfo->EaSize = 0;
315
316 *Written = FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName);
317 pInfo->NextEntryOffset = 0;
318 if (BufferLength > FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName))
319 {
320 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName));
321 RtlCopyMemory(pInfo->FileName,
322 DirContext->LongNameU.Buffer,
323 BytesToCopy);
324 *Written += BytesToCopy;
325
326 if (BytesToCopy == DirContext->LongNameU.Length)
327 {
328 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) +
329 BytesToCopy);
330 Status = STATUS_SUCCESS;
331 }
332 }
333
334 if (vfatVolumeIsFatX(DeviceExt))
335 {
336 FsdDosDateTimeToSystemTime(DeviceExt,
337 DirContext->DirEntry.FatX.CreationDate,
338 DirContext->DirEntry.FatX.CreationTime,
339 &pInfo->CreationTime);
340 FsdDosDateTimeToSystemTime(DeviceExt,
341 DirContext->DirEntry.FatX.AccessDate,
342 DirContext->DirEntry.FatX.AccessTime,
343 &pInfo->LastAccessTime);
344 FsdDosDateTimeToSystemTime(DeviceExt,
345 DirContext->DirEntry.FatX.UpdateDate,
346 DirContext->DirEntry.FatX.UpdateTime,
347 &pInfo->LastWriteTime);
348
349 pInfo->ChangeTime = pInfo->LastWriteTime;
350 pInfo->EndOfFile.u.HighPart = 0;
351 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
352 /* Make allocsize a rounded up multiple of BytesPerCluster */
353 pInfo->AllocationSize.u.HighPart = 0;
354 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
355 DeviceExt->FatInfo.BytesPerCluster);
356 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
357 }
358 else
359 {
360 FsdDosDateTimeToSystemTime(DeviceExt,
361 DirContext->DirEntry.Fat.CreationDate,
362 DirContext->DirEntry.Fat.CreationTime,
363 &pInfo->CreationTime);
364 FsdDosDateTimeToSystemTime(DeviceExt,
365 DirContext->DirEntry.Fat.AccessDate,
366 0,
367 &pInfo->LastAccessTime);
368 FsdDosDateTimeToSystemTime(DeviceExt,
369 DirContext->DirEntry.Fat.UpdateDate,
370 DirContext->DirEntry.Fat.UpdateTime,
371 &pInfo->LastWriteTime);
372
373 pInfo->ChangeTime = pInfo->LastWriteTime;
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,
379 DeviceExt->FatInfo.BytesPerCluster);
380 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
381 }
382 }
383
384 return Status;
385 }
386
387 static
388 NTSTATUS
389 VfatGetFileBothInformation(
390 PVFAT_DIRENTRY_CONTEXT DirContext,
391 PDEVICE_EXTENSION DeviceExt,
392 PFILE_BOTH_DIR_INFORMATION pInfo,
393 ULONG BufferLength,
394 PULONG Written,
395 BOOLEAN First)
396 {
397 NTSTATUS Status;
398 ULONG BytesToCopy = 0;
399
400 *Written = 0;
401 Status = STATUS_BUFFER_OVERFLOW;
402
403 if (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) > BufferLength)
404 return Status;
405
406 if (First || (BufferLength >= FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName) + DirContext->LongNameU.Length))
407 {
408 pInfo->FileNameLength = DirContext->LongNameU.Length;
409 pInfo->EaSize = 0;
410
411 *Written = FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName);
412 pInfo->NextEntryOffset = 0;
413 if (BufferLength > FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName))
414 {
415 BytesToCopy = min(DirContext->LongNameU.Length, BufferLength - FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName));
416 RtlCopyMemory(pInfo->FileName,
417 DirContext->LongNameU.Buffer,
418 BytesToCopy);
419 *Written += BytesToCopy;
420
421 if (BytesToCopy == DirContext->LongNameU.Length)
422 {
423 pInfo->NextEntryOffset = ULONG_ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) +
424 BytesToCopy);
425 Status = STATUS_SUCCESS;
426 }
427 }
428
429 if (vfatVolumeIsFatX(DeviceExt))
430 {
431 pInfo->ShortName[0] = 0;
432 pInfo->ShortNameLength = 0;
433 /* pInfo->FileIndex = ; */
434
435 FsdDosDateTimeToSystemTime(DeviceExt,
436 DirContext->DirEntry.FatX.CreationDate,
437 DirContext->DirEntry.FatX.CreationTime,
438 &pInfo->CreationTime);
439 FsdDosDateTimeToSystemTime(DeviceExt,
440 DirContext->DirEntry.FatX.AccessDate,
441 DirContext->DirEntry.FatX.AccessTime,
442 &pInfo->LastAccessTime);
443 FsdDosDateTimeToSystemTime(DeviceExt,
444 DirContext->DirEntry.FatX.UpdateDate,
445 DirContext->DirEntry.FatX.UpdateTime,
446 &pInfo->LastWriteTime);
447
448 pInfo->ChangeTime = pInfo->LastWriteTime;
449
450 if (BooleanFlagOn(DirContext->DirEntry.FatX.Attrib, FILE_ATTRIBUTE_DIRECTORY))
451 {
452 pInfo->EndOfFile.QuadPart = 0;
453 pInfo->AllocationSize.QuadPart = 0;
454 }
455 else
456 {
457 pInfo->EndOfFile.u.HighPart = 0;
458 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.FatX.FileSize;
459 /* Make allocsize a rounded up multiple of BytesPerCluster */
460 pInfo->AllocationSize.u.HighPart = 0;
461 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.FatX.FileSize,
462 DeviceExt->FatInfo.BytesPerCluster);
463 }
464
465 pInfo->FileAttributes = DirContext->DirEntry.FatX.Attrib & 0x3f;
466 }
467 else
468 {
469 pInfo->ShortNameLength = (CCHAR)DirContext->ShortNameU.Length;
470
471 RtlCopyMemory(pInfo->FileName,
472 DirContext->LongNameU.Buffer,
473 DirContext->LongNameU.Length);
474
475 /* pInfo->FileIndex = ; */
476
477 FsdDosDateTimeToSystemTime(DeviceExt,
478 DirContext->DirEntry.Fat.CreationDate,
479 DirContext->DirEntry.Fat.CreationTime,
480 &pInfo->CreationTime);
481 FsdDosDateTimeToSystemTime(DeviceExt,
482 DirContext->DirEntry.Fat.AccessDate,
483 0,
484 &pInfo->LastAccessTime);
485 FsdDosDateTimeToSystemTime(DeviceExt,
486 DirContext->DirEntry.Fat.UpdateDate,
487 DirContext->DirEntry.Fat.UpdateTime,
488 &pInfo->LastWriteTime);
489
490 pInfo->ChangeTime = pInfo->LastWriteTime;
491
492 if (BooleanFlagOn(DirContext->DirEntry.Fat.Attrib, FILE_ATTRIBUTE_DIRECTORY))
493 {
494 pInfo->EndOfFile.QuadPart = 0;
495 pInfo->AllocationSize.QuadPart = 0;
496 }
497 else
498 {
499 pInfo->EndOfFile.u.HighPart = 0;
500 pInfo->EndOfFile.u.LowPart = DirContext->DirEntry.Fat.FileSize;
501 /* Make allocsize a rounded up multiple of BytesPerCluster */
502 pInfo->AllocationSize.u.HighPart = 0;
503 pInfo->AllocationSize.u.LowPart = ROUND_UP(DirContext->DirEntry.Fat.FileSize, DeviceExt->FatInfo.BytesPerCluster);
504 }
505
506 pInfo->FileAttributes = DirContext->DirEntry.Fat.Attrib & 0x3f;
507 }
508 }
509
510 return Status;
511 }
512
513 static
514 NTSTATUS
515 DoQuery(
516 PVFAT_IRP_CONTEXT IrpContext)
517 {
518 NTSTATUS Status = STATUS_SUCCESS;
519 LONG BufferLength = 0;
520 PUNICODE_STRING pSearchPattern = NULL;
521 FILE_INFORMATION_CLASS FileInformationClass;
522 PUCHAR Buffer = NULL;
523 PFILE_NAMES_INFORMATION Buffer0 = NULL;
524 PVFATFCB pFcb;
525 PVFATCCB pCcb;
526 BOOLEAN FirstQuery = FALSE;
527 BOOLEAN FirstCall = TRUE;
528 VFAT_DIRENTRY_CONTEXT DirContext;
529 WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
530 WCHAR ShortNameBuffer[13];
531 ULONG Written;
532
533 PIO_STACK_LOCATION Stack = IrpContext->Stack;
534
535 pCcb = (PVFATCCB)IrpContext->FileObject->FsContext2;
536 pFcb = (PVFATFCB)IrpContext->FileObject->FsContext;
537
538 /* Determine Buffer for result : */
539 BufferLength = Stack->Parameters.QueryDirectory.Length;
540 #if 0
541 /* Do not probe the user buffer until SEH is available */
542 if (IrpContext->Irp->RequestorMode != KernelMode &&
543 IrpContext->Irp->MdlAddress == NULL &&
544 IrpContext->Irp->UserBuffer != NULL)
545 {
546 ProbeForWrite(IrpContext->Irp->UserBuffer, BufferLength, 1);
547 }
548 #endif
549 Buffer = VfatGetUserBuffer(IrpContext->Irp, FALSE);
550
551 if (!ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource,
552 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
553 {
554 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
555 if (NT_SUCCESS(Status))
556 Status = STATUS_PENDING;
557
558 return Status;
559 }
560
561 if (!ExAcquireResourceSharedLite(&pFcb->MainResource,
562 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
563 {
564 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
565 Status = VfatLockUserBuffer(IrpContext->Irp, BufferLength, IoWriteAccess);
566 if (NT_SUCCESS(Status))
567 Status = STATUS_PENDING;
568
569 return Status;
570 }
571
572 /* Obtain the callers parameters */
573 #ifdef _MSC_VER
574 /* HACKHACK: Bug in the MS ntifs.h header:
575 * FileName is really a PUNICODE_STRING, not a PSTRING */
576 pSearchPattern = (PUNICODE_STRING)Stack->Parameters.QueryDirectory.FileName;
577 #else
578 pSearchPattern = Stack->Parameters.QueryDirectory.FileName;
579 #endif
580 FileInformationClass = Stack->Parameters.QueryDirectory.FileInformationClass;
581
582 /* Allocate search pattern in case:
583 * -> We don't have one already in context
584 * -> We have been given an input pattern
585 * -> The pattern length is not null
586 * -> The pattern buffer is not null
587 * Otherwise, we'll fall later and allocate a match all (*) pattern
588 */
589 if (pSearchPattern &&
590 pSearchPattern->Length != 0 && pSearchPattern->Buffer != NULL)
591 {
592 if (!pCcb->SearchPattern.Buffer)
593 {
594 FirstQuery = TRUE;
595 pCcb->SearchPattern.MaximumLength = pSearchPattern->Length + sizeof(WCHAR);
596 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
597 pCcb->SearchPattern.MaximumLength,
598 TAG_VFAT);
599 if (!pCcb->SearchPattern.Buffer)
600 {
601 ExReleaseResourceLite(&pFcb->MainResource);
602 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
603 return STATUS_INSUFFICIENT_RESOURCES;
604 }
605 RtlCopyUnicodeString(&pCcb->SearchPattern, pSearchPattern);
606 pCcb->SearchPattern.Buffer[pCcb->SearchPattern.Length / sizeof(WCHAR)] = 0;
607 }
608 }
609 else if (!pCcb->SearchPattern.Buffer)
610 {
611 FirstQuery = TRUE;
612 pCcb->SearchPattern.MaximumLength = 2 * sizeof(WCHAR);
613 pCcb->SearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool,
614 2 * sizeof(WCHAR),
615 TAG_VFAT);
616 if (!pCcb->SearchPattern.Buffer)
617 {
618 ExReleaseResourceLite(&pFcb->MainResource);
619 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
620 return STATUS_INSUFFICIENT_RESOURCES;
621 }
622 pCcb->SearchPattern.Buffer[0] = L'*';
623 pCcb->SearchPattern.Buffer[1] = 0;
624 pCcb->SearchPattern.Length = sizeof(WCHAR);
625 }
626
627 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_INDEX_SPECIFIED))
628 {
629 DirContext.DirIndex = pCcb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
630 }
631 else if (FirstQuery || BooleanFlagOn(IrpContext->Stack->Flags, SL_RESTART_SCAN))
632 {
633 DirContext.DirIndex = pCcb->Entry = 0;
634 }
635 else
636 {
637 DirContext.DirIndex = pCcb->Entry;
638 }
639
640 DPRINT("Buffer=%p tofind=%wZ\n", Buffer, &pCcb->SearchPattern);
641
642 DirContext.LongNameU.Buffer = LongNameBuffer;
643 DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
644 DirContext.ShortNameU.Buffer = ShortNameBuffer;
645 DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
646
647 Written = 0;
648 while ((Status == STATUS_SUCCESS) && (BufferLength > 0))
649 {
650 Status = FindFile(IrpContext->DeviceExt,
651 pFcb,
652 &pCcb->SearchPattern,
653 &DirContext,
654 FirstCall);
655 pCcb->Entry = DirContext.DirIndex;
656
657 DPRINT("Found %wZ, Status=%x, entry %x\n", &DirContext.LongNameU, Status, pCcb->Entry);
658
659 FirstCall = FALSE;
660 if (NT_SUCCESS(Status))
661 {
662 switch (FileInformationClass)
663 {
664 case FileNameInformation:
665 Status = VfatGetFileNameInformation(&DirContext,
666 (PFILE_NAME_INFORMATION)Buffer,
667 BufferLength,
668 &Written,
669 Buffer0 == NULL);
670 break;
671
672 case FileDirectoryInformation:
673 Status = VfatGetFileDirectoryInformation(&DirContext,
674 IrpContext->DeviceExt,
675 (PFILE_DIRECTORY_INFORMATION)Buffer,
676 BufferLength,
677 &Written,
678 Buffer0 == NULL);
679 break;
680
681 case FileFullDirectoryInformation:
682 Status = VfatGetFileFullDirectoryInformation(&DirContext,
683 IrpContext->DeviceExt,
684 (PFILE_FULL_DIR_INFORMATION)Buffer,
685 BufferLength,
686 &Written,
687 Buffer0 == NULL);
688 break;
689
690 case FileBothDirectoryInformation:
691 Status = VfatGetFileBothInformation(&DirContext,
692 IrpContext->DeviceExt,
693 (PFILE_BOTH_DIR_INFORMATION)Buffer,
694 BufferLength,
695 &Written,
696 Buffer0 == NULL);
697 break;
698
699 case FileNamesInformation:
700 Status = VfatGetFileNamesInformation(&DirContext,
701 (PFILE_NAMES_INFORMATION)Buffer,
702 BufferLength,
703 &Written,
704 Buffer0 == NULL);
705 break;
706
707 default:
708 Status = STATUS_INVALID_INFO_CLASS;
709 break;
710 }
711
712 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_INVALID_INFO_CLASS)
713 break;
714 }
715 else
716 {
717 Status = (FirstQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
718 break;
719 }
720
721 Buffer0 = (PFILE_NAMES_INFORMATION) Buffer;
722 Buffer0->FileIndex = DirContext.DirIndex;
723 pCcb->Entry = ++DirContext.DirIndex;
724 BufferLength -= Buffer0->NextEntryOffset;
725
726 if (BooleanFlagOn(IrpContext->Stack->Flags, SL_RETURN_SINGLE_ENTRY))
727 break;
728
729 Buffer += Buffer0->NextEntryOffset;
730 }
731
732 if (Buffer0)
733 {
734 Buffer0->NextEntryOffset = 0;
735 Status = STATUS_SUCCESS;
736 IrpContext->Irp->IoStatus.Information = Stack->Parameters.QueryDirectory.Length - BufferLength;
737 }
738 else
739 {
740 ASSERT(Status != STATUS_SUCCESS || BufferLength == 0);
741 ASSERT(Written <= Stack->Parameters.QueryDirectory.Length);
742 IrpContext->Irp->IoStatus.Information = Written;
743 }
744
745 ExReleaseResourceLite(&pFcb->MainResource);
746 ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
747
748 return Status;
749 }
750
751 NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
752 {
753 PVCB pVcb;
754 PVFATFCB pFcb;
755 PIO_STACK_LOCATION Stack;
756 Stack = IrpContext->Stack;
757 pVcb = IrpContext->DeviceExt;
758 pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
759
760 FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
761 &(pVcb->NotifyList),
762 IrpContext->FileObject->FsContext2,
763 (PSTRING)&(pFcb->PathNameU),
764 BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
765 FALSE,
766 Stack->Parameters.NotifyDirectory.CompletionFilter,
767 IrpContext->Irp,
768 NULL,
769 NULL);
770
771 /* We won't handle IRP completion */
772 IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;
773
774 return STATUS_PENDING;
775 }
776
777 /*
778 * FUNCTION: directory control : read/write directory informations
779 */
780 NTSTATUS
781 VfatDirectoryControl(
782 PVFAT_IRP_CONTEXT IrpContext)
783 {
784 NTSTATUS Status = STATUS_SUCCESS;
785
786 IrpContext->Irp->IoStatus.Information = 0;
787
788 switch (IrpContext->MinorFunction)
789 {
790 case IRP_MN_QUERY_DIRECTORY:
791 Status = DoQuery (IrpContext);
792 break;
793
794 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
795 Status = VfatNotifyChangeDirectory(IrpContext);
796 break;
797
798 default:
799 /* Error */
800 DPRINT("Unexpected minor function %x in VFAT driver\n",
801 IrpContext->MinorFunction);
802 Status = STATUS_INVALID_DEVICE_REQUEST;
803 break;
804 }
805
806 if (Status == STATUS_PENDING && BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_COMPLETE))
807 {
808 return VfatMarkIrpContextForQueue(IrpContext);
809 }
810
811 return Status;
812 }
813
814 /* EOF */