From 20cb2818a78ba20af02c8f17c8cf41edd31e0415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B8=CC=86=20=D0=9F?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=BE=D0=B2?= Date: Sun, 14 Apr 2019 22:13:51 +0300 Subject: [PATCH] path_conv: special-case root directory to have trailing slash When converting `/c/` to `C:\`, the trailing slash is actually really necessary, as `C:` is not an absolute path. We must be very careful to do this only for root directories, though. If we kept the trailing slash also for, say, `/y/directory/`, we would run into the following issue: On FAT file systems, the normalized path is used to fake inode numbers. As a result, `Y:\directory\` and `Y:\directory` have different inode numbers!!! This would result in very non-obvious symptoms. Back when we were too careless about keeping the trailing slash, it was reported to the Git for Windows project that the `find` and `rm` commands can error out on FAT file systems with very confusing "No such file or directory" errors, for no good reason. During the original investigation, Vasil Minkov pointed out in https://github.com/git-for-windows/git/issues/1497#issuecomment-372665870, that this bug had been fixed in Cygwin as early as 1997... and the bug was unfortunately reintroduced into early MSYS2 versions. Signed-off-by: Johannes Schindelin --- winsup/cygwin/path.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index bc5b4d35fd..ed3076ce15 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -709,6 +709,12 @@ path_conv::check (const char *src, unsigned opt, need_directory = 1; *--tail = '\0'; } + /* Special case for "/" must set need_directory, without removing + trailing slash */ + else if (tail == path_copy + 1 && isslash (tail[-1])) + { + need_directory = 1; + } path_end = tail; /* Scan path_copy from right to left looking either for a symlink @@ -1248,6 +1254,7 @@ path_conv::check (const char *src, unsigned opt, cfree (wide_path); wide_path = NULL; } + if (need_directory) { size_t n = strlen (this->path);