mergetools/xxdiff: prevent segfaults from stopping difftool
[git/debian.git] / chdir-notify.c
blob5f7f2c2ac236f7aab50f0bbdc46324fd56213be9
1 #include "cache.h"
2 #include "chdir-notify.h"
3 #include "list.h"
4 #include "strbuf.h"
6 struct chdir_notify_entry {
7 const char *name;
8 chdir_notify_callback cb;
9 void *data;
10 struct list_head list;
12 static LIST_HEAD(chdir_notify_entries);
14 void chdir_notify_register(const char *name,
15 chdir_notify_callback cb,
16 void *data)
18 struct chdir_notify_entry *e = xmalloc(sizeof(*e));
19 e->name = name;
20 e->cb = cb;
21 e->data = data;
22 list_add_tail(&e->list, &chdir_notify_entries);
25 static void reparent_cb(const char *name,
26 const char *old_cwd,
27 const char *new_cwd,
28 void *data)
30 char **path = data;
31 char *tmp = *path;
33 if (!tmp)
34 return;
36 *path = reparent_relative_path(old_cwd, new_cwd, tmp);
37 free(tmp);
39 if (name) {
40 trace_printf_key(&trace_setup_key,
41 "setup: reparent %s to '%s'",
42 name, *path);
46 void chdir_notify_reparent(const char *name, char **path)
48 chdir_notify_register(name, reparent_cb, path);
51 int chdir_notify(const char *new_cwd)
53 struct strbuf old_cwd = STRBUF_INIT;
54 struct list_head *pos;
56 if (strbuf_getcwd(&old_cwd) < 0)
57 return -1;
58 if (chdir(new_cwd) < 0) {
59 int saved_errno = errno;
60 strbuf_release(&old_cwd);
61 errno = saved_errno;
62 return -1;
65 trace_printf_key(&trace_setup_key,
66 "setup: chdir from '%s' to '%s'",
67 old_cwd.buf, new_cwd);
69 list_for_each(pos, &chdir_notify_entries) {
70 struct chdir_notify_entry *e =
71 list_entry(pos, struct chdir_notify_entry, list);
72 e->cb(e->name, old_cwd.buf, new_cwd, e->data);
75 strbuf_release(&old_cwd);
76 return 0;
79 char *reparent_relative_path(const char *old_cwd,
80 const char *new_cwd,
81 const char *path)
83 char *ret, *full;
85 if (is_absolute_path(path))
86 return xstrdup(path);
88 full = xstrfmt("%s/%s", old_cwd, path);
89 ret = xstrdup(remove_leading_path(full, new_cwd));
90 free(full);
92 return ret;