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