• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include "uv.h"
23 #include "task.h"
24 
25 #include <string.h>
26 #include <fcntl.h>
27 
28 #if defined(__APPLE__) && !TARGET_OS_IPHONE
29 # include <AvailabilityMacros.h>
30 #endif
31 
32 #ifndef HAVE_KQUEUE
33 # if defined(__APPLE__) ||                                                    \
34      defined(__DragonFly__) ||                                                \
35      defined(__FreeBSD__) ||                                                  \
36      defined(__OpenBSD__) ||                                                  \
37      defined(__NetBSD__)
38 #  define HAVE_KQUEUE 1
39 # endif
40 #endif
41 
42 static uv_fs_event_t fs_event;
43 static const char file_prefix[] = "fsevent-";
44 static const int fs_event_file_count = 16;
45 #if defined(__APPLE__) || defined(_WIN32)
46 static const char file_prefix_in_subdir[] = "subdir";
47 static int fs_multievent_cb_called;
48 #endif
49 static uv_timer_t timer;
50 static int timer_cb_called;
51 static int close_cb_called;
52 static int fs_event_created;
53 static int fs_event_removed;
54 static int fs_event_cb_called;
55 #if defined(PATH_MAX)
56 static char fs_event_filename[PATH_MAX];
57 #else
58 static char fs_event_filename[1024];
59 #endif  /* defined(PATH_MAX) */
60 static int timer_cb_touch_called;
61 static int timer_cb_exact_called;
62 
fs_event_fail(uv_fs_event_t * handle,const char * filename,int events,int status)63 static void fs_event_fail(uv_fs_event_t* handle,
64                           const char* filename,
65                           int events,
66                           int status) {
67   ASSERT(0 && "should never be called");
68 }
69 
create_dir(const char * name)70 static void create_dir(const char* name) {
71   int r;
72   uv_fs_t req;
73   r = uv_fs_mkdir(NULL, &req, name, 0755, NULL);
74   ASSERT(r == 0 || r == UV_EEXIST);
75   uv_fs_req_cleanup(&req);
76 }
77 
create_file(const char * name)78 static void create_file(const char* name) {
79   int r;
80   uv_file file;
81   uv_fs_t req;
82 
83   r = uv_fs_open(NULL, &req, name, UV_FS_O_WRONLY | UV_FS_O_CREAT,
84                  S_IWUSR | S_IRUSR,
85                  NULL);
86   ASSERT_GE(r, 0);
87   file = r;
88   uv_fs_req_cleanup(&req);
89   r = uv_fs_close(NULL, &req, file, NULL);
90   ASSERT_OK(r);
91   uv_fs_req_cleanup(&req);
92 }
93 
touch_file(const char * name)94 static void touch_file(const char* name) {
95   int r;
96   uv_file file;
97   uv_fs_t req;
98   uv_buf_t buf;
99 
100   r = uv_fs_open(NULL, &req, name, UV_FS_O_RDWR, 0, NULL);
101   ASSERT_GE(r, 0);
102   file = r;
103   uv_fs_req_cleanup(&req);
104 
105   buf = uv_buf_init("foo", 4);
106   r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
107   ASSERT_GE(r, 0);
108   uv_fs_req_cleanup(&req);
109 
110   r = uv_fs_close(NULL, &req, file, NULL);
111   ASSERT_OK(r);
112   uv_fs_req_cleanup(&req);
113 }
114 
close_cb(uv_handle_t * handle)115 static void close_cb(uv_handle_t* handle) {
116   ASSERT_NOT_NULL(handle);
117   close_cb_called++;
118 }
119 
fail_cb(uv_fs_event_t * handle,const char * path,int events,int status)120 static void fail_cb(uv_fs_event_t* handle,
121                     const char* path,
122                     int events,
123                     int status) {
124   ASSERT(0 && "fail_cb called");
125 }
126 
fs_event_cb_dir(uv_fs_event_t * handle,const char * filename,int events,int status)127 static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
128   int events, int status) {
129   ++fs_event_cb_called;
130   ASSERT_PTR_EQ(handle, &fs_event);
131   ASSERT_OK(status);
132   ASSERT_EQ(events, UV_CHANGE);
133   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
134   ASSERT_OK(strcmp(filename, "file1"));
135   #else
136   ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
137   #endif
138   ASSERT_OK(uv_fs_event_stop(handle));
139   uv_close((uv_handle_t*)handle, close_cb);
140 }
141 
fs_event_get_filename(int i)142 static const char* fs_event_get_filename(int i) {
143   snprintf(fs_event_filename,
144            sizeof(fs_event_filename),
145            "watch_dir/%s%d",
146            file_prefix,
147            i);
148   return fs_event_filename;
149 }
150 
fs_event_create_files(uv_timer_t * handle)151 static void fs_event_create_files(uv_timer_t* handle) {
152   /* Make sure we're not attempting to create files we do not intend */
153   ASSERT_LT(fs_event_created, fs_event_file_count);
154 
155   /* Create the file */
156   create_file(fs_event_get_filename(fs_event_created));
157 
158   if (++fs_event_created < fs_event_file_count) {
159     /* Create another file on a different event loop tick.  We do it this way
160      * to avoid fs events coalescing into one fs event. */
161     ASSERT_OK(uv_timer_start(&timer, fs_event_create_files, 100, 0));
162   }
163 }
164 
fs_event_unlink_files(uv_timer_t * handle)165 static void fs_event_unlink_files(uv_timer_t* handle) {
166   int r;
167   int i;
168 
169   /* NOTE: handle might be NULL if invoked not as timer callback */
170   if (handle == NULL) {
171     /* Unlink all files */
172     for (i = 0; i < 16; i++) {
173       r = remove(fs_event_get_filename(i));
174       if (handle != NULL)
175         ASSERT_OK(r);
176     }
177   } else {
178     /* Make sure we're not attempting to remove files we do not intend */
179     ASSERT_LT(fs_event_removed, fs_event_file_count);
180 
181     /* Remove the file */
182     ASSERT_OK(remove(fs_event_get_filename(fs_event_removed)));
183 
184     if (++fs_event_removed < fs_event_file_count) {
185       /* Remove another file on a different event loop tick.  We do it this way
186        * to avoid fs events coalescing into one fs event. */
187       ASSERT_OK(uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
188     }
189   }
190 }
191 
fs_event_cb_dir_multi_file(uv_fs_event_t * handle,const char * filename,int events,int status)192 static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
193                                        const char* filename,
194                                        int events,
195                                        int status) {
196   fs_event_cb_called++;
197   ASSERT_PTR_EQ(handle, &fs_event);
198   ASSERT_OK(status);
199   ASSERT(events == UV_CHANGE || events == UV_RENAME);
200   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
201   ASSERT_OK(strncmp(filename, file_prefix, sizeof(file_prefix) - 1));
202   #else
203   ASSERT_NE(filename == NULL ||
204             strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0, 0);
205   #endif
206 
207   if (fs_event_created + fs_event_removed == fs_event_file_count) {
208     /* Once we've processed all create events, delete all files */
209     ASSERT_OK(uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
210   } else if (fs_event_cb_called == 2 * fs_event_file_count) {
211     /* Once we've processed all create and delete events, stop watching */
212     uv_close((uv_handle_t*) &timer, close_cb);
213     uv_close((uv_handle_t*) handle, close_cb);
214   }
215 }
216 
217 #if defined(__APPLE__) || defined(_WIN32)
fs_event_get_filename_in_subdir(int i)218 static const char* fs_event_get_filename_in_subdir(int i) {
219   snprintf(fs_event_filename,
220            sizeof(fs_event_filename),
221            "watch_dir/subdir/%s%d",
222            file_prefix,
223            i);
224   return fs_event_filename;
225 }
226 
fs_event_create_files_in_subdir(uv_timer_t * handle)227 static void fs_event_create_files_in_subdir(uv_timer_t* handle) {
228   /* Make sure we're not attempting to create files we do not intend */
229   ASSERT_LT(fs_event_created, fs_event_file_count);
230 
231   /* Create the file */
232   create_file(fs_event_get_filename_in_subdir(fs_event_created));
233 
234   if (++fs_event_created < fs_event_file_count) {
235     /* Create another file on a different event loop tick.  We do it this way
236      * to avoid fs events coalescing into one fs event. */
237     ASSERT_OK(uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0));
238   }
239 }
240 
fs_event_unlink_files_in_subdir(uv_timer_t * handle)241 static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) {
242   int r;
243   int i;
244 
245   /* NOTE: handle might be NULL if invoked not as timer callback */
246   if (handle == NULL) {
247     /* Unlink all files */
248     for (i = 0; i < 16; i++) {
249       r = remove(fs_event_get_filename_in_subdir(i));
250       if (handle != NULL)
251         ASSERT_OK(r);
252     }
253   } else {
254     /* Make sure we're not attempting to remove files we do not intend */
255     ASSERT_LT(fs_event_removed, fs_event_file_count);
256 
257     /* Remove the file */
258     ASSERT_OK(remove(fs_event_get_filename_in_subdir(fs_event_removed)));
259 
260     if (++fs_event_removed < fs_event_file_count) {
261       /* Remove another file on a different event loop tick.  We do it this way
262        * to avoid fs events coalescing into one fs event. */
263       ASSERT_OK(uv_timer_start(&timer,
264                                fs_event_unlink_files_in_subdir,
265                                1,
266                                0));
267     }
268   }
269 }
270 
fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t * handle,const char * filename,int events,int status)271 static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
272                                                  const char* filename,
273                                                  int events,
274                                                  int status) {
275 #ifdef _WIN32
276   /* Each file created (or deleted) will cause this callback to be called twice
277    * under Windows: once with the name of the file, and second time with the
278    * name of the directory. We will ignore the callback for the directory
279    * itself. */
280   if (filename && strcmp(filename, file_prefix_in_subdir) == 0)
281     return;
282 #endif
283   /* It may happen that the "subdir" creation event is captured even though
284    * we started watching after its actual creation.
285    */
286   if (strcmp(filename, "subdir") == 0)
287     return;
288 
289   fs_multievent_cb_called++;
290   ASSERT_PTR_EQ(handle, &fs_event);
291   ASSERT_OK(status);
292   ASSERT(events == UV_CHANGE || events == UV_RENAME);
293   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
294   ASSERT_OK(strncmp(filename,
295                     file_prefix_in_subdir,
296                     sizeof(file_prefix_in_subdir) - 1));
297   #else
298   ASSERT_NE(filename == NULL ||
299             strncmp(filename,
300                     file_prefix_in_subdir,
301                     sizeof(file_prefix_in_subdir) - 1) == 0, 0);
302   #endif
303 
304   if (fs_event_created == fs_event_file_count &&
305       fs_multievent_cb_called == fs_event_created) {
306     /* Once we've processed all create events, delete all files */
307     ASSERT_OK(uv_timer_start(&timer,
308                              fs_event_unlink_files_in_subdir,
309                              1,
310                              0));
311   } else if (fs_multievent_cb_called == 2 * fs_event_file_count) {
312     /* Once we've processed all create and delete events, stop watching */
313     ASSERT_EQ(fs_event_removed, fs_event_file_count);
314     uv_close((uv_handle_t*) &timer, close_cb);
315     uv_close((uv_handle_t*) handle, close_cb);
316   }
317 }
318 #endif
319 
fs_event_cb_file(uv_fs_event_t * handle,const char * filename,int events,int status)320 static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
321   int events, int status) {
322   ++fs_event_cb_called;
323   ASSERT_PTR_EQ(handle, &fs_event);
324   ASSERT_OK(status);
325   ASSERT_EQ(events, UV_CHANGE);
326   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
327   ASSERT_OK(strcmp(filename, "file2"));
328   #else
329   ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
330   #endif
331   ASSERT_OK(uv_fs_event_stop(handle));
332   uv_close((uv_handle_t*)handle, close_cb);
333 }
334 
fs_event_cb_file_current_dir(uv_fs_event_t * handle,const char * filename,int events,int status)335 static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
336   const char* filename, int events, int status) {
337   ++fs_event_cb_called;
338 
339   ASSERT_PTR_EQ(handle, &fs_event);
340   ASSERT_OK(status);
341   ASSERT_EQ(events, UV_CHANGE);
342   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
343   ASSERT_OK(strcmp(filename, "watch_file"));
344   #else
345   ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
346   #endif
347 
348   uv_close((uv_handle_t*)handle, close_cb);
349 }
350 
timer_cb_file(uv_timer_t * handle)351 static void timer_cb_file(uv_timer_t* handle) {
352   ++timer_cb_called;
353 
354   if (timer_cb_called == 1) {
355     touch_file("watch_dir/file1");
356   } else {
357     touch_file("watch_dir/file2");
358     uv_close((uv_handle_t*)handle, close_cb);
359   }
360 }
361 
timer_cb_touch(uv_timer_t * timer)362 static void timer_cb_touch(uv_timer_t* timer) {
363   uv_close((uv_handle_t*)timer, NULL);
364   touch_file((char*) timer->data);
365   timer_cb_touch_called++;
366 }
367 
timer_cb_exact(uv_timer_t * handle)368 static void timer_cb_exact(uv_timer_t* handle) {
369   int r;
370 
371   if (timer_cb_exact_called == 0) {
372     touch_file("watch_dir/file.js");
373   } else {
374     uv_close((uv_handle_t*)handle, NULL);
375     r = uv_fs_event_stop(&fs_event);
376     ASSERT_OK(r);
377     uv_close((uv_handle_t*) &fs_event, NULL);
378   }
379 
380   ++timer_cb_exact_called;
381 }
382 
timer_cb_watch_twice(uv_timer_t * handle)383 static void timer_cb_watch_twice(uv_timer_t* handle) {
384   uv_fs_event_t* handles = handle->data;
385   uv_close((uv_handle_t*) (handles + 0), NULL);
386   uv_close((uv_handle_t*) (handles + 1), NULL);
387   uv_close((uv_handle_t*) handle, NULL);
388 }
389 
fs_event_cb_close(uv_fs_event_t * handle,const char * filename,int events,int status)390 static void fs_event_cb_close(uv_fs_event_t* handle,
391                               const char* filename,
392                               int events,
393                               int status) {
394   ASSERT_OK(status);
395 
396   ASSERT_LT(fs_event_cb_called, 3);
397   ++fs_event_cb_called;
398 
399   if (fs_event_cb_called == 3) {
400     uv_close((uv_handle_t*) handle, close_cb);
401   }
402 }
403 
404 
TEST_IMPL(fs_event_watch_dir)405 TEST_IMPL(fs_event_watch_dir) {
406 #if defined(NO_FS_EVENTS)
407   RETURN_SKIP(NO_FS_EVENTS);
408 #elif defined(__MVS__)
409   RETURN_SKIP("Directory watching not supported on this platform.");
410 #elif defined(__APPLE__) && defined(__TSAN__)
411   RETURN_SKIP("Times out under TSAN.");
412 #endif
413 
414   uv_loop_t* loop = uv_default_loop();
415   int r;
416 
417   /* Setup */
418   fs_event_unlink_files(NULL);
419   remove("watch_dir/file2");
420   remove("watch_dir/file1");
421   remove("watch_dir/");
422   create_dir("watch_dir");
423 
424   r = uv_fs_event_init(loop, &fs_event);
425   ASSERT_OK(r);
426   r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
427   ASSERT_OK(r);
428   r = uv_timer_init(loop, &timer);
429   ASSERT_OK(r);
430   r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
431   ASSERT_OK(r);
432 
433   uv_run(loop, UV_RUN_DEFAULT);
434 
435   ASSERT_EQ(fs_event_cb_called, fs_event_created + fs_event_removed);
436   ASSERT_EQ(2, close_cb_called);
437 
438   /* Cleanup */
439   fs_event_unlink_files(NULL);
440   remove("watch_dir/file2");
441   remove("watch_dir/file1");
442   remove("watch_dir/");
443 
444   MAKE_VALGRIND_HAPPY(loop);
445   return 0;
446 }
447 
448 
TEST_IMPL(fs_event_watch_dir_recursive)449 TEST_IMPL(fs_event_watch_dir_recursive) {
450 #if defined(__APPLE__) && defined(__TSAN__)
451   RETURN_SKIP("Times out under TSAN.");
452 #elif defined(__APPLE__) || defined(_WIN32)
453   uv_loop_t* loop;
454   int r;
455   uv_fs_event_t fs_event_root;
456 
457   /* Setup */
458   loop = uv_default_loop();
459   fs_event_unlink_files(NULL);
460   remove("watch_dir/file2");
461   remove("watch_dir/file1");
462   remove("watch_dir/subdir");
463   remove("watch_dir/");
464   create_dir("watch_dir");
465   create_dir("watch_dir/subdir");
466 
467   r = uv_fs_event_init(loop, &fs_event);
468   ASSERT_OK(r);
469   r = uv_fs_event_start(&fs_event,
470                         fs_event_cb_dir_multi_file_in_subdir,
471                         "watch_dir",
472                         UV_FS_EVENT_RECURSIVE);
473   ASSERT_OK(r);
474   r = uv_timer_init(loop, &timer);
475   ASSERT_OK(r);
476   r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0);
477   ASSERT_OK(r);
478 
479 #ifndef _WIN32
480   /* Also try to watch the root directory.
481    * This will be noisier, so we're just checking for any couple events to happen. */
482   r = uv_fs_event_init(loop, &fs_event_root);
483   ASSERT_OK(r);
484   r = uv_fs_event_start(&fs_event_root,
485                         fs_event_cb_close,
486                         "/",
487                         UV_FS_EVENT_RECURSIVE);
488   ASSERT_OK(r);
489 #else
490   fs_event_cb_called += 3;
491   close_cb_called += 1;
492   (void)fs_event_root;
493 #endif
494 
495   uv_run(loop, UV_RUN_DEFAULT);
496 
497   ASSERT_EQ(fs_multievent_cb_called, fs_event_created + fs_event_removed);
498   ASSERT_EQ(3, fs_event_cb_called);
499   ASSERT_EQ(3, close_cb_called);
500 
501   /* Cleanup */
502   fs_event_unlink_files_in_subdir(NULL);
503   remove("watch_dir/file2");
504   remove("watch_dir/file1");
505   remove("watch_dir/subdir");
506   remove("watch_dir/");
507 
508   MAKE_VALGRIND_HAPPY(loop);
509   return 0;
510 #else
511   RETURN_SKIP("Recursive directory watching not supported on this platform.");
512 #endif
513 }
514 
515 #ifdef _WIN32
TEST_IMPL(fs_event_watch_dir_short_path)516 TEST_IMPL(fs_event_watch_dir_short_path) {
517   uv_loop_t* loop;
518   uv_fs_t req;
519   int has_shortnames;
520   int r;
521 
522   /* Setup */
523   loop = uv_default_loop();
524   remove("watch_dir/file1");
525   remove("watch_dir/");
526   create_dir("watch_dir");
527   create_file("watch_dir/file1");
528 
529   /* Newer version of Windows ship with
530      HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation
531      not equal to 0. So we verify the files we created are addressable by a 8.3
532      short name */
533   has_shortnames = uv_fs_stat(NULL, &req, "watch_~1", NULL) != UV_ENOENT;
534   if (has_shortnames) {
535     r = uv_fs_event_init(loop, &fs_event);
536     ASSERT_OK(r);
537     r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0);
538     ASSERT_OK(r);
539     r = uv_timer_init(loop, &timer);
540     ASSERT_OK(r);
541     r = uv_timer_start(&timer, timer_cb_file, 100, 0);
542     ASSERT_OK(r);
543 
544     uv_run(loop, UV_RUN_DEFAULT);
545 
546     ASSERT_EQ(1, fs_event_cb_called);
547     ASSERT_EQ(1, timer_cb_called);
548     ASSERT_EQ(1, close_cb_called);
549   }
550 
551   /* Cleanup */
552   remove("watch_dir/file1");
553   remove("watch_dir/");
554 
555   MAKE_VALGRIND_HAPPY(loop);
556 
557   if (!has_shortnames)
558     RETURN_SKIP("Was not able to address files with 8.3 short name.");
559 
560   return 0;
561 }
562 #endif
563 
564 
TEST_IMPL(fs_event_watch_file)565 TEST_IMPL(fs_event_watch_file) {
566 #if defined(NO_FS_EVENTS)
567   RETURN_SKIP(NO_FS_EVENTS);
568 #endif
569 
570   uv_loop_t* loop = uv_default_loop();
571   int r;
572 
573   /* Setup */
574   remove("watch_dir/file2");
575   remove("watch_dir/file1");
576   remove("watch_dir/");
577   create_dir("watch_dir");
578   create_file("watch_dir/file1");
579   create_file("watch_dir/file2");
580 
581   r = uv_fs_event_init(loop, &fs_event);
582   ASSERT_OK(r);
583   r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0);
584   ASSERT_OK(r);
585   r = uv_timer_init(loop, &timer);
586   ASSERT_OK(r);
587   r = uv_timer_start(&timer, timer_cb_file, 100, 100);
588   ASSERT_OK(r);
589 
590   uv_run(loop, UV_RUN_DEFAULT);
591 
592   ASSERT_EQ(1, fs_event_cb_called);
593   ASSERT_EQ(2, timer_cb_called);
594   ASSERT_EQ(2, close_cb_called);
595 
596   /* Cleanup */
597   remove("watch_dir/file2");
598   remove("watch_dir/file1");
599   remove("watch_dir/");
600 
601   MAKE_VALGRIND_HAPPY(loop);
602   return 0;
603 }
604 
TEST_IMPL(fs_event_watch_file_exact_path)605 TEST_IMPL(fs_event_watch_file_exact_path) {
606   /*
607     This test watches a file named "file.jsx" and modifies a file named
608     "file.js". The test verifies that no events occur for file.jsx.
609   */
610 
611 #if defined(NO_FS_EVENTS)
612   RETURN_SKIP(NO_FS_EVENTS);
613 #endif
614 
615   uv_loop_t* loop;
616   int r;
617 
618   loop = uv_default_loop();
619 
620   /* Setup */
621   remove("watch_dir/file.js");
622   remove("watch_dir/file.jsx");
623   remove("watch_dir/");
624   create_dir("watch_dir");
625   create_file("watch_dir/file.js");
626   create_file("watch_dir/file.jsx");
627 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12)
628   /* Empirically, FSEvents seems to (reliably) report the preceding
629    * create_file events prior to macOS 10.11.6 in the subsequent fs_watch
630    * creation, but that behavior hasn't been observed to occur on newer
631    * versions. Give a long delay here to let the system settle before running
632    * the test. */
633   uv_sleep(1100);
634   uv_update_time(loop);
635 #endif
636 
637   r = uv_fs_event_init(loop, &fs_event);
638   ASSERT_OK(r);
639   r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0);
640   ASSERT_OK(r);
641   r = uv_timer_init(loop, &timer);
642   ASSERT_OK(r);
643   r = uv_timer_start(&timer, timer_cb_exact, 100, 100);
644   ASSERT_OK(r);
645   r = uv_run(loop, UV_RUN_DEFAULT);
646   ASSERT_OK(r);
647   ASSERT_EQ(2, timer_cb_exact_called);
648 
649   /* Cleanup */
650   remove("watch_dir/file.js");
651   remove("watch_dir/file.jsx");
652   remove("watch_dir/");
653 
654   MAKE_VALGRIND_HAPPY(loop);
655   return 0;
656 }
657 
TEST_IMPL(fs_event_watch_file_twice)658 TEST_IMPL(fs_event_watch_file_twice) {
659 #if defined(NO_FS_EVENTS)
660   RETURN_SKIP(NO_FS_EVENTS);
661 #endif
662   const char path[] = "test/fixtures/empty_file";
663   uv_fs_event_t watchers[2];
664   uv_timer_t timer;
665   uv_loop_t* loop;
666 
667   loop = uv_default_loop();
668   timer.data = watchers;
669 
670   ASSERT_OK(uv_fs_event_init(loop, watchers + 0));
671   ASSERT_OK(uv_fs_event_start(watchers + 0, fail_cb, path, 0));
672   ASSERT_OK(uv_fs_event_init(loop, watchers + 1));
673   ASSERT_OK(uv_fs_event_start(watchers + 1, fail_cb, path, 0));
674   ASSERT_OK(uv_timer_init(loop, &timer));
675   ASSERT_OK(uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
676   ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
677 
678   MAKE_VALGRIND_HAPPY(loop);
679   return 0;
680 }
681 
TEST_IMPL(fs_event_watch_file_current_dir)682 TEST_IMPL(fs_event_watch_file_current_dir) {
683 #if defined(NO_FS_EVENTS)
684   RETURN_SKIP(NO_FS_EVENTS);
685 #endif
686   uv_timer_t timer;
687   uv_loop_t* loop;
688   int r;
689 
690   loop = uv_default_loop();
691 
692   /* Setup */
693   remove("watch_file");
694   create_file("watch_file");
695 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12)
696   /* Empirically, kevent seems to (sometimes) report the preceding
697    * create_file events prior to macOS 10.11.6 in the subsequent fs_event_start
698    * So let the system settle before running the test. */
699   uv_sleep(1100);
700   uv_update_time(loop);
701 #endif
702 
703   r = uv_fs_event_init(loop, &fs_event);
704   ASSERT_OK(r);
705   r = uv_fs_event_start(&fs_event,
706                         fs_event_cb_file_current_dir,
707                         "watch_file",
708                         0);
709   ASSERT_OK(r);
710 
711 
712   r = uv_timer_init(loop, &timer);
713   ASSERT_OK(r);
714 
715   timer.data = "watch_file";
716   r = uv_timer_start(&timer, timer_cb_touch, 1100, 0);
717   ASSERT_OK(r);
718 
719   ASSERT_OK(timer_cb_touch_called);
720   ASSERT_OK(fs_event_cb_called);
721   ASSERT_OK(close_cb_called);
722 
723   uv_run(loop, UV_RUN_DEFAULT);
724 
725   ASSERT_EQ(1, timer_cb_touch_called);
726   /* FSEvents on macOS sometimes sends one change event, sometimes two. */
727   ASSERT_NE(0, fs_event_cb_called);
728   ASSERT_EQ(1, close_cb_called);
729 
730   /* Cleanup */
731   remove("watch_file");
732 
733   MAKE_VALGRIND_HAPPY(loop);
734   return 0;
735 }
736 
737 #ifdef _WIN32
TEST_IMPL(fs_event_watch_file_root_dir)738 TEST_IMPL(fs_event_watch_file_root_dir) {
739   uv_loop_t* loop;
740   int r;
741 
742   const char* sys_drive = getenv("SystemDrive");
743   char path[] = "\\\\?\\X:\\bootsect.bak";
744 
745   ASSERT_NOT_NULL(sys_drive);
746   strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1);
747 
748   loop = uv_default_loop();
749 
750   r = uv_fs_event_init(loop, &fs_event);
751   ASSERT_OK(r);
752   r = uv_fs_event_start(&fs_event, fail_cb, path, 0);
753   if (r == UV_ENOENT)
754     RETURN_SKIP("bootsect.bak doesn't exist in system root.\n");
755   ASSERT_OK(r);
756 
757   uv_close((uv_handle_t*) &fs_event, NULL);
758 
759   MAKE_VALGRIND_HAPPY(loop);
760   return 0;
761 }
762 #endif
763 
TEST_IMPL(fs_event_no_callback_after_close)764 TEST_IMPL(fs_event_no_callback_after_close) {
765 #if defined(NO_FS_EVENTS)
766   RETURN_SKIP(NO_FS_EVENTS);
767 #endif
768 
769   uv_loop_t* loop = uv_default_loop();
770   int r;
771 
772   /* Setup */
773   remove("watch_dir/file1");
774   remove("watch_dir/");
775   create_dir("watch_dir");
776   create_file("watch_dir/file1");
777 
778   r = uv_fs_event_init(loop, &fs_event);
779   ASSERT_OK(r);
780   r = uv_fs_event_start(&fs_event,
781                         fs_event_cb_file,
782                         "watch_dir/file1",
783                         0);
784   ASSERT_OK(r);
785 
786 
787   uv_close((uv_handle_t*)&fs_event, close_cb);
788   touch_file("watch_dir/file1");
789   uv_run(loop, UV_RUN_DEFAULT);
790 
791   ASSERT_OK(fs_event_cb_called);
792   ASSERT_EQ(1, close_cb_called);
793 
794   /* Cleanup */
795   remove("watch_dir/file1");
796   remove("watch_dir/");
797 
798   MAKE_VALGRIND_HAPPY(loop);
799   return 0;
800 }
801 
TEST_IMPL(fs_event_no_callback_on_close)802 TEST_IMPL(fs_event_no_callback_on_close) {
803 #if defined(NO_FS_EVENTS)
804   RETURN_SKIP(NO_FS_EVENTS);
805 #endif
806 
807   uv_loop_t* loop = uv_default_loop();
808   int r;
809 
810   /* Setup */
811   remove("watch_dir/file1");
812   remove("watch_dir/");
813   create_dir("watch_dir");
814   create_file("watch_dir/file1");
815 
816   r = uv_fs_event_init(loop, &fs_event);
817   ASSERT_OK(r);
818   r = uv_fs_event_start(&fs_event,
819                         fs_event_cb_file,
820                         "watch_dir/file1",
821                         0);
822   ASSERT_OK(r);
823 
824   uv_close((uv_handle_t*)&fs_event, close_cb);
825 
826   uv_run(loop, UV_RUN_DEFAULT);
827 
828   ASSERT_OK(fs_event_cb_called);
829   ASSERT_EQ(1, close_cb_called);
830 
831   /* Cleanup */
832   remove("watch_dir/file1");
833   remove("watch_dir/");
834 
835   MAKE_VALGRIND_HAPPY(loop);
836   return 0;
837 }
838 
839 
timer_cb(uv_timer_t * handle)840 static void timer_cb(uv_timer_t* handle) {
841   int r;
842 
843   r = uv_fs_event_init(handle->loop, &fs_event);
844   ASSERT_OK(r);
845   r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0);
846   ASSERT_OK(r);
847 
848   uv_close((uv_handle_t*)&fs_event, close_cb);
849   uv_close((uv_handle_t*)handle, close_cb);
850 }
851 
852 
TEST_IMPL(fs_event_immediate_close)853 TEST_IMPL(fs_event_immediate_close) {
854 #if defined(NO_FS_EVENTS)
855   RETURN_SKIP(NO_FS_EVENTS);
856 #endif
857   uv_timer_t timer;
858   uv_loop_t* loop;
859   int r;
860 
861   loop = uv_default_loop();
862 
863   r = uv_timer_init(loop, &timer);
864   ASSERT_OK(r);
865 
866   r = uv_timer_start(&timer, timer_cb, 1, 0);
867   ASSERT_OK(r);
868 
869   uv_run(loop, UV_RUN_DEFAULT);
870 
871   ASSERT_EQ(2, close_cb_called);
872 
873   MAKE_VALGRIND_HAPPY(loop);
874   return 0;
875 }
876 
877 
TEST_IMPL(fs_event_close_with_pending_event)878 TEST_IMPL(fs_event_close_with_pending_event) {
879 #if defined(NO_FS_EVENTS)
880   RETURN_SKIP(NO_FS_EVENTS);
881 #endif
882   uv_loop_t* loop;
883   int r;
884 
885   loop = uv_default_loop();
886 
887   create_dir("watch_dir");
888   create_file("watch_dir/file");
889 
890   r = uv_fs_event_init(loop, &fs_event);
891   ASSERT_OK(r);
892   r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0);
893   ASSERT_OK(r);
894 
895   /* Generate an fs event. */
896   touch_file("watch_dir/file");
897 
898   uv_close((uv_handle_t*)&fs_event, close_cb);
899 
900   uv_run(loop, UV_RUN_DEFAULT);
901 
902   ASSERT_EQ(1, close_cb_called);
903 
904   /* Clean up */
905   remove("watch_dir/file");
906   remove("watch_dir/");
907 
908   MAKE_VALGRIND_HAPPY(loop);
909   return 0;
910 }
911 
TEST_IMPL(fs_event_close_with_pending_delete_event)912 TEST_IMPL(fs_event_close_with_pending_delete_event) {
913 #if defined(NO_FS_EVENTS)
914   RETURN_SKIP(NO_FS_EVENTS);
915 #endif
916   uv_loop_t* loop;
917   int r;
918 
919   loop = uv_default_loop();
920 
921   create_dir("watch_dir");
922   create_file("watch_dir/file");
923 
924   r = uv_fs_event_init(loop, &fs_event);
925   ASSERT_OK(r);
926   r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file", 0);
927   ASSERT_OK(r);
928 
929   /* Generate an fs event. */
930   remove("watch_dir/file");
931 
932   /* Allow time for the remove event to propagate to the pending list. */
933   /* XXX - perhaps just for __sun? */
934   uv_sleep(1100);
935   uv_update_time(loop);
936 
937   uv_close((uv_handle_t*)&fs_event, close_cb);
938 
939   uv_run(loop, UV_RUN_DEFAULT);
940 
941   ASSERT_EQ(1, close_cb_called);
942 
943   /* Clean up */
944   remove("watch_dir/");
945 
946   MAKE_VALGRIND_HAPPY(loop);
947   return 0;
948 }
949 
TEST_IMPL(fs_event_close_in_callback)950 TEST_IMPL(fs_event_close_in_callback) {
951 #if defined(NO_FS_EVENTS)
952   RETURN_SKIP(NO_FS_EVENTS);
953 #elif defined(__MVS__)
954   RETURN_SKIP("Directory watching not supported on this platform.");
955 #elif defined(__APPLE__) && defined(__TSAN__)
956   RETURN_SKIP("Times out under TSAN.");
957 #endif
958   uv_loop_t* loop;
959   int r;
960 
961   loop = uv_default_loop();
962 
963   fs_event_unlink_files(NULL);
964   create_dir("watch_dir");
965 
966   r = uv_fs_event_init(loop, &fs_event);
967   ASSERT_OK(r);
968   r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
969   ASSERT_OK(r);
970 
971   r = uv_timer_init(loop, &timer);
972   ASSERT_OK(r);
973   r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
974   ASSERT_OK(r);
975 
976   uv_run(loop, UV_RUN_DEFAULT);
977 
978   uv_close((uv_handle_t*)&timer, close_cb);
979 
980   uv_run(loop, UV_RUN_ONCE);
981 
982   ASSERT_EQ(2, close_cb_called);
983   ASSERT_EQ(3, fs_event_cb_called);
984 
985   /* Clean up */
986   fs_event_unlink_files(NULL);
987   remove("watch_dir/");
988 
989   MAKE_VALGRIND_HAPPY(loop);
990   return 0;
991 }
992 
TEST_IMPL(fs_event_start_and_close)993 TEST_IMPL(fs_event_start_and_close) {
994 #if defined(NO_FS_EVENTS)
995   RETURN_SKIP(NO_FS_EVENTS);
996 #endif
997   uv_loop_t* loop;
998   uv_fs_event_t fs_event1;
999   uv_fs_event_t fs_event2;
1000   int r;
1001 
1002   loop = uv_default_loop();
1003 
1004   create_dir("watch_dir");
1005 
1006   r = uv_fs_event_init(loop, &fs_event1);
1007   ASSERT_OK(r);
1008   r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0);
1009   ASSERT_OK(r);
1010 
1011   r = uv_fs_event_init(loop, &fs_event2);
1012   ASSERT_OK(r);
1013   r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0);
1014   ASSERT_OK(r);
1015 
1016   uv_close((uv_handle_t*) &fs_event2, close_cb);
1017   uv_close((uv_handle_t*) &fs_event1, close_cb);
1018 
1019   uv_run(loop, UV_RUN_DEFAULT);
1020 
1021   ASSERT_EQ(2, close_cb_called);
1022 
1023   remove("watch_dir/");
1024   MAKE_VALGRIND_HAPPY(loop);
1025   return 0;
1026 }
1027 
TEST_IMPL(fs_event_getpath)1028 TEST_IMPL(fs_event_getpath) {
1029 #if defined(NO_FS_EVENTS)
1030   RETURN_SKIP(NO_FS_EVENTS);
1031 #endif
1032   uv_loop_t* loop = uv_default_loop();
1033   unsigned i;
1034   int r;
1035   char buf[1024];
1036   size_t len;
1037   const char* const watch_dir[] = {
1038     "watch_dir",
1039     "watch_dir/",
1040     "watch_dir///",
1041     "watch_dir/subfolder/..",
1042     "watch_dir//subfolder//..//",
1043   };
1044 
1045   create_dir("watch_dir");
1046   create_dir("watch_dir/subfolder");
1047 
1048 
1049   for (i = 0; i < ARRAY_SIZE(watch_dir); i++) {
1050     r = uv_fs_event_init(loop, &fs_event);
1051     ASSERT_OK(r);
1052     len = sizeof buf;
1053     r = uv_fs_event_getpath(&fs_event, buf, &len);
1054     ASSERT_EQ(r, UV_EINVAL);
1055     r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0);
1056     ASSERT_OK(r);
1057     len = 0;
1058     r = uv_fs_event_getpath(&fs_event, buf, &len);
1059     ASSERT_EQ(r, UV_ENOBUFS);
1060     ASSERT_LT(len, sizeof buf); /* sanity check */
1061     ASSERT_EQ(len, strlen(watch_dir[i]) + 1);
1062     r = uv_fs_event_getpath(&fs_event, buf, &len);
1063     ASSERT_OK(r);
1064     ASSERT_EQ(len, strlen(watch_dir[i]));
1065     ASSERT(strcmp(buf, watch_dir[i]) == 0);
1066     r = uv_fs_event_stop(&fs_event);
1067     ASSERT_OK(r);
1068     uv_close((uv_handle_t*) &fs_event, close_cb);
1069 
1070     uv_run(loop, UV_RUN_DEFAULT);
1071 
1072     ASSERT_EQ(1, close_cb_called);
1073     close_cb_called = 0;
1074   }
1075 
1076   remove("watch_dir/");
1077   MAKE_VALGRIND_HAPPY(loop);
1078   return 0;
1079 }
1080 
1081 #if defined(__APPLE__)
1082 
1083 static int fs_event_error_reported;
1084 
fs_event_error_report_cb(uv_fs_event_t * handle,const char * filename,int events,int status)1085 static void fs_event_error_report_cb(uv_fs_event_t* handle,
1086                                      const char* filename,
1087                                      int events,
1088                                      int status) {
1089   if (status != 0)
1090     fs_event_error_reported = status;
1091 }
1092 
timer_cb_nop(uv_timer_t * handle)1093 static void timer_cb_nop(uv_timer_t* handle) {
1094   ++timer_cb_called;
1095   uv_close((uv_handle_t*) handle, close_cb);
1096 }
1097 
fs_event_error_report_close_cb(uv_handle_t * handle)1098 static void fs_event_error_report_close_cb(uv_handle_t* handle) {
1099   ASSERT_NOT_NULL(handle);
1100   close_cb_called++;
1101 
1102   /* handle is allocated on-stack, no need to free it */
1103 }
1104 
1105 
TEST_IMPL(fs_event_error_reporting)1106 TEST_IMPL(fs_event_error_reporting) {
1107   unsigned int i;
1108   uv_loop_t loops[1024];
1109   uv_fs_event_t events[ARRAY_SIZE(loops)];
1110   uv_loop_t* loop;
1111   uv_fs_event_t* event;
1112 
1113   TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
1114 
1115   remove("watch_dir/");
1116   create_dir("watch_dir");
1117 
1118   /* Create a lot of loops, and start FSEventStream in each of them.
1119    * Eventually, this should create enough streams to make FSEventStreamStart()
1120    * fail.
1121    */
1122   for (i = 0; i < ARRAY_SIZE(loops); i++) {
1123     loop = &loops[i];
1124     ASSERT_OK(uv_loop_init(loop));
1125     event = &events[i];
1126 
1127     timer_cb_called = 0;
1128     close_cb_called = 0;
1129     ASSERT_OK(uv_fs_event_init(loop, event));
1130     ASSERT_OK(uv_fs_event_start(event,
1131                                 fs_event_error_report_cb,
1132                                 "watch_dir",
1133                                 0));
1134     uv_unref((uv_handle_t*) event);
1135 
1136     /* Let loop run for some time */
1137     ASSERT_OK(uv_timer_init(loop, &timer));
1138     ASSERT_OK(uv_timer_start(&timer, timer_cb_nop, 2, 0));
1139     uv_run(loop, UV_RUN_DEFAULT);
1140     ASSERT_EQ(1, timer_cb_called);
1141     ASSERT_EQ(1, close_cb_called);
1142     if (fs_event_error_reported != 0)
1143       break;
1144   }
1145 
1146   /* At least one loop should fail */
1147   ASSERT_EQ(fs_event_error_reported, UV_EMFILE);
1148 
1149   /* Stop and close all events, and destroy loops */
1150   do {
1151     loop = &loops[i];
1152     event = &events[i];
1153 
1154     ASSERT_OK(uv_fs_event_stop(event));
1155     uv_ref((uv_handle_t*) event);
1156     uv_close((uv_handle_t*) event, fs_event_error_report_close_cb);
1157 
1158     close_cb_called = 0;
1159     uv_run(loop, UV_RUN_DEFAULT);
1160     ASSERT_EQ(1, close_cb_called);
1161 
1162     uv_loop_close(loop);
1163   } while (i-- != 0);
1164 
1165   remove("watch_dir/");
1166   MAKE_VALGRIND_HAPPY(uv_default_loop());
1167   return 0;
1168 }
1169 
1170 #else  /* !defined(__APPLE__) */
1171 
TEST_IMPL(fs_event_error_reporting)1172 TEST_IMPL(fs_event_error_reporting) {
1173   /* No-op, needed only for FSEvents backend */
1174 
1175   MAKE_VALGRIND_HAPPY(uv_default_loop());
1176   return 0;
1177 }
1178 
1179 #endif  /* defined(__APPLE__) */
1180 
TEST_IMPL(fs_event_watch_invalid_path)1181 TEST_IMPL(fs_event_watch_invalid_path) {
1182 #if defined(NO_FS_EVENTS)
1183   RETURN_SKIP(NO_FS_EVENTS);
1184 #endif
1185 
1186   uv_loop_t* loop;
1187   int r;
1188 
1189   loop = uv_default_loop();
1190   r = uv_fs_event_init(loop, &fs_event);
1191   ASSERT_OK(r);
1192   r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0);
1193   ASSERT(r);
1194   ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event));
1195   r = uv_fs_event_start(&fs_event, fs_event_cb_file, "", 0);
1196   ASSERT(r);
1197   ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event));
1198   MAKE_VALGRIND_HAPPY(loop);
1199   return 0;
1200 }
1201 
1202 static int fs_event_cb_stop_calls;
1203 
fs_event_cb_stop(uv_fs_event_t * handle,const char * path,int events,int status)1204 static void fs_event_cb_stop(uv_fs_event_t* handle, const char* path,
1205                              int events, int status) {
1206   uv_fs_event_stop(handle);
1207   fs_event_cb_stop_calls++;
1208 }
1209 
TEST_IMPL(fs_event_stop_in_cb)1210 TEST_IMPL(fs_event_stop_in_cb) {
1211   uv_fs_event_t fs;
1212   uv_timer_t timer;
1213   char path[] = "fs_event_stop_in_cb.txt";
1214 
1215 #if defined(NO_FS_EVENTS)
1216   RETURN_SKIP(NO_FS_EVENTS);
1217 #endif
1218 
1219   remove(path);
1220   create_file(path);
1221 
1222   ASSERT_OK(uv_fs_event_init(uv_default_loop(), &fs));
1223   ASSERT_OK(uv_fs_event_start(&fs, fs_event_cb_stop, path, 0));
1224 
1225   /* Note: timer_cb_touch() closes the handle. */
1226   timer.data = path;
1227   ASSERT_OK(uv_timer_init(uv_default_loop(), &timer));
1228   ASSERT_OK(uv_timer_start(&timer, timer_cb_touch, 100, 0));
1229 
1230   ASSERT_OK(fs_event_cb_stop_calls);
1231   ASSERT_OK(timer_cb_touch_called);
1232 
1233   ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1234 
1235   ASSERT_EQ(1, fs_event_cb_stop_calls);
1236   ASSERT_EQ(1, timer_cb_touch_called);
1237 
1238   uv_close((uv_handle_t*) &fs, NULL);
1239   ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1240   ASSERT_EQ(1, fs_event_cb_stop_calls);
1241 
1242   remove(path);
1243 
1244   MAKE_VALGRIND_HAPPY(uv_default_loop());
1245   return 0;
1246 }
1247