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