Visual C++ backend for rbuild (for now just a hacked mingw backend) and related compi...
[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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 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;
179 BOOLEAN HasSpaces;
180 GENERATE_NAME_CONTEXT NameContext;
181
182 DPRINT("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n",
183 Parent, FileToFind, pDirIndex ? *pDirIndex : 0);
184 DPRINT("FindFile: old Pathname %x, old Objectname %x)\n",
185 Fcb->PathName, Fcb->ObjectName);
186
187 IsRoot = FALSE;
188 DirIndex = 0;
189
190 if (FileToFind == NULL || FileToFind->Length == 0)
191 {
192 RtlInitUnicodeString(&TempString, L".");
193 FileToFind = &TempString;
194 }
195
196 if (Parent)
197 {
198 if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
199 {
200 IsRoot = TRUE;
201 }
202 }
203 else
204 {
205 IsRoot = TRUE;
206 }
207
208 if (IsRoot == TRUE)
209 {
210 StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
211 DirSize = DeviceExt->CdInfo.RootSize;
212
213
214 if (FileToFind->Buffer[0] == 0 ||
215 (FileToFind->Buffer[0] == '\\' && FileToFind->Buffer[1] == 0) ||
216 (FileToFind->Buffer[0] == '.' && FileToFind->Buffer[1] == 0))
217 {
218 /* it's root : complete essentials fields then return ok */
219 RtlZeroMemory(Fcb, sizeof(FCB));
220
221 Fcb->PathName[0] = '\\';
222 Fcb->ObjectName = &Fcb->PathName[1];
223 Fcb->Entry.ExtentLocationL = DeviceExt->CdInfo.RootStart;
224 Fcb->Entry.DataLengthL = DeviceExt->CdInfo.RootSize;
225 Fcb->Entry.FileFlags = 0x02; //FILE_ATTRIBUTE_DIRECTORY;
226
227 if (pDirIndex)
228 *pDirIndex = 0;
229 if (pOffset)
230 *pOffset = 0;
231 DPRINT("CdfsFindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
232 return STATUS_SUCCESS;
233 }
234 }
235 else
236 {
237 StreamOffset.QuadPart = (LONGLONG)Parent->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
238 DirSize = Parent->Entry.DataLengthL;
239 }
240
241 DPRINT("StreamOffset %I64u DirSize %lu\n", StreamOffset.QuadPart, DirSize);
242
243 if (pDirIndex && (*pDirIndex))
244 DirIndex = *pDirIndex;
245
246 if (pOffset && (*pOffset))
247 {
248 Offset = *pOffset;
249 StreamOffset.QuadPart += ROUND_DOWN(Offset, BLOCKSIZE);
250 }
251
252 if (!CcMapData(DeviceExt->StreamFileObject, &StreamOffset,
253 BLOCKSIZE, TRUE, &Context, &Block))
254 {
255 DPRINT("CcMapData() failed\n");
256 return STATUS_UNSUCCESSFUL;
257 }
258
259 Record = (PDIR_RECORD) ((ULONG_PTR)Block + Offset % BLOCKSIZE);
260 if (Offset)
261 {
262 Offset += Record->RecordLength;
263 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
264 }
265
266 while(TRUE)
267 {
268 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
269 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
270
271 Status = CdfsGetEntryName(DeviceExt, &Context, &Block, &StreamOffset,
272 DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);
273
274 if (Status == STATUS_NO_MORE_ENTRIES)
275 {
276 break;
277 }
278 else if (Status == STATUS_UNSUCCESSFUL)
279 {
280 /* Note: the directory cache has already been unpinned */
281 return Status;
282 }
283
284 DPRINT("Name '%S'\n", name);
285
286 RtlInitUnicodeString(&LongName, name);
287 ShortName.Length = 0;
288 ShortName.MaximumLength = 26;
289 ShortName.Buffer = ShortNameBuffer;
290
291 if ((RtlIsNameLegalDOS8Dot3(&LongName, NULL, &HasSpaces) == FALSE) ||
292 (HasSpaces == TRUE))
293 {
294 /* Build short name */
295 RtlGenerate8dot3Name(&LongName,
296 FALSE,
297 &NameContext,
298 &ShortName);
299 }
300 else
301 {
302 /* copy short name */
303 RtlUpcaseUnicodeString(&ShortName,
304 &LongName,
305 FALSE);
306 }
307
308 DPRINT("ShortName '%wZ'\n", &ShortName);
309
310 if (FsRtlIsNameInExpression(FileToFind, &LongName, TRUE, NULL) ||
311 FsRtlIsNameInExpression(FileToFind, &ShortName, TRUE, NULL))
312 {
313 if (Parent && Parent->PathName)
314 {
315 len = wcslen(Parent->PathName);
316 memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
317 Fcb->ObjectName=&Fcb->PathName[len];
318 if (len != 1 || Fcb->PathName[0] != '\\')
319 {
320 Fcb->ObjectName[0] = '\\';
321 Fcb->ObjectName = &Fcb->ObjectName[1];
322 }
323 }
324 else
325 {
326 Fcb->ObjectName=Fcb->PathName;
327 Fcb->ObjectName[0]='\\';
328 Fcb->ObjectName=&Fcb->ObjectName[1];
329 }
330
331 DPRINT("PathName '%S' ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName);
332
333 memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD));
334 wcsncpy(Fcb->ObjectName, name, MAX_PATH);
335
336 /* Copy short name */
337 Fcb->ShortNameU.Length = ShortName.Length;
338 Fcb->ShortNameU.MaximumLength = ShortName.Length;
339 Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
340 memcpy(Fcb->ShortNameBuffer, ShortName.Buffer, ShortName.Length);
341
342 if (pDirIndex)
343 *pDirIndex = DirIndex;
344 if (pOffset)
345 *pOffset = Offset;
346
347 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",
348 Fcb->PathName, Fcb->ObjectName, DirIndex);
349
350 CcUnpinData(Context);
351
352 return STATUS_SUCCESS;
353 }
354
355 Offset += Record->RecordLength;
356 Record = (PDIR_RECORD)((ULONG_PTR)Record + Record->RecordLength);
357 DirIndex++;
358 }
359
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 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
383 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
384 return(STATUS_BUFFER_OVERFLOW);
385
386 Info->FileNameLength = Length;
387 Info->NextEntryOffset =
388 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, 4);
389 memcpy(Info->FileName, Fcb->ObjectName, Length);
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 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
406 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
407 return(STATUS_BUFFER_OVERFLOW);
408
409 Info->FileNameLength = Length;
410 Info->NextEntryOffset =
411 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, 4);
412 memcpy(Info->FileName, Fcb->ObjectName, Length);
413
414 /* Convert file times */
415 CdfsDateTimeToSystemTime(Fcb,
416 &Info->CreationTime);
417 CdfsDateTimeToSystemTime(Fcb,
418 &Info->LastAccessTime);
419 CdfsDateTimeToSystemTime(Fcb,
420 &Info->LastWriteTime);
421 CdfsDateTimeToSystemTime(Fcb,
422 &Info->ChangeTime);
423
424 /* Convert file flags */
425 CdfsFileFlagsToAttributes(Fcb,
426 &Info->FileAttributes);
427 if (CdfsFCBIsDirectory(Fcb))
428 {
429 Info->EndOfFile.QuadPart = 0LL;
430 Info->AllocationSize.QuadPart = 0LL;
431 }
432 else
433 {
434 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
435
436 /* Make AllocSize a rounded up multiple of the sector size */
437 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
438 }
439
440 // Info->FileIndex=;
441
442 return(STATUS_SUCCESS);
443 }
444
445
446 static NTSTATUS
447 CdfsGetFullDirectoryInformation(PFCB Fcb,
448 PDEVICE_EXTENSION DeviceExt,
449 PFILE_FULL_DIR_INFORMATION Info,
450 ULONG BufferLength)
451 {
452 ULONG Length;
453
454 DPRINT("CdfsGetFullDirectoryInformation() called\n");
455
456 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
457 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
458 return(STATUS_BUFFER_OVERFLOW);
459
460 Info->FileNameLength = Length;
461 Info->NextEntryOffset =
462 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, 4);
463 memcpy(Info->FileName, Fcb->ObjectName, Length);
464
465 /* Convert file times */
466 CdfsDateTimeToSystemTime(Fcb,
467 &Info->CreationTime);
468 CdfsDateTimeToSystemTime(Fcb,
469 &Info->LastAccessTime);
470 CdfsDateTimeToSystemTime(Fcb,
471 &Info->LastWriteTime);
472 CdfsDateTimeToSystemTime(Fcb,
473 &Info->ChangeTime);
474
475 /* Convert file flags */
476 CdfsFileFlagsToAttributes(Fcb,
477 &Info->FileAttributes);
478
479 if (CdfsFCBIsDirectory(Fcb))
480 {
481 Info->EndOfFile.QuadPart = 0LL;
482 Info->AllocationSize.QuadPart = 0LL;
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 Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
510 if ((sizeof (FILE_BOTH_DIR_INFORMATION) + Length) > BufferLength)
511 return(STATUS_BUFFER_OVERFLOW);
512
513 Info->FileNameLength = Length;
514 Info->NextEntryOffset =
515 ROUND_UP(sizeof(FILE_BOTH_DIR_INFORMATION) + Length, 4);
516 memcpy(Info->FileName, Fcb->ObjectName, Length);
517
518 /* Convert file times */
519 CdfsDateTimeToSystemTime(Fcb,
520 &Info->CreationTime);
521 CdfsDateTimeToSystemTime(Fcb,
522 &Info->LastAccessTime);
523 CdfsDateTimeToSystemTime(Fcb,
524 &Info->LastWriteTime);
525 CdfsDateTimeToSystemTime(Fcb,
526 &Info->ChangeTime);
527
528 /* Convert file flags */
529 CdfsFileFlagsToAttributes(Fcb,
530 &Info->FileAttributes);
531
532 if (CdfsFCBIsDirectory(Fcb))
533 {
534 Info->EndOfFile.QuadPart = 0LL;
535 Info->AllocationSize.QuadPart = 0LL;
536 }
537 else
538 {
539 Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
540
541 /* Make AllocSize a rounded up multiple of the sector size */
542 Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
543 }
544
545 // Info->FileIndex=;
546 Info->EaSize = 0;
547
548 /* Copy short name */
549 Info->ShortNameLength = Fcb->ShortNameU.Length;
550 memcpy(Info->ShortName, Fcb->ShortNameU.Buffer, Fcb->ShortNameU.Length);
551
552 return(STATUS_SUCCESS);
553 }
554
555
556 static NTSTATUS
557 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject,
558 PIRP Irp)
559 {
560 PDEVICE_EXTENSION DeviceExtension;
561 LONG BufferLength = 0;
562 PUNICODE_STRING SearchPattern = NULL;
563 FILE_INFORMATION_CLASS FileInformationClass;
564 ULONG FileIndex = 0;
565 PUCHAR Buffer = NULL;
566 PFILE_NAMES_INFORMATION Buffer0 = NULL;
567 PFCB Fcb;
568 PCCB Ccb;
569 FCB TempFcb;
570 BOOLEAN First = FALSE;
571 PIO_STACK_LOCATION Stack;
572 PFILE_OBJECT FileObject;
573 NTSTATUS Status = STATUS_SUCCESS;
574
575 DPRINT("CdfsQueryDirectory() called\n");
576
577 DeviceExtension = DeviceObject->DeviceExtension;
578 Stack = IoGetCurrentIrpStackLocation(Irp);
579 FileObject = Stack->FileObject;
580
581 Ccb = (PCCB)FileObject->FsContext2;
582 Fcb = (PFCB)FileObject->FsContext;
583
584 /* Obtain the callers parameters */
585 BufferLength = Stack->Parameters.QueryDirectory.Length;
586 SearchPattern = Stack->Parameters.QueryDirectory.FileName;
587 FileInformationClass =
588 Stack->Parameters.QueryDirectory.FileInformationClass;
589 FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
590
591
592 if (SearchPattern != NULL)
593 {
594 if (Ccb->DirectorySearchPattern.Buffer == NULL)
595 {
596 First = TRUE;
597 Ccb->DirectorySearchPattern.Buffer =
598 ExAllocatePool(NonPagedPool, SearchPattern->Length + sizeof(WCHAR));
599 if (Ccb->DirectorySearchPattern.Buffer == NULL)
600 {
601 return STATUS_INSUFFICIENT_RESOURCES;
602 }
603
604 Ccb->DirectorySearchPattern.Length = SearchPattern->Length;
605 Ccb->DirectorySearchPattern.MaximumLength = SearchPattern->Length + sizeof(WCHAR);
606
607 memcpy(Ccb->DirectorySearchPattern.Buffer,
608 SearchPattern->Buffer,
609 SearchPattern->Length);
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 = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
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 = Ccb->CurrentByteOffset.u.LowPart;
633 Ccb->Offset = 0;
634 }
635 else if (First || (Stack->Flags & SL_RESTART_SCAN))
636 {
637 Ccb->Entry = 0;
638 Ccb->Offset = 0;
639 }
640
641 /* Determine Buffer for result */
642 if (Irp->MdlAddress)
643 {
644 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
645 }
646 else
647 {
648 Buffer = Irp->UserBuffer;
649 }
650 DPRINT("Buffer = %p tofind = %wZ\n", Buffer, &Ccb->DirectorySearchPattern);
651
652 TempFcb.ObjectName = TempFcb.PathName;
653 while (Status == STATUS_SUCCESS && BufferLength > 0)
654 {
655 Status = CdfsFindFile(DeviceExtension,
656 &TempFcb,
657 Fcb,
658 &Ccb->DirectorySearchPattern,
659 &Ccb->Entry,
660 &Ccb->Offset);
661 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
662
663 if (NT_SUCCESS(Status))
664 {
665 switch (FileInformationClass)
666 {
667 case FileNameInformation:
668 Status = CdfsGetNameInformation(&TempFcb,
669 DeviceExtension,
670 (PFILE_NAMES_INFORMATION)Buffer,
671 BufferLength);
672 break;
673
674 case FileDirectoryInformation:
675 Status = CdfsGetDirectoryInformation(&TempFcb,
676 DeviceExtension,
677 (PFILE_DIRECTORY_INFORMATION)Buffer,
678 BufferLength);
679 break;
680
681 case FileFullDirectoryInformation:
682 Status = CdfsGetFullDirectoryInformation(&TempFcb,
683 DeviceExtension,
684 (PFILE_FULL_DIR_INFORMATION)Buffer,
685 BufferLength);
686 break;
687
688 case FileBothDirectoryInformation:
689 Status = CdfsGetBothDirectoryInformation(&TempFcb,
690 DeviceExtension,
691 (PFILE_BOTH_DIR_INFORMATION)Buffer,
692 BufferLength);
693 break;
694
695 default:
696 Status = STATUS_INVALID_INFO_CLASS;
697 }
698
699 if (Status == STATUS_BUFFER_OVERFLOW)
700 {
701 if (Buffer0)
702 {
703 Buffer0->NextEntryOffset = 0;
704 }
705 break;
706 }
707 }
708 else
709 {
710 if (Buffer0)
711 {
712 Buffer0->NextEntryOffset = 0;
713 }
714
715 if (First)
716 {
717 Status = STATUS_NO_SUCH_FILE;
718 }
719 else
720 {
721 Status = STATUS_NO_MORE_FILES;
722 }
723 break;
724 }
725
726 Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
727 Buffer0->FileIndex = FileIndex++;
728 Ccb->Entry++;
729
730 if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
731 {
732 break;
733 }
734 BufferLength -= Buffer0->NextEntryOffset;
735 Buffer += Buffer0->NextEntryOffset;
736 }
737
738 if (Buffer0)
739 {
740 Buffer0->NextEntryOffset = 0;
741 }
742
743 if (FileIndex > 0)
744 {
745 Status = STATUS_SUCCESS;
746 }
747
748 return(Status);
749 }
750
751
752
753 NTSTATUS STDCALL
754 CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
755 PIRP Irp)
756 {
757 PIO_STACK_LOCATION Stack;
758 NTSTATUS Status;
759
760 DPRINT("CdfsDirectoryControl() called\n");
761
762 Stack = IoGetCurrentIrpStackLocation(Irp);
763
764 switch (Stack->MinorFunction)
765 {
766 case IRP_MN_QUERY_DIRECTORY:
767 Status = CdfsQueryDirectory(DeviceObject,
768 Irp);
769 break;
770
771 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
772 DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
773 Status = STATUS_NOT_IMPLEMENTED;
774 break;
775
776 default:
777 DPRINT1("CDFS: MinorFunction %d\n", Stack->MinorFunction);
778 Status = STATUS_INVALID_DEVICE_REQUEST;
779 break;
780 }
781
782 Irp->IoStatus.Status = Status;
783 Irp->IoStatus.Information = 0;
784
785 IoCompleteRequest(Irp, IO_NO_INCREMENT);
786
787 return(Status);
788 }
789
790 /* EOF */