3 * Copyright (C) 2002, 2004 ReactOS Team
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.
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.
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.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/cdfs/dirctl.c
23 * PURPOSE: CDROM (ISO 9660) filesystem driver
24 * PROGRAMMER: Art Yerkes
29 /* INCLUDES *****************************************************************/
36 /* FUNCTIONS ****************************************************************/
38 #define ROUND_DOWN(N, S) (((N) / (S)) * (S))
39 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
41 /* FUNCTIONS ****************************************************************/
44 * FUNCTION: Retrieves the file name, be it in short or long file name format
47 CdfsGetEntryName(PDEVICE_EXTENSION DeviceExt
,
50 PLARGE_INTEGER StreamOffset
,
57 PDIR_RECORD Record
= *Ptr
;
60 if (*CurrentOffset
>= DirLength
)
61 return(STATUS_NO_MORE_ENTRIES
);
63 if (*CurrentOffset
== 0)
66 Record
= (PDIR_RECORD
)*Block
;
67 while (Index
< *pIndex
)
69 (*Ptr
) = (PVOID
)((ULONG_PTR
)(*Ptr
) + Record
->RecordLength
);
70 (*CurrentOffset
) += Record
->RecordLength
;
72 if ((ULONG_PTR
)(*Ptr
) - (ULONG_PTR
)(*Block
) >= BLOCKSIZE
|| Record
->RecordLength
== 0)
74 DPRINT("Map next sector\n");
75 CcUnpinData(*Context
);
76 StreamOffset
->QuadPart
+= BLOCKSIZE
;
77 *CurrentOffset
= ROUND_UP(*CurrentOffset
, BLOCKSIZE
);
80 CcMapData(DeviceExt
->StreamFileObject
, StreamOffset
, BLOCKSIZE
, TRUE
, Context
, Block
);
82 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
84 DPRINT("CcMapData() failed\n");
85 _SEH2_YIELD(return _SEH2_GetExceptionCode());
89 Record
= (PDIR_RECORD
)*Ptr
;
91 if (*CurrentOffset
>= DirLength
)
92 return(STATUS_NO_MORE_ENTRIES
);
98 if ((ULONG_PTR
)(*Ptr
) - (ULONG_PTR
)(*Block
) >= BLOCKSIZE
|| Record
->RecordLength
== 0)
100 DPRINT("Map next sector\n");
101 CcUnpinData(*Context
);
102 StreamOffset
->QuadPart
+= BLOCKSIZE
;
103 *CurrentOffset
= ROUND_UP(*CurrentOffset
, BLOCKSIZE
);
106 CcMapData(DeviceExt
->StreamFileObject
, StreamOffset
, BLOCKSIZE
, TRUE
, Context
, Block
);
108 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
110 DPRINT("CcMapData() failed\n");
111 _SEH2_YIELD(return _SEH2_GetExceptionCode());
115 Record
= (PDIR_RECORD
)*Ptr
;
118 if (*CurrentOffset
>= DirLength
)
119 return STATUS_NO_MORE_ENTRIES
;
121 DPRINT("Index %lu RecordLength %lu Offset %lu\n",
122 *pIndex
, Record
->RecordLength
, *CurrentOffset
);
124 if (!CdfsIsRecordValid(DeviceExt
, Record
))
126 CcUnpinData(*Context
);
127 return STATUS_DISK_CORRUPT_ERROR
;
130 CdfsGetDirEntryName(DeviceExt
, Record
, Name
);
134 return(STATUS_SUCCESS
);
139 * FUNCTION: Find a file
142 CdfsFindFile(PDEVICE_EXTENSION DeviceExt
,
145 PUNICODE_STRING FileToFind
,
150 WCHAR ShortNameBuffer
[13];
151 UNICODE_STRING TempString
;
152 UNICODE_STRING ShortName
;
153 UNICODE_STRING LongName
;
154 UNICODE_STRING FileToFindUpcase
;
161 PVOID Context
= NULL
;
164 LARGE_INTEGER StreamOffset
, OffsetOfEntry
;
166 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
167 Parent
, FileToFind
, pDirIndex
? *pDirIndex
: 0);
168 DPRINT("FindFile: old Pathname %p, old Objectname %p)\n",
169 Fcb
->PathName
, Fcb
->ObjectName
);
174 if (FileToFind
== NULL
|| FileToFind
->Length
== 0)
176 RtlInitUnicodeString(&TempString
, L
".");
177 FileToFind
= &TempString
;
182 if (Parent
->Entry
.ExtentLocationL
== DeviceExt
->CdInfo
.RootStart
)
194 StreamOffset
.QuadPart
= (LONGLONG
)DeviceExt
->CdInfo
.RootStart
* (LONGLONG
)BLOCKSIZE
;
195 DirSize
= DeviceExt
->CdInfo
.RootSize
;
198 if (FileToFind
->Buffer
[0] == 0 ||
199 (FileToFind
->Buffer
[0] == '\\' && FileToFind
->Buffer
[1] == 0) ||
200 (FileToFind
->Buffer
[0] == '.' && FileToFind
->Buffer
[1] == 0))
202 /* it's root : complete essentials fields then return ok */
203 RtlZeroMemory(Fcb
, sizeof(FCB
));
204 RtlInitEmptyUnicodeString(&Fcb
->PathName
, Fcb
->PathNameBuffer
, sizeof(Fcb
->PathNameBuffer
));
206 Fcb
->PathNameBuffer
[0] = '\\';
207 Fcb
->PathName
.Length
= sizeof(WCHAR
);
208 Fcb
->ObjectName
= &Fcb
->PathNameBuffer
[1];
209 Fcb
->Entry
.ExtentLocationL
= DeviceExt
->CdInfo
.RootStart
;
210 Fcb
->Entry
.DataLengthL
= DeviceExt
->CdInfo
.RootSize
;
211 Fcb
->Entry
.FileFlags
= 0x02; //FILE_ATTRIBUTE_DIRECTORY;
217 DPRINT("CdfsFindFile: new Pathname %wZ, new Objectname %S)\n",&Fcb
->PathName
, Fcb
->ObjectName
);
218 return STATUS_SUCCESS
;
223 StreamOffset
.QuadPart
= (LONGLONG
)Parent
->Entry
.ExtentLocationL
* (LONGLONG
)BLOCKSIZE
;
224 DirSize
= Parent
->Entry
.DataLengthL
;
227 DPRINT("StreamOffset %I64d DirSize %u\n", StreamOffset
.QuadPart
, DirSize
);
229 if (pDirIndex
&& (*pDirIndex
))
230 DirIndex
= *pDirIndex
;
232 if (pOffset
&& (*pOffset
))
235 StreamOffset
.QuadPart
+= ROUND_DOWN(Offset
, BLOCKSIZE
);
240 CcMapData(DeviceExt
->StreamFileObject
, &StreamOffset
, BLOCKSIZE
, TRUE
, &Context
, &Block
);
242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
244 DPRINT("CcMapData() failed\n");
245 _SEH2_YIELD(return _SEH2_GetExceptionCode());
249 Record
= (PDIR_RECORD
) ((ULONG_PTR
)Block
+ Offset
% BLOCKSIZE
);
252 Offset
+= Record
->RecordLength
;
253 Record
= (PDIR_RECORD
)((ULONG_PTR
)Record
+ Record
->RecordLength
);
256 /* Upper case the expression for FsRtlIsNameInExpression */
257 Status
= RtlUpcaseUnicodeString(&FileToFindUpcase
, FileToFind
, TRUE
);
258 if (!NT_SUCCESS(Status
))
265 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
266 Record
->RecordLength
, Record
->ExtAttrRecordLength
, Record
->FileIdLength
);
268 Status
= CdfsGetEntryName
269 (DeviceExt
, &Context
, &Block
, &StreamOffset
,
270 DirSize
, (PVOID
*)&Record
, name
, &DirIndex
, &Offset
);
272 if (Status
== STATUS_NO_MORE_ENTRIES
)
276 else if (Status
== STATUS_UNSUCCESSFUL
|| Status
== STATUS_DISK_CORRUPT_ERROR
)
278 /* Note: the directory cache has already been unpinned */
279 RtlFreeUnicodeString(&FileToFindUpcase
);
283 DPRINT("Name '%S'\n", name
);
285 RtlInitUnicodeString(&LongName
, name
);
287 ShortName
.Length
= 0;
288 ShortName
.MaximumLength
= 26;
289 ShortName
.Buffer
= ShortNameBuffer
;
291 OffsetOfEntry
.QuadPart
= StreamOffset
.QuadPart
+ Offset
;
292 CdfsShortNameCacheGet(Parent
, &OffsetOfEntry
, &LongName
, &ShortName
);
294 DPRINT("ShortName '%wZ'\n", &ShortName
);
296 if (FsRtlIsNameInExpression(&FileToFindUpcase
, &LongName
, TRUE
, NULL
) ||
297 FsRtlIsNameInExpression(&FileToFindUpcase
, &ShortName
, TRUE
, NULL
))
299 if (Parent
->PathName
.Buffer
[0])
301 RtlCopyUnicodeString(&Fcb
->PathName
, &Parent
->PathName
);
302 len
= Parent
->PathName
.Length
/ sizeof(WCHAR
);
303 Fcb
->ObjectName
=&Fcb
->PathName
.Buffer
[len
];
304 if (len
!= 1 || Fcb
->PathName
.Buffer
[0] != '\\')
306 Fcb
->ObjectName
[0] = '\\';
307 Fcb
->ObjectName
= &Fcb
->ObjectName
[1];
312 Fcb
->ObjectName
=Fcb
->PathName
.Buffer
;
313 Fcb
->ObjectName
[0]='\\';
314 Fcb
->ObjectName
=&Fcb
->ObjectName
[1];
317 DPRINT("PathName '%wZ' ObjectName '%S'\n", &Fcb
->PathName
, Fcb
->ObjectName
);
319 memcpy(&Fcb
->Entry
, Record
, sizeof(DIR_RECORD
));
320 wcsncpy(Fcb
->ObjectName
, name
, min(wcslen(name
) + 1,
321 MAX_PATH
- (Fcb
->PathName
.Length
/ sizeof(WCHAR
)) + wcslen(Fcb
->ObjectName
)));
323 /* Copy short name */
324 Fcb
->ShortNameU
.Length
= ShortName
.Length
;
325 Fcb
->ShortNameU
.MaximumLength
= ShortName
.Length
;
326 Fcb
->ShortNameU
.Buffer
= Fcb
->ShortNameBuffer
;
327 memcpy(Fcb
->ShortNameBuffer
, ShortName
.Buffer
, ShortName
.Length
);
330 *pDirIndex
= DirIndex
;
334 DPRINT("FindFile: new Pathname %wZ, new Objectname %S, DirIndex %u\n",
335 &Fcb
->PathName
, Fcb
->ObjectName
, DirIndex
);
337 RtlFreeUnicodeString(&FileToFindUpcase
);
338 CcUnpinData(Context
);
340 return STATUS_SUCCESS
;
343 Offset
+= Record
->RecordLength
;
344 Record
= (PDIR_RECORD
)((ULONG_PTR
)Record
+ Record
->RecordLength
);
348 RtlFreeUnicodeString(&FileToFindUpcase
);
349 CcUnpinData(Context
);
352 *pDirIndex
= DirIndex
;
357 return STATUS_UNSUCCESSFUL
;
362 CdfsGetNameInformation(PFCB Fcb
,
363 PDEVICE_EXTENSION DeviceExt
,
364 PFILE_NAMES_INFORMATION Info
,
369 DPRINT("CdfsGetNameInformation() called\n");
371 UNREFERENCED_PARAMETER(DeviceExt
);
373 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
374 if ((sizeof(FILE_NAMES_INFORMATION
) + Length
) > BufferLength
)
375 return(STATUS_BUFFER_OVERFLOW
);
377 Info
->FileNameLength
= Length
;
378 Info
->NextEntryOffset
=
379 ROUND_UP(sizeof(FILE_NAMES_INFORMATION
) + Length
, sizeof(ULONG
));
380 RtlCopyMemory(Info
->FileName
, Fcb
->ObjectName
, Length
);
384 return(STATUS_SUCCESS
);
389 CdfsGetDirectoryInformation(PFCB Fcb
,
390 PDEVICE_EXTENSION DeviceExt
,
391 PFILE_DIRECTORY_INFORMATION Info
,
396 DPRINT("CdfsGetDirectoryInformation() called\n");
398 UNREFERENCED_PARAMETER(DeviceExt
);
400 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
401 if ((sizeof (FILE_DIRECTORY_INFORMATION
) + Length
) > BufferLength
)
402 return(STATUS_BUFFER_OVERFLOW
);
404 Info
->FileNameLength
= Length
;
405 Info
->NextEntryOffset
=
406 ROUND_UP(sizeof(FILE_DIRECTORY_INFORMATION
) + Length
, sizeof(ULONG
));
407 RtlCopyMemory(Info
->FileName
, Fcb
->ObjectName
, Length
);
409 /* Convert file times */
410 CdfsDateTimeToSystemTime(Fcb
,
411 &Info
->CreationTime
);
412 Info
->LastWriteTime
= Info
->CreationTime
;
413 Info
->ChangeTime
= Info
->CreationTime
;
415 /* Convert file flags */
416 CdfsFileFlagsToAttributes(Fcb
,
417 &Info
->FileAttributes
);
418 if (CdfsFCBIsDirectory(Fcb
))
420 Info
->EndOfFile
.QuadPart
= 0;
421 Info
->AllocationSize
.QuadPart
= 0;
425 Info
->EndOfFile
.QuadPart
= Fcb
->Entry
.DataLengthL
;
427 /* Make AllocSize a rounded up multiple of the sector size */
428 Info
->AllocationSize
.QuadPart
= ROUND_UP(Fcb
->Entry
.DataLengthL
, BLOCKSIZE
);
433 return(STATUS_SUCCESS
);
438 CdfsGetFullDirectoryInformation(PFCB Fcb
,
439 PDEVICE_EXTENSION DeviceExt
,
440 PFILE_FULL_DIR_INFORMATION Info
,
445 DPRINT("CdfsGetFullDirectoryInformation() called\n");
447 UNREFERENCED_PARAMETER(DeviceExt
);
449 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
450 if ((sizeof (FILE_FULL_DIR_INFORMATION
) + Length
) > BufferLength
)
451 return(STATUS_BUFFER_OVERFLOW
);
453 Info
->FileNameLength
= Length
;
454 Info
->NextEntryOffset
=
455 ROUND_UP(sizeof(FILE_FULL_DIR_INFORMATION
) + Length
, sizeof(ULONG
));
456 RtlCopyMemory(Info
->FileName
, Fcb
->ObjectName
, Length
);
458 /* Convert file times */
459 CdfsDateTimeToSystemTime(Fcb
,
460 &Info
->CreationTime
);
461 Info
->LastWriteTime
= Info
->CreationTime
;
462 Info
->ChangeTime
= Info
->CreationTime
;
464 /* Convert file flags */
465 CdfsFileFlagsToAttributes(Fcb
,
466 &Info
->FileAttributes
);
468 if (CdfsFCBIsDirectory(Fcb
))
470 Info
->EndOfFile
.QuadPart
= 0;
471 Info
->AllocationSize
.QuadPart
= 0;
475 Info
->EndOfFile
.QuadPart
= Fcb
->Entry
.DataLengthL
;
477 /* Make AllocSize a rounded up multiple of the sector size */
478 Info
->AllocationSize
.QuadPart
= ROUND_UP(Fcb
->Entry
.DataLengthL
, BLOCKSIZE
);
484 return(STATUS_SUCCESS
);
489 CdfsGetBothDirectoryInformation(PFCB Fcb
,
490 PDEVICE_EXTENSION DeviceExt
,
491 PFILE_BOTH_DIR_INFORMATION Info
,
496 DPRINT("CdfsGetBothDirectoryInformation() called\n");
498 UNREFERENCED_PARAMETER(DeviceExt
);
500 Length
= wcslen(Fcb
->ObjectName
) * sizeof(WCHAR
);
501 if ((sizeof (FILE_BOTH_DIR_INFORMATION
) + Length
) > BufferLength
)
502 return(STATUS_BUFFER_OVERFLOW
);
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
);
509 /* Convert file times */
510 CdfsDateTimeToSystemTime(Fcb
,
511 &Info
->CreationTime
);
512 Info
->LastWriteTime
= Info
->CreationTime
;
513 Info
->ChangeTime
= Info
->CreationTime
;
515 /* Convert file flags */
516 CdfsFileFlagsToAttributes(Fcb
,
517 &Info
->FileAttributes
);
519 if (CdfsFCBIsDirectory(Fcb
))
521 Info
->EndOfFile
.QuadPart
= 0;
522 Info
->AllocationSize
.QuadPart
= 0;
526 Info
->EndOfFile
.QuadPart
= Fcb
->Entry
.DataLengthL
;
528 /* Make AllocSize a rounded up multiple of the sector size */
529 Info
->AllocationSize
.QuadPart
= ROUND_UP(Fcb
->Entry
.DataLengthL
, BLOCKSIZE
);
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
);
540 return(STATUS_SUCCESS
);
545 CdfsQueryDirectory(PDEVICE_OBJECT DeviceObject
,
548 PDEVICE_EXTENSION DeviceExtension
;
549 LONG BufferLength
= 0;
550 PUNICODE_STRING SearchPattern
= NULL
;
551 FILE_INFORMATION_CLASS FileInformationClass
;
553 PUCHAR Buffer
= NULL
;
554 PFILE_NAMES_INFORMATION Buffer0
= NULL
;
558 BOOLEAN First
= FALSE
;
559 PIO_STACK_LOCATION Stack
;
560 PFILE_OBJECT FileObject
;
561 NTSTATUS Status
= STATUS_SUCCESS
;
563 DPRINT("CdfsQueryDirectory() called\n");
565 DeviceExtension
= DeviceObject
->DeviceExtension
;
566 Stack
= IoGetCurrentIrpStackLocation(Irp
);
567 FileObject
= Stack
->FileObject
;
568 RtlInitEmptyUnicodeString(&TempFcb
.PathName
, TempFcb
.PathNameBuffer
, sizeof(TempFcb
.PathNameBuffer
));
570 Ccb
= (PCCB
)FileObject
->FsContext2
;
571 Fcb
= (PFCB
)FileObject
->FsContext
;
573 /* Obtain the callers parameters */
574 BufferLength
= Stack
->Parameters
.QueryDirectory
.Length
;
575 SearchPattern
= Stack
->Parameters
.QueryDirectory
.FileName
;
576 FileInformationClass
=
577 Stack
->Parameters
.QueryDirectory
.FileInformationClass
;
578 FileIndex
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
580 /* Determine Buffer for result */
583 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
587 Buffer
= Irp
->UserBuffer
;
590 /* Allocate search pattern in case:
591 * -> We don't have one already in context
592 * -> We have been given an input pattern
593 * -> The pattern length is not null
594 * -> The pattern buffer is not null
595 * Otherwise, we'll fall later and allocate a match all (*) pattern
597 if (SearchPattern
!= NULL
&&
598 SearchPattern
->Length
!= 0 && SearchPattern
->Buffer
!= NULL
)
600 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
)
603 Ccb
->DirectorySearchPattern
.Buffer
=
604 ExAllocatePoolWithTag(NonPagedPool
, SearchPattern
->Length
+ sizeof(WCHAR
), CDFS_SEARCH_PATTERN_TAG
);
605 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
)
607 return STATUS_INSUFFICIENT_RESOURCES
;
609 Ccb
->DirectorySearchPattern
.MaximumLength
= SearchPattern
->Length
+ sizeof(WCHAR
);
610 RtlCopyUnicodeString(&Ccb
->DirectorySearchPattern
, SearchPattern
);
611 Ccb
->DirectorySearchPattern
.Buffer
[SearchPattern
->Length
/ sizeof(WCHAR
)] = 0;
614 else if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
)
617 Ccb
->DirectorySearchPattern
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, 2 * sizeof(WCHAR
), CDFS_SEARCH_PATTERN_TAG
);
618 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
)
620 return STATUS_INSUFFICIENT_RESOURCES
;
623 Ccb
->DirectorySearchPattern
.Length
= sizeof(WCHAR
);
624 Ccb
->DirectorySearchPattern
.MaximumLength
= 2 * sizeof(WCHAR
);
625 Ccb
->DirectorySearchPattern
.Buffer
[0] = L
'*';
626 Ccb
->DirectorySearchPattern
.Buffer
[1] = 0;
628 DPRINT("Search pattern '%wZ'\n", &Ccb
->DirectorySearchPattern
);
630 /* Determine directory index */
631 if (Stack
->Flags
& SL_INDEX_SPECIFIED
)
633 Ccb
->Entry
= Stack
->Parameters
.QueryDirectory
.FileIndex
;
634 Ccb
->Offset
= Ccb
->CurrentByteOffset
.u
.LowPart
;
636 else if (First
|| (Stack
->Flags
& SL_RESTART_SCAN
))
641 DPRINT("Buffer = %p tofind = %wZ\n", Buffer
, &Ccb
->DirectorySearchPattern
);
643 TempFcb
.ObjectName
= TempFcb
.PathName
.Buffer
;
644 while (Status
== STATUS_SUCCESS
&& BufferLength
> 0)
646 Status
= CdfsFindFile(DeviceExtension
,
649 &Ccb
->DirectorySearchPattern
,
652 DPRINT("Found %S, Status=%x, entry %x\n", TempFcb
.ObjectName
, Status
, Ccb
->Entry
);
654 if (NT_SUCCESS(Status
))
656 switch (FileInformationClass
)
658 case FileNameInformation
:
659 Status
= CdfsGetNameInformation(&TempFcb
,
661 (PFILE_NAMES_INFORMATION
)Buffer
,
665 case FileDirectoryInformation
:
666 Status
= CdfsGetDirectoryInformation(&TempFcb
,
668 (PFILE_DIRECTORY_INFORMATION
)Buffer
,
672 case FileFullDirectoryInformation
:
673 Status
= CdfsGetFullDirectoryInformation(&TempFcb
,
675 (PFILE_FULL_DIR_INFORMATION
)Buffer
,
679 case FileBothDirectoryInformation
:
680 Status
= CdfsGetBothDirectoryInformation(&TempFcb
,
682 (PFILE_BOTH_DIR_INFORMATION
)Buffer
,
687 Status
= STATUS_INVALID_INFO_CLASS
;
690 if (Status
== STATUS_BUFFER_OVERFLOW
)
694 Buffer0
->NextEntryOffset
= 0;
703 Buffer0
->NextEntryOffset
= 0;
708 Status
= STATUS_NO_SUCH_FILE
;
712 Status
= STATUS_NO_MORE_FILES
;
717 Buffer0
= (PFILE_NAMES_INFORMATION
)Buffer
;
718 Buffer0
->FileIndex
= FileIndex
++;
721 if (Stack
->Flags
& SL_RETURN_SINGLE_ENTRY
)
725 BufferLength
-= Buffer0
->NextEntryOffset
;
726 Buffer
+= Buffer0
->NextEntryOffset
;
731 Buffer0
->NextEntryOffset
= 0;
736 Status
= STATUS_SUCCESS
;
744 CdfsNotifyChangeDirectory(PDEVICE_OBJECT DeviceObject
,
746 PCDFS_IRP_CONTEXT IrpContext
)
748 PDEVICE_EXTENSION DeviceExtension
;
751 PIO_STACK_LOCATION Stack
;
752 PFILE_OBJECT FileObject
;
754 DPRINT("CdfsNotifyChangeDirectory() called\n");
756 DeviceExtension
= DeviceObject
->DeviceExtension
;
757 Stack
= IoGetCurrentIrpStackLocation(Irp
);
758 FileObject
= Stack
->FileObject
;
760 Ccb
= (PCCB
)FileObject
->FsContext2
;
761 Fcb
= (PFCB
)FileObject
->FsContext
;
763 FsRtlNotifyFullChangeDirectory(DeviceExtension
->NotifySync
,
764 &(DeviceExtension
->NotifyList
),
766 (PSTRING
)&(Fcb
->PathName
),
767 BooleanFlagOn(Stack
->Flags
, SL_WATCH_TREE
),
769 Stack
->Parameters
.NotifyDirectory
.CompletionFilter
,
774 /* We won't handle IRP completion */
775 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
777 return STATUS_PENDING
;
782 CdfsDirectoryControl(
783 PCDFS_IRP_CONTEXT IrpContext
)
786 PDEVICE_OBJECT DeviceObject
;
789 DPRINT("CdfsDirectoryControl() called\n");
793 Irp
= IrpContext
->Irp
;
794 DeviceObject
= IrpContext
->DeviceObject
;
796 switch (IrpContext
->MinorFunction
)
798 case IRP_MN_QUERY_DIRECTORY
:
799 Status
= CdfsQueryDirectory(DeviceObject
,
803 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
804 Status
= CdfsNotifyChangeDirectory(DeviceObject
,
809 DPRINT1("CDFS: MinorFunction %u\n", IrpContext
->MinorFunction
);
810 Status
= STATUS_INVALID_DEVICE_REQUEST
;
814 if (Status
!= STATUS_PENDING
)
816 Irp
->IoStatus
.Information
= 0;