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