2 * FFS File System Driver for Windows
8 * Lee Jae-Hong, http://www.pyrasis.com
19 extern PFFS_GLOBAL FFSGlobal
;
25 #pragma alloc_text(PAGE, FFSGetInfoLength)
26 #pragma alloc_text(PAGE, FFSProcessDirEntry)
27 #pragma alloc_text(PAGE, FFSQueryDirectory)
28 #pragma alloc_text(PAGE, FFSNotifyChangeDirectory)
29 #pragma alloc_text(PAGE, FFSDirectoryControl)
30 #pragma alloc_text(PAGE, FFSIsDirectoryEmpty)
35 IN FILE_INFORMATION_CLASS FileInformationClass
)
39 switch (FileInformationClass
)
41 case FileDirectoryInformation
:
42 return sizeof(FILE_DIRECTORY_INFORMATION
);
45 case FileFullDirectoryInformation
:
46 return sizeof(FILE_FULL_DIR_INFORMATION
);
49 case FileBothDirectoryInformation
:
50 return sizeof(FILE_BOTH_DIR_INFORMATION
);
53 case FileNamesInformation
:
54 return sizeof(FILE_NAMES_INFORMATION
);
68 IN FILE_INFORMATION_CLASS FileInformationClass
,
74 IN PUNICODE_STRING pName
,
79 PFILE_DIRECTORY_INFORMATION FDI
;
80 PFILE_FULL_DIR_INFORMATION FFI
;
81 PFILE_BOTH_DIR_INFORMATION FBI
;
82 PFILE_NAMES_INFORMATION FNI
;
90 NameLength
= pName
->Length
;
94 FFSPrint((DBG_ERROR
, "FFSPricessDirEntry: ffs_dir_entry is empty.\n"));
98 InfoLength
= FFSGetInfoLength(FileInformationClass
);
100 if (!InfoLength
|| InfoLength
+ NameLength
- sizeof(WCHAR
) > Length
)
102 FFSPrint((DBG_INFO
, "FFSPricessDirEntry: Buffer is not enough.\n"));
108 if(!FFSv1LoadInode(Vcb
, in
, &dinode1
))
110 FFSPrint((DBG_ERROR
, "FFSPricessDirEntry: Loading inode %xh error.\n", in
));
119 if(!FFSv2LoadInode(Vcb
, in
, &dinode2
))
121 FFSPrint((DBG_ERROR
, "FFSPricessDirEntry: Loading inode %xh error.\n", in
));
129 switch(FileInformationClass
)
131 case FileDirectoryInformation
:
132 FDI
= (PFILE_DIRECTORY_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
134 FDI
->NextEntryOffset
= InfoLength
+ NameLength
- sizeof(WCHAR
);
136 FDI
->NextEntryOffset
= 0;
137 FDI
->FileIndex
= FileIndex
;
141 FDI
->CreationTime
= FFSSysTime(dinode1
.di_ctime
);
142 FDI
->LastAccessTime
= FFSSysTime(dinode1
.di_atime
);
143 FDI
->LastWriteTime
= FFSSysTime(dinode1
.di_mtime
);
144 FDI
->ChangeTime
= FFSSysTime(dinode1
.di_mtime
);
145 FDI
->EndOfFile
.QuadPart
= dinode1
.di_size
;
146 FDI
->AllocationSize
.QuadPart
= dinode1
.di_size
;
147 FDI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
149 if (FlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || FFSIsReadOnly(dinode1
.di_mode
))
151 SetFlag(FDI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
154 if ((dinode1
.di_mode
& IFMT
) == IFDIR
)
155 FDI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
157 FDI
->FileNameLength
= NameLength
;
158 RtlCopyMemory(FDI
->FileName
, pName
->Buffer
, NameLength
);
159 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
164 FDI
->CreationTime
= FFSSysTime((ULONG
)dinode2
.di_ctime
);
165 FDI
->LastAccessTime
= FFSSysTime((ULONG
)dinode2
.di_atime
);
166 FDI
->LastWriteTime
= FFSSysTime((ULONG
)dinode2
.di_mtime
);
167 FDI
->ChangeTime
= FFSSysTime((ULONG
)dinode2
.di_mtime
);
168 FDI
->EndOfFile
.QuadPart
= dinode2
.di_size
;
169 FDI
->AllocationSize
.QuadPart
= dinode2
.di_size
;
170 FDI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
172 if (FlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || FFSIsReadOnly(dinode2
.di_mode
))
174 SetFlag(FDI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
177 if ((dinode2
.di_mode
& IFMT
) == IFDIR
)
178 FDI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
180 FDI
->FileNameLength
= NameLength
;
181 RtlCopyMemory(FDI
->FileName
, pName
->Buffer
, NameLength
);
182 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
186 case FileFullDirectoryInformation
:
187 FFI
= (PFILE_FULL_DIR_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
189 FFI
->NextEntryOffset
= InfoLength
+ NameLength
- sizeof(WCHAR
);
191 FFI
->NextEntryOffset
= 0;
192 FFI
->FileIndex
= FileIndex
;
196 FFI
->CreationTime
= FFSSysTime(dinode1
.di_ctime
);
197 FFI
->LastAccessTime
= FFSSysTime(dinode1
.di_atime
);
198 FFI
->LastWriteTime
= FFSSysTime(dinode1
.di_mtime
);
199 FFI
->ChangeTime
= FFSSysTime(dinode1
.di_mtime
);
200 FFI
->EndOfFile
.QuadPart
= dinode1
.di_size
;
201 FFI
->AllocationSize
.QuadPart
= dinode1
.di_size
;
202 FFI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
204 if (IsFlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || FFSIsReadOnly(dinode1
.di_mode
))
206 SetFlag(FFI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
209 if ((dinode1
.di_mode
& IFMT
) == IFDIR
)
210 FFI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
212 FFI
->FileNameLength
= NameLength
;
213 RtlCopyMemory(FFI
->FileName
, pName
->Buffer
, NameLength
);
214 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
220 FFI
->CreationTime
= FFSSysTime((ULONG
)dinode2
.di_ctime
);
221 FFI
->LastAccessTime
= FFSSysTime((ULONG
)dinode2
.di_atime
);
222 FFI
->LastWriteTime
= FFSSysTime((ULONG
)dinode2
.di_mtime
);
223 FFI
->ChangeTime
= FFSSysTime((ULONG
)dinode2
.di_mtime
);
224 FFI
->EndOfFile
.QuadPart
= dinode2
.di_size
;
225 FFI
->AllocationSize
.QuadPart
= dinode2
.di_size
;
226 FFI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
228 if (IsFlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || FFSIsReadOnly(dinode2
.di_mode
))
230 SetFlag(FFI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
233 if ((dinode2
.di_mode
& IFMT
) == IFDIR
)
234 FFI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
236 FFI
->FileNameLength
= NameLength
;
237 RtlCopyMemory(FFI
->FileName
, pName
->Buffer
, NameLength
);
238 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
243 case FileBothDirectoryInformation
:
244 FBI
= (PFILE_BOTH_DIR_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
246 FBI
->NextEntryOffset
= InfoLength
+ NameLength
- sizeof(WCHAR
);
248 FBI
->NextEntryOffset
= 0;
252 FBI
->CreationTime
= FFSSysTime(dinode1
.di_ctime
);
253 FBI
->LastAccessTime
= FFSSysTime(dinode1
.di_atime
);
254 FBI
->LastWriteTime
= FFSSysTime(dinode1
.di_mtime
);
255 FBI
->ChangeTime
= FFSSysTime(dinode1
.di_mtime
);
257 FBI
->FileIndex
= FileIndex
;
258 FBI
->EndOfFile
.QuadPart
= dinode1
.di_size
;
259 FBI
->AllocationSize
.QuadPart
= dinode1
.di_size
;
260 FBI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
262 if (FlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || FFSIsReadOnly(dinode1
.di_mode
))
264 SetFlag(FBI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
267 if ((dinode1
.di_mode
& IFMT
) == IFDIR
)
268 FBI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
269 FBI
->FileNameLength
= NameLength
;
270 RtlCopyMemory(FBI
->FileName
, pName
->Buffer
, NameLength
);
271 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
277 FBI
->CreationTime
= FFSSysTime((ULONG
)dinode2
.di_ctime
);
278 FBI
->LastAccessTime
= FFSSysTime((ULONG
)dinode2
.di_atime
);
279 FBI
->LastWriteTime
= FFSSysTime((ULONG
)dinode2
.di_mtime
);
280 FBI
->ChangeTime
= FFSSysTime((ULONG
)dinode2
.di_mtime
);
282 FBI
->FileIndex
= FileIndex
;
283 FBI
->EndOfFile
.QuadPart
= dinode2
.di_size
;
284 FBI
->AllocationSize
.QuadPart
= dinode2
.di_size
;
285 FBI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
287 if (FlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || FFSIsReadOnly(dinode2
.di_mode
))
289 SetFlag(FBI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
292 if ((dinode2
.di_mode
& IFMT
) == IFDIR
)
293 FBI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
294 FBI
->FileNameLength
= NameLength
;
295 RtlCopyMemory(FBI
->FileName
, pName
->Buffer
, NameLength
);
296 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
301 case FileNamesInformation
:
302 FNI
= (PFILE_NAMES_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
304 FNI
->NextEntryOffset
= InfoLength
+ NameLength
- sizeof(WCHAR
);
306 FNI
->NextEntryOffset
= 0;
307 FNI
->FileNameLength
= NameLength
;
308 RtlCopyMemory(FNI
->FileName
, pName
->Buffer
, NameLength
);
309 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
321 __drv_mustHoldCriticalRegion
324 IN PFFS_IRP_CONTEXT IrpContext
)
326 PDEVICE_OBJECT DeviceObject
;
327 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
329 PFILE_OBJECT FileObject
;
333 PIO_STACK_LOCATION IoStackLocation
;
334 FILE_INFORMATION_CLASS FileInformationClass
;
336 PUNICODE_STRING FileName
;
339 BOOLEAN ReturnSingleEntry
;
340 BOOLEAN IndexSpecified
;
343 PFFSv1_INODE dinode1
= NULL
;
344 PFFSv2_INODE dinode2
= NULL
;
345 BOOLEAN FcbResourceAcquired
= FALSE
;
346 ULONG UsedLength
= 0;
347 USHORT InodeFileNameLength
;
348 UNICODE_STRING InodeFileName
;
349 PFFS_DIR_ENTRY pDir
= NULL
;
359 InodeFileName
.Buffer
= NULL
;
365 ASSERT((IrpContext
->Identifier
.Type
== FFSICX
) &&
366 (IrpContext
->Identifier
.Size
== sizeof(FFS_IRP_CONTEXT
)));
368 DeviceObject
= IrpContext
->DeviceObject
;
371 // This request is not allowed on the main device object
373 if (DeviceObject
== FFSGlobal
->DeviceObject
)
375 Status
= STATUS_INVALID_DEVICE_REQUEST
;
379 Vcb
= (PFFS_VCB
)DeviceObject
->DeviceExtension
;
383 ASSERT((Vcb
->Identifier
.Type
== FFSVCB
) &&
384 (Vcb
->Identifier
.Size
== sizeof(FFS_VCB
)));
386 ASSERT(IsMounted(Vcb
));
388 FileObject
= IrpContext
->FileObject
;
390 Fcb
= (PFFS_FCB
)FileObject
->FsContext
;
395 // This request is not allowed on volumes
397 if (Fcb
->Identifier
.Type
== FFSVCB
)
399 Status
= STATUS_INVALID_PARAMETER
;
403 ASSERT((Fcb
->Identifier
.Type
== FFSFCB
) &&
404 (Fcb
->Identifier
.Size
== sizeof(FFS_FCB
)));
406 if (!IsDirectory(Fcb
))
408 Status
= STATUS_INVALID_PARAMETER
;
412 Ccb
= (PFFS_CCB
)FileObject
->FsContext2
;
416 ASSERT((Ccb
->Identifier
.Type
== FFSCCB
) &&
417 (Ccb
->Identifier
.Size
== sizeof(FFS_CCB
)));
419 Irp
= IrpContext
->Irp
;
421 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
423 #if !defined(_GNU_NTIFS_) || defined(__REACTOS__)
425 FileInformationClass
=
426 IoStackLocation
->Parameters
.QueryDirectory
.FileInformationClass
;
428 Length
= IoStackLocation
->Parameters
.QueryDirectory
.Length
;
430 FileName
= IoStackLocation
->Parameters
.QueryDirectory
.FileName
;
432 FileIndex
= IoStackLocation
->Parameters
.QueryDirectory
.FileIndex
;
436 FileInformationClass
= ((PEXTENDED_IO_STACK_LOCATION
)
437 IoStackLocation
)->Parameters
.QueryDirectory
.FileInformationClass
;
439 Length
= ((PEXTENDED_IO_STACK_LOCATION
)
440 IoStackLocation
)->Parameters
.QueryDirectory
.Length
;
442 FileName
= ((PEXTENDED_IO_STACK_LOCATION
)
443 IoStackLocation
)->Parameters
.QueryDirectory
.FileName
;
445 FileIndex
= ((PEXTENDED_IO_STACK_LOCATION
)
446 IoStackLocation
)->Parameters
.QueryDirectory
.FileIndex
;
448 #endif // _GNU_NTIFS_
450 RestartScan
= FlagOn(IoStackLocation
->Flags
, SL_RESTART_SCAN
);
451 ReturnSingleEntry
= FlagOn(IoStackLocation
->Flags
, SL_RETURN_SINGLE_ENTRY
);
452 IndexSpecified
= FlagOn(IoStackLocation
->Flags
, SL_INDEX_SPECIFIED
);
454 if (!Irp->MdlAddress && Irp->UserBuffer)
456 ProbeForWrite(Irp->UserBuffer, Length, 1);
459 Buffer
= FFSGetUserBuffer(Irp
);
464 Status
= STATUS_INVALID_USER_BUFFER
;
468 if (!IrpContext
->IsSynchronous
)
470 Status
= STATUS_PENDING
;
474 if (!ExAcquireResourceSharedLite(
476 IrpContext
->IsSynchronous
))
478 Status
= STATUS_PENDING
;
482 FcbResourceAcquired
= TRUE
;
484 if (FileName
!= NULL
)
486 if (Ccb
->DirectorySearchPattern
.Buffer
!= NULL
)
494 Ccb
->DirectorySearchPattern
.Length
=
495 Ccb
->DirectorySearchPattern
.MaximumLength
=
498 Ccb
->DirectorySearchPattern
.Buffer
=
499 ExAllocatePoolWithTag(PagedPool
, FileName
->Length
, FFS_POOL_TAG
);
501 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
)
503 Status
= STATUS_INSUFFICIENT_RESOURCES
;
507 Status
= RtlUpcaseUnicodeString(
508 &(Ccb
->DirectorySearchPattern
),
512 if (!NT_SUCCESS(Status
))
516 else if (Ccb
->DirectorySearchPattern
.Buffer
!= NULL
)
519 FileName
= &Ccb
->DirectorySearchPattern
;
525 Ccb
->DirectorySearchPattern
.Length
=
526 Ccb
->DirectorySearchPattern
.MaximumLength
= 2;
528 Ccb
->DirectorySearchPattern
.Buffer
=
529 ExAllocatePoolWithTag(PagedPool
, 2, FFS_POOL_TAG
);
531 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
)
533 Status
= STATUS_INSUFFICIENT_RESOURCES
;
538 Ccb
->DirectorySearchPattern
.Buffer
,
544 if (RestartScan
|| FirstQuery
)
546 FileIndex
= Fcb
->FFSMcb
->DeOffset
= 0;
550 FileIndex
= Ccb
->CurrentByteOffset
;
556 dinode1
= (PFFSv1_INODE
)ExAllocatePoolWithTag(
558 DINODE1_SIZE
, FFS_POOL_TAG
);
562 Status
= STATUS_INSUFFICIENT_RESOURCES
;
566 RtlZeroMemory(Buffer
, Length
);
568 if (Fcb
->dinode1
->di_size
<= FileIndex
)
570 Status
= STATUS_NO_MORE_FILES
;
576 dinode2
= (PFFSv2_INODE
)ExAllocatePoolWithTag(
578 DINODE2_SIZE
, FFS_POOL_TAG
);
582 Status
= STATUS_INSUFFICIENT_RESOURCES
;
586 RtlZeroMemory(Buffer
, Length
);
588 if (Fcb
->dinode2
->di_size
<= FileIndex
)
590 Status
= STATUS_NO_MORE_FILES
;
595 pDir
= ExAllocatePoolWithTag(PagedPool
,
596 sizeof(FFS_DIR_ENTRY
), FFS_POOL_TAG
);
599 Status
= STATUS_INSUFFICIENT_RESOURCES
;
607 dwSize
= (ULONG
)Fcb
->dinode1
->di_size
- FileIndex
-
608 (sizeof(FFS_DIR_ENTRY
) - FFS_NAME_LEN
+ 1);
610 ByteOffset
= FileIndex
;
614 while (bRun
&& UsedLength
< Length
&& dwBytes
< dwSize
)
618 RtlZeroMemory(pDir
, sizeof(FFS_DIR_ENTRY
));
620 Status
= FFSv1ReadInode(
626 sizeof(FFS_DIR_ENTRY
),
629 if (!NT_SUCCESS(Status
))
636 if (pDir
->d_reclen
== 0)
642 goto ProcessNextEntryv1
;
645 OemName
.Buffer
= pDir
->d_name
;
646 OemName
.Length
= (pDir
->d_namlen
& 0xff);
647 OemName
.MaximumLength
= OemName
.Length
;
652 // We could not filter the files: "." and ".."
655 if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
657 if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
662 goto ProcessNextEntry1;
668 InodeFileNameLength
= (USHORT
)
669 RtlOemStringToUnicodeSize(&OemName
);
671 InodeFileName
.Length
= 0;
672 InodeFileName
.MaximumLength
= InodeFileNameLength
+ 2;
674 if (InodeFileNameLength
<= 0)
679 InodeFileName
.Buffer
= ExAllocatePoolWithTag(
681 InodeFileNameLength
+ 2, FFS_POOL_TAG
);
683 if (!InodeFileName
.Buffer
)
685 Status
= STATUS_INSUFFICIENT_RESOURCES
;
690 InodeFileName
.Buffer
,
691 InodeFileNameLength
+ 2);
693 Status
= FFSOEMToUnicode(&InodeFileName
,
696 if (!NT_SUCCESS(Status
))
701 if (FsRtlDoesNameContainWildCards(
702 &(Ccb
->DirectorySearchPattern
)) ?
703 FsRtlIsNameInExpression(
704 &(Ccb
->DirectorySearchPattern
),
708 !RtlCompareUnicodeString(
709 &(Ccb
->DirectorySearchPattern
),
713 dwReturn
= FFSProcessDirEntry(
714 Vcb
, FileInformationClass
,
719 (FileIndex
+ dwBytes
),
730 UsedLength
+= dwReturn
;
734 if (InodeFileName
.Buffer
!= NULL
)
736 ExFreePool(InodeFileName
.Buffer
);
737 InodeFileName
.Buffer
= NULL
;
744 dwBytes
+=pDir
->d_reclen
;
745 Ccb
->CurrentByteOffset
= FileIndex
+ dwBytes
;
748 if (UsedLength
&& ReturnSingleEntry
)
750 Status
= STATUS_SUCCESS
;
754 ByteOffset
= FileIndex
+ dwBytes
;
760 dwSize
= (ULONG
)Fcb
->dinode2
->di_size
- FileIndex
-
761 (sizeof(FFS_DIR_ENTRY
) - FFS_NAME_LEN
+ 1);
763 ByteOffset
= FileIndex
;
767 while (bRun
&& UsedLength
< Length
&& dwBytes
< dwSize
)
771 RtlZeroMemory(pDir
, sizeof(FFS_DIR_ENTRY
));
773 Status
= FFSv2ReadInode(
779 sizeof(FFS_DIR_ENTRY
),
782 if (!NT_SUCCESS(Status
))
789 if (pDir
->d_reclen
== 0)
795 goto ProcessNextEntryv2
;
798 OemName
.Buffer
= pDir
->d_name
;
799 OemName
.Length
= (pDir
->d_namlen
& 0xff);
800 OemName
.MaximumLength
= OemName
.Length
;
804 // We could not filter the files: "." and ".."
807 if ((OemName.Length >) 1 && OemName.Buffer[0] == '.')
809 if ( OemName.Length == 2 && OemName.Buffer[1] == '.')
814 goto ProcessNextEntry2;
820 InodeFileNameLength
= (USHORT
)
821 RtlOemStringToUnicodeSize(&OemName
);
823 InodeFileName
.Length
= 0;
824 InodeFileName
.MaximumLength
= InodeFileNameLength
+ 2;
826 if (InodeFileNameLength
<= 0)
831 InodeFileName
.Buffer
= ExAllocatePoolWithTag(
833 InodeFileNameLength
+ 2, FFS_POOL_TAG
);
835 if (!InodeFileName
.Buffer
)
837 Status
= STATUS_INSUFFICIENT_RESOURCES
;
842 InodeFileName
.Buffer
,
843 InodeFileNameLength
+ 2);
845 Status
= FFSOEMToUnicode(&InodeFileName
,
848 if (!NT_SUCCESS(Status
))
853 if (FsRtlDoesNameContainWildCards(
854 &(Ccb
->DirectorySearchPattern
)) ?
855 FsRtlIsNameInExpression(
856 &(Ccb
->DirectorySearchPattern
),
860 !RtlCompareUnicodeString(
861 &(Ccb
->DirectorySearchPattern
),
865 dwReturn
= FFSProcessDirEntry(
866 Vcb
, FileInformationClass
,
871 (FileIndex
+ dwBytes
),
882 UsedLength
+= dwReturn
;
886 if (InodeFileName
.Buffer
!= NULL
)
888 ExFreePool(InodeFileName
.Buffer
);
889 InodeFileName
.Buffer
= NULL
;
896 dwBytes
+=pDir
->d_reclen
;
897 Ccb
->CurrentByteOffset
= FileIndex
+ dwBytes
;
900 if (UsedLength
&& ReturnSingleEntry
)
902 Status
= STATUS_SUCCESS
;
906 ByteOffset
= FileIndex
+ dwBytes
;
910 FileIndex
+= dwBytes
;
912 ((PULONG
)((PUCHAR
)Buffer
+ dwTemp
)) [0] = 0;
918 Status
= STATUS_NO_SUCH_FILE
;
922 Status
= STATUS_NO_MORE_FILES
;
927 Status
= STATUS_SUCCESS
;
934 if (FcbResourceAcquired
)
936 ExReleaseResourceForThreadLite(
938 ExGetCurrentResourceThread());
962 if (InodeFileName
.Buffer
!= NULL
)
964 ExFreePool(InodeFileName
.Buffer
);
967 if (!IrpContext
->ExceptionInProgress
)
969 if (Status
== STATUS_PENDING
)
971 Status
= FFSLockUserBuffer(
976 if (NT_SUCCESS(Status
))
978 Status
= FFSQueueRequest(IrpContext
);
982 FFSCompleteIrpContext(IrpContext
, Status
);
987 IrpContext
->Irp
->IoStatus
.Information
= UsedLength
;
988 FFSCompleteIrpContext(IrpContext
, Status
);
997 __drv_mustHoldCriticalRegion
999 FFSNotifyChangeDirectory(
1000 IN PFFS_IRP_CONTEXT IrpContext
)
1002 PDEVICE_OBJECT DeviceObject
;
1003 BOOLEAN CompleteRequest
;
1004 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1006 PFILE_OBJECT FileObject
;
1009 PIO_STACK_LOCATION IrpSp
;
1010 ULONG CompletionFilter
;
1013 BOOLEAN bFcbAcquired
= FALSE
;
1015 PUNICODE_STRING FullName
;
1023 ASSERT((IrpContext
->Identifier
.Type
== FFSICX
) &&
1024 (IrpContext
->Identifier
.Size
== sizeof(FFS_IRP_CONTEXT
)));
1027 // Always set the wait flag in the Irp context for the original request.
1030 SetFlag(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
1032 DeviceObject
= IrpContext
->DeviceObject
;
1034 if (DeviceObject
== FFSGlobal
->DeviceObject
)
1036 CompleteRequest
= TRUE
;
1037 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1041 Vcb
= (PFFS_VCB
)DeviceObject
->DeviceExtension
;
1043 ASSERT(Vcb
!= NULL
);
1045 ASSERT((Vcb
->Identifier
.Type
== FFSVCB
) &&
1046 (Vcb
->Identifier
.Size
== sizeof(FFS_VCB
)));
1048 ASSERT(IsMounted(Vcb
));
1050 FileObject
= IrpContext
->FileObject
;
1052 Fcb
= (PFFS_FCB
)FileObject
->FsContext
;
1056 if (Fcb
->Identifier
.Type
== FFSVCB
)
1059 CompleteRequest
= TRUE
;
1060 Status
= STATUS_INVALID_PARAMETER
;
1064 ASSERT((Fcb
->Identifier
.Type
== FFSFCB
) &&
1065 (Fcb
->Identifier
.Size
== sizeof(FFS_FCB
)));
1067 if (!IsDirectory(Fcb
))
1070 CompleteRequest
= TRUE
;
1071 Status
= STATUS_INVALID_PARAMETER
;
1075 if (ExAcquireResourceExclusiveLite(
1079 bFcbAcquired
= TRUE
;
1083 Status
= STATUS_PENDING
;
1087 Irp
= IrpContext
->Irp
;
1089 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1091 #if !defined(_GNU_NTIFS_) || defined(__REACTOS__)
1094 IrpSp
->Parameters
.NotifyDirectory
.CompletionFilter
;
1096 #else // _GNU_NTIFS_
1098 CompletionFilter
= ((PEXTENDED_IO_STACK_LOCATION
)
1099 IrpSp
)->Parameters
.NotifyDirectory
.CompletionFilter
;
1101 #endif // _GNU_NTIFS_
1103 WatchTree
= IsFlagOn(IrpSp
->Flags
, SL_WATCH_TREE
);
1105 if (FlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
))
1107 Status
= STATUS_DELETE_PENDING
;
1111 FullName
= &Fcb
->LongName
;
1113 if (FullName
->Buffer
== NULL
)
1115 if (!FFSGetFullFileName(Fcb
->FFSMcb
, FullName
))
1117 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1122 FsRtlNotifyFullChangeDirectory(Vcb
->NotifySync
,
1124 FileObject
->FsContext2
,
1133 CompleteRequest
= FALSE
;
1135 Status
= STATUS_PENDING
;
1138 Currently the driver is read-only but here is an example on how to use the
1139 FsRtl-functions to report a change:
1141 ANSI_STRING TestString;
1142 USHORT FileNamePartLength;
1144 RtlInitAnsiString(&TestString, "\\ntifs.h");
1146 FileNamePartLength = 7;
1148 FsRtlNotifyReportChange(
1149 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
1150 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
1151 &TestString, // PSTRING FullTargetName
1152 &FileNamePartLength, // PUSHORT FileNamePartLength
1153 FILE_NOTIFY_CHANGE_NAME // ULONG FilterMatch
1158 ANSI_STRING TestString;
1160 RtlInitAnsiString(&TestString, "\\ntifs.h");
1162 FsRtlNotifyFullReportChange(
1163 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
1164 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
1165 &TestString, // PSTRING FullTargetName
1166 1, // USHORT TargetNameOffset
1167 NULL, // PSTRING StreamName OPTIONAL
1168 NULL, // PSTRING NormalizedParentName OPTIONAL
1169 FILE_NOTIFY_CHANGE_NAME, // ULONG FilterMatch
1171 NULL // PVOID TargetContext
1180 ExReleaseResourceForThreadLite(
1182 ExGetCurrentResourceThread());
1185 if (!IrpContext
->ExceptionInProgress
)
1187 if (!CompleteRequest
)
1189 IrpContext
->Irp
= NULL
;
1192 FFSCompleteIrpContext(IrpContext
, Status
);
1201 FFSNotifyReportChange(
1202 IN PFFS_IRP_CONTEXT IrpContext
,
1208 PUNICODE_STRING FullName
;
1211 FullName
= &Fcb
->LongName
;
1213 // ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
1215 if (FullName
->Buffer
== NULL
)
1217 if (!FFSGetFullFileName(Fcb
->FFSMcb
, FullName
))
1219 /*Status = STATUS_INSUFFICIENT_RESOURCES;*/
1224 Offset
= (USHORT
)(FullName
->Length
-
1225 Fcb
->FFSMcb
->ShortName
.Length
);
1227 FsRtlNotifyFullReportChange(Vcb
->NotifySync
,
1229 (PSTRING
)(FullName
),
1237 // ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
1241 __drv_mustHoldCriticalRegion
1243 FFSDirectoryControl(
1244 IN PFFS_IRP_CONTEXT IrpContext
)
1252 ASSERT((IrpContext
->Identifier
.Type
== FFSICX
) &&
1253 (IrpContext
->Identifier
.Size
== sizeof(FFS_IRP_CONTEXT
)));
1255 switch (IrpContext
->MinorFunction
)
1257 case IRP_MN_QUERY_DIRECTORY
:
1258 Status
= FFSQueryDirectory(IrpContext
);
1261 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
1262 Status
= FFSNotifyChangeDirectory(IrpContext
);
1266 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1267 FFSCompleteIrpContext(IrpContext
, Status
);
1275 FFSIsDirectoryEmpty(
1279 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1281 PFFS_DIR_ENTRY pTarget
= NULL
;
1286 BOOLEAN bRet
= TRUE
;
1290 if (!IsFlagOn(Dcb
->FFSMcb
->FileAttr
, FILE_ATTRIBUTE_DIRECTORY
))
1295 pTarget
= (PFFS_DIR_ENTRY
)ExAllocatePoolWithTag(PagedPool
,
1296 FFS_DIR_REC_LEN(FFS_NAME_LEN
), FFS_POOL_TAG
);
1299 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1306 while ((LONGLONG
)dwBytes
< Dcb
->Header
.AllocationSize
.QuadPart
)
1308 RtlZeroMemory(pTarget
, FFS_DIR_REC_LEN(FFS_NAME_LEN
));
1310 if (FS_VERSION
== 1)
1312 Status
= FFSv1ReadInode(
1318 FFS_DIR_REC_LEN(FFS_NAME_LEN
),
1323 Status
= FFSv2ReadInode(
1329 FFS_DIR_REC_LEN(FFS_NAME_LEN
),
1333 if (!NT_SUCCESS(Status
))
1335 FFSPrint((DBG_ERROR
, "FFSRemoveEntry: Reading Directory Content error.\n"));
1341 if (pTarget
->d_namlen
== 1 && pTarget
->d_name
[0] == '.')
1344 else if (pTarget
->d_namlen
== 2 && pTarget
->d_name
[0] == '.' &&
1345 pTarget
->d_name
[1] == '.')
1359 dwBytes
+= pTarget
->d_reclen
;
1365 if (pTarget
!= NULL
)
1367 ExFreePool(pTarget
);