RFC: Reparse Point/NT Symlink Support [3]

Erich E. Hoover erich.e.hoover at gmail.com
Wed Sep 29 12:29:35 CDT 2021


On Tue, Aug 31, 2021 at 11:00 AM Erich E. Hoover
<erich.e.hoover at gmail.com> wrote:
>
> On Tue, Aug 31, 2021 at 10:52 AM Zebediah Figura (she/her)
> <zfigura at codeweavers.com> wrote:
> > ...
> > Is there a problem with collapse_path(), or is it just a matter of
> > asking for the parent of the current directory? If the latter, wouldn't
> > it just be a matter of storing the unresolved path in the TEB?
>
> That's necessary but not sufficient, you also need to change the path
> resolution.  It's completely valid (and common) to pass a relative
> path that does something "stupid".  An extension of the Linux example:
> ===
> ~/tmplnk$ cd link/..
> ~/tmplnk$ ls
> link  test
> ~/tmplnk$ ls link/..
> target
> ===

Something about this didn't sit right with me, so I went back over my
notes and this is incorrect at the API level.  The working directory
is only handled in this special way at the shell/console level, at the
API level it is handled the same way as other paths (target-relative).
This means that it is a lot easier to implement reparsing on a
per-element level than I had attempted long-ago where I stupidly tried
to resolve the paths right before passing them to the standard C
routines.

So, back to the "how do we handle this?" question.  I would like to
keep my approach _mostly_ the same (using Unix symlinks) for these
reasons:
1) it is easy to detect the existence of a symlink programmatically
and work with data stored in the symlink (whether that data is
interpreted properly by the OS or not)
2) it allows easier traversal of the directory structure when not in
Wine for paths that are "convertible" (some tags, such as
IO_REPARSE_TAG_APPEXECLINK, are not possibly convertible by the OS)
3) if/when we need to treat certain key folders as Junction Points
then these folders will still work properly outside Wine (e.g. My
Documents -> Documents)

What I would like to treat differently now is how the Wine prefix is
stored inside the symlink.  The current implementation rewrites the
prefix path if it is incorrect (doesn't match the current prefix) and
this solution is ... not ideal.  So, I would like to suggest that
instead of (<REPARSE-TAG> and <P> are slash/dot encoded):
<REPARSE-TAG>/path/to/prefix<P>/remainder/of/path
that we can, instead, use a BSD-style variadic symlink that looks like so:
<REPARSE-TAG>${WINEPREFIX}/remainder/of/path

I did not use this solution before for several reasons:
1) This would break non-Wine usage of the symlinks
2) Linux does not support BSD-style variadic symlinks
3) I had misremembered that the relative path handling at the API
level was complicated, so I thought that implementing this in Wine
would be too difficult

However, it looks like I can now work around all of these issues:
1) On BSD systems 'symvar' can be used to set the value of ${WINEPREFIX}
2) On Linux an unprivileged namespace can be configured to effectively
allow the same thing (note that this _only_ works for an absolute
path*, such as is the case with ${WINEPREFIX})
3) Wine can perform the reinterpretation of ${WINEPREFIX} when it
parses paths, so it doesn't need to worry about #1 or #2

If this doesn't sound too crazy then I can put together the
modifications to make this happen.  As part of that I'd like to
introduce a tool (command 'wineprefix'?) that configures the Unix
environment properly for Linux/BSD to allow the shell to function with
this variadic symlink so that users like Martin Storsjö (and myself)
can just run the tool to be dropped into a shell where ${WINEPREFIX}
inside a symlink will be treated appropriately.  (Part of why it's
taken me a while to respond to this thread has been putting together a
"proof of concept" of this tool to make sure that the idea works,
which I can now confirm.)  Please let me know what you guys think,
hopefully this sounds better to folks.

Best,
Erich

* If this worked for relative paths then I would propose storing the
reparse tag the same way (e.g. "symvar xA000000C=.")



More information about the wine-devel mailing list