e8568e31d23df46d8a46ee07ec7875f5af4bb214
[reactos.git] / reactos / drivers / filesystems / cdfs / dirctl.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: services/fs/cdfs/dirctl.c
23 * PURPOSE: CDROM (ISO 9660) filesystem driver
24 * PROGRAMMER: Art Yerkes
25 * Eric Kohl
26 * UPDATE HISTORY:
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include "cdfs.h"
32
33 #define NDEBUG
34 #include <debug.h>
35
36 /* FUNCTIONS ****************************************************************/
37
38 #define ROUND_DOWN(N, S) (((N) / (S)) * (S))
39 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
40
41 /* FUNCTIONS ****************************************************************/
42
43 /*
44 * FUNCTION: Retrieves the file name, be it in short or long file name format
45 */
46 static NTSTATUS
47 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
48 PVOID *Context,
49 PVOID *Block,
50 PLARGE_INTEGER StreamOffset,
51 ULONG DirLength,
52 PVOID *Ptr,
53 PWSTR Name,
54 PULONG pIndex,
55 PULONG CurrentOffset)
56 {
57 PDIR_RECORD Record = *Ptr;
58 ULONG Index;
59
60 if (*CurrentOffset >= DirLength)
61 return(STATUS_NO_MORE_ENTRIES);
62
63 if (*CurrentOffset == 0)
64 {
65 Index = 0;
66 Record = (PDIR_RECORD)*Block;
67 while (Index < *pIndex)
68 {
69 (*Ptr) = (PVOID)((ULONG_PTR)(*Ptr) + Record->RecordLength);
70 (*CurrentOffset) += Record->RecordLength;
71 Record = *Ptr;
72 if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0)
73 {
74 DPRINT("Map next sector\n");
75 CcUnpinData(*Context);
76 StreamOffset->QuadPart += BLOCKSIZE;
77 *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE);
78 if (!CcMapData(DeviceExt->StreamFileObject,
79 StreamOffset,
80 BLOCKSIZE, TRUE,
81 Context, Block))
82 {
83 DPRINT("CcMapData() failed\n");
84 return(STATUS_UNSUCCESSFUL);
85 }
86 *Ptr = *Block;
87 Record = (PDIR_RECORD)*Ptr;
88 }
89 if (*CurrentOffset >= DirLength)
90 return(STATUS_NO_MORE_ENTRIES);
91
92 Index++;
93 }
94 }
95
96 if ((ULONG_PTR)(*Ptr) - (ULONG_PTR)(*Block) >= BLOCKSIZE || Record->RecordLength == 0)
97 {
98 DPRINT("Map next sector\n");
99 CcUnpinData(*Context);
100 StreamOffset->QuadPart += BLOCKSIZE;
101 *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE);
102 if (!CcMapData(DeviceExt->StreamFileObject,
103 StreamOffset,
104 BLOCKSIZE, TRUE,
105 Context, Block))
106 {
107 DPRINT("CcMapData() failed\n");
108 return(STATUS_UNSUCCESSFUL);
109 }
110 *Ptr = *Block;
111 Record = (PDIR_RECORD)*Ptr;
112 }
113
114 if (*CurrentOffset >= DirLength)
115 return STATUS_NO_MORE_ENTRIES;
116
117 DPRINT("Index %lu RecordLength %lu Offset %lu\n",
118 *pIndex, Record->RecordLength, *CurrentOffset);
119
120 if (Record->FileIdLength == 1 && Record->FileId[0] == 0)
121 {
122 wcscpy(Name, L".");
123 }
124 else if (Record->FileIdLength == 1 && Record->FileId[0] == 1)
125 {
126 wcscpy(Name, L"..");
127 }
128 else
129 {
130 if (DeviceExt->CdInfo.JolietLevel == 0)
131 {
132 ULONG i;
133
134 for (i = 0; i < Record->FileIdLength && Record->FileId[i] != ';'; i++)
135 Name[i] = (WCHAR)Record->FileId[i];
136 Name[i] = 0;
137 }
138 else
139 {
140 CdfsSwapString(Name, Record->FileId, Record->FileIdLength);
141 }
142 }
143
144 DPRINT("Name '%S'\n", Name);
145
146 *Ptr = Record;
147
148 return(STATUS_SUCCESS);
149 }
150
151
152 /*
153 * FUNCTION: Find a file
154 */
155 static NTSTATUS
156 CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
157 PFCB Fcb,
158 PFCB Parent,
159 PUNICODE_STRING FileToFind,
160 PULONG pDirIndex,
161 PULONG pOffset)
162 {
163 WCHAR name[256];
164 WCHAR ShortNameBuffer[13];
165 UNICODE_STRING TempString;
166 UNICODE_STRING ShortName;
167 UNICODE_STRING LongName;
168 UNICODE_STRING FileToFindUpcase;
169 PVOID Block;
170 NTSTATUS Status;
171 ULONG len;
172 ULONG DirIndex;
173 ULONG Offset = 0;
174 BOOLEAN IsRoot;
175 PVOID Context = NULL;
176 ULONG DirSize;
177 PDIR_RECORD Record;
178 LARGE_INTEGER StreamOffset, OffsetOfEntry;
179
180 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
181 Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
182 DPRINT("FindFile: old Pathname %p, old Objectname %p)\n",
183 Fcb->PathName, Fcb->ObjectName);
184
185 IsRoot = FALSE;
186 DirIndex = 0;
187
188 if (FileToFind == NULL || FileToFind->Length == 0)
189 {
190 RtlInitUnicodeString(&TempString, L".");
191 FileToFind = &TempString;
192 }
193
194 if (Parent)
195 {
196 if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
197 {
198 IsRoot = TRUE;
199 }
200 }
201 else
202 {
203 IsRoot = TRUE;
204 }
205
206 if (IsRoot == TRUE)
207 {
208 StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
209 DirSize = DeviceExt->CdInfo.RootSize;
210
211
212 if (FileToFind->Buffer[0] == 0 ||
213 (FileToFind->Buffer[0] == '\\' && FileToFind->Buffer[1] == 0) ||
214 (FileToFind->Buffer[0] == '.' && FileToFind->Buffer[1] == 0))
215 {
216 /* it's root : complete essentials fields then return ok */
217 RtlZeroMemory(Fcb, sizeof(FCB));
218
219 Fcb->PathName[0] = '\\';
220 Fcb->ObjectName = &Fcb->PathName[1];
221 Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
222 Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
223 Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY;
224
225 if (pDirIndex)
226 *pDirIndex = 0;
227 if (pOffset)
228 *pOffset = 0;
229 DPRINT("CdfsFindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
230 return STATUS_SUCCESS;
231 }
232 }
233 else
234 {
235 StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
236 DirSize = Parent->Entry.DataLengthL;
237 }
238
239 DPRINT("StreamOffset %I64d DirSize %u\n", StreamOffset.QuadPart, DirSize);
240
241 if (pDirIndex && (*pDirIndex))
242 DirIndex = *pDirIndex;
243
244 if (pOffset && (*pOffset))
245 {
246 Offset = *pOffset;
247 StreamOffset.QuadPart += ROUND_DOWN(Offset, BLOCKSIZE);
248 }
249
250 if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
251 BLOCKSIZE, TRUE, &Context, &Block))
252 {
253 DPRINT("CcMapData() failed\n");
254 return STATUS_UNSUCCESSFUL;
255 }
256
257 Record = (PDIR_RECORD) ((ULONG_PTR)Block + Offset % BLOCKSIZE);
258 if (Offset)
259 {
260 Offset += Record->RecordLength;
261 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
262 }
263
264 /* Upper case the expression for FsRtlIsNameInExpression */
265 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE);
266 if (!NT_SUCCESS(Status))
267 {
268 return Status;
269 }
270
271 while(TRUE)
272 {
273 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
274 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
275
276 Status = CdfsGetEntryName
277 (DeviceExt, &Context, &Block, &StreamOffset,
278 DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);
279
280 if (Status == STATUS_NO_MORE_ENTRIES)
281 {
282 break;
283 }
284 else if (Status == STATUS_UNSUCCESSFUL)
285 {
286 /* Note: the directory cache has already been unpinned */
287 RtlFreeUnicodeString(&FileToFindUpcase);
288 return Status;
289 }
290
291 DPRINT("Name '%S'\n", name);
292
293 RtlInitUnicodeString(&LongName, name);
294 ShortName.Length = 0;
295 ShortName.MaximumLength = 26;
296 ShortName.Buffer = ShortNameBuffer;
297
298 OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
299 CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName);
300
301 DPRINT("ShortName '%wZ'\n", &ShortName);
302
303 if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
304 FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
305 {
306 if (Parent->PathName[0])
307 {
308 len = wcslen(Parent->PathName);
309 memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
310 Fcb->ObjectName=&Fcb->PathName[len];
311 if (len != 1 || Fcb->PathName[0] != '\\')
312 {
313 Fcb->ObjectName[0] = '\\';
314 Fcb->ObjectName = &Fcb->ObjectName[1];
315 }
316 }
317 else
318 {
319 Fcb->ObjectName=Fcb->PathName;
320 Fcb->ObjectName[0]='\\';
321 Fcb->ObjectName=&Fcb->ObjectName[1];
322 }
323
324 DPRINT("PathName '%S' ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName);
325
326 memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD));
327 wcsncpy(Fcb->ObjectName, name, min(wcslen(name) + 1,
328 MAX_PATH - wcslen(Fcb->PathName) + wcslen(Fcb->ObjectName)));
329
330 /* Copy short name */
331 Fcb->ShortNameU.Length = ShortName.Length;
332 Fcb->ShortNameU.MaximumLength = ShortName.Length;
333 Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
334 memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length);
335
336 if (pDirIndex)
337 *pDirIndex = DirIndex;
338 if (pOffset)
339 *pOffset = Offset;
340
341 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %u\n",
342 Fcb->PathName, Fcb->ObjectName, DirIndex);
343
344 RtlFreeUnicodeString(&FileToFindUpcase);
345 CcUnpinData(Context);
346
347 return STATUS_SUCCESS;
348 }
349
350 Offset += Record->RecordLength;
351 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
352 DirIndex++;
353 }
354
355 RtlFreeUnicodeString(&FileToFindUpcase);
356 CcUnpinData(Context);
357
358 if (pDirIndex)
359 *pDirIndex = DirIndex;
360
361 if (pOffset)
362 *pOffset = Offset;
363
364 return STATUS_UNSUCCESSFUL;
365 }
366
367
368 static NTSTATUS
369 CdfsGetNameInformation(PFCB Fcb,
370 PDEVICE_EXTENSION DeviceExt,
371 PFILE_NAMES_INFORMATION Info,
372 ULONG BufferLength)
373 {
374 ULONG Length;
375
376 DPRINT("CdfsGetNameInformation() called\n");
377
378 UNREFERENCED_PARAMETER(DeviceExt);
379
380 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
381 if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
382 return(STATUS_BUFFER_OVERFLOW);
383
384 Info->FileNameLength = Length;
385 Info->NextEntryOffset =
386 ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
387 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
388
389 // Info->FileIndex=;
390
391 return(STATUS_SUCCESS);
392 }
393
394
395 static NTSTATUS
396 CdfsGetDirectoryInformation(PFCB Fcb,
397 PDEVICE_EXTENSION DeviceExt,
398 PFILE_DIRECTORY_INFORMATION Info,
399 ULONG BufferLength)
400 {
401 ULONG Length;
402
403 DPRINT("CdfsGetDirectoryInformation() called\n");
404
405 UNREFERENCED_PARAMETER(DeviceExt);
406
407 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
408 if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
409 return(STATUS_BUFFER_OVERFLOW);
410
411 Info->FileNameLength = Length;
412 Info->NextEntryOffset =
413 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
414 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
415
416 /* Convert file times */
417 CdfsDateTimeToSystemTime(Fcb,
418 &Info->CreationTime);
419 Info->LastWriteTime = Info->CreationTime;
420 Info->ChangeTime = Info->CreationTime;
421
422 /* Convert file flags */
423 CdfsFileFlagsToAttributes(Fcb,
424 &Info->FileAttributes);
425 if (CdfsFCBIsDirectory(Fcb))
426 {
427 Info->EndOfFile.QuadPart = 0;
428 Info->AllocationSize.QuadPart = 0;
429 }
430 else
431 {
432 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
433
434 /* Make AllocSize a rounded up multiple of the sector size */
435 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
436 }
437
438 // Info->FileIndex=;
439
440 return(STATUS_SUCCESS);
441 }
442
443
444 static NTSTATUS
445 CdfsGetFullDirectoryInformation(PFCB Fcb,
446 PDEVICE_EXTENSION DeviceExt,
447 PFILE_FULL_DIR_INFORMATION Info,
448 ULONG BufferLength)
449 {
450 ULONG Length;
451
452 DPRINT("CdfsGetFullDirectoryInformation() called\n");
453
454 UNREFERENCED_PARAMETER(DeviceExt);
455
456 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
457 if ((sizeof (FILE_FULL_DIR_INFORMATION) + Length) > BufferLength)
458 return(STATUS_BUFFER_OVERFLOW);
459
460 Info->FileNameLength = Length;
461 Info->NextEntryOffset =
462 ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) + Length, sizeof(ULONG));
463 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
464
465 /* Convert file times */
466 CdfsDateTimeToSystemTime(Fcb,
467 &Info->CreationTime);
468 Info->LastWriteTime = Info->CreationTime;
469 Info->ChangeTime = Info->CreationTime;
470
471 /* Convert file flags */
472 CdfsFileFlagsToAttributes(Fcb,
473 &Info->FileAttributes);
474
475 if (CdfsFCBIsDirectory(Fcb))
476 {
477 Info->EndOfFile.QuadPart = 0;
478 Info->AllocationSize.QuadPart = 0;
479 }
480 else
481 {
482 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
483
484 /* Make AllocSize a rounded up multiple of the sector size */
485 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
486 }
487
488 // Info->FileIndex=;
489 Info->EaSize = 0;
490
491 return(STATUS_SUCCESS);
492 }
493
494
495 static NTSTATUS
496 CdfsGetBothDirectoryInformation(PFCB Fcb,
497 PDEVICE_EXTENSION DeviceExt,
498 PFILE_BOTH_DIR_INFORMATION Info,
499 ULONG BufferLength)
500 {
501 ULONG Length;
502
503 DPRINT("CdfsGetBothDirectoryInformation() called\n");
504
505 UNREFERENCED_PARAMETER(DeviceExt);
506
507 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
508 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
509 return(STATUS_BUFFER_OVERFLOW);
510
511 Info->FileNameLength = Length;
512 Info->NextEntryOffset =
513 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
514 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
515
516 /* Convert file times */
517 CdfsDateTimeToSystemTime(Fcb,
518 &Info->CreationTime);
519 Info->LastWriteTime = Info->CreationTime;
520 Info->ChangeTime = Info->CreationTime;
521
522 /* Convert file flags */
523 CdfsFileFlagsToAttributes(Fcb,
524 &Info->FileAttributes);
525
526 if (CdfsFCBIsDirectory(Fcb))
527 {
528 Info->EndOfFile.QuadPart = 0;
529 Info->AllocationSize.QuadPart = 0;
530 }
531 else
532 {
533 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
534
535 /* Make AllocSize a rounded up multiple of the sector size */
536 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
537 }
538
539 // Info->FileIndex=;
540 Info->EaSize = 0;
541
542 /* Copy short name */
543 ASSERT(Fcb->ShortNameU.Length / sizeof(WCHAR) <= 12);
544 Info->ShortNameLength = (CCHAR)Fcb->ShortNameU.Length;
545 RtlCopyMemory(Info->ShortName, Fcb->ShortNameU.Buffer, Fcb->ShortNameU.Length);
546
547 return(STATUS_SUCCESS);
548 }
549
550
551 static NTSTATUS
552 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject,
553 PIRP Irp)
554 {
555 PDEVICE_EXTENSION DeviceExtension;
556 LONG BufferLength = 0;
557 PUNICODE_STRING SearchPattern = NULL;
558 FILE_INFORMATION_CLASS FileInformationClass;
559 ULONG FileIndex = 0;
560 PUCHAR Buffer = NULL;
561 PFILE_NAMES_INFORMATION Buffer0 = NULL;
562 PFCB Fcb;
563 PCCB Ccb;
564 FCB TempFcb;
565 BOOLEAN First = FALSE;
566 PIO_STACK_LOCATION Stack;
567 PFILE_OBJECT FileObject;
568 NTSTATUS Status = STATUS_SUCCESS;
569
570 DPRINT("CdfsQueryDirectory() called\n");
571
572 DeviceExtension = DeviceObject->DeviceExtension;
573 Stack = IoGetCurrentIrpStackLocation(Irp);
574 FileObject = Stack->FileObject;
575
576 Ccb = (PCCB)FileObject->FsContext2;
577 Fcb = (PFCB)FileObject->FsContext;
578
579 /* Obtain the callers parameters */
580 BufferLength = Stack->Parameters.QueryDirectory.Length;
581 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
582 FileInformationClass =
583 Stack->Parameters.QueryDirectory.FileInformationClass;
584 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
585
586 /* Determine Buffer for result */
587 if (Irp->MdlAddress)
588 {
589 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
590 }
591 else
592 {
593 Buffer = Irp->UserBuffer;
594 }
595
596 /* Allocate search pattern in case:
597 * -> We don't have one already in context
598 * -> We have been given an input pattern
599 * -> The pattern length is not null
600 * -> The pattern buffer is not null
601 * Otherwise, we'll fall later and allocate a match all (*) pattern
602 */
603 if (SearchPattern != NULL &&
604 SearchPattern->Length != 0 && SearchPattern->Buffer != NULL)
605 {
606 if (Ccb->DirectorySearchPattern.Buffer == NULL)
607 {
608 First = TRUE;
609 Ccb->DirectorySearchPattern.Buffer =
610 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_CCB);
611 if (Ccb->DirectorySearchPattern.Buffer == NULL)
612 {
613 return STATUS_INSUFFICIENT_RESOURCES;
614 }
615 Ccb->DirectorySearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
616 RtlCopyUnicodeString(&Ccb->DirectorySearchPattern, SearchPattern);
617 Ccb->DirectorySearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
618 }
619 }
620 else if (Ccb->DirectorySearchPattern.Buffer == NULL)
621 {
622 First = TRUE;
623 Ccb->DirectorySearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_CCB);
624 if (Ccb->DirectorySearchPattern.Buffer == NULL)
625 {
626 return STATUS_INSUFFICIENT_RESOURCES;
627 }
628
629 Ccb->DirectorySearchPattern.Length = sizeof(WCHAR);
630 Ccb->DirectorySearchPattern.MaximumLength = 2 * sizeof(WCHAR);
631 Ccb->DirectorySearchPattern.Buffer[0] = L'*';
632 Ccb->DirectorySearchPattern.Buffer[1] = 0;
633 }
634 DPRINT("Search pattern '%wZ'\n", &Ccb->DirectorySearchPattern);
635
636 /* Determine directory index */
637 if (Stack->Flags & SL_INDEX_SPECIFIED)
638 {
639 Ccb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
640 Ccb->Offset = Ccb->CurrentByteOffset.u.LowPart;
641 }
642 else if (First || (Stack->Flags & SL_RESTART_SCAN))
643 {
644 Ccb->Entry = 0;
645 Ccb->Offset = 0;
646 }
647 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->DirectorySearchPattern);
648
649 TempFcb.ObjectName = TempFcb.PathName;
650 while (Status == STATUS_SUCCESS && BufferLength > 0)
651 {
652 Status = CdfsFindFile(DeviceExtension,
653 &TempFcb,
654 Fcb,
655 &Ccb->DirectorySearchPattern,
656 &Ccb->Entry,
657 &Ccb->Offset);
658 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
659
660 if (NT_SUCCESS(Status))
661 {
662 switch (FileInformationClass)
663 {
664 case FileNameInformation:
665 Status = CdfsGetNameInformation(&TempFcb,
666 DeviceExtension,
667 (PFILE_NAMES_INFORMATION)Buffer,
668 BufferLength);
669 break;
670
671 case FileDirectoryInformation:
672 Status = CdfsGetDirectoryInformation(&TempFcb,
673 DeviceExtension,
674 (PFILE_DIRECTORY_INFORMATION)Buffer,
675 BufferLength);
676 break;
677
678 case FileFullDirectoryInformation:
679 Status = CdfsGetFullDirectoryInformation(&TempFcb,
680 DeviceExtension,
681 (PFILE_FULL_DIR_INFORMATION)Buffer,
682 BufferLength);
683 break;
684
685 case FileBothDirectoryInformation:
686 Status = CdfsGetBothDirectoryInformation(&TempFcb,
687 DeviceExtension,
688 (PFILE_BOTH_DIR_INFORMATION)Buffer,
689 BufferLength);
690 break;
691
692 default:
693 Status = STATUS_INVALID_INFO_CLASS;
694 }
695
696 if (Status == STATUS_BUFFER_OVERFLOW)
697 {
698 if (Buffer0)
699 {
700 Buffer0->NextEntryOffset = 0;
701 }
702 break;
703 }
704 }
705 else
706 {
707 if (Buffer0)
708 {
709 Buffer0->NextEntryOffset = 0;
710 }
711
712 if (First)
713 {
714 Status = STATUS_NO_SUCH_FILE;
715 }
716 else
717 {
718 Status = STATUS_NO_MORE_FILES;
719 }
720 break;
721 }
722
723 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
724 Buffer0->FileIndex = FileIndex++;
725 Ccb->Entry++;
726
727 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
728 {
729 break;
730 }
731 BufferLength -= Buffer0->NextEntryOffset;
732 Buffer += Buffer0->NextEntryOffset;
733 }
734
735 if (Buffer0)
736 {
737 Buffer0->NextEntryOffset = 0;
738 }
739
740 if (FileIndex > 0)
741 {
742 Status = STATUS_SUCCESS;
743 }
744
745 return(Status);
746 }
747
748
749
750 NTSTATUS NTAPI
751 CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
752 PIRP Irp)
753 {
754 PIO_STACK_LOCATION Stack;
755 NTSTATUS Status;
756
757 DPRINT("CdfsDirectoryControl() called\n");
758 FsRtlEnterFileSystem();
759
760 Stack = IoGetCurrentIrpStackLocation(Irp);
761
762 switch (Stack->MinorFunction)
763 {
764 case IRP_MN_QUERY_DIRECTORY:
765 Status = CdfsQueryDirectory(DeviceObject,
766 Irp);
767 break;
768
769 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
770 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
771 Status = STATUS_NOT_IMPLEMENTED;
772 break;
773
774 default:
775 DPRINT1("CDFS: MinorFunction %u\n", Stack->MinorFunction);
776 Status = STATUS_INVALID_DEVICE_REQUEST;
777 break;
778 }
779
780 Irp->IoStatus.Status = Status;
781 Irp->IoStatus.Information = 0;
782
783 IoCompleteRequest(Irp, IO_NO_INCREMENT);
784 FsRtlExitFileSystem();
785
786 return(Status);
787 }
788
789 /* EOF */