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