Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2001-04-13 01:21:37 +0400
committerCorinna Vinschen <corinna@vinschen.de>2001-04-13 01:21:37 +0400
commit70c370d674c5696d39e64970300c889c64ecd752 (patch)
tree310510f16858e53d6f08f6bab19d744d66469183
parentb8a8c59d33d5df1dbd709d6e340c250faa4ebf7b (diff)
* dir.cc (mkdir): Check for case clash.
* environ.cc: Add extern declaration for `pcheck_case'. (check_case_init): New function. (struct parse_thing): Add "check_case" option. * errno.cc (_sys_nerrlist): Add text for ECASECLASH. (strerror): Add case branch for ECASECLASH. * fhandler.cc (fhandler_disk_file::open): Check for case clash. * path.cc: Add global variable `pcheck_case'. (struct symlink_info): Add member `case_clash' and method `case_check'. (path_prefix_p_): Call `pathnmatch' instead of `strncasematch'. (pathnmatch): New funtion. (pathmatch): Ditto. (path_conv::check): Add handling for case checking. (symlink): Check for case clash. (symlink_info::check): Add parameter for case checking. Handle case checking. (symlink_info::case_check): New method. (chdir): Don't use unconverted path if pcheck_case==PCHECK_STRICT. * path.h: Add extern declarations for `pathmatch' and `pathnmatch'. (enum case_checking): New enumeration type describing the case checking behaviour of path conversion routines. (class path_conv): Add member `case_clash'. * syscalls.cc (_link): Check for case clash.
-rw-r--r--winsup/cygwin/ChangeLog27
-rw-r--r--winsup/cygwin/dir.cc2
-rw-r--r--winsup/cygwin/environ.cc29
-rw-r--r--winsup/cygwin/errno.cc6
-rw-r--r--winsup/cygwin/fhandler.cc6
-rw-r--r--winsup/cygwin/path.cc189
-rw-r--r--winsup/cygwin/path.h12
-rw-r--r--winsup/cygwin/syscalls.cc2
8 files changed, 228 insertions, 45 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 560dda555..d3d59bba5 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,30 @@
+Thu Apr 17 23:19:00 2001 Corinna Vinschen <corinna@vinschen.de>
+
+ * dir.cc (mkdir): Check for case clash.
+ * environ.cc: Add extern declaration for `pcheck_case'.
+ (check_case_init): New function.
+ (struct parse_thing): Add "check_case" option.
+ * errno.cc (_sys_nerrlist): Add text for ECASECLASH.
+ (strerror): Add case branch for ECASECLASH.
+ * fhandler.cc (fhandler_disk_file::open): Check for case clash.
+ * path.cc: Add global variable `pcheck_case'.
+ (struct symlink_info): Add member `case_clash' and method `case_check'.
+ (path_prefix_p_): Call `pathnmatch' instead of `strncasematch'.
+ (pathnmatch): New funtion.
+ (pathmatch): Ditto.
+ (path_conv::check): Add handling for case checking.
+ (symlink): Check for case clash.
+ (symlink_info::check): Add parameter for case checking.
+ Handle case checking.
+ (symlink_info::case_check): New method.
+ (chdir): Don't use unconverted path if pcheck_case==PCHECK_STRICT.
+ * path.h: Add extern declarations for `pathmatch' and
+ `pathnmatch'.
+ (enum case_checking): New enumeration type describing
+ the case checking behaviour of path conversion routines.
+ (class path_conv): Add member `case_clash'.
+ * syscalls.cc (_link): Check for case clash.
+
Thu Apr 12 12:49:53 2001 Christopher Faylor <cgf@cygnus.com>
* syscalls.cc (mkfifo): New function stub.
diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
index fef678756..2f13fcdca 100644
--- a/winsup/cygwin/dir.cc
+++ b/winsup/cygwin/dir.cc
@@ -306,7 +306,7 @@ mkdir (const char *dir, mode_t mode)
if (real_dir.error)
{
- set_errno (real_dir.error);
+ set_errno (real_dir.case_clash ? ECASECLASH : real_dir.error);
goto done;
}
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 43b246e27..2f8e350d8 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -32,6 +32,7 @@ extern BOOL allow_ntea;
extern BOOL allow_smbntsec;
extern BOOL allow_winsymlinks;
extern BOOL strip_title_path;
+extern int pcheck_case;
extern DWORD chunksize;
BOOL reset_com = TRUE;
static BOOL envcache = TRUE;
@@ -394,6 +395,33 @@ glob_init (const char *buf)
}
static void
+check_case_init (const char *buf)
+{
+ if (!buf || !*buf)
+ return;
+
+ if (strncmp (buf, "relax", 5)== 0)
+ {
+ pcheck_case = PCHECK_RELAXED;
+ debug_printf ("File case checking set to RELAXED");
+ }
+ else if (strcmp (buf, "adjust")== 0)
+ {
+ pcheck_case = PCHECK_ADJUST;
+ debug_printf ("File case checking set to ADJUST");
+ }
+ else if (strcmp (buf, "strict")== 0)
+ {
+ pcheck_case = PCHECK_STRICT;
+ debug_printf ("File case checking set to STRICT");
+ }
+ else
+ {
+ debug_printf ("Wrong case checking name: %s", buf);
+ }
+}
+
+static void
codepage_init (const char *buf)
{
if (!buf || !*buf)
@@ -441,6 +469,7 @@ struct parse_thing
} known[] =
{
{"binmode", {x: &binmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}},
+ {"check_case", {func: &check_case_init}, isfunc, NULL, {{0}, {0}}},
{"codepage", {func: &codepage_init}, isfunc, NULL, {{0}, {0}}},
{"envcache", {&envcache}, justset, NULL, {{TRUE}, {FALSE}}},
{"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}},
diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc
index c7b491cb4..3a4026077 100644
--- a/winsup/cygwin/errno.cc
+++ b/winsup/cygwin/errno.cc
@@ -283,7 +283,8 @@ extern const char __declspec(dllexport) * const _sys_errlist[]=
/* ESTALE 133 */ "Stale NFS file handle",
/* ENOTSUP 134 */ "134",
/* ENOMEDIUM 135 */ "no medium",
-/* ENOSHARE 136 */ "No such host or network path"
+/* ENOSHARE 136 */ "No such host or network path",
+/* ECASECLASH 137 */ "Filename exists with different case"
};
int __declspec(dllexport) _sys_nerr =
@@ -659,6 +660,9 @@ strerror (int errnum)
case ENOSHARE:
error = "No such host or network path";
break;
+ case ECASECLASH:
+ error = "Filename exists with different case";
+ break;
default:
#ifdef _MT_SAFE
char *buf= _reent_winsup()->_strerror_buf;
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 73fe3f554..ff9a9dfb4 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -1208,9 +1208,11 @@ fhandler_disk_file::open (const char *path, int flags, mode_t mode)
PC_SYM_NOFOLLOW : PC_SYM_FOLLOW);
if (real_path.error &&
- (flags & O_NOSYMLINK || real_path.error != ENOENT || !(flags & O_CREAT)))
+ (flags & O_NOSYMLINK || real_path.error != ENOENT
+ || !(flags & O_CREAT) || real_path.case_clash))
{
- set_errno (real_path.error);
+ set_errno (flags & O_CREAT && real_path.case_clash ? ECASECLASH
+ : real_path.error);
syscall_printf ("0 = fhandler_disk_file::open (%s, %p)", path, flags);
return 0;
}
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 9d2f63d54..3193c7a98 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -101,12 +101,17 @@ struct symlink_info
int is_symlink;
bool ext_tacked_on;
int error;
+ BOOL case_clash;
symlink_info (): contents (buf + MAX_PATH + 1) {}
- int check (const char *path, const suffix_info *suffixes);
+ int check (const char *path, const suffix_info *suffixes,
+ char *orig_path, BOOL sym_ignore);
+ BOOL case_check (const char *path, char *orig_path);
};
cwdstuff cygcwd; /* The current working directory. */
+int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */
+
#define path_prefix_p(p1, p2, l1) \
((cyg_tolower(*(p1))==cyg_tolower(*(p2))) && \
path_prefix_p_(p1, p2, l1))
@@ -150,12 +155,30 @@ path_prefix_p_ (const char *path1, const char *path2, int len1)
if (len1 == 0)
return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
- if (!strncasematch (path1, path2, len1))
+ if (!pathnmatch (path1, path2, len1))
return 0;
return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
}
+/* Return non-zero if paths match in first len chars.
+ Check is dependent of the case sensitivity setting. */
+int
+pathnmatch (const char *path1, const char *path2, int len)
+{
+ return pcheck_case == PCHECK_STRICT ? !strncmp (path1, path2, len)
+ : strncasematch (path1, path2, len);
+}
+
+/* Return non-zero if paths match. Check is dependent of the case
+ sensitivity setting. */
+int
+pathmatch (const char *path1, const char *path2)
+{
+ return pcheck_case == PCHECK_STRICT ? !strcmp (path1, path2)
+ : strcasematch (path1, path2);
+}
+
/* Convert an arbitrary path SRC to a pure Win32 path, suitable for
passing to Win32 API routines.
@@ -211,6 +234,7 @@ path_conv::check (const char *src, unsigned opt,
path_flags = 0;
known_suffix = NULL;
fileattr = (DWORD) -1;
+ case_clash = FALSE;
for (;;)
{
MALLOC_CHECK;
@@ -247,7 +271,7 @@ path_conv::check (const char *src, unsigned opt,
if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
strcat (full_path, "\\");
- if (opt & PC_SYM_IGNORE)
+ if ((opt & PC_SYM_IGNORE) && pcheck_case == PCHECK_RELAXED)
{
fileattr = GetFileAttributesA (path);
goto out;
@@ -284,44 +308,77 @@ path_conv::check (const char *src, unsigned opt,
sym.pflags = path_flags;
}
- int len = sym.check (path_copy, suff);
+ int len = sym.check (path_copy, suff, full_path, opt & PC_SYM_IGNORE);
- if (!component)
- path_flags = sym.pflags;
+ if (sym.case_clash)
+ {
+ case_clash = TRUE;
+ error = ENOENT;
+ goto out;
+ }
- /* If symlink.check found an existing non-symlink file, then
- it sets the appropriate flag. It also sets any suffix found
- into `ext_here'. */
- if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
+ if (!(opt & PC_SYM_IGNORE))
{
- error = sym.error;
- if (component == 0)
+ if (!component)
+ path_flags = sym.pflags;
+
+ /* If symlink.check found an existing non-symlink file, then
+ it sets the appropriate flag. It also sets any suffix found
+ into `ext_here'. */
+ if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
{
- fileattr = sym.fileattr;
- goto fillin;
+ error = sym.error;
+ if (component == 0)
+ {
+ fileattr = sym.fileattr;
+ if (sym.ext_here && *sym.ext_here)
+ {
+ known_suffix = this->path + sym.extn;
+ if (sym.ext_tacked_on)
+ strcpy (known_suffix, sym.ext_here);
+ }
+ }
+ if (pcheck_case == PCHECK_RELAXED)
+ goto out; // file found
+ /* Avoid further symlink evaluation. Only case checks are
+ done now. */
+ opt |= PC_SYM_IGNORE;
}
- goto out; // file found
- }
- /* Found a symlink if len > 0. If component == 0, then the
- src path itself was a symlink. If !follow_mode then
- we're done. Otherwise we have to insert the path found
- into the full path that we are building and perform all of
- these operations again on the newly derived path. */
- else if (len > 0)
- {
- saw_symlinks = 1;
- if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW))
+ /* Found a symlink if len > 0. If component == 0, then the
+ src path itself was a symlink. If !follow_mode then
+ we're done. Otherwise we have to insert the path found
+ into the full path that we are building and perform all of
+ these operations again on the newly derived path. */
+ else if (len > 0)
{
- set_symlink (); // last component of path is a symlink.
- fileattr = sym.fileattr;
- if (opt & PC_SYM_CONTENTS)
- strcpy (path, sym.contents);
- goto fillin;
+ saw_symlinks = 1;
+ if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW))
+ {
+ set_symlink (); // last component of path is a symlink.
+ fileattr = sym.fileattr;
+ if (opt & PC_SYM_CONTENTS)
+ {
+ strcpy (path, sym.contents);
+ goto out;
+ }
+ if (sym.ext_here && *sym.ext_here)
+ {
+ known_suffix = this->path + sym.extn;
+ if (sym.ext_tacked_on)
+ strcpy (known_suffix, sym.ext_here);
+ }
+ if (pcheck_case == PCHECK_RELAXED)
+ goto out;
+ /* Avoid further symlink evaluation. Only case checks are
+ done now. */
+ opt |= PC_SYM_IGNORE;
+ }
+ else
+ break;
}
- break;
- }
+ /* No existing file found. */
- /* No existing file found. */
+ }
if (!(tail = strrchr (path_copy, '\\')) ||
(tail > path_copy && tail[-1] == ':'))
@@ -378,7 +435,7 @@ path_conv::check (const char *src, unsigned opt,
}
}
-fillin:
+/*fillin:*/
if (sym.ext_here && *sym.ext_here && !(opt & PC_SYM_CONTENTS))
{
known_suffix = this->path + sym.extn;
@@ -399,6 +456,7 @@ out:
error = ENOTDIR;
return;
}
+
DWORD serial, volflags;
char fs_name[16];
@@ -2258,18 +2316,17 @@ symlink (const char *topath, const char *frompath)
char w32topath[MAX_PATH + 1];
DWORD written;
- if (allow_winsymlinks)
+ win32_path.check (frompath, PC_SYM_NOFOLLOW);
+ if (allow_winsymlinks && !win32_path.error)
{
strcpy (from, frompath);
strcat (from, ".lnk");
win32_path.check (from, PC_SYM_NOFOLLOW);
}
- else
- win32_path.check (frompath, PC_SYM_NOFOLLOW);
if (win32_path.error)
{
- set_errno (win32_path.error);
+ set_errno (win32_path.case_clash ? ECASECLASH : win32_path.error);
goto done;
}
@@ -2573,7 +2630,8 @@ suffix_scan::next ()
stored into BUF if PATH is a symlink. */
int
-symlink_info::check (const char *path, const suffix_info *suffixes)
+symlink_info::check (const char *path, const suffix_info *suffixes,
+ char *orig_path, BOOL sym_ignore)
{
HANDLE h;
int res = 0;
@@ -2585,6 +2643,8 @@ symlink_info::check (const char *path, const suffix_info *suffixes)
ext_tacked_on = !*ext_here;
+ case_clash = FALSE;
+
while (suffix.next ())
{
error = 0;
@@ -2599,6 +2659,10 @@ symlink_info::check (const char *path, const suffix_info *suffixes)
continue;
}
+ if (pcheck_case != PCHECK_RELAXED && !case_check (path, orig_path)
+ || sym_ignore)
+ goto file_not_symlink;
+
int sym_check = 0;
if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
@@ -2662,6 +2726,50 @@ out:
return res;
}
+/* Check the correct case of the last path component (given in DOS style).
+ Adjust the case in this->path if pcheck_case == PCHECK_ADJUST or return
+ FALSE if pcheck_case == PCHECK_STRICT.
+ Dont't call if pcheck_case == PCHECK_RELAXED.
+*/
+
+BOOL
+symlink_info::case_check (const char *path, char *orig_path)
+{
+ WIN32_FIND_DATA data;
+ HANDLE h;
+ const char *c;
+
+ /* Set a pointer to the beginning of the last component. */
+ if (!(c = strrchr (path, '\\')))
+ c = path;
+ else
+ ++c;
+
+ if ((h = FindFirstFile (path, &data))
+ != INVALID_HANDLE_VALUE)
+ {
+ FindClose (h);
+
+ /* If that part of the component exists, check the case. */
+ if (strcmp (c, data.cFileName))
+ {
+ /* If check is set to STRICT, a wrong case results
+ in returning a ENOENT. */
+ if (pcheck_case == PCHECK_STRICT)
+ {
+ case_clash = TRUE;
+ return FALSE;
+ }
+
+ /* PCHECK_ADJUST adjusts the case in the incoming
+ path which points to the path in *this. */
+ strncpy (orig_path + (c - path), data.cFileName,
+ strlen (data.cFileName));
+ }
+ }
+ return TRUE;
+}
+
/* readlink system call */
extern "C"
@@ -2855,7 +2963,8 @@ chdir (const char *dir)
we'll see if Cygwin mailing list users whine about the current behavior. */
if (res == -1)
__seterrno ();
- else if (!path.has_symlinks () && strpbrk (dir, ":\\") == NULL)
+ else if (!path.has_symlinks () && strpbrk (dir, ":\\") == NULL
+ && pcheck_case == PCHECK_RELAXED)
cygcwd.set (path, dir);
else
cygcwd.set (path, NULL);
diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h
index bdca965b4..4f9df23b0 100644
--- a/winsup/cygwin/path.h
+++ b/winsup/cygwin/path.h
@@ -25,6 +25,13 @@ enum pathconv_arg
PC_NULLEMPTY = 0x0020
};
+enum case_checking
+{
+ PCHECK_RELAXED = 0,
+ PCHECK_ADJUST = 1,
+ PCHECK_STRICT = 2
+};
+
#define PC_NONULLEMPTY -1
#include <sys/mount.h>
@@ -89,6 +96,8 @@ class path_conv
DWORD fileattr;
+ BOOL case_clash;
+
void check (const char *src, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL) __attribute__ ((regparm(3)));
@@ -171,3 +180,6 @@ struct cwdstuff
};
extern cwdstuff cygcwd;
+
+extern int pathmatch (const char *path1, const char *path2);
+extern int pathnmatch (const char *path1, const char *path2, int len);
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index f7f51999a..933baafcf 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -545,7 +545,7 @@ _link (const char *a, const char *b)
}
if (real_b.error)
{
- set_errno (real_b.error);
+ set_errno (real_b.case_clash ? ECASECLASH : real_b.error);
goto done;
}