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 NTAPI
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 NTAPI
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
;
113 // First, get a pointer to the current I/O stack location
114 PtrIoStackLocation
= IoGetCurrentIrpStackLocation(PtrIrp
);
115 ASSERT(PtrIoStackLocation
);
117 PtrFileObject
= PtrIoStackLocation
->FileObject
;
118 ASSERT(PtrFileObject
);
120 // Get the FCB and CCB pointers
121 PtrCCB
= (PtrExt2CCB
)(PtrFileObject
->FsContext2
);
123 PtrFCB
= PtrCCB
->PtrFCB
;
128 // Get some of the parameters supplied to us
129 switch (PtrIoStackLocation
->MinorFunction
) {
130 case IRP_MN_QUERY_DIRECTORY
:
132 RC
= Ext2QueryDirectory(PtrIrpContext
, PtrIrp
, (PEXTENDED_IO_STACK_LOCATION
)PtrIoStackLocation
, PtrFileObject
, PtrFCB
, PtrCCB
);
134 RC
= Ext2QueryDirectory(PtrIrpContext
, PtrIrp
, PtrIoStackLocation
, PtrFileObject
, PtrFCB
, PtrCCB
);
137 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
139 RC
= STATUS_NOT_IMPLEMENTED
;
140 PtrIrp
->IoStatus
.Status
= RC
;
141 PtrIrp
->IoStatus
.Information
= 0;
142 IoCompleteRequest(PtrIrp
, IO_DISK_INCREMENT
);
144 // RC = Ext2NotifyChangeDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
147 // This should not happen.
148 RC
= STATUS_INVALID_DEVICE_REQUEST
;
149 PtrIrp
->IoStatus
.Status
= RC
;
150 PtrIrp
->IoStatus
.Information
= 0;
152 // Free up the Irp Context
153 Ext2ReleaseIrpContext(PtrIrpContext
);
156 IoCompleteRequest(PtrIrp
, IO_NO_INCREMENT
);
164 /*************************************************************************
166 * Function: Ext2QueryDirectory()
169 * Query directory request.
171 * Expected Interrupt Level (for execution) :
175 * Return Value: STATUS_SUCCESS/Error
177 *************************************************************************/
178 NTSTATUS NTAPI
Ext2QueryDirectory(
179 PtrExt2IrpContext PtrIrpContext
,
182 PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation
,
184 PIO_STACK_LOCATION PtrIoStackLocation
,
186 PFILE_OBJECT PtrFileObject
,
190 NTSTATUS RC
= STATUS_SUCCESS
;
191 BOOLEAN PostRequest
= FALSE
;
192 PtrExt2NTRequiredFCB PtrReqdFCB
= NULL
;
193 BOOLEAN CanWait
= FALSE
;
194 PtrExt2VCB PtrVCB
= NULL
;
195 BOOLEAN AcquiredFCB
= FALSE
;
196 unsigned long BufferLength
= 0;
197 unsigned long BufferIndex
= 0;
198 unsigned long FileIndex
= 0;
199 PUNICODE_STRING PtrSearchPattern
= NULL
;
200 FILE_INFORMATION_CLASS FileInformationClass
;
201 BOOLEAN RestartScan
= FALSE
;
202 BOOLEAN ReturnSingleEntry
= FALSE
;
203 BOOLEAN IndexSpecified
= FALSE
;
204 unsigned char *Buffer
= NULL
;
205 BOOLEAN FirstTimeQuery
= FALSE
;
206 unsigned long StartingIndexForSearch
= 0;
207 unsigned long BytesReturned
= 0;
208 BOOLEAN BufferUsedup
= FALSE
;
210 BOOLEAN SearchWithWildCards
= FALSE
;
212 PFILE_BOTH_DIR_INFORMATION BothDirInformation
= NULL
;
213 PFILE_DIRECTORY_INFORMATION DirectoryInformation
= NULL
;
216 PEXT2_DIR_ENTRY PtrDirEntry
= NULL
;
217 PEXT2_INODE PtrInode
= NULL
;
219 unsigned long LogicalBlockSize
;
221 unsigned long ThisBlock
;
223 // The starting Physical Block No...
224 //LARGE_INTEGER StartPhysicalBlock;
225 LARGE_INTEGER StartBufferOffset
;
226 ULONG PinBufferLength
;
228 // Buffer Control Block
230 BYTE
* PtrPinnedBlockBuffer
= NULL
;
234 DebugTrace(DEBUG_TRACE_MISC
, " === Querying Directory %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
238 // Validate the sent-in FCB
239 if ((PtrFCB
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
) || !(PtrFCB
->FCBFlags
& EXT2_FCB_DIRECTORY
))
241 // We will only allow notify requests on directories.
242 RC
= STATUS_INVALID_PARAMETER
;
245 PtrReqdFCB
= &(PtrFCB
->NTRequiredFCB
);
246 CanWait
= ((PtrIrpContext
->IrpContextFlags
& EXT2_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
);
247 PtrVCB
= PtrFCB
->PtrVCB
;
250 // Asynchronous IO requested
251 // Posting request...
254 * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL
255 * requests aren't handled in the worker thread yet. I tried
256 * adding handling of them to the worked routine, but there
257 * were problems with accessing the PtrIoStackLocation->
258 * Parameters.QueryDirectory.FileName variable.
259 * -- Filip Navara, 18/08/2004
265 try_return(RC
= STATUS_PENDING
);
269 // Obtain the callers parameters
270 BufferLength
= PtrIoStackLocation
->Parameters
.QueryDirectory
.Length
;
271 PtrSearchPattern
= ( PUNICODE_STRING
) PtrIoStackLocation
->Parameters
.QueryDirectory
.FileName
;
272 FileInformationClass
= PtrIoStackLocation
->Parameters
.QueryDirectory
.FileInformationClass
;
273 FileIndex
= PtrIoStackLocation
->Parameters
.QueryDirectory
.FileIndex
;
275 // Some additional arguments that affect the FSD behavior
276 RestartScan
= (PtrIoStackLocation
->Flags
& SL_RESTART_SCAN
);
277 ReturnSingleEntry
= (PtrIoStackLocation
->Flags
& SL_RETURN_SINGLE_ENTRY
);
278 IndexSpecified
= (PtrIoStackLocation
->Flags
& SL_INDEX_SPECIFIED
);
281 // Acquiring exclusive access to the FCB.
282 // This is not mandatory
284 DebugTrace(DEBUG_TRACE_MISC
, "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0);
286 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB
->MainResource
.ActiveCount
, PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
287 ExAcquireResourceExclusiveLite(&(PtrReqdFCB
->MainResource
), TRUE
);
289 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB acquired [DirCtrl]", 0);
292 // We must determine the buffer pointer to be used. Since this
293 // routine could either be invoked directly in the context of the
294 // calling thread, or in the context of a worker thread, here is
295 // a general way of determining what we should use.
296 Buffer
= Ext2GetCallersBuffer ( PtrIrp
);
298 // The method of determining where to look from and what to look for is
299 // unfortunately extremely confusing. However, here is a methodology you
300 // you can broadly adopt:
301 // (a) You have to maintain a search buffer per CCB structure.
302 // (b) This search buffer is initialized the very first time
303 // a query directory operation is performed using the file object.
304 // (For the sample FSD, the search buffer is stored in the
305 // DirectorySearchPattern field)
306 // However, the caller still has the option of "overriding" this stored
307 // search pattern by supplying a new one in a query directory operation.
310 if( PtrCCB
->DirectorySearchPattern
.Length
)
312 if( PtrCCB
->DirectorySearchPattern
.Buffer
[PtrCCB
->DirectorySearchPattern
.Length
/2] != 0 )
314 DebugTrace(DEBUG_TRACE_MISC
, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0);
316 DebugTrace(DEBUG_TRACE_MISC
, " === Old Search pattern %S", PtrCCB
->DirectorySearchPattern
.Buffer
);
319 if (PtrSearchPattern
!= NULL
)
321 // User has supplied a search pattern
322 // Now validate that the search pattern is legitimate
324 if ( PtrCCB
->DirectorySearchPattern
.Length
== 0 )
326 // This must be the very first query request.
327 FirstTimeQuery
= TRUE
;
331 // We should ignore the search pattern in the CCB and instead,
332 // use the user-supplied pattern for this particular query
333 // directory request.
334 Ext2DeallocateUnicodeString( &PtrCCB
->DirectorySearchPattern
);
337 // Now, allocate enough memory to contain the caller
338 // supplied search pattern and fill in the DirectorySearchPattern
340 Ext2CopyUnicodeString( &PtrCCB
->DirectorySearchPattern
, PtrSearchPattern
);
342 PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) );
343 ASSERT(PtrCCB->DirectorySearchPattern);
344 RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) );
347 else if ( PtrCCB
->DirectorySearchPattern
.Length
== 0 )
349 // This MUST be the first directory query operation (else the
350 // DirectorySearchPattern field would never be empty. Also, the caller
351 // has neglected to provide a pattern so we MUST invent one.
352 // Use "*" (following NT conventions) as your search pattern
353 // and store it in the PtrCCB->DirectorySearchPattern field.
356 PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") );
357 ASSERT(PtrCCB->DirectorySearchPattern);
358 RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/
360 Ext2CopyWideCharToUnicodeString( &PtrCCB
->DirectorySearchPattern
, L
"*" );
362 FirstTimeQuery
= TRUE
;
366 // The caller has not supplied any search pattern...
367 // Using previously supplied pattern
368 PtrSearchPattern
= &PtrCCB
->DirectorySearchPattern
;
371 if( PtrCCB
->DirectorySearchPattern
.Buffer
[PtrCCB
->DirectorySearchPattern
.Length
/2] != 0 )
373 DebugTrace(DEBUG_TRACE_MISC
, "&&&&&&&&& PtrCCB->DirectorySearchPattern not NULL terminated!", 0 );
375 DebugTrace(DEBUG_TRACE_MISC
, " === Search pattern %S", PtrCCB
->DirectorySearchPattern
.Buffer
);
376 SearchWithWildCards
= FsRtlDoesNameContainWildCards( PtrSearchPattern
);
378 // There is one other piece of information that your FSD must store
379 // in the CCB structure for query directory support. This is the index
380 // value (i.e. the offset in your on-disk directory structure) from
381 // which you should start searching.
382 // However, the flags supplied with the IRP can make us override this
387 // Caller has told us wherefrom to begin.
388 // You may need to round this to an appropriate directory entry
389 // entry alignment value.
390 StartingIndexForSearch
= FileIndex
;
392 else if (RestartScan
)
394 StartingIndexForSearch
= 0;
398 // Get the starting offset from the CCB.
399 StartingIndexForSearch
= PtrCCB
->CurrentByteOffset
.LowPart
;
402 // Read in the file inode if it hasn't already been read...
403 Ext2InitializeFCBInodeInfo( PtrFCB
);
405 if (PtrFileObject
->PrivateCacheMap
== NULL
)
407 CcInitializeCacheMap(PtrFileObject
, (PCC_FILE_SIZES
)(&(PtrReqdFCB
->CommonFCBHeader
.AllocationSize
)),
408 TRUE
, // We will utilize pin access for directories
409 &(Ext2GlobalData
.CacheMgrCallBacks
), // callbacks
410 PtrCCB
); // The context used in callbacks
415 // Read in the next Data Block of this directory
417 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
418 StartBufferOffset
.QuadPart
= ( StartingIndexForSearch
/ LogicalBlockSize
);
419 StartBufferOffset
.QuadPart
*= LogicalBlockSize
; // This should be the StartBufferOffset alaigned to LBlock boundary...
421 PinBufferLength
= PtrReqdFCB
->CommonFCBHeader
.FileSize
.LowPart
- StartBufferOffset
.LowPart
;
423 if ( !CcMapData( PtrFileObject
,
428 (PVOID
*)&PtrPinnedBlockBuffer
) )
431 DebugTrace(DEBUG_TRACE_MISC
, "Cache read failiure while reading in volume meta data", 0);
436 DebugTrace(DEBUG_TRACE_MISC
, "Cache hit while reading in volume meta data", 0);
439 PtrInode
= Ext2AllocatePool( PagedPool
, sizeof( EXT2_INODE
) );
442 // Walking through the directory entries...
443 for( BufferUsedup
= FALSE
, BufferIndex
= 0; !BufferUsedup
&& StartingIndexForSearch
< ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ; )
445 PtrDirEntry
= (PEXT2_DIR_ENTRY
) &PtrPinnedBlockBuffer
[ StartingIndexForSearch
- StartBufferOffset
.LowPart
];
447 StartingIndexForSearch
+= PtrDirEntry
->rec_len
;
448 PtrCCB
->CurrentByteOffset
.LowPart
= StartingIndexForSearch
;
450 if( PtrDirEntry
->inode
== 0 )
454 if( PtrDirEntry
->name_len
== 0 || PtrDirEntry
->rec_len
== 0 )
457 // This should not happen
458 // Hqw can this be so!!!
461 if( BothDirInformation
)
463 BothDirInformation
->NextEntryOffset
= 0;
468 RC
= STATUS_NO_SUCH_FILE
;
470 RC
= STATUS_NO_MORE_FILES
;
475 // Does this entry match the search criterian?
479 UNICODE_STRING FileName
;
481 // Constructing a counted Unicode string out of PtrDirEntry
482 Ext2CopyCharToUnicodeString( &FileName
, PtrDirEntry
->name
, PtrDirEntry
->name_len
);
484 if ( SearchWithWildCards
)
486 Matched
= FsRtlIsNameInExpression ( PtrSearchPattern
, &FileName
, FALSE
, NULL
);
490 Matched
= ! RtlCompareUnicodeString( PtrSearchPattern
, &FileName
, FALSE
);
493 Ext2DeallocateUnicodeString( &FileName
);
500 switch( FileInformationClass
)
502 case FileBothDirectoryInformation
:
504 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileBothDirectoryInformation", 0 );
505 ThisBlock
= sizeof( FILE_BOTH_DIR_INFORMATION
);
506 ThisBlock
+= PtrDirEntry
->name_len
*2;
507 ThisBlock
= Ext2QuadAlign( ThisBlock
);
509 if( ( BufferIndex
+ ThisBlock
) > BufferLength
)
512 // Next entry won't fit into the buffer...
513 // will have to return...
516 if( BothDirInformation
)
517 BothDirInformation
->NextEntryOffset
= 0;
519 RC
= STATUS_NO_MORE_FILES
;
524 Ext2ReadInode( PtrVCB
, PtrDirEntry
->inode
, PtrInode
);
527 try_return( RC
= STATUS_UNSUCCESSFUL
);
530 BothDirInformation
= ( PFILE_BOTH_DIR_INFORMATION
) ( Buffer
+ ( BufferIndex
) );
531 BothDirInformation
->EaSize
= 0;
532 BothDirInformation
->AllocationSize
.QuadPart
= PtrInode
->i_blocks
* 512;
533 BothDirInformation
->EndOfFile
.QuadPart
= PtrInode
->i_size
;
534 BothDirInformation
->ChangeTime
.QuadPart
= 0;
536 BothDirInformation
->CreationTime
.QuadPart
= ( __int64
) PtrInode
->i_ctime
* 10000000;
537 BothDirInformation
->CreationTime
.QuadPart
+= Ext2GlobalData
.TimeDiff
.QuadPart
;
539 BothDirInformation
->LastAccessTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
) PtrInode
->i_atime
* 10000000 );
540 BothDirInformation
->LastWriteTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
)PtrInode
->i_mtime
* 10000000 );
542 // Getting the file type...
543 BothDirInformation
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
544 if( ! Ext2IsModeRegularFile( PtrInode
->i_mode
) )
546 // Not a reqular file...
547 if( Ext2IsModeDirectory( PtrInode
->i_mode
) )
550 BothDirInformation
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
555 // Treated with respect... ;)
557 BothDirInformation
->FileAttributes
|= ( FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_READONLY
);
558 // FILE_ATTRIBUTE_DEVICE
560 if ( Ext2IsModeHidden( PtrInode
->i_mode
) )
562 BothDirInformation
->FileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
565 if ( Ext2IsModeReadOnly( PtrInode
->i_mode
) )
567 BothDirInformation
->FileAttributes
|= FILE_ATTRIBUTE_READONLY
;
571 BothDirInformation
->FileIndex
= StartingIndexForSearch
;
572 BothDirInformation
->FileNameLength
= PtrDirEntry
->name_len
*2 + 2;
573 BothDirInformation
->ShortNameLength
= 0;
574 BothDirInformation
->ShortName
[0] = 0;
576 // Copying out the name as WCHAR null terminated strings
577 for( j
= 0; j
< PtrDirEntry
->name_len
; j
++ )
579 // BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j];
580 BothDirInformation
->FileName
[ j
] = PtrDirEntry
->name
[j
];
582 // BothDirInformation->ShortName[j] = PtrDirEntry->name[j];
588 BothDirInformation->ShortNameLength = j * 2 + 2;
589 BothDirInformation->ShortName[ j ] = 0;
593 BothDirInformation->ShortNameLength = 24;
594 BothDirInformation->ShortName[ 11 ] = 0;
597 BothDirInformation
->FileName
[ j
] = 0;
598 BytesReturned
+= ThisBlock
;
599 BufferIndex
+= ThisBlock
;
601 if( !ReturnSingleEntry
&& ( StartingIndexForSearch
< ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ))
602 BothDirInformation
->NextEntryOffset
= ThisBlock
;
604 BothDirInformation
->NextEntryOffset
= 0;
607 case FileDirectoryInformation
:
608 // DirectoryInformation
609 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileDirectoryInformation", 0 );
610 ThisBlock
= sizeof( FILE_DIRECTORY_INFORMATION
);
611 ThisBlock
+= PtrDirEntry
->name_len
*2;
612 ThisBlock
= Ext2QuadAlign( ThisBlock
);
614 if( ( BufferIndex
+ ThisBlock
) > BufferLength
)
617 // Next entry won't fit into the buffer...
618 // will have to return...
621 if( DirectoryInformation
)
622 DirectoryInformation
->NextEntryOffset
= 0;
624 RC
= STATUS_NO_MORE_FILES
;
629 Ext2ReadInode( PtrVCB
, PtrDirEntry
->inode
, PtrInode
);
632 try_return( RC
= STATUS_UNSUCCESSFUL
);
635 DirectoryInformation
= ( PFILE_DIRECTORY_INFORMATION
) ( Buffer
+ ( BufferIndex
) );
636 DirectoryInformation
->AllocationSize
.QuadPart
= PtrInode
->i_blocks
* 512;
637 DirectoryInformation
->EndOfFile
.QuadPart
= PtrInode
->i_size
;
638 DirectoryInformation
->ChangeTime
.QuadPart
= 0;
640 DirectoryInformation
->CreationTime
.QuadPart
= ( __int64
) PtrInode
->i_ctime
* 10000000;
641 DirectoryInformation
->CreationTime
.QuadPart
+= Ext2GlobalData
.TimeDiff
.QuadPart
;
643 DirectoryInformation
->LastAccessTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
) PtrInode
->i_atime
* 10000000 );
644 DirectoryInformation
->LastWriteTime
.QuadPart
= Ext2GlobalData
.TimeDiff
.QuadPart
+ ( ( __int64
)PtrInode
->i_mtime
* 10000000 );
646 // Getting the file type...
647 DirectoryInformation
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
648 if( ! Ext2IsModeRegularFile( PtrInode
->i_mode
) )
650 // Not a reqular file...
651 if( Ext2IsModeDirectory( PtrInode
->i_mode
) )
654 DirectoryInformation
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
659 // Treated with respect... ;)
661 DirectoryInformation
->FileAttributes
|= ( FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_READONLY
);
662 // FILE_ATTRIBUTE_DEVICE
664 if ( Ext2IsModeHidden( PtrInode
->i_mode
) )
666 DirectoryInformation
->FileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
669 if ( Ext2IsModeReadOnly( PtrInode
->i_mode
) )
671 DirectoryInformation
->FileAttributes
|= FILE_ATTRIBUTE_READONLY
;
675 DirectoryInformation
->FileIndex
= StartingIndexForSearch
;
676 DirectoryInformation
->FileNameLength
= PtrDirEntry
->name_len
*2 + 2;
678 // Copying out the name as WCHAR null terminated strings
679 for( j
= 0; j
< PtrDirEntry
->name_len
; j
++ )
681 DirectoryInformation
->FileName
[ j
] = PtrDirEntry
->name
[j
];
684 DirectoryInformation
->FileName
[ j
] = 0;
685 BytesReturned
+= ThisBlock
;
686 BufferIndex
+= ThisBlock
;
688 if( !ReturnSingleEntry
&& ( StartingIndexForSearch
< ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ))
689 DirectoryInformation
->NextEntryOffset
= ThisBlock
;
691 DirectoryInformation
->NextEntryOffset
= 0;
694 case FileFullDirectoryInformation
:
695 // FullDirInformation->
696 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileFullDirectoryInformation - Not handled", 0 );
698 case FileNamesInformation
:
699 // NamesInformation->
700 DebugTrace(DEBUG_TRACE_DIRINFO
, " === FileNamesInformation - Not handled", 0 );
703 DebugTrace(DEBUG_TRACE_DIRINFO
, " === Invalid Dir Info class - Not handled", 0 );
704 try_return( RC
= STATUS_INVALID_INFO_CLASS
);
706 if( ReturnSingleEntry
)
714 if( !BytesReturned
&& StartingIndexForSearch
>= ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
) )
716 Ext2DeallocateUnicodeString( &PtrCCB
->DirectorySearchPattern
);
717 PtrCCB
->CurrentByteOffset
.QuadPart
= 0;
719 RC
= STATUS_NO_SUCH_FILE
;
721 RC
= STATUS_NO_MORE_FILES
;
724 else if( BytesReturned
)
726 BothDirInformation
->NextEntryOffset
= 0;
736 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [DirCtrl]", PtrInode
);
737 ExFreePool( PtrInode
);
742 CcUnpinData( PtrBCB
);
750 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
751 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Released in [DirCtrl]", 0);
752 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
753 PtrReqdFCB
->MainResource
.ActiveCount
,
754 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
755 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
758 // Map the users buffer and then post the request.
759 RC
= Ext2LockCallersBuffer(PtrIrp
, TRUE
, BufferLength
);
760 ASSERT(NT_SUCCESS(RC
));
762 RC
= Ext2PostRequest(PtrIrpContext
, PtrIrp
);
765 else if (!(PtrIrpContext
->IrpContextFlags
&
766 EXT2_IRP_CONTEXT_EXCEPTION
))
770 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
771 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Released [DirCtrl]", 0);
772 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
773 PtrReqdFCB
->MainResource
.ActiveCount
,
774 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
775 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
778 // Complete the request.
779 PtrIrp
->IoStatus
.Status
= RC
;
780 PtrIrp
->IoStatus
.Information
= BytesReturned
;
782 // Free up the Irp Context
783 Ext2ReleaseIrpContext(PtrIrpContext
);
786 IoCompleteRequest(PtrIrp
, IO_DISK_INCREMENT
);
789 // Flush the saved BCBs...
790 // Ext2FlushSavedBCBs ( PtrIrpContext );
799 /*************************************************************************
801 * Function: Ext2NotifyChangeDirectory()
804 * Handle the notify request.
806 * Expected Interrupt Level (for execution) :
810 * Return Value: STATUS_SUCCESS/Error
812 *************************************************************************/
813 NTSTATUS NTAPI
Ext2NotifyChangeDirectory(
814 PtrExt2IrpContext PtrIrpContext
,
817 PEXTENDED_IO_STACK_LOCATION PtrIoStackLocation
,
819 PIO_STACK_LOCATION PtrIoStackLocation
,
821 PFILE_OBJECT PtrFileObject
,
825 NTSTATUS RC
= STATUS_SUCCESS
;
826 BOOLEAN CompleteRequest
= FALSE
;
827 BOOLEAN PostRequest
= FALSE
;
828 PtrExt2NTRequiredFCB PtrReqdFCB
= NULL
;
829 BOOLEAN CanWait
= FALSE
;
830 ULONG CompletionFilter
= 0;
831 BOOLEAN WatchTree
= FALSE
;
832 PtrExt2VCB PtrVCB
= NULL
;
833 BOOLEAN AcquiredFCB
= FALSE
;
837 // Validate the sent-in FCB
838 if ((PtrFCB
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
) || !(PtrFCB
->FCBFlags
& EXT2_FCB_DIRECTORY
)) {
839 // We will only allow notify requests on directories.
840 RC
= STATUS_INVALID_PARAMETER
;
841 CompleteRequest
= TRUE
;
844 PtrReqdFCB
= &(PtrFCB
->NTRequiredFCB
);
845 CanWait
= ((PtrIrpContext
->IrpContextFlags
& EXT2_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
);
846 PtrVCB
= PtrFCB
->PtrVCB
;
848 // Acquire the FCB resource shared
849 DebugTrace(DEBUG_TRACE_MISC
, "*** Attempting to acquire FCB Shared[DirCtrl]", 0);
850 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]", PtrReqdFCB
->MainResource
.ActiveCount
, PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
851 if (!ExAcquireResourceSharedLite(&(PtrReqdFCB
->MainResource
), CanWait
))
853 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Acquisition FAILED [DirCtrl]", 0);
855 try_return(RC
= STATUS_PENDING
);
858 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB acquired [DirCtrl]", 0);
860 // Obtain some parameters sent by the caller
861 CompletionFilter
= PtrIoStackLocation
->Parameters
.NotifyDirectory
.CompletionFilter
;
862 WatchTree
= (PtrIoStackLocation
->Flags
& SL_WATCH_TREE
? TRUE
: FALSE
);
864 // If you wish to capture the subject context, you can do so as
867 // PSECURITY_SUBJECT_CONTEXT SubjectContext;
868 // SubjectContext = Ext2AllocatePool(PagedPool,
869 // sizeof(SECURITY_SUBJECT_CONTEXT) );
870 // SeCaptureSubjectContext(SubjectContext);
873 FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC
)&(PtrVCB
->NotifyIRPMutex
), &(PtrVCB
->NextNotifyIRP
), (void *)PtrCCB
,
874 (PSTRING
)(PtrFCB
->FCBName
->ObjectName
.Buffer
), WatchTree
, FALSE
, CompletionFilter
, PtrIrp
,
875 NULL
, // Ext2TraverseAccessCheck(...) ?
876 NULL
); // SubjectContext ?
888 // Perform appropriate post related processing here
891 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
892 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Released in DirCtrl", 0);
893 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
894 PtrReqdFCB
->MainResource
.ActiveCount
,
895 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
896 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
900 RC
= Ext2PostRequest(PtrIrpContext
, PtrIrp
);
902 else if (CompleteRequest
)
904 PtrIrp
->IoStatus
.Status
= RC
;
905 PtrIrp
->IoStatus
.Information
= 0;
907 // Free up the Irp Context
908 Ext2ReleaseIrpContext(PtrIrpContext
);
911 IoCompleteRequest(PtrIrp
, IO_DISK_INCREMENT
);
913 // Simply free up the IrpContext since the IRP has been queued
914 Ext2ReleaseIrpContext(PtrIrpContext
);
917 // Release the FCB resources if acquired.
920 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
921 DebugTrace(DEBUG_TRACE_MISC
, "*** FReleased in [DirCtrl]", 0);
922 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [DirCtrl]",
923 PtrReqdFCB
->MainResource
.ActiveCount
,
924 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
925 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);