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