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
) );