3737
3838static uv_fs_event_t fs_event ;
3939static const char file_prefix [] = "fsevent-" ;
40+ static const char file_prefix_in_subdir [] = "subdir" ;
4041static uv_timer_t timer ;
4142static int timer_cb_called ;
4243static int close_cb_called ;
@@ -51,6 +52,7 @@ static char fs_event_filename[1024];
5152static int timer_cb_touch_called ;
5253
5354static void fs_event_unlink_files (uv_timer_t * handle );
55+ static void fs_event_unlink_files_in_subdir (uv_timer_t * handle );
5456
5557static void create_dir (uv_loop_t * loop , const char * name ) {
5658 int r ;
@@ -138,6 +140,25 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
138140 }
139141}
140142
143+ static void fs_event_cb_dir_multi_file_in_subdir (uv_fs_event_t * handle ,
144+ const char * filename ,
145+ int events ,
146+ int status ) {
147+ fs_event_cb_called ++ ;
148+ ASSERT (handle == & fs_event );
149+ ASSERT (status == 0 );
150+ ASSERT (events == UV_RENAME || events == UV_CHANGE );
151+ ASSERT (filename == NULL ||
152+ strncmp (filename , file_prefix_in_subdir , sizeof (file_prefix_in_subdir ) - 1 ) == 0 );
153+
154+ /* Stop watching dir when received events about all files:
155+ * both create and close events */
156+ if (fs_event_cb_called == 2 * fs_event_file_count ) {
157+ ASSERT (0 == uv_fs_event_stop (handle ));
158+ uv_close ((uv_handle_t * ) handle , close_cb );
159+ }
160+ }
161+
141162static const char * fs_event_get_filename (int i ) {
142163 snprintf (fs_event_filename ,
143164 sizeof (fs_event_filename ),
@@ -147,6 +168,15 @@ static const char* fs_event_get_filename(int i) {
147168 return fs_event_filename ;
148169}
149170
171+ static const char * fs_event_get_filename_in_subdir (int i ) {
172+ snprintf (fs_event_filename ,
173+ sizeof (fs_event_filename ),
174+ "watch_dir/subdir/%s%d" ,
175+ file_prefix ,
176+ i );
177+ return fs_event_filename ;
178+ }
179+
150180static void fs_event_create_files (uv_timer_t * handle ) {
151181 int i ;
152182
@@ -164,6 +194,41 @@ static void fs_event_create_files(uv_timer_t* handle) {
164194 ASSERT (0 == uv_timer_start (& timer , fs_event_unlink_files , 50 , 0 ));
165195}
166196
197+ static void fs_event_create_files_in_subdir (uv_timer_t * handle ) {
198+ int i ;
199+
200+ /* Already created all files */
201+ if (fs_event_created == fs_event_file_count ) {
202+ uv_close ((uv_handle_t * ) & timer , close_cb );
203+ return ;
204+ }
205+
206+ /* Create all files */
207+ for (i = 0 ; i < 16 ; i ++ , fs_event_created ++ )
208+ create_file (handle -> loop , fs_event_get_filename_in_subdir (i ));
209+
210+ /* And unlink them */
211+ ASSERT (0 == uv_timer_start (& timer , fs_event_unlink_files_in_subdir , 50 , 0 ));
212+ }
213+
214+ void fs_event_unlink_files_in_subdir (uv_timer_t * handle ) {
215+ int r ;
216+ int i ;
217+
218+ /* NOTE: handle might be NULL if invoked not as timer callback */
219+
220+ /* Unlink all files */
221+ for (i = 0 ; i < 16 ; i ++ ) {
222+ r = remove (fs_event_get_filename_in_subdir (i ));
223+ if (handle != NULL )
224+ ASSERT (r == 0 );
225+ }
226+
227+ /* And create them again */
228+ if (handle != NULL )
229+ ASSERT (0 == uv_timer_start (& timer , fs_event_create_files_in_subdir , 50 , 0 ));
230+ }
231+
167232void fs_event_unlink_files (uv_timer_t * handle ) {
168233 int r ;
169234 int i ;
@@ -282,6 +347,51 @@ TEST_IMPL(fs_event_watch_dir) {
282347 return 0 ;
283348}
284349
350+ TEST_IMPL (fs_event_watch_dir_recursive ) {
351+ #if defined(__APPLE__ ) || defined(_WIN32 )
352+ uv_loop_t * loop ;
353+ int r ;
354+
355+ /* Setup */
356+ loop = uv_default_loop ();
357+ fs_event_unlink_files (NULL );
358+ remove ("watch_dir/file2" );
359+ remove ("watch_dir/file1" );
360+ remove ("watch_dir/subdir" );
361+ remove ("watch_dir/" );
362+ create_dir (loop , "watch_dir" );
363+ create_dir (loop , "watch_dir/subdir" );
364+
365+ r = uv_fs_event_init (loop , & fs_event );
366+ ASSERT (r == 0 );
367+ r = uv_fs_event_start (& fs_event , fs_event_cb_dir_multi_file_in_subdir , "watch_dir" , UV_FS_EVENT_RECURSIVE );
368+ ASSERT (r == 0 );
369+ r = uv_timer_init (loop , & timer );
370+ ASSERT (r == 0 );
371+ r = uv_timer_start (& timer , fs_event_create_files_in_subdir , 100 , 0 );
372+ ASSERT (r == 0 );
373+
374+ uv_run (loop , UV_RUN_DEFAULT );
375+
376+ ASSERT (fs_event_cb_called == 2 * fs_event_file_count );
377+ ASSERT (fs_event_created == fs_event_file_count );
378+ ASSERT (close_cb_called == 2 );
379+
380+ /* Cleanup */
381+ fs_event_unlink_files_in_subdir (NULL );
382+ remove ("watch_dir/file2" );
383+ remove ("watch_dir/file1" );
384+ remove ("watch_dir/subdir" );
385+ remove ("watch_dir/" );
386+
387+ MAKE_VALGRIND_HAPPY ();
388+ return 0 ;
389+ #else
390+ RETURN_SKIP ("Recursive directory watching not supported on this platform." );
391+ #endif
392+ }
393+
394+
285395TEST_IMPL (fs_event_watch_file ) {
286396 uv_loop_t * loop = uv_default_loop ();
287397 int r ;
0 commit comments