]> git.ipfire.org Git - thirdparty/git.git/blob - chdir-notify.c
Merge branch 'rs/remove-approxidate-relative'
[thirdparty/git.git] / chdir-notify.c
1 #include "cache.h"
2 #include "abspath.h"
3 #include "chdir-notify.h"
4 #include "list.h"
5 #include "strbuf.h"
6
7 struct chdir_notify_entry {
8 const char *name;
9 chdir_notify_callback cb;
10 void *data;
11 struct list_head list;
12 };
13 static LIST_HEAD(chdir_notify_entries);
14
15 void chdir_notify_register(const char *name,
16 chdir_notify_callback cb,
17 void *data)
18 {
19 struct chdir_notify_entry *e = xmalloc(sizeof(*e));
20 e->name = name;
21 e->cb = cb;
22 e->data = data;
23 list_add_tail(&e->list, &chdir_notify_entries);
24 }
25
26 static void reparent_cb(const char *name,
27 const char *old_cwd,
28 const char *new_cwd,
29 void *data)
30 {
31 char **path = data;
32 char *tmp = *path;
33
34 if (!tmp)
35 return;
36
37 *path = reparent_relative_path(old_cwd, new_cwd, tmp);
38 free(tmp);
39
40 if (name) {
41 trace_printf_key(&trace_setup_key,
42 "setup: reparent %s to '%s'",
43 name, *path);
44 }
45 }
46
47 void chdir_notify_reparent(const char *name, char **path)
48 {
49 chdir_notify_register(name, reparent_cb, path);
50 }
51
52 int chdir_notify(const char *new_cwd)
53 {
54 struct strbuf old_cwd = STRBUF_INIT;
55 struct list_head *pos;
56
57 if (strbuf_getcwd(&old_cwd) < 0)
58 return -1;
59 if (chdir(new_cwd) < 0) {
60 int saved_errno = errno;
61 strbuf_release(&old_cwd);
62 errno = saved_errno;
63 return -1;
64 }
65
66 trace_printf_key(&trace_setup_key,
67 "setup: chdir from '%s' to '%s'",
68 old_cwd.buf, new_cwd);
69
70 list_for_each(pos, &chdir_notify_entries) {
71 struct chdir_notify_entry *e =
72 list_entry(pos, struct chdir_notify_entry, list);
73 e->cb(e->name, old_cwd.buf, new_cwd, e->data);
74 }
75
76 strbuf_release(&old_cwd);
77 return 0;
78 }
79
80 char *reparent_relative_path(const char *old_cwd,
81 const char *new_cwd,
82 const char *path)
83 {
84 char *ret, *full;
85
86 if (is_absolute_path(path))
87 return xstrdup(path);
88
89 full = xstrfmt("%s/%s", old_cwd, path);
90 ret = xstrdup(remove_leading_path(full, new_cwd));
91 free(full);
92
93 return ret;
94 }