Patch #954115: Fix os.stat handling of UNC roots.
Will backport to 2.3.
This commit is contained in:
parent
0659452b8b
commit
d8948725d2
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue