2 * COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
3 * PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
6 * PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén.
11 /* INCLUDES *****************************************************************/
15 /* GLOBALS ***************************************************************/
17 extern PRFSD_GLOBAL RfsdGlobal
;
19 /* DEFINITIONS *************************************************************/
22 RfsdDirectoryCallback(
26 typedef struct _RFSD_CALLBACK_CONTEXT
{
31 PRFSD_KEY_IN_MEMORY pDirectoryKey
;
32 ULONG idxStartingDentry
; // The dentry at which the callback should beging triggering output to the Buffer
33 ULONG idxCurrentDentry
; // The current dentry (relative to entire set of dentrys, across all spans)
35 // These parameters are forwarded to ProcessDirectoryEntry
36 FILE_INFORMATION_CLASS FileInformationClass
; // [s]
38 ULONG BufferLength
; // [s]
39 BOOLEAN ReturnSingleEntry
; // [s]
44 } RFSD_CALLBACK_CONTEXT
, *PRFSD_CALLBACK_CONTEXT
;
47 #pragma alloc_text(PAGE, RfsdGetInfoLength)
48 #pragma alloc_text(PAGE, RfsdProcessDirEntry)
49 #pragma alloc_text(PAGE, RfsdQueryDirectory)
50 #pragma alloc_text(PAGE, RfsdNotifyChangeDirectory)
51 #pragma alloc_text(PAGE, RfsdDirectoryControl)
52 #pragma alloc_text(PAGE, RfsdIsDirectoryEmpty)
53 #pragma alloc_text(PAGE, RfsdDirectoryCallback)
57 RfsdGetInfoLength(IN FILE_INFORMATION_CLASS FileInformationClass
)
61 switch (FileInformationClass
) {
63 case FileDirectoryInformation
:
64 return sizeof(FILE_DIRECTORY_INFORMATION
);
67 case FileFullDirectoryInformation
:
68 return sizeof(FILE_FULL_DIR_INFORMATION
);
71 case FileBothDirectoryInformation
:
72 return sizeof(FILE_BOTH_DIR_INFORMATION
);
75 case FileNamesInformation
:
76 return sizeof(FILE_NAMES_INFORMATION
);
86 ULONG
// Returns 0 on error, or InfoLength + NameLength (the amount of the buffer used for the entry given)
89 IN FILE_INFORMATION_CLASS FileInformationClass
, // Identifier indicating the type of file information this function should report
90 IN __u32 Key_ParentDirectoryID
,
91 IN __u32 Key_ObjectID
,
92 IN PVOID Buffer
, // The user's buffer, as obtained from the IRP context (it is already gauranteed to be valid)
93 IN ULONG UsedLength
, // Length of Buffer used so far
94 IN ULONG Length
, // Length of Buffer remaining, beyond UsedLength
95 IN ULONG FileIndex
, // Byte offset of the dentry?? (This will just be placed into the file info structure of the same name)
96 IN PUNICODE_STRING pName
, // Filled unicode equivalent of the name (as pulled out from the dentry)
97 IN BOOLEAN Single
, // Whether or not QueryDirectory is only supposed to return a single entry
98 IN PVOID pPreviousEntry
) // A pointer to the previous dir entry in Buffer, which will be linked into the newly added entry if one is created
101 PFILE_DIRECTORY_INFORMATION FDI
;
102 PFILE_FULL_DIR_INFORMATION FFI
;
103 PFILE_BOTH_DIR_INFORMATION FBI
;
104 PFILE_NAMES_INFORMATION FNI
;
106 ULONG InfoLength
= 0;
107 ULONG NameLength
= 0;
110 LONGLONG AllocationSize
;
114 // Calculate the size of the entry
115 NameLength
= pName
->Length
;
116 InfoLength
= RfsdGetInfoLength(FileInformationClass
);
118 if (!InfoLength
|| InfoLength
+ NameLength
- sizeof(WCHAR
) > Length
) {
119 RfsdPrint((DBG_INFO
, "RfsdPricessDirEntry: Buffer is not enough.\n"));
123 // Given the incoming key for this dentry, load the corresponding stat data.
125 RFSD_KEY_IN_MEMORY key
;
126 key
.k_dir_id
= Key_ParentDirectoryID
;
127 key
.k_objectid
= Key_ObjectID
;
129 if(!RfsdLoadInode(Vcb
, &key
, &inode
)) {
130 RfsdPrint((DBG_ERROR
, "RfsdPricessDirEntry: Loading stat data %xh, %xh error.\n", Key_ParentDirectoryID
, Key_ObjectID
));
136 FileSize
= (LONGLONG
) inode
.i_size
;
137 AllocationSize
= CEILING_ALIGNED(FileSize
, (ULONGLONG
)Vcb
->BlockSize
); // TODO: THIS ISN'T QUITE RIGHT
139 // Link the previous entry into this entry
140 if (pPreviousEntry
) {
141 // NOTE: All entries begin with NextEntryOffset, so it doesn't matter what type I cast to.
142 ((PFILE_NAMES_INFORMATION
) (pPreviousEntry
))->NextEntryOffset
=
143 (ULONG
) ((PUCHAR
) Buffer
+ UsedLength
- (PUCHAR
) (pPreviousEntry
));
146 switch(FileInformationClass
) {
148 case FileDirectoryInformation
:
149 FDI
= (PFILE_DIRECTORY_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
150 FDI
->NextEntryOffset
= 0;
152 FDI
->FileIndex
= FileIndex
;
153 FDI
->CreationTime
= RfsdSysTime(inode
.i_ctime
);
154 FDI
->LastAccessTime
= RfsdSysTime(inode
.i_atime
);
155 FDI
->LastWriteTime
= RfsdSysTime(inode
.i_mtime
);
156 FDI
->ChangeTime
= RfsdSysTime(inode
.i_mtime
);
157 FDI
->EndOfFile
.QuadPart
= FileSize
;
158 FDI
->AllocationSize
.QuadPart
= AllocationSize
;
159 FDI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
161 if (FlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || RfsdIsReadOnly(inode
.i_mode
)) {
162 SetFlag(FDI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
165 if (S_ISDIR(inode
.i_mode
))
166 FDI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
168 FDI
->FileNameLength
= NameLength
;
169 RtlCopyMemory(FDI
->FileName
, pName
->Buffer
, NameLength
);
170 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
173 case FileFullDirectoryInformation
:
175 FFI
= (PFILE_FULL_DIR_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
176 FFI
->NextEntryOffset
= 0;
178 FFI
->FileIndex
= FileIndex
;
179 FFI
->CreationTime
= RfsdSysTime(inode
.i_ctime
);
180 FFI
->LastAccessTime
= RfsdSysTime(inode
.i_atime
);
181 FFI
->LastWriteTime
= RfsdSysTime(inode
.i_mtime
);
182 FFI
->ChangeTime
= RfsdSysTime(inode
.i_mtime
);
183 FFI
->EndOfFile
.QuadPart
= FileSize
;
184 FFI
->AllocationSize
.QuadPart
= AllocationSize
;
185 FFI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
187 if (IsFlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || RfsdIsReadOnly(inode
.i_mode
)) {
188 SetFlag(FFI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
191 if (S_ISDIR(inode
.i_mode
))
192 FFI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
194 FFI
->FileNameLength
= NameLength
;
195 RtlCopyMemory(FFI
->FileName
, pName
->Buffer
, NameLength
);
196 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
200 case FileBothDirectoryInformation
:
202 FBI
= (PFILE_BOTH_DIR_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
203 FBI
->NextEntryOffset
= 0;
205 FBI
->CreationTime
= RfsdSysTime(inode
.i_ctime
);
206 FBI
->LastAccessTime
= RfsdSysTime(inode
.i_atime
);
207 FBI
->LastWriteTime
= RfsdSysTime(inode
.i_mtime
);
208 FBI
->ChangeTime
= RfsdSysTime(inode
.i_mtime
);
210 FBI
->FileIndex
= FileIndex
;
211 FBI
->EndOfFile
.QuadPart
= FileSize
;
212 FBI
->AllocationSize
.QuadPart
= AllocationSize
;
213 FBI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
215 if (FlagOn(Vcb
->Flags
, VCB_READ_ONLY
) || RfsdIsReadOnly(inode
.i_mode
)) {
216 SetFlag(FBI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
);
219 if (S_ISDIR(inode
.i_mode
))
220 FBI
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
222 FBI
->FileNameLength
= NameLength
;
223 RtlCopyMemory(FBI
->FileName
, pName
->Buffer
, NameLength
);
224 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
228 case FileNamesInformation
:
230 FNI
= (PFILE_NAMES_INFORMATION
) ((PUCHAR
)Buffer
+ UsedLength
);
231 FNI
->NextEntryOffset
= 0;
233 FNI
->FileNameLength
= NameLength
;
234 RtlCopyMemory(FNI
->FileName
, pName
->Buffer
, NameLength
);
235 dwBytes
= InfoLength
+ NameLength
- sizeof(WCHAR
);
247 caller suplies a ptr to a file obj for an open target dir, a search pattern to use when listing, and a spec of the info requested.
248 FSD expected to search and return matching info [503]
250 The Fcb->RfsdMcb->Key will determine which directory to list the contents of.
252 __drv_mustHoldCriticalRegion
254 RfsdQueryDirectory (IN PRFSD_IRP_CONTEXT IrpContext
)
256 PDEVICE_OBJECT DeviceObject
;
257 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
259 PFILE_OBJECT FileObject
;
263 PIO_STACK_LOCATION IoStackLocation
;
264 FILE_INFORMATION_CLASS FileInformationClass
;
266 PUNICODE_STRING FileName
;
269 BOOLEAN ReturnSingleEntry
;
270 BOOLEAN IndexSpecified
;
273 PRFSD_KEY_IN_MEMORY pQueryKey
; // The key of the directory item that is being retrieved
274 BOOLEAN FcbResourceAcquired
= FALSE
;
275 ULONG UsedLength
= 0;
283 ASSERT((IrpContext
->Identifier
.Type
== RFSDICX
) &&
284 (IrpContext
->Identifier
.Size
== sizeof(RFSD_IRP_CONTEXT
)));
286 DeviceObject
= IrpContext
->DeviceObject
;
289 // This request is not allowed on the main device object
291 if (DeviceObject
== RfsdGlobal
->DeviceObject
) {
292 Status
= STATUS_INVALID_DEVICE_REQUEST
;
296 Vcb
= (PRFSD_VCB
) DeviceObject
->DeviceExtension
;
300 ASSERT((Vcb
->Identifier
.Type
== RFSDVCB
) &&
301 (Vcb
->Identifier
.Size
== sizeof(RFSD_VCB
)));
303 ASSERT(IsMounted(Vcb
));
305 FileObject
= IrpContext
->FileObject
;
307 Fcb
= (PRFSD_FCB
) FileObject
->FsContext
;
308 pQueryKey
= &(Fcb
->RfsdMcb
->Key
);
312 KdPrint(("QueryDirectory on Key {%x,%x,%x,%x}\n",
313 pQueryKey
->k_dir_id
, pQueryKey
->k_objectid
, pQueryKey
->k_offset
, pQueryKey
->k_type
));
316 // This request is not allowed on volumes
318 if (Fcb
->Identifier
.Type
== RFSDVCB
) {
319 Status
= STATUS_INVALID_PARAMETER
;
323 ASSERT((Fcb
->Identifier
.Type
== RFSDFCB
) &&
324 (Fcb
->Identifier
.Size
== sizeof(RFSD_FCB
)));
326 if (!IsDirectory(Fcb
)) {
327 Status
= STATUS_INVALID_PARAMETER
;
331 Ccb
= (PRFSD_CCB
) FileObject
->FsContext2
;
335 ASSERT((Ccb
->Identifier
.Type
== RFSDCCB
) &&
336 (Ccb
->Identifier
.Size
== sizeof(RFSD_CCB
)));
338 Irp
= IrpContext
->Irp
;
340 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
344 FileInformationClass
=
345 IoStackLocation
->Parameters
.QueryDirectory
.FileInformationClass
;
347 Length
= IoStackLocation
->Parameters
.QueryDirectory
.Length
;
349 FileName
= IoStackLocation
->Parameters
.QueryDirectory
.FileName
;
351 FileIndex
= IoStackLocation
->Parameters
.QueryDirectory
.FileIndex
;
353 RestartScan
= FlagOn(IoStackLocation
->Flags
, SL_RESTART_SCAN
);
355 ReturnSingleEntry
= FlagOn(IoStackLocation
->Flags
, SL_RETURN_SINGLE_ENTRY
);
357 IndexSpecified
= FlagOn(IoStackLocation
->Flags
, SL_INDEX_SPECIFIED
);
361 FileInformationClass
= ((PEXTENDED_IO_STACK_LOCATION
)
362 IoStackLocation
)->Parameters
.QueryDirectory
.FileInformationClass
;
364 Length
= ((PEXTENDED_IO_STACK_LOCATION
)
365 IoStackLocation
)->Parameters
.QueryDirectory
.Length
;
367 FileName
= ((PEXTENDED_IO_STACK_LOCATION
)
368 IoStackLocation
)->Parameters
.QueryDirectory
.FileName
;
370 FileIndex
= ((PEXTENDED_IO_STACK_LOCATION
)
371 IoStackLocation
)->Parameters
.QueryDirectory
.FileIndex
;
373 RestartScan
= FlagOn(((PEXTENDED_IO_STACK_LOCATION
)
374 IoStackLocation
)->Flags
, SL_RESTART_SCAN
);
376 ReturnSingleEntry
= FlagOn(((PEXTENDED_IO_STACK_LOCATION
)
377 IoStackLocation
)->Flags
, SL_RETURN_SINGLE_ENTRY
);
379 IndexSpecified
= FlagOn(((PEXTENDED_IO_STACK_LOCATION
)
380 IoStackLocation
)->Flags
, SL_INDEX_SPECIFIED
);
382 #endif // _GNU_NTIFS_
385 if (!Irp->MdlAddress && Irp->UserBuffer) {
386 ProbeForWrite(Irp->UserBuffer, Length, 1);
390 // Check that the user's buffer for the output is valid..
391 Buffer
= RfsdGetUserBuffer(Irp
);
393 if (Buffer
== NULL
) {
395 Status
= STATUS_INVALID_USER_BUFFER
;
399 // Check if we have a synchronous or asynchronous request...
400 if (!IrpContext
->IsSynchronous
) {
401 Status
= STATUS_PENDING
;
405 if (!ExAcquireResourceSharedLite(
407 IrpContext
->IsSynchronous
)) {
408 Status
= STATUS_PENDING
;
412 FcbResourceAcquired
= TRUE
;
414 if (FileName
!= NULL
) {
415 // The caller provided a FileName to search on...
417 if (Ccb
->DirectorySearchPattern
.Buffer
!= NULL
) {
422 // Set up the DirectorySearchPattern to simply be an uppercase copy of the FileName.
423 Ccb
->DirectorySearchPattern
.Length
=
424 Ccb
->DirectorySearchPattern
.MaximumLength
=
427 Ccb
->DirectorySearchPattern
.Buffer
=
428 ExAllocatePoolWithTag(PagedPool
, FileName
->Length
, RFSD_POOL_TAG
);
430 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
) {
431 Status
= STATUS_INSUFFICIENT_RESOURCES
;
435 Status
= RtlUpcaseUnicodeString(
436 &(Ccb
->DirectorySearchPattern
),
440 if (!NT_SUCCESS(Status
))
443 } else if (Ccb
->DirectorySearchPattern
.Buffer
!= NULL
) {
445 FileName
= &Ccb
->DirectorySearchPattern
;
447 // (The FileName and CCB's DirectorySearchPattern were null)
451 Ccb
->DirectorySearchPattern
.Length
=
452 Ccb
->DirectorySearchPattern
.MaximumLength
= 2;
454 Ccb
->DirectorySearchPattern
.Buffer
=
455 ExAllocatePoolWithTag(PagedPool
, 2, RFSD_POOL_TAG
);
457 if (Ccb
->DirectorySearchPattern
.Buffer
== NULL
) {
458 Status
= STATUS_INSUFFICIENT_RESOURCES
;
463 Ccb
->DirectorySearchPattern
.Buffer
,
467 if (!IndexSpecified
) {
468 if (RestartScan
|| FirstQuery
) {
469 FileIndex
= Fcb
->RfsdMcb
->DeOffset
= 0;
471 // If we are not starting/restaring a scan, then we must have already started.
472 // Retrieve the byte offset (in the directory . file) where we left off.
473 FileIndex
= Ccb
->CurrentByteOffset
;
478 RtlZeroMemory(Buffer
, Length
);
480 // Leave if a previous query has already read the entire contents of the directory
481 if (Fcb
->Inode
->i_size
<= FileIndex
) {
482 Status
= STATUS_NO_MORE_FILES
;
488 // Construct a context for the call, and call to parse the entire file system tree.
489 // A callback will be triggered on any direntry span belonging to DirectoryKey.
490 // This callback will fill the requested section of the user buffer.
492 ULONG CurrentFileIndex
;
494 RFSD_CALLBACK_CONTEXT CallbackContext
;
495 CallbackContext
.Vcb
= Vcb
;
496 CallbackContext
.Ccb
= Ccb
;
497 CallbackContext
.idxStartingDentry
= FileIndex
/ sizeof(RFSD_DENTRY_HEAD
);
498 CallbackContext
.idxCurrentDentry
= 0;
499 CallbackContext
.pDirectoryKey
= pQueryKey
;
500 CallbackContext
.FileInformationClass
= FileInformationClass
;
501 CallbackContext
.Buffer
= Buffer
;
502 CallbackContext
.BufferLength
= Length
;
503 CallbackContext
.ReturnSingleEntry
= ReturnSingleEntry
;
504 CallbackContext
.pUsedLength
= &UsedLength
;
505 CallbackContext
.pPreviousEntry
= NULL
;
507 RfsdPrint((DBG_TRACE
, "Calculated idxCurrentDentry to be %i\n", CallbackContext
.idxStartingDentry
));
509 RfsdParseFilesystemTree(Vcb
, pQueryKey
, Vcb
->SuperBlock
->s_root_block
, &RfsdDirectoryCallback
, &CallbackContext
);
512 //================================================================
515 // No amount of the dsetination buffer has been used (meaning there were no results)...
517 Status
= STATUS_NO_SUCH_FILE
;
519 Status
= STATUS_NO_MORE_FILES
;
522 Status
= STATUS_SUCCESS
;
527 if (FcbResourceAcquired
) {
528 ExReleaseResourceForThreadLite(
530 ExGetCurrentResourceThread() );
533 if (!IrpContext
->ExceptionInProgress
) {
534 if (Status
== STATUS_PENDING
) {
535 Status
= RfsdLockUserBuffer(
540 if (NT_SUCCESS(Status
)) {
541 Status
= RfsdQueueRequest(IrpContext
);
543 RfsdCompleteIrpContext(IrpContext
, Status
);
546 IrpContext
->Irp
->IoStatus
.Information
= UsedLength
;
547 RfsdCompleteIrpContext(IrpContext
, Status
);
555 __drv_mustHoldCriticalRegion
557 RfsdNotifyChangeDirectory (
558 IN PRFSD_IRP_CONTEXT IrpContext
561 PDEVICE_OBJECT DeviceObject
;
562 BOOLEAN CompleteRequest
;
563 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
565 PFILE_OBJECT FileObject
;
568 PIO_STACK_LOCATION IrpSp
;
569 ULONG CompletionFilter
;
571 BOOLEAN bFcbAcquired
= FALSE
;
572 PUNICODE_STRING FullName
;
580 ASSERT((IrpContext
->Identifier
.Type
== RFSDICX
) &&
581 (IrpContext
->Identifier
.Size
== sizeof(RFSD_IRP_CONTEXT
)));
584 // Always set the wait flag in the Irp context for the original request.
587 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
);
589 DeviceObject
= IrpContext
->DeviceObject
;
591 if (DeviceObject
== RfsdGlobal
->DeviceObject
) {
592 CompleteRequest
= TRUE
;
593 Status
= STATUS_INVALID_DEVICE_REQUEST
;
597 Vcb
= (PRFSD_VCB
) DeviceObject
->DeviceExtension
;
601 ASSERT((Vcb
->Identifier
.Type
== RFSDVCB
) &&
602 (Vcb
->Identifier
.Size
== sizeof(RFSD_VCB
)));
604 ASSERT(IsMounted(Vcb
));
606 FileObject
= IrpContext
->FileObject
;
608 Fcb
= (PRFSD_FCB
) FileObject
->FsContext
;
612 if (Fcb
->Identifier
.Type
== RFSDVCB
) {
614 CompleteRequest
= TRUE
;
615 Status
= STATUS_INVALID_PARAMETER
;
619 ASSERT((Fcb
->Identifier
.Type
== RFSDFCB
) &&
620 (Fcb
->Identifier
.Size
== sizeof(RFSD_FCB
)));
622 if (!IsDirectory(Fcb
)) {
623 //- DbgBreak(); // NOTE: Windows (at least I've noticed it with the image previewer), will send this request oftentimes on a file!
624 CompleteRequest
= TRUE
;
625 Status
= STATUS_INVALID_PARAMETER
;
629 if (ExAcquireResourceExclusiveLite(
634 Status
= STATUS_PENDING
;
638 Irp
= IrpContext
->Irp
;
640 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
645 IrpSp
->Parameters
.NotifyDirectory
.CompletionFilter
;
649 CompletionFilter
= ((PEXTENDED_IO_STACK_LOCATION
)
650 IrpSp
)->Parameters
.NotifyDirectory
.CompletionFilter
;
652 #endif // _GNU_NTIFS_
654 WatchTree
= IsFlagOn(IrpSp
->Flags
, SL_WATCH_TREE
);
656 if (FlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
)) {
657 Status
= STATUS_DELETE_PENDING
;
661 FullName
= &Fcb
->LongName
;
663 if (FullName
->Buffer
== NULL
) {
664 if (!RfsdGetFullFileName(Fcb
->RfsdMcb
, FullName
)) {
665 Status
= STATUS_INSUFFICIENT_RESOURCES
;
670 FsRtlNotifyFullChangeDirectory( Vcb
->NotifySync
,
672 FileObject
->FsContext2
,
681 CompleteRequest
= FALSE
;
683 Status
= STATUS_PENDING
;
686 Currently the driver is read-only but here is an example on how to use the
687 FsRtl-functions to report a change:
689 ANSI_STRING TestString;
690 USHORT FileNamePartLength;
692 RtlInitAnsiString(&TestString, "\\ntifs.h");
694 FileNamePartLength = 7;
696 FsRtlNotifyReportChange(
697 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
698 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
699 &TestString, // PSTRING FullTargetName
700 &FileNamePartLength, // PUSHORT FileNamePartLength
701 FILE_NOTIFY_CHANGE_NAME // ULONG FilterMatch
706 ANSI_STRING TestString;
708 RtlInitAnsiString(&TestString, "\\ntifs.h");
710 FsRtlNotifyFullReportChange(
711 Vcb->NotifySync, // PNOTIFY_SYNC NotifySync
712 &Vcb->NotifyList, // PLIST_ENTRY NotifyList
713 &TestString, // PSTRING FullTargetName
714 1, // USHORT TargetNameOffset
715 NULL, // PSTRING StreamName OPTIONAL
716 NULL, // PSTRING NormalizedParentName OPTIONAL
717 FILE_NOTIFY_CHANGE_NAME, // ULONG FilterMatch
719 NULL // PVOID TargetContext
726 ExReleaseResourceForThreadLite(
728 ExGetCurrentResourceThread());
731 if (!IrpContext
->ExceptionInProgress
) {
733 if (!CompleteRequest
) {
734 IrpContext
->Irp
= NULL
;
737 RfsdCompleteIrpContext(IrpContext
, Status
);
745 RfsdNotifyReportChange (
746 IN PRFSD_IRP_CONTEXT IrpContext
,
752 PUNICODE_STRING FullName
;
755 FullName
= &Fcb
->LongName
;
757 // ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
759 if (FullName
->Buffer
== NULL
) {
760 if (!RfsdGetFullFileName(Fcb
->RfsdMcb
, FullName
)) {
761 /*Status = STATUS_INSUFFICIENT_RESOURCES;*/
766 Offset
= (USHORT
) ( FullName
->Length
-
767 Fcb
->RfsdMcb
->ShortName
.Length
);
769 FsRtlNotifyFullReportChange( Vcb
->NotifySync
,
771 (PSTRING
) (FullName
),
779 // ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
782 __drv_mustHoldCriticalRegion
784 RfsdDirectoryControl (IN PRFSD_IRP_CONTEXT IrpContext
)
792 ASSERT((IrpContext
->Identifier
.Type
== RFSDICX
) &&
793 (IrpContext
->Identifier
.Size
== sizeof(RFSD_IRP_CONTEXT
)));
795 switch (IrpContext
->MinorFunction
) {
797 case IRP_MN_QUERY_DIRECTORY
:
798 Status
= RfsdQueryDirectory(IrpContext
);
801 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
802 Status
= RfsdNotifyChangeDirectory(IrpContext
);
806 Status
= STATUS_INVALID_DEVICE_REQUEST
;
807 RfsdCompleteIrpContext(IrpContext
, Status
);
815 BOOLEAN
RfsdIsDirectoryEmpty (
819 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
821 //PRFSD_DIR_ENTRY2 pTarget = NULL;
826 BOOLEAN bRet
= FALSE
;
830 if (!IsFlagOn(Dcb
->RfsdMcb
->FileAttr
, FILE_ATTRIBUTE_DIRECTORY
)) {
836 pTarget
= (PRFSD_DIR_ENTRY2
) ExAllocatePoolWithTag(PagedPool
,
837 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
), RFSD_POOL_TAG
);
839 Status
= STATUS_INSUFFICIENT_RESOURCES
;
847 while ((LONGLONG
)dwBytes
< Dcb
->Header
.AllocationSize
.QuadPart
) {
849 RtlZeroMemory(pTarget
, RFSD_DIR_REC_LEN(RFSD_NAME_LEN
));
851 Status
= RfsdReadInode(
854 &(Dcb
->RfsdMcb
->Key
),
858 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
),
861 if (!NT_SUCCESS(Status
)) {
862 RfsdPrint((DBG_ERROR
, "RfsdRemoveEntry: Reading Directory Content error.\n"));
867 if (pTarget
->inode
) {
868 if (pTarget
->name_len
== 1 && pTarget
->name
[0] == '.') {
869 } else if (pTarget
->name_len
== 2 && pTarget
->name
[0] == '.' &&
870 pTarget
->name
[1] == '.') {
879 dwBytes
+= pTarget
->rec_len
;
884 if (pTarget
!= NULL
) {
892 #endif // !RFSD_READ_ONLY
895 This callback is triggered when the FS tree parser hits a leaf node that may contain a directory item.
896 The function then reads each dentry in the item, and is reponsible for sending them into to ProcessDirEntry.
897 The callback is doing work on behalf of QueryDir -- the context given is from there.
899 // NOTE: This signature has to be changed here, at the top decleration, and in the RFSD_CALLBACK macro definition
901 RfsdDirectoryCallback(
905 PRFSD_CALLBACK_CONTEXT pCallbackContext
= (PRFSD_CALLBACK_CONTEXT
) pContext
;
906 RFSD_KEY_IN_MEMORY DirectoryKey
;
907 PUCHAR pBlockBuffer
= NULL
;
908 PRFSD_ITEM_HEAD pDirectoryItemHeader
= NULL
;
909 PUCHAR pDirectoryItemBuffer
= NULL
;
911 UNICODE_STRING InodeFileName
;
915 InodeFileName
.Buffer
= NULL
;
917 RfsdPrint((DBG_FUNC
, /*__FUNCTION__*/ " invoked on block %i\n", BlockNumber
));
921 pBlockBuffer
= RfsdAllocateAndLoadBlock(pCallbackContext
->Vcb
, BlockNumber
);
922 if (!pBlockBuffer
) { Status
= STATUS_INSUFFICIENT_RESOURCES
; goto out
; }
924 // Construct the item key to search for
925 DirectoryKey
= *(pCallbackContext
->pDirectoryKey
);
926 DirectoryKey
.k_type
= RFSD_KEY_TYPE_v2_DIRENTRY
;
928 // Get the item header and its information
929 Status
= RfsdFindItemHeaderInBlock(
930 pCallbackContext
->Vcb
, &DirectoryKey
, pBlockBuffer
,
931 ( &pDirectoryItemHeader
), //<
932 &CompareKeysWithoutOffset
935 // If this block doesn't happen to contain a directory item, skip it.
936 if ( (Status
== STATUS_NO_SUCH_MEMBER
) || !pDirectoryItemHeader
)
938 KdPrint(("Block %i did not contain the appropriate diritem header\n", BlockNumber
));
939 Status
= STATUS_SUCCESS
; goto out
;
942 RfsdPrint((DBG_INFO
, "Found %i dentries in block\n", pDirectoryItemHeader
->u
.ih_entry_count
));
944 // Calculate if the requested result will be from this dentry span
945 // If the end of this span is not greater than the requested start, it can be skipped.
946 if ( !( (pCallbackContext
->idxCurrentDentry
+ (USHORT
)(pDirectoryItemHeader
->u
.ih_entry_count
)) > pCallbackContext
->idxStartingDentry
) )
948 RfsdPrint((DBG_TRACE
, "SKIPPING block\n"));
950 pCallbackContext
->idxCurrentDentry
+= pDirectoryItemHeader
->u
.ih_entry_count
;
951 Status
= STATUS_SUCCESS
;
957 // Otherwise, Read out each dentry, and call ProcessDirEntry on it.
960 PRFSD_DENTRY_HEAD pPrevDentry
= NULL
;
961 ULONG offsetDentry_toSequentialSpan
; // The byte offset of this dentry, relative to the dentry spans, as though only their DENTRY_HEADs were stitched together sequentially
963 // Skip ahead to the starting dentry in this span.
964 ULONG idxDentryInSpan
= pCallbackContext
->idxStartingDentry
- pCallbackContext
->idxCurrentDentry
;
965 pCallbackContext
->idxCurrentDentry
+= idxDentryInSpan
;
967 RfsdPrint((DBG_TRACE
, "Sarting dentry: %i. skipped to %i dentry in span\n", pCallbackContext
->idxStartingDentry
, idxDentryInSpan
));
969 offsetDentry_toSequentialSpan
= pCallbackContext
->idxCurrentDentry
* sizeof(RFSD_DENTRY_HEAD
);
971 // Setup the item buffer
972 pDirectoryItemBuffer
= (PUCHAR
) pBlockBuffer
+ pDirectoryItemHeader
->ih_item_location
;
976 && ( *(pCallbackContext
->pUsedLength
) < (pCallbackContext
->BufferLength
) )
977 && (idxDentryInSpan
< (pDirectoryItemHeader
->u
.ih_entry_count
)) )
980 STRING OemName
; // FUTURE: does this support codepages?
981 PRFSD_DENTRY_HEAD pCurrentDentry
;
982 USHORT InodeFileNameLength
= 0;
984 // Read a directory entry from the buffered directory item (from the file associated with the filled inode)
985 pCurrentDentry
= (PRFSD_DENTRY_HEAD
) (pDirectoryItemBuffer
+ (idxDentryInSpan
* sizeof(RFSD_DENTRY_HEAD
) ));
987 // Skip the directory entry for the parent of the root directory (because it should not be shown, and has no stat data)
988 // (NOTE: Any change made here should also be mirrored in RfsdScanDirCallback)
989 if (pCurrentDentry
->deh_dir_id
== 0 /*&& pCurrentDentry->deh_objectid == 1*/)
990 { goto ProcessNextEntry
; }
992 // Pull the name of the file out from the buffer.
993 // NOTE: The filename is not gauranteed to be null-terminated, and so the end may implicitly be the start of the previous entry.
994 OemName
.Buffer
= (PUCHAR
) pDirectoryItemBuffer
+ pCurrentDentry
->deh_location
;
995 OemName
.MaximumLength
= (pPrevDentry
? pPrevDentry
->deh_location
: // The end of this entry is the start of the previous
996 pDirectoryItemHeader
->ih_item_len
// Otherwise this is the first entry, the end of which is the end of the item.
997 ) - pCurrentDentry
->deh_location
;
998 if (!pPrevDentry
&& pCallbackContext
->idxStartingDentry
> 1 && pCallbackContext
->Ccb
->deh_location
)
1000 if (OemName
.MaximumLength
!= pCallbackContext
->Ccb
->deh_location
- pCurrentDentry
->deh_location
)
1002 //KdPrint(("Changed MaximumLength from %d to %d for {%.*s}\n", OemName.MaximumLength, pCallbackContext->Ccb->deh_location - pCurrentDentry->deh_location, RfsdStringLength(OemName.Buffer, pCallbackContext->Ccb->deh_location - pCurrentDentry->deh_location), OemName.Buffer));
1004 OemName
.MaximumLength
= pCallbackContext
->Ccb
->deh_location
- pCurrentDentry
->deh_location
;
1006 OemName
.Length
= RfsdStringLength(OemName
.Buffer
, OemName
.MaximumLength
);
1009 // Calculate the name's unicode length, allocate memory, and convert the codepaged name to unicode
1010 InodeFileNameLength
= (USHORT
) RfsdOEMToUnicodeSize(&OemName
);
1011 InodeFileName
.Length
= 0;
1012 InodeFileName
.MaximumLength
= InodeFileNameLength
+ 2;
1014 if (InodeFileNameLength
<= 0)
1017 InodeFileName
.Buffer
= ExAllocatePoolWithTag(
1019 InodeFileNameLength
+ 2, RFSD_POOL_TAG
);
1021 if (!InodeFileName
.Buffer
) {
1022 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1026 RtlZeroMemory(InodeFileName
.Buffer
, InodeFileNameLength
+ 2);
1028 Status
= RfsdOEMToUnicode( &InodeFileName
, &OemName
);
1029 if (!NT_SUCCESS(Status
)) { Status
= STATUS_INTERNAL_ERROR
; goto out
; } // TODO: CHECK IF TIHS OK
1031 ////////////// END OF MY PART
1032 if (FsRtlDoesNameContainWildCards(
1033 &(pCallbackContext
->Ccb
->DirectorySearchPattern
)) ?
1034 FsRtlIsNameInExpression(
1035 &(pCallbackContext
->Ccb
->DirectorySearchPattern
),
1039 !RtlCompareUnicodeString(
1040 &(pCallbackContext
->Ccb
->DirectorySearchPattern
),
1043 // The name either contains wild cards, or matches the directory search pattern...
1046 ULONG dwBytesWritten
;
1047 dwBytesWritten
= RfsdProcessDirEntry(
1048 pCallbackContext
->Vcb
, pCallbackContext
->FileInformationClass
,
1049 pCurrentDentry
->deh_dir_id
,
1050 pCurrentDentry
->deh_objectid
,
1051 pCallbackContext
->Buffer
,
1052 *(pCallbackContext
->pUsedLength
),
1053 pCallbackContext
->BufferLength
- *(pCallbackContext
->pUsedLength
), // The remaining length in the user's buffer
1054 offsetDentry_toSequentialSpan
,
1056 pCallbackContext
->ReturnSingleEntry
,
1057 pCallbackContext
->pPreviousEntry
);
1059 if (dwBytesWritten
<= 0) {
1060 Status
= STATUS_EVENT_DONE
;
1062 pCallbackContext
->Ccb
->deh_location
= pPrevDentry
? pPrevDentry
->deh_location
: 0;
1064 pCallbackContext
->Ccb
->deh_location
= 0;
1065 pCallbackContext
->pPreviousEntry
= (PUCHAR
) (pCallbackContext
->Buffer
) + *(pCallbackContext
->pUsedLength
);
1066 *(pCallbackContext
->pUsedLength
) += dwBytesWritten
;
1071 if (InodeFileName
.Buffer
) {
1072 ExFreePool(InodeFileName
.Buffer
);
1073 InodeFileName
.Buffer
= NULL
;
1079 pPrevDentry
= pCurrentDentry
;
1084 ++(pCallbackContext
->idxCurrentDentry
);
1085 ++(pCallbackContext
->idxStartingDentry
);
1086 offsetDentry_toSequentialSpan
+= sizeof(RFSD_DENTRY_HEAD
);
1088 // Store the current position, so that it will be available for the next call
1089 pCallbackContext
->Ccb
->CurrentByteOffset
= offsetDentry_toSequentialSpan
;
1093 if ( ( *(pCallbackContext
->pUsedLength
) > 0) && pCallbackContext
->ReturnSingleEntry
) {
1094 Status
= STATUS_EVENT_DONE
;
1103 if (pBlockBuffer
) ExFreePool(pBlockBuffer
);
1104 if (InodeFileName
.Buffer
) ExFreePool(InodeFileName
.Buffer
);