fsmonitor: avoid memory leak in `fsm_settings__get_incompatible_msg()`
[git/debian.git] / fsmonitor-settings.c
blob464424a1e924c63073a501fc0b9c030904074314
1 #include "cache.h"
2 #include "config.h"
3 #include "repository.h"
4 #include "fsmonitor-settings.h"
6 /*
7 * We keep this structure defintion private and have getters
8 * for all fields so that we can lazy load it as needed.
9 */
10 struct fsmonitor_settings {
11 enum fsmonitor_mode mode;
12 enum fsmonitor_reason reason;
13 char *hook_path;
16 static enum fsmonitor_reason check_for_incompatible(struct repository *r)
18 if (!r->worktree) {
20 * Bare repositories don't have a working directory and
21 * therefore have nothing to watch.
23 return FSMONITOR_REASON_BARE;
26 #ifdef HAVE_FSMONITOR_OS_SETTINGS
28 enum fsmonitor_reason reason;
30 reason = fsm_os__incompatible(r);
31 if (reason != FSMONITOR_REASON_OK)
32 return reason;
34 #endif
36 return FSMONITOR_REASON_OK;
39 static struct fsmonitor_settings *alloc_settings(void)
41 struct fsmonitor_settings *s;
43 CALLOC_ARRAY(s, 1);
44 s->mode = FSMONITOR_MODE_DISABLED;
45 s->reason = FSMONITOR_REASON_UNTESTED;
47 return s;
50 static void lookup_fsmonitor_settings(struct repository *r)
52 const char *const_str;
53 int bool_value;
55 if (r->settings.fsmonitor)
56 return;
59 * Overload the existing "core.fsmonitor" config setting (which
60 * has historically been either unset or a hook pathname) to
61 * now allow a boolean value to enable the builtin FSMonitor
62 * or to turn everything off. (This does imply that you can't
63 * use a hook script named "true" or "false", but that's OK.)
65 switch (repo_config_get_maybe_bool(r, "core.fsmonitor", &bool_value)) {
67 case 0: /* config value was set to <bool> */
68 if (bool_value)
69 fsm_settings__set_ipc(r);
70 else
71 fsm_settings__set_disabled(r);
72 return;
74 case 1: /* config value was unset */
75 const_str = getenv("GIT_TEST_FSMONITOR");
76 break;
78 case -1: /* config value set to an arbitrary string */
79 if (repo_config_get_pathname(r, "core.fsmonitor", &const_str))
80 return; /* should not happen */
81 break;
83 default: /* should not happen */
84 return;
87 if (const_str && *const_str)
88 fsm_settings__set_hook(r, const_str);
89 else
90 fsm_settings__set_disabled(r);
93 enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
95 if (!r)
96 r = the_repository;
97 if (!r->settings.fsmonitor)
98 lookup_fsmonitor_settings(r);
100 return r->settings.fsmonitor->mode;
103 const char *fsm_settings__get_hook_path(struct repository *r)
105 if (!r)
106 r = the_repository;
107 if (!r->settings.fsmonitor)
108 lookup_fsmonitor_settings(r);
110 return r->settings.fsmonitor->hook_path;
113 void fsm_settings__set_ipc(struct repository *r)
115 enum fsmonitor_reason reason = check_for_incompatible(r);
117 if (reason != FSMONITOR_REASON_OK) {
118 fsm_settings__set_incompatible(r, reason);
119 return;
123 * Caller requested IPC explicitly, so avoid (possibly
124 * recursive) config lookup.
126 if (!r)
127 r = the_repository;
128 if (!r->settings.fsmonitor)
129 r->settings.fsmonitor = alloc_settings();
131 r->settings.fsmonitor->mode = FSMONITOR_MODE_IPC;
132 r->settings.fsmonitor->reason = reason;
133 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
136 void fsm_settings__set_hook(struct repository *r, const char *path)
138 enum fsmonitor_reason reason = check_for_incompatible(r);
140 if (reason != FSMONITOR_REASON_OK) {
141 fsm_settings__set_incompatible(r, reason);
142 return;
146 * Caller requested hook explicitly, so avoid (possibly
147 * recursive) config lookup.
149 if (!r)
150 r = the_repository;
151 if (!r->settings.fsmonitor)
152 r->settings.fsmonitor = alloc_settings();
154 r->settings.fsmonitor->mode = FSMONITOR_MODE_HOOK;
155 r->settings.fsmonitor->reason = reason;
156 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
157 r->settings.fsmonitor->hook_path = strdup(path);
160 void fsm_settings__set_disabled(struct repository *r)
162 if (!r)
163 r = the_repository;
164 if (!r->settings.fsmonitor)
165 r->settings.fsmonitor = alloc_settings();
167 r->settings.fsmonitor->mode = FSMONITOR_MODE_DISABLED;
168 r->settings.fsmonitor->reason = FSMONITOR_REASON_OK;
169 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
172 void fsm_settings__set_incompatible(struct repository *r,
173 enum fsmonitor_reason reason)
175 if (!r)
176 r = the_repository;
177 if (!r->settings.fsmonitor)
178 r->settings.fsmonitor = alloc_settings();
180 r->settings.fsmonitor->mode = FSMONITOR_MODE_INCOMPATIBLE;
181 r->settings.fsmonitor->reason = reason;
182 FREE_AND_NULL(r->settings.fsmonitor->hook_path);
185 enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
187 if (!r)
188 r = the_repository;
189 if (!r->settings.fsmonitor)
190 lookup_fsmonitor_settings(r);
192 return r->settings.fsmonitor->reason;
195 char *fsm_settings__get_incompatible_msg(const struct repository *r,
196 enum fsmonitor_reason reason)
198 struct strbuf msg = STRBUF_INIT;
200 switch (reason) {
201 case FSMONITOR_REASON_UNTESTED:
202 case FSMONITOR_REASON_OK:
203 goto done;
205 case FSMONITOR_REASON_BARE: {
206 char *cwd = xgetcwd();
208 strbuf_addf(&msg,
209 _("bare repository '%s' is incompatible with fsmonitor"),
210 cwd);
211 free(cwd);
212 goto done;
215 case FSMONITOR_REASON_ERROR:
216 strbuf_addf(&msg,
217 _("repository '%s' is incompatible with fsmonitor due to errors"),
218 r->worktree);
219 goto done;
221 case FSMONITOR_REASON_REMOTE:
222 strbuf_addf(&msg,
223 _("remote repository '%s' is incompatible with fsmonitor"),
224 r->worktree);
225 goto done;
227 case FSMONITOR_REASON_VFS4GIT:
228 strbuf_addf(&msg,
229 _("virtual repository '%s' is incompatible with fsmonitor"),
230 r->worktree);
231 goto done;
233 case FSMONITOR_REASON_NOSOCKETS:
234 strbuf_addf(&msg,
235 _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"),
236 r->worktree);
237 goto done;
240 BUG("Unhandled case in fsm_settings__get_incompatible_msg: '%d'",
241 reason);
243 done:
244 return strbuf_detach(&msg, NULL);