* 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:
parent
b8a8c59d33
commit
70c370d674
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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}}},
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user