2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/find.c
5 * PURPOSE: Find functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
11 /* INCLUDES *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 CHAR staticchangebuff
[sizeof(FILE_NOTIFY_INFORMATION
) + 16];
20 IO_STATUS_BLOCK staticIoStatusBlock
;
22 /* PRIVATE FUNCTIONS **********************************************************/
26 BasepIoCompletion(IN PVOID ApcContext
,
27 IN PIO_STATUS_BLOCK IoStatusBlock
,
30 PBASEP_ACTCTX_BLOCK ActivationBlock
= ApcContext
;
31 LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
;
32 DWORD BytesTransfered
, Result
;
33 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActCtx
;
34 PVOID ActivationContext
= NULL
;
36 /* Setup the activation frame */
37 RtlZeroMemory(&ActCtx
, sizeof(ActCtx
));
38 ActCtx
.Size
= sizeof(ActCtx
);
39 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
41 /* Check if the routine returned an error */
42 if (NT_ERROR(IoStatusBlock
->Status
))
44 /* Convert the error code and don't copy anything */
45 Result
= RtlNtStatusToDosError(IoStatusBlock
->Status
);
50 /* Set success code and copy the bytes transferred */
51 Result
= ERROR_SUCCESS
;
52 BytesTransfered
= IoStatusBlock
->Information
;
55 /* Read context and routine out from the activation block */
56 ActivationContext
= ActivationBlock
->ActivationContext
;
57 CompletionRoutine
= ActivationBlock
->CompletionRoutine
;
59 /* Check if the block should be freed */
60 if (!(ActivationBlock
->Flags
& 1))
63 BasepFreeActivationContextActivationBlock(ActivationBlock
);
66 /* Activate the context, call the routine, and then deactivate the context */
67 RtlActivateActivationContextUnsafeFast(&ActCtx
, ActivationContext
);
68 CompletionRoutine(Result
, BytesTransfered
, (LPOVERLAPPED
)IoStatusBlock
);
69 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
74 BasepIoCompletionSimple(IN PVOID ApcContext
,
75 IN PIO_STATUS_BLOCK IoStatusBlock
,
78 LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
= ApcContext
;
79 DWORD Result
, BytesTransfered
;
81 /* Check if the routine returned an error */
82 if (NT_ERROR(IoStatusBlock
->Status
))
84 /* Convert the error code and don't copy anything */
85 Result
= RtlNtStatusToDosError(IoStatusBlock
->Status
);
90 /* Set success code and copy the bytes transferred */
91 Result
= ERROR_SUCCESS
;
92 BytesTransfered
= IoStatusBlock
->Information
;
95 /* Call the callback routine */
96 CompletionRoutine(Result
, BytesTransfered
, (LPOVERLAPPED
)IoStatusBlock
);
99 /* PUBLIC FUNCTIONS ***********************************************************/
106 FindCloseChangeNotification(IN HANDLE hChangeHandle
)
108 /* Just close the handle */
109 return CloseHandle(hChangeHandle
);
117 FindFirstChangeNotificationA(IN LPCSTR lpPathName
,
118 IN BOOL bWatchSubtree
,
119 IN DWORD dwNotifyFilter
)
121 /* Call the W(ide) function */
122 ConvertWin32AnsiChangeApiToUnicodeApi(FindFirstChangeNotification
,
133 FindFirstChangeNotificationW(IN LPCWSTR lpPathName
,
134 IN BOOL bWatchSubtree
,
135 IN DWORD dwNotifyFilter
)
138 UNICODE_STRING NtPathU
;
139 OBJECT_ATTRIBUTES ObjectAttributes
;
141 RTL_RELATIVE_NAME_U RelativeName
;
143 IO_STATUS_BLOCK IoStatusBlock
;
145 /* Convert to NT path and get the relative name too */
146 if (!RtlDosPathNameToNtPathName_U(lpPathName
,
151 /* Bail out if the path name makes no sense */
152 SetLastError(ERROR_PATH_NOT_FOUND
);
153 return INVALID_HANDLE_VALUE
;
156 /* Save the path buffer in case we free it later */
157 PathBuffer
= NtPathU
.Buffer
;
159 /* If we have a relative name... */
160 if (RelativeName
.RelativeName
.Length
)
162 /* Do a relative open with only the relative path set */
163 NtPathU
= RelativeName
.RelativeName
;
167 /* Do a full path open with no containing directory */
168 RelativeName
.ContainingDirectory
= NULL
;
171 /* Now open the directory name that was passed in */
172 InitializeObjectAttributes(&ObjectAttributes
,
174 OBJ_CASE_INSENSITIVE
,
175 RelativeName
.ContainingDirectory
,
177 Status
= NtOpenFile(&hDir
,
178 SYNCHRONIZE
| FILE_LIST_DIRECTORY
,
181 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
182 FILE_DIRECTORY_FILE
| FILE_OPEN_FOR_BACKUP_INTENT
);
184 /* Release our buffer and relative name structure */
185 RtlReleaseRelativeName(&RelativeName
);
186 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
188 /* Check if the open failed */
189 if (!NT_SUCCESS(Status
))
191 /* Bail out in that case */
192 BaseSetLastNTError(Status
);
193 return INVALID_HANDLE_VALUE
;
196 /* Now setup the notification on the directory as requested */
197 Status
= NtNotifyChangeDirectoryFile(hDir
,
201 &staticIoStatusBlock
,
203 sizeof(staticchangebuff
),
205 (BOOLEAN
)bWatchSubtree
);
206 if (!NT_SUCCESS(Status
))
208 /* We failed, close the handle and convert the error */
210 BaseSetLastNTError(Status
);
211 hDir
= INVALID_HANDLE_VALUE
;
214 /* Return the directory handle on success, or invalid handle otherwise */
223 FindNextChangeNotification(IN HANDLE hChangeHandle
)
227 /* Just call the native API directly, dealing with the non-optional parameters */
228 Status
= NtNotifyChangeDirectoryFile(hChangeHandle
,
232 &staticIoStatusBlock
,
234 sizeof(staticchangebuff
),
235 FILE_NOTIFY_CHANGE_SECURITY
,
237 if (!NT_SUCCESS(Status
))
239 /* Convert the error code and fail */
240 BaseSetLastNTError(Status
);
253 ReadDirectoryChangesW(IN HANDLE hDirectory
,
254 IN LPVOID lpBuffer OPTIONAL
,
255 IN DWORD nBufferLength
,
256 IN BOOL bWatchSubtree
,
257 IN DWORD dwNotifyFilter
,
258 OUT LPDWORD lpBytesReturned
,
259 IN LPOVERLAPPED lpOverlapped OPTIONAL
,
260 IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
266 PIO_APC_ROUTINE ApcRoutine
;
267 PBASEP_ACTCTX_BLOCK ActivationContext
= NULL
;
269 IO_STATUS_BLOCK IoStatusBlock
;
271 /* Is the caller doing this synchronously? */
274 /* Great, just pass in the parameters */
275 Status
= NtNotifyChangeDirectoryFile(hDirectory
,
284 if (Status
== STATUS_PENDING
)
286 /* Wait for completion since we are synchronous */
287 Status
= NtWaitForSingleObject(hDirectory
, FALSE
, NULL
);
288 if (!NT_SUCCESS(Status
))
290 /* The wait failed, bail out */
291 BaseSetLastNTError(Status
);
295 /* Retrieve the final status code */
296 Status
= IoStatusBlock
.Status
;
299 /* Did the operation succeed? */
300 if (NT_SUCCESS(Status
))
302 /* Return the bytes transferd and success */
303 *lpBytesReturned
= IoStatusBlock
.Information
;
307 /* Convert error code and return failure */
308 BaseSetLastNTError(Status
);
312 /* Does the caller want an APC callbac? */
313 if (lpCompletionRoutine
)
315 /* Don't use an event in this case */
318 /* Allocate a Fusion/SxS activation context for the callback routine */
319 Status
= BasepAllocateActivationContextActivationBlock(1 | 2,
323 if (!NT_SUCCESS(Status
))
325 /* This failed, so abandon the call */
326 BaseSetLastNTError(Status
);
330 /* Use the SxS context as the APC context */
331 ApcContext
= ActivationContext
;
332 if (ActivationContext
)
334 /* And use a special stub routine that deals with activation */
335 ApcRoutine
= BasepIoCompletion
;
339 /* If there was no context, however, use the simple stub routine */
340 ApcContext
= lpCompletionRoutine
;
341 ApcRoutine
= BasepIoCompletionSimple
;
346 /* Use the even with no APC routine */
347 EventHandle
= lpOverlapped
->hEvent
;
350 /* LPOVERLAPPED should be ignored if event is ORed with 1 */
351 ApcContext
= (ULONG_PTR
)lpOverlapped
->hEvent
& 1 ? NULL
: lpOverlapped
;
354 /* Set the initial status to pending and call the native API */
355 lpOverlapped
->Internal
= STATUS_PENDING
;
356 Status
= NtNotifyChangeDirectoryFile(hDirectory
,
360 (PIO_STATUS_BLOCK
)lpOverlapped
,
364 (BOOLEAN
)bWatchSubtree
);
365 if (NT_ERROR(Status
))
367 /* Normally we cleanup the context in the completon routine, but we failed */
368 if (ActivationContext
) BasepFreeActivationContextActivationBlock(ActivationContext
);
370 /* Convert the error and fail */
371 BaseSetLastNTError(Status
);