Fixes: debbugs:17865
[bpt/emacs.git] / src / w32notify.c
CommitLineData
6f011d81 1/* Filesystem notifications support for GNU Emacs on the Microsoft Windows API.
ba318903 2 Copyright (C) 2012-2014 Free Software Foundation, Inc.
6f011d81
EZ
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18
f282b9f7
EZ
19/* Written by Eli Zaretskii <eliz@gnu.org>.
20
21 Design overview:
c5c91b84
EZ
22
23 For each watch request, we launch a separate worker thread. The
24 worker thread runs the watch_worker function, which issues an
f282b9f7
EZ
25 asynchronous call to ReadDirectoryChangesW, and then waits in
26 SleepEx for that call to complete. Waiting in SleepEx puts the
27 thread in an "alertable" state, so it wakes up when either (a) the
28 call to ReadDirectoryChangesW completes, or (b) the main thread
29 instructs the worker thread to terminate by sending it an APC, see
30 below.
c5c91b84
EZ
31
32 When the ReadDirectoryChangesW call completes, its completion
33 routine watch_completion is automatically called. watch_completion
34 stashes the received file events in a buffer used to communicate
35 them to the main thread (using a critical section, so that several
36 threads could use the same buffer), posts a special message,
37 WM_EMACS_FILENOTIFY, to the Emacs's message queue, and returns.
38 That causes the SleepEx function call inside watch_worker to
39 return, and watch_worker then issues another call to
40 ReadDirectoryChangesW. (Except when it does not, see below.)
41
a0eb10b3 42 In a GUI session, the WM_EMACS_FILENOTIFY message posted to the
977c6479
EZ
43 message queue gets dispatched to the main Emacs window procedure,
44 which queues it for processing by w32_read_socket. When
45 w32_read_socket sees this message, it accesses the buffer with file
46 notifications (using a critical section), extracts the information,
47 converts it to a series of FILE_NOTIFY_EVENT events, and stuffs
48 them into the input event queue to be processed by keyboard.c input
49 machinery (read_char via a call to kbd_buffer_get_event).
50
51 In a non-GUI session, we send the WM_EMACS_FILENOTIFY message to
52 the main (a.k.a. "Lisp") thread instead, since there are no window
53 procedures in console programs. That message wakes up
54 MsgWaitForMultipleObjects inside sys_select, which then signals to
55 its caller that some keyboard input is available. This causes
56 w32_console_read_socket to be called, which accesses the buffer
57 with file notifications and stuffs them into the input event queue
58 for keyboard.c to process.
59
60 When the FILE_NOTIFY_EVENT event is processed by keyboard.c's
61 kbd_buffer_get_event, it is converted to a Lispy event that can be
102ae68d 62 bound to a command. The default binding is file-notify-handle-event,
977c6479
EZ
63 defined on subr.el.
64
f282b9f7
EZ
65 After w32_read_socket or w32_console_read_socket are done
66 processing the notifications, they reset a flag signaling to all
67 watch worker threads that the notifications buffer is available for
68 more input.
c5c91b84
EZ
69
70 When the watch is removed by a call to w32notify-rm-watch, the main
71 thread requests that the worker thread terminates by queuing an APC
72 for the worker thread. The APC specifies the watch_end function to
73 be called. watch_end calls CancelIo on the outstanding
74 ReadDirectoryChangesW call and closes the handle on which the
75 watched directory was open. When watch_end returns, the
76 watch_completion function is called one last time with the
77 ERROR_OPERATION_ABORTED status, which causes it to clean up and set
78 a flag telling watch_worker to exit without issuing another
f282b9f7
EZ
79 ReadDirectoryChangesW call. Since watch_worker is the thread
80 procedure of the worker thread, exiting it causes the thread to
81 exit. The main thread waits for some time for the worker thread to
82 exit, and if it doesn't, terminates it forcibly. */
c5c91b84 83
6f011d81
EZ
84#include <stddef.h>
85#include <errno.h>
86
87/* must include CRT headers *before* config.h */
88#include <config.h>
89
90#include <windows.h>
91
92#include "lisp.h"
93#include "w32term.h" /* for enter_crit/leave_crit and WM_EMACS_FILENOTIFY */
eb3abb61 94#include "w32common.h" /* for OS version data */
6f011d81
EZ
95#include "w32.h" /* for w32_strerror */
96#include "coding.h"
97#include "keyboard.h"
98#include "frame.h" /* needed by termhooks.h */
99#include "termhooks.h" /* for FILE_NOTIFY_EVENT */
100
37a4dabe
EZ
101#define DIRWATCH_SIGNATURE 0x01233210
102
6f011d81
EZ
103struct notification {
104 BYTE *buf; /* buffer for ReadDirectoryChangesW */
105 OVERLAPPED *io_info; /* the OVERLAPPED structure for async I/O */
106 BOOL subtree; /* whether to watch subdirectories */
107 DWORD filter; /* bit mask for events to watch */
439b1ae8 108 char *watchee; /* the file we are interested in, UTF-8 encoded */
6f011d81
EZ
109 HANDLE dir; /* handle to the watched directory */
110 HANDLE thr; /* handle to the thread that watches */
0b86d359 111 volatile int terminate; /* if non-zero, request for the thread to terminate */
37a4dabe 112 unsigned signature;
6f011d81
EZ
113};
114
6f011d81 115/* Used for communicating notifications to the main thread. */
0b86d359 116volatile int notification_buffer_in_use;
6f011d81
EZ
117BYTE file_notifications[16384];
118DWORD notifications_size;
37a4dabe 119void *notifications_desc;
6f011d81
EZ
120
121static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize;
122static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time;
123static Lisp_Object Qsecurity_desc, Qsubtree, watch_list;
124
6f011d81
EZ
125/* Signal to the main thread that we have file notifications for it to
126 process. */
127static void
0b86d359
EZ
128send_notifications (BYTE *info, DWORD info_size, void *desc,
129 volatile int *terminate)
6f011d81
EZ
130{
131 int done = 0;
a10c8269 132 struct frame *f = SELECTED_FRAME ();
6f011d81 133
6f011d81
EZ
134 /* A single buffer is used to communicate all notifications to the
135 main thread. Since both the main thread and several watcher
136 threads could be active at the same time, we use a critical area
137 and an "in-use" flag to synchronize them. A watcher thread can
138 only put its notifications in the buffer if it acquires the
139 critical area and finds the "in-use" flag reset. The main thread
140 resets the flag after it is done processing notifications.
141
142 FIXME: is there a better way of dealing with this? */
143 while (!done && !*terminate)
144 {
145 enter_crit ();
146 if (!notification_buffer_in_use)
147 {
148 if (info_size)
149 memcpy (file_notifications, info, info_size);
150 notifications_size = info_size;
37a4dabe 151 notifications_desc = desc;
977c6479
EZ
152 /* If PostMessage fails, the message queue is full. If that
153 happens, the last thing they will worry about is file
154 notifications. So we effectively discard the
155 notification in that case. */
156 if ((FRAME_TERMCAP_P (f)
157 /* We send the message to the main (a.k.a. "Lisp")
158 thread, where it will wake up MsgWaitForMultipleObjects
159 inside sys_select, causing it to report that there's
160 some keyboard input available. This will in turn cause
161 w32_console_read_socket to be called, which will pick
162 up the file notifications. */
163 && PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0))
182b170f 164 || (FRAME_W32_P (f)
182b170f 165 && PostMessage (FRAME_W32_WINDOW (f),
9c099ca7
EZ
166 WM_EMACS_FILENOTIFY, 0, 0))
167 /* When we are running in batch mode, there's no one to
168 send a message, so we just signal the data is
169 available and hope sys_select will be called soon and
170 will read the data. */
171 || (FRAME_INITIAL_P (f) && noninteractive))
6f011d81
EZ
172 notification_buffer_in_use = 1;
173 done = 1;
6f011d81
EZ
174 }
175 leave_crit ();
176 if (!done)
177 Sleep (5);
178 }
179}
180
181/* An APC routine to cancel outstanding directory watch. Invoked by
182 the main thread via QueueUserAPC. This is needed because only the
183 thread that issued the ReadDirectoryChangesW call can call CancelIo
184 to cancel that. (CancelIoEx is only available since Vista, so we
185 cannot use it on XP.) */
186VOID CALLBACK
187watch_end (ULONG_PTR arg)
188{
189 HANDLE hdir = (HANDLE)arg;
190
191 if (hdir && hdir != INVALID_HANDLE_VALUE)
192 {
193 CancelIo (hdir);
194 CloseHandle (hdir);
195 }
196}
197
f282b9f7
EZ
198/* A completion routine (a.k.a. "APC function") for handling events
199 read by ReadDirectoryChangesW. Called by the OS when the thread
200 which issued the asynchronous ReadDirectoryChangesW call is in the
6f011d81
EZ
201 "alertable state", i.e. waiting inside SleepEx call. */
202VOID CALLBACK
203watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info)
204{
205 struct notification *dirwatch;
206
207 /* Who knows what happened? Perhaps the OVERLAPPED structure was
208 freed by someone already? In any case, we cannot do anything
209 with this request, so just punt and skip it. FIXME: should we
210 raise the 'terminate' flag in this case? */
211 if (!io_info)
212 return;
213
214 /* We have a pointer to our dirwatch structure conveniently stashed
215 away in the hEvent member of the OVERLAPPED struct. According to
216 MSDN documentation of ReadDirectoryChangesW: "The hEvent member
217 of the OVERLAPPED structure is not used by the system, so you can
218 use it yourself." */
219 dirwatch = (struct notification *)io_info->hEvent;
220 if (status == ERROR_OPERATION_ABORTED)
221 {
222 /* We've been called because the main thread told us to issue
223 CancelIo on the directory we watch, and watch_end did so.
224 The directory handle is already closed. We should clean up
4a0e1924 225 and exit, signaling to the thread worker routine not to
37a4dabe 226 issue another call to ReadDirectoryChangesW. Note that we
9e1821d3
EZ
227 don't free the dirwatch object itself nor the memory consumed
228 by its buffers; this is done by the main thread in
229 remove_watch. Calling malloc/free from a thread other than
230 the main thread is a no-no. */
7d605354 231 dirwatch->dir = NULL;
6f011d81
EZ
232 dirwatch->terminate = 1;
233 }
234 else
235 {
6f011d81 236 /* Tell the main thread we have notifications for it. */
37a4dabe 237 send_notifications (dirwatch->buf, bytes_ret, dirwatch,
6f011d81
EZ
238 &dirwatch->terminate);
239 }
240}
241
242/* Worker routine for the watch thread. */
243static DWORD WINAPI
244watch_worker (LPVOID arg)
245{
246 struct notification *dirwatch = (struct notification *)arg;
247
248 do {
249 BOOL status;
250 DWORD sleep_result;
251 DWORD bytes_ret = 0;
252
253 if (dirwatch->dir)
254 {
255 status = ReadDirectoryChangesW (dirwatch->dir, dirwatch->buf, 16384,
256 dirwatch->subtree, dirwatch->filter,
257 &bytes_ret,
258 dirwatch->io_info, watch_completion);
259 if (!status)
260 {
c5c91b84 261 DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ()));
37a4dabe 262 /* We cannot remove the dirwatch object from watch_list,
9e1821d3
EZ
263 because we are in a separate thread. For the same
264 reason, we also cannot free memory consumed by the
265 buffers allocated for the dirwatch object. So we close
266 the directory handle, but do not free the object itself
267 or its buffers. We also don't touch the signature.
268 This way, remove_watch can still identify the object,
269 remove it, and free its memory. */
6f011d81
EZ
270 CloseHandle (dirwatch->dir);
271 dirwatch->dir = NULL;
6f011d81
EZ
272 return 1;
273 }
274 }
275 /* Sleep indefinitely until awoken by the I/O completion, which
276 could be either a change notification or a cancellation of the
277 watch. */
278 sleep_result = SleepEx (INFINITE, TRUE);
6f011d81
EZ
279 } while (!dirwatch->terminate);
280
6f011d81
EZ
281 return 0;
282}
283
284/* Launch a thread to watch changes to FILE in a directory open on
285 handle HDIR. */
37a4dabe 286static struct notification *
6f011d81
EZ
287start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags)
288{
37a4dabe
EZ
289 struct notification *dirwatch = xzalloc (sizeof (struct notification));
290 HANDLE thr;
291
292 dirwatch->signature = DIRWATCH_SIGNATURE;
293 dirwatch->buf = xmalloc (16384);
294 dirwatch->io_info = xzalloc (sizeof(OVERLAPPED));
6f011d81
EZ
295 /* Stash a pointer to dirwatch structure for use by the completion
296 routine. According to MSDN documentation of ReadDirectoryChangesW:
297 "The hEvent member of the OVERLAPPED structure is not used by the
298 system, so you can use it yourself." */
37a4dabe
EZ
299 dirwatch->io_info->hEvent = dirwatch;
300 dirwatch->subtree = subdirs;
301 dirwatch->filter = flags;
302 dirwatch->watchee = xstrdup (file);
303 dirwatch->terminate = 0;
304 dirwatch->dir = hdir;
6f011d81
EZ
305
306 /* See w32proc.c where it calls CreateThread for the story behind
307 the 2nd and 5th argument in the call to CreateThread. */
37a4dabe
EZ
308 dirwatch->thr = CreateThread (NULL, 64 * 1024, watch_worker, (void *)dirwatch,
309 0x00010000, NULL);
6f011d81 310
37a4dabe 311 if (!dirwatch->thr)
6f011d81 312 {
37a4dabe
EZ
313 xfree (dirwatch->buf);
314 xfree (dirwatch->io_info);
315 xfree (dirwatch->watchee);
316 xfree (dirwatch);
317 dirwatch = NULL;
6f011d81 318 }
37a4dabe 319 return dirwatch;
6f011d81
EZ
320}
321
322/* Called from the main thread to start watching FILE in PARENT_DIR,
323 subject to FLAGS. If SUBDIRS is TRUE, watch the subdirectories of
37a4dabe
EZ
324 PARENT_DIR as well. Value is a pointer to 'struct notification'
325 used by the thread that watches the changes. */
326static struct notification *
6f011d81
EZ
327add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags)
328{
329 HANDLE hdir;
37a4dabe 330 struct notification *dirwatch = NULL;
6f011d81 331
fb6a5d68 332 if (!file)
6f011d81
EZ
333 return NULL;
334
439b1ae8
EZ
335 if (w32_unicode_filenames)
336 {
337 wchar_t dir_w[MAX_PATH], file_w[MAX_PATH];
338
339 filename_to_utf16 (parent_dir, dir_w);
340 if (*file)
341 filename_to_utf16 (file, file_w);
342 else
343 file_w[0] = 0;
344
345 hdir = CreateFileW (dir_w,
346 FILE_LIST_DIRECTORY,
347 /* FILE_SHARE_DELETE doesn't preclude other
348 processes from deleting files inside
349 parent_dir. */
350 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
351 NULL, OPEN_EXISTING,
352 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
353 NULL);
354 }
355 else
356 {
357 char dir_a[MAX_PATH], file_a[MAX_PATH];
358
359 filename_to_ansi (parent_dir, dir_a);
360 if (*file)
361 filename_to_ansi (file, file_a);
362 else
363 file_a[0] = '\0';
364
365 hdir = CreateFileA (dir_a,
366 FILE_LIST_DIRECTORY,
367 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
368 NULL, OPEN_EXISTING,
369 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
370 NULL);
371 }
6f011d81
EZ
372 if (hdir == INVALID_HANDLE_VALUE)
373 return NULL;
374
37a4dabe
EZ
375 if ((dirwatch = start_watching (file, hdir, subdirs, flags)) == NULL)
376 CloseHandle (hdir);
6f011d81 377
37a4dabe 378 return dirwatch;
6f011d81
EZ
379}
380
37a4dabe 381/* Stop watching a directory specified by a pointer to its dirwatch object. */
6f011d81 382static int
37a4dabe 383remove_watch (struct notification *dirwatch)
6f011d81 384{
37a4dabe 385 if (dirwatch && dirwatch->signature == DIRWATCH_SIGNATURE)
6f011d81
EZ
386 {
387 int i;
388 BOOL status;
389 DWORD exit_code, err;
390
391 /* Only the thread that issued the outstanding I/O call can call
392 CancelIo on it. (CancelIoEx is available only since Vista.)
393 So we need to queue an APC for the worker thread telling it
394 to terminate. */
37a4dabe 395 if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir))
6f011d81
EZ
396 DebPrint (("QueueUserAPC failed (%lu)!\n", GetLastError ()));
397 /* We also set the terminate flag, for when the thread is
398 waiting on the critical section that never gets acquired.
399 FIXME: is there a cleaner method? Using SleepEx there is a
400 no-no, as that will lead to recursive APC invocations and
401 stack overflow. */
37a4dabe 402 dirwatch->terminate = 1;
6f011d81
EZ
403 /* Wait for the thread to exit. FIXME: is there a better method
404 that is not overly complex? */
405 for (i = 0; i < 50; i++)
406 {
37a4dabe 407 if (!((status = GetExitCodeThread (dirwatch->thr, &exit_code))
6f011d81
EZ
408 && exit_code == STILL_ACTIVE))
409 break;
410 Sleep (10);
411 }
412 if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
413 || exit_code == STILL_ACTIVE)
414 {
415 if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
37a4dabe
EZ
416 {
417 TerminateThread (dirwatch->thr, 0);
418 if (dirwatch->dir)
419 CloseHandle (dirwatch->dir);
420 }
6f011d81
EZ
421 }
422
423 /* Clean up. */
37a4dabe 424 if (dirwatch->thr)
6f011d81 425 {
37a4dabe
EZ
426 CloseHandle (dirwatch->thr);
427 dirwatch->thr = NULL;
6f011d81 428 }
37a4dabe
EZ
429 xfree (dirwatch->buf);
430 xfree (dirwatch->io_info);
431 xfree (dirwatch->watchee);
432 xfree (dirwatch);
433
6f011d81
EZ
434 return 0;
435 }
436 else
437 {
37a4dabe 438 DebPrint (("Unknown dirwatch object!\n"));
6f011d81
EZ
439 return -1;
440 }
441}
442
443static DWORD
444filter_list_to_flags (Lisp_Object filter_list)
445{
446 DWORD flags = 0;
447
448 if (NILP (filter_list))
449 return flags;
450
451 if (!NILP (Fmember (Qfile_name, filter_list)))
452 flags |= FILE_NOTIFY_CHANGE_FILE_NAME;
453 if (!NILP (Fmember (Qdirectory_name, filter_list)))
454 flags |= FILE_NOTIFY_CHANGE_DIR_NAME;
455 if (!NILP (Fmember (Qattributes, filter_list)))
456 flags |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
457 if (!NILP (Fmember (Qsize, filter_list)))
458 flags |= FILE_NOTIFY_CHANGE_SIZE;
459 if (!NILP (Fmember (Qlast_write_time, filter_list)))
460 flags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
461 if (!NILP (Fmember (Qlast_access_time, filter_list)))
462 flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
463 if (!NILP (Fmember (Qcreation_time, filter_list)))
464 flags |= FILE_NOTIFY_CHANGE_CREATION;
465 if (!NILP (Fmember (Qsecurity_desc, filter_list)))
466 flags |= FILE_NOTIFY_CHANGE_SECURITY;
467
468 return flags;
469}
470
471DEFUN ("w32notify-add-watch", Fw32notify_add_watch,
472 Sw32notify_add_watch, 3, 3, 0,
473 doc: /* Add a watch for filesystem events pertaining to FILE.
474
475This arranges for filesystem events pertaining to FILE to be reported
476to Emacs. Use `w32notify-rm-watch' to cancel the watch.
477
d8cd7742
EZ
478Value is a descriptor for the added watch. If the file cannot be
479watched for some reason, this function signals a `file-error' error.
6f011d81
EZ
480
481FILTER is a list of conditions for reporting an event. It can include
482the following symbols:
483
484 'file-name' -- report file creation, deletion, or renaming
485 'directory-name' -- report directory creation, deletion, or renaming
486 'attributes' -- report changes in attributes
487 'size' -- report changes in file-size
488 'last-write-time' -- report changes in last-write time
489 'last-access-time' -- report changes in last-access time
490 'creation-time' -- report changes in creation time
491 'security-desc' -- report changes in security descriptor
492
493If FILE is a directory, and FILTER includes 'subtree', then all the
494subdirectories will also be watched and changes in them reported.
495
496When any event happens that satisfies the conditions specified by
497FILTER, Emacs will call the CALLBACK function passing it a single
498argument EVENT, which is of the form
499
500 (DESCRIPTOR ACTION FILE)
501
502DESCRIPTOR is the same object as the one returned by this function.
503ACTION is the description of the event. It could be any one of the
504following:
505
506 'added' -- FILE was added
507 'removed' -- FILE was deleted
508 'modified' -- FILE's contents or its attributes were modified
509 'renamed-from' -- a file was renamed whose old name was FILE
510 'renamed-to' -- a file was renamed and its new name is FILE
511
d8cd7742
EZ
512FILE is the name of the file whose event is being reported.
513
514Note that some networked filesystems, such as Samba-mounted Unix
515volumes, might not send notifications about file changes. In these
516cases, this function will return a valid descriptor, but notifications
517will never come in. Volumes shared from remote Windows machines do
518generate notifications correctly, though. */)
6f011d81
EZ
519 (Lisp_Object file, Lisp_Object filter, Lisp_Object callback)
520{
439b1ae8 521 Lisp_Object dirfn, basefn, watch_object, watch_descriptor;
6f011d81
EZ
522 DWORD flags;
523 BOOL subdirs = FALSE;
37a4dabe 524 struct notification *dirwatch = NULL;
6f011d81
EZ
525 Lisp_Object lisp_errstr;
526 char *errstr;
527
528 CHECK_LIST (filter);
529
530 /* The underlying features are available only since XP. */
531 if (os_subtype == OS_9X
532 || (w32_major_version == 5 && w32_major_version < 1))
533 {
534 errno = ENOSYS;
535 report_file_error ("Watching filesystem events is not supported",
536 Qnil);
537 }
538
fb6a5d68
EZ
539 /* filenotify.el always passes us a directory, either the parent
540 directory of a file to be watched, or the directory to be
541 watched. */
439b1ae8
EZ
542 file = Fdirectory_file_name (Fexpand_file_name (file, Qnil));
543 if (NILP (Ffile_directory_p (file)))
fb6a5d68
EZ
544 {
545 /* This should only happen if we are called directly, not via
439b1ae8
EZ
546 filenotify.el. If BASEFN is empty, the argument was the root
547 directory on its drive. */
548 dirfn = ENCODE_FILE (Ffile_name_directory (file));
549 basefn = ENCODE_FILE (Ffile_name_nondirectory (file));
550 if (*SDATA (basefn) == '\0')
fb6a5d68
EZ
551 subdirs = TRUE;
552 }
439b1ae8
EZ
553 else
554 {
555 dirfn = ENCODE_FILE (file);
556 basefn = Qnil;
557 }
6f011d81
EZ
558
559 if (!NILP (Fmember (Qsubtree, filter)))
560 subdirs = TRUE;
561
562 flags = filter_list_to_flags (filter);
563
439b1ae8
EZ
564 dirwatch = add_watch (SSDATA (dirfn), NILP (basefn) ? "" : SSDATA (basefn),
565 subdirs, flags);
37a4dabe 566 if (!dirwatch)
6f011d81
EZ
567 {
568 DWORD err = GetLastError ();
569
570 errno = EINVAL;
571 if (err)
572 {
573 errstr = w32_strerror (err);
574 if (!NILP (Vlocale_coding_system))
575 lisp_errstr
576 = code_convert_string_norecord (build_unibyte_string (errstr),
577 Vlocale_coding_system, 0);
578 else
579 lisp_errstr = build_string (errstr);
580 report_file_error ("Cannot watch file",
581 Fcons (lisp_errstr, Fcons (file, Qnil)));
582 }
583 else
584 report_file_error ("Cannot watch file", Fcons (file, Qnil));
585 }
586 /* Store watch object in watch list. */
0b86d359 587 watch_descriptor = XIL ((EMACS_INT)dirwatch);
6f011d81
EZ
588 watch_object = Fcons (watch_descriptor, callback);
589 watch_list = Fcons (watch_object, watch_list);
590
591 return watch_descriptor;
592}
593
594DEFUN ("w32notify-rm-watch", Fw32notify_rm_watch,
595 Sw32notify_rm_watch, 1, 1, 0,
596 doc: /* Remove an existing watch specified by its WATCH-DESCRIPTOR.
597
598WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'. */)
599 (Lisp_Object watch_descriptor)
600{
601 Lisp_Object watch_object;
0b86d359
EZ
602 struct notification *dirwatch;
603 int status = -1;
6f011d81 604
37a4dabe
EZ
605 /* Remove the watch object from watch list. Do this before freeing
606 the object, do that even if we fail to free it, watch_list is
607 kept free of junk. */
6f011d81
EZ
608 watch_object = Fassoc (watch_descriptor, watch_list);
609 if (!NILP (watch_object))
0b86d359
EZ
610 {
611 watch_list = Fdelete (watch_object, watch_list);
612 dirwatch = (struct notification *)XLI (watch_descriptor);
613 if (w32_valid_pointer_p (dirwatch, sizeof(struct notification)))
614 status = remove_watch (dirwatch);
615 }
6f011d81 616
0b86d359 617 if (status == -1)
37a4dabe
EZ
618 report_file_error ("Invalid watch descriptor", Fcons (watch_descriptor,
619 Qnil));
620
6f011d81
EZ
621 return Qnil;
622}
623
624Lisp_Object
0b86d359 625w32_get_watch_object (void *desc)
37a4dabe 626{
0b86d359
EZ
627 Lisp_Object descriptor = XIL ((EMACS_INT)desc);
628
d884121b
EZ
629 /* This is called from the input queue handling code, inside a
630 critical section, so we cannot possibly QUIT if watch_list is not
631 in the right condition. */
0b86d359 632 return NILP (watch_list) ? Qnil : assoc_no_quit (descriptor, watch_list);
37a4dabe
EZ
633}
634
635void
636globals_of_w32notify (void)
6f011d81 637{
37a4dabe 638 watch_list = Qnil;
6f011d81
EZ
639}
640
641void
642syms_of_w32notify (void)
643{
644 DEFSYM (Qfile_name, "file-name");
645 DEFSYM (Qdirectory_name, "directory-name");
646 DEFSYM (Qattributes, "attributes");
647 DEFSYM (Qsize, "size");
648 DEFSYM (Qlast_write_time, "last-write-time");
649 DEFSYM (Qlast_access_time, "last-access-time");
650 DEFSYM (Qcreation_time, "creation-time");
651 DEFSYM (Qsecurity_desc, "security-desc");
652 DEFSYM (Qsubtree, "subtree");
653
654 defsubr (&Sw32notify_add_watch);
655 defsubr (&Sw32notify_rm_watch);
656
657 staticpro (&watch_list);
658
659 Fprovide (intern_c_string ("w32notify"), Qnil);
660}