| 1 | /* Filesystem notifications support for GNU Emacs on the Microsoft Windows API. |
| 2 | Copyright (C) 2012-2014 Free Software Foundation, Inc. |
| 3 | |
| 4 | This file is part of GNU Emacs. |
| 5 | |
| 6 | GNU Emacs is free software: you can redistribute it and/or modify |
| 7 | it under the terms of the GNU General Public License as published by |
| 8 | the Free Software Foundation, either version 3 of the License, or |
| 9 | (at your option) any later version. |
| 10 | |
| 11 | GNU Emacs 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 |
| 14 | GNU General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU General Public License |
| 17 | along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | /* Written by Eli Zaretskii <eliz@gnu.org>. |
| 20 | |
| 21 | Design overview: |
| 22 | |
| 23 | For each watch request, we launch a separate worker thread. The |
| 24 | worker thread runs the watch_worker function, which issues an |
| 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. |
| 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 | |
| 42 | In a GUI session, the WM_EMACS_FILENOTIFY message posted to the |
| 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 |
| 62 | bound to a command. The default binding is file-notify-handle-event, |
| 63 | defined on subr.el. |
| 64 | |
| 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. |
| 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 |
| 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. */ |
| 83 | |
| 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 */ |
| 94 | #include "w32common.h" /* for OS version data */ |
| 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 | |
| 101 | #define DIRWATCH_SIGNATURE 0x01233210 |
| 102 | |
| 103 | struct 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 */ |
| 108 | char *watchee; /* the file we are interested in, UTF-8 encoded */ |
| 109 | HANDLE dir; /* handle to the watched directory */ |
| 110 | HANDLE thr; /* handle to the thread that watches */ |
| 111 | volatile int terminate; /* if non-zero, request for the thread to terminate */ |
| 112 | unsigned signature; |
| 113 | }; |
| 114 | |
| 115 | /* Used for communicating notifications to the main thread. */ |
| 116 | volatile int notification_buffer_in_use; |
| 117 | BYTE file_notifications[16384]; |
| 118 | DWORD notifications_size; |
| 119 | void *notifications_desc; |
| 120 | |
| 121 | static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize; |
| 122 | static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time; |
| 123 | static Lisp_Object Qsecurity_desc, Qsubtree, watch_list; |
| 124 | |
| 125 | /* Signal to the main thread that we have file notifications for it to |
| 126 | process. */ |
| 127 | static void |
| 128 | send_notifications (BYTE *info, DWORD info_size, void *desc, |
| 129 | volatile int *terminate) |
| 130 | { |
| 131 | int done = 0; |
| 132 | struct frame *f = SELECTED_FRAME (); |
| 133 | |
| 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; |
| 151 | notifications_desc = desc; |
| 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)) |
| 164 | || (FRAME_W32_P (f) |
| 165 | && PostMessage (FRAME_W32_WINDOW (f), |
| 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)) |
| 172 | notification_buffer_in_use = 1; |
| 173 | done = 1; |
| 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.) */ |
| 186 | VOID CALLBACK |
| 187 | watch_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 | |
| 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 |
| 201 | "alertable state", i.e. waiting inside SleepEx call. */ |
| 202 | VOID CALLBACK |
| 203 | watch_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 |
| 225 | and exit, signaling to the thread worker routine not to |
| 226 | issue another call to ReadDirectoryChangesW. Note that we |
| 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. */ |
| 231 | dirwatch->dir = NULL; |
| 232 | dirwatch->terminate = 1; |
| 233 | } |
| 234 | else |
| 235 | { |
| 236 | /* Tell the main thread we have notifications for it. */ |
| 237 | send_notifications (dirwatch->buf, bytes_ret, dirwatch, |
| 238 | &dirwatch->terminate); |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | /* Worker routine for the watch thread. */ |
| 243 | static DWORD WINAPI |
| 244 | watch_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 | { |
| 261 | DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ())); |
| 262 | /* We cannot remove the dirwatch object from watch_list, |
| 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. */ |
| 270 | CloseHandle (dirwatch->dir); |
| 271 | dirwatch->dir = NULL; |
| 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); |
| 279 | } while (!dirwatch->terminate); |
| 280 | |
| 281 | return 0; |
| 282 | } |
| 283 | |
| 284 | /* Launch a thread to watch changes to FILE in a directory open on |
| 285 | handle HDIR. */ |
| 286 | static struct notification * |
| 287 | start_watching (const char *file, HANDLE hdir, BOOL subdirs, DWORD flags) |
| 288 | { |
| 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)); |
| 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." */ |
| 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; |
| 305 | |
| 306 | /* See w32proc.c where it calls CreateThread for the story behind |
| 307 | the 2nd and 5th argument in the call to CreateThread. */ |
| 308 | dirwatch->thr = CreateThread (NULL, 64 * 1024, watch_worker, (void *)dirwatch, |
| 309 | 0x00010000, NULL); |
| 310 | |
| 311 | if (!dirwatch->thr) |
| 312 | { |
| 313 | xfree (dirwatch->buf); |
| 314 | xfree (dirwatch->io_info); |
| 315 | xfree (dirwatch->watchee); |
| 316 | xfree (dirwatch); |
| 317 | dirwatch = NULL; |
| 318 | } |
| 319 | return dirwatch; |
| 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 |
| 324 | PARENT_DIR as well. Value is a pointer to 'struct notification' |
| 325 | used by the thread that watches the changes. */ |
| 326 | static struct notification * |
| 327 | add_watch (const char *parent_dir, const char *file, BOOL subdirs, DWORD flags) |
| 328 | { |
| 329 | HANDLE hdir; |
| 330 | struct notification *dirwatch = NULL; |
| 331 | |
| 332 | if (!file) |
| 333 | return NULL; |
| 334 | |
| 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 | } |
| 372 | if (hdir == INVALID_HANDLE_VALUE) |
| 373 | return NULL; |
| 374 | |
| 375 | if ((dirwatch = start_watching (file, hdir, subdirs, flags)) == NULL) |
| 376 | CloseHandle (hdir); |
| 377 | |
| 378 | return dirwatch; |
| 379 | } |
| 380 | |
| 381 | /* Stop watching a directory specified by a pointer to its dirwatch object. */ |
| 382 | static int |
| 383 | remove_watch (struct notification *dirwatch) |
| 384 | { |
| 385 | if (dirwatch && dirwatch->signature == DIRWATCH_SIGNATURE) |
| 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. */ |
| 395 | if (!QueueUserAPC (watch_end, dirwatch->thr, (ULONG_PTR)dirwatch->dir)) |
| 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. */ |
| 402 | dirwatch->terminate = 1; |
| 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 | { |
| 407 | if (!((status = GetExitCodeThread (dirwatch->thr, &exit_code)) |
| 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)) |
| 416 | { |
| 417 | TerminateThread (dirwatch->thr, 0); |
| 418 | if (dirwatch->dir) |
| 419 | CloseHandle (dirwatch->dir); |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | /* Clean up. */ |
| 424 | if (dirwatch->thr) |
| 425 | { |
| 426 | CloseHandle (dirwatch->thr); |
| 427 | dirwatch->thr = NULL; |
| 428 | } |
| 429 | xfree (dirwatch->buf); |
| 430 | xfree (dirwatch->io_info); |
| 431 | xfree (dirwatch->watchee); |
| 432 | xfree (dirwatch); |
| 433 | |
| 434 | return 0; |
| 435 | } |
| 436 | else |
| 437 | { |
| 438 | DebPrint (("Unknown dirwatch object!\n")); |
| 439 | return -1; |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | static DWORD |
| 444 | filter_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 | |
| 471 | DEFUN ("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 | |
| 475 | This arranges for filesystem events pertaining to FILE to be reported |
| 476 | to Emacs. Use `w32notify-rm-watch' to cancel the watch. |
| 477 | |
| 478 | Value is a descriptor for the added watch. If the file cannot be |
| 479 | watched for some reason, this function signals a `file-error' error. |
| 480 | |
| 481 | FILTER is a list of conditions for reporting an event. It can include |
| 482 | the 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 | |
| 493 | If FILE is a directory, and FILTER includes 'subtree', then all the |
| 494 | subdirectories will also be watched and changes in them reported. |
| 495 | |
| 496 | When any event happens that satisfies the conditions specified by |
| 497 | FILTER, Emacs will call the CALLBACK function passing it a single |
| 498 | argument EVENT, which is of the form |
| 499 | |
| 500 | (DESCRIPTOR ACTION FILE) |
| 501 | |
| 502 | DESCRIPTOR is the same object as the one returned by this function. |
| 503 | ACTION is the description of the event. It could be any one of the |
| 504 | following: |
| 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 | |
| 512 | FILE is the name of the file whose event is being reported. |
| 513 | |
| 514 | Note that some networked filesystems, such as Samba-mounted Unix |
| 515 | volumes, might not send notifications about file changes. In these |
| 516 | cases, this function will return a valid descriptor, but notifications |
| 517 | will never come in. Volumes shared from remote Windows machines do |
| 518 | generate notifications correctly, though. */) |
| 519 | (Lisp_Object file, Lisp_Object filter, Lisp_Object callback) |
| 520 | { |
| 521 | Lisp_Object dirfn, basefn, watch_object, watch_descriptor; |
| 522 | DWORD flags; |
| 523 | BOOL subdirs = FALSE; |
| 524 | struct notification *dirwatch = NULL; |
| 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 | |
| 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. */ |
| 542 | file = Fdirectory_file_name (Fexpand_file_name (file, Qnil)); |
| 543 | if (NILP (Ffile_directory_p (file))) |
| 544 | { |
| 545 | /* This should only happen if we are called directly, not via |
| 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') |
| 551 | subdirs = TRUE; |
| 552 | } |
| 553 | else |
| 554 | { |
| 555 | dirfn = ENCODE_FILE (file); |
| 556 | basefn = Qnil; |
| 557 | } |
| 558 | |
| 559 | if (!NILP (Fmember (Qsubtree, filter))) |
| 560 | subdirs = TRUE; |
| 561 | |
| 562 | flags = filter_list_to_flags (filter); |
| 563 | |
| 564 | dirwatch = add_watch (SSDATA (dirfn), NILP (basefn) ? "" : SSDATA (basefn), |
| 565 | subdirs, flags); |
| 566 | if (!dirwatch) |
| 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. */ |
| 587 | watch_descriptor = XIL ((EMACS_INT)dirwatch); |
| 588 | watch_object = Fcons (watch_descriptor, callback); |
| 589 | watch_list = Fcons (watch_object, watch_list); |
| 590 | |
| 591 | return watch_descriptor; |
| 592 | } |
| 593 | |
| 594 | DEFUN ("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 | |
| 598 | WATCH-DESCRIPTOR should be an object returned by `w32notify-add-watch'. */) |
| 599 | (Lisp_Object watch_descriptor) |
| 600 | { |
| 601 | Lisp_Object watch_object; |
| 602 | struct notification *dirwatch; |
| 603 | int status = -1; |
| 604 | |
| 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. */ |
| 608 | watch_object = Fassoc (watch_descriptor, watch_list); |
| 609 | if (!NILP (watch_object)) |
| 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 | } |
| 616 | |
| 617 | if (status == -1) |
| 618 | report_file_error ("Invalid watch descriptor", Fcons (watch_descriptor, |
| 619 | Qnil)); |
| 620 | |
| 621 | return Qnil; |
| 622 | } |
| 623 | |
| 624 | Lisp_Object |
| 625 | w32_get_watch_object (void *desc) |
| 626 | { |
| 627 | Lisp_Object descriptor = XIL ((EMACS_INT)desc); |
| 628 | |
| 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. */ |
| 632 | return NILP (watch_list) ? Qnil : assoc_no_quit (descriptor, watch_list); |
| 633 | } |
| 634 | |
| 635 | void |
| 636 | globals_of_w32notify (void) |
| 637 | { |
| 638 | watch_list = Qnil; |
| 639 | } |
| 640 | |
| 641 | void |
| 642 | syms_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 | } |