1 /*************************************************************************
5 * Module: Ext2 File System Driver (Kernel mode execution only)
8 * Contains code to handle the "directory control" dispatch entry point.
10 * Author: Manoj Paul Joseph
13 *************************************************************************/
17 // define the file specific bug-check id
18 #define EXT2_BUG_CHECK_ID EXT2_FILE_DIR_CONTROL
20 #define DEBUG_LEVEL (DEBUG_TRACE_DIRCTRL)
23 /*************************************************************************
25 * Function: Ext2DirControl()
28 * The I/O Manager will invoke this routine to handle a directory control
31 * Expected Interrupt Level (for execution) :
33 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
34 * to be deferred to a worker thread context)
36 * Return Value: STATUS_SUCCESS/Error
38 *************************************************************************/
39 NTSTATUS
Ext2DirControl(
40 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
41 PIRP Irp
) // I/O Request Packet
43 NTSTATUS RC
= STATUS_SUCCESS
;
44 PtrExt2IrpContext PtrIrpContext
= NULL
;
45 BOOLEAN AreWeTopLevel
= FALSE
;
47 DebugTrace(DEBUG_TRACE_IRP_ENTRY
, "DIR Control IRP received...", 0);
50 FsRtlEnterFileSystem();
55 // set the top level context
56 AreWeTopLevel
= Ext2IsIrpTopLevel(Irp
);
60 // get an IRP context structure and issue the request
61 PtrIrpContext
= Ext2AllocateIrpContext(Irp
, DeviceObject
);
62 ASSERT(PtrIrpContext
);
64 RC
= Ext2CommonDirControl(PtrIrpContext
, Irp
);
67 except (Ext2ExceptionFilter(PtrIrpContext
, GetExceptionInformation()))
70 RC
= Ext2ExceptionHandler(PtrIrpContext
, Irp
);
72 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR
, RC
);
76 IoSetTopLevelIrp(NULL
);
79 FsRtlExitFileSystem();
86 /*************************************************************************
88 * Function: Ext2CommonDirControl()
91 * The actual work is performed here. This routine may be invoked in one'
92 * of the two possible contexts:
93 * (a) in the context of a system worker thread
94 * (b) in the context of the original caller
96 * Expected Interrupt Level (for execution) :
100 * Return Value: STATUS_SUCCESS/Error
102 *************************************************************************/
103 NTSTATUS
Ext2CommonDirControl(
104 PtrExt2IrpContext PtrIrpContext
,
107 NTSTATUS RC
= STATUS_SUCCESS
;
108 PIO_STACK_LOCATION PtrIoStackLocation
= NULL
;
109 PFILE_OBJECT PtrFileObject
= NULL
;
110 PtrExt2FCB PtrFCB
= NULL
;
111 PtrExt2CCB PtrCCB
= NULL
;
112 PtrExt2VCB PtrVCB
= NULL
;
114 // First, get a pointer to the current I/O stack location
115 PtrIoStackLocation
= IoGetCurrentIrpStackLocation(PtrIrp
);
116 ASSERT(PtrIoStackLocation
);
118 PtrFileObject
= PtrIoStackLocation
->FileObject
;
119 ASSERT(PtrFileObject
);
121 // Get the FCB and CCB pointers
122 PtrCCB
= (PtrExt2CCB
)(PtrFileObject
->FsContext2
);
124 PtrFCB
= PtrCCB
->PtrFCB
;
129 // Get some of the parameters supplied to us
130 switch (PtrIoStackLocation
->MinorFunction
) {
131 case IRP_MN_QUERY_DIRECTORY
:
133 RC
= Ext2QueryDirectory(PtrIrpContext
, PtrIrp
, (PEXTENDED_IO_STACK_LOCATION
)PtrIoStackLocation
, PtrFileObject
, PtrFCB
, PtrCCB
);
135 RC
= Ext2QueryDirectory(PtrIrpContext
, PtrIrp
, PtrIoStackLocation
, PtrFileObject
, PtrFCB
, PtrCCB
);
138 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
140 RC
= STATUS_NOT_IMPLEMENTED
;
141 PtrIrp
->IoStatus
.Status
= RC
;
142 PtrIrp
->IoStatus
.Information
= 0;
143 IoCompleteRequest(PtrIrp
, IO_DISK_INCREMENT
);
145 // RC = Ext2NotifyChangeDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
148 // This should not happen.
149 RC
= STATUS_INVALID_DEVICE_REQUEST
;
150 PtrIrp
->IoStatus
.Status
= RC
;
151 PtrIrp
->IoStatus
.Information
= 0;
153 // Free up the Irp Context
154 Ext2ReleaseIrpContext(PtrIrpContext
);
157 IoCompleteRequest(PtrIrp
, IO_NO_INCREMENT
);
165 /*************************************************************************
167 * Function: Ext2QueryDirectory()
170 * Query directory request.
172 * Expected Interrupt Level (for execution) :
176 * Return Value: STATUS_SUCCESS/Error
178 *************************************************************************/
179 NTSTATUS
Ext2QueryDirectory(
180 PtrExt2IrpContext PtrIrpContext
,
183 PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation
,
185 PIO_STACK_LOCATION PtrIoStackLocation
,
187 PFILE_OBJECT PtrFileObject
,
191 NTSTATUS RC
= STATUS_SUCCESS
;
192 BOOLEAN CompleteRequest
= TRUE
;
193 BOOLEAN PostRequest
= FALSE
;
194 PtrExt2NTRequiredFCB PtrReqdFCB
= NULL
;
195 BOOLEAN CanWait
= FALSE
;
196 PtrExt2VCB PtrVCB
= NULL
;
197 BOOLEAN AcquiredFCB
= FALSE
;
198 unsigned long BufferLength
= 0;
199 unsigned long BufferIndex
= 0;
200 unsigned long FileIndex
= 0;
201 PUNICODE_STRING PtrSearchPattern
= NULL
;
202 FILE_INFORMATION_CLASS FileInformationClass
;
203 BOOLEAN RestartScan
= FALSE
;
204 BOOLEAN ReturnSingleEntry
= FALSE
;
205 BOOLEAN IndexSpecified
= FALSE
;
206 unsigned char *Buffer
= NULL
;
207 BOOLEAN FirstTimeQuery
= FALSE
;
208 unsigned long StartingIndexForSearch
= 0;
209 unsigned long BytesReturned
= 0;
210 BOOLEAN BufferUsedup
= FALSE
;
212 BOOLEAN SearchWithWildCards
= FALSE
;
214 PFILE_BOTH_DIR_INFORMATION BothDirInformation
= NULL
;
215 PFILE_FULL_DIR_INFORMATION FullDirInformation
= NULL
;
216 PFILE_DIRECTORY_INFORMATION DirectoryInformation
= NULL
;
217 PFILE_NAMES_INFORMATION NamesInformation
= NULL
;
220 PEXT2_DIR_ENTRY PtrDirEntry
= NULL
;
221 PEXT2_INODE PtrInode
= NULL
;
223 unsigned long LogicalBlockSize
;
225 unsigned long ThisBlock
;
227 // The starting Physical Block No...
228 //LARGE_INTEGER StartPhysicalBlock;
229 LARGE_INTEGER StartBufferOffset
;
230 ULONG PinBufferLength
;
232 // Buffer Control Block
234 BYTE
* PtrPinnedBlockBuffer
= NULL
;
238 DebugTrace(DEBUG_TRACE_MISC
, " === Querying Directory %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
242 // Validate the sent-in FCB
243 if ((PtrFCB
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
) || !(PtrFCB
->FCBFlags
& EXT2_FCB_DIRECTORY
))
245 // We will only allow notify requests on directories.
246 RC
= STATUS_INVALID_PARAMETER
;
249 PtrReqdFCB
= &(PtrFCB
->NTRequiredFCB
);
250 CanWait
= ((PtrIrpContext
->IrpContextFlags
& EXT2_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
);
251 PtrVCB
= PtrFCB
->PtrVCB
;
254 // Asynchronous IO requested
255 // Posting request...
258 * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL
259 * requests aren't handled in the worker thread yet. I tried
260 * adding handling of them to the worked routine, but there
261 * were problems with accessing the PtrIoStackLocation->
262 * Parameters.QueryDirectory.FileName variable.
263 * -- Filip Navara, 18/08/2004
269 try_return(RC
= STATUS_PENDING
);
273 // Obtain the callers parameters
274 BufferLength
= PtrIoStackLocation
->Parameters
.QueryDirectory
.Length
;
275 PtrSearchPattern
= ( PUNICODE_STRING
) PtrIoStackLocation
->Parameters
.QueryDirectory
.FileName
;
276 FileInformationClass
= PtrIoStackLocation
->Parameters
.QueryDirectory
.FileInformationClass
;
277 FileIndex
= PtrIoStackLocation
->Parameters
.QueryDirectory
.FileIndex
;
279 // Some additional arguments that affect the FSD behavior
280 RestartScan
= (PtrIoStackLocation
->Flags
& SL_RESTART_SCAN
);
281 ReturnSingleEntry
= (PtrIoStackLocation
->Flags
& SL_RETURN_SINGLE_ENTRY
);
282 IndexSpecified
= (PtrIoStackLocation
->Flags
& SL_INDEX_SPECIFIED
);
285 // Acquiring exclusive access to the FCB.
286 // This is not mandatory
288 DebugTrace(DEBUG_TRACE_MISC
, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0);
290 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB
->MainResource
.ActiveCount
, PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
291 ExAcquireResourceExclusiveLite(&(PtrReqdFCB
->MainResource
), TRUE
);
293 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB acquired [DirCtrl]", 0);
296 // We must determine the buffer pointer to be used. Since this
297 // routine could either be invoked directly in the context of the
298 // calling thread, or in the context of a worker thread, here is
299 // a general way of determining what we should use.
300 Buffer
= Ext2GetCallersBuffer ( PtrIrp
);
302 // The method of determining where to look from and what to look for is
303 // unfortunately extremely confusing. However, here is a methodology you
304 // you can broadly adopt:
305 // (a) You have to maintain a search buffer per CCB structure.
306 // (b) This search buffer is initialized the very first time
307 // a query directory operation is performed using the file object.
308 // (For the sample FSD, the search buffer is stored in the
309 // DirectorySearchPattern field)
310 // However, the caller still has the option of "overriding" this stored
311 // search pattern by supplying a new one in a query directory operation.
314 if( PtrCCB
->DirectorySearchPattern
.Length
)
316 if( PtrCCB
->DirectorySearchPattern
.Buffer
[PtrCCB
->DirectorySearchPattern
.Length
/2] != 0 )
318 DebugTrace(DEBUG_TRACE_MISC
, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0);
320 DebugTrace(DEBUG_TRACE_MISC
, " === Old Search pattern %S", PtrCCB
->DirectorySearchPattern
.Buffer
);
323 if (PtrSearchPattern
!= NULL
)
325 // User has supplied a search pattern
326 // Now validate that the search pattern is legitimate
328 if ( PtrCCB
->DirectorySearchPattern
.Length
== 0 )
330 // This must be the very first query request.
331 FirstTimeQuery
= TRUE
;
335 // We should ignore the search pattern in the CCB and instead,
336 // use the user-supplied pattern for this particular query
337 // directory request.
338 Ext2DeallocateUnicodeString( &PtrCCB
->DirectorySearchPattern
);
341 // Now, allocate enough memory to contain the caller
342 // supplied search pattern and fill in the DirectorySearchPattern
344 Ext2CopyUnicodeString( &PtrCCB
->DirectorySearchPattern
, PtrSearchPattern
);
346 PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) );
347 ASSERT(PtrCCB->DirectorySearchPattern);
348 RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) );
351 else if ( PtrCCB
->DirectorySearchPattern
.Length
== 0 )
353 // This MUST be the first directory query operation (else the
354 // DirectorySearchPattern field would never be empty. Also, the caller
355 // has neglected to provide a pattern so we MUST invent one.
356 // Use "*" (following NT conventions) as your search pattern
357 // and store it in the PtrCCB->DirectorySearchPattern field.
360 PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") );
361 ASSERT(PtrCCB->DirectorySearchPattern);
362 RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/
364 Ext2CopyWideCharToUnicodeString( &PtrCCB
->DirectorySearchPattern
, L
"*" );
366 FirstTimeQuery
= TRUE
;
370 // The caller has not supplied any search pattern...
371 // Using previously supplied pattern
372 PtrSearchPattern
= &PtrCCB
->DirectorySearchPattern
;
375 if( PtrCCB
->DirectorySearchPattern
.Buffer
[PtrCCB
->DirectorySearchPattern
.Length
/2] != 0 )
377 DebugTrace(DEBUG_TRACE_MISC
, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 );
379 DebugTrace(DEBUG_TRACE_MISC
, " === Search pattern %S", PtrCCB
->DirectorySearchPattern
.Buffer
);
380 SearchWithWildCards
= FsRtlDoesNameContainWildCards( PtrSearchPattern
);
382 // There is one other piece of information that your FSD must store
383 // in the CCB structure for query directory support. This is the index
384 // value (i.e. the offset in your on-disk directory structure) from
385 // which you should start searching.
386 // However, the flags supplied with the IRP can make us override this
391 // Caller has told us wherefrom to begin.
392 // You may need to round this to an appropriate directory entry
393 // entry alignment value.
394 StartingIndexForSearch
= FileIndex
;
396 else if (RestartScan
)
398 StartingIndexForSearch
= 0;
402 // Get the starting offset from the CCB.
403 StartingIndexForSearch
= PtrCCB
->CurrentByteOffset
.LowPart
;
406 // Read in the file inode if it hasn't already been read...
407 Ext2InitializeFCBInodeInfo( PtrFCB
);
409 if (PtrFileObject
->PrivateCacheMap
== NULL
)
411 CcInitializeCacheMap(PtrFileObject
, (PCC_FILE_SIZES
)(&(PtrReqdFCB
->CommonFCBHeader
.AllocationSize
)),
412 TRUE
, // We will utilize pin access for directories
413 &(Ext2GlobalData
.CacheMgrCallBacks
), // callbacks
414 PtrCCB
); // The context used in callbacks
419 // Read in the next Data Block of this directory
421 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
422 StartBufferOffset
.QuadPart
= ( StartingIndexForSearch
/ LogicalBlockSize
);
423 StartBufferOffset
.QuadPart
*= LogicalBlockSize
; // This should be the StartBufferOffset alaigned to LBlock boundary...
425 PinBufferLength
= PtrReqdFCB
->CommonFCBHeader
.FileSize
.LowPart
- StartBufferOffset
.LowPart
;
427 if ( !CcMapData( PtrFileObject
,
432 (PVOID
*)&PtrPinnedBlockBuffer
) )
435 DebugTrace(DEBUG_TRACE_MISC
, "Cache read failiure while reading in volume meta data", 0);
436 try_return( STATUS_ACCESS_DENIED
);
440 DebugTrace(DEBUG_TRACE_MISC
, "Cache hit while reading in volume meta data", 0);
443 PtrInode
= Ext2AllocatePool( PagedPool
, sizeof( EXT2_INODE
) );
446 // Walking through the directory entries...
447 for( BufferUsedup
= FALSE
, BufferIndex
= 0; !BufferUsedup
&& StartingIndexForSearch
< ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ; )
449 PtrDirEntry
= (PEXT2_DIR_ENTRY
) &PtrPinnedBlockBuffer
[ StartingIndexForSearch
- StartBufferOffset
.LowPart
];
451 StartingIndexForSearch
+= PtrDirEntry
->rec_len
;
452 PtrCCB
->CurrentByteOffset
.LowPart
= StartingIndexForSearch
;
454 if( PtrDirEntry
->inode
== 0 )
458 if( PtrDirEntry
->name_len
== 0 || PtrDirEntry
->rec_len
== 0 )
461 // This should not happen
462 // Hqw can this be so!!!
465 if( BothDirInformation
)
467 BothDirInformation
->NextEntryOffset
= 0;
472 RC
= STATUS_NO_SUCH_FILE
;
474 RC
= STATUS_NO_MORE_FILES
;
479 // Does this entry match the search criterian?
483 UNICODE_STRING FileName
;
485 // Constructing a counted Unicode string out of PtrDirEntry
486 Ext2CopyCharToUnicodeString( &FileName
, PtrDirEntry
->name
, PtrDirEntry
->name_len
);
488 if ( SearchWithWildCards
)
490 Matched
= FsRtlIsNameInExpression ( PtrSearchPattern
, &FileName
, FALSE
, NULL
);
494 Matched
= ! RtlCompareUnicodeString( PtrSearchPattern
, &FileName
, FALSE
);
497 Ext2DeallocateUnicodeString( &FileName
);
504 switch( FileInformationClass
)
506 case FileBothDirectoryInformation
:
508 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileBothDirectoryInformation", 0 );
509 ThisBlock
= sizeof( FILE_BOTH_DIR_INFORMATION
);
510 ThisBlock
+= PtrDirEntry
->name_len
*2;
511 ThisBlock
= Ext2QuadAlign( ThisBlock
);
513 if( ( BufferIndex
+ ThisBlock
) > BufferLength
)
516 // Next entry won't fit into the buffer...
517 // will have to return...
520 if( BothDirInformation
)
521 BothDirInformation
->NextEntryOffset
= 0;
523 RC
= STATUS_NO_MORE_FILES
;
528 Ext2ReadInode( PtrVCB
, PtrDirEntry
->inode
, PtrInode
);
531 try_return( RC
= STATUS_UNSUCCESSFUL
);
534 BothDirInformation
= ( PFILE_BOTH_DIR_INFORMATION
) ( Buffer
+ ( BufferIndex
) );
535 BothDirInformation
->EaSize
= 0;
536 BothDirInformation
->AllocationSize
.QuadPart
= PtrInode
->i_blocks
* 512;
537 BothDirInformation
->EndOfFile
.QuadPart
= PtrInode
->i_size
;
538 BothDirInformation
->ChangeTime
.QuadPart
= 0;
540 BothDirInformation
->CreationTime
.QuadPart
= ( __int64
) PtrInode
->i_ctime
* 10000000;
541 BothDirInformation
->CreationTime
.QuadPart
+= Ext2GlobalData
.TimeDiff
.QuadPart
;
543 BothDirInformation
->LastAccessTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
) PtrInode
->i_atime
* 10000000 );
544 BothDirInformation
->LastWriteTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
)PtrInode
->i_mtime
* 10000000 );
546 // Getting the file type...
547 BothDirInformation
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
548 if( ! Ext2IsModeRegularFile( PtrInode
->i_mode
) )
550 // Not a reqular file...
551 if( Ext2IsModeDirectory( PtrInode
->i_mode
) )
554 BothDirInformation
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
559 // Treated with respect... ;)
561 BothDirInformation
->FileAttributes
|= ( FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_READONLY
);
562 // FILE_ATTRIBUTE_DEVICE
564 if ( Ext2IsModeHidden( PtrInode
->i_mode
) )
566 BothDirInformation
->FileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
569 if ( Ext2IsModeReadOnly( PtrInode
->i_mode
) )
571 BothDirInformation
->FileAttributes
|= FILE_ATTRIBUTE_READONLY
;
575 BothDirInformation
->FileIndex
= StartingIndexForSearch
;
576 BothDirInformation
->FileNameLength
= PtrDirEntry
->name_len
*2 + 2;
577 BothDirInformation
->ShortNameLength
= 0;
578 BothDirInformation
->ShortName
[0] = 0;
580 // Copying out the name as WCHAR null terminated strings
581 for( j
= 0; j
< PtrDirEntry
->name_len
; j
++ )
583 // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j];
584 BothDirInformation
->FileName
[ j
] = PtrDirEntry
->name
[j
];
586 // BothDirInformation->ShortName[j] = PtrDirEntry->name[j];;
592 BothDirInformation->ShortNameLength = j * 2 + 2;
593 BothDirInformation->ShortName[ j ] = 0;
597 BothDirInformation->ShortNameLength = 24;
598 BothDirInformation->ShortName[ 11 ] = 0;
601 BothDirInformation
->FileName
[ j
] = 0;
602 BytesReturned
+= ThisBlock
;
603 BufferIndex
+= ThisBlock
;
605 if( !ReturnSingleEntry
&& ( StartingIndexForSearch
< ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ))
606 BothDirInformation
->NextEntryOffset
= ThisBlock
;
608 BothDirInformation
->NextEntryOffset
= 0;
611 case FileDirectoryInformation
:
612 // DirectoryInformation
613 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileDirectoryInformation", 0 );
614 ThisBlock
= sizeof( FILE_DIRECTORY_INFORMATION
);
615 ThisBlock
+= PtrDirEntry
->name_len
*2;
616 ThisBlock
= Ext2QuadAlign( ThisBlock
);
618 if( ( BufferIndex
+ ThisBlock
) > BufferLength
)
621 // Next entry won't fit into the buffer...
622 // will have to return...
625 if( DirectoryInformation
)
626 DirectoryInformation
->NextEntryOffset
= 0;
628 RC
= STATUS_NO_MORE_FILES
;
633 Ext2ReadInode( PtrVCB
, PtrDirEntry
->inode
, PtrInode
);
636 try_return( RC
= STATUS_UNSUCCESSFUL
);
639 DirectoryInformation
= ( PFILE_DIRECTORY_INFORMATION
) ( Buffer
+ ( BufferIndex
) );
640 DirectoryInformation
->AllocationSize
.QuadPart
= PtrInode
->i_blocks
* 512;
641 DirectoryInformation
->EndOfFile
.QuadPart
= PtrInode
->i_size
;
642 DirectoryInformation
->ChangeTime
.QuadPart
= 0;
644 DirectoryInformation
->CreationTime
.QuadPart
= ( __int64
) PtrInode
->i_ctime
* 10000000;
645 DirectoryInformation
->CreationTime
.QuadPart
+= Ext2GlobalData
.TimeDiff
.QuadPart
;
647 DirectoryInformation
->LastAccessTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
) PtrInode
->i_atime
* 10000000 );
648 DirectoryInformation
->LastWriteTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
)PtrInode
->i_mtime
* 10000000 );
650 // Getting the file type...
651 DirectoryInformation
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
652 if( ! Ext2IsModeRegularFile( PtrInode
->i_mode
) )
654 // Not a reqular file...
655 if( Ext2IsModeDirectory( PtrInode
->i_mode
) )
658 DirectoryInformation
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
663 // Treated with respect... ;)
665 DirectoryInformation
->FileAttributes
|= ( FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_READONLY
);
666 // FILE_ATTRIBUTE_DEVICE
668 if ( Ext2IsModeHidden( PtrInode
->i_mode
) )
670 DirectoryInformation
->FileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
673 if ( Ext2IsModeReadOnly( PtrInode
->i_mode
) )
675 DirectoryInformation
->FileAttributes
|= FILE_ATTRIBUTE_READONLY
;
679 DirectoryInformation
->FileIndex
= StartingIndexForSearch
;
680 DirectoryInformation
->FileNameLength
= PtrDirEntry
->name_len
*2 + 2;
682 // Copying out the name as WCHAR null terminated strings
683 for( j
= 0; j
< PtrDirEntry
->name_len
; j
++ )
685 DirectoryInformation
->FileName
[ j
] = PtrDirEntry
->name
[j
];
688 DirectoryInformation
->FileName
[ j
] = 0;
689 BytesReturned
+= ThisBlock
;
690 BufferIndex
+= ThisBlock
;
692 if( !ReturnSingleEntry
&& ( StartingIndexForSearch
< ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ))
693 DirectoryInformation
->NextEntryOffset
= ThisBlock
;
695 DirectoryInformation
->NextEntryOffset
= 0;
698 case FileFullDirectoryInformation
:
699 // FullDirInformation->
700 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileFullDirectoryInformation - Not handled", 0 );
702 case FileNamesInformation
:
703 // NamesInformation->
704 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileNamesInformation - Not handled", 0 );
707 DebugTrace(DEBUG_TRACE_DIRINFO
, " === Invalid Dir Info class - Not handled", 0 );
708 try_return( RC
= STATUS_INVALID_INFO_CLASS
);
710 if( ReturnSingleEntry
)
718 if( !BytesReturned
&& StartingIndexForSearch
>= ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
) )
720 Ext2DeallocateUnicodeString( &PtrCCB
->DirectorySearchPattern
);
721 PtrCCB
->CurrentByteOffset
.QuadPart
= 0;
723 RC
= STATUS_NO_SUCH_FILE
;
725 RC
= STATUS_NO_MORE_FILES
;
728 else if( BytesReturned
)
730 BothDirInformation
->NextEntryOffset
= 0;
740 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [DirCtrl]", PtrInode
);
741 ExFreePool( PtrInode
);
746 CcUnpinData( PtrBCB
);
754 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
755 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Released in [DirCtrl]", 0);
756 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
757 PtrReqdFCB
->MainResource
.ActiveCount
,
758 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
759 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
762 // Map the users buffer and then post the request.
763 RC
= Ext2LockCallersBuffer(PtrIrp
, TRUE
, BufferLength
);
764 ASSERT(NT_SUCCESS(RC
));
766 RC
= Ext2PostRequest(PtrIrpContext
, PtrIrp
);
769 else if (!(PtrIrpContext
->IrpContextFlags
&
770 EXT2_IRP_CONTEXT_EXCEPTION
))
774 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
775 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Released [DirCtrl]", 0);
776 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
777 PtrReqdFCB
->MainResource
.ActiveCount
,
778 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
779 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
782 // Complete the request.
783 PtrIrp
->IoStatus
.Status
= RC
;
784 PtrIrp
->IoStatus
.Information
= BytesReturned
;
786 // Free up the Irp Context
787 Ext2ReleaseIrpContext(PtrIrpContext
);
790 IoCompleteRequest(PtrIrp
, IO_DISK_INCREMENT
);
793 // Flush the saved BCBs...
794 // Ext2FlushSavedBCBs ( PtrIrpContext );
803 /*************************************************************************
805 * Function: Ext2NotifyChangeDirectory()
808 * Handle the notify request.
810 * Expected Interrupt Level (for execution) :
814 * Return Value: STATUS_SUCCESS/Error
816 *************************************************************************/
817 NTSTATUS
Ext2NotifyChangeDirectory(
818 PtrExt2IrpContext PtrIrpContext
,
821 PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation
,
823 PIO_STACK_LOCATION PtrIoStackLocation
,
825 PFILE_OBJECT PtrFileObject
,
829 NTSTATUS RC
= STATUS_SUCCESS
;
830 BOOLEAN CompleteRequest
= FALSE
;
831 BOOLEAN PostRequest
= FALSE
;
832 PtrExt2NTRequiredFCB PtrReqdFCB
= NULL
;
833 BOOLEAN CanWait
= FALSE
;
834 ULONG CompletionFilter
= 0;
835 BOOLEAN WatchTree
= FALSE
;
836 PtrExt2VCB PtrVCB
= NULL
;
837 BOOLEAN AcquiredFCB
= FALSE
;
841 // Validate the sent-in FCB
842 if ((PtrFCB
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
) || !(PtrFCB
->FCBFlags
& EXT2_FCB_DIRECTORY
)) {
843 // We will only allow notify requests on directories.
844 RC
= STATUS_INVALID_PARAMETER
;
845 CompleteRequest
= TRUE
;
848 PtrReqdFCB
= &(PtrFCB
->NTRequiredFCB
);
849 CanWait
= ((PtrIrpContext
->IrpContextFlags
& EXT2_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
);
850 PtrVCB
= PtrFCB
->PtrVCB
;
852 // Acquire the FCB resource shared
853 DebugTrace(DEBUG_TRACE_MISC
, "*** Attempting to acquire FCB Shared[DirCtrl]", 0);
854 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB
->MainResource
.ActiveCount
, PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
855 if (!ExAcquireResourceSharedLite(&(PtrReqdFCB
->MainResource
), CanWait
))
857 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Acquisition FAILED [DirCtrl]", 0);
859 try_return(RC
= STATUS_PENDING
);
862 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB acquired [DirCtrl]", 0);
864 // Obtain some parameters sent by the caller
865 CompletionFilter
= PtrIoStackLocation
->Parameters
.NotifyDirectory
.CompletionFilter
;
866 WatchTree
= (PtrIoStackLocation
->Flags
& SL_WATCH_TREE
? TRUE
: FALSE
);
868 // If you wish to capture the subject context, you can do so as
871 // PSECURITY_SUBJECT_CONTEXT SubjectContext;
872 // SubjectContext = Ext2AllocatePool(PagedPool,
873 // sizeof(SECURITY_SUBJECT_CONTEXT) );
874 // SeCaptureSubjectContext(SubjectContext);
877 FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC
)&(PtrVCB
->NotifyIRPMutex
), &(PtrVCB
->NextNotifyIRP
), (void *)PtrCCB
,
878 (PSTRING
)(PtrFCB
->FCBName
->ObjectName
.Buffer
), WatchTree
, FALSE
, CompletionFilter
, PtrIrp
,
879 NULL
, // Ext2TraverseAccessCheck(...) ?
880 NULL
); // SubjectContext ?
892 // Perform appropriate post related processing here
895 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
896 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Released in DirCtrl", 0);
897 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
898 PtrReqdFCB
->MainResource
.ActiveCount
,
899 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
900 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
904 RC
= Ext2PostRequest(PtrIrpContext
, PtrIrp
);
906 else if (CompleteRequest
)
908 PtrIrp
->IoStatus
.Status
= RC
;
909 PtrIrp
->IoStatus
.Information
= 0;
911 // Free up the Irp Context
912 Ext2ReleaseIrpContext(PtrIrpContext
);
915 IoCompleteRequest(PtrIrp
, IO_DISK_INCREMENT
);
917 // Simply free up the IrpContext since the IRP has been queued
918 Ext2ReleaseIrpContext(PtrIrpContext
);
921 // Release the FCB resources if acquired.
924 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
925 DebugTrace(DEBUG_TRACE_MISC
, "*** FReleased in [DirCtrl]", 0);
926 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
927 PtrReqdFCB
->MainResource
.ActiveCount
,
928 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
929 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);