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