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
34 #include "kernel_private.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(file
);
39 /****************************************************************************
40 * FindFirstChangeNotificationA (KERNEL32.@)
42 HANDLE WINAPI
FindFirstChangeNotificationA( LPCSTR lpPathName
, BOOL bWatchSubtree
,
43 DWORD dwNotifyFilter
)
47 if (!(pathW
= FILE_name_AtoW( lpPathName
, FALSE
))) return INVALID_HANDLE_VALUE
;
48 return FindFirstChangeNotificationW( pathW
, bWatchSubtree
, dwNotifyFilter
);
52 * NtNotifyChangeDirectoryFile may write back to the IO_STATUS_BLOCK
53 * asynchronously. We don't care about the contents, but it can't
54 * be placed on the stack since it will go out of scope when we return.
56 static IO_STATUS_BLOCK FindFirstChange_iosb
;
58 /****************************************************************************
59 * FindFirstChangeNotificationW (KERNEL32.@)
61 HANDLE WINAPI
FindFirstChangeNotificationW( LPCWSTR lpPathName
, BOOL bWatchSubtree
,
64 UNICODE_STRING nt_name
;
65 OBJECT_ATTRIBUTES attr
;
67 HANDLE handle
= INVALID_HANDLE_VALUE
;
69 TRACE( "%s %d %x\n", debugstr_w(lpPathName
), bWatchSubtree
, dwNotifyFilter
);
71 if (!RtlDosPathNameToNtPathName_U( lpPathName
, &nt_name
, NULL
, NULL
))
73 SetLastError( ERROR_PATH_NOT_FOUND
);
77 attr
.Length
= sizeof(attr
);
78 attr
.RootDirectory
= 0;
79 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
80 attr
.ObjectName
= &nt_name
;
81 attr
.SecurityDescriptor
= NULL
;
82 attr
.SecurityQualityOfService
= NULL
;
84 status
= NtOpenFile( &handle
, FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
85 &attr
, &FindFirstChange_iosb
,
86 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
87 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
88 RtlFreeUnicodeString( &nt_name
);
90 if (status
!= STATUS_SUCCESS
)
92 SetLastError( RtlNtStatusToDosError(status
) );
93 return INVALID_HANDLE_VALUE
;
96 status
= NtNotifyChangeDirectoryFile( handle
, NULL
, NULL
, NULL
,
97 &FindFirstChange_iosb
,
98 NULL
, 0, dwNotifyFilter
, bWatchSubtree
);
99 if (status
!= STATUS_PENDING
)
102 SetLastError( RtlNtStatusToDosError(status
) );
103 return INVALID_HANDLE_VALUE
;
108 /****************************************************************************
109 * FindNextChangeNotification (KERNEL32.@)
111 BOOL WINAPI
FindNextChangeNotification( HANDLE handle
)
115 TRACE("%p\n",handle
);
117 status
= NtNotifyChangeDirectoryFile( handle
, NULL
, NULL
, NULL
,
118 &FindFirstChange_iosb
,
119 NULL
, 0, FILE_NOTIFY_CHANGE_SIZE
, 0 );
120 if (status
!= STATUS_PENDING
)
122 SetLastError( RtlNtStatusToDosError(status
) );
128 /****************************************************************************
129 * FindCloseChangeNotification (KERNEL32.@)
131 BOOL WINAPI
FindCloseChangeNotification( HANDLE handle
)
133 return CloseHandle( handle
);
136 static void WINAPI
invoke_completion(LPVOID ctx
, IO_STATUS_BLOCK
*ios
, ULONG res
)
138 LPOVERLAPPED_COMPLETION_ROUTINE completion
= ctx
;
139 completion(ios
->u
.Status
, ios
->Information
, (LPOVERLAPPED
)ios
);
142 /****************************************************************************
143 * ReadDirectoryChangesW (KERNEL32.@)
147 * The filter is remember from the first run and ignored on successive runs.
149 * If there's no output buffer on the first run, it's ignored successive runs
150 * and STATUS_NOTIFY_ENUM_DIRECTORY is returned with an empty buffer.
152 * If a NULL overlapped->hEvent is passed, the directory handle is used
155 BOOL WINAPI
ReadDirectoryChangesW( HANDLE handle
, LPVOID buffer
, DWORD len
, BOOL subtree
,
156 DWORD filter
, LPDWORD returned
, LPOVERLAPPED overlapped
,
157 LPOVERLAPPED_COMPLETION_ROUTINE completion
)
160 IO_STATUS_BLOCK
*ios
;
163 LPVOID cvalue
= NULL
;
165 TRACE("%p %p %08x %d %08x %p %p %p\n", handle
, buffer
, len
, subtree
, filter
,
166 returned
, overlapped
, completion
);
170 memset( &ov
, 0, sizeof ov
);
171 ov
.hEvent
= CreateEventW( NULL
, 0, 0, NULL
);
177 if(completion
) cvalue
= completion
;
178 else if (((ULONG_PTR
)overlapped
->hEvent
& 1) == 0) cvalue
= overlapped
;
181 ios
= (PIO_STATUS_BLOCK
) pov
;
182 ios
->u
.Status
= STATUS_PENDING
;
184 status
= NtNotifyChangeDirectoryFile( handle
, completion
&& overlapped
? NULL
: pov
->hEvent
,
185 completion
&& overlapped
? invoke_completion
: NULL
,
186 cvalue
, ios
, buffer
, len
, filter
, subtree
);
187 if (status
== STATUS_PENDING
)
192 WaitForSingleObjectEx( ov
.hEvent
, INFINITE
, TRUE
);
194 *returned
= ios
->Information
;
195 status
= ios
->u
.Status
;
199 CloseHandle( ov
.hEvent
);
201 if (status
!= STATUS_SUCCESS
)
203 SetLastError( RtlNtStatusToDosError(status
) );