compat/mingw: support POSIX semantics for atomic renames
[git/gitster.git] / compat / fsmonitor / fsm-listen-win32.c
blob80e092b511c9733ab717d98053798f62ea5d2685
1 #include "git-compat-util.h"
2 #include "config.h"
3 #include "fsmonitor-ll.h"
4 #include "fsm-listen.h"
5 #include "fsmonitor--daemon.h"
6 #include "gettext.h"
7 #include "simple-ipc.h"
8 #include "trace2.h"
11 * The documentation of ReadDirectoryChangesW() states that the maximum
12 * buffer size is 64K when the monitored directory is remote.
14 * Larger buffers may be used when the monitored directory is local and
15 * will help us receive events faster from the kernel and avoid dropped
16 * events.
18 * So we try to use a very large buffer and silently fallback to 64K if
19 * we get an error.
21 #define MAX_RDCW_BUF_FALLBACK (65536)
22 #define MAX_RDCW_BUF (65536 * 8)
24 struct one_watch
26 char buffer[MAX_RDCW_BUF];
27 DWORD buf_len;
28 DWORD count;
30 struct strbuf path;
31 wchar_t wpath_longname[MAX_PATH + 1];
32 DWORD wpath_longname_len;
34 HANDLE hDir;
35 HANDLE hEvent;
36 OVERLAPPED overlapped;
39 * Is there an active ReadDirectoryChangesW() call pending. If so, we
40 * need to later call GetOverlappedResult() and possibly CancelIoEx().
42 BOOL is_active;
45 * Are shortnames enabled on the containing drive? This is
46 * always true for "C:/" drives and usually never true for
47 * other drives.
49 * We only set this for the worktree because we only need to
50 * convert shortname paths to longname paths for items we send
51 * to clients. (We don't care about shortname expansion for
52 * paths inside a GITDIR because we never send them to
53 * clients.)
55 BOOL has_shortnames;
56 BOOL has_tilde;
57 wchar_t dotgit_shortname[16]; /* for 8.3 name */
60 struct fsm_listen_data
62 struct one_watch *watch_worktree;
63 struct one_watch *watch_gitdir;
65 HANDLE hEventShutdown;
67 HANDLE hListener[3]; /* we don't own these handles */
68 #define LISTENER_SHUTDOWN 0
69 #define LISTENER_HAVE_DATA_WORKTREE 1
70 #define LISTENER_HAVE_DATA_GITDIR 2
71 int nr_listener_handles;
75 * Convert the WCHAR path from the event into UTF8 and normalize it.
77 * `wpath_len` is in WCHARS not bytes.
79 static int normalize_path_in_utf8(wchar_t *wpath, DWORD wpath_len,
80 struct strbuf *normalized_path)
82 int reserve;
83 int len = 0;
85 strbuf_reset(normalized_path);
86 if (!wpath_len)
87 goto normalize;
90 * Pre-reserve enough space in the UTF8 buffer for
91 * each Unicode WCHAR character to be mapped into a
92 * sequence of 2 UTF8 characters. That should let us
93 * avoid ERROR_INSUFFICIENT_BUFFER 99.9+% of the time.
95 reserve = 2 * wpath_len + 1;
96 strbuf_grow(normalized_path, reserve);
98 for (;;) {
99 len = WideCharToMultiByte(CP_UTF8, 0,
100 wpath, wpath_len,
101 normalized_path->buf,
102 strbuf_avail(normalized_path) - 1,
103 NULL, NULL);
104 if (len > 0)
105 goto normalize;
106 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
107 error(_("[GLE %ld] could not convert path to UTF-8: '%.*ls'"),
108 GetLastError(), (int)wpath_len, wpath);
109 return -1;
112 strbuf_grow(normalized_path,
113 strbuf_avail(normalized_path) + reserve);
116 normalize:
117 strbuf_setlen(normalized_path, len);
118 return strbuf_normalize_path(normalized_path);
122 * See if the worktree root directory has shortnames enabled.
123 * This will help us decide if we need to do an expensive shortname
124 * to longname conversion on every notification event.
126 * We do not want to create a file to test this, so we assume that the
127 * root directory contains a ".git" file or directory. (Our caller
128 * only calls us for the worktree root, so this should be fine.)
130 * Remember the spelling of the shortname for ".git" if it exists.
132 static void check_for_shortnames(struct one_watch *watch)
134 wchar_t buf_in[MAX_PATH + 1];
135 wchar_t buf_out[MAX_PATH + 1];
136 wchar_t *last;
137 wchar_t *p;
139 /* build L"<wt-root-path>/.git" */
140 swprintf(buf_in, ARRAY_SIZE(buf_in) - 1, L"%ls.git",
141 watch->wpath_longname);
143 if (!GetShortPathNameW(buf_in, buf_out, ARRAY_SIZE(buf_out)))
144 return;
147 * Get the final filename component of the shortpath.
148 * We know that the path does not have a final slash.
150 for (last = p = buf_out; *p; p++)
151 if (*p == L'/' || *p == '\\')
152 last = p + 1;
154 if (!wcscmp(last, L".git"))
155 return;
157 watch->has_shortnames = 1;
158 wcsncpy(watch->dotgit_shortname, last,
159 ARRAY_SIZE(watch->dotgit_shortname));
162 * The shortname for ".git" is usually of the form "GIT~1", so
163 * we should be able to avoid shortname to longname mapping on
164 * every notification event if the source string does not
165 * contain a "~".
167 * However, the documentation for GetLongPathNameW() says
168 * that there are filesystems that don't follow that pattern
169 * and warns against this optimization.
171 * Lets test this.
173 if (wcschr(watch->dotgit_shortname, L'~'))
174 watch->has_tilde = 1;
177 enum get_relative_result {
178 GRR_NO_CONVERSION_NEEDED,
179 GRR_HAVE_CONVERSION,
180 GRR_SHUTDOWN,
184 * Info notification paths are relative to the root of the watch.
185 * If our CWD is still at the root, then we can use relative paths
186 * to convert from shortnames to longnames. If our process has a
187 * different CWD, then we need to construct an absolute path, do
188 * the conversion, and then return the root-relative portion.
190 * We use the longname form of the root as our basis and assume that
191 * it already has a trailing slash.
193 * `wpath_len` is in WCHARS not bytes.
195 static enum get_relative_result get_relative_longname(
196 struct one_watch *watch,
197 const wchar_t *wpath, DWORD wpath_len,
198 wchar_t *wpath_longname, size_t bufsize_wpath_longname)
200 wchar_t buf_in[2 * MAX_PATH + 1];
201 wchar_t buf_out[MAX_PATH + 1];
202 DWORD root_len;
203 DWORD out_len;
206 * Build L"<wt-root-path>/<event-rel-path>"
207 * Note that the <event-rel-path> might not be null terminated
208 * so we avoid swprintf() constructions.
210 root_len = watch->wpath_longname_len;
211 if (root_len + wpath_len >= ARRAY_SIZE(buf_in)) {
213 * This should not happen. We cannot append the observed
214 * relative path onto the end of the worktree root path
215 * without overflowing the buffer. Just give up.
217 return GRR_SHUTDOWN;
219 wcsncpy(buf_in, watch->wpath_longname, root_len);
220 wcsncpy(buf_in + root_len, wpath, wpath_len);
221 buf_in[root_len + wpath_len] = 0;
224 * We don't actually know if the source pathname is a
225 * shortname or a longname. This Windows routine allows
226 * either to be given as input.
228 out_len = GetLongPathNameW(buf_in, buf_out, ARRAY_SIZE(buf_out));
229 if (!out_len) {
231 * The shortname to longname conversion can fail for
232 * various reasons, for example if the file has been
233 * deleted. (That is, if we just received a
234 * delete-file notification event and the file is
235 * already gone, we can't ask the file system to
236 * lookup the longname for it. Likewise, for moves
237 * and renames where we are given the old name.)
239 * Since deleting or moving a file or directory by its
240 * shortname is rather obscure, I'm going ignore the
241 * failure and ask the caller to report the original
242 * relative path. This seems kinder than failing here
243 * and forcing a resync. Besides, forcing a resync on
244 * every file/directory delete would effectively
245 * cripple monitoring.
247 * We might revisit this in the future.
249 return GRR_NO_CONVERSION_NEEDED;
252 if (!wcscmp(buf_in, buf_out)) {
254 * The path does not have a shortname alias.
256 return GRR_NO_CONVERSION_NEEDED;
259 if (wcsncmp(buf_in, buf_out, root_len)) {
261 * The spelling of the root directory portion of the computed
262 * longname has changed. This should not happen. Basically,
263 * it means that we don't know where (without recomputing the
264 * longname of just the root directory) to split out the
265 * relative path. Since this should not happen, I'm just
266 * going to let this fail and force a shutdown (because all
267 * subsequent events are probably going to see the same
268 * mismatch).
270 return GRR_SHUTDOWN;
273 if (out_len - root_len >= bufsize_wpath_longname) {
275 * This should not happen. We cannot copy the root-relative
276 * portion of the path into the provided buffer without an
277 * overrun. Just give up.
279 return GRR_SHUTDOWN;
282 /* Return the worktree root-relative portion of the longname. */
284 wcscpy(wpath_longname, buf_out + root_len);
285 return GRR_HAVE_CONVERSION;
288 void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
290 SetEvent(state->listen_data->hListener[LISTENER_SHUTDOWN]);
293 static struct one_watch *create_watch(const char *path)
295 struct one_watch *watch = NULL;
296 DWORD desired_access = FILE_LIST_DIRECTORY;
297 DWORD share_mode =
298 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
299 HANDLE hDir;
300 DWORD len_longname;
301 wchar_t wpath[MAX_PATH + 1];
302 wchar_t wpath_longname[MAX_PATH + 1];
304 if (xutftowcs_path(wpath, path) < 0) {
305 error(_("could not convert to wide characters: '%s'"), path);
306 return NULL;
309 hDir = CreateFileW(wpath,
310 desired_access, share_mode, NULL, OPEN_EXISTING,
311 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
312 NULL);
313 if (hDir == INVALID_HANDLE_VALUE) {
314 error(_("[GLE %ld] could not watch '%s'"),
315 GetLastError(), path);
316 return NULL;
319 len_longname = GetLongPathNameW(wpath, wpath_longname,
320 ARRAY_SIZE(wpath_longname));
321 if (!len_longname) {
322 error(_("[GLE %ld] could not get longname of '%s'"),
323 GetLastError(), path);
324 CloseHandle(hDir);
325 return NULL;
328 if (wpath_longname[len_longname - 1] != L'/' &&
329 wpath_longname[len_longname - 1] != L'\\') {
330 wpath_longname[len_longname++] = L'/';
331 wpath_longname[len_longname] = 0;
334 CALLOC_ARRAY(watch, 1);
336 watch->buf_len = sizeof(watch->buffer); /* assume full MAX_RDCW_BUF */
338 strbuf_init(&watch->path, 0);
339 strbuf_addstr(&watch->path, path);
341 wcscpy(watch->wpath_longname, wpath_longname);
342 watch->wpath_longname_len = len_longname;
344 watch->hDir = hDir;
345 watch->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
347 return watch;
350 static void destroy_watch(struct one_watch *watch)
352 if (!watch)
353 return;
355 strbuf_release(&watch->path);
356 if (watch->hDir != INVALID_HANDLE_VALUE)
357 CloseHandle(watch->hDir);
358 if (watch->hEvent != INVALID_HANDLE_VALUE)
359 CloseHandle(watch->hEvent);
361 free(watch);
364 static int start_rdcw_watch(struct one_watch *watch)
366 DWORD dwNotifyFilter =
367 FILE_NOTIFY_CHANGE_FILE_NAME |
368 FILE_NOTIFY_CHANGE_DIR_NAME |
369 FILE_NOTIFY_CHANGE_ATTRIBUTES |
370 FILE_NOTIFY_CHANGE_SIZE |
371 FILE_NOTIFY_CHANGE_LAST_WRITE |
372 FILE_NOTIFY_CHANGE_CREATION;
374 ResetEvent(watch->hEvent);
376 memset(&watch->overlapped, 0, sizeof(watch->overlapped));
377 watch->overlapped.hEvent = watch->hEvent;
380 * Queue an async call using Overlapped IO. This returns immediately.
381 * Our event handle will be signalled when the real result is available.
383 * The return value here just means that we successfully queued it.
384 * We won't know if the Read...() actually produces data until later.
386 watch->is_active = ReadDirectoryChangesW(
387 watch->hDir, watch->buffer, watch->buf_len, TRUE,
388 dwNotifyFilter, &watch->count, &watch->overlapped, NULL);
390 if (watch->is_active)
391 return 0;
393 error(_("ReadDirectoryChangedW failed on '%s' [GLE %ld]"),
394 watch->path.buf, GetLastError());
395 return -1;
398 static int recv_rdcw_watch(struct one_watch *watch)
400 DWORD gle;
402 watch->is_active = FALSE;
405 * The overlapped result is ready. If the Read...() was successful
406 * we finally receive the actual result into our buffer.
408 if (GetOverlappedResult(watch->hDir, &watch->overlapped, &watch->count,
409 TRUE))
410 return 0;
412 gle = GetLastError();
413 if (gle == ERROR_INVALID_PARAMETER &&
415 * The kernel throws an invalid parameter error when our
416 * buffer is too big and we are pointed at a remote
417 * directory (and possibly for other reasons). Quietly
418 * set it down and try again.
420 * See note about MAX_RDCW_BUF at the top.
422 watch->buf_len > MAX_RDCW_BUF_FALLBACK) {
423 watch->buf_len = MAX_RDCW_BUF_FALLBACK;
424 return -2;
428 * GetOverlappedResult() fails if the watched directory is
429 * deleted while we were waiting for an overlapped IO to
430 * complete. The documentation did not list specific errors,
431 * but I observed ERROR_ACCESS_DENIED (0x05) errors during
432 * testing.
434 * Note that we only get notificaiton events for events
435 * *within* the directory, not *on* the directory itself.
436 * (These might be properies of the parent directory, for
437 * example).
439 * NEEDSWORK: We might try to check for the deleted directory
440 * case and return a better error message, but I'm not sure it
441 * is worth it.
443 * Shutdown if we get any error.
446 error(_("GetOverlappedResult failed on '%s' [GLE %ld]"),
447 watch->path.buf, gle);
448 return -1;
451 static void cancel_rdcw_watch(struct one_watch *watch)
453 DWORD count;
455 if (!watch || !watch->is_active)
456 return;
459 * The calls to ReadDirectoryChangesW() and GetOverlappedResult()
460 * form a "pair" (my term) where we queue an IO and promise to
461 * hang around and wait for the kernel to give us the result.
463 * If for some reason after we queue the IO, we have to quit
464 * or otherwise not stick around for the second half, we must
465 * tell the kernel to abort the IO. This prevents the kernel
466 * from writing to our buffer and/or signalling our event
467 * after we free them.
469 * (Ask me how much fun it was to track that one down).
471 CancelIoEx(watch->hDir, &watch->overlapped);
472 GetOverlappedResult(watch->hDir, &watch->overlapped, &count, TRUE);
473 watch->is_active = FALSE;
477 * Process a single relative pathname event.
478 * Return 1 if we should shutdown.
480 static int process_1_worktree_event(
481 struct string_list *cookie_list,
482 struct fsmonitor_batch **batch,
483 const struct strbuf *path,
484 enum fsmonitor_path_type t,
485 DWORD info_action)
487 const char *slash;
489 switch (t) {
490 case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX:
491 /* special case cookie files within .git */
493 /* Use just the filename of the cookie file. */
494 slash = find_last_dir_sep(path->buf);
495 string_list_append(cookie_list,
496 slash ? slash + 1 : path->buf);
497 break;
499 case IS_INSIDE_DOT_GIT:
500 /* ignore everything inside of "<worktree>/.git/" */
501 break;
503 case IS_DOT_GIT:
504 /* "<worktree>/.git" was deleted (or renamed away) */
505 if ((info_action == FILE_ACTION_REMOVED) ||
506 (info_action == FILE_ACTION_RENAMED_OLD_NAME)) {
507 trace2_data_string("fsmonitor", NULL,
508 "fsm-listen/dotgit",
509 "removed");
510 return 1;
512 break;
514 case IS_WORKDIR_PATH:
515 /* queue normal pathname */
516 if (!*batch)
517 *batch = fsmonitor_batch__new();
518 fsmonitor_batch__add_path(*batch, path->buf);
519 break;
521 case IS_GITDIR:
522 case IS_INSIDE_GITDIR:
523 case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
524 default:
525 BUG("unexpected path classification '%d' for '%s'",
526 t, path->buf);
529 return 0;
533 * Process filesystem events that happen anywhere (recursively) under the
534 * <worktree> root directory. For a normal working directory, this includes
535 * both version controlled files and the contents of the .git/ directory.
537 * If <worktree>/.git is a file, then we only see events for the file
538 * itself.
540 static int process_worktree_events(struct fsmonitor_daemon_state *state)
542 struct fsm_listen_data *data = state->listen_data;
543 struct one_watch *watch = data->watch_worktree;
544 struct strbuf path = STRBUF_INIT;
545 struct string_list cookie_list = STRING_LIST_INIT_DUP;
546 struct fsmonitor_batch *batch = NULL;
547 const char *p = watch->buffer;
548 wchar_t wpath_longname[MAX_PATH + 1];
551 * If the kernel gets more events than will fit in the kernel
552 * buffer associated with our RDCW handle, it drops them and
553 * returns a count of zero.
555 * Yes, the call returns WITHOUT error and with length zero.
556 * This is the documented behavior. (My testing has confirmed
557 * that it also sets the last error to ERROR_NOTIFY_ENUM_DIR,
558 * but we do not rely on that since the function did not
559 * return an error and it is not documented.)
561 * (The "overflow" case is not ambiguous with the "no data" case
562 * because we did an INFINITE wait.)
564 * This means we have a gap in coverage. Tell the daemon layer
565 * to resync.
567 if (!watch->count) {
568 trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel",
569 "overflow");
570 fsmonitor_force_resync(state);
571 return LISTENER_HAVE_DATA_WORKTREE;
575 * On Windows, `info` contains an "array" of paths that are
576 * relative to the root of whichever directory handle received
577 * the event.
579 for (;;) {
580 FILE_NOTIFY_INFORMATION *info = (void *)p;
581 wchar_t *wpath = info->FileName;
582 DWORD wpath_len = info->FileNameLength / sizeof(WCHAR);
583 enum fsmonitor_path_type t;
584 enum get_relative_result grr;
586 if (watch->has_shortnames) {
587 if (!wcscmp(wpath, watch->dotgit_shortname)) {
589 * This event exactly matches the
590 * spelling of the shortname of
591 * ".git", so we can skip some steps.
593 * (This case is odd because the user
594 * can "rm -rf GIT~1" and we cannot
595 * use the filesystem to map it back
596 * to ".git".)
598 strbuf_reset(&path);
599 strbuf_addstr(&path, ".git");
600 t = IS_DOT_GIT;
601 goto process_it;
604 if (watch->has_tilde && !wcschr(wpath, L'~')) {
606 * Shortnames on this filesystem have tildes
607 * and the notification path does not have
608 * one, so we assume that it is a longname.
610 goto normalize_it;
613 grr = get_relative_longname(watch, wpath, wpath_len,
614 wpath_longname,
615 ARRAY_SIZE(wpath_longname));
616 switch (grr) {
617 case GRR_NO_CONVERSION_NEEDED: /* use info buffer as is */
618 break;
619 case GRR_HAVE_CONVERSION:
620 wpath = wpath_longname;
621 wpath_len = wcslen(wpath);
622 break;
623 default:
624 case GRR_SHUTDOWN:
625 goto force_shutdown;
629 normalize_it:
630 if (normalize_path_in_utf8(wpath, wpath_len, &path) == -1)
631 goto skip_this_path;
633 t = fsmonitor_classify_path_workdir_relative(path.buf);
635 process_it:
636 if (process_1_worktree_event(&cookie_list, &batch, &path, t,
637 info->Action))
638 goto force_shutdown;
640 skip_this_path:
641 if (!info->NextEntryOffset)
642 break;
643 p += info->NextEntryOffset;
646 fsmonitor_publish(state, batch, &cookie_list);
647 batch = NULL;
648 string_list_clear(&cookie_list, 0);
649 strbuf_release(&path);
650 return LISTENER_HAVE_DATA_WORKTREE;
652 force_shutdown:
653 fsmonitor_batch__free_list(batch);
654 string_list_clear(&cookie_list, 0);
655 strbuf_release(&path);
656 return LISTENER_SHUTDOWN;
660 * Process filesystem events that happened anywhere (recursively) under the
661 * external <gitdir> (such as non-primary worktrees or submodules).
662 * We only care about cookie files that our client threads created here.
664 * Note that we DO NOT get filesystem events on the external <gitdir>
665 * itself (it is not inside something that we are watching). In particular,
666 * we do not get an event if the external <gitdir> is deleted.
668 * Also, we do not care about shortnames within the external <gitdir>, since
669 * we never send these paths to clients.
671 static int process_gitdir_events(struct fsmonitor_daemon_state *state)
673 struct fsm_listen_data *data = state->listen_data;
674 struct one_watch *watch = data->watch_gitdir;
675 struct strbuf path = STRBUF_INIT;
676 struct string_list cookie_list = STRING_LIST_INIT_DUP;
677 const char *p = watch->buffer;
679 if (!watch->count) {
680 trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel",
681 "overflow");
682 fsmonitor_force_resync(state);
683 return LISTENER_HAVE_DATA_GITDIR;
686 for (;;) {
687 FILE_NOTIFY_INFORMATION *info = (void *)p;
688 const char *slash;
689 enum fsmonitor_path_type t;
691 if (normalize_path_in_utf8(
692 info->FileName,
693 info->FileNameLength / sizeof(WCHAR),
694 &path) == -1)
695 goto skip_this_path;
697 t = fsmonitor_classify_path_gitdir_relative(path.buf);
699 switch (t) {
700 case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
701 /* special case cookie files within gitdir */
703 /* Use just the filename of the cookie file. */
704 slash = find_last_dir_sep(path.buf);
705 string_list_append(&cookie_list,
706 slash ? slash + 1 : path.buf);
707 break;
709 case IS_INSIDE_GITDIR:
710 goto skip_this_path;
712 default:
713 BUG("unexpected path classification '%d' for '%s'",
714 t, path.buf);
717 skip_this_path:
718 if (!info->NextEntryOffset)
719 break;
720 p += info->NextEntryOffset;
723 fsmonitor_publish(state, NULL, &cookie_list);
724 string_list_clear(&cookie_list, 0);
725 strbuf_release(&path);
726 return LISTENER_HAVE_DATA_GITDIR;
729 void fsm_listen__loop(struct fsmonitor_daemon_state *state)
731 struct fsm_listen_data *data = state->listen_data;
732 DWORD dwWait;
733 int result;
735 state->listen_error_code = 0;
737 if (start_rdcw_watch(data->watch_worktree) == -1)
738 goto force_error_stop;
740 if (data->watch_gitdir &&
741 start_rdcw_watch(data->watch_gitdir) == -1)
742 goto force_error_stop;
745 * Now that we've established the rdcw watches, we can start
746 * serving clients.
748 ipc_server_start_async(state->ipc_server_data);
750 for (;;) {
751 dwWait = WaitForMultipleObjects(data->nr_listener_handles,
752 data->hListener,
753 FALSE, INFINITE);
755 if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_WORKTREE) {
756 result = recv_rdcw_watch(data->watch_worktree);
757 if (result == -1) {
758 /* hard error */
759 goto force_error_stop;
761 if (result == -2) {
762 /* retryable error */
763 if (start_rdcw_watch(data->watch_worktree) == -1)
764 goto force_error_stop;
765 continue;
768 /* have data */
769 if (process_worktree_events(state) == LISTENER_SHUTDOWN)
770 goto force_shutdown;
771 if (start_rdcw_watch(data->watch_worktree) == -1)
772 goto force_error_stop;
773 continue;
776 if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_GITDIR) {
777 result = recv_rdcw_watch(data->watch_gitdir);
778 if (result == -1) {
779 /* hard error */
780 goto force_error_stop;
782 if (result == -2) {
783 /* retryable error */
784 if (start_rdcw_watch(data->watch_gitdir) == -1)
785 goto force_error_stop;
786 continue;
789 /* have data */
790 if (process_gitdir_events(state) == LISTENER_SHUTDOWN)
791 goto force_shutdown;
792 if (start_rdcw_watch(data->watch_gitdir) == -1)
793 goto force_error_stop;
794 continue;
797 if (dwWait == WAIT_OBJECT_0 + LISTENER_SHUTDOWN)
798 goto clean_shutdown;
800 error(_("could not read directory changes [GLE %ld]"),
801 GetLastError());
802 goto force_error_stop;
805 force_error_stop:
806 state->listen_error_code = -1;
808 force_shutdown:
810 * Tell the IPC thead pool to stop (which completes the await
811 * in the main thread (which will also signal this thread (if
812 * we are still alive))).
814 ipc_server_stop_async(state->ipc_server_data);
816 clean_shutdown:
817 cancel_rdcw_watch(data->watch_worktree);
818 cancel_rdcw_watch(data->watch_gitdir);
821 int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
823 struct fsm_listen_data *data;
825 CALLOC_ARRAY(data, 1);
827 data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
829 data->watch_worktree = create_watch(state->path_worktree_watch.buf);
830 if (!data->watch_worktree)
831 goto failed;
833 check_for_shortnames(data->watch_worktree);
835 if (state->nr_paths_watching > 1) {
836 data->watch_gitdir = create_watch(state->path_gitdir_watch.buf);
837 if (!data->watch_gitdir)
838 goto failed;
841 data->hListener[LISTENER_SHUTDOWN] = data->hEventShutdown;
842 data->nr_listener_handles++;
844 data->hListener[LISTENER_HAVE_DATA_WORKTREE] =
845 data->watch_worktree->hEvent;
846 data->nr_listener_handles++;
848 if (data->watch_gitdir) {
849 data->hListener[LISTENER_HAVE_DATA_GITDIR] =
850 data->watch_gitdir->hEvent;
851 data->nr_listener_handles++;
854 state->listen_data = data;
855 return 0;
857 failed:
858 CloseHandle(data->hEventShutdown);
859 destroy_watch(data->watch_worktree);
860 destroy_watch(data->watch_gitdir);
862 return -1;
865 void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
867 struct fsm_listen_data *data;
869 if (!state || !state->listen_data)
870 return;
872 data = state->listen_data;
874 CloseHandle(data->hEventShutdown);
875 destroy_watch(data->watch_worktree);
876 destroy_watch(data->watch_gitdir);
878 FREE_AND_NULL(state->listen_data);