summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/path.cc
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r--winsup/cygwin/path.cc48
1 files changed, 18 insertions, 30 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index ad60e07a1..033a0c5c5 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -168,6 +168,7 @@ path_conv::check (const char *src, unsigned opt,
char path_copy[MAX_PATH];
char tmp_buf[MAX_PATH];
symlink_info sym;
+ bool need_directory = 0;
char *rel_path, *full_path;
@@ -189,16 +190,15 @@ path_conv::check (const char *src, unsigned opt,
for (;;)
{
MALLOC_CHECK;
- DWORD need_directory = 0;
char *p = strrchr (src, '/');
if (p)
{
- if (strcmp (p, "/") == 0 || strcmp (p, "/.") == 0)
- need_directory = PATH_NEEDDIR;
+ if (p[1] == '\0' || strcmp (p, "/.") == 0)
+ need_directory = 1;
}
else if ((p = strrchr (src, '\\')) &&
- (strcmp (p, "\\") == 0 || strcmp (p, "\\.") == 0))
- need_directory = PATH_NEEDDIR;
+ (p[1] == '\0' || strcmp (p, "\\.") == 0))
+ need_directory = 1;
/* Must look up path in mount table, etc. */
error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
full_path,
@@ -285,7 +285,7 @@ path_conv::check (const char *src, unsigned opt,
these operations again on the newly derived path. */
else if (len > 0)
{
- if (component == 0 && !(opt & PC_SYM_FOLLOW))
+ if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW))
{
set_symlink (); // last component of path is a symlink.
fileattr = sym.fileattr;
@@ -363,6 +363,18 @@ fillin:
}
out:
+ /* Deal with Windows stupidity which considers filename\. to be valid
+ even when "filename" is not a directory. */
+ if (!need_directory || error)
+ /* nothing to do */;
+ else if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
+ path_flags &= ~PATH_SYMLINK;
+ else
+ {
+ debug_printf ("%s is a non-directory", path);
+ error = ENOTDIR;
+ return;
+ }
DWORD serial, volflags;
strcpy (tmp_buf, full_path);
@@ -2187,7 +2199,6 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
HANDLE h;
int res = 0;
char extbuf[MAX_PATH + 5];
- int needdir;
const char *path = in_path;
if (!suffixes)
@@ -2206,13 +2217,6 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
is_symlink = TRUE;
error = 0;
- if (!(pflags & PATH_NEEDDIR))
- needdir = 0;
- else
- {
- pflags &= ~PATH_NEEDDIR;
- needdir = 1;
- }
do
{
if (!next_suffix (ext_here, suffixes))
@@ -2229,22 +2233,6 @@ symlink_info::check (const char *in_path, const suffix_info *suffixes)
continue;
}
- /* Windows allows path\. even when `path' isn't a directory.
- Detect this scenario and disallow it, since it is non-UNIX like.
- FIXME: This code actually checks for things like foo/ and foo/..
- even though those usages have already been (erroneously?) eaten
- by cygwin_shared->mount.conv_to_win32_path in path_conv::check. */
-
- char *p = strrchr (path, '\\');
- if (p && !(fileattr & FILE_ATTRIBUTE_DIRECTORY) &&
- (needdir || *++p == '\0' ||
- (*p == '.' && (*++p == '\0' || (*p == '.' && p[1] == '\0')))))
- {
- debug_printf ("%s is a non-directory", path);
- error = ENOTDIR;
- goto file_not_symlink;
- }
-
/* A symlink will have the `system' file attribute. */
/* Only files can be symlinks (which can be symlinks to directories). */
if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))