* path.h (get_nt_native_path): Add third parameter to declaration and

declare with regparms.
	* path.cc (get_nt_native_path): Add third parameter to allow conversion
	of leading and trailing dots and spaces on filesystems only supporting
	filenames following DOS rules.
	(path_conv::get_nt_native_path): Call get_nt_native_path according to
	fs.has_dos_filenames_only flag.
	(getfileattr): Accommodate new parameter to get_nt_native_path.
	(symlink_info::check): Revamp fs_update_called handling to call
	fs.update only once per call.  Call get_nt_native_path according to
	fs.has_dos_filenames_only flag.  Streamline filesystem dependent code
	not to be called more than once unnecessarily.  Drop code tweaking
	incoming path for broken filesystems only allowing DOS pathnames.
	Rely on changed get_nt_native_path instead.
	* mount.cc (fillout_mntent): Accommodate new parameter to
	get_nt_native_path.
	* strfuncs.cc (tfx_rev_chars): New conversion table with comment.
	(sys_cp_wcstombs): Use tfx_rev_chars rather than tfx_chars.
This commit is contained in:
Corinna Vinschen 2010-04-23 11:07:35 +00:00
parent 948214b000
commit 8802178fdd
5 changed files with 110 additions and 33 deletions

View File

@ -1,3 +1,24 @@
2010-04-23 Corinna Vinschen <corinna@vinschen.de>
* path.h (get_nt_native_path): Add third parameter to declaration and
declare with regparms.
* path.cc (get_nt_native_path): Add third parameter to allow conversion
of leading and trailing dots and spaces on filesystems only supporting
filenames following DOS rules.
(path_conv::get_nt_native_path): Call get_nt_native_path according to
fs.has_dos_filenames_only flag.
(getfileattr): Accommodate new parameter to get_nt_native_path.
(symlink_info::check): Revamp fs_update_called handling to call
fs.update only once per call. Call get_nt_native_path according to
fs.has_dos_filenames_only flag. Streamline filesystem dependent code
not to be called more than once unnecessarily. Drop code tweaking
incoming path for broken filesystems only allowing DOS pathnames.
Rely on changed get_nt_native_path instead.
* mount.cc (fillout_mntent): Accommodate new parameter to
get_nt_native_path.
* strfuncs.cc (tfx_rev_chars): New conversion table with comment.
(sys_cp_wcstombs): Use tfx_rev_chars rather than tfx_chars.
2010-04-22 Corinna Vinschen <corinna@vinschen.de> 2010-04-22 Corinna Vinschen <corinna@vinschen.de>
* path.cc (symlink_info::check): Make sure to restart only once. * path.cc (symlink_info::check): Make sure to restart only once.

View File

@ -1470,7 +1470,7 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
tmp_pathbuf tp; tmp_pathbuf tp;
UNICODE_STRING unat; UNICODE_STRING unat;
tp.u_get (&unat); tp.u_get (&unat);
get_nt_native_path (native_path, unat); get_nt_native_path (native_path, unat, false);
if (append_bs) if (append_bs)
RtlAppendUnicodeToString (&unat, L"\\"); RtlAppendUnicodeToString (&unat, L"\\");
mntinfo.update (&unat, NULL); mntinfo.update (&unat, NULL);

View File

@ -393,7 +393,7 @@ str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
} }
PUNICODE_STRING PUNICODE_STRING
get_nt_native_path (const char *path, UNICODE_STRING& upath) get_nt_native_path (const char *path, UNICODE_STRING& upath, bool dos)
{ {
upath.Length = 0; upath.Length = 0;
if (path[0] == '/') /* special path w/o NT path representation. */ if (path[0] == '/') /* special path w/o NT path representation. */
@ -425,6 +425,26 @@ get_nt_native_path (const char *path, UNICODE_STRING& upath)
RtlAppendUnicodeStringToString (&upath, &ro_u_natp); RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
str2uni_cat (upath, path + 4); str2uni_cat (upath, path + 4);
} }
if (dos)
{
/* Unfortunately we can't just use transform_chars with the tfx_rev_chars
table since only leading and trainlig spaces and dots are affected.
So we step to every backslash and fix surrounding dots and spaces.
That makes these broken filesystems a bit slower, but, hey. */
PWCHAR cp = upath.Buffer + 7;
PWCHAR cend = upath.Buffer + upath.Length / sizeof (WCHAR);
while (++cp < cend)
if (*cp == L'\\')
{
PWCHAR ccp = cp - 1;
while (*ccp == L'.' || *ccp == L' ')
*ccp-- |= 0xf000;
while (cp[1] == L' ')
*++cp |= 0xf000;
}
while (*--cp == L'.' || *cp == L' ')
*cp |= 0xf000;
}
return &upath; return &upath;
} }
@ -437,7 +457,7 @@ path_conv::get_nt_native_path ()
uni_path.MaximumLength = (strlen (path) + 10) * sizeof (WCHAR); uni_path.MaximumLength = (strlen (path) + 10) * sizeof (WCHAR);
wide_path = (PWCHAR) cmalloc_abort (HEAP_STR, uni_path.MaximumLength); wide_path = (PWCHAR) cmalloc_abort (HEAP_STR, uni_path.MaximumLength);
uni_path.Buffer = wide_path; uni_path.Buffer = wide_path;
::get_nt_native_path (path, uni_path); ::get_nt_native_path (path, uni_path, fs.has_dos_filenames_only ());
} }
return &uni_path; return &uni_path;
} }
@ -501,7 +521,7 @@ getfileattr (const char *path, bool caseinsensitive) /* path has to be always ab
InitializeObjectAttributes (&attr, &upath, InitializeObjectAttributes (&attr, &upath,
caseinsensitive ? OBJ_CASE_INSENSITIVE : 0, caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
NULL, NULL); NULL, NULL);
get_nt_native_path (path, upath); get_nt_native_path (path, upath, false);
status = NtQueryAttributesFile (&attr, &fbi); status = NtQueryAttributesFile (&attr, &fbi);
if (NT_SUCCESS (status)) if (NT_SUCCESS (status))
@ -2178,9 +2198,10 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt,
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
FILE_BASIC_INFORMATION fbi; FILE_BASIC_INFORMATION fbi;
suffix_scan suffix; suffix_scan suffix;
bool fs_update_called = false;
ULONG ci_flag = cygwin_shared->obcaseinsensitive || (pflags & PATH_NOPOSIX) const ULONG ci_flag = cygwin_shared->obcaseinsensitive
? OBJ_CASE_INSENSITIVE : 0; || (pflags & PATH_NOPOSIX) ? OBJ_CASE_INSENSITIVE : 0;
/* TODO: Temporarily do all char->UNICODE conversion here. This should /* TODO: Temporarily do all char->UNICODE conversion here. This should
already be slightly faster than using Ascii functions. */ already be slightly faster than using Ascii functions. */
tmp_pathbuf tp; tmp_pathbuf tp;
@ -2212,10 +2233,9 @@ restart:
while (suffix.next ()) while (suffix.next ())
{ {
bool no_ea = false; bool no_ea = false;
bool fs_update_called = false;
error = 0; error = 0;
get_nt_native_path (suffix.path, upath); get_nt_native_path (suffix.path, upath, fs.has_dos_filenames_only ());
if (h) if (h)
{ {
NtClose (h); NtClose (h);
@ -2261,7 +2281,8 @@ restart:
} }
if (status == STATUS_OBJECT_NAME_NOT_FOUND) if (status == STATUS_OBJECT_NAME_NOT_FOUND)
{ {
if (ci_flag == 0 && wincap.has_broken_udf ()) if (ci_flag == 0 && wincap.has_broken_udf ()
&& (!fs_update_called || fs.is_udf ()))
{ {
/* On NT 5.x UDF is broken (at least) in terms of case /* On NT 5.x UDF is broken (at least) in terms of case
sensitivity. When trying to open a file case sensitive, sensitivity. When trying to open a file case sensitive,
@ -2276,10 +2297,9 @@ restart:
attr.Attributes = 0; attr.Attributes = 0;
if (NT_SUCCESS (status)) if (NT_SUCCESS (status))
{ {
fs.update (&upath, h); if (!fs_update_called)
if (fs.is_udf ()) fs_update_called = fs.update (&upath, h);
fs_update_called = true; if (!fs.is_udf ())
else
{ {
NtClose (h); NtClose (h);
status = STATUS_OBJECT_NAME_NOT_FOUND; status = STATUS_OBJECT_NAME_NOT_FOUND;
@ -2295,31 +2315,29 @@ restart:
we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
already attach a suffix *and* the above special case for UDF already attach a suffix *and* the above special case for UDF
on XP didn't succeeed. */ on XP didn't succeeed. */
if (!restarted && !*ext_here && !fs_update_called) if (!restarted && !*ext_here
&& (!fs_update_called || fs.has_dos_filenames_only ()))
{ {
/* Check for leading space or trailing dot or space in /* Check for leading space or trailing dot or space in
last component. */ last component. */
char *pend = ext_here; char *pend = ext_here;
while (pend[-1] == '.' || pend[-1] == ' ') if (pend[-1] == '.' || pend[-1] == ' ')
--pend; --pend;
char *pbeg = pend; char *pbeg = pend;
while (pbeg[-1] != '\\') while (pbeg[-1] != '\\')
--pbeg; --pbeg;
/* If so, call fs.update to check if the filesystem is one of /* If so, call fs.update to check if the filesystem is one of
the broken ones. */ the broken ones. */
if ((*pbeg == ' ' || *pend != '\0') if (*pbeg == ' ' || *pend != '\0')
&& fs.update (&upath, NULL)
&& fs.has_dos_filenames_only ())
{ {
/* If so, strip leading spaces and trailing dots and spaces if (!fs_update_called)
from filename and... */ fs_update_called = fs.update (&upath, NULL);
if (pbeg) if (fs.has_dos_filenames_only ())
while (*pbeg == ' ') {
memmove (pbeg, pbeg + 1, --pend - pbeg); /* If so, try again. */
*pend = '\0'; restarted = true;
/* ...try again. */ goto restart;
restarted = true; }
goto restart;
} }
} }
} }
@ -2327,7 +2345,7 @@ restart:
if (NT_SUCCESS (status) if (NT_SUCCESS (status)
/* Check file system while we're having the file open anyway. /* Check file system while we're having the file open anyway.
This speeds up path_conv noticably (~10%). */ This speeds up path_conv noticably (~10%). */
&& (fs_update_called || fs.update (&upath, h)) && (fs_update_called || (fs_update_called = fs.update (&upath, h)))
&& NT_SUCCESS (status = fs.has_buggy_basic_info () && NT_SUCCESS (status = fs.has_buggy_basic_info ()
? NtQueryAttributesFile (&attr, &fbi) ? NtQueryAttributesFile (&attr, &fbi)
: NtQueryInformationFile (h, &io, &fbi, sizeof fbi, : NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
@ -2397,7 +2415,7 @@ restart:
TRUE, &basename, TRUE); TRUE, &basename, TRUE);
/* Take the opportunity to check file system while we're /* Take the opportunity to check file system while we're
having the handle to the parent dir. */ having the handle to the parent dir. */
fs.update (&upath, h); fs_update_called = fs.update (&upath, h);
NtClose (dir); NtClose (dir);
if (!NT_SUCCESS (status)) if (!NT_SUCCESS (status))
{ {

View File

@ -302,7 +302,7 @@ int path_prefix_p (const char *path1, const char *path2, int len1,
bool is_floppy (const char *); bool is_floppy (const char *);
int normalize_win32_path (const char *, char *, char *&); int normalize_win32_path (const char *, char *, char *&);
int normalize_posix_path (const char *, char *, char *&); int normalize_posix_path (const char *, char *, char *&);
PUNICODE_STRING get_nt_native_path (const char *, UNICODE_STRING&); PUNICODE_STRING get_nt_native_path (const char *, UNICODE_STRING&, bool) __attribute__ ((regparm (3)));
/* FIXME: Move to own include file eventually */ /* FIXME: Move to own include file eventually */

View File

@ -23,8 +23,7 @@ details. */
use area in the U+f0XX range. The affected characters are all control use area in the U+f0XX range. The affected characters are all control
chars 1 <= c <= 31, as well as the characters " * : < > ? |. The backslash chars 1 <= c <= 31, as well as the characters " * : < > ? |. The backslash
is affected as well, but we can't transform it as long as we accept Win32 is affected as well, but we can't transform it as long as we accept Win32
paths as input. paths as input. */
The reverse functionality is in function sys_cp_wcstombs. */
static const WCHAR tfx_chars[] = { static const WCHAR tfx_chars[] = {
0, 0xf000 | 1, 0xf000 | 2, 0xf000 | 3, 0, 0xf000 | 1, 0xf000 | 2, 0xf000 | 3,
0xf000 | 4, 0xf000 | 5, 0xf000 | 6, 0xf000 | 7, 0xf000 | 4, 0xf000 | 5, 0xf000 | 6, 0xf000 | 7,
@ -60,6 +59,45 @@ static const WCHAR tfx_chars[] = {
0xf000 | '|', '}', '~', 127 0xf000 | '|', '}', '~', 127
}; };
/* This is the table for the reverse functionality in sys_cp_wcstombs.
It differs deliberately in two code places (space and dot) to allow
converting back space and dot on filesystems only supporting DOS
filenames. */
static const WCHAR tfx_rev_chars[] = {
0, 0xf000 | 1, 0xf000 | 2, 0xf000 | 3,
0xf000 | 4, 0xf000 | 5, 0xf000 | 6, 0xf000 | 7,
0xf000 | 8, 0xf000 | 9, 0xf000 | 10, 0xf000 | 11,
0xf000 | 12, 0xf000 | 13, 0xf000 | 14, 0xf000 | 15,
0xf000 | 16, 0xf000 | 17, 0xf000 | 18, 0xf000 | 19,
0xf000 | 20, 0xf000 | 21, 0xf000 | 22, 0xf000 | 23,
0xf000 | 24, 0xf000 | 25, 0xf000 | 26, 0xf000 | 27,
0xf000 | 28, 0xf000 | 29, 0xf000 | 30, 0xf000 | 31,
0xf000 | ' ', '!', 0xf000 | '"', '#',
'$', '%', '&', 39,
'(', ')', 0xf000 | '*', '+',
',', '-', 0xf000 | '.', '\\',
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 0xf000 | ':', ';',
0xf000 | '<', '=', 0xf000 | '>', 0xf000 | '?',
'@', 'A', 'B', 'C',
'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '[',
'\\', ']', '^', '_',
'`', 'a', 'b', 'c',
'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o',
'p', 'q', 'r', 's',
't', 'u', 'v', 'w',
'x', 'y', 'z', '{',
0xf000 | '|', '}', '~', 127
};
void void
transform_chars (PWCHAR path, PWCHAR path_end) transform_chars (PWCHAR path, PWCHAR path_end)
{ {
@ -382,7 +420,7 @@ sys_cp_wcstombs (wctomb_p f_wctomb, const char *charset, char *dst, size_t len,
Reverse functionality for invalid bytes in a multibyte sequence is Reverse functionality for invalid bytes in a multibyte sequence is
in sys_cp_mbstowcs below. */ in sys_cp_mbstowcs below. */
if ((pw & 0xff00) == 0xf000 if ((pw & 0xff00) == 0xf000
&& (((cwc = (pw & 0xff)) <= 0x7f && tfx_chars[cwc] >= 0xf000) && (((cwc = (pw & 0xff)) <= 0x7f && tfx_rev_chars[cwc] >= 0xf000)
|| (cwc >= 0x80 && MB_CUR_MAX > 1))) || (cwc >= 0x80 && MB_CUR_MAX > 1)))
{ {
buf[0] = (char) cwc; buf[0] = (char) cwc;