]>
Commit | Line | Data |
---|---|---|
b7b189cd | 1 | #include "git-compat-util.h" |
0b027f6c | 2 | #include "abspath.h" |
2b5ed373 JK |
3 | #include "chdir-notify.h" |
4 | #include "list.h" | |
b7b189cd | 5 | #include "path.h" |
2b5ed373 | 6 | #include "strbuf.h" |
74ea5c95 | 7 | #include "trace.h" |
2b5ed373 JK |
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 | static void reparent_cb(const char *name, | |
29 | const char *old_cwd, | |
30 | const char *new_cwd, | |
31 | void *data) | |
32 | { | |
33 | char **path = data; | |
34 | char *tmp = *path; | |
35 | ||
36 | if (!tmp) | |
37 | return; | |
38 | ||
39 | *path = reparent_relative_path(old_cwd, new_cwd, tmp); | |
40 | free(tmp); | |
41 | ||
42 | if (name) { | |
43 | trace_printf_key(&trace_setup_key, | |
44 | "setup: reparent %s to '%s'", | |
45 | name, *path); | |
46 | } | |
47 | } | |
48 | ||
49 | void chdir_notify_reparent(const char *name, char **path) | |
50 | { | |
51 | chdir_notify_register(name, reparent_cb, path); | |
52 | } | |
53 | ||
54 | int chdir_notify(const char *new_cwd) | |
55 | { | |
56 | struct strbuf old_cwd = STRBUF_INIT; | |
57 | struct list_head *pos; | |
58 | ||
59 | if (strbuf_getcwd(&old_cwd) < 0) | |
60 | return -1; | |
61 | if (chdir(new_cwd) < 0) { | |
62 | int saved_errno = errno; | |
63 | strbuf_release(&old_cwd); | |
64 | errno = saved_errno; | |
65 | return -1; | |
66 | } | |
67 | ||
68 | trace_printf_key(&trace_setup_key, | |
69 | "setup: chdir from '%s' to '%s'", | |
70 | old_cwd.buf, new_cwd); | |
71 | ||
72 | list_for_each(pos, &chdir_notify_entries) { | |
73 | struct chdir_notify_entry *e = | |
74 | list_entry(pos, struct chdir_notify_entry, list); | |
75 | e->cb(e->name, old_cwd.buf, new_cwd, e->data); | |
76 | } | |
77 | ||
78 | strbuf_release(&old_cwd); | |
79 | return 0; | |
80 | } | |
81 | ||
82 | char *reparent_relative_path(const char *old_cwd, | |
83 | const char *new_cwd, | |
84 | const char *path) | |
85 | { | |
86 | char *ret, *full; | |
87 | ||
88 | if (is_absolute_path(path)) | |
89 | return xstrdup(path); | |
90 | ||
91 | full = xstrfmt("%s/%s", old_cwd, path); | |
92 | ret = xstrdup(remove_leading_path(full, new_cwd)); | |
93 | free(full); | |
94 | ||
95 | return ret; | |
96 | } |