- If an UNC path is mounted to a drive using SMB3.11, accessing to
the drive fails with error "Too many levels of symbolic links."
This patch fixes the issue.
When trying to create a directory called `xyz` in the presence of a
directory `xyz.lnk`, the Cygwin runtime errors out with an `ENOENT`.
The root cause is actually a bit deeper: the `symlink_info::check()`
method tries to figure out whether the given path refers to a symbolic
link as emulated via `.lnk` files, but since it is a directory, that is
not the case, and that hypothesis is rejected.
However, the `fileattr` field is not cleared, so that a later
`.exists()` call on the instance mistakenly thinks that the symlink
actually exists. Let's clear that field.
This fixes https://github.com/msys2/msys2-runtime/issues/81
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
- The last change in path.cc introduced a bug that causes an error
when accessing a virtual drive which mounts UNC path such as
"\\server\share\dir" rather than "\\server\share". This patch
fixes the issue.
The new GetFinalPathNameW handling for native symlinks in inner path
components is disabled if caller doesn't want to follow symlinks, or
doesn't want to follow reparse points.
The check for a file or dir within /dev/mqueue is accidentally using
the incoming path, which could be a relative path. Make sure to
restore the absolute POSIX path in path_copy and only then test the
path.
Also, move the actual check for a valid path below /dev/mqueue into
the fhandler_mqueue class.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
/dev has been handled as virtual dir in cwdstuff, thus not allowing
to start native apps from /dev as CWD, even if /dev actually exists
on disk. Unfortunately this also affects Cygwin executables started
from a debugger.
When chdir'ing to /dev, check if /dev exists on disk. If so, treat
it as any other existing path.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
The mq_open call is just a framework now. This patch moves the
entire functionality into fhandler_mqueue. To support standard
OS calls (as on Linux), make fhandler_mqueue a derived class from
fhandler_disk_file and keep the base handle the handle to the
default stream, to allow implementing O_PATH functionlaity as well
as reading from the file and NOT reading binary message queue data.
Implement a standard fhandler_mqueue::open method, allowing, for
instance, to touch a file under /dev/mqueue and if it doesn't exist,
to create a message queue file.
FIXME: This introduces a BAD HACK into path_conv::check, which needs
reviewing.
Keep the posix path intact in the fhandler, and change get_proc_fd_name
accordingly to return only the basename plus leading slash for
/proc/<PID>/fd.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
POSIX message queues will be moved into NTFS streams.
Extend get_nt_native_path to provide a filename suffix which is not
subject to special character transposition, to allow specifying
a colon.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
The old check was insufficient: new insider preview builds of Windows
allow running x86_64 process on ARM64. The IsWow64Process2 function
seems to be the intended way to figure this situation out.
This avoids MAX_PATH-related problems in native tools in case the
virtual drive points to a deep directory
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Rather than fetching the system Windows directory at dll init time
only on 32 bit, fetch it on all platforms. Store as WCHAR and
UNICODE_STRING. Use where appropriate to simplify code.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
commit 456c3a4638 was only going half-way. It handled symlinks and
junction points as inner path components and made realpath return the
correct path, but it ignored drive letter substitution, i. e., virtual
drives created with, e. g.
subst X: C:\foo\bar
It was also too simple. Just returning an error code from
symlink_info::check puts an unnecessary onus on the symlink evaluation
loop in path_conv::check.
Rework the code to use GetFinalPathNameByHandle, and only do this after
checking the current file for being a symlink failed.
If the final path returned by GetFinalPathNameByHandle is not the same
as the incoming path, replace the incoming path with the POSIXified
final path. This also short-circuits path evaluation, because
path_conv::check doesn't have to recurse over the inner path components
multiple times if all symlinks are of a native type, while still getting
the final path as end result.
Virtual drives are now handled like symlinks. This is a necessary change
from before to make sure virtual drives are handled identically across
different access methods. An example is realpath(1) from coreutils. It
doesn't call readlink(2), but iterates over all path components using
lstat/readlink calls. Both methods should result in the same real path.
Fixes: 456c3a4638 ("path_conv: Try to handle native symlinks more sanely")
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Commit 456c3a4638 added a workaround when handling paths with native
symlinks as inner path components. This patch introduced a problem for
paths handled by the WOW64 File System Redirector (FSR).
Fix this problem by not performing the new code from commit 456c3a4638
for paths under the Windows directory. Only do this in WOW64.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
For local paths, add a check if the inner path components contain native
symlinks or junctions. Compare the incoming path with the path returned
by NtQueryInformationFile(FileNameInformation). If they differ, there
must be at least one native symlink or junction in the path. If so,
treat the currently evaluated file as non-existant. This forces
path_conv::check to backtrack inner path components until we eliminated
all native symlinks or junctions and have a normalized path.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
When the Windows Store version of Python is installed, so-called "app
execution aliases" are put into the `PATH`. These are reparse points
under the hood, with an undocumented format.
We do know a bit about this format, though, as per the excellent analysis:
https://www.tiraniddo.dev/2019/09/overview-of-windows-execution-aliases.html
The first 4 bytes is the reparse tag, in this case it's
0x8000001B which is documented in the Windows SDK as
IO_REPARSE_TAG_APPEXECLINK. Unfortunately there doesn't seem to
be a corresponding structure, but with a bit of reverse
engineering we can work out the format is as follows:
Version: <4 byte integer>
Package ID: <NUL Terminated Unicode String>
Entry Point: <NUL Terminated Unicode String>
Executable: <NUL Terminated Unicode String>
Application Type: <NUL Terminated Unicode String>
Let's treat them as symbolic links. For example, in this developer's
setup, this will result in the following nice output:
$ cd $LOCALAPPDATA/Microsoft/WindowsApps/
$ ls -l python3.exe
lrwxrwxrwx 1 me 4096 105 Aug 23 2020 python3.exe -> '/c/Program Files/WindowsApps/PythonSoftwareFoundation.Python.3.7_3.7.2544.0_x64__qbz5n2kfra8p0/python.exe'
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Allow check_reparse_point_target to recognize reparse points with
reparse tag IO_REPARSE_TAG_AF_UNIX. These are used in recent versions
of Windows 10 to represent AF_UNIX sockets.
check_reparse_point_target now returns PATH_REP on files of this type,
so that they are treated as known reparse points (but not as sockets).
This allows tools like 'rm', 'ls', etc. to operate on these files.
Addresses: https://cygwin.com/pipermail/cygwin/2020-September/246362.htmlhttps://cygwin.com/pipermail/cygwin/2021-January/247666.html
https://cygwin.com/pipermail/cygwin/2020-December/246938.html
reports a problem where, when adding a Cygwin default symlink
to $PATH since Cygwin 3.1.5, $PATH handling appears to be broken.
3.1.5 switched to WSL symlinks as Cygwin default symlinks.
A piece of code in path handling skips resolving reparse points
if they are the last component in the path. Thus a reparse point
in $PATH is not resolved but converted to Windows path syntax
verbatim.
If you do this with a WSL symlink, certain WinAPI functions fail.
The underlying $PATH handling fails to recognize the reparse
point in $PATH and returns with STATUS_IO_REPARSE_TAG_NOT_HANDLED.
As a result, the calling WinAPI function fails, most prominently
so CreateProcess.
Fix this problem by adding a PATH_REP_NOAPI bit to path_types
and a matching method path_conv::is_winapi_reparse_point().
Right now this flag is set for WSL symlinks and Cygwin AF_UNIX
sockets (new type implemented as reparse points).
The aforementioned code skipping repare point path resolution calls
is_winapi_reparse_point() rather than is_known_reparse_point(),
so now path resolution is only skipped for reparse points known
to WinAPI.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Use fhandler_dev_floppy instead of fhandler_procsys for such devices.
The read()/write() functions from fhandler_procsys do not ensure
sector aligned transfers and lseek() fails always.
Signed-off-by: Christian Franke <franke@computer.org>
If __WITH_AF_UNIX is defined when Cygwin is built, then a named
AF_UNIX socket is represented by a reparse point with a
Cygwin-specific tag and GUID. Make such files recognizable as reparse
points (but not as sockets) even if __WITH_AF_UNIX is not defined.
That way utilities such as 'ls' and 'rm' still behave reasonably.
This requires two changes:
- Define the GUID __cygwin_socket_guid unconditionally.
- Make check_reparse_point_target return PATH_REP on a reparse point
of this type if __WITH_AF_UNIX is not defined.
Commit aa467e6e, "Cygwin: add AF_UNIX reparse points to path
handling", changed check_reparse_point_target so that it could return
a positive value on a known reparse point that is not a symlink. But
some of the code in check_reparse_point that handles this positive
return value was executed unconditionally, when it should have been
executed only for symlinks.
As a result, posixify could be called on a buffer containing garbage,
and check_reparse_point could erroneously return a positive value on a
non-symlink. This is now fixed so that posixify is only called if the
reparse point is a symlink, and check_reparse_point returns 0 if the
reparse point is not a symlink.
Also fix symlink_info::check to handle this last case, in which
check_reparse_point returns 0 on a known reparse point.
Commit aa467e6e, "Cygwin: add AF_UNIX reparse points to path
handling", changed the return values of check_reparse_point_target.
Update the comment accordingly.
fhandler_process::exists is called when we are checking a path
starting with "/proc/<pid>/fd". If it returns virt_none and sets an
errno, there is no need for further checking. Just set 'error' and
return.
This patch has been inspired by the Linux kernel patch
294f69e662d1 compiler_attributes.h: Add 'fallthrough' pseudo keyword for switch/case use
written by Joe Perches <joe AT perches DOT com> based on an idea from
Dan Carpenter <dan DOT carpenter AT oracle DOT com>. The following text
is from the original log message:
Reserve the pseudo keyword 'fallthrough' for the ability to convert the
various case block /* fallthrough */ style comments to appear to be an
actual reserved word with the same gcc case block missing fallthrough
warning capability.
All switch/case blocks now should end in one of:
break;
fallthrough;
goto <label>;
return [expression];
continue;
In C mode, GCC supports the __fallthrough__ attribute since 7.1,
the same time the warning and the comment parsing were introduced.
Cygwin-only: add an explicit -Wimplicit-fallthrough=5 to the build
flags.
If the cygdrive prefix is /, then the following happens right now:
$ ln -s /tmp/foo .
$ ls -l foo
lrwxrwxrwx 1 user group 12 Apr 15 23:44 foo -> /mnt/tmp/foo
Fix this by skipping cygdrive prefix conversion to WSL drive
prefix "/mnt", if the cygdrive prefix is just "/". There's no
satisfying way to do the right thing all the time in this case
anyway. For a description and the alternatives, see
https://cygwin.com/pipermail/cygwin-developers/2020-April/011859.html
Also, fix a typo in a comment.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Unfortunately Windows doesn't understand WSL symlinks,
despite being a really easy job. NT functions trying
to access paths traversing WSL symlinks return the status
code STATUS_IO_REPARSE_TAG_NOT_HANDLED. Handle this
status code same as STATUS_OBJECT_PATH_NOT_FOUND in
symlink_info::check to align behaviour to traversing
paths with other non-NTFS type symlinks.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
WSL symlinks are reparse points containing a POSIX path in UTF-8.
On filesystems supporting reparse points, use this symlink type.
On other filesystems, or in case of error, fall back to the good
old plain SYSTEM file.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Commit 4a36897af3 allowed to convert /mnt/<drive> path
prefixes to Cygwin cygdrive prefixes on the fly. However,
the patch neglected WSL symlinks pointing to the /mnt
directory. Rearrange path conversion so /mnt is converted
to the cygdrive prefix path itself.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Treat WSL symlinks just like other symlinks. Convert
absolute paths pointing to Windows drives via
/mnt/<driveletter> to Windows-style paths <driveletter>:
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This option has been disabled long ago and nobody missed it.
Removing drops a bit of unneeded code
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
mknod32 actually creates a path_conv, just to call mknod_worker
with a win32 path. This doesn't only require to create path_conv
twice, it also breaks permissions on filesystems supporting ACLs.
Fix this by passing the path_conv created in the caller down to
symlink_worker. Also, while at it, simplify the handling of trailing
slashes and move it out of symlink_worker. Especially use the
new PC_SYM_NOFOLLOW_DIR flag to avoid fiddeling with creating
a new path copy without the trailing slash.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Usually a trailing slash requires to follow an existing symlink,
even with PC_SYM_NOFOLLOW. The reason is that "foo/" is equivalent
to "foo/." so the symlink is in fact not the last path component,
"." is. This is default for almost all scenarios.
PC_SYM_NOFOLLOW_DIR now allows the caller to request not to
follow the symlink even if a trailing slash is given. This can
be used in callers to perform certain functions Linux-compatible.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Commit 283cb372, "Cygwin: normalize_win32_path: improve error
checking", required a prefix '\\?\' or '\??\' in the source path to be
followed by 'UNC\' or 'X:\', where X is a drive letter. That was too
restrictive, since it disallowed the paths '\\?\X: and '\??\X:'. This
caused problems when a user tried to use the root of a drive as the
Cygwin installation root, as reported here:
https://cygwin.com/ml/cygwin/2020-01/msg00111.html
Modify the requirement so that '\??\X:' and '\\?\X:' are now allowed
as source paths, without a trailing backslash.
On certain error conditions there is a code snippet that checks
whether the last component of the path has a trailing dot or space or
a leading space. Skip this check if the last component is empty,
i.e., if the path ends with a backslash. This avoids an assertion
failure if the trailing backslash is the only backslash in the path,
as is the case for a DOS drive 'X:\'.
Addresses: https://cygwin.com/ml/cygwin/2019-12/msg00016.html
If the source path starts with the Win32 long path prefix '\\?\' or
the NT object directory prefix '\??\', require the prefix to be
followed by 'UNC\' or '<drive letter>:\'. Otherwise return EINVAL.
This fixes the assertion failure in symlink_info::check that was
reported here:
https://cygwin.com/ml/cygwin/2019-09/msg00228.html
That assertion failure was caused by normalize_win32_path returning a
path with no backslashes when the source path was '\\?\DRIVE'.
Prior to commit b0717aae, path_conv::check had the following code:
if (strncmp (path, "\\\\.\\", 4))
{
/* Windows ignores trailing dots and spaces in the last path
component, and ignores exactly one trailing dot in inner
path components. */
char *tail = NULL;
[...]
if (!tail || tail == path)
/* nothing */;
else if (tail[-1] != '\\')
{
*tail = '\0';
[...]
}
Commit b0717aae0 intended to disable this code, but it inadvertently
disabled only part of it. In particular, the declaration of the local
tail variable was in the disabled code, but the following remained:
if (!tail || tail == path)
/* nothing */;
else if (tail[-1] != '\\')
{
*tail = '\0';
[...]
}
[A later commit removed the disabled code.]
The tail variable here points into a string different from path,
causing that string to be truncated under some circumstances. See
https://cygwin.com/ml/cygwin/2019-09/msg00001.html
for more details.
This commit fixes the problem by removing the leftover code
that was intended to be removed in b0717aae.
It is used only once, and the name is supposed to suggest "device that
is not based on the filesystem". This intended meaning is clearer if
we just replace is_auto_device() by its definition at the place where
it's used.
path_conv now sets the PATH_RESOLVE_PROCFD flag in path_flags if
the PC_SYM_NOFOLLOW_PROCFD pathconv_arg flag has been set on input
*and* the file is actually a proc fd symlink.
Add matching path_conv::follow_fd_symlink method for checking and
use it in open(2).
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
- Remove another unfortunate amalgamation: Mount flags (MOUNT_xxx)
are converted to path_types (PATH_xxx) and mixed with non-mount
path_types flags in the same storage, leading to a tangled,
pell-mell usage of mount flags and path flags in path_conv and
symlink_info.
- There's also the case of PC_NONULLEMPTY. It's used in exactly
one place with a path_conv constructor only used in this single
place, just to override the automatic PC_NULLEMPTY addition
when calling the other path_conv constructors. Crazily,
PC_NONULLEMPTY is a define, no path_types flag, despite its
name.
- It doesn't help that the binary flag exists as mount and path
flag, while the text flag only exists as path flag. This leads
to mount code using path flags to set text/binary. Very confusing
is the fact that a text mount/path flag is not actually required;
the mount code sets the text flag on non binary mounts anyway, so
there are only two states. However, to puzzle people a bit more,
path_conv::binary wrongly implies there's a third, non-binary/non-text
state.
Clean up this mess:
- Store path flags separately from mount flags in path_conv and
symlink_info classes and change all checks and testing inline
methods accordingly.
- Make PC_NONULLEMPTY a simple path_types flag and drop the
redundant path_check constructor.
- Clean up the definition of pathconv_arg, path_types, and mount flags.
Use _BIT expression, newly define in cygwin/bits.h.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>