1c2c66affSColin Finck ////////////////////////////////////////////////////////////////////
2c2c66affSColin Finck // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3c2c66affSColin Finck // All rights reserved
4c2c66affSColin Finck // This file was released under the GPLv2 on June 2015.
5c2c66affSColin Finck ////////////////////////////////////////////////////////////////////
6c2c66affSColin Finck /*************************************************************************
7c2c66affSColin Finck *
8c2c66affSColin Finck * File: DirCntrl.cpp
9c2c66affSColin Finck *
10c2c66affSColin Finck * Module: UDF File System Driver (Kernel mode execution only)
11c2c66affSColin Finck *
12c2c66affSColin Finck * Description:
13c2c66affSColin Finck *   Contains code to handle the "directory control" dispatch entry point.
14c2c66affSColin Finck *
15c2c66affSColin Finck *************************************************************************/
16c2c66affSColin Finck 
17c2c66affSColin Finck #include            "udffs.h"
18c2c66affSColin Finck 
19c2c66affSColin Finck // define the file specific bug-check id
20c2c66affSColin Finck #define         UDF_BUG_CHECK_ID                UDF_FILE_DIR_CONTROL
21c2c66affSColin Finck 
22c2c66affSColin Finck /*
23c2c66affSColin Finck // Local support routine(s):
24c2c66affSColin Finck */
25c2c66affSColin Finck 
26c2c66affSColin Finck #define UDF_FNM_FLAG_CAN_BE_8D3    0x01
27c2c66affSColin Finck #define UDF_FNM_FLAG_IGNORE_CASE   0x02
28c2c66affSColin Finck #define UDF_FNM_FLAG_CONTAINS_WC   0x04
29c2c66affSColin Finck 
30c2c66affSColin Finck NTSTATUS UDFFindNextMatch(
31c2c66affSColin Finck     IN PVCB            Vcb,
32c2c66affSColin Finck     IN PDIR_INDEX_HDR  hDirIndex,
33c2c66affSColin Finck     IN PLONG           CurrentNumber,      // Must be modified
34c2c66affSColin Finck     IN PUNICODE_STRING PtrSearchPattern,
35c2c66affSColin Finck     IN UCHAR           FNM_Flags,
36c2c66affSColin Finck     IN PHASH_ENTRY     hashes,
37c2c66affSColin Finck    OUT PDIR_INDEX_ITEM* _DirNdx);
38c2c66affSColin Finck 
39c2c66affSColin Finck /*************************************************************************
40c2c66affSColin Finck *
41c2c66affSColin Finck * Function: UDFDirControl()
42c2c66affSColin Finck *
43c2c66affSColin Finck * Description:
44c2c66affSColin Finck *   The I/O Manager will invoke this routine to handle a directory control
45c2c66affSColin Finck *   request
46c2c66affSColin Finck *
47c2c66affSColin Finck * Expected Interrupt Level (for execution) :
48c2c66affSColin Finck *
49c2c66affSColin Finck *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
50c2c66affSColin Finck *   to be deferred to a worker thread context)
51c2c66affSColin Finck *
52c2c66affSColin Finck * Return Value: STATUS_SUCCESS/Error
53c2c66affSColin Finck *
54c2c66affSColin Finck *************************************************************************/
55c2c66affSColin Finck NTSTATUS
56c2c66affSColin Finck NTAPI
UDFDirControl(PDEVICE_OBJECT DeviceObject,PIRP Irp)57c2c66affSColin Finck UDFDirControl(
58c2c66affSColin Finck     PDEVICE_OBJECT      DeviceObject,       // the logical volume device object
59c2c66affSColin Finck     PIRP                Irp                 // I/O Request Packet
60c2c66affSColin Finck     )
61c2c66affSColin Finck {
62c2c66affSColin Finck     NTSTATUS            RC = STATUS_SUCCESS;
63c2c66affSColin Finck     PtrUDFIrpContext    PtrIrpContext = NULL;
64c2c66affSColin Finck     BOOLEAN             AreWeTopLevel = FALSE;
65c2c66affSColin Finck 
66c2c66affSColin Finck     TmPrint(("UDFDirControl: \n"));
67c2c66affSColin Finck 
68c2c66affSColin Finck     FsRtlEnterFileSystem();
69c2c66affSColin Finck     ASSERT(DeviceObject);
70c2c66affSColin Finck     ASSERT(Irp);
71c2c66affSColin Finck 
72c2c66affSColin Finck     // set the top level context
73c2c66affSColin Finck     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
74c2c66affSColin Finck     ASSERT(!UDFIsFSDevObj(DeviceObject));
75c2c66affSColin Finck 
76c2c66affSColin Finck     _SEH2_TRY {
77c2c66affSColin Finck 
78c2c66affSColin Finck         // get an IRP context structure and issue the request
79c2c66affSColin Finck         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
80c2c66affSColin Finck         if(PtrIrpContext) {
81c2c66affSColin Finck             RC = UDFCommonDirControl(PtrIrpContext, Irp);
82c2c66affSColin Finck         } else {
83c2c66affSColin Finck             RC = STATUS_INSUFFICIENT_RESOURCES;
84c2c66affSColin Finck             Irp->IoStatus.Status = RC;
85c2c66affSColin Finck             Irp->IoStatus.Information = 0;
86c2c66affSColin Finck             // complete the IRP
87c2c66affSColin Finck             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
88c2c66affSColin Finck         }
89c2c66affSColin Finck 
90c2c66affSColin Finck     } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
91c2c66affSColin Finck 
92c2c66affSColin Finck         RC = UDFExceptionHandler(PtrIrpContext, Irp);
93c2c66affSColin Finck 
94c2c66affSColin Finck         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
95c2c66affSColin Finck     } _SEH2_END;
96c2c66affSColin Finck 
97c2c66affSColin Finck     if (AreWeTopLevel) {
98c2c66affSColin Finck         IoSetTopLevelIrp(NULL);
99c2c66affSColin Finck     }
100c2c66affSColin Finck 
101c2c66affSColin Finck     FsRtlExitFileSystem();
102c2c66affSColin Finck 
103c2c66affSColin Finck     return(RC);
104c2c66affSColin Finck } // end UDFDirControl()
105c2c66affSColin Finck 
106c2c66affSColin Finck 
107c2c66affSColin Finck 
108c2c66affSColin Finck /*************************************************************************
109c2c66affSColin Finck *
110c2c66affSColin Finck * Function: UDFCommonDirControl()
111c2c66affSColin Finck *
112c2c66affSColin Finck * Description:
113c2c66affSColin Finck *   The actual work is performed here. This routine may be invoked in one'
114c2c66affSColin Finck *   of the two possible contexts:
115c2c66affSColin Finck *   (a) in the context of a system worker thread
116c2c66affSColin Finck *   (b) in the context of the original caller
117c2c66affSColin Finck *
118c2c66affSColin Finck * Expected Interrupt Level (for execution) :
119c2c66affSColin Finck *
120c2c66affSColin Finck *  IRQL_PASSIVE_LEVEL
121c2c66affSColin Finck *
122c2c66affSColin Finck * Return Value: STATUS_SUCCESS/Error
123c2c66affSColin Finck *
124c2c66affSColin Finck *************************************************************************/
125c2c66affSColin Finck NTSTATUS
126c2c66affSColin Finck NTAPI
UDFCommonDirControl(PtrUDFIrpContext PtrIrpContext,PIRP Irp)127c2c66affSColin Finck UDFCommonDirControl(
128c2c66affSColin Finck    PtrUDFIrpContext  PtrIrpContext,
129c2c66affSColin Finck    PIRP              Irp
130c2c66affSColin Finck    )
131c2c66affSColin Finck {
132c2c66affSColin Finck     NTSTATUS                RC = STATUS_SUCCESS;
133c2c66affSColin Finck     PIO_STACK_LOCATION      IrpSp = NULL;
134c2c66affSColin Finck     PFILE_OBJECT            FileObject = NULL;
135c2c66affSColin Finck     PtrUDFFCB               Fcb = NULL;
136c2c66affSColin Finck     PtrUDFCCB               Ccb = NULL;
137*a91f5e8eSDoug Lyons     _SEH2_VOLATILE PVCB     Vcb = NULL;
138*a91f5e8eSDoug Lyons     _SEH2_VOLATILE BOOLEAN  AcquiredVcb = FALSE;
139c2c66affSColin Finck 
140c2c66affSColin Finck     TmPrint(("UDFCommonDirControl: \n"));
141c2c66affSColin Finck //    BrutePoint();
142c2c66affSColin Finck 
143c2c66affSColin Finck     _SEH2_TRY {
144c2c66affSColin Finck         // First, get a pointer to the current I/O stack location
145c2c66affSColin Finck         IrpSp = IoGetCurrentIrpStackLocation(Irp);
146c2c66affSColin Finck         ASSERT(IrpSp);
147c2c66affSColin Finck 
148c2c66affSColin Finck         FileObject = IrpSp->FileObject;
149c2c66affSColin Finck         ASSERT(FileObject);
150c2c66affSColin Finck 
151c2c66affSColin Finck         // Get the FCB and CCB pointers
152c2c66affSColin Finck         Ccb = (PtrUDFCCB)(FileObject->FsContext2);
153c2c66affSColin Finck         ASSERT(Ccb);
154c2c66affSColin Finck         Fcb = Ccb->Fcb;
155c2c66affSColin Finck         ASSERT(Fcb);
156c2c66affSColin Finck 
157c2c66affSColin Finck         Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
158c2c66affSColin Finck         ASSERT(Vcb);
159c2c66affSColin Finck         ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
160c2c66affSColin Finck //        Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
161c2c66affSColin Finck 
162c2c66affSColin Finck         UDFFlushTryBreak(Vcb);
163c2c66affSColin Finck         UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
164c2c66affSColin Finck         AcquiredVcb = TRUE;
165c2c66affSColin Finck         // Get some of the parameters supplied to us
166c2c66affSColin Finck         switch (IrpSp->MinorFunction) {
167c2c66affSColin Finck         case IRP_MN_QUERY_DIRECTORY:
168c2c66affSColin Finck             RC = UDFQueryDirectory(PtrIrpContext, Irp, IrpSp, FileObject, Fcb, Ccb);
169c2c66affSColin Finck             break;
170c2c66affSColin Finck         case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
171c2c66affSColin Finck             RC = UDFNotifyChangeDirectory(PtrIrpContext, Irp, IrpSp, FileObject, Fcb, Ccb);
172c2c66affSColin Finck             break;
173c2c66affSColin Finck         default:
174c2c66affSColin Finck             // This should not happen.
175c2c66affSColin Finck             RC = STATUS_INVALID_DEVICE_REQUEST;
176c2c66affSColin Finck             Irp->IoStatus.Status = RC;
177c2c66affSColin Finck             Irp->IoStatus.Information = 0;
178c2c66affSColin Finck 
179c2c66affSColin Finck             // Free up the Irp Context
180c2c66affSColin Finck             UDFReleaseIrpContext(PtrIrpContext);
181c2c66affSColin Finck 
182c2c66affSColin Finck             // complete the IRP
183c2c66affSColin Finck             IoCompleteRequest(Irp, IO_NO_INCREMENT);
184c2c66affSColin Finck             break;
185c2c66affSColin Finck         }
186c2c66affSColin Finck 
187c2c66affSColin Finck //try_exit: NOTHING;
188c2c66affSColin Finck 
189c2c66affSColin Finck     } _SEH2_FINALLY {
190c2c66affSColin Finck 
191c2c66affSColin Finck         if(AcquiredVcb) {
192c2c66affSColin Finck             UDFReleaseResource(&(Vcb->VCBResource));
193c2c66affSColin Finck             AcquiredVcb = FALSE;
194c2c66affSColin Finck         }
195c2c66affSColin Finck     } _SEH2_END;
196c2c66affSColin Finck     return(RC);
197c2c66affSColin Finck } // end UDFCommonDirControl()
198c2c66affSColin Finck 
199c2c66affSColin Finck 
200c2c66affSColin Finck /*************************************************************************
201c2c66affSColin Finck *
202c2c66affSColin Finck * Function: UDFQueryDirectory()
203c2c66affSColin Finck *
204c2c66affSColin Finck * Description:
205c2c66affSColin Finck *   Query directory request.
206c2c66affSColin Finck *
207c2c66affSColin Finck * Expected Interrupt Level (for execution) :
208c2c66affSColin Finck *
209c2c66affSColin Finck *  IRQL_PASSIVE_LEVEL
210c2c66affSColin Finck *
211c2c66affSColin Finck * Return Value: STATUS_SUCCESS/Error
212c2c66affSColin Finck *
213c2c66affSColin Finck *************************************************************************/
214c2c66affSColin Finck NTSTATUS
215c2c66affSColin Finck NTAPI
UDFQueryDirectory(PtrUDFIrpContext PtrIrpContext,PIRP Irp,PIO_STACK_LOCATION IrpSp,PFILE_OBJECT FileObject,PtrUDFFCB Fcb,PtrUDFCCB Ccb)216c2c66affSColin Finck UDFQueryDirectory(
217c2c66affSColin Finck     PtrUDFIrpContext            PtrIrpContext,
218c2c66affSColin Finck     PIRP                        Irp,
219c2c66affSColin Finck     PIO_STACK_LOCATION          IrpSp,
220c2c66affSColin Finck     PFILE_OBJECT                FileObject,
221c2c66affSColin Finck     PtrUDFFCB                   Fcb,
222c2c66affSColin Finck     PtrUDFCCB                   Ccb
223c2c66affSColin Finck     )
224c2c66affSColin Finck {
225c2c66affSColin Finck     NTSTATUS                    RC = STATUS_SUCCESS;
226c2c66affSColin Finck     BOOLEAN                     PostRequest = FALSE;
227c2c66affSColin Finck     PtrUDFNTRequiredFCB         NtReqFcb = NULL;
228c2c66affSColin Finck     BOOLEAN                     CanWait = FALSE;
229*a91f5e8eSDoug Lyons     _SEH2_VOLATILE PVCB         Vcb = NULL;
230*a91f5e8eSDoug Lyons     _SEH2_VOLATILE BOOLEAN      AcquiredFCB = FALSE;
231c2c66affSColin Finck     unsigned long               BufferLength = 0;
232c2c66affSColin Finck     UNICODE_STRING              SearchPattern;
233c2c66affSColin Finck     PUNICODE_STRING             PtrSearchPattern;
234c2c66affSColin Finck     FILE_INFORMATION_CLASS      FileInformationClass;
235c2c66affSColin Finck     BOOLEAN                     ReturnSingleEntry = FALSE;
236c2c66affSColin Finck     PUCHAR                      Buffer = NULL;
237c2c66affSColin Finck     BOOLEAN                     FirstTimeQuery = FALSE;
238c2c66affSColin Finck     LONG                        NextMatch;
239c2c66affSColin Finck     LONG                        PrevMatch = -1;
240c2c66affSColin Finck     ULONG                       CurrentOffset;
241c2c66affSColin Finck     ULONG                       BaseLength;
242c2c66affSColin Finck     ULONG                       FileNameBytes;
243c2c66affSColin Finck     ULONG                       Information = 0;
244c2c66affSColin Finck     ULONG                       LastOffset = 0;
245c2c66affSColin Finck     BOOLEAN                     AtLeastOneFound = FALSE;
246c2c66affSColin Finck     PEXTENDED_IO_STACK_LOCATION pStackLocation = (PEXTENDED_IO_STACK_LOCATION) IrpSp;
247c2c66affSColin Finck     PUDF_FILE_INFO              DirFileInfo = NULL;
248c2c66affSColin Finck     PDIR_INDEX_HDR              hDirIndex = NULL;
249c2c66affSColin Finck     PFILE_BOTH_DIR_INFORMATION  DirInformation = NULL;      // Returned from udf_info module
250c2c66affSColin Finck     PFILE_BOTH_DIR_INFORMATION  BothDirInformation = NULL;  // Pointer in callers buffer
251c2c66affSColin Finck     PFILE_NAMES_INFORMATION     NamesInfo;
252c2c66affSColin Finck     ULONG                       BytesRemainingInBuffer;
253c2c66affSColin Finck     UCHAR                       FNM_Flags = 0;
254c2c66affSColin Finck     PHASH_ENTRY                 cur_hashes = NULL;
255c2c66affSColin Finck     PDIR_INDEX_ITEM             DirNdx;
256c2c66affSColin Finck     // do some pre-init...
257c2c66affSColin Finck     SearchPattern.Buffer = NULL;
258c2c66affSColin Finck 
259c2c66affSColin Finck     UDFPrint(("UDFQueryDirectory: @=%#x\n", &PtrIrpContext));
260c2c66affSColin Finck 
261c2c66affSColin Finck #define CanBe8dot3    (FNM_Flags & UDF_FNM_FLAG_CAN_BE_8D3)
262c2c66affSColin Finck #define IgnoreCase    (FNM_Flags & UDF_FNM_FLAG_IGNORE_CASE)
263c2c66affSColin Finck #define ContainsWC    (FNM_Flags & UDF_FNM_FLAG_CONTAINS_WC)
264c2c66affSColin Finck 
265c2c66affSColin Finck     _SEH2_TRY
266c2c66affSColin Finck     {
267c2c66affSColin Finck 
268c2c66affSColin Finck         // Validate the sent-in FCB
269c2c66affSColin Finck         if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
270c2c66affSColin Finck             // We will only allow notify requests on directories.
271c2c66affSColin Finck             try_return(RC = STATUS_INVALID_PARAMETER);
272c2c66affSColin Finck         }
273c2c66affSColin Finck 
274c2c66affSColin Finck         // Obtain the callers parameters
275c2c66affSColin Finck         NtReqFcb = Fcb->NTRequiredFCB;
276c2c66affSColin Finck         CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
277c2c66affSColin Finck         Vcb = Fcb->Vcb;
278c2c66affSColin Finck         //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
279c2c66affSColin Finck         FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? 0 : UDF_FNM_FLAG_IGNORE_CASE;
280c2c66affSColin Finck         DirFileInfo = Fcb->FileInfo;
281c2c66affSColin Finck         BufferLength = pStackLocation->Parameters.QueryDirectory.Length;
282c2c66affSColin Finck 
283c2c66affSColin Finck         // If the caller does not want to block, it would be easier to
284c2c66affSColin Finck         // simply post the request now.
285c2c66affSColin Finck         if (!CanWait) {
286c2c66affSColin Finck             PostRequest = TRUE;
287c2c66affSColin Finck             try_return(RC = STATUS_PENDING);
288c2c66affSColin Finck         }
289c2c66affSColin Finck 
290c2c66affSColin Finck         // Continue obtaining the callers parameters...
291c2c66affSColin Finck         if(IgnoreCase && pStackLocation->Parameters.QueryDirectory.FileName) {
292c2c66affSColin Finck             PtrSearchPattern = &SearchPattern;
293c2c66affSColin Finck             if(!NT_SUCCESS(RC = RtlUpcaseUnicodeString(PtrSearchPattern, (PUNICODE_STRING)(pStackLocation->Parameters.QueryDirectory.FileName), TRUE)))
294c2c66affSColin Finck                 try_return(RC);
295c2c66affSColin Finck         } else {
296c2c66affSColin Finck             PtrSearchPattern = (PUNICODE_STRING)(pStackLocation->Parameters.QueryDirectory.FileName);
297c2c66affSColin Finck         }
298c2c66affSColin Finck         FileInformationClass = pStackLocation->Parameters.QueryDirectory.FileInformationClass;
299c2c66affSColin Finck 
300c2c66affSColin Finck         // Calculate baselength (without name) for each InfoClass
301c2c66affSColin Finck         switch (FileInformationClass) {
302c2c66affSColin Finck 
303c2c66affSColin Finck         case FileDirectoryInformation:
304c2c66affSColin Finck             BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] );
305c2c66affSColin Finck             break;
306c2c66affSColin Finck         case FileFullDirectoryInformation:
307c2c66affSColin Finck             BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,  FileName[0] );
308c2c66affSColin Finck             break;
309c2c66affSColin Finck         case FileNamesInformation:
310c2c66affSColin Finck             BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,     FileName[0] );
311c2c66affSColin Finck             break;
312c2c66affSColin Finck         case FileBothDirectoryInformation:
313c2c66affSColin Finck             BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,  FileName[0] );
314c2c66affSColin Finck             break;
315c2c66affSColin Finck         default:
316c2c66affSColin Finck             try_return(RC = STATUS_INVALID_INFO_CLASS);
317c2c66affSColin Finck         }
318c2c66affSColin Finck 
319c2c66affSColin Finck         // Some additional arguments that affect the FSD behavior
320c2c66affSColin Finck         ReturnSingleEntry = (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) ? TRUE : FALSE;
321c2c66affSColin Finck 
322c2c66affSColin Finck         UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
323c2c66affSColin Finck         UDFAcquireResourceShared(&(NtReqFcb->MainResource), TRUE);
324c2c66affSColin Finck         AcquiredFCB = TRUE;
325c2c66affSColin Finck 
326c2c66affSColin Finck         // We must determine the buffer pointer to be used. Since this
327c2c66affSColin Finck         // routine could either be invoked directly in the context of the
328c2c66affSColin Finck         // calling thread, or in the context of a worker thread, here is
329c2c66affSColin Finck         // a general way of determining what we should use.
330c2c66affSColin Finck         if(Irp->MdlAddress) {
331c2c66affSColin Finck             Buffer = (PUCHAR) MmGetSystemAddressForMdlSafer(Irp->MdlAddress);
332c2c66affSColin Finck             if(!Buffer)
333c2c66affSColin Finck                 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
334c2c66affSColin Finck         } else {
335c2c66affSColin Finck             Buffer = (PUCHAR) Irp->UserBuffer;
336c2c66affSColin Finck             if(!Buffer)
337c2c66affSColin Finck                 try_return(RC = STATUS_INVALID_USER_BUFFER);
338c2c66affSColin Finck         }
339c2c66affSColin Finck 
340c2c66affSColin Finck         // The method of determining where to look from and what to look for is
341c2c66affSColin Finck         // unfortunately extremely confusing. However, here is a methodology
342c2c66affSColin Finck         // we broadly adopt:
343c2c66affSColin Finck         // (a) We have to maintain a search buffer per CCB structure.
344c2c66affSColin Finck         // (b) This search buffer is initialized the very first time
345c2c66affSColin Finck         //       a query directory operation is performed using the file object.
346c2c66affSColin Finck         // (For the UDF FSD, the search buffer is stored in the
347c2c66affSColin Finck         //   DirectorySearchPattern field)
348c2c66affSColin Finck         // However, the caller still has the option of "overriding" this stored
349c2c66affSColin Finck         // search pattern by supplying a new one in a query directory operation.
350c2c66affSColin Finck         if(PtrSearchPattern &&
351c2c66affSColin Finck            PtrSearchPattern->Buffer &&
352c2c66affSColin Finck            !(PtrSearchPattern->Buffer[PtrSearchPattern->Length/sizeof(WCHAR) - 1])) {
353c2c66affSColin Finck             PtrSearchPattern->Length -= sizeof(WCHAR);
354c2c66affSColin Finck         }
355c2c66affSColin Finck 
356c2c66affSColin Finck         if(IrpSp->Flags & SL_INDEX_SPECIFIED) {
357c2c66affSColin Finck             // Good idea from M$: we should continue search from NEXT item
358c2c66affSColin Finck             // when FileIndex specified...
359c2c66affSColin Finck             // Strange idea from M$: we should do it with EMPTY pattern...
360c2c66affSColin Finck             PtrSearchPattern = NULL;
361c2c66affSColin Finck             Ccb->CCBFlags |= UDF_CCB_MATCH_ALL;
362c2c66affSColin Finck         } else if(PtrSearchPattern &&
363c2c66affSColin Finck                   PtrSearchPattern->Buffer &&
364c2c66affSColin Finck                   !UDFIsMatchAllMask(PtrSearchPattern, NULL) ) {
365c2c66affSColin Finck 
366c2c66affSColin Finck             Ccb->CCBFlags &= ~(UDF_CCB_MATCH_ALL |
367c2c66affSColin Finck                                UDF_CCB_WILDCARD_PRESENT |
368c2c66affSColin Finck                                UDF_CCB_CAN_BE_8_DOT_3);
369c2c66affSColin Finck             // Once we have validated the search pattern, we must
370c2c66affSColin Finck             // check whether we need to store this search pattern in
371c2c66affSColin Finck             // the CCB.
372c2c66affSColin Finck             if(Ccb->DirectorySearchPattern) {
373c2c66affSColin Finck                 MyFreePool__(Ccb->DirectorySearchPattern->Buffer);
374c2c66affSColin Finck                 MyFreePool__(Ccb->DirectorySearchPattern);
375c2c66affSColin Finck                 Ccb->DirectorySearchPattern = NULL;
376c2c66affSColin Finck             }
377c2c66affSColin Finck             // This must be the very first query request.
378c2c66affSColin Finck             FirstTimeQuery = TRUE;
379c2c66affSColin Finck 
380c2c66affSColin Finck             // Now, allocate enough memory to contain the caller
381c2c66affSColin Finck             // supplied search pattern and fill in the DirectorySearchPattern
382c2c66affSColin Finck             // field in the CCB
383c2c66affSColin Finck             Ccb->DirectorySearchPattern = (PUNICODE_STRING)MyAllocatePool__(NonPagedPool,sizeof(UNICODE_STRING));
384c2c66affSColin Finck             if(!(Ccb->DirectorySearchPattern)) {
385c2c66affSColin Finck                 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
386c2c66affSColin Finck             }
387c2c66affSColin Finck             Ccb->DirectorySearchPattern->Length = PtrSearchPattern->Length;
388c2c66affSColin Finck             Ccb->DirectorySearchPattern->MaximumLength = PtrSearchPattern->MaximumLength;
389c2c66affSColin Finck             Ccb->DirectorySearchPattern->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool,PtrSearchPattern->MaximumLength);
390c2c66affSColin Finck             if(!(Ccb->DirectorySearchPattern->Buffer)) {
391c2c66affSColin Finck                 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
392c2c66affSColin Finck             }
393c2c66affSColin Finck             RtlCopyMemory(Ccb->DirectorySearchPattern->Buffer,PtrSearchPattern->Buffer,
394c2c66affSColin Finck                           PtrSearchPattern->MaximumLength);
395c2c66affSColin Finck             if(FsRtlDoesNameContainWildCards(PtrSearchPattern)) {
396c2c66affSColin Finck                 Ccb->CCBFlags |= UDF_CCB_WILDCARD_PRESENT;
397c2c66affSColin Finck             } else {
398c2c66affSColin Finck                 UDFBuildHashEntry(Vcb, PtrSearchPattern, cur_hashes = &(Ccb->hashes), HASH_POSIX | HASH_ULFN);
399c2c66affSColin Finck             }
400c2c66affSColin Finck             if(UDFCanNameBeA8dot3(PtrSearchPattern))
401c2c66affSColin Finck                 Ccb->CCBFlags |= UDF_CCB_CAN_BE_8_DOT_3;
402c2c66affSColin Finck 
403c2c66affSColin Finck         } else if(!Ccb->DirectorySearchPattern &&
404c2c66affSColin Finck                   !(Ccb->CCBFlags & UDF_CCB_MATCH_ALL) ) {
405c2c66affSColin Finck 
406c2c66affSColin Finck             // If the filename is not specified or is a single '*' then we will
407c2c66affSColin Finck             // match all names.
408c2c66affSColin Finck             FirstTimeQuery = TRUE;
409c2c66affSColin Finck             PtrSearchPattern = NULL;
410c2c66affSColin Finck             Ccb->CCBFlags |= UDF_CCB_MATCH_ALL;
411c2c66affSColin Finck 
412c2c66affSColin Finck         } else {
413c2c66affSColin Finck             // The caller has not supplied any search pattern that we are
414c2c66affSColin Finck             // forced to use. However, the caller had previously supplied
415c2c66affSColin Finck             // a pattern (or we must have invented one) and we will use it.
416c2c66affSColin Finck             // This is definitely not the first query operation on this
417c2c66affSColin Finck             // directory using this particular file object.
418c2c66affSColin Finck             if(Ccb->CCBFlags & UDF_CCB_MATCH_ALL) {
419c2c66affSColin Finck                 PtrSearchPattern = NULL;
420c2c66affSColin Finck /*                if(Ccb->CurrentIndex)
421c2c66affSColin Finck                     Ccb->CurrentIndex++;*/
422c2c66affSColin Finck             } else {
423c2c66affSColin Finck                 PtrSearchPattern = Ccb->DirectorySearchPattern;
424c2c66affSColin Finck                 if(!(Ccb->CCBFlags & UDF_CCB_WILDCARD_PRESENT)) {
425c2c66affSColin Finck                     cur_hashes = &(Ccb->hashes);
426c2c66affSColin Finck                 }
427c2c66affSColin Finck             }
428c2c66affSColin Finck         }
429c2c66affSColin Finck 
430c2c66affSColin Finck         if(IrpSp->Flags & SL_INDEX_SPECIFIED) {
431c2c66affSColin Finck             // Caller has told us wherefrom to begin.
432c2c66affSColin Finck             // We may need to round this to an appropriate directory entry
433c2c66affSColin Finck             // entry alignment value.
434c2c66affSColin Finck             NextMatch = pStackLocation->Parameters.QueryDirectory.FileIndex + 1;
435c2c66affSColin Finck         } else if(IrpSp->Flags & SL_RESTART_SCAN) {
436c2c66affSColin Finck             NextMatch = 0;
437c2c66affSColin Finck         } else {
438c2c66affSColin Finck             // Get the starting offset from the CCB.
439c2c66affSColin Finck             // Remember to update this value on our way out from this function.
440c2c66affSColin Finck             // But, do not update the CCB CurrentByteOffset field if our reach
441c2c66affSColin Finck             // the end of the directory (or get an error reading the directory)
442c2c66affSColin Finck             // while performing the search.
443c2c66affSColin Finck             NextMatch = Ccb->CurrentIndex + 1; // Last good index
444c2c66affSColin Finck         }
445c2c66affSColin Finck 
446c2c66affSColin Finck         FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_WILDCARD_PRESENT) ? UDF_FNM_FLAG_CONTAINS_WC : 0;
447c2c66affSColin Finck         // this is used only when mask is supplied
448c2c66affSColin Finck         FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_CAN_BE_8_DOT_3) ? UDF_FNM_FLAG_CAN_BE_8D3 : 0;
449c2c66affSColin Finck 
450c2c66affSColin Finck         // This is an additional verifying
451c2c66affSColin Finck         if(!UDFIsADirectory(DirFileInfo)) {
452c2c66affSColin Finck             try_return(RC = STATUS_INVALID_PARAMETER);
453c2c66affSColin Finck         }
454c2c66affSColin Finck 
455c2c66affSColin Finck         hDirIndex = DirFileInfo->Dloc->DirIndex;
456c2c66affSColin Finck         if(!hDirIndex) {
457c2c66affSColin Finck             try_return(RC = STATUS_INVALID_PARAMETER);
458c2c66affSColin Finck         }
459c2c66affSColin Finck 
460c2c66affSColin Finck         RC = STATUS_SUCCESS;
461c2c66affSColin Finck         // Allocate buffer enough to save both DirInformation and FileName
462c2c66affSColin Finck         DirInformation = (PFILE_BOTH_DIR_INFORMATION)MyAllocatePool__(NonPagedPool,
463c2c66affSColin Finck                             sizeof(FILE_BOTH_DIR_INFORMATION)+((ULONG)UDF_NAME_LEN*sizeof(WCHAR)) );
464c2c66affSColin Finck         if(!DirInformation) {
465c2c66affSColin Finck             try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
466c2c66affSColin Finck         }
467c2c66affSColin Finck         CurrentOffset=0;
468c2c66affSColin Finck         BytesRemainingInBuffer = pStackLocation->Parameters.QueryDirectory.Length;
469c2c66affSColin Finck         RtlZeroMemory(Buffer,BytesRemainingInBuffer);
470c2c66affSColin Finck 
471c2c66affSColin Finck         if((!FirstTimeQuery) && !UDFDirIndex(hDirIndex, (uint_di)NextMatch) ) {
472c2c66affSColin Finck             try_return( RC = STATUS_NO_MORE_FILES);
473c2c66affSColin Finck         }
474c2c66affSColin Finck 
475c2c66affSColin Finck         // One final note though:
476c2c66affSColin Finck         // If we do not find a directory entry OR while searching we reach the
477c2c66affSColin Finck         // end of the directory, then the return code should be set as follows:
478c2c66affSColin Finck 
479c2c66affSColin Finck         // (a) If any files have been returned (i.e. ReturnSingleEntry was FALSE
480c2c66affSColin Finck         //       and we did find at least one match), then return STATUS_SUCCESS
481c2c66affSColin Finck         // (b) If no entry is being returned then:
482c2c66affSColin Finck         //       (i) If this is the first query i.e. FirstTimeQuery is TRUE
483c2c66affSColin Finck         //            then return STATUS_NO_SUCH_FILE
484c2c66affSColin Finck         //       (ii) Otherwise, return STATUS_NO_MORE_FILES
485c2c66affSColin Finck 
486c2c66affSColin Finck         while(TRUE) {
487c2c66affSColin Finck             // If the user had requested only a single match and we have
488c2c66affSColin Finck             // returned that, then we stop at this point.
489c2c66affSColin Finck             if(ReturnSingleEntry && AtLeastOneFound) {
490c2c66affSColin Finck                 try_return(RC);
491c2c66affSColin Finck             }
492c2c66affSColin Finck             // We call UDFFindNextMatch to look down the next matching dirent.
493c2c66affSColin Finck             RC = UDFFindNextMatch(Vcb, hDirIndex,&NextMatch,PtrSearchPattern, FNM_Flags, cur_hashes, &DirNdx);
494c2c66affSColin Finck             // If we didn't receive next match, then we are at the end of the
495c2c66affSColin Finck             // directory.  If we have returned any files, we exit with
496c2c66affSColin Finck             // success, otherwise we return STATUS_NO_MORE_FILES.
497c2c66affSColin Finck             if(!NT_SUCCESS(RC)) {
498c2c66affSColin Finck                 RC = AtLeastOneFound ? STATUS_SUCCESS :
499c2c66affSColin Finck                                       (FirstTimeQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
500c2c66affSColin Finck                 try_return(RC);
501c2c66affSColin Finck             }
502c2c66affSColin Finck             // We found at least one matching file entry
503c2c66affSColin Finck             AtLeastOneFound = TRUE;
504c2c66affSColin Finck             if(!NT_SUCCESS(RC = UDFFileDirInfoToNT(Vcb, DirNdx, DirInformation))) {
505c2c66affSColin Finck                 // this happends when we can't allocate tmp buffers
506c2c66affSColin Finck                 try_return(RC);
507c2c66affSColin Finck             }
508c2c66affSColin Finck             DirInformation->FileIndex = NextMatch;
509c2c66affSColin Finck             FileNameBytes = DirInformation->FileNameLength;
510c2c66affSColin Finck 
511c2c66affSColin Finck             if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) {
512c2c66affSColin Finck                 // We haven't successfully transfered current data &
513c2c66affSColin Finck                 // later NextMatch will be incremented. Thus we should
514c2c66affSColin Finck                 // prevent loosing information in such a way:
515c2c66affSColin Finck                 if(NextMatch) NextMatch --;
516c2c66affSColin Finck                 // If this won't fit and we have returned a previous entry then just
517c2c66affSColin Finck                 // return STATUS_SUCCESS. Otherwise
518c2c66affSColin Finck                 // use a status code of STATUS_BUFFER_OVERFLOW.
519c2c66affSColin Finck                 if(CurrentOffset) {
520c2c66affSColin Finck                     try_return(RC = STATUS_SUCCESS);
521c2c66affSColin Finck                 }
522c2c66affSColin Finck                 // strange policy...
523c2c66affSColin Finck                 ReturnSingleEntry = TRUE;
524c2c66affSColin Finck                 FileNameBytes = BaseLength + FileNameBytes - BytesRemainingInBuffer;
525c2c66affSColin Finck                 RC = STATUS_BUFFER_OVERFLOW;
526c2c66affSColin Finck             }
527c2c66affSColin Finck             //  Now we have an entry to return to our caller.
528c2c66affSColin Finck             //  We'll case on the type of information requested and fill up
529c2c66affSColin Finck             //  the user buffer if everything fits.
530c2c66affSColin Finck             switch (FileInformationClass) {
531c2c66affSColin Finck 
532c2c66affSColin Finck             case FileBothDirectoryInformation:
533c2c66affSColin Finck             case FileFullDirectoryInformation:
534c2c66affSColin Finck             case FileDirectoryInformation:
535c2c66affSColin Finck 
536c2c66affSColin Finck                 BothDirInformation = (PFILE_BOTH_DIR_INFORMATION)(Buffer + CurrentOffset);
537c2c66affSColin Finck                 RtlCopyMemory(BothDirInformation,DirInformation,BaseLength);
538c2c66affSColin Finck                 BothDirInformation->FileIndex = NextMatch;
539c2c66affSColin Finck                 BothDirInformation->FileNameLength = FileNameBytes;
540c2c66affSColin Finck                 break;
541c2c66affSColin Finck 
542c2c66affSColin Finck             case FileNamesInformation:
543c2c66affSColin Finck 
544c2c66affSColin Finck                 NamesInfo = (PFILE_NAMES_INFORMATION)(Buffer + CurrentOffset);
545c2c66affSColin Finck                 NamesInfo->FileIndex = NextMatch;
546c2c66affSColin Finck                 NamesInfo->FileNameLength = FileNameBytes;
547c2c66affSColin Finck                 break;
548c2c66affSColin Finck 
549c2c66affSColin Finck             default:
550c2c66affSColin Finck                 break;
551c2c66affSColin Finck             }
552c2c66affSColin Finck             if (FileNameBytes) {
553c2c66affSColin Finck                 //  This is a Unicode name, we can copy the bytes directly.
554c2c66affSColin Finck                 RtlCopyMemory( (PVOID)(Buffer + CurrentOffset + BaseLength),
555c2c66affSColin Finck                                DirInformation->FileName, FileNameBytes );
556c2c66affSColin Finck             }
557c2c66affSColin Finck 
558c2c66affSColin Finck             Information = CurrentOffset + BaseLength + FileNameBytes;
559c2c66affSColin Finck 
560c2c66affSColin Finck             //  ((..._INFORMATION)(PointerToPreviousEntryInBuffer))->NextEntryOffset = CurrentOffset - LastOffset;
561c2c66affSColin Finck             *((PULONG)(Buffer+LastOffset)) = CurrentOffset - LastOffset;
562c2c66affSColin Finck             //  Set up our variables for the next dirent.
563c2c66affSColin Finck             FirstTimeQuery = FALSE;
564c2c66affSColin Finck 
565c2c66affSColin Finck             LastOffset    = CurrentOffset;
566c2c66affSColin Finck             PrevMatch     = NextMatch;
567c2c66affSColin Finck             NextMatch++;
568c2c66affSColin Finck             CurrentOffset = UDFQuadAlign(Information);
569c2c66affSColin Finck             BytesRemainingInBuffer = BufferLength - CurrentOffset;
570c2c66affSColin Finck         }
571c2c66affSColin Finck 
572c2c66affSColin Finck try_exit:   NOTHING;
573c2c66affSColin Finck 
574c2c66affSColin Finck 
575c2c66affSColin Finck     } _SEH2_FINALLY {
576c2c66affSColin Finck 
577c2c66affSColin Finck         if (PostRequest) {
578c2c66affSColin Finck 
579c2c66affSColin Finck             if (AcquiredFCB) {
580c2c66affSColin Finck                 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
581c2c66affSColin Finck                 UDFReleaseResource(&(NtReqFcb->MainResource));
582c2c66affSColin Finck             }
583c2c66affSColin Finck             // Map the users buffer and then post the request.
584c2c66affSColin Finck             RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, BufferLength);
585c2c66affSColin Finck             ASSERT(NT_SUCCESS(RC));
586c2c66affSColin Finck 
587c2c66affSColin Finck             RC = UDFPostRequest(PtrIrpContext, Irp);
588c2c66affSColin Finck 
589c2c66affSColin Finck         } else {
590c2c66affSColin Finck #ifdef UDF_DBG
591c2c66affSColin Finck             if(!NT_SUCCESS(RC)) {
592c2c66affSColin Finck                UDFPrint(("    Not found\n"));
593c2c66affSColin Finck             }
594c2c66affSColin Finck #endif // UDF_DBG
595c2c66affSColin Finck             // Remember to update the CurrentByteOffset field in the CCB if required.
596c2c66affSColin Finck             if(Ccb) Ccb->CurrentIndex = PrevMatch;
597c2c66affSColin Finck 
598c2c66affSColin Finck             if (AcquiredFCB) {
599c2c66affSColin Finck                 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
600c2c66affSColin Finck                 UDFReleaseResource(&(NtReqFcb->MainResource));
601c2c66affSColin Finck             }
602c2c66affSColin Finck             if (!_SEH2_AbnormalTermination()) {
603c2c66affSColin Finck                 // complete the IRP
604c2c66affSColin Finck                 Irp->IoStatus.Status = RC;
605c2c66affSColin Finck                 Irp->IoStatus.Information = Information;
606c2c66affSColin Finck                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
607c2c66affSColin Finck                 // Free up the Irp Context
608c2c66affSColin Finck                 UDFReleaseIrpContext(PtrIrpContext);
609c2c66affSColin Finck             }
610c2c66affSColin Finck         }
611c2c66affSColin Finck 
612c2c66affSColin Finck         if(SearchPattern.Buffer) RtlFreeUnicodeString(&SearchPattern);
613c2c66affSColin Finck         if(DirInformation) MyFreePool__(DirInformation);
614c2c66affSColin Finck     } _SEH2_END;
615c2c66affSColin Finck 
616c2c66affSColin Finck     return(RC);
617c2c66affSColin Finck } // end UDFQueryDirectory()
618c2c66affSColin Finck 
619c2c66affSColin Finck /*
620c2c66affSColin Finck   Return: STATUS_NO_SUCH_FILE if no more files found
621c2c66affSColin Finck */
622c2c66affSColin Finck NTSTATUS
UDFFindNextMatch(IN PVCB Vcb,IN PDIR_INDEX_HDR hDirIndex,IN PLONG CurrentNumber,IN PUNICODE_STRING PtrSearchPattern,IN UCHAR FNM_Flags,IN PHASH_ENTRY hashes,OUT PDIR_INDEX_ITEM * _DirNdx)623c2c66affSColin Finck UDFFindNextMatch(
624c2c66affSColin Finck     IN PVCB Vcb,
625c2c66affSColin Finck     IN PDIR_INDEX_HDR  hDirIndex,
626c2c66affSColin Finck     IN PLONG           CurrentNumber,      // Must be modified in case, when we found next match
627c2c66affSColin Finck     IN PUNICODE_STRING PtrSearchPattern,
628c2c66affSColin Finck     IN UCHAR           FNM_Flags,
629c2c66affSColin Finck     IN PHASH_ENTRY     hashes,
630c2c66affSColin Finck    OUT PDIR_INDEX_ITEM* _DirNdx
631c2c66affSColin Finck     )
632c2c66affSColin Finck {
633c2c66affSColin Finck     LONG    EntryNumber = (*CurrentNumber);
634c2c66affSColin Finck     PDIR_INDEX_ITEM DirNdx;
635c2c66affSColin Finck 
636c2c66affSColin Finck #define CanBe8dot3    (FNM_Flags & UDF_FNM_FLAG_CAN_BE_8D3)
637c2c66affSColin Finck #define IgnoreCase    (FNM_Flags & UDF_FNM_FLAG_IGNORE_CASE)
638c2c66affSColin Finck #define ContainsWC    (FNM_Flags & UDF_FNM_FLAG_CONTAINS_WC)
639c2c66affSColin Finck 
640c2c66affSColin Finck     for(;(DirNdx = UDFDirIndex(hDirIndex, EntryNumber));EntryNumber++) {
641c2c66affSColin Finck         if(!DirNdx->FName.Buffer ||
642c2c66affSColin Finck            UDFIsDeleted(DirNdx))
643c2c66affSColin Finck             continue;
644c2c66affSColin Finck         if(hashes &&
645c2c66affSColin Finck            (DirNdx->hashes.hLfn != hashes->hLfn) &&
646c2c66affSColin Finck            (DirNdx->hashes.hPosix != hashes->hPosix) &&
647c2c66affSColin Finck            (!CanBe8dot3 || ((DirNdx->hashes.hDos != hashes->hLfn) && (DirNdx->hashes.hDos != hashes->hPosix))) )
648c2c66affSColin Finck             continue;
649c2c66affSColin Finck         if(UDFIsNameInExpression(Vcb, &(DirNdx->FName),PtrSearchPattern, NULL,IgnoreCase,
650c2c66affSColin Finck                                 ContainsWC, CanBe8dot3 && !(DirNdx->FI_Flags & UDF_FI_FLAG_DOS),
651c2c66affSColin Finck                                 EntryNumber < 2) &&
652c2c66affSColin Finck            !(DirNdx->FI_Flags & UDF_FI_FLAG_FI_INTERNAL))
653c2c66affSColin Finck             break;
654c2c66affSColin Finck     }
655c2c66affSColin Finck 
656c2c66affSColin Finck     if(DirNdx) {
657c2c66affSColin Finck         // Modify CurrentNumber to appropriate value
658c2c66affSColin Finck         *CurrentNumber = EntryNumber;
659c2c66affSColin Finck         *_DirNdx = DirNdx;
660c2c66affSColin Finck         return STATUS_SUCCESS;
661c2c66affSColin Finck     } else {
662c2c66affSColin Finck         // Do not modify CurrentNumber because we have not found next match entry
663c2c66affSColin Finck         return STATUS_NO_MORE_FILES;
664c2c66affSColin Finck     }
665c2c66affSColin Finck } // end UDFFindNextMatch()
666c2c66affSColin Finck 
667c2c66affSColin Finck /*************************************************************************
668c2c66affSColin Finck *
669c2c66affSColin Finck * Function: UDFNotifyChangeDirectory()
670c2c66affSColin Finck *
671c2c66affSColin Finck * Description:
672c2c66affSColin Finck *   Handle the notify request.
673c2c66affSColin Finck *
674c2c66affSColin Finck * Expected Interrupt Level (for execution) :
675c2c66affSColin Finck *
676c2c66affSColin Finck *  IRQL_PASSIVE_LEVEL
677c2c66affSColin Finck *
678c2c66affSColin Finck * Return Value: STATUS_SUCCESS/Error
679c2c66affSColin Finck *
680c2c66affSColin Finck *************************************************************************/
681c2c66affSColin Finck NTSTATUS
682c2c66affSColin Finck NTAPI
UDFNotifyChangeDirectory(PtrUDFIrpContext PtrIrpContext,PIRP Irp,PIO_STACK_LOCATION IrpSp,PFILE_OBJECT FileObject,PtrUDFFCB Fcb,PtrUDFCCB Ccb)683c2c66affSColin Finck UDFNotifyChangeDirectory(
684c2c66affSColin Finck     PtrUDFIrpContext            PtrIrpContext,
685c2c66affSColin Finck     PIRP                        Irp,
686c2c66affSColin Finck     PIO_STACK_LOCATION          IrpSp,
687c2c66affSColin Finck     PFILE_OBJECT                FileObject,
688c2c66affSColin Finck     PtrUDFFCB                   Fcb,
689c2c66affSColin Finck     PtrUDFCCB                   Ccb
690c2c66affSColin Finck     )
691c2c66affSColin Finck {
692c2c66affSColin Finck     NTSTATUS                    RC = STATUS_SUCCESS;
693c2c66affSColin Finck     BOOLEAN                     CompleteRequest = FALSE;
694c2c66affSColin Finck     BOOLEAN                     PostRequest = FALSE;
695c2c66affSColin Finck     PtrUDFNTRequiredFCB         NtReqFcb = NULL;
696c2c66affSColin Finck     BOOLEAN                     CanWait = FALSE;
697c2c66affSColin Finck     ULONG                       CompletionFilter = 0;
698c2c66affSColin Finck     BOOLEAN                     WatchTree = FALSE;
699*a91f5e8eSDoug Lyons     _SEH2_VOLATILE PVCB         Vcb = NULL;
700*a91f5e8eSDoug Lyons     _SEH2_VOLATILE BOOLEAN      AcquiredFCB = FALSE;
701c2c66affSColin Finck     PEXTENDED_IO_STACK_LOCATION pStackLocation = (PEXTENDED_IO_STACK_LOCATION) IrpSp;
702c2c66affSColin Finck 
703c2c66affSColin Finck     UDFPrint(("UDFNotifyChangeDirectory\n"));
704c2c66affSColin Finck 
705c2c66affSColin Finck     _SEH2_TRY {
706c2c66affSColin Finck 
707c2c66affSColin Finck         // Validate the sent-in FCB
708c2c66affSColin Finck         if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
709c2c66affSColin Finck             !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
710c2c66affSColin Finck 
711c2c66affSColin Finck             CompleteRequest = TRUE;
712c2c66affSColin Finck             try_return(RC = STATUS_INVALID_PARAMETER);
713c2c66affSColin Finck         }
714c2c66affSColin Finck 
715c2c66affSColin Finck         NtReqFcb = Fcb->NTRequiredFCB;
716c2c66affSColin Finck         CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
717c2c66affSColin Finck         Vcb = Fcb->Vcb;
718c2c66affSColin Finck 
719c2c66affSColin Finck         // Acquire the FCB resource shared
720c2c66affSColin Finck         UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
721c2c66affSColin Finck         if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) {
722c2c66affSColin Finck             PostRequest = TRUE;
723c2c66affSColin Finck             try_return(RC = STATUS_PENDING);
724c2c66affSColin Finck         }
725c2c66affSColin Finck         AcquiredFCB = TRUE;
726c2c66affSColin Finck 
727c2c66affSColin Finck         //  If the file is marked as DELETE_PENDING then complete this
728c2c66affSColin Finck         //  request immediately.
729c2c66affSColin Finck         if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
730c2c66affSColin Finck             ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
731c2c66affSColin Finck             try_return(RC = STATUS_DELETE_PENDING);
732c2c66affSColin Finck         }
733c2c66affSColin Finck 
734c2c66affSColin Finck         // Obtain some parameters sent by the caller
735c2c66affSColin Finck         CompletionFilter = pStackLocation ->Parameters.NotifyDirectory.CompletionFilter;
736c2c66affSColin Finck         WatchTree = (IrpSp->Flags & SL_WATCH_TREE) ? TRUE : FALSE;
737c2c66affSColin Finck 
738c2c66affSColin Finck         // If we wish to capture the subject context, we can do so as
739c2c66affSColin Finck         // follows:
740c2c66affSColin Finck         // {
741c2c66affSColin Finck         //      PSECURITY_SUBJECT_CONTEXT SubjectContext;
742c2c66affSColin Finck         //  SubjectContext = MyAllocatePool__(PagedPool,
743c2c66affSColin Finck         //                                  sizeof(SECURITY_SUBJECT_CONTEXT));
744c2c66affSColin Finck         //      SeCaptureSubjectContext(SubjectContext);
745c2c66affSColin Finck         //  }
746c2c66affSColin Finck 
747c2c66affSColin Finck         FsRtlNotifyFullChangeDirectory(Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb,
748c2c66affSColin Finck                             (Fcb->FileInfo->ParentFile) ? (PSTRING)&(Fcb->FCBName->ObjectName) : (PSTRING)&(UDFGlobalData.UnicodeStrRoot),
749c2c66affSColin Finck                             WatchTree, FALSE, CompletionFilter, Irp,
750c2c66affSColin Finck                             NULL,   // UDFTraverseAccessCheck(...) ?
751c2c66affSColin Finck                             NULL);  // SubjectContext ?
752c2c66affSColin Finck 
753c2c66affSColin Finck         RC = STATUS_PENDING;
754c2c66affSColin Finck 
755c2c66affSColin Finck         try_exit:   NOTHING;
756c2c66affSColin Finck 
757c2c66affSColin Finck     } _SEH2_FINALLY {
758c2c66affSColin Finck 
759c2c66affSColin Finck         if (PostRequest) {
760c2c66affSColin Finck             // Perform appropriate related post processing here
761c2c66affSColin Finck             if (AcquiredFCB) {
762c2c66affSColin Finck                 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
763c2c66affSColin Finck                 UDFReleaseResource(&(NtReqFcb->MainResource));
764c2c66affSColin Finck                 AcquiredFCB = FALSE;
765c2c66affSColin Finck             }
766c2c66affSColin Finck             RC = UDFPostRequest(PtrIrpContext, Irp);
767c2c66affSColin Finck         } else if (CompleteRequest) {
768c2c66affSColin Finck 
769c2c66affSColin Finck             if (!_SEH2_AbnormalTermination()) {
770c2c66affSColin Finck                 Irp->IoStatus.Status = RC;
771c2c66affSColin Finck                 Irp->IoStatus.Information = 0;
772c2c66affSColin Finck                 // Free up the Irp Context
773c2c66affSColin Finck                 UDFReleaseIrpContext(PtrIrpContext);
774c2c66affSColin Finck                 // complete the IRP
775c2c66affSColin Finck                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
776c2c66affSColin Finck             }
777c2c66affSColin Finck 
778c2c66affSColin Finck         } else {
779c2c66affSColin Finck             // Simply free up the IrpContext since the IRP has been queued
780c2c66affSColin Finck             if (!_SEH2_AbnormalTermination())
781c2c66affSColin Finck                 UDFReleaseIrpContext(PtrIrpContext);
782c2c66affSColin Finck         }
783c2c66affSColin Finck 
784c2c66affSColin Finck         // Release the FCB resources if acquired.
785c2c66affSColin Finck         if (AcquiredFCB) {
786c2c66affSColin Finck             UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
787c2c66affSColin Finck             UDFReleaseResource(&(NtReqFcb->MainResource));
788c2c66affSColin Finck             AcquiredFCB = FALSE;
789c2c66affSColin Finck         }
790c2c66affSColin Finck 
791c2c66affSColin Finck     } _SEH2_END;
792c2c66affSColin Finck 
793c2c66affSColin Finck     return(RC);
794c2c66affSColin Finck } // end UDFNotifyChangeDirectory()
795