Patch #954115: Fix os.stat handling of UNC roots.

Will backport to 2.3.
This commit is contained in:
Martin v. Löwis 2004-06-02 09:57:56 +00:00
parent 0659452b8b
commit d8948725d2
2 changed files with 96 additions and 18 deletions

View File

@ -210,6 +210,8 @@ Core and builtins
Extension modules
-----------------
- nt now properly allows to refer to UNC roots, e.g. in nt.stat().
- the weakref module now supports additional objects: array.array,
sre.pattern_objects, file objects, and sockets.

View File

@ -892,6 +892,66 @@ _pystat_fromstructstat(STRUCT_STAT st)
return v;
}
#ifdef MS_WINDOWS
/* IsUNCRoot -- test whether the supplied path is of the form \\SERVER\SHARE\,
where / can be used in place of \ and the trailing slash is optional.
Both SERVER and SHARE must have at least one character.
*/
#define ISSLASHA(c) ((c) == '\\' || (c) == '/')
#define ISSLASHW(c) ((c) == L'\\' || (c) == L'/')
#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
static BOOL
IsUNCRootA(char *path, int pathlen)
{
#define ISSLASH ISSLASHA
int i, share;
if (pathlen < 5 || !ISSLASH(path[0]) || !ISSLASH(path[1]))
/* minimum UNCRoot is \\x\y */
return FALSE;
for (i = 2; i < pathlen ; i++)
if (ISSLASH(path[i])) break;
if (i == 2 || i == pathlen)
/* do not allow \\\SHARE or \\SERVER */
return FALSE;
share = i+1;
for (i = share; i < pathlen; i++)
if (ISSLASH(path[i])) break;
return (i != share && (i == pathlen || i == pathlen-1));
#undef ISSLASH
}
#ifdef Py_WIN_WIDE_FILENAMES
static BOOL
IsUNCRootW(Py_UNICODE *path, int pathlen)
{
#define ISSLASH ISSLASHW
int i, share;
if (pathlen < 5 || !ISSLASH(path[0]) || !ISSLASH(path[1]))
/* minimum UNCRoot is \\x\y */
return FALSE;
for (i = 2; i < pathlen ; i++)
if (ISSLASH(path[i])) break;
if (i == 2 || i == pathlen)
/* do not allow \\\SHARE or \\SERVER */
return FALSE;
share = i+1;
for (i = share; i < pathlen; i++)
if (ISSLASH(path[i])) break;
return (i != share && (i == pathlen || i == pathlen-1));
#undef ISSLASH
}
#endif /* Py_WIN_WIDE_FILENAMES */
#endif /* MS_WINDOWS */
static PyObject *
posix_do_stat(PyObject *self, PyObject *args,
char *format,
@ -931,17 +991,24 @@ posix_do_stat(PyObject *self, PyObject *args,
/* Remove trailing slash or backslash, unless it's the current
drive root (/ or \) or a specific drive's root (like c:\ or c:/).
*/
if (pathlen > 0 &&
(wpath[pathlen-1]== L'\\' || wpath[pathlen-1] == L'/')) {
if (pathlen > 0) {
if (ISSLASHW(wpath[pathlen-1])) {
/* It does end with a slash -- exempt the root drive cases. */
/* XXX UNC root drives should also be exempted? */
if (pathlen == 1 || (pathlen == 3 && wpath[1] == L':'))
if (pathlen == 1 || (pathlen == 3 && wpath[1] == L':') ||
IsUNCRootW(wpath, pathlen))
/* leave it alone */;
else {
/* nuke the trailing backslash */
wpath[pathlen-1] = L'\0';
}
}
else if (ISSLASHW(wpath[1]) && pathlen < ARRAYSIZE(wpath)-1 &&
IsUNCRootW(wpath, pathlen)) {
/* UNC root w/o trailing slash: add one when there's room */
wpath[pathlen++] = L'\\';
wpath[pathlen] = L'\0';
}
}
Py_BEGIN_ALLOW_THREADS
/* PyUnicode_AS_UNICODE result OK without
thread lock as it is a simple dereference. */
@ -974,11 +1041,11 @@ posix_do_stat(PyObject *self, PyObject *args,
/* Remove trailing slash or backslash, unless it's the current
drive root (/ or \) or a specific drive's root (like c:\ or c:/).
*/
if (pathlen > 0 &&
(path[pathlen-1]== '\\' || path[pathlen-1] == '/')) {
if (pathlen > 0) {
if (ISSLASHA(path[pathlen-1])) {
/* It does end with a slash -- exempt the root drive cases. */
/* XXX UNC root drives should also be exempted? */
if (pathlen == 1 || (pathlen == 3 && path[1] == ':'))
if (pathlen == 1 || (pathlen == 3 && path[1] == ':') ||
IsUNCRootA(path, pathlen))
/* leave it alone */;
else {
/* nuke the trailing backslash */
@ -987,6 +1054,15 @@ posix_do_stat(PyObject *self, PyObject *args,
path = pathcopy;
}
}
else if (ISSLASHA(path[1]) && pathlen < ARRAYSIZE(pathcopy)-1 &&
IsUNCRootA(path, pathlen)) {
/* UNC root w/o trailing slash: add one when there's room */
strncpy(pathcopy, path, pathlen);
pathcopy[pathlen++] = '\\';
pathcopy[pathlen] = '\0';
path = pathcopy;
}
}
#endif /* MS_WINDOWS */
Py_BEGIN_ALLOW_THREADS