[CDFS]
[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->PathNameBuffer[0] = '\\';
220 Fcb->ObjectName = &Fcb->PathNameBuffer[1];
221 Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
222 Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
223 Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY;
224 Fcb->PathName.Length = sizeof(WCHAR);
225 Fcb->PathName.MaximumLength = sizeof(Fcb->PathNameBuffer);
226 Fcb->PathName.Buffer = Fcb->PathNameBuffer;
227
228 if (pDirIndex)
229 *pDirIndex = 0;
230 if (pOffset)
231 *pOffset = 0;
232 DPRINT("CdfsFindFile: new Pathname %wZ, new Objectname %S)\n",&Fcb->PathName, Fcb->ObjectName);
233 return STATUS_SUCCESS;
234 }
235 }
236 else
237 {
238 StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
239 DirSize = Parent->Entry.DataLengthL;
240 }
241
242 DPRINT("StreamOffset %I64d DirSize %u\n", StreamOffset.QuadPart, DirSize);
243
244 if (pDirIndex && (*pDirIndex))
245 DirIndex = *pDirIndex;
246
247 if (pOffset && (*pOffset))
248 {
249 Offset = *pOffset;
250 StreamOffset.QuadPart += ROUND_DOWN(Offset, BLOCKSIZE);
251 }
252
253 if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
254 BLOCKSIZE, TRUE, &Context, &Block))
255 {
256 DPRINT("CcMapData() failed\n");
257 return STATUS_UNSUCCESSFUL;
258 }
259
260 Record = (PDIR_RECORD) ((ULONG_PTR)Block + Offset % BLOCKSIZE);
261 if (Offset)
262 {
263 Offset += Record->RecordLength;
264 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
265 }
266
267 /* Upper case the expression for FsRtlIsNameInExpression */
268 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE);
269 if (!NT_SUCCESS(Status))
270 {
271 return Status;
272 }
273
274 while(TRUE)
275 {
276 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
277 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
278
279 Status = CdfsGetEntryName
280 (DeviceExt, &Context, &Block, &StreamOffset,
281 DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);
282
283 if (Status == STATUS_NO_MORE_ENTRIES)
284 {
285 break;
286 }
287 else if (Status == STATUS_UNSUCCESSFUL)
288 {
289 /* Note: the directory cache has already been unpinned */
290 RtlFreeUnicodeString(&FileToFindUpcase);
291 return Status;
292 }
293
294 DPRINT("Name '%S'\n", name);
295
296 RtlInitUnicodeString(&LongName, name);
297 ShortName.Length = 0;
298 ShortName.MaximumLength = 26;
299 ShortName.Buffer = ShortNameBuffer;
300
301 OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
302 CdfsShortNameCacheGet(Parent, &OffsetOfEntry, &LongName, &ShortName);
303
304 DPRINT("ShortName '%wZ'\n", &ShortName);
305
306 if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
307 FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
308 {
309 if (Parent->PathName.Buffer[0])
310 {
311 len = Parent->PathName.Length / sizeof(WCHAR);
312 memcpy(Fcb->PathName.Buffer, Parent->PathName.Buffer, Parent->PathName.Length);
313 Fcb->PathName.Length = Parent->PathName.Length;
314 Fcb->ObjectName=&Fcb->PathName.Buffer[len];
315 if (len != 1 || Fcb->PathName.Buffer[0] != '\\')
316 {
317 Fcb->ObjectName[0] = '\\';
318 Fcb->ObjectName = &Fcb->ObjectName[1];
319 }
320 }
321 else
322 {
323 Fcb->ObjectName=Fcb->PathName.Buffer;
324 Fcb->ObjectName[0]='\\';
325 Fcb->ObjectName=&Fcb->ObjectName[1];
326 }
327
328 DPRINT("PathName '%wZ' ObjectName '%S'\n", &Fcb->PathName, Fcb->ObjectName);
329
330 memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD));
331 wcsncpy(Fcb->ObjectName, name, min(wcslen(name) + 1,
332 MAX_PATH - (Fcb->PathName.Length / sizeof(WCHAR)) + wcslen(Fcb->ObjectName)));
333
334 /* Copy short name */
335 Fcb->ShortNameU.Length = ShortName.Length;
336 Fcb->ShortNameU.MaximumLength = ShortName.Length;
337 Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
338 memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length);
339
340 if (pDirIndex)
341 *pDirIndex = DirIndex;
342 if (pOffset)
343 *pOffset = Offset;
344
345 DPRINT("FindFile: new Pathname %wZ, new Objectname %S, DirIndex %u\n",
346 &Fcb->PathName, Fcb->ObjectName, DirIndex);
347
348 RtlFreeUnicodeString(&FileToFindUpcase);
349 CcUnpinData(Context);
350
351 return STATUS_SUCCESS;
352 }
353
354 Offset += Record->RecordLength;
355 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
356 DirIndex++;
357 }
358
359 RtlFreeUnicodeString(&FileToFindUpcase);
360 CcUnpinData(Context);
361
362 if (pDirIndex)
363 *pDirIndex = DirIndex;
364
365 if (pOffset)
366 *pOffset = Offset;
367
368 return STATUS_UNSUCCESSFUL;
369 }
370
371
372 static NTSTATUS
373 CdfsGetNameInformation(PFCB Fcb,
374 PDEVICE_EXTENSION DeviceExt,
375 PFILE_NAMES_INFORMATION Info,
376 ULONG BufferLength)
377 {
378 ULONG Length;
379
380 DPRINT("CdfsGetNameInformation() called\n");
381
382 UNREFERENCED_PARAMETER(DeviceExt);
383
384 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
385 if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
386 return(STATUS_BUFFER_OVERFLOW);
387
388 Info->FileNameLength = Length;
389 Info->NextEntryOffset =
390 ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
391 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
392
393 // Info->FileIndex=;
394
395 return(STATUS_SUCCESS);
396 }
397
398
399 static NTSTATUS
400 CdfsGetDirectoryInformation(PFCB Fcb,
401 PDEVICE_EXTENSION DeviceExt,
402 PFILE_DIRECTORY_INFORMATION Info,
403 ULONG BufferLength)
404 {
405 ULONG Length;
406
407 DPRINT("CdfsGetDirectoryInformation() called\n");
408
409 UNREFERENCED_PARAMETER(DeviceExt);
410
411 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
412 if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
413 return(STATUS_BUFFER_OVERFLOW);
414
415 Info->FileNameLength = Length;
416 Info->NextEntryOffset =
417 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
418 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
419
420 /* Convert file times */
421 CdfsDateTimeToSystemTime(Fcb,
422 &Info->CreationTime);
423 Info->LastWriteTime = Info->CreationTime;
424 Info->ChangeTime = Info->CreationTime;
425
426 /* Convert file flags */
427 CdfsFileFlagsToAttributes(Fcb,
428 &Info->FileAttributes);
429 if (CdfsFCBIsDirectory(Fcb))
430 {
431 Info->EndOfFile.QuadPart = 0;
432 Info->AllocationSize.QuadPart = 0;
433 }
434 else
435 {
436 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
437
438 /* Make AllocSize a rounded up multiple of the sector size */
439 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
440 }
441
442 // Info->FileIndex=;
443
444 return(STATUS_SUCCESS);
445 }
446
447
448 static NTSTATUS
449 CdfsGetFullDirectoryInformation(PFCB Fcb,
450 PDEVICE_EXTENSION DeviceExt,
451 PFILE_FULL_DIR_INFORMATION Info,
452 ULONG BufferLength)
453 {
454 ULONG Length;
455
456 DPRINT("CdfsGetFullDirectoryInformation() called\n");
457
458 UNREFERENCED_PARAMETER(DeviceExt);
459
460 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
461 if ((sizeof (FILE_FULL_DIR_INFORMATION) + Length) > BufferLength)
462 return(STATUS_BUFFER_OVERFLOW);
463
464 Info->FileNameLength = Length;
465 Info->NextEntryOffset =
466 ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) + Length, sizeof(ULONG));
467 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
468
469 /* Convert file times */
470 CdfsDateTimeToSystemTime(Fcb,
471 &Info->CreationTime);
472 Info->LastWriteTime = Info->CreationTime;
473 Info->ChangeTime = Info->CreationTime;
474
475 /* Convert file flags */
476 CdfsFileFlagsToAttributes(Fcb,
477 &Info->FileAttributes);
478
479 if (CdfsFCBIsDirectory(Fcb))
480 {
481 Info->EndOfFile.QuadPart = 0;
482 Info->AllocationSize.QuadPart = 0;
483 }
484 else
485 {
486 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
487
488 /* Make AllocSize a rounded up multiple of the sector size */
489 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
490 }
491
492 // Info->FileIndex=;
493 Info->EaSize = 0;
494
495 return(STATUS_SUCCESS);
496 }
497
498
499 static NTSTATUS
500 CdfsGetBothDirectoryInformation(PFCB Fcb,
501 PDEVICE_EXTENSION DeviceExt,
502 PFILE_BOTH_DIR_INFORMATION Info,
503 ULONG BufferLength)
504 {
505 ULONG Length;
506
507 DPRINT("CdfsGetBothDirectoryInformation() called\n");
508
509 UNREFERENCED_PARAMETER(DeviceExt);
510
511 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
512 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
513 return(STATUS_BUFFER_OVERFLOW);
514
515 Info->FileNameLength = Length;
516 Info->NextEntryOffset =
517 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
518 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
519
520 /* Convert file times */
521 CdfsDateTimeToSystemTime(Fcb,
522 &Info->CreationTime);
523 Info->LastWriteTime = Info->CreationTime;
524 Info->ChangeTime = Info->CreationTime;
525
526 /* Convert file flags */
527 CdfsFileFlagsToAttributes(Fcb,
528 &Info->FileAttributes);
529
530 if (CdfsFCBIsDirectory(Fcb))
531 {
532 Info->EndOfFile.QuadPart = 0;
533 Info->AllocationSize.QuadPart = 0;
534 }
535 else
536 {
537 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
538
539 /* Make AllocSize a rounded up multiple of the sector size */
540 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
541 }
542
543 // Info->FileIndex=;
544 Info->EaSize = 0;
545
546 /* Copy short name */
547 ASSERT(Fcb->ShortNameU.Length / sizeof(WCHAR) <= 12);
548 Info->ShortNameLength = (CCHAR)Fcb->ShortNameU.Length;
549 RtlCopyMemory(Info->ShortName, Fcb->ShortNameU.Buffer, Fcb->ShortNameU.Length);
550
551 return(STATUS_SUCCESS);
552 }
553
554
555 static NTSTATUS
556 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject,
557 PIRP Irp)
558 {
559 PDEVICE_EXTENSION DeviceExtension;
560 LONG BufferLength = 0;
561 PUNICODE_STRING SearchPattern = NULL;
562 FILE_INFORMATION_CLASS FileInformationClass;
563 ULONG FileIndex = 0;
564 PUCHAR Buffer = NULL;
565 PFILE_NAMES_INFORMATION Buffer0 = NULL;
566 PFCB Fcb;
567 PCCB Ccb;
568 FCB TempFcb;
569 BOOLEAN First = FALSE;
570 PIO_STACK_LOCATION Stack;
571 PFILE_OBJECT FileObject;
572 NTSTATUS Status = STATUS_SUCCESS;
573
574 DPRINT("CdfsQueryDirectory() called\n");
575
576 DeviceExtension = DeviceObject->DeviceExtension;
577 Stack = IoGetCurrentIrpStackLocation(Irp);
578 FileObject = Stack->FileObject;
579 TempFcb.PathName.Buffer = TempFcb.PathNameBuffer;
580 TempFcb.PathName.MaximumLength = sizeof(TempFcb.PathNameBuffer);
581
582 Ccb = (PCCB)FileObject->FsContext2;
583 Fcb = (PFCB)FileObject->FsContext;
584
585 /* Obtain the callers parameters */
586 BufferLength = Stack->Parameters.QueryDirectory.Length;
587 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
588 FileInformationClass =
589 Stack->Parameters.QueryDirectory.FileInformationClass;
590 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
591
592 /* Determine Buffer for result */
593 if (Irp->MdlAddress)
594 {
595 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
596 }
597 else
598 {
599 Buffer = Irp->UserBuffer;
600 }
601
602 /* Allocate search pattern in case:
603 * -> We don't have one already in context
604 * -> We have been given an input pattern
605 * -> The pattern length is not null
606 * -> The pattern buffer is not null
607 * Otherwise, we'll fall later and allocate a match all (*) pattern
608 */
609 if (SearchPattern != NULL &&
610 SearchPattern->Length != 0 && SearchPattern->Buffer != NULL)
611 {
612 if (Ccb->DirectorySearchPattern.Buffer == NULL)
613 {
614 First = TRUE;
615 Ccb->DirectorySearchPattern.Buffer =
616 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_CCB);
617 if (Ccb->DirectorySearchPattern.Buffer == NULL)
618 {
619 return STATUS_INSUFFICIENT_RESOURCES;
620 }
621 Ccb->DirectorySearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
622 RtlCopyUnicodeString(&Ccb->DirectorySearchPattern, SearchPattern);
623 Ccb->DirectorySearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
624 }
625 }
626 else if (Ccb->DirectorySearchPattern.Buffer == NULL)
627 {
628 First = TRUE;
629 Ccb->DirectorySearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_CCB);
630 if (Ccb->DirectorySearchPattern.Buffer == NULL)
631 {
632 return STATUS_INSUFFICIENT_RESOURCES;
633 }
634
635 Ccb->DirectorySearchPattern.Length = sizeof(WCHAR);
636 Ccb->DirectorySearchPattern.MaximumLength = 2 * sizeof(WCHAR);
637 Ccb->DirectorySearchPattern.Buffer[0] = L'*';
638 Ccb->DirectorySearchPattern.Buffer[1] = 0;
639 }
640 DPRINT("Search pattern '%wZ'\n", &Ccb->DirectorySearchPattern);
641
642 /* Determine directory index */
643 if (Stack->Flags & SL_INDEX_SPECIFIED)
644 {
645 Ccb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
646 Ccb->Offset = Ccb->CurrentByteOffset.u.LowPart;
647 }
648 else if (First || (Stack->Flags & SL_RESTART_SCAN))
649 {
650 Ccb->Entry = 0;
651 Ccb->Offset = 0;
652 }
653 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->DirectorySearchPattern);
654
655 TempFcb.ObjectName = TempFcb.PathName.Buffer;
656 while (Status == STATUS_SUCCESS && BufferLength > 0)
657 {
658 Status = CdfsFindFile(DeviceExtension,
659 &TempFcb,
660 Fcb,
661 &Ccb->DirectorySearchPattern,
662 &Ccb->Entry,
663 &Ccb->Offset);
664 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
665
666 if (NT_SUCCESS(Status))
667 {
668 switch (FileInformationClass)
669 {
670 case FileNameInformation:
671 Status = CdfsGetNameInformation(&TempFcb,
672 DeviceExtension,
673 (PFILE_NAMES_INFORMATION)Buffer,
674 BufferLength);
675 break;
676
677 case FileDirectoryInformation:
678 Status = CdfsGetDirectoryInformation(&TempFcb,
679 DeviceExtension,
680 (PFILE_DIRECTORY_INFORMATION)Buffer,
681 BufferLength);
682 break;
683
684 case FileFullDirectoryInformation:
685 Status = CdfsGetFullDirectoryInformation(&TempFcb,
686 DeviceExtension,
687 (PFILE_FULL_DIR_INFORMATION)Buffer,
688 BufferLength);
689 break;
690
691 case FileBothDirectoryInformation:
692 Status = CdfsGetBothDirectoryInformation(&TempFcb,
693 DeviceExtension,
694 (PFILE_BOTH_DIR_INFORMATION)Buffer,
695 BufferLength);
696 break;
697
698 default:
699 Status = STATUS_INVALID_INFO_CLASS;
700 }
701
702 if (Status == STATUS_BUFFER_OVERFLOW)
703 {
704 if (Buffer0)
705 {
706 Buffer0->NextEntryOffset = 0;
707 }
708 break;
709 }
710 }
711 else
712 {
713 if (Buffer0)
714 {
715 Buffer0->NextEntryOffset = 0;
716 }
717
718 if (First)
719 {
720 Status = STATUS_NO_SUCH_FILE;
721 }
722 else
723 {
724 Status = STATUS_NO_MORE_FILES;
725 }
726 break;
727 }
728
729 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
730 Buffer0->FileIndex = FileIndex++;
731 Ccb->Entry++;
732
733 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
734 {
735 break;
736 }
737 BufferLength -= Buffer0->NextEntryOffset;
738 Buffer += Buffer0->NextEntryOffset;
739 }
740
741 if (Buffer0)
742 {
743 Buffer0->NextEntryOffset = 0;
744 }
745
746 if (FileIndex > 0)
747 {
748 Status = STATUS_SUCCESS;
749 }
750
751 return(Status);
752 }
753
754
755 NTSTATUS NTAPI
756 CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
757 PIRP Irp)
758 {
759 PIO_STACK_LOCATION Stack;
760 NTSTATUS Status;
761
762 DPRINT("CdfsDirectoryControl() called\n");
763 FsRtlEnterFileSystem();
764
765 Stack = IoGetCurrentIrpStackLocation(Irp);
766
767 switch (Stack->MinorFunction)
768 {
769 case IRP_MN_QUERY_DIRECTORY:
770 Status = CdfsQueryDirectory(DeviceObject,
771 Irp);
772 break;
773
774 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
775 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
776 Status = STATUS_NOT_IMPLEMENTED;
777 break;
778
779 default:
780 DPRINT1("CDFS: MinorFunction %u\n", Stack->MinorFunction);
781 Status = STATUS_INVALID_DEVICE_REQUEST;
782 break;
783 }
784
785 Irp->IoStatus.Status = Status;
786 Irp->IoStatus.Information = 0;
787
788 IoCompleteRequest(Irp, IO_NO_INCREMENT);
789 FsRtlExitFileSystem();
790
791 return(Status);
792 }
793
794 /* EOF */