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