Coverage Report

Created: 2026-01-09 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/chdir-notify.c
Line
Count
Source
1
#include "git-compat-util.h"
2
#include "abspath.h"
3
#include "chdir-notify.h"
4
#include "list.h"
5
#include "path.h"
6
#include "strbuf.h"
7
#include "trace.h"
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
0
{
21
0
  struct chdir_notify_entry *e = xmalloc(sizeof(*e));
22
0
  e->name = name;
23
0
  e->cb = cb;
24
0
  e->data = data;
25
0
  list_add_tail(&e->list, &chdir_notify_entries);
26
0
}
27
28
void chdir_notify_unregister(const char *name, chdir_notify_callback cb,
29
           void *data)
30
0
{
31
0
  struct list_head *pos, *p;
32
33
0
  list_for_each_safe(pos, p, &chdir_notify_entries) {
34
0
    struct chdir_notify_entry *e =
35
0
      list_entry(pos, struct chdir_notify_entry, list);
36
37
0
    if (e->cb != cb || e->data != data || !e->name != !name ||
38
0
        (e->name && strcmp(e->name, name)))
39
0
      continue;
40
41
0
    list_del(pos);
42
0
    free(e);
43
0
  }
44
0
}
45
46
static void reparent_cb(const char *name,
47
      const char *old_cwd,
48
      const char *new_cwd,
49
      void *data)
50
0
{
51
0
  char **path = data;
52
0
  char *tmp = *path;
53
54
0
  if (!tmp)
55
0
    return;
56
57
0
  *path = reparent_relative_path(old_cwd, new_cwd, tmp);
58
0
  free(tmp);
59
60
0
  if (name) {
61
0
    trace_printf_key(&trace_setup_key,
62
0
         "setup: reparent %s to '%s'",
63
0
         name, *path);
64
0
  }
65
0
}
66
67
void chdir_notify_reparent(const char *name, char **path)
68
0
{
69
0
  chdir_notify_register(name, reparent_cb, path);
70
0
}
71
72
int chdir_notify(const char *new_cwd)
73
0
{
74
0
  struct strbuf old_cwd = STRBUF_INIT;
75
0
  struct list_head *pos;
76
77
0
  if (strbuf_getcwd(&old_cwd) < 0)
78
0
    return -1;
79
0
  if (chdir(new_cwd) < 0) {
80
0
    int saved_errno = errno;
81
0
    strbuf_release(&old_cwd);
82
0
    errno = saved_errno;
83
0
    return -1;
84
0
  }
85
86
0
  trace_printf_key(&trace_setup_key,
87
0
       "setup: chdir from '%s' to '%s'",
88
0
       old_cwd.buf, new_cwd);
89
90
0
  list_for_each(pos, &chdir_notify_entries) {
91
0
    struct chdir_notify_entry *e =
92
0
      list_entry(pos, struct chdir_notify_entry, list);
93
0
    e->cb(e->name, old_cwd.buf, new_cwd, e->data);
94
0
  }
95
96
0
  strbuf_release(&old_cwd);
97
0
  return 0;
98
0
}
99
100
char *reparent_relative_path(const char *old_cwd,
101
           const char *new_cwd,
102
           const char *path)
103
0
{
104
0
  char *ret, *full;
105
106
0
  if (is_absolute_path(path))
107
0
    return xstrdup(path);
108
109
0
  full = xstrfmt("%s/%s", old_cwd, path);
110
0
  ret = xstrdup(remove_leading_path(full, new_cwd));
111
0
  free(full);
112
113
0
  return ret;
114
0
}