update for HEAD-2003091401
[reactos.git] / drivers / fs / cdfs / dirctl.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2002 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 <ddk/ntddk.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 #include "cdfs.h"
38
39 /* DEFINES ******************************************************************/
40
41 #define ROUND_DOWN(N, S) (((N) / (S)) * (S))
42
43 /* FUNCTIONS ****************************************************************/
44
45 static NTSTATUS
46 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt,
47                  PVOID *Context,
48                  PVOID *Block,
49                  PLARGE_INTEGER StreamOffset,
50                  ULONG DirLength,
51                  PVOID *Ptr,
52                  PWSTR Name,
53                  PULONG pIndex,
54                  PULONG CurrentOffset)
55 /*
56  * FUNCTION: Retrieves the file name, be it in short or long file name format
57  */
58 {
59   PDIR_RECORD Record = *Ptr;
60   ULONG Index;
61   
62   if (*CurrentOffset >= DirLength)
63      return(STATUS_NO_MORE_ENTRIES);
64
65   if (*CurrentOffset == 0)
66   {
67      Index = 0;
68      Record = (PDIR_RECORD)*Block;
69      while (Index < *pIndex)
70      {
71        (*Ptr) += Record->RecordLength;
72        (*CurrentOffset) += Record->RecordLength;
73        Record = *Ptr;
74        if (*Ptr - *Block >= BLOCKSIZE || Record->RecordLength == 0)
75        {
76           DPRINT("Map next sector\n");
77           CcUnpinData(*Context);
78           StreamOffset->QuadPart += BLOCKSIZE;
79           *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE);
80           if (!CcMapData(DeviceExt->StreamFileObject,
81                          StreamOffset,
82                          BLOCKSIZE, TRUE,
83                          Context, Block))
84           {
85              DPRINT("CcMapData() failed\n");
86              return(STATUS_UNSUCCESSFUL);
87           }
88           *Ptr = *Block;
89           Record = (PDIR_RECORD)*Ptr;
90        }
91        if (*CurrentOffset >= DirLength)
92          return(STATUS_NO_MORE_ENTRIES);
93
94        Index++;
95      }
96   }
97
98   if (*Ptr - *Block >= BLOCKSIZE || Record->RecordLength == 0)
99   {
100      DPRINT("Map next sector\n");
101      CcUnpinData(*Context);
102      StreamOffset->QuadPart += BLOCKSIZE;
103      *CurrentOffset = ROUND_UP(*CurrentOffset, BLOCKSIZE);
104      if (!CcMapData(DeviceExt->StreamFileObject,
105                        StreamOffset,
106                        BLOCKSIZE, TRUE,
107                        Context, Block))
108      {
109        DPRINT("CcMapData() failed\n");
110        return(STATUS_UNSUCCESSFUL);
111      }
112      *Ptr = *Block;
113      Record = (PDIR_RECORD)*Ptr;
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 static NTSTATUS
153 CdfsFindFile(PDEVICE_EXTENSION DeviceExt,
154              PFCB Fcb,
155              PFCB Parent,
156              PWSTR FileToFind,
157              PULONG pDirIndex,
158              PULONG pOffset)
159 /*
160  * FUNCTION: Find a file
161  */
162 {
163   WCHAR name[256];
164   WCHAR TempStr[2];
165   WCHAR ShortNameBuffer[13];
166   UNICODE_STRING ShortName;
167   UNICODE_STRING LongName;
168   PVOID Block;
169   NTSTATUS Status;
170   ULONG len;
171   ULONG DirIndex;
172   ULONG Offset = 0;
173   ULONG Read;
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 '%S', 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   if (wcslen (FileToFind) == 0)
190     {
191       CHECKPOINT;
192       TempStr[0] = (WCHAR) '.';
193       TempStr[1] = 0;
194       FileToFind = (PWSTR)&TempStr;
195     }
196
197   if (Parent)
198     {
199       if (Parent->Entry.ExtentLocationL == DeviceExt->CdInfo.RootStart)
200         {
201           IsRoot = TRUE;
202         }
203     }
204   else
205     {
206       IsRoot = TRUE;
207     }
208
209   if (IsRoot == TRUE)
210     {
211       StreamOffset.QuadPart = (LONGLONG)DeviceExt->CdInfo.RootStart * (LONGLONG)BLOCKSIZE;
212       DirSize = DeviceExt->CdInfo.RootSize;
213
214
215       if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
216           || (FileToFind[0] == '.' && FileToFind[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) (Block + Offset % BLOCKSIZE);
260   if (Offset)
261   {  
262      Offset += Record->RecordLength;
263      Record = (PVOID)Record + Record->RecordLength;
264   }
265   while(TRUE)
266     {
267       DPRINT("RecordLength %u  ExtAttrRecordLength %u  NameLength %u\n",
268              Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
269
270       Status = CdfsGetEntryName(DeviceExt, &Context, &Block, &StreamOffset,
271                                 DirSize, (PVOID*)&Record, name, &DirIndex, &Offset);
272
273       if (Status == STATUS_NO_MORE_ENTRIES)
274         {
275           break;
276         }
277       else if (Status == STATUS_UNSUCCESSFUL)
278         {
279           /* Note: the directory cache has already been unpinned */
280           return(Status);
281         }
282
283       DPRINT("Name '%S'\n", name);
284
285       RtlInitUnicodeString(&LongName, name);
286       ShortName.Length = 0;
287       ShortName.MaximumLength = 26;
288       ShortName.Buffer = ShortNameBuffer;
289
290       if ((RtlIsNameLegalDOS8Dot3(&LongName, NULL, &HasSpaces) == FALSE) ||
291           (HasSpaces == TRUE))
292         {
293           /* Build short name */
294           RtlGenerate8dot3Name(&LongName,
295                                FALSE,
296                                &NameContext,
297                                &ShortName);
298         }
299       else
300         {
301           /* copy short name */
302           RtlUpcaseUnicodeString(&ShortName,
303                                  &LongName,
304                                  FALSE);
305         }
306
307       DPRINT("ShortName '%wZ'\n", &ShortName);
308
309       if (wstrcmpjoki(name, FileToFind) ||
310           wstrcmpjoki(ShortNameBuffer, FileToFind))
311         {
312           if (Parent && Parent->PathName)
313             {
314               len = wcslen(Parent->PathName);
315               memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
316               Fcb->ObjectName=&Fcb->PathName[len];
317               if (len != 1 || Fcb->PathName[0] != '\\')
318                 {
319                   Fcb->ObjectName[0] = '\\';
320                   Fcb->ObjectName = &Fcb->ObjectName[1];
321                 }
322             }
323           else
324             {
325               Fcb->ObjectName=Fcb->PathName;
326               Fcb->ObjectName[0]='\\';
327               Fcb->ObjectName=&Fcb->ObjectName[1];
328             }
329
330           DPRINT("PathName '%S'  ObjectName '%S'\n", Fcb->PathName, Fcb->ObjectName);
331
332           memcpy(&Fcb->Entry, Record, sizeof(DIR_RECORD));
333           wcsncpy(Fcb->ObjectName, name, MAX_PATH);
334
335           /* Copy short name */
336           Fcb->ShortNameLength = ShortName.Length;
337           memcpy(Fcb->ShortName, ShortName.Buffer, ShortName.Length);
338
339           if (pDirIndex)
340             *pDirIndex = DirIndex;
341           if (pOffset)
342             *pOffset = Offset;
343
344           DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",
345                  Fcb->PathName, Fcb->ObjectName, DirIndex);
346
347           CcUnpinData(Context);
348
349           return(STATUS_SUCCESS);
350         }
351
352
353       Offset += Record->RecordLength;
354       Record = (PVOID)Record + Record->RecordLength;
355       DirIndex++;
356
357     }
358
359   CcUnpinData(Context);
360
361   if (pDirIndex)
362     *pDirIndex = DirIndex;
363
364   if (pOffset)
365     *pOffset = Offset;
366
367   return(STATUS_UNSUCCESSFUL);
368 }
369
370
371 static NTSTATUS
372 CdfsGetNameInformation(PFCB Fcb,
373                        PDEVICE_EXTENSION DeviceExt,
374                        PFILE_NAMES_INFORMATION Info,
375                        ULONG BufferLength)
376 {
377   ULONG Length;
378
379   DPRINT("CdfsGetNameInformation() called\n");
380
381   Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
382   if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
383     return(STATUS_BUFFER_OVERFLOW);
384
385   Info->FileNameLength = Length;
386   Info->NextEntryOffset =
387     ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
388   memcpy(Info->FileName, Fcb->ObjectName, Length);
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_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
406     return(STATUS_BUFFER_OVERFLOW);
407
408   Info->FileNameLength = Length;
409   Info->NextEntryOffset =
410     ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
411   memcpy(Info->FileName, Fcb->ObjectName, Length);
412
413   /* Convert file times */
414   CdfsDateTimeToFileTime(Fcb,
415                          &Info->CreationTime);
416   CdfsDateTimeToFileTime(Fcb,
417                          &Info->LastAccessTime);
418   CdfsDateTimeToFileTime(Fcb,
419                          &Info->LastWriteTime);
420   CdfsDateTimeToFileTime(Fcb,
421                          &Info->ChangeTime);
422
423   /* Convert file flags */
424   CdfsFileFlagsToAttributes(Fcb,
425                             &Info->FileAttributes);
426
427   Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
428
429   /* Make AllocSize a rounded up multiple of the sector size */
430   Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
431
432 //  Info->FileIndex=;
433
434   return(STATUS_SUCCESS);
435 }
436
437
438 static NTSTATUS
439 CdfsGetFullDirectoryInformation(PFCB Fcb,
440                                 PDEVICE_EXTENSION DeviceExt,
441                                 PFILE_FULL_DIRECTORY_INFORMATION Info,
442                                 ULONG BufferLength)
443 {
444   ULONG Length;
445
446   DPRINT("CdfsGetFullDirectoryInformation() called\n");
447
448   Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
449   if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
450     return(STATUS_BUFFER_OVERFLOW);
451
452   Info->FileNameLength = Length;
453   Info->NextEntryOffset =
454     ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
455   memcpy(Info->FileName, Fcb->ObjectName, Length);
456
457   /* Convert file times */
458   CdfsDateTimeToFileTime(Fcb,
459                          &Info->CreationTime);
460   CdfsDateTimeToFileTime(Fcb,
461                          &Info->LastAccessTime);
462   CdfsDateTimeToFileTime(Fcb,
463                          &Info->LastWriteTime);
464   CdfsDateTimeToFileTime(Fcb,
465                          &Info->ChangeTime);
466
467   /* Convert file flags */
468   CdfsFileFlagsToAttributes(Fcb,
469                             &Info->FileAttributes);
470
471   Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
472
473   /* Make AllocSize a rounded up multiple of the sector size */
474   Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
475
476 //  Info->FileIndex=;
477   Info->EaSize = 0;
478
479   return(STATUS_SUCCESS);
480 }
481
482
483 static NTSTATUS
484 CdfsGetBothDirectoryInformation(PFCB Fcb,
485                                 PDEVICE_EXTENSION DeviceExt,
486                                 PFILE_BOTH_DIRECTORY_INFORMATION Info,
487                                 ULONG BufferLength)
488 {
489   ULONG Length;
490
491   DPRINT("CdfsGetBothDirectoryInformation() called\n");
492
493   Length = wcslen(Fcb->ObjectName) * sizeof(WCHAR);
494   if ((sizeof (FILE_BOTH_DIRECTORY_INFORMATION) + Length) > BufferLength)
495     return(STATUS_BUFFER_OVERFLOW);
496
497   Info->FileNameLength = Length;
498   Info->NextEntryOffset =
499     ROUND_UP(sizeof(FILE_BOTH_DIRECTORY_INFORMATION) + Length, 4);
500   memcpy(Info->FileName, Fcb->ObjectName, Length);
501
502   /* Convert file times */
503   CdfsDateTimeToFileTime(Fcb,
504                          &Info->CreationTime);
505   CdfsDateTimeToFileTime(Fcb,
506                          &Info->LastAccessTime);
507   CdfsDateTimeToFileTime(Fcb,
508                          &Info->LastWriteTime);
509   CdfsDateTimeToFileTime(Fcb,
510                          &Info->ChangeTime);
511
512   /* Convert file flags */
513   CdfsFileFlagsToAttributes(Fcb,
514                             &Info->FileAttributes);
515
516   Info->EndOfFile.QuadPart = Fcb->Entry.DataLengthL;
517
518   /* Make AllocSize a rounded up multiple of the sector size */
519   Info->AllocationSize.QuadPart = ROUND_UP(Fcb->Entry.DataLengthL, BLOCKSIZE);
520
521 //  Info->FileIndex=;
522   Info->EaSize = 0;
523
524   /* Copy short name */
525   Info->ShortNameLength = Fcb->ShortNameLength;
526   memcpy(Info->ShortName, Fcb->ShortName, Fcb->ShortNameLength);
527
528   return(STATUS_SUCCESS);
529 }
530
531
532 static NTSTATUS
533 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject,
534                    PIRP Irp)
535 {
536   PDEVICE_EXTENSION DeviceExtension;
537   LONG BufferLength = 0;
538   PUNICODE_STRING SearchPattern = NULL;
539   FILE_INFORMATION_CLASS FileInformationClass;
540   ULONG FileIndex = 0;
541   PUCHAR Buffer = NULL;
542   PFILE_NAMES_INFORMATION Buffer0 = NULL;
543   PFCB Fcb;
544   PCCB Ccb;
545   FCB TempFcb;
546   BOOLEAN First = FALSE;
547   PEXTENDED_IO_STACK_LOCATION Stack;
548   PFILE_OBJECT FileObject;
549   NTSTATUS Status = STATUS_SUCCESS;
550
551   DPRINT("CdfsQueryDirectory() called\n");
552
553   DeviceExtension = DeviceObject->DeviceExtension;
554   Stack = (PEXTENDED_IO_STACK_LOCATION) IoGetCurrentIrpStackLocation(Irp);
555   FileObject = Stack->FileObject;
556
557   Ccb = (PCCB)FileObject->FsContext2;
558   Fcb = (PFCB)FileObject->FsContext;
559
560   /* Obtain the callers parameters */
561   BufferLength = Stack->Parameters.QueryDirectory.Length;
562   SearchPattern = Stack->Parameters.QueryDirectory.FileName;
563   FileInformationClass =
564     Stack->Parameters.QueryDirectory.FileInformationClass;
565   FileIndex = Stack->Parameters.QueryDirectory.FileIndex;
566
567
568   if (SearchPattern != NULL)
569     {
570       if (!Ccb->DirectorySearchPattern)
571         {
572           First = TRUE;
573           Ccb->DirectorySearchPattern =
574             ExAllocatePool(NonPagedPool, SearchPattern->Length + sizeof(WCHAR));
575           if (!Ccb->DirectorySearchPattern)
576             {
577               return(STATUS_INSUFFICIENT_RESOURCES);
578             }
579
580           memcpy(Ccb->DirectorySearchPattern,
581                  SearchPattern->Buffer,
582                  SearchPattern->Length);
583           Ccb->DirectorySearchPattern[SearchPattern->Length / sizeof(WCHAR)] = 0;
584         }
585     }
586   else if (!Ccb->DirectorySearchPattern)
587     {
588       First = TRUE;
589       Ccb->DirectorySearchPattern = ExAllocatePool(NonPagedPool, 2 * sizeof(WCHAR));
590       if (!Ccb->DirectorySearchPattern)
591         {
592           return(STATUS_INSUFFICIENT_RESOURCES);
593         }
594       Ccb->DirectorySearchPattern[0] = L'*';
595       Ccb->DirectorySearchPattern[1] = 0;
596     }
597   DPRINT("Search pattern '%S'\n", Ccb->DirectorySearchPattern);
598
599   /* Determine directory index */
600   if (Stack->Flags & SL_INDEX_SPECIFIED)
601     {
602       Ccb->Entry = Ccb->CurrentByteOffset.u.LowPart;
603       Ccb->Offset = 0;
604     }
605   else if (First || (Stack->Flags & SL_RESTART_SCAN))
606     {
607       Ccb->Entry = 0;
608       Ccb->Offset = 0;
609     }
610
611   /* Determine Buffer for result */
612   if (Irp->MdlAddress)
613     {
614       Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
615     }
616   else
617     {
618       Buffer = Irp->UserBuffer;
619     }
620   DPRINT("Buffer=%x tofind=%S\n", Buffer, Ccb->DirectorySearchPattern);
621
622   TempFcb.ObjectName = TempFcb.PathName;
623   while (Status == STATUS_SUCCESS && BufferLength > 0)
624     {
625       Status = CdfsFindFile(DeviceExtension,
626                             &TempFcb,
627                             Fcb,
628                             Ccb->DirectorySearchPattern,
629                             &Ccb->Entry,
630                             &Ccb->Offset);
631       DPRINT("Found %S, Status=%x, entry %x\n", TempFcb.ObjectName, Status, Ccb->Entry);
632
633       if (NT_SUCCESS(Status))
634         {
635           switch (FileInformationClass)
636             {
637               case FileNameInformation:
638                 Status = CdfsGetNameInformation(&TempFcb,
639                                                 DeviceExtension,
640                                                 (PFILE_NAMES_INFORMATION)Buffer,
641                                                 BufferLength);
642                 break;
643
644               case FileDirectoryInformation:
645                 Status = CdfsGetDirectoryInformation(&TempFcb,
646                                                      DeviceExtension,
647                                                      (PFILE_DIRECTORY_INFORMATION)Buffer,
648                                                      BufferLength);
649                 break;
650
651               case FileFullDirectoryInformation:
652                 Status = CdfsGetFullDirectoryInformation(&TempFcb,
653                                                          DeviceExtension,
654                                                          (PFILE_FULL_DIRECTORY_INFORMATION)Buffer,
655                                                          BufferLength);
656                 break;
657
658               case FileBothDirectoryInformation:
659                 Status = CdfsGetBothDirectoryInformation(&TempFcb,
660                                                          DeviceExtension,
661                                                          (PFILE_BOTH_DIRECTORY_INFORMATION)Buffer,
662                                                          BufferLength);
663                 break;
664
665               default:
666                 Status = STATUS_INVALID_INFO_CLASS;
667             }
668
669           if (Status == STATUS_BUFFER_OVERFLOW)
670             {
671               if (Buffer0)
672                 {
673                   Buffer0->NextEntryOffset = 0;
674                 }
675               break;
676             }
677         }
678       else
679         {
680           if (Buffer0)
681             {
682               Buffer0->NextEntryOffset = 0;
683             }
684
685           if (First)
686             {
687               Status = STATUS_NO_SUCH_FILE;
688             }
689           else
690             {
691               Status = STATUS_NO_MORE_FILES;
692             }
693           break;
694         }
695
696       Buffer0 = (PFILE_NAMES_INFORMATION)Buffer;
697       Buffer0->FileIndex = FileIndex++;
698       Ccb->Entry++;
699
700       if (Stack->Flags & SL_RETURN_SINGLE_ENTRY)
701         {
702           break;
703         }
704       BufferLength -= Buffer0->NextEntryOffset;
705       Buffer += Buffer0->NextEntryOffset;
706     }
707
708   if (Buffer0)
709     {
710       Buffer0->NextEntryOffset = 0;
711     }
712
713   if (FileIndex > 0)
714     {
715       Status = STATUS_SUCCESS;
716     }
717
718   return(Status);
719 }
720
721
722
723 NTSTATUS STDCALL
724 CdfsDirectoryControl(PDEVICE_OBJECT DeviceObject,
725                      PIRP Irp)
726 {
727   PIO_STACK_LOCATION Stack;
728   NTSTATUS Status;
729
730   DPRINT("CdfsDirectoryControl() called\n");
731
732   Stack = IoGetCurrentIrpStackLocation(Irp);
733
734   switch (Stack->MinorFunction)
735     {
736       case IRP_MN_QUERY_DIRECTORY:
737         Status = CdfsQueryDirectory(DeviceObject,
738                                     Irp);
739         break;
740
741       case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
742         DPRINT1("IRP_MN_NOTIFY_CHANGE_DIRECTORY\n");
743         Status = STATUS_NOT_IMPLEMENTED;
744         break;
745
746       default:
747         DPRINT1("CDFS: MinorFunction %d\n", Stack->MinorFunction);
748         Status = STATUS_INVALID_DEVICE_REQUEST;
749         break;
750     }
751
752   Irp->IoStatus.Status = Status;
753   Irp->IoStatus.Information = 0;
754
755   IoCompleteRequest(Irp, IO_NO_INCREMENT);
756
757   return(Status);
758 }
759
760 /* EOF */