2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
10 /* INCLUDES *****************************************************************/
14 /* GLOBALS ***************************************************************/
16 extern PEXT2_GLOBAL Ext2Global
;
18 /* DEFINITIONS *************************************************************/
21 #pragma alloc_text(PAGE, Ext2GetInfoLength)
22 #pragma alloc_text(PAGE, Ext2ProcessEntry)
23 #pragma alloc_text(PAGE, Ext2QueryDirectory)
24 #pragma alloc_text(PAGE, Ext2NotifyChangeDirectory)
25 #pragma alloc_text(PAGE, Ext2DirectoryControl)
26 #pragma alloc_text(PAGE, Ext2IsDirectoryEmpty)
30 Ext2GetInfoLength(IN FILE_INFORMATION_CLASS FileInformationClass
)
32 switch (FileInformationClass
) {
34 case FileDirectoryInformation
:
35 return FIELD_OFFSET(FILE_DIRECTORY_INFORMATION
, FileName
[0]);
37 case FileFullDirectoryInformation
:
38 return FIELD_OFFSET(FILE_FULL_DIR_INFORMATION
, FileName
[0]);
40 case FileBothDirectoryInformation
:
41 return FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION
, FileName
[0]);
43 case FileNamesInformation
:
44 return FIELD_OFFSET(FILE_NAMES_INFORMATION
, FileName
[0]);
46 case FileIdFullDirectoryInformation
:
47 return FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION
, FileName
[0]);
49 case FileIdBothDirectoryInformation
:
50 return FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION
, FileName
[0]);
61 IN PEXT2_IRP_CONTEXT IrpContext
,
64 IN FILE_INFORMATION_CLASS FileInformationClass
,
70 IN PUNICODE_STRING pName
,
75 PFILE_DIRECTORY_INFORMATION FDI
= NULL
;
76 PFILE_FULL_DIR_INFORMATION FFI
= NULL
;
77 PFILE_ID_FULL_DIR_INFORMATION FIF
= NULL
;
79 PFILE_BOTH_DIR_INFORMATION FBI
= NULL
;
80 PFILE_ID_BOTH_DIR_INFORMATION FIB
= NULL
;
82 PFILE_NAMES_INFORMATION FNI
= NULL
;
85 PEXT2_MCB Target
= NULL
;
87 NTSTATUS Status
= STATUS_SUCCESS
;
88 struct inode Inode
= { 0 };
95 LONGLONG FileSize
= 0;
96 LONGLONG AllocationSize
;
97 ULONG FileAttributes
= 0;
99 BOOLEAN IsEntrySymlink
= FALSE
;
102 NameLength
= pName
->Length
;
103 ASSERT((UsedLength
& 7) == 0);
105 InfoLength
= Ext2GetInfoLength(FileInformationClass
);
106 if (InfoLength
== 0) {
107 DEBUG(DL_ERR
, ("Ext2ProcessDirEntry: Invalid Info Class %xh for %wZ in %wZ\n",
108 FileInformationClass
, pName
, &Dcb
->Mcb
->FullName
));
109 return STATUS_INVALID_INFO_CLASS
;
112 if (InfoLength
+ NameLength
> Length
) {
113 DEBUG(DL_INF
, ( "Ext2PricessDirEntry: Buffer is not enough.\n"));
114 Status
= STATUS_BUFFER_OVERFLOW
;
115 if (UsedLength
|| InfoLength
> Length
) {
116 DEBUG(DL_CP
, ("Ext2ProcessDirEntry: Buffer overflows for %wZ in %wZ\n",
117 pName
, &Dcb
->Mcb
->FullName
));
122 DEBUG(DL_CP
, ("Ext2ProcessDirEntry: %wZ in %wZ\n", pName
, &Dcb
->Mcb
->FullName
));
124 Mcb
= Ext2SearchMcb(Vcb
, Dcb
->Mcb
, pName
);
126 if (S_ISLNK(Mcb
->Inode
.i_mode
) && NULL
== Mcb
->Target
) {
127 Ext2FollowLink( IrpContext
, Vcb
, Dcb
->Mcb
, Mcb
, 0);
133 Inode
.i_sb
= &Vcb
->sb
;
134 if (!Ext2LoadInode(Vcb
, &Inode
)) {
135 DEBUG(DL_ERR
, ("Ext2PricessDirEntry: Loading inode %xh (%wZ) error.\n",
138 Status
= STATUS_SUCCESS
;
142 if (S_ISDIR(Inode
.i_mode
) || S_ISREG(Inode
.i_mode
)) {
143 } else if (S_ISLNK(Inode
.i_mode
)) {
144 DEBUG(DL_RES
, ("Ext2ProcessDirEntry: SymLink: %wZ\\%wZ\n",
145 &Dcb
->Mcb
->FullName
, pName
));
146 Ext2LookupFile(IrpContext
, Vcb
, pName
, Dcb
->Mcb
, &Mcb
,0);
148 if (Mcb
&& IsMcbSpecialFile(Mcb
)) {
159 FileAttributes
= Mcb
->FileAttr
;
160 if (IsMcbSymLink(Mcb
)) {
161 Target
= Mcb
->Target
;
163 ASSERT(!IsMcbSymLink(Target
));
164 if (IsMcbDirectory(Target
)) {
166 FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
168 FileSize
= Target
->Inode
.i_size
;
170 if (IsFileDeleted(Target
)) {
171 ClearFlag(FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
);
175 if (IsMcbDirectory(Mcb
)) {
178 FileSize
= Mcb
->Inode
.i_size
;
182 if (IsInodeSymLink(&Mcb
->Inode
)) {
183 IsEntrySymlink
= TRUE
;
188 if (S_ISDIR(Inode
.i_mode
)) {
191 FileSize
= Inode
.i_size
;
194 if (S_ISDIR(Inode
.i_mode
)) {
195 FileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
196 } else if (S_ISLNK(Inode
.i_mode
)) {
197 FileAttributes
= FILE_ATTRIBUTE_REPARSE_POINT
;
198 IsEntrySymlink
= TRUE
;
200 FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
203 if (!Ext2CheckInodeAccess(Vcb
, &Inode
, Ext2FileCanWrite
)) {
204 SetFlag(FileAttributes
, FILE_ATTRIBUTE_READONLY
);
208 if (FileAttributes
== 0)
209 FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
211 AllocationSize
= CEILING_ALIGNED(ULONGLONG
, FileSize
, BLOCK_SIZE
);
213 /* process special files under root directory */
215 /* set hidden and system attributes for Recycled /
216 RECYCLER / pagefile.sys */
217 BOOLEAN IsDirectory
= IsFlagOn(FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
);
218 if (Ext2IsSpecialSystemFile(pName
, IsDirectory
)) {
219 SetFlag(FileAttributes
, FILE_ATTRIBUTE_HIDDEN
);
220 SetFlag(FileAttributes
, FILE_ATTRIBUTE_SYSTEM
);
224 /* set hidden attribute for all entries starting with '.' */
225 if (( pName
->Length
>= 4 && pName
->Buffer
[0] == L
'.') &&
226 ((pName
->Length
== 4 && pName
->Buffer
[1] != L
'.') ||
227 pName
->Length
>= 6 )) {
228 SetFlag(FileAttributes
, FILE_ATTRIBUTE_HIDDEN
);
231 switch (FileInformationClass
) {
233 case FileIdFullDirectoryInformation
:
234 FIF
= (PFILE_ID_FULL_DIR_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
235 case FileFullDirectoryInformation
:
236 FFI
= (PFILE_FULL_DIR_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
237 case FileDirectoryInformation
:
238 FDI
= (PFILE_DIRECTORY_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
241 FDI
->NextEntryOffset
= CEILING_ALIGNED(ULONG
, InfoLength
+ NameLength
, 8);
244 FDI
->FileIndex
= FileIndex
;
248 FDI
->CreationTime
= Mcb
->CreationTime
;
249 FDI
->LastAccessTime
= Mcb
->LastAccessTime
;
250 FDI
->LastWriteTime
= Mcb
->LastWriteTime
;
251 FDI
->ChangeTime
= Mcb
->ChangeTime
;
255 FDI
->CreationTime
= Ext2NtTime(Inode
.i_ctime
);
256 FDI
->LastAccessTime
= Ext2NtTime(Inode
.i_atime
);
257 FDI
->LastWriteTime
= Ext2NtTime(Inode
.i_mtime
);
258 FDI
->ChangeTime
= Ext2NtTime(Inode
.i_mtime
);
261 FDI
->FileAttributes
= FileAttributes
;
262 FDI
->EndOfFile
.QuadPart
= FileSize
;
263 FDI
->AllocationSize
.QuadPart
= AllocationSize
;
265 FDI
->FileNameLength
= NameLength
;
266 if (InfoLength
+ NameLength
> Length
) {
267 NameLength
= Length
- InfoLength
;
271 FIF
->FileId
.QuadPart
= (LONGLONG
) in
;
272 if (IsEntrySymlink
) {
273 FIF
->EaSize
= IO_REPARSE_TAG_SYMLINK
;
275 RtlCopyMemory(&FIF
->FileName
[0], &pName
->Buffer
[0], NameLength
);
277 if (IsEntrySymlink
) {
278 FFI
->EaSize
= IO_REPARSE_TAG_SYMLINK
;
280 RtlCopyMemory(&FFI
->FileName
[0], &pName
->Buffer
[0], NameLength
);
282 RtlCopyMemory(&FDI
->FileName
[0], &pName
->Buffer
[0], NameLength
);
285 *EntrySize
= InfoLength
+ NameLength
;
289 case FileIdBothDirectoryInformation
:
290 FIB
= (PFILE_ID_BOTH_DIR_INFORMATION
)((PUCHAR
)Buffer
+ UsedLength
);
291 case FileBothDirectoryInformation
:
292 FBI
= (PFILE_BOTH_DIR_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
295 FBI
->NextEntryOffset
= CEILING_ALIGNED(ULONG
, InfoLength
+ NameLength
, 8);
298 FBI
->FileIndex
= FileIndex
;
299 FBI
->EndOfFile
.QuadPart
= FileSize
;
300 FBI
->AllocationSize
.QuadPart
= AllocationSize
;
304 FBI
->CreationTime
= Mcb
->CreationTime
;
305 FBI
->LastAccessTime
= Mcb
->LastAccessTime
;
306 FBI
->LastWriteTime
= Mcb
->LastWriteTime
;
307 FBI
->ChangeTime
= Mcb
->ChangeTime
;
311 FBI
->CreationTime
= Ext2NtTime(Inode
.i_ctime
);
312 FBI
->LastAccessTime
= Ext2NtTime(Inode
.i_atime
);
313 FBI
->LastWriteTime
= Ext2NtTime(Inode
.i_mtime
);
314 FBI
->ChangeTime
= Ext2NtTime(Inode
.i_mtime
);
317 FBI
->FileAttributes
= FileAttributes
;
319 FBI
->FileNameLength
= NameLength
;
320 if (InfoLength
+ NameLength
> Length
) {
321 NameLength
= Length
- InfoLength
;
325 FIB
->FileId
.QuadPart
= (LONGLONG
)in
;
326 if (IsEntrySymlink
) {
327 FIB
->EaSize
= IO_REPARSE_TAG_SYMLINK
;
329 RtlCopyMemory(&FIB
->FileName
[0], &pName
->Buffer
[0], NameLength
);
331 RtlCopyMemory(&FBI
->FileName
[0], &pName
->Buffer
[0], NameLength
);
334 *EntrySize
= InfoLength
+ NameLength
;
337 case FileNamesInformation
:
339 FNI
= (PFILE_NAMES_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
341 FNI
->NextEntryOffset
= CEILING_ALIGNED(ULONG
, InfoLength
+ NameLength
, 8);
344 FNI
->FileNameLength
= NameLength
;
345 if (InfoLength
+ NameLength
> Length
) {
346 NameLength
= Length
- InfoLength
;
348 RtlCopyMemory(&FNI
->FileName
[0], &pName
->Buffer
[0], NameLength
);
350 *EntrySize
= InfoLength
+ NameLength
;
354 Status
= STATUS_INVALID_INFO_CLASS
;
364 DEBUG(DL_CP
, ("Ext2ProcessDirEntry: Status = %xh for %wZ in %wZ\n",
365 Status
, pName
, &Dcb
->Mcb
->FullName
));
374 IN POEM_STRING OemName
379 /* we could not filter the files: "." and ".." */
380 if (OemName
->Length
>= 1 && OemName
->Buffer
[0] == '.') {
382 if ( OemName
->Length
== 2 && OemName
->Buffer
[1] == '.') {
384 } else if (OemName
->Length
== 1) {
389 /* checking name prefix */
390 if (Vcb
->bHidingPrefix
) {
391 PatLen
= strlen(&Vcb
->sHidingPrefix
[0]);
392 if (PatLen
> 0 && PatLen
<= OemName
->Length
) {
393 if ( _strnicmp( OemName
->Buffer
,
401 /* checking name suffix */
402 if (Vcb
->bHidingSuffix
) {
403 PatLen
= strlen(&Vcb
->sHidingSuffix
[0]);
404 if (PatLen
> 0 && PatLen
<= OemName
->Length
) {
405 if ( _strnicmp(&OemName
->Buffer
[OemName
->Length
- PatLen
],
406 Vcb
->sHidingSuffix
, PatLen
) == 0) {
415 static int Ext2FillEntry(void *context
, const char *name
, int namlen
,
416 ULONG offset
, __u32 ino
, unsigned int d_type
)
418 PEXT2_FILLDIR_CONTEXT fc
= context
;
419 PEXT2_IRP_CONTEXT IrpContext
= fc
->efc_irp
;
421 PEXT2_FCB Fcb
= IrpContext
->Fcb
;
422 PEXT2_CCB Ccb
= IrpContext
->Ccb
;
423 PEXT2_VCB Vcb
= Fcb
->Vcb
;
426 UNICODE_STRING Unicode
= { 0 };
427 NTSTATUS Status
= STATUS_SUCCESS
;
432 if (fc
->efc_start
> 0 && (fc
->efc_single
|| (fc
->efc_size
<
433 fc
->efc_start
+ namlen
* 2 + Ext2GetInfoLength(fc
->efc_fi
)) )) {
439 Oem
.Buffer
= (void *)name
;
440 Oem
.Length
= namlen
& 0xFF;
441 Oem
.MaximumLength
= Oem
.Length
;
444 if ((Oem
.Length
== 1 && name
[0] == '.') || (Oem
.Length
== 2 &&
445 name
[0] == '.' && name
[1] == '.' )) {
449 if (Ext2IsWearingCloak(Vcb
, &Oem
)) {
453 NameLen
= (USHORT
)Ext2OEMToUnicodeSize(Vcb
, &Oem
);
455 fc
->efc_status
= STATUS_INSUFFICIENT_RESOURCES
;
460 Unicode
.MaximumLength
= NameLen
+ 2;
461 Unicode
.Buffer
= Ext2AllocatePool(
463 Unicode
.MaximumLength
,
466 if (!Unicode
.Buffer
) {
467 DEBUG(DL_ERR
, ( "Ex2QueryDirectory: failed to "
468 "allocate InodeFileName.\n"));
469 fc
->efc_status
= STATUS_INSUFFICIENT_RESOURCES
;
473 RtlZeroMemory(Unicode
.Buffer
, Unicode
.MaximumLength
);
474 INC_MEM_COUNT(PS_INODE_NAME
, Unicode
.Buffer
, Unicode
.MaximumLength
);
476 Status
= Ext2OEMToUnicode(Vcb
, &Unicode
, &Oem
);
477 if (!NT_SUCCESS(Status
)) {
478 DEBUG(DL_ERR
, ( "Ex2QueryDirectory: Ext2OEMtoUnicode failed with %xh.\n", Status
));
479 fc
->efc_status
= STATUS_INSUFFICIENT_RESOURCES
;
484 if (FsRtlDoesNameContainWildCards( &Ccb
->DirectorySearchPattern
) ?
485 FsRtlIsNameInExpression(&Ccb
->DirectorySearchPattern
,
486 &Unicode
, TRUE
, NULL
) :
487 !RtlCompareUnicodeString(&Ccb
->DirectorySearchPattern
,
489 Status
= Ext2ProcessEntry(fc
->efc_irp
, Vcb
, Fcb
, fc
->efc_fi
, ino
, fc
->efc_buf
,
490 CEILING_ALIGNED(ULONG
, fc
->efc_start
, 8),
491 fc
->efc_size
- CEILING_ALIGNED(ULONG
, fc
->efc_start
, 8),
492 offset
, &Unicode
, &EntrySize
, fc
->efc_single
);
493 if (NT_SUCCESS(Status
)) {
495 fc
->efc_prev
= CEILING_ALIGNED(ULONG
, fc
->efc_start
, 8);
496 fc
->efc_start
= fc
->efc_prev
+ EntrySize
;
501 if (Status
== STATUS_BUFFER_OVERFLOW
) {
502 if (fc
->efc_start
== 0) {
503 fc
->efc_start
= EntrySize
;
505 Status
= STATUS_SUCCESS
;
514 fc
->efc_status
= Status
;
515 if (Unicode
.Buffer
) {
516 DEC_MEM_COUNT(PS_INODE_NAME
, Unicode
.Buffer
, Unicode
.MaximumLength
);
517 Ext2FreePool(Unicode
.Buffer
, EXT2_INAME_MAGIC
);
525 Ext2QueryDirectory (IN PEXT2_IRP_CONTEXT IrpContext
)
527 PDEVICE_OBJECT DeviceObject
;
528 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
529 PEXT2_VCB Vcb
= NULL
;
530 PFILE_OBJECT FileObject
= NULL
;
531 PEXT2_FCB Fcb
= NULL
;
532 PEXT2_MCB Mcb
= NULL
;
533 PEXT2_CCB Ccb
= NULL
;
535 PIO_STACK_LOCATION IoStackLocation
= NULL
;
539 PUNICODE_STRING FileName
;
543 BOOLEAN ReturnSingleEntry
;
544 BOOLEAN IndexSpecified
;
546 BOOLEAN FcbResourceAcquired
= FALSE
;
549 FILE_INFORMATION_CLASS fi
;
551 OEM_STRING Oem
= { 0 };
552 UNICODE_STRING Unicode
= { 0 };
553 PEXT2_DIR_ENTRY2 pDir
= NULL
;
559 EXT2_FILLDIR_CONTEXT fc
= { 0 };
564 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
565 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
567 DeviceObject
= IrpContext
->DeviceObject
;
570 // This request is not allowed on the main device object
572 if (IsExt2FsDevice(DeviceObject
)) {
573 Status
= STATUS_INVALID_DEVICE_REQUEST
;
577 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
579 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
580 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
582 if (!IsMounted(Vcb
)) {
583 Status
= STATUS_VOLUME_DISMOUNTED
;
587 if (FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
)) {
588 Status
= STATUS_ACCESS_DENIED
;
592 FileObject
= IrpContext
->FileObject
;
593 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
595 Status
= STATUS_INVALID_PARAMETER
;
600 Status
= STATUS_INVALID_PARAMETER
;
603 ASSERT (!IsMcbSymLink(Mcb
));
606 // This request is not allowed on volumes
608 if (Fcb
->Identifier
.Type
== EXT2VCB
) {
609 Status
= STATUS_INVALID_PARAMETER
;
613 ASSERT((Fcb
->Identifier
.Type
== EXT2FCB
) &&
614 (Fcb
->Identifier
.Size
== sizeof(EXT2_FCB
)));
616 if (!IsMcbDirectory(Mcb
)) {
617 Status
= STATUS_NOT_A_DIRECTORY
;
621 if (IsFileDeleted(Mcb
)) {
622 Status
= STATUS_NOT_A_DIRECTORY
;
626 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
629 ASSERT((Ccb
->Identifier
.Type
== EXT2CCB
) &&
630 (Ccb
->Identifier
.Size
== sizeof(EXT2_CCB
)));
632 Irp
= IrpContext
->Irp
;
633 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
637 fi
= IoStackLocation
->Parameters
.QueryDirectory
.FileInformationClass
;
639 Length
= IoStackLocation
->Parameters
.QueryDirectory
.Length
;
641 FileName
= (PUNICODE_STRING
)IoStackLocation
->Parameters
.QueryDirectory
.FileName
;
643 FileIndex
= IoStackLocation
->Parameters
.QueryDirectory
.FileIndex
;
647 fi
= ((PEXTENDED_IO_STACK_LOCATION
)
648 IoStackLocation
)->Parameters
.QueryDirectory
.FileInformationClass
;
650 Length
= ((PEXTENDED_IO_STACK_LOCATION
)
651 IoStackLocation
)->Parameters
.QueryDirectory
.Length
;
653 FileName
= ((PEXTENDED_IO_STACK_LOCATION
)
654 IoStackLocation
)->Parameters
.QueryDirectory
.FileName
;
656 FileIndex
= ((PEXTENDED_IO_STACK_LOCATION
)
657 IoStackLocation
)->Parameters
.QueryDirectory
.FileIndex
;
659 #endif // _GNU_NTIFS_
661 RestartScan
= FlagOn(((PEXTENDED_IO_STACK_LOCATION
)
662 IoStackLocation
)->Flags
, SL_RESTART_SCAN
);
663 ReturnSingleEntry
= FlagOn(((PEXTENDED_IO_STACK_LOCATION
)
664 IoStackLocation
)->Flags
, SL_RETURN_SINGLE_ENTRY
);
665 IndexSpecified
= FlagOn(((PEXTENDED_IO_STACK_LOCATION
)
666 IoStackLocation
)->Flags
, SL_INDEX_SPECIFIED
);
668 Buffer
= Ext2GetUserBuffer(Irp
);
669 if (Buffer
== NULL
) {
671 Status
= STATUS_INVALID_USER_BUFFER
;
675 if (!IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
676 Status
= STATUS_PENDING
;
680 if (!ExAcquireResourceSharedLite(
682 IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) )) {
683 Status
= STATUS_PENDING
;
686 FcbResourceAcquired
= TRUE
;
688 if (FileName
!= NULL
) {
690 if (Ccb
->DirectorySearchPattern
.Buffer
!= NULL
) {
698 Ccb
->DirectorySearchPattern
.Length
=
699 Ccb
->DirectorySearchPattern
.MaximumLength
=
702 Ccb
->DirectorySearchPattern
.Buffer
=
703 Ext2AllocatePool(PagedPool
, FileName
->Length
,
706 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
) {
707 DEBUG(DL_ERR
, ( "Ex2QueryDirectory: failed to allocate SerarchPattern.\n"));
708 Status
= STATUS_INSUFFICIENT_RESOURCES
;
712 INC_MEM_COUNT( PS_DIR_PATTERN
,
713 Ccb
->DirectorySearchPattern
.Buffer
,
714 Ccb
->DirectorySearchPattern
.MaximumLength
);
716 Status
= RtlUpcaseUnicodeString(
717 &(Ccb
->DirectorySearchPattern
),
721 if (!NT_SUCCESS(Status
)) {
726 } else if (Ccb
->DirectorySearchPattern
.Buffer
!= NULL
) {
729 FileName
= &Ccb
->DirectorySearchPattern
;
735 Ccb
->DirectorySearchPattern
.Length
=
736 Ccb
->DirectorySearchPattern
.MaximumLength
= 2;
738 Ccb
->DirectorySearchPattern
.Buffer
=
739 Ext2AllocatePool(PagedPool
, 4, EXT2_DIRSP_MAGIC
);
741 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
) {
742 DEBUG(DL_ERR
, ( "Ex2QueryDirectory: failed to allocate SerarchPattern (1st).\n"));
743 Status
= STATUS_INSUFFICIENT_RESOURCES
;
747 INC_MEM_COUNT( PS_DIR_PATTERN
,
748 Ccb
->DirectorySearchPattern
.Buffer
,
749 Ccb
->DirectorySearchPattern
.MaximumLength
);
751 RtlZeroMemory(Ccb
->DirectorySearchPattern
.Buffer
, 4);
753 Ccb
->DirectorySearchPattern
.Buffer
,
757 if (IndexSpecified
) {
758 Ccb
->filp
.f_pos
= FileIndex
;
760 if (RestartScan
|| FirstQuery
) {
761 Ccb
->filp
.f_pos
= FileIndex
= 0;
763 FileIndex
= (ULONG
)Ccb
->filp
.f_pos
;
767 RtlZeroMemory(Buffer
, Length
);
769 fc
.efc_irp
= IrpContext
;
771 fc
.efc_size
= Length
;
773 fc
.efc_single
= ReturnSingleEntry
;
775 fc
.efc_status
= STATUS_SUCCESS
;
777 #ifdef EXT2_HTREE_INDEX
779 if (EXT3_HAS_COMPAT_FEATURE(Mcb
->Inode
.i_sb
,
780 EXT3_FEATURE_COMPAT_DIR_INDEX
) &&
781 ((EXT3_I(&Mcb
->Inode
)->i_flags
& EXT3_INDEX_FL
) ||
782 ((Mcb
->Inode
.i_size
>> BLOCK_BITS
) == 1)) ) {
783 int rc
= ext3_dx_readdir(&Ccb
->filp
, Ext2FillEntry
, &fc
);
784 Status
= fc
.efc_status
;
785 if (rc
!= ERR_BAD_DX_DIR
) {
789 * We don't set the inode dirty flag since it's not
790 * critical that it get flushed back to the disk.
792 EXT3_I(&Mcb
->Inode
)->i_flags
&= ~EXT3_INDEX_FL
;
796 if (Mcb
->Inode
.i_size
<= Ccb
->filp
.f_pos
) {
797 Status
= STATUS_NO_MORE_FILES
;
801 pDir
= Ext2AllocatePool(
803 sizeof(EXT2_DIR_ENTRY2
),
808 DEBUG(DL_ERR
, ( "Ex2QueryDirectory: failed to allocate pDir.\n"));
809 Status
= STATUS_INSUFFICIENT_RESOURCES
;
813 INC_MEM_COUNT(PS_DIR_ENTRY
, pDir
, sizeof(EXT2_DIR_ENTRY2
));
814 ByteOffset
= FileIndex
;
816 DEBUG(DL_CP
, ("Ex2QueryDirectory: Dir: %wZ Index=%xh Pattern : %wZ.\n",
817 &Fcb
->Mcb
->FullName
, FileIndex
, &Ccb
->DirectorySearchPattern
));
819 while ((ByteOffset
< Mcb
->Inode
.i_size
) &&
820 (CEILING_ALIGNED(ULONG
, fc
.efc_start
, 8) < Length
)) {
822 RtlZeroMemory(pDir
, sizeof(EXT2_DIR_ENTRY2
));
824 Status
= Ext2ReadInode(
828 (ULONGLONG
)ByteOffset
,
830 sizeof(EXT2_DIR_ENTRY2
),
834 if (!NT_SUCCESS(Status
)) {
839 if (pDir
->rec_len
== 0) {
840 RecLen
= BLOCK_SIZE
- (ByteOffset
& (BLOCK_SIZE
- 1));
842 RecLen
= ext3_rec_len_from_disk(pDir
->rec_len
);
845 if (!pDir
->inode
|| pDir
->inode
>= INODES_COUNT
) {
846 goto ProcessNextEntry
;
850 if ((pDir
->name_len
== 1 && pDir
->name
[0] == '.') ||
851 (pDir
->name_len
== 2 && pDir
->name
[0] == '.' && pDir
->name
[1] == '.' )) {
852 goto ProcessNextEntry
;
855 Oem
.Buffer
= pDir
->name
;
856 Oem
.Length
= (pDir
->name_len
& 0xff);
857 Oem
.MaximumLength
= Oem
.Length
;
859 if (Ext2IsWearingCloak(Vcb
, &Oem
)) {
860 goto ProcessNextEntry
;
863 NameLen
= (USHORT
) Ext2OEMToUnicodeSize(Vcb
, &Oem
);
866 DEBUG(DL_CP
, ("Ext2QueryDirectory: failed to count unicode length for inode: %xh\n",
868 Status
= STATUS_INSUFFICIENT_RESOURCES
;
872 if ( Unicode
.Buffer
!= NULL
&& Unicode
.MaximumLength
> NameLen
) {
875 /* free and re-allocate it */
876 if (Unicode
.Buffer
) {
877 DEC_MEM_COUNT(PS_INODE_NAME
,
879 Unicode
.MaximumLength
);
880 Ext2FreePool(Unicode
.Buffer
, EXT2_INAME_MAGIC
);
882 Unicode
.MaximumLength
= NameLen
+ 2;
883 Unicode
.Buffer
= Ext2AllocatePool(
884 PagedPool
, Unicode
.MaximumLength
,
887 if (!Unicode
.Buffer
) {
888 DEBUG(DL_ERR
, ( "Ex2QueryDirectory: failed to "
889 "allocate InodeFileName.\n"));
890 Status
= STATUS_INSUFFICIENT_RESOURCES
;
893 INC_MEM_COUNT(PS_INODE_NAME
, Unicode
.Buffer
, Unicode
.MaximumLength
);
897 RtlZeroMemory(Unicode
.Buffer
, Unicode
.MaximumLength
);
899 Status
= Ext2OEMToUnicode(Vcb
, &Unicode
, &Oem
);
900 if (!NT_SUCCESS(Status
)) {
901 DEBUG(DL_ERR
, ( "Ex2QueryDirectory: Ext2OEMtoUnicode failed with %xh.\n", Status
));
902 Status
= STATUS_INSUFFICIENT_RESOURCES
;
906 DEBUG(DL_CP
, ( "Ex2QueryDirectory: process inode: %xh / %wZ (%d).\n",
907 pDir
->inode
, &Unicode
, Unicode
.Length
));
909 if (FsRtlDoesNameContainWildCards(
910 &(Ccb
->DirectorySearchPattern
)) ?
911 FsRtlIsNameInExpression(
912 &(Ccb
->DirectorySearchPattern
),
916 !RtlCompareUnicodeString(
917 &(Ccb
->DirectorySearchPattern
),
921 Status
= Ext2ProcessEntry(
928 CEILING_ALIGNED(ULONG
, fc
.efc_start
, 8),
929 Length
- CEILING_ALIGNED(ULONG
, fc
.efc_start
, 8),
936 if (NT_SUCCESS(Status
)) {
938 fc
.efc_prev
= CEILING_ALIGNED(ULONG
, fc
.efc_start
, 8);
939 fc
.efc_start
= fc
.efc_prev
+ EntrySize
;
944 if (Status
== STATUS_BUFFER_OVERFLOW
) {
945 if (fc
.efc_start
== 0) {
946 fc
.efc_start
= EntrySize
;
948 Status
= STATUS_SUCCESS
;
959 ByteOffset
+= RecLen
;
960 Ccb
->filp
.f_pos
= ByteOffset
;
962 if (fc
.efc_start
&& ReturnSingleEntry
) {
963 Status
= STATUS_SUCCESS
;
970 ((PULONG
)((PUCHAR
)Buffer
+ fc
.efc_prev
))[0] = 0;
971 FileIndex
= ByteOffset
;
973 if (Status
== STATUS_BUFFER_OVERFLOW
) {
974 /* just return fc.efc_start/EntrySize bytes that we filled */
975 } else if (!fc
.efc_start
) {
976 if (NT_SUCCESS(Status
)) {
978 Status
= STATUS_NO_SUCH_FILE
;
980 Status
= STATUS_NO_MORE_FILES
;
984 Status
= STATUS_SUCCESS
;
989 if (FcbResourceAcquired
) {
990 ExReleaseResourceLite(&Fcb
->MainResource
);
994 Ext2FreePool(pDir
, EXT2_DENTRY_MAGIC
);
995 DEC_MEM_COUNT(PS_DIR_ENTRY
, pDir
, sizeof(EXT2_DIR_ENTRY2
));
998 if (Unicode
.Buffer
!= NULL
) {
999 DEC_MEM_COUNT(PS_INODE_NAME
, Unicode
.Buffer
, Unicode
.MaximumLength
);
1000 Ext2FreePool(Unicode
.Buffer
, EXT2_INAME_MAGIC
);
1003 if (!IrpContext
->ExceptionInProgress
) {
1005 if ( Status
== STATUS_PENDING
||
1006 Status
== STATUS_CANT_WAIT
) {
1008 Status
= Ext2LockUserBuffer(
1013 if (NT_SUCCESS(Status
)) {
1014 Status
= Ext2QueueRequest(IrpContext
);
1016 Ext2CompleteIrpContext(IrpContext
, Status
);
1019 IrpContext
->Irp
->IoStatus
.Information
= fc
.efc_start
;
1020 Ext2CompleteIrpContext(IrpContext
, Status
);
1029 Ext2NotifyChangeDirectory (
1030 IN PEXT2_IRP_CONTEXT IrpContext
1033 PDEVICE_OBJECT DeviceObject
;
1034 BOOLEAN CompleteRequest
= TRUE
;
1035 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1036 PEXT2_VCB Vcb
= NULL
;
1037 PEXT2_FCB Fcb
= NULL
;
1038 PEXT2_CCB Ccb
= NULL
;
1040 PIO_STACK_LOCATION IrpSp
;
1041 PFILE_OBJECT FileObject
;
1042 ULONG CompletionFilter
;
1045 BOOLEAN bFcbAcquired
= FALSE
;
1050 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
1051 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
1054 // Always set the wait flag in the Irp context for the original request.
1057 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1059 DeviceObject
= IrpContext
->DeviceObject
;
1061 if (IsExt2FsDevice(DeviceObject
)) {
1062 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1066 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
1068 ASSERT(Vcb
!= NULL
);
1069 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
1070 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
1072 FileObject
= IrpContext
->FileObject
;
1073 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
1075 if (Fcb
->Identifier
.Type
== EXT2VCB
) {
1077 Status
= STATUS_INVALID_PARAMETER
;
1080 ASSERT((Fcb
->Identifier
.Type
== EXT2FCB
) &&
1081 (Fcb
->Identifier
.Size
== sizeof(EXT2_FCB
)));
1083 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
1085 ASSERT((Ccb
->Identifier
.Type
== EXT2CCB
) &&
1086 (Ccb
->Identifier
.Size
== sizeof(EXT2_CCB
)));
1088 /* do nothing if target fie was deleted */
1089 if (FlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
)) {
1090 Status
= STATUS_FILE_DELETED
;
1094 if (!IsDirectory(Fcb
)) {
1096 Status
= STATUS_INVALID_PARAMETER
;
1100 if (ExAcquireResourceExclusiveLite(
1103 bFcbAcquired
= TRUE
;
1105 Status
= STATUS_PENDING
;
1109 Irp
= IrpContext
->Irp
;
1111 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1116 IrpSp
->Parameters
.NotifyDirectory
.CompletionFilter
;
1118 #else // _GNU_NTIFS_
1120 CompletionFilter
= ((PEXTENDED_IO_STACK_LOCATION
)
1121 IrpSp
)->Parameters
.NotifyDirectory
.CompletionFilter
;
1123 #endif // _GNU_NTIFS_
1125 WatchTree
= IsFlagOn(IrpSp
->Flags
, SL_WATCH_TREE
);
1127 if (FlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
)) {
1128 Status
= STATUS_DELETE_PENDING
;
1132 FsRtlNotifyFullChangeDirectory( Vcb
->NotifySync
,
1134 FileObject
->FsContext2
,
1135 (PSTRING
)(&Fcb
->Mcb
->FullName
),
1143 CompleteRequest
= FALSE
;
1145 Status
= STATUS_PENDING
;
1148 Currently the driver is read-only but here is an example on how to use the
1149 FsRtl-functions to report a change:
1151 ANSI_STRING TestString;
1152 USHORT FileNamePartLength;
1154 RtlInitAnsiString(&TestString, "\\ntifs.h");
1156 FileNamePartLength = 7;
1158 FsRtlNotifyReportChange(
1159 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
1160 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
1161 &TestString, // PSTRING FullTargetName
1162 &FileNamePartLength, // PUSHORT FileNamePartLength
1163 FILE_NOTIFY_CHANGE_NAME // ULONG FilterMatch
1168 ANSI_STRING TestString;
1170 RtlInitAnsiString(&TestString, "\\ntifs.h");
1172 FsRtlNotifyFullReportChange(
1173 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
1174 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
1175 &TestString, // PSTRING FullTargetName
1176 1, // USHORT TargetNameOffset
1177 NULL, // PSTRING StreamName OPTIONAL
1178 NULL, // PSTRING NormalizedParentName OPTIONAL
1179 FILE_NOTIFY_CHANGE_NAME, // ULONG FilterMatch
1181 NULL // PVOID TargetContext
1188 ExReleaseResourceLite(&Fcb
->MainResource
);
1191 if (!IrpContext
->ExceptionInProgress
) {
1192 if (CompleteRequest
) {
1193 if (Status
== STATUS_PENDING
) {
1194 Ext2QueueRequest(IrpContext
);
1196 Ext2CompleteIrpContext(IrpContext
, Status
);
1199 IrpContext
->Irp
= NULL
;
1200 Ext2CompleteIrpContext(IrpContext
, Status
);
1209 Ext2NotifyReportChange (
1210 IN PEXT2_IRP_CONTEXT IrpContext
,
1218 Offset
= (USHORT
) ( Mcb
->FullName
.Length
-
1219 Mcb
->ShortName
.Length
);
1221 FsRtlNotifyFullReportChange( Vcb
->NotifySync
,
1223 (PSTRING
) (&Mcb
->FullName
),
1231 // ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
1236 Ext2DirectoryControl (IN PEXT2_IRP_CONTEXT IrpContext
)
1242 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
1243 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
1245 switch (IrpContext
->MinorFunction
) {
1247 case IRP_MN_QUERY_DIRECTORY
:
1248 Status
= Ext2QueryDirectory(IrpContext
);
1251 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
1252 Status
= Ext2NotifyChangeDirectory(IrpContext
);
1256 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1257 Ext2CompleteIrpContext(IrpContext
, Status
);
1265 Ext2IsDirectoryEmpty (
1266 PEXT2_IRP_CONTEXT IrpContext
,
1271 if (!IsMcbDirectory(Mcb
) || IsMcbSymLink(Mcb
)) {
1275 return !!ext3_is_dir_empty(IrpContext
, &Mcb
->Inode
);