- Remove ALL the unneeded "author date id revision" svn properties.
[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 /* $Id: dirctl.c 57791 2012-12-02 21:04:31Z pschweitzer $
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, min(wcslen(name) + 1,
329 MAX_PATH - wcslen(Fcb->PathName) + wcslen(Fcb->ObjectName)));
330
331 /* Copy short name */
332 Fcb->ShortNameU.Length = ShortName.Length;
333 Fcb->ShortNameU.MaximumLength = ShortName.Length;
334 Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
335 memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length);
336
337 if (pDirIndex)
338 *pDirIndex = DirIndex;
339 if (pOffset)
340 *pOffset = Offset;
341
342 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",
343 Fcb->PathName, Fcb->ObjectName, DirIndex);
344
345 RtlFreeUnicodeString(&FileToFindUpcase);
346 CcUnpinData(Context);
347
348 return STATUS_SUCCESS;
349 }
350
351 Offset += Record->RecordLength;
352 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
353 DirIndex++;
354 }
355
356 RtlFreeUnicodeString(&FileToFindUpcase);
357 CcUnpinData(Context);
358
359 if (pDirIndex)
360 *pDirIndex = DirIndex;
361
362 if (pOffset)
363 *pOffset = Offset;
364
365 return STATUS_UNSUCCESSFUL;
366 }
367
368
369 static NTSTATUS
370 CdfsGetNameInformation(PFCB Fcb,
371 PDEVICE_EXTENSION DeviceExt,
372 PFILE_NAMES_INFORMATION Info,
373 ULONG BufferLength)
374 {
375 ULONG Length;
376
377 DPRINT("CdfsGetNameInformation() called\n");
378
379 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
380 if ((sizeof(FILE_NAMES_INFORMATION) + Length) > BufferLength)
381 return(STATUS_BUFFER_OVERFLOW);
382
383 Info->FileNameLength = Length;
384 Info->NextEntryOffset =
385 ROUND_UP(sizeof(FILE_NAMES_INFORMATION) + Length, sizeof(ULONG));
386 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
387
388 // Info->FileIndex=;
389
390 return(STATUS_SUCCESS);
391 }
392
393
394 static NTSTATUS
395 CdfsGetDirectoryInformation(PFCB Fcb,
396 PDEVICE_EXTENSION DeviceExt,
397 PFILE_DIRECTORY_INFORMATION Info,
398 ULONG BufferLength)
399 {
400 ULONG Length;
401
402 DPRINT("CdfsGetDirectoryInformation() called\n");
403
404 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
405 if ((sizeof (FILE_DIRECTORY_INFORMATION) + Length) > BufferLength)
406 return(STATUS_BUFFER_OVERFLOW);
407
408 Info->FileNameLength = Length;
409 Info->NextEntryOffset =
410 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION) + Length, sizeof(ULONG));
411 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
412
413 /* Convert file times */
414 CdfsDateTimeToSystemTime(Fcb,
415 &Info->CreationTime);
416 Info->LastWriteTime = Info->CreationTime;
417 Info->ChangeTime = Info->CreationTime;
418
419 /* Convert file flags */
420 CdfsFileFlagsToAttributes(Fcb,
421 &Info->FileAttributes);
422 if (CdfsFCBIsDirectory(Fcb))
423 {
424 Info->EndOfFile.QuadPart = 0;
425 Info->AllocationSize.QuadPart = 0;
426 }
427 else
428 {
429 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
430
431 /* Make AllocSize a rounded up multiple of the sector size */
432 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
433 }
434
435 // Info->FileIndex=;
436
437 return(STATUS_SUCCESS);
438 }
439
440
441 static NTSTATUS
442 CdfsGetFullDirectoryInformation(PFCB Fcb,
443 PDEVICE_EXTENSION DeviceExt,
444 PFILE_FULL_DIR_INFORMATION Info,
445 ULONG BufferLength)
446 {
447 ULONG Length;
448
449 DPRINT("CdfsGetFullDirectoryInformation() called\n");
450
451 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
452 if ((sizeof (FILE_FULL_DIR_INFORMATION) + Length) > BufferLength)
453 return(STATUS_BUFFER_OVERFLOW);
454
455 Info->FileNameLength = Length;
456 Info->NextEntryOffset =
457 ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION) + Length, sizeof(ULONG));
458 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
459
460 /* Convert file times */
461 CdfsDateTimeToSystemTime(Fcb,
462 &Info->CreationTime);
463 Info->LastWriteTime = Info->CreationTime;
464 Info->ChangeTime = Info->CreationTime;
465
466 /* Convert file flags */
467 CdfsFileFlagsToAttributes(Fcb,
468 &Info->FileAttributes);
469
470 if (CdfsFCBIsDirectory(Fcb))
471 {
472 Info->EndOfFile.QuadPart = 0;
473 Info->AllocationSize.QuadPart = 0;
474 }
475 else
476 {
477 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
478
479 /* Make AllocSize a rounded up multiple of the sector size */
480 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
481 }
482
483 // Info->FileIndex=;
484 Info->EaSize = 0;
485
486 return(STATUS_SUCCESS);
487 }
488
489
490 static NTSTATUS
491 CdfsGetBothDirectoryInformation(PFCB Fcb,
492 PDEVICE_EXTENSION DeviceExt,
493 PFILE_BOTH_DIR_INFORMATION Info,
494 ULONG BufferLength)
495 {
496 ULONG Length;
497
498 DPRINT("CdfsGetBothDirectoryInformation() called\n");
499
500 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
501 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
502 return(STATUS_BUFFER_OVERFLOW);
503
504 Info->FileNameLength = Length;
505 Info->NextEntryOffset =
506 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, sizeof(ULONG));
507 RtlCopyMemory(Info->FileName, Fcb->ObjectName, Length);
508
509 /* Convert file times */
510 CdfsDateTimeToSystemTime(Fcb,
511 &Info->CreationTime);
512 Info->LastWriteTime = Info->CreationTime;
513 Info->ChangeTime = Info->CreationTime;
514
515 /* Convert file flags */
516 CdfsFileFlagsToAttributes(Fcb,
517 &Info->FileAttributes);
518
519 if (CdfsFCBIsDirectory(Fcb))
520 {
521 Info->EndOfFile.QuadPart = 0;
522 Info->AllocationSize.QuadPart = 0;
523 }
524 else
525 {
526 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
527
528 /* Make AllocSize a rounded up multiple of the sector size */
529 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
530 }
531
532 // Info->FileIndex=;
533 Info->EaSize = 0;
534
535 /* Copy short name */
536 ASSERT(Fcb->ShortNameU.Length / sizeof(WCHAR) <= 12);
537 Info->ShortNameLength = (CCHAR)Fcb->ShortNameU.Length;
538 RtlCopyMemory(Info->ShortName, Fcb->ShortNameU.Buffer, Fcb->ShortNameU.Length);
539
540 return(STATUS_SUCCESS);
541 }
542
543
544 static NTSTATUS
545 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject,
546 PIRP Irp)
547 {
548 PDEVICE_EXTENSION DeviceExtension;
549 LONG BufferLength = 0;
550 PUNICODE_STRING SearchPattern = NULL;
551 FILE_INFORMATION_CLASS FileInformationClass;
552 ULONG FileIndex = 0;
553 PUCHAR Buffer = NULL;
554 PFILE_NAMES_INFORMATION Buffer0 = NULL;
555 PFCB Fcb;
556 PCCB Ccb;
557 FCB TempFcb;
558 BOOLEAN First = FALSE;
559 PIO_STACK_LOCATION Stack;
560 PFILE_OBJECT FileObject;
561 NTSTATUS Status = STATUS_SUCCESS;
562
563 DPRINT("CdfsQueryDirectory() called\n");
564
565 DeviceExtension = DeviceObject->DeviceExtension;
566 Stack = IoGetCurrentIrpStackLocation(Irp);
567 FileObject = Stack->FileObject;
568
569 Ccb = (PCCB)FileObject->FsContext2;
570 Fcb = (PFCB)FileObject->FsContext;
571
572 /* Obtain the callers parameters */
573 BufferLength = Stack->Parameters.QueryDirectory.Length;
574 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
575 FileInformationClass =
576 Stack->Parameters.QueryDirectory.FileInformationClass;
577 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
578
579 /* Determine Buffer for result */
580 if (Irp->MdlAddress)
581 {
582 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
583 }
584 else
585 {
586 Buffer = Irp->UserBuffer;
587 }
588
589 /* Allocate search pattern in case:
590 * -> We don't have one already in context
591 * -> We have been given an input pattern
592 * -> The pattern length is not null
593 * -> The pattern buffer is not null
594 * Otherwise, we'll fall later and allocate a match all (*) pattern
595 */
596 if (SearchPattern != NULL &&
597 SearchPattern->Length != 0 && SearchPattern->Buffer != NULL)
598 {
599 if (Ccb->DirectorySearchPattern.Buffer == NULL)
600 {
601 First = TRUE;
602 Ccb->DirectorySearchPattern.Buffer =
603 ExAllocatePoolWithTag(NonPagedPool, SearchPattern->Length + sizeof(WCHAR), TAG_CCB);
604 if (Ccb->DirectorySearchPattern.Buffer == NULL)
605 {
606 return STATUS_INSUFFICIENT_RESOURCES;
607 }
608 Ccb->DirectorySearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
609 RtlCopyUnicodeString(&Ccb->DirectorySearchPattern, SearchPattern);
610 Ccb->DirectorySearchPattern.Buffer[SearchPattern->Length / sizeof(WCHAR)] = 0;
611 }
612 }
613 else if (Ccb->DirectorySearchPattern.Buffer == NULL)
614 {
615 First = TRUE;
616 Ccb->DirectorySearchPattern.Buffer = ExAllocatePoolWithTag(NonPagedPool, 2 * sizeof(WCHAR), TAG_CCB);
617 if (Ccb->DirectorySearchPattern.Buffer == NULL)
618 {
619 return STATUS_INSUFFICIENT_RESOURCES;
620 }
621
622 Ccb->DirectorySearchPattern.Length = sizeof(WCHAR);
623 Ccb->DirectorySearchPattern.MaximumLength = 2 * sizeof(WCHAR);
624 Ccb->DirectorySearchPattern.Buffer[0] = L'*';
625 Ccb->DirectorySearchPattern.Buffer[1] = 0;
626 }
627 DPRINT("Search pattern '%wZ'\n", &Ccb->DirectorySearchPattern);
628
629 /* Determine directory index */
630 if (Stack->Flags & SL_INDEX_SPECIFIED)
631 {
632 Ccb->Entry = Stack->Parameters.QueryDirectory.FileIndex;
633 Ccb->Offset = Ccb->CurrentByteOffset.u.LowPart;
634 }
635 else if (First || (Stack->Flags & SL_RESTART_SCAN))
636 {
637 Ccb->Entry = 0;
638 Ccb->Offset = 0;
639 }
640 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->DirectorySearchPattern);
641
642 TempFcb.ObjectName = TempFcb.PathName;
643 while (Status == STATUS_SUCCESS && BufferLength > 0)
644 {
645 Status = CdfsFindFile(DeviceExtension,
646 &TempFcb,
647 Fcb,
648 &Ccb->DirectorySearchPattern,
649 &Ccb->Entry,
650 &Ccb->Offset);
651 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
652
653 if (NT_SUCCESS(Status))
654 {
655 switch (FileInformationClass)
656 {
657 case FileNameInformation:
658 Status = CdfsGetNameInformation(&TempFcb,
659 DeviceExtension,
660 (PFILE_NAMES_INFORMATION)Buffer,
661 BufferLength);
662 break;
663
664 case FileDirectoryInformation:
665 Status = CdfsGetDirectoryInformation(&TempFcb,
666 DeviceExtension,
667 (PFILE_DIRECTORY_INFORMATION)Buffer,
668 BufferLength);
669 break;
670
671 case FileFullDirectoryInformation:
672 Status = CdfsGetFullDirectoryInformation(&TempFcb,
673 DeviceExtension,
674 (PFILE_FULL_DIR_INFORMATION)Buffer,
675 BufferLength);
676 break;
677
678 case FileBothDirectoryInformation:
679 Status = CdfsGetBothDirectoryInformation(&TempFcb,
680 DeviceExtension,
681 (PFILE_BOTH_DIR_INFORMATION)Buffer,
682 BufferLength);
683 break;
684
685 default:
686 Status = STATUS_INVALID_INFO_CLASS;
687 }
688
689 if (Status == STATUS_BUFFER_OVERFLOW)
690 {
691 if (Buffer0)
692 {
693 Buffer0->NextEntryOffset = 0;
694 }
695 break;
696 }
697 }
698 else
699 {
700 if (Buffer0)
701 {
702 Buffer0->NextEntryOffset = 0;
703 }
704
705 if (First)
706 {
707 Status = STATUS_NO_SUCH_FILE;
708 }
709 else
710 {
711 Status = STATUS_NO_MORE_FILES;
712 }
713 break;
714 }
715
716 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
717 Buffer0->FileIndex = FileIndex++;
718 Ccb->Entry++;
719
720 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
721 {
722 break;
723 }
724 BufferLength -= Buffer0->NextEntryOffset;
725 Buffer += Buffer0->NextEntryOffset;
726 }
727
728 if (Buffer0)
729 {
730 Buffer0->NextEntryOffset = 0;
731 }
732
733 if (FileIndex > 0)
734 {
735 Status = STATUS_SUCCESS;
736 }
737
738 return(Status);
739 }
740
741
742
743 NTSTATUS NTAPI
744 CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
745 PIRP Irp)
746 {
747 PIO_STACK_LOCATION Stack;
748 NTSTATUS Status;
749
750 DPRINT("CdfsDirectoryControl() called\n");
751 FsRtlEnterFileSystem();
752
753 Stack = IoGetCurrentIrpStackLocation(Irp);
754
755 switch (Stack->MinorFunction)
756 {
757 case IRP_MN_QUERY_DIRECTORY:
758 Status = CdfsQueryDirectory(DeviceObject,
759 Irp);
760 break;
761
762 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
763 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
764 Status = STATUS_NOT_IMPLEMENTED;
765 break;
766
767 default:
768 DPRINT1("CDFS: MinorFunction %d\n", Stack->MinorFunction);
769 Status = STATUS_INVALID_DEVICE_REQUEST;
770 break;
771 }
772
773 Irp->IoStatus.Status = Status;
774 Irp->IoStatus.Information = 0;
775
776 IoCompleteRequest(Irp, IO_NO_INCREMENT);
777 FsRtlExitFileSystem();
778
779 return(Status);
780 }
781
782 /* EOF */