1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "directory control" dispatch entry point.
15 *************************************************************************/
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_DIR_CONTROL
23 // Local support routine(s):
26 #define UDF_FNM_FLAG_CAN_BE_8D3 0x01
27 #define UDF_FNM_FLAG_IGNORE_CASE 0x02
28 #define UDF_FNM_FLAG_CONTAINS_WC 0x04
30 NTSTATUS
UDFFindNextMatch(
32 IN PDIR_INDEX_HDR hDirIndex
,
33 IN PLONG CurrentNumber
, // Must be modified
34 IN PUNICODE_STRING PtrSearchPattern
,
36 IN PHASH_ENTRY hashes
,
37 OUT PDIR_INDEX_ITEM
* _DirNdx
);
39 /*************************************************************************
41 * Function: UDFDirControl()
44 * The I/O Manager will invoke this routine to handle a directory control
47 * Expected Interrupt Level (for execution) :
49 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
50 * to be deferred to a worker thread context)
52 * Return Value: STATUS_SUCCESS/Error
54 *************************************************************************/
58 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
59 PIRP Irp
// I/O Request Packet
62 NTSTATUS RC
= STATUS_SUCCESS
;
63 PtrUDFIrpContext PtrIrpContext
= NULL
;
64 BOOLEAN AreWeTopLevel
= FALSE
;
66 TmPrint(("UDFDirControl: \n"));
68 FsRtlEnterFileSystem();
72 // set the top level context
73 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
74 ASSERT(!UDFIsFSDevObj(DeviceObject
));
78 // get an IRP context structure and issue the request
79 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
81 RC
= UDFCommonDirControl(PtrIrpContext
, Irp
);
83 RC
= STATUS_INSUFFICIENT_RESOURCES
;
84 Irp
->IoStatus
.Status
= RC
;
85 Irp
->IoStatus
.Information
= 0;
87 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
90 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
92 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
94 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
98 IoSetTopLevelIrp(NULL
);
101 FsRtlExitFileSystem();
104 } // end UDFDirControl()
108 /*************************************************************************
110 * Function: UDFCommonDirControl()
113 * The actual work is performed here. This routine may be invoked in one'
114 * of the two possible contexts:
115 * (a) in the context of a system worker thread
116 * (b) in the context of the original caller
118 * Expected Interrupt Level (for execution) :
122 * Return Value: STATUS_SUCCESS/Error
124 *************************************************************************/
128 PtrUDFIrpContext PtrIrpContext
,
132 NTSTATUS RC
= STATUS_SUCCESS
;
133 PIO_STACK_LOCATION IrpSp
= NULL
;
134 PFILE_OBJECT FileObject
= NULL
;
135 PtrUDFFCB Fcb
= NULL
;
136 PtrUDFCCB Ccb
= NULL
;
138 BOOLEAN AcquiredVcb
= FALSE
;
140 TmPrint(("UDFCommonDirControl: \n"));
144 // First, get a pointer to the current I/O stack location
145 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
148 FileObject
= IrpSp
->FileObject
;
151 // Get the FCB and CCB pointers
152 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
157 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
159 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
160 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
162 UDFFlushTryBreak(Vcb
);
163 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
165 // Get some of the parameters supplied to us
166 switch (IrpSp
->MinorFunction
) {
167 case IRP_MN_QUERY_DIRECTORY
:
168 RC
= UDFQueryDirectory(PtrIrpContext
, Irp
, IrpSp
, FileObject
, Fcb
, Ccb
);
170 case IRP_MN_NOTIFY_CHANGE_DIRECTORY
:
171 RC
= UDFNotifyChangeDirectory(PtrIrpContext
, Irp
, IrpSp
, FileObject
, Fcb
, Ccb
);
174 // This should not happen.
175 RC
= STATUS_INVALID_DEVICE_REQUEST
;
176 Irp
->IoStatus
.Status
= RC
;
177 Irp
->IoStatus
.Information
= 0;
179 // Free up the Irp Context
180 UDFReleaseIrpContext(PtrIrpContext
);
183 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
192 UDFReleaseResource(&(Vcb
->VCBResource
));
197 } // end UDFCommonDirControl()
200 /*************************************************************************
202 * Function: UDFQueryDirectory()
205 * Query directory request.
207 * Expected Interrupt Level (for execution) :
211 * Return Value: STATUS_SUCCESS/Error
213 *************************************************************************/
217 PtrUDFIrpContext PtrIrpContext
,
219 PIO_STACK_LOCATION IrpSp
,
220 PFILE_OBJECT FileObject
,
225 NTSTATUS RC
= STATUS_SUCCESS
;
226 BOOLEAN PostRequest
= FALSE
;
227 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
228 BOOLEAN CanWait
= FALSE
;
230 BOOLEAN AcquiredFCB
= FALSE
;
231 unsigned long BufferLength
= 0;
232 UNICODE_STRING SearchPattern
;
233 PUNICODE_STRING PtrSearchPattern
;
234 FILE_INFORMATION_CLASS FileInformationClass
;
235 BOOLEAN ReturnSingleEntry
= FALSE
;
236 PUCHAR Buffer
= NULL
;
237 BOOLEAN FirstTimeQuery
= FALSE
;
243 ULONG Information
= 0;
244 ULONG LastOffset
= 0;
245 BOOLEAN AtLeastOneFound
= FALSE
;
246 PEXTENDED_IO_STACK_LOCATION pStackLocation
= (PEXTENDED_IO_STACK_LOCATION
) IrpSp
;
247 PUDF_FILE_INFO DirFileInfo
= NULL
;
248 PDIR_INDEX_HDR hDirIndex
= NULL
;
249 PFILE_BOTH_DIR_INFORMATION DirInformation
= NULL
; // Returned from udf_info module
250 PFILE_BOTH_DIR_INFORMATION BothDirInformation
= NULL
; // Pointer in callers buffer
251 PFILE_NAMES_INFORMATION NamesInfo
;
252 ULONG BytesRemainingInBuffer
;
254 PHASH_ENTRY cur_hashes
= NULL
;
255 PDIR_INDEX_ITEM DirNdx
;
256 // do some pre-init...
257 SearchPattern
.Buffer
= NULL
;
259 UDFPrint(("UDFQueryDirectory: @=%#x\n", &PtrIrpContext
));
261 #define CanBe8dot3 (FNM_Flags & UDF_FNM_FLAG_CAN_BE_8D3)
262 #define IgnoreCase (FNM_Flags & UDF_FNM_FLAG_IGNORE_CASE)
263 #define ContainsWC (FNM_Flags & UDF_FNM_FLAG_CONTAINS_WC)
268 // Validate the sent-in FCB
269 if ((Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
) || !(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
270 // We will only allow notify requests on directories.
271 try_return(RC
= STATUS_INVALID_PARAMETER
);
274 // Obtain the callers parameters
275 NtReqFcb
= Fcb
->NTRequiredFCB
;
276 CanWait
= (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
;
278 //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
279 FNM_Flags
|= (Ccb
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? 0 : UDF_FNM_FLAG_IGNORE_CASE
;
280 DirFileInfo
= Fcb
->FileInfo
;
281 BufferLength
= pStackLocation
->Parameters
.QueryDirectory
.Length
;
283 // If the caller does not want to block, it would be easier to
284 // simply post the request now.
287 try_return(RC
= STATUS_PENDING
);
290 // Continue obtaining the callers parameters...
291 if(IgnoreCase
&& pStackLocation
->Parameters
.QueryDirectory
.FileName
) {
292 PtrSearchPattern
= &SearchPattern
;
293 if(!NT_SUCCESS(RC
= RtlUpcaseUnicodeString(PtrSearchPattern
, (PUNICODE_STRING
)(pStackLocation
->Parameters
.QueryDirectory
.FileName
), TRUE
)))
296 PtrSearchPattern
= (PUNICODE_STRING
)(pStackLocation
->Parameters
.QueryDirectory
.FileName
);
298 FileInformationClass
= pStackLocation
->Parameters
.QueryDirectory
.FileInformationClass
;
300 // Calculate baselength (without name) for each InfoClass
301 switch (FileInformationClass
) {
303 case FileDirectoryInformation
:
304 BaseLength
= FIELD_OFFSET( FILE_DIRECTORY_INFORMATION
, FileName
[0] );
306 case FileFullDirectoryInformation
:
307 BaseLength
= FIELD_OFFSET( FILE_FULL_DIR_INFORMATION
, FileName
[0] );
309 case FileNamesInformation
:
310 BaseLength
= FIELD_OFFSET( FILE_NAMES_INFORMATION
, FileName
[0] );
312 case FileBothDirectoryInformation
:
313 BaseLength
= FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION
, FileName
[0] );
316 try_return(RC
= STATUS_INVALID_INFO_CLASS
);
319 // Some additional arguments that affect the FSD behavior
320 ReturnSingleEntry
= (IrpSp
->Flags
& SL_RETURN_SINGLE_ENTRY
) ? TRUE
: FALSE
;
322 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
323 UDFAcquireResourceShared(&(NtReqFcb
->MainResource
), TRUE
);
326 // We must determine the buffer pointer to be used. Since this
327 // routine could either be invoked directly in the context of the
328 // calling thread, or in the context of a worker thread, here is
329 // a general way of determining what we should use.
330 if(Irp
->MdlAddress
) {
331 Buffer
= (PUCHAR
) MmGetSystemAddressForMdlSafer(Irp
->MdlAddress
);
333 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
335 Buffer
= (PUCHAR
) Irp
->UserBuffer
;
337 try_return(RC
= STATUS_INVALID_USER_BUFFER
);
340 // The method of determining where to look from and what to look for is
341 // unfortunately extremely confusing. However, here is a methodology
343 // (a) We have to maintain a search buffer per CCB structure.
344 // (b) This search buffer is initialized the very first time
345 // a query directory operation is performed using the file object.
346 // (For the UDF FSD, the search buffer is stored in the
347 // DirectorySearchPattern field)
348 // However, the caller still has the option of "overriding" this stored
349 // search pattern by supplying a new one in a query directory operation.
350 if(PtrSearchPattern
&&
351 PtrSearchPattern
->Buffer
&&
352 !(PtrSearchPattern
->Buffer
[PtrSearchPattern
->Length
/sizeof(WCHAR
) - 1])) {
353 PtrSearchPattern
->Length
-= sizeof(WCHAR
);
356 if(IrpSp
->Flags
& SL_INDEX_SPECIFIED
) {
357 // Good idea from M$: we should continue search from NEXT item
358 // when FileIndex specified...
359 // Strange idea from M$: we should do it with EMPTY pattern...
360 PtrSearchPattern
= NULL
;
361 Ccb
->CCBFlags
|= UDF_CCB_MATCH_ALL
;
362 } else if(PtrSearchPattern
&&
363 PtrSearchPattern
->Buffer
&&
364 !UDFIsMatchAllMask(PtrSearchPattern
, NULL
) ) {
366 Ccb
->CCBFlags
&= ~(UDF_CCB_MATCH_ALL
|
367 UDF_CCB_WILDCARD_PRESENT
|
368 UDF_CCB_CAN_BE_8_DOT_3
);
369 // Once we have validated the search pattern, we must
370 // check whether we need to store this search pattern in
372 if(Ccb
->DirectorySearchPattern
) {
373 MyFreePool__(Ccb
->DirectorySearchPattern
->Buffer
);
374 MyFreePool__(Ccb
->DirectorySearchPattern
);
375 Ccb
->DirectorySearchPattern
= NULL
;
377 // This must be the very first query request.
378 FirstTimeQuery
= TRUE
;
380 // Now, allocate enough memory to contain the caller
381 // supplied search pattern and fill in the DirectorySearchPattern
383 Ccb
->DirectorySearchPattern
= (PUNICODE_STRING
)MyAllocatePool__(NonPagedPool
,sizeof(UNICODE_STRING
));
384 if(!(Ccb
->DirectorySearchPattern
)) {
385 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
387 Ccb
->DirectorySearchPattern
->Length
= PtrSearchPattern
->Length
;
388 Ccb
->DirectorySearchPattern
->MaximumLength
= PtrSearchPattern
->MaximumLength
;
389 Ccb
->DirectorySearchPattern
->Buffer
= (PWCHAR
)MyAllocatePool__(NonPagedPool
,PtrSearchPattern
->MaximumLength
);
390 if(!(Ccb
->DirectorySearchPattern
->Buffer
)) {
391 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
393 RtlCopyMemory(Ccb
->DirectorySearchPattern
->Buffer
,PtrSearchPattern
->Buffer
,
394 PtrSearchPattern
->MaximumLength
);
395 if(FsRtlDoesNameContainWildCards(PtrSearchPattern
)) {
396 Ccb
->CCBFlags
|= UDF_CCB_WILDCARD_PRESENT
;
398 UDFBuildHashEntry(Vcb
, PtrSearchPattern
, cur_hashes
= &(Ccb
->hashes
), HASH_POSIX
| HASH_ULFN
);
400 if(UDFCanNameBeA8dot3(PtrSearchPattern
))
401 Ccb
->CCBFlags
|= UDF_CCB_CAN_BE_8_DOT_3
;
403 } else if(!Ccb
->DirectorySearchPattern
&&
404 !(Ccb
->CCBFlags
& UDF_CCB_MATCH_ALL
) ) {
406 // If the filename is not specified or is a single '*' then we will
408 FirstTimeQuery
= TRUE
;
409 PtrSearchPattern
= NULL
;
410 Ccb
->CCBFlags
|= UDF_CCB_MATCH_ALL
;
413 // The caller has not supplied any search pattern that we are
414 // forced to use. However, the caller had previously supplied
415 // a pattern (or we must have invented one) and we will use it.
416 // This is definitely not the first query operation on this
417 // directory using this particular file object.
418 if(Ccb
->CCBFlags
& UDF_CCB_MATCH_ALL
) {
419 PtrSearchPattern
= NULL
;
420 /* if(Ccb->CurrentIndex)
421 Ccb->CurrentIndex++;*/
423 PtrSearchPattern
= Ccb
->DirectorySearchPattern
;
424 if(!(Ccb
->CCBFlags
& UDF_CCB_WILDCARD_PRESENT
)) {
425 cur_hashes
= &(Ccb
->hashes
);
430 if(IrpSp
->Flags
& SL_INDEX_SPECIFIED
) {
431 // Caller has told us wherefrom to begin.
432 // We may need to round this to an appropriate directory entry
433 // entry alignment value.
434 NextMatch
= pStackLocation
->Parameters
.QueryDirectory
.FileIndex
+ 1;
435 } else if(IrpSp
->Flags
& SL_RESTART_SCAN
) {
438 // Get the starting offset from the CCB.
439 // Remember to update this value on our way out from this function.
440 // But, do not update the CCB CurrentByteOffset field if our reach
441 // the end of the directory (or get an error reading the directory)
442 // while performing the search.
443 NextMatch
= Ccb
->CurrentIndex
+ 1; // Last good index
446 FNM_Flags
|= (Ccb
->CCBFlags
& UDF_CCB_WILDCARD_PRESENT
) ? UDF_FNM_FLAG_CONTAINS_WC
: 0;
447 // this is used only when mask is supplied
448 FNM_Flags
|= (Ccb
->CCBFlags
& UDF_CCB_CAN_BE_8_DOT_3
) ? UDF_FNM_FLAG_CAN_BE_8D3
: 0;
450 // This is an additional verifying
451 if(!UDFIsADirectory(DirFileInfo
)) {
452 try_return(RC
= STATUS_INVALID_PARAMETER
);
455 hDirIndex
= DirFileInfo
->Dloc
->DirIndex
;
457 try_return(RC
= STATUS_INVALID_PARAMETER
);
461 // Allocate buffer enough to save both DirInformation and FileName
462 DirInformation
= (PFILE_BOTH_DIR_INFORMATION
)MyAllocatePool__(NonPagedPool
,
463 sizeof(FILE_BOTH_DIR_INFORMATION
)+((ULONG
)UDF_NAME_LEN
*sizeof(WCHAR
)) );
464 if(!DirInformation
) {
465 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
468 BytesRemainingInBuffer
= pStackLocation
->Parameters
.QueryDirectory
.Length
;
469 RtlZeroMemory(Buffer
,BytesRemainingInBuffer
);
471 if((!FirstTimeQuery
) && !UDFDirIndex(hDirIndex
, (uint_di
)NextMatch
) ) {
472 try_return( RC
= STATUS_NO_MORE_FILES
);
475 // One final note though:
476 // If we do not find a directory entry OR while searching we reach the
477 // end of the directory, then the return code should be set as follows:
479 // (a) If any files have been returned (i.e. ReturnSingleEntry was FALSE
480 // and we did find at least one match), then return STATUS_SUCCESS
481 // (b) If no entry is being returned then:
482 // (i) If this is the first query i.e. FirstTimeQuery is TRUE
483 // then return STATUS_NO_SUCH_FILE
484 // (ii) Otherwise, return STATUS_NO_MORE_FILES
487 // If the user had requested only a single match and we have
488 // returned that, then we stop at this point.
489 if(ReturnSingleEntry
&& AtLeastOneFound
) {
492 // We call UDFFindNextMatch to look down the next matching dirent.
493 RC
= UDFFindNextMatch(Vcb
, hDirIndex
,&NextMatch
,PtrSearchPattern
, FNM_Flags
, cur_hashes
, &DirNdx
);
494 // If we didn't receive next match, then we are at the end of the
495 // directory. If we have returned any files, we exit with
496 // success, otherwise we return STATUS_NO_MORE_FILES.
497 if(!NT_SUCCESS(RC
)) {
498 RC
= AtLeastOneFound
? STATUS_SUCCESS
:
499 (FirstTimeQuery
? STATUS_NO_SUCH_FILE
: STATUS_NO_MORE_FILES
);
502 // We found at least one matching file entry
503 AtLeastOneFound
= TRUE
;
504 if(!NT_SUCCESS(RC
= UDFFileDirInfoToNT(Vcb
, DirNdx
, DirInformation
))) {
505 // this happends when we can't allocate tmp buffers
508 DirInformation
->FileIndex
= NextMatch
;
509 FileNameBytes
= DirInformation
->FileNameLength
;
511 if ((BaseLength
+ FileNameBytes
) > BytesRemainingInBuffer
) {
512 // We haven't successfully transfered current data &
513 // later NextMatch will be incremented. Thus we should
514 // prevent loosing information in such a way:
515 if(NextMatch
) NextMatch
--;
516 // If this won't fit and we have returned a previous entry then just
517 // return STATUS_SUCCESS. Otherwise
518 // use a status code of STATUS_BUFFER_OVERFLOW.
520 try_return(RC
= STATUS_SUCCESS
);
523 ReturnSingleEntry
= TRUE
;
524 FileNameBytes
= BaseLength
+ FileNameBytes
- BytesRemainingInBuffer
;
525 RC
= STATUS_BUFFER_OVERFLOW
;
527 // Now we have an entry to return to our caller.
528 // We'll case on the type of information requested and fill up
529 // the user buffer if everything fits.
530 switch (FileInformationClass
) {
532 case FileBothDirectoryInformation
:
533 case FileFullDirectoryInformation
:
534 case FileDirectoryInformation
:
536 BothDirInformation
= (PFILE_BOTH_DIR_INFORMATION
)(Buffer
+ CurrentOffset
);
537 RtlCopyMemory(BothDirInformation
,DirInformation
,BaseLength
);
538 BothDirInformation
->FileIndex
= NextMatch
;
539 BothDirInformation
->FileNameLength
= FileNameBytes
;
542 case FileNamesInformation
:
544 NamesInfo
= (PFILE_NAMES_INFORMATION
)(Buffer
+ CurrentOffset
);
545 NamesInfo
->FileIndex
= NextMatch
;
546 NamesInfo
->FileNameLength
= FileNameBytes
;
553 // This is a Unicode name, we can copy the bytes directly.
554 RtlCopyMemory( (PVOID
)(Buffer
+ CurrentOffset
+ BaseLength
),
555 DirInformation
->FileName
, FileNameBytes
);
558 Information
= CurrentOffset
+ BaseLength
+ FileNameBytes
;
560 // ((..._INFORMATION)(PointerToPreviousEntryInBuffer))->NextEntryOffset = CurrentOffset - LastOffset;
561 *((PULONG
)(Buffer
+LastOffset
)) = CurrentOffset
- LastOffset
;
562 // Set up our variables for the next dirent.
563 FirstTimeQuery
= FALSE
;
565 LastOffset
= CurrentOffset
;
566 PrevMatch
= NextMatch
;
568 CurrentOffset
= UDFQuadAlign(Information
);
569 BytesRemainingInBuffer
= BufferLength
- CurrentOffset
;
580 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
581 UDFReleaseResource(&(NtReqFcb
->MainResource
));
583 // Map the users buffer and then post the request.
584 RC
= UDFLockCallersBuffer(PtrIrpContext
, Irp
, TRUE
, BufferLength
);
585 ASSERT(NT_SUCCESS(RC
));
587 RC
= UDFPostRequest(PtrIrpContext
, Irp
);
591 if(!NT_SUCCESS(RC
)) {
592 UDFPrint((" Not found\n"));
595 // Remember to update the CurrentByteOffset field in the CCB if required.
596 if(Ccb
) Ccb
->CurrentIndex
= PrevMatch
;
599 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
600 UDFReleaseResource(&(NtReqFcb
->MainResource
));
602 if (!_SEH2_AbnormalTermination()) {
604 Irp
->IoStatus
.Status
= RC
;
605 Irp
->IoStatus
.Information
= Information
;
606 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
607 // Free up the Irp Context
608 UDFReleaseIrpContext(PtrIrpContext
);
612 if(SearchPattern
.Buffer
) RtlFreeUnicodeString(&SearchPattern
);
613 if(DirInformation
) MyFreePool__(DirInformation
);
617 } // end UDFQueryDirectory()
620 Return: STATUS_NO_SUCH_FILE if no more files found
625 IN PDIR_INDEX_HDR hDirIndex
,
626 IN PLONG CurrentNumber
, // Must be modified in case, when we found next match
627 IN PUNICODE_STRING PtrSearchPattern
,
629 IN PHASH_ENTRY hashes
,
630 OUT PDIR_INDEX_ITEM
* _DirNdx
633 LONG EntryNumber
= (*CurrentNumber
);
634 PDIR_INDEX_ITEM DirNdx
;
636 #define CanBe8dot3 (FNM_Flags & UDF_FNM_FLAG_CAN_BE_8D3)
637 #define IgnoreCase (FNM_Flags & UDF_FNM_FLAG_IGNORE_CASE)
638 #define ContainsWC (FNM_Flags & UDF_FNM_FLAG_CONTAINS_WC)
640 for(;(DirNdx
= UDFDirIndex(hDirIndex
, EntryNumber
));EntryNumber
++) {
641 if(!DirNdx
->FName
.Buffer
||
642 UDFIsDeleted(DirNdx
))
645 (DirNdx
->hashes
.hLfn
!= hashes
->hLfn
) &&
646 (DirNdx
->hashes
.hPosix
!= hashes
->hPosix
) &&
647 (!CanBe8dot3
|| ((DirNdx
->hashes
.hDos
!= hashes
->hLfn
) && (DirNdx
->hashes
.hDos
!= hashes
->hPosix
))) )
649 if(UDFIsNameInExpression(Vcb
, &(DirNdx
->FName
),PtrSearchPattern
, NULL
,IgnoreCase
,
650 ContainsWC
, CanBe8dot3
&& !(DirNdx
->FI_Flags
& UDF_FI_FLAG_DOS
),
652 !(DirNdx
->FI_Flags
& UDF_FI_FLAG_FI_INTERNAL
))
657 // Modify CurrentNumber to appropriate value
658 *CurrentNumber
= EntryNumber
;
660 return STATUS_SUCCESS
;
662 // Do not modify CurrentNumber because we have not found next match entry
663 return STATUS_NO_MORE_FILES
;
665 } // end UDFFindNextMatch()
667 /*************************************************************************
669 * Function: UDFNotifyChangeDirectory()
672 * Handle the notify request.
674 * Expected Interrupt Level (for execution) :
678 * Return Value: STATUS_SUCCESS/Error
680 *************************************************************************/
683 UDFNotifyChangeDirectory(
684 PtrUDFIrpContext PtrIrpContext
,
686 PIO_STACK_LOCATION IrpSp
,
687 PFILE_OBJECT FileObject
,
692 NTSTATUS RC
= STATUS_SUCCESS
;
693 BOOLEAN CompleteRequest
= FALSE
;
694 BOOLEAN PostRequest
= FALSE
;
695 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
696 BOOLEAN CanWait
= FALSE
;
697 ULONG CompletionFilter
= 0;
698 BOOLEAN WatchTree
= FALSE
;
700 BOOLEAN AcquiredFCB
= FALSE
;
701 PEXTENDED_IO_STACK_LOCATION pStackLocation
= (PEXTENDED_IO_STACK_LOCATION
) IrpSp
;
703 UDFPrint(("UDFNotifyChangeDirectory\n"));
707 // Validate the sent-in FCB
708 if ( (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
) ||
709 !(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
711 CompleteRequest
= TRUE
;
712 try_return(RC
= STATUS_INVALID_PARAMETER
);
715 NtReqFcb
= Fcb
->NTRequiredFCB
;
716 CanWait
= (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
;
719 // Acquire the FCB resource shared
720 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
721 if (!UDFAcquireResourceShared(&(NtReqFcb
->MainResource
), CanWait
)) {
723 try_return(RC
= STATUS_PENDING
);
727 // If the file is marked as DELETE_PENDING then complete this
728 // request immediately.
729 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
730 ASSERT(!(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
731 try_return(RC
= STATUS_DELETE_PENDING
);
734 // Obtain some parameters sent by the caller
735 CompletionFilter
= pStackLocation
->Parameters
.NotifyDirectory
.CompletionFilter
;
736 WatchTree
= (IrpSp
->Flags
& SL_WATCH_TREE
) ? TRUE
: FALSE
;
738 // If we wish to capture the subject context, we can do so as
741 // PSECURITY_SUBJECT_CONTEXT SubjectContext;
742 // SubjectContext = MyAllocatePool__(PagedPool,
743 // sizeof(SECURITY_SUBJECT_CONTEXT));
744 // SeCaptureSubjectContext(SubjectContext);
747 FsRtlNotifyFullChangeDirectory(Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
), (PVOID
)Ccb
,
748 (Fcb
->FileInfo
->ParentFile
) ? (PSTRING
)&(Fcb
->FCBName
->ObjectName
) : (PSTRING
)&(UDFGlobalData
.UnicodeStrRoot
),
749 WatchTree
, FALSE
, CompletionFilter
, Irp
,
750 NULL
, // UDFTraverseAccessCheck(...) ?
751 NULL
); // SubjectContext ?
760 // Perform appropriate related post processing here
762 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
763 UDFReleaseResource(&(NtReqFcb
->MainResource
));
766 RC
= UDFPostRequest(PtrIrpContext
, Irp
);
767 } else if (CompleteRequest
) {
769 if (!_SEH2_AbnormalTermination()) {
770 Irp
->IoStatus
.Status
= RC
;
771 Irp
->IoStatus
.Information
= 0;
772 // Free up the Irp Context
773 UDFReleaseIrpContext(PtrIrpContext
);
775 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
779 // Simply free up the IrpContext since the IRP has been queued
780 if (!_SEH2_AbnormalTermination())
781 UDFReleaseIrpContext(PtrIrpContext
);
784 // Release the FCB resources if acquired.
786 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
787 UDFReleaseResource(&(NtReqFcb
->MainResource
));
794 } // end UDFNotifyChangeDirectory()