On Sat, Sep 10, 2022 at 4:00 PM Eric DeCosta via GitGitGadget <gitgitgadget@xxxxxxxxx> wrote: > Starting with macOS 10.15 (Catalina), Apple introduced a new feature > called 'firmlinks' in order to separate the boot volume into two > volumes, one read-only and one writable but still present them to the > user as a single volume. Along with this change, Apple removed the > ability to create symlinks in the root directory and replaced them with > 'synthetic firmlinks'. See 'man synthetic.conf' > > When FSEevents reports the path of changed files, if the path invloves > a synthetic firmlink, the path is reported from the point of the > synthetic firmlink and not the real path. For example: s/invloves/involves/ > Real path: > /System/Volumes/Data/network/working/directory/foo.txt > > Synthetic firmlink: > /network -> /System/Volumes/Data/network > > FSEvents path: > /network/working/directory/foo.txt > > This causes the FSEvents path to not match against the worktree > directory. > > There are several ways in which synthetic firmlinks can be created: > they can be defined in /etc/synthetic.conf, the automounter can create > them, and there may be other means. Simply reading /etc/synthetic.conf > is insufficient. No matter what process creates synthetic firmlinks, > they all get created in the root directory. > > Therefore, in order to deal with synthetic firmlinks, the root directory > is scanned and the first possible synthetic firmink that, when resolved, > is a prefix of the worktree is used to map FSEvents paths to worktree > paths. > > Signed-off-by: Eric DeCosta <edecosta@xxxxxxxxxxxxx> > --- > diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c > @@ -38,3 +41,91 @@ int fsmonitor__is_fs_remote(const char *path) > +/* > + * 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 altogteher. > + */ s/altogteher/altogether/ > diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h > @@ -1,6 +1,14 @@ > +struct alias_info > +{ > + struct strbuf alias; > + struct strbuf points_to; > +}; > +/* > + * Get the alias in given path, if any. > + * > + * Sets alias to the first alias that matches any part of the path. > + * > + * Returns -1 on error, 0 otherwise. > + */ > +int fsmonitor__get_alias(const char *path, struct alias_info *info); I suppose it's somewhat clear here that the caller is responsible for releasing the strbufs in alias_info (though it's not clear why they need to be strbufs in the first place)... > +/* > + * Resolve the path against the given alias. > + * > + * Returns the resolved path if there is one, NULL otherwise. > + */ > +char *fsmonitor__resolve_alias(const char *path, > + const struct alias_info *info); But what about the return value from this function? It's `char*` which suggests a possible ownership transfer(?). Is the caller responsible for freeing it? If so, perhaps the documentation could state that.