2 * Tests for file change notification functions
4 * Copyright (c) 2004 Hans Leidekker
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* TODO: - security attribute changes
22 * - compound filter and multiple notifications
23 * - subtree notifications
24 * - non-documented flags FILE_NOTIFY_CHANGE_LAST_ACCESS and
25 * FILE_NOTIFY_CHANGE_CREATION
31 #include "wine/test.h"
35 static DWORD CALLBACK
NotificationThread(LPVOID arg
)
37 HANDLE change
= (HANDLE
) arg
;
41 status
= WaitForSingleObject(change
, 100);
43 if (status
== WAIT_OBJECT_0
) {
44 ret
= FindNextChangeNotification(change
);
47 ok(FindCloseChangeNotification(change
), "FindCloseChangeNotification error: %ld\n",
50 ExitThread((DWORD
)ret
);
53 static HANDLE
StartNotificationThread(LPCSTR path
, BOOL subtree
, DWORD flags
)
55 HANDLE change
, thread
;
58 change
= FindFirstChangeNotificationA(path
, subtree
, flags
);
59 ok(change
!= INVALID_HANDLE_VALUE
, "FindFirstChangeNotification error: %ld\n", GetLastError());
61 thread
= CreateThread(NULL
, 0, (LPTHREAD_START_ROUTINE
)NotificationThread
, (LPVOID
)change
,
63 ok(thread
!= INVALID_HANDLE_VALUE
, "CreateThread error: %ld\n", GetLastError());
68 static DWORD
FinishNotificationThread(HANDLE thread
)
70 DWORD status
, exitcode
;
72 status
= WaitForSingleObject(thread
, 5000);
73 ok(status
== WAIT_OBJECT_0
, "WaitForSingleObject status %ld error %ld\n", status
, GetLastError());
75 ok(GetExitCodeThread(thread
, &exitcode
), "Could not retrieve thread exit code\n");
80 static void test_FindFirstChangeNotification(void)
82 HANDLE change
, file
, thread
;
83 DWORD attributes
, count
;
86 char workdir
[MAX_PATH
], dirname1
[MAX_PATH
], dirname2
[MAX_PATH
];
87 char filename1
[MAX_PATH
], filename2
[MAX_PATH
];
88 static const char prefix
[] = "FCN";
93 change
= FindFirstChangeNotificationA("not-a-file", FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
94 ok(change
== INVALID_HANDLE_VALUE
&& GetLastError() == ERROR_FILE_NOT_FOUND
,
95 "FindFirstChangeNotification error: %ld\n", GetLastError());
97 if (0) /* This documents win2k behavior. It crashes on win98. */
99 change
= FindFirstChangeNotificationA(NULL
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
100 ok(change
== NULL
&& GetLastError() == ERROR_PATH_NOT_FOUND
,
101 "FindFirstChangeNotification error: %ld\n", GetLastError());
104 ret
= FindNextChangeNotification(NULL
);
105 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "FindNextChangeNotification error: %ld\n",
108 ret
= FindCloseChangeNotification(NULL
);
109 ok(!ret
&& GetLastError() == ERROR_INVALID_HANDLE
, "FindCloseChangeNotification error: %ld\n",
112 ret
= GetTempPathA(MAX_PATH
, workdir
);
113 ok(ret
, "GetTempPathA error: %ld\n", GetLastError());
115 lstrcatA(workdir
, "testFileChangeNotification");
117 ret
= CreateDirectoryA(workdir
, NULL
);
118 ok(ret
, "CreateDirectoryA error: %ld\n", GetLastError());
120 ret
= GetTempFileNameA(workdir
, prefix
, 0, filename1
);
121 ok(ret
, "GetTempFileNameA error: %ld\n", GetLastError());
123 file
= CreateFileA(filename1
, GENERIC_WRITE
|GENERIC_READ
, 0, NULL
, CREATE_ALWAYS
,
124 FILE_ATTRIBUTE_NORMAL
, 0);
125 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
126 ok(CloseHandle(file
), "CloseHandle error: %ld\n", GetLastError());
128 /* Try to register notification for a file. win98 and win2k behave differently here */
129 change
= FindFirstChangeNotificationA(filename1
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
130 ok(change
== INVALID_HANDLE_VALUE
&& (GetLastError() == ERROR_DIRECTORY
||
131 GetLastError() == ERROR_FILE_NOT_FOUND
),
132 "FindFirstChangeNotification error: %ld\n", GetLastError());
134 lstrcpyA(dirname1
, filename1
);
135 lstrcatA(dirname1
, "dir");
137 ret
= CreateDirectoryA(dirname1
, NULL
);
138 ok(ret
, "CreateDirectoryA error: %ld\n", GetLastError());
140 /* What if we remove the directory we registered notification for? */
141 thread
= StartNotificationThread(dirname1
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
142 ret
= RemoveDirectoryA(dirname1
);
143 ok(ret
, "RemoveDirectoryA error: %ld\n", GetLastError());
145 /* win98 and win2k behave differently here */
146 ret
= FinishNotificationThread(thread
);
147 ok(ret
|| !ret
, "You'll never read this\n");
149 /* functional checks */
151 /* Create a directory */
152 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
153 ret
= CreateDirectoryA(dirname1
, NULL
);
154 ok(ret
, "CreateDirectoryA error: %ld\n", GetLastError());
155 ok(FinishNotificationThread(thread
), "Missed notification\n");
157 lstrcpyA(dirname2
, dirname1
);
158 lstrcatA(dirname2
, "new");
160 /* Rename a directory */
161 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
162 ret
= MoveFileA(dirname1
, dirname2
);
163 ok(ret
, "MoveFileA error: %ld\n", GetLastError());
164 ok(FinishNotificationThread(thread
), "Missed notification\n");
166 /* Delete a directory */
167 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_DIR_NAME
);
168 ret
= RemoveDirectoryA(dirname2
);
169 ok(ret
, "RemoveDirectoryA error: %ld\n", GetLastError());
170 ok(FinishNotificationThread(thread
), "Missed notification\n");
172 lstrcpyA(filename2
, filename1
);
173 lstrcatA(filename2
, "new");
176 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
177 ret
= MoveFileA(filename1
, filename2
);
178 ok(ret
, "MoveFileA error: %ld\n", GetLastError());
179 ok(FinishNotificationThread(thread
), "Missed notification\n");
182 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
183 ret
= DeleteFileA(filename2
);
184 ok(ret
, "DeleteFileA error: %ld\n", GetLastError());
185 ok(FinishNotificationThread(thread
), "Missed notification\n");
188 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_FILE_NAME
);
189 file
= CreateFileA(filename2
, GENERIC_WRITE
|GENERIC_READ
, 0, NULL
, CREATE_ALWAYS
,
190 FILE_ATTRIBUTE_NORMAL
, 0);
191 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
192 ok(CloseHandle(file
), "CloseHandle error: %ld\n", GetLastError());
193 ok(FinishNotificationThread(thread
), "Missed notification\n");
195 attributes
= GetFileAttributesA(filename2
);
196 ok(attributes
!= INVALID_FILE_ATTRIBUTES
, "GetFileAttributesA error: %ld\n", GetLastError());
197 attributes
&= FILE_ATTRIBUTE_READONLY
;
199 /* Change file attributes */
200 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_ATTRIBUTES
);
201 ret
= SetFileAttributesA(filename2
, attributes
);
202 ok(ret
, "SetFileAttributesA error: %ld\n", GetLastError());
203 ok(FinishNotificationThread(thread
), "Missed notification\n");
205 /* Change last write time by writing to a file */
206 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_LAST_WRITE
);
207 file
= CreateFileA(filename2
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
208 FILE_ATTRIBUTE_NORMAL
, 0);
209 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
210 ret
= WriteFile(file
, buffer
, sizeof(buffer
), &count
, NULL
);
211 ok(ret
&& count
== sizeof(buffer
), "WriteFile error: %ld\n", GetLastError());
212 ok(CloseHandle(file
), "CloseHandle error: %ld\n", GetLastError());
213 ok(FinishNotificationThread(thread
), "Missed notification\n");
215 /* Change file size by truncating a file */
216 thread
= StartNotificationThread(workdir
, FALSE
, FILE_NOTIFY_CHANGE_SIZE
);
217 file
= CreateFileA(filename2
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
218 FILE_ATTRIBUTE_NORMAL
, 0);
219 ok(file
!= INVALID_HANDLE_VALUE
, "CreateFileA error: %ld\n", GetLastError());
220 ret
= WriteFile(file
, buffer
, sizeof(buffer
) / 2, &count
, NULL
);
221 ok(ret
&& count
== sizeof(buffer
) / 2, "WriteFileA error: %ld\n", GetLastError());
222 ok(CloseHandle(file
), "CloseHandle error: %ld\n", GetLastError());
223 ok(FinishNotificationThread(thread
), "Missed notification\n");
227 ret
= DeleteFileA(filename2
);
228 ok(ret
, "DeleteFileA error: %ld\n", GetLastError());
230 ret
= RemoveDirectoryA(workdir
);
231 ok(ret
, "RemoveDirectoryA error: %ld\n", GetLastError());
236 test_FindFirstChangeNotification();