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