* 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.
This commit is contained in:
Corinna Vinschen 2001-04-12 21:21:37 +00:00
parent b8a8c59d33
commit 70c370d674
8 changed files with 232 additions and 49 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
@ -393,6 +394,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)
{
@ -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}}},

View File

@ -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;

View File

@ -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;
}

View File

@ -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 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 (sym.case_clash)
{
error = sym.error;
if (component == 0)
{
fileattr = sym.fileattr;
goto fillin;
}
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))
{
set_symlink (); // last component of path is a symlink.
fileattr = sym.fileattr;
if (opt & PC_SYM_CONTENTS)
strcpy (path, sym.contents);
goto fillin;
}
break;
case_clash = TRUE;
error = ENOENT;
goto out;
}
/* No existing file found. */
if (!(opt & PC_SYM_IGNORE))
{
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)
{
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;
}
/* 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))
{
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;
}
/* 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);

View File

@ -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);

View File

@ -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;
}