chdir-notify.con commit Merge branch 'jt/clone-server-option' (6d3df8e)
   1#include "cache.h"
   2#include "chdir-notify.h"
   3#include "list.h"
   4#include "strbuf.h"
   5
   6struct chdir_notify_entry {
   7        const char *name;
   8        chdir_notify_callback cb;
   9        void *data;
  10        struct list_head list;
  11};
  12static LIST_HEAD(chdir_notify_entries);
  13
  14void 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
  25static 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
  46void chdir_notify_reparent(const char *name, char **path)
  47{
  48        chdir_notify_register(name, reparent_cb, path);
  49}
  50
  51int 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
  79char *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}