]> git.ipfire.org Git - thirdparty/git.git/blob - compat/fsmonitor/fsm-path-utils-darwin.c
config: do not leak excludes_file
[thirdparty/git.git] / compat / fsmonitor / fsm-path-utils-darwin.c
1 #include "fsmonitor.h"
2 #include "fsmonitor-path-utils.h"
3 #include <dirent.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <sys/param.h>
7 #include <sys/mount.h>
8
9 int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
10 {
11 struct statfs fs;
12 if (statfs(path, &fs) == -1) {
13 int saved_errno = errno;
14 trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
15 path, strerror(saved_errno));
16 errno = saved_errno;
17 return -1;
18 }
19
20 trace_printf_key(&trace_fsmonitor,
21 "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
22 path, fs.f_type, fs.f_flags, fs.f_fstypename);
23
24 if (!(fs.f_flags & MNT_LOCAL))
25 fs_info->is_remote = 1;
26 else
27 fs_info->is_remote = 0;
28
29 fs_info->typename = xstrdup(fs.f_fstypename);
30
31 trace_printf_key(&trace_fsmonitor,
32 "'%s' is_remote: %d",
33 path, fs_info->is_remote);
34 return 0;
35 }
36
37 int fsmonitor__is_fs_remote(const char *path)
38 {
39 struct fs_info fs;
40 if (fsmonitor__get_fs_info(path, &fs))
41 return -1;
42
43 free(fs.typename);
44
45 return fs.is_remote;
46 }
47
48 /*
49 * Scan the root directory for synthetic firmlinks that when resolved
50 * are a prefix of the path, stopping at the first one found.
51 *
52 * Some information about firmlinks and synthetic firmlinks:
53 * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
54 *
55 * macOS no longer allows symlinks in the root directory; any link found
56 * there is therefore a synthetic firmlink.
57 *
58 * If this function gets called often, will want to cache all the firmlink
59 * information, but for now there is only one caller of this function.
60 *
61 * If there is more than one alias for the path, that is another
62 * matter altogether.
63 */
64 int fsmonitor__get_alias(const char *path, struct alias_info *info)
65 {
66 DIR *dir;
67 int retval = -1;
68 const char *const root = "/";
69 struct stat st;
70 struct dirent *de;
71 struct strbuf alias;
72 struct strbuf points_to = STRBUF_INIT;
73
74 dir = opendir(root);
75 if (!dir)
76 return error_errno(_("opendir('%s') failed"), root);
77
78 strbuf_init(&alias, 256);
79
80 while ((de = readdir(dir)) != NULL) {
81 strbuf_reset(&alias);
82 strbuf_addf(&alias, "%s%s", root, de->d_name);
83
84 if (lstat(alias.buf, &st) < 0) {
85 error_errno(_("lstat('%s') failed"), alias.buf);
86 goto done;
87 }
88
89 if (!S_ISLNK(st.st_mode))
90 continue;
91
92 if (strbuf_readlink(&points_to, alias.buf, st.st_size) < 0) {
93 error_errno(_("strbuf_readlink('%s') failed"), alias.buf);
94 goto done;
95 }
96
97 if (!strncmp(points_to.buf, path, points_to.len) &&
98 (path[points_to.len] == '/')) {
99 strbuf_addbuf(&info->alias, &alias);
100 strbuf_addbuf(&info->points_to, &points_to);
101 trace_printf_key(&trace_fsmonitor,
102 "Found alias for '%s' : '%s' -> '%s'",
103 path, info->alias.buf, info->points_to.buf);
104 retval = 0;
105 goto done;
106 }
107 }
108 retval = 0; /* no alias */
109
110 done:
111 strbuf_release(&alias);
112 strbuf_release(&points_to);
113 if (closedir(dir) < 0)
114 return error_errno(_("closedir('%s') failed"), root);
115 return retval;
116 }
117
118 char *fsmonitor__resolve_alias(const char *path,
119 const struct alias_info *info)
120 {
121 if (!info->alias.len)
122 return NULL;
123
124 if ((!strncmp(info->alias.buf, path, info->alias.len))
125 && path[info->alias.len] == '/') {
126 struct strbuf tmp = STRBUF_INIT;
127 const char *remainder = path + info->alias.len;
128
129 strbuf_addbuf(&tmp, &info->points_to);
130 strbuf_add(&tmp, remainder, strlen(remainder));
131 return strbuf_detach(&tmp, NULL);
132 }
133
134 return NULL;
135 }