Commit 806fed21 authored by Eli Zaretskii's avatar Eli Zaretskii
Browse files

Fix bug #13553 with usage of IS_DIRECTORY_SEP on MS-Windows under DBCS.

 src/w32.c (parse_root, get_volume_info, readdir, read_unc_volume)
 (logon_network_drive, stat_worker, symlink, chase_symlinks): Use
 CharNextExA and CharPrevExA to iterate over file names encoded in
 DBCS.
parent 26854e9c
2013-01-26 Eli Zaretskii <eliz@gnu.org>
* w32.c (parse_root, get_volume_info, readdir, read_unc_volume)
(logon_network_drive, stat_worker, symlink, chase_symlinks): Use
CharNextExA and CharPrevExA to iterate over file names encoded in
DBCS. (Bug#13553)
2013-01-25 Eli Zaretskii <eliz@gnu.org> 2013-01-25 Eli Zaretskii <eliz@gnu.org>
   
* w32.c (w32_get_long_filename, init_environment, readlink): * w32.c (w32_get_long_filename, init_environment, readlink):
......
...@@ -1503,12 +1503,17 @@ parse_root (char * name, char ** pPath) ...@@ -1503,12 +1503,17 @@ parse_root (char * name, char ** pPath)
else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1])) else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
{ {
int slashes = 2; int slashes = 2;
int dbcs_p = max_filename_mbslen () > 1;
name += 2; name += 2;
do do
{ {
if (IS_DIRECTORY_SEP (*name) && --slashes == 0) if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
break; break;
name++; if (dbcs_p)
name = CharNextExA (file_name_codepage, name, 0);
else
name++;
} }
while ( *name ); while ( *name );
if (IS_DIRECTORY_SEP (name[0])) if (IS_DIRECTORY_SEP (name[0]))
...@@ -2369,12 +2374,23 @@ get_volume_info (const char * name, const char ** pPath) ...@@ -2369,12 +2374,23 @@ get_volume_info (const char * name, const char ** pPath)
{ {
char *str = temp; char *str = temp;
int slashes = 4; int slashes = 4;
int dbcs_p = max_filename_mbslen () > 1;
rootname = temp; rootname = temp;
do do
{ {
if (IS_DIRECTORY_SEP (*name) && --slashes == 0) if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
break; break;
*str++ = *name++; if (!dbcs_p)
*str++ = *name++;
else
{
const char *p = name;
name = CharNextExA (file_name_codepage, name, 0);
memcpy (str, p, name - p);
str += name - p;
}
} }
while ( *name ); while ( *name );
...@@ -2610,11 +2626,23 @@ readdir (DIR *dirp) ...@@ -2610,11 +2626,23 @@ readdir (DIR *dirp)
{ {
char filename[MAXNAMLEN + 3]; char filename[MAXNAMLEN + 3];
int ln; int ln;
int dbcs_p = max_filename_mbslen () > 1;
strcpy (filename, dir_pathname); strcpy (filename, dir_pathname);
ln = strlen (filename) - 1; ln = strlen (filename) - 1;
if (!IS_DIRECTORY_SEP (filename[ln])) if (!dbcs_p)
strcat (filename, "\\"); {
if (!IS_DIRECTORY_SEP (filename[ln]))
strcat (filename, "\\");
}
else
{
char *end = filename + ln + 1;
char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
if (!IS_DIRECTORY_SEP (*last_char))
strcat (filename, "\\");
}
strcat (filename, "*"); strcat (filename, "*");
/* Note: No need to resolve symlinks in FILENAME, because /* Note: No need to resolve symlinks in FILENAME, because
...@@ -2719,6 +2747,7 @@ read_unc_volume (HANDLE henum, char *readbuf, int size) ...@@ -2719,6 +2747,7 @@ read_unc_volume (HANDLE henum, char *readbuf, int size)
DWORD bufsize = 512; DWORD bufsize = 512;
char *buffer; char *buffer;
char *ptr; char *ptr;
int dbcs_p = max_filename_mbslen () > 1;
count = 1; count = 1;
buffer = alloca (bufsize); buffer = alloca (bufsize);
...@@ -2729,7 +2758,13 @@ read_unc_volume (HANDLE henum, char *readbuf, int size) ...@@ -2729,7 +2758,13 @@ read_unc_volume (HANDLE henum, char *readbuf, int size)
/* WNetEnumResource returns \\resource\share...skip forward to "share". */ /* WNetEnumResource returns \\resource\share...skip forward to "share". */
ptr = ((LPNETRESOURCE) buffer)->lpRemoteName; ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
ptr += 2; ptr += 2;
while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++; if (!dbcs_p)
while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
else
{
while (*ptr && !IS_DIRECTORY_SEP (*ptr))
ptr = CharNextExA (file_name_codepage, ptr, 0);
}
ptr++; ptr++;
strncpy (readbuf, ptr, size); strncpy (readbuf, ptr, size);
...@@ -2766,9 +2801,11 @@ logon_network_drive (const char *path) ...@@ -2766,9 +2801,11 @@ logon_network_drive (const char *path)
{ {
NETRESOURCE resource; NETRESOURCE resource;
char share[MAX_PATH]; char share[MAX_PATH];
int i, n_slashes; int n_slashes;
char drive[4]; char drive[4];
UINT drvtype; UINT drvtype;
char *p;
int dbcs_p;
if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1])) if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
drvtype = DRIVE_REMOTE; drvtype = DRIVE_REMOTE;
...@@ -2790,13 +2827,18 @@ logon_network_drive (const char *path) ...@@ -2790,13 +2827,18 @@ logon_network_drive (const char *path)
n_slashes = 2; n_slashes = 2;
strncpy (share, path, MAX_PATH); strncpy (share, path, MAX_PATH);
/* Truncate to just server and share name. */ /* Truncate to just server and share name. */
for (i = 2; i < MAX_PATH; i++) dbcs_p = max_filename_mbslen () > 1;
for (p = share + 2; *p && p < share + MAX_PATH; )
{ {
if (IS_DIRECTORY_SEP (share[i]) && ++n_slashes > 3) if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
{ {
share[i] = '\0'; *p = '\0';
break; break;
} }
if (dbcs_p)
p = CharNextExA (file_name_codepage, p, 0);
else
p++;
} }
resource.dwType = RESOURCETYPE_DISK; resource.dwType = RESOURCETYPE_DISK;
...@@ -3557,6 +3599,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) ...@@ -3557,6 +3599,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
DWORD access_rights = 0; DWORD access_rights = 0;
DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1; DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
FILETIME ctime, atime, wtime; FILETIME ctime, atime, wtime;
int dbcs_p;
if (path == NULL || buf == NULL) if (path == NULL || buf == NULL)
{ {
...@@ -3751,6 +3794,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) ...@@ -3751,6 +3794,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
did not ask for extra precision, resolving symlinks will fly did not ask for extra precision, resolving symlinks will fly
in the face of that request, since the user then wants the in the face of that request, since the user then wants the
lightweight version of the code. */ lightweight version of the code. */
dbcs_p = max_filename_mbslen () > 1;
rootdir = (path >= save_name + len - 1 rootdir = (path >= save_name + len - 1
&& (IS_DIRECTORY_SEP (*path) || *path == 0)); && (IS_DIRECTORY_SEP (*path) || *path == 0));
...@@ -3778,8 +3822,19 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) ...@@ -3778,8 +3822,19 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
} }
else if (rootdir) else if (rootdir)
{ {
if (!IS_DIRECTORY_SEP (name[len-1])) if (!dbcs_p)
strcat (name, "\\"); {
if (!IS_DIRECTORY_SEP (name[len-1]))
strcat (name, "\\");
}
else
{
char *end = name + len;
char *n = CharPrevExA (file_name_codepage, name, end, 0);
if (!IS_DIRECTORY_SEP (*n))
strcat (name, "\\");
}
if (GetDriveType (name) < 2) if (GetDriveType (name) < 2)
{ {
errno = ENOENT; errno = ENOENT;
...@@ -3791,15 +3846,37 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks) ...@@ -3791,15 +3846,37 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
} }
else else
{ {
if (IS_DIRECTORY_SEP (name[len-1])) if (!dbcs_p)
name[len - 1] = 0; {
if (IS_DIRECTORY_SEP (name[len-1]))
name[len - 1] = 0;
}
else
{
char *end = name + len;
char *n = CharPrevExA (file_name_codepage, name, end, 0);
if (IS_DIRECTORY_SEP (*n))
*n = 0;
}
/* (This is hacky, but helps when doing file completions on /* (This is hacky, but helps when doing file completions on
network drives.) Optimize by using information available from network drives.) Optimize by using information available from
active readdir if possible. */ active readdir if possible. */
len = strlen (dir_pathname); len = strlen (dir_pathname);
if (IS_DIRECTORY_SEP (dir_pathname[len-1])) if (!dbcs_p)
len--; {
if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
len--;
}
else
{
char *end = dir_pathname + len;
char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
if (IS_DIRECTORY_SEP (*n))
len--;
}
if (dir_find_handle != INVALID_HANDLE_VALUE if (dir_find_handle != INVALID_HANDLE_VALUE
&& !(is_a_symlink && follow_symlinks) && !(is_a_symlink && follow_symlinks)
&& strnicmp (save_name, dir_pathname, len) == 0 && strnicmp (save_name, dir_pathname, len) == 0
...@@ -4060,6 +4137,7 @@ symlink (char const *filename, char const *linkname) ...@@ -4060,6 +4137,7 @@ symlink (char const *filename, char const *linkname)
char linkfn[MAX_PATH], *tgtfn; char linkfn[MAX_PATH], *tgtfn;
DWORD flags = 0; DWORD flags = 0;
int dir_access, filename_ends_in_slash; int dir_access, filename_ends_in_slash;
int dbcs_p;
/* Diagnostics follows Posix as much as possible. */ /* Diagnostics follows Posix as much as possible. */
if (filename == NULL || linkname == NULL) if (filename == NULL || linkname == NULL)
...@@ -4085,6 +4163,8 @@ symlink (char const *filename, char const *linkname) ...@@ -4085,6 +4163,8 @@ symlink (char const *filename, char const *linkname)
return -1; return -1;
} }
dbcs_p = max_filename_mbslen () > 1;
/* Note: since empty FILENAME was already rejected, we can safely /* Note: since empty FILENAME was already rejected, we can safely
refer to FILENAME[1]. */ refer to FILENAME[1]. */
if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1]))) if (!(IS_DIRECTORY_SEP (filename[0]) || IS_DEVICE_SEP (filename[1])))
...@@ -4099,8 +4179,21 @@ symlink (char const *filename, char const *linkname) ...@@ -4099,8 +4179,21 @@ symlink (char const *filename, char const *linkname)
char tem[MAX_PATH]; char tem[MAX_PATH];
char *p = linkfn + strlen (linkfn); char *p = linkfn + strlen (linkfn);
while (p > linkfn && !IS_ANY_SEP (p[-1])) if (!dbcs_p)
p--; {
while (p > linkfn && !IS_ANY_SEP (p[-1]))
p--;
}
else
{
char *p1 = CharPrevExA (file_name_codepage, linkfn, p, 0);
while (p > linkfn && !IS_ANY_SEP (*p1))
{
p = p1;
p1 = CharPrevExA (file_name_codepage, linkfn, p1, 0);
}
}
if (p > linkfn) if (p > linkfn)
strncpy (tem, linkfn, p - linkfn); strncpy (tem, linkfn, p - linkfn);
tem[p - linkfn] = '\0'; tem[p - linkfn] = '\0';
...@@ -4115,7 +4208,15 @@ symlink (char const *filename, char const *linkname) ...@@ -4115,7 +4208,15 @@ symlink (char const *filename, char const *linkname)
exist, but ends in a slash, we create a symlink to directory. If exist, but ends in a slash, we create a symlink to directory. If
FILENAME exists and is a directory, we always create a symlink to FILENAME exists and is a directory, we always create a symlink to
directory. */ directory. */
filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]); if (!dbcs_p)
filename_ends_in_slash = IS_DIRECTORY_SEP (filename[strlen (filename) - 1]);
else
{
const char *end = filename + strlen (filename);
const char *n = CharPrevExA (file_name_codepage, filename, end, 0);
filename_ends_in_slash = IS_DIRECTORY_SEP (*n);
}
if (dir_access == 0 || filename_ends_in_slash) if (dir_access == 0 || filename_ends_in_slash)
flags = SYMBOLIC_LINK_FLAG_DIRECTORY; flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
...@@ -4440,6 +4541,7 @@ chase_symlinks (const char *file) ...@@ -4440,6 +4541,7 @@ chase_symlinks (const char *file)
char link[MAX_PATH]; char link[MAX_PATH];
ssize_t res, link_len; ssize_t res, link_len;
int loop_count = 0; int loop_count = 0;
int dbcs_p;
if (is_windows_9x () == TRUE || !is_symlink (file)) if (is_windows_9x () == TRUE || !is_symlink (file))
return (char *)file; return (char *)file;
...@@ -4447,13 +4549,27 @@ chase_symlinks (const char *file) ...@@ -4447,13 +4549,27 @@ chase_symlinks (const char *file)
if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0) if ((link_len = GetFullPathName (file, MAX_PATH, link, NULL)) == 0)
return (char *)file; return (char *)file;
dbcs_p = max_filename_mbslen () > 1;
target[0] = '\0'; target[0] = '\0';
do { do {
/* Remove trailing slashes, as we want to resolve the last /* Remove trailing slashes, as we want to resolve the last
non-trivial part of the link name. */ non-trivial part of the link name. */
while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1])) if (!dbcs_p)
link[link_len--] = '\0'; {
while (link_len > 3 && IS_DIRECTORY_SEP (link[link_len-1]))
link[link_len--] = '\0';
}
else if (link_len > 3)
{
char *n = CharPrevExA (file_name_codepage, link, link + link_len, 0);
while (n >= link + 2 && IS_DIRECTORY_SEP (*n))
{
n[1] = '\0';
n = CharPrevExA (file_name_codepage, link, n, 0);
}
}
res = readlink (link, target, MAX_PATH); res = readlink (link, target, MAX_PATH);
if (res > 0) if (res > 0)
...@@ -4466,8 +4582,21 @@ chase_symlinks (const char *file) ...@@ -4466,8 +4582,21 @@ chase_symlinks (const char *file)
the symlink, then copy the result back to target. */ the symlink, then copy the result back to target. */
char *p = link + link_len; char *p = link + link_len;
while (p > link && !IS_ANY_SEP (p[-1])) if (!dbcs_p)
p--; {
while (p > link && !IS_ANY_SEP (p[-1]))
p--;
}
else
{
char *p1 = CharPrevExA (file_name_codepage, link, p, 0);
while (p > link && !IS_ANY_SEP (*p1))
{
p = p1;
p1 = CharPrevExA (file_name_codepage, link, p1, 0);
}
}
strcpy (p, target); strcpy (p, target);
strcpy (target, link); strcpy (target, link);
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment