| #include "cache.h" | |
| #include "chdir-notify.h" | |
| #include "list.h" | |
| #include "strbuf.h" | |
| struct chdir_notify_entry { | |
| const char *name; | |
| chdir_notify_callback cb; | |
| void *data; | |
| struct list_head list; | |
| }; | |
| static LIST_HEAD(chdir_notify_entries); | |
| void chdir_notify_register(const char *name, | |
| chdir_notify_callback cb, | |
| void *data) | |
| { | |
| struct chdir_notify_entry *e = xmalloc(sizeof(*e)); | |
| e->name = name; | |
| e->cb = cb; | |
| e->data = data; | |
| list_add_tail(&e->list, &chdir_notify_entries); | |
| } | |
| static void reparent_cb(const char *name, | |
| const char *old_cwd, | |
| const char *new_cwd, | |
| void *data) | |
| { | |
| char **path = data; | |
| char *tmp = *path; | |
| if (!tmp) | |
| return; | |
| *path = reparent_relative_path(old_cwd, new_cwd, tmp); | |
| free(tmp); | |
| if (name) { | |
| trace_printf_key(&trace_setup_key, | |
| "setup: reparent %s to '%s'", | |
| name, *path); | |
| } | |
| } | |
| void chdir_notify_reparent(const char *name, char **path) | |
| { | |
| chdir_notify_register(name, reparent_cb, path); | |
| } | |
| int chdir_notify(const char *new_cwd) | |
| { | |
| struct strbuf old_cwd = STRBUF_INIT; | |
| struct list_head *pos; | |
| if (strbuf_getcwd(&old_cwd) < 0) | |
| return -1; | |
| if (chdir(new_cwd) < 0) { | |
| int saved_errno = errno; | |
| strbuf_release(&old_cwd); | |
| errno = saved_errno; | |
| return -1; | |
| } | |
| trace_printf_key(&trace_setup_key, | |
| "setup: chdir from '%s' to '%s'", | |
| old_cwd.buf, new_cwd); | |
| list_for_each(pos, &chdir_notify_entries) { | |
| struct chdir_notify_entry *e = | |
| list_entry(pos, struct chdir_notify_entry, list); | |
| e->cb(e->name, old_cwd.buf, new_cwd, e->data); | |
| } | |
| strbuf_release(&old_cwd); | |
| return 0; | |
| } | |
| char *reparent_relative_path(const char *old_cwd, | |
| const char *new_cwd, | |
| const char *path) | |
| { | |
| char *ret, *full; | |
| if (is_absolute_path(path)) | |
| return xstrdup(path); | |
| full = xstrfmt("%s/%s", old_cwd, path); | |
| ret = xstrdup(remove_leading_path(full, new_cwd)); | |
| free(full); | |
| return ret; | |
| } |