2 * Win32 file change notification functions
4 * Copyright 1998 Ulrich Weigand
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #define WIN32_NO_STATUS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
35 #include "kernel_private.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(file);
40 /****************************************************************************
41 * FindFirstChangeNotificationA (KERNEL32.@)
43 HANDLE WINAPI FindFirstChangeNotificationA( LPCSTR lpPathName, BOOL bWatchSubtree,
44 DWORD dwNotifyFilter )
48 if (!(pathW = FILE_name_AtoW( lpPathName, FALSE ))) return INVALID_HANDLE_VALUE;
49 return FindFirstChangeNotificationW( pathW, bWatchSubtree, dwNotifyFilter );
53 * NtNotifyChangeDirectoryFile may write back to the IO_STATUS_BLOCK
54 * asynchronously. We don't care about the contents, but it can't
55 * be placed on the stack since it will go out of scope when we return.
57 static IO_STATUS_BLOCK FindFirstChange_iosb;
59 /****************************************************************************
60 * FindFirstChangeNotificationW (KERNEL32.@)
62 HANDLE WINAPI FindFirstChangeNotificationW( LPCWSTR lpPathName, BOOL bWatchSubtree,
65 UNICODE_STRING nt_name;
66 OBJECT_ATTRIBUTES attr;
68 HANDLE handle = INVALID_HANDLE_VALUE;
70 TRACE( "%s %d %x\n", debugstr_w(lpPathName), bWatchSubtree, dwNotifyFilter );
72 if (!RtlDosPathNameToNtPathName_U( lpPathName, &nt_name, NULL, NULL ))
74 SetLastError( ERROR_PATH_NOT_FOUND );
78 attr.Length = sizeof(attr);
79 attr.RootDirectory = 0;
80 attr.Attributes = OBJ_CASE_INSENSITIVE;
81 attr.ObjectName = &nt_name;
82 attr.SecurityDescriptor = NULL;
83 attr.SecurityQualityOfService = NULL;
85 status = NtOpenFile( &handle, FILE_LIST_DIRECTORY | SYNCHRONIZE,
86 &attr, &FindFirstChange_iosb,
87 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
88 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
89 RtlFreeUnicodeString( &nt_name );
91 if (status != STATUS_SUCCESS)
93 SetLastError( RtlNtStatusToDosError(status) );
94 return INVALID_HANDLE_VALUE;
97 status = NtNotifyChangeDirectoryFile( handle, NULL, NULL, NULL,
98 &FindFirstChange_iosb,
99 NULL, 0, dwNotifyFilter, bWatchSubtree );
100 if (status != STATUS_PENDING)
103 SetLastError( RtlNtStatusToDosError(status) );
104 return INVALID_HANDLE_VALUE;
109 /****************************************************************************
110 * FindNextChangeNotification (KERNEL32.@)
112 BOOL WINAPI FindNextChangeNotification( HANDLE handle )
116 TRACE("%p\n",handle);
118 status = NtNotifyChangeDirectoryFile( handle, NULL, NULL, NULL,
119 &FindFirstChange_iosb,
120 NULL, 0, FILE_NOTIFY_CHANGE_SIZE, 0 );
121 if (status != STATUS_PENDING)
123 SetLastError( RtlNtStatusToDosError(status) );
129 /****************************************************************************
130 * FindCloseChangeNotification (KERNEL32.@)
132 BOOL WINAPI FindCloseChangeNotification( HANDLE handle )
134 return CloseHandle( handle );
137 static void WINAPI invoke_completion(LPVOID ctx, IO_STATUS_BLOCK *ios, ULONG res)
139 LPOVERLAPPED_COMPLETION_ROUTINE completion = ctx;
140 completion(ios->u.Status, ios->Information, (LPOVERLAPPED)ios);
143 /****************************************************************************
144 * ReadDirectoryChangesW (KERNEL32.@)
148 * The filter is remember from the first run and ignored on successive runs.
150 * If there's no output buffer on the first run, it's ignored successive runs
151 * and STATUS_NOTIFY_ENUM_DIRECTORY is returned with an empty buffer.
153 * If a NULL overlapped->hEvent is passed, the directory handle is used
156 BOOL WINAPI ReadDirectoryChangesW( HANDLE handle, LPVOID buffer, DWORD len, BOOL subtree,
157 DWORD filter, LPDWORD returned, LPOVERLAPPED overlapped,
158 LPOVERLAPPED_COMPLETION_ROUTINE completion )
161 IO_STATUS_BLOCK *ios;
164 LPVOID cvalue = NULL;
166 TRACE("%p %p %08x %d %08x %p %p %p\n", handle, buffer, len, subtree, filter,
167 returned, overlapped, completion );
171 memset( &ov, 0, sizeof ov );
172 ov.hEvent = CreateEventW( NULL, 0, 0, NULL );
178 if(completion) cvalue = completion;
179 else if (((ULONG_PTR)overlapped->hEvent & 1) == 0) cvalue = overlapped;
182 ios = (PIO_STATUS_BLOCK) pov;
183 ios->u.Status = STATUS_PENDING;
185 status = NtNotifyChangeDirectoryFile( handle, completion && overlapped ? NULL : pov->hEvent,
186 completion && overlapped ? invoke_completion : NULL,
187 cvalue, ios, buffer, len, filter, subtree );
188 if (status == STATUS_PENDING)
193 WaitForSingleObjectEx( ov.hEvent, INFINITE, TRUE );
194 CloseHandle( ov.hEvent );
196 *returned = ios->Information;
197 status = ios->u.Status;
200 if (status != STATUS_SUCCESS)
202 SetLastError( RtlNtStatusToDosError(status) );