Commit d8948725 authored by Martin v. Löwis's avatar Martin v. Löwis

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

Will backport to 2.3.
parent 0659452b
...@@ -210,6 +210,8 @@ Core and builtins ...@@ -210,6 +210,8 @@ Core and builtins
Extension modules 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, - the weakref module now supports additional objects: array.array,
sre.pattern_objects, file objects, and sockets. sre.pattern_objects, file objects, and sockets.
......
...@@ -892,6 +892,66 @@ _pystat_fromstructstat(STRUCT_STAT st) ...@@ -892,6 +892,66 @@ _pystat_fromstructstat(STRUCT_STAT st)
return v; 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 * static PyObject *
posix_do_stat(PyObject *self, PyObject *args, posix_do_stat(PyObject *self, PyObject *args,
char *format, char *format,
...@@ -931,17 +991,24 @@ posix_do_stat(PyObject *self, PyObject *args, ...@@ -931,17 +991,24 @@ posix_do_stat(PyObject *self, PyObject *args,
/* Remove trailing slash or backslash, unless it's the current /* Remove trailing slash or backslash, unless it's the current
drive root (/ or \) or a specific drive's root (like c:\ or c:/). drive root (/ or \) or a specific drive's root (like c:\ or c:/).
*/ */
if (pathlen > 0 && if (pathlen > 0) {
(wpath[pathlen-1]== L'\\' || wpath[pathlen-1] == L'/')) { if (ISSLASHW(wpath[pathlen-1])) {
/* It does end with a slash -- exempt the root drive cases. */ /* 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 */; /* leave it alone */;
else { else {
/* nuke the trailing backslash */ /* nuke the trailing backslash */
wpath[pathlen-1] = L'\0'; 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 Py_BEGIN_ALLOW_THREADS
/* PyUnicode_AS_UNICODE result OK without /* PyUnicode_AS_UNICODE result OK without
thread lock as it is a simple dereference. */ thread lock as it is a simple dereference. */
...@@ -974,11 +1041,11 @@ posix_do_stat(PyObject *self, PyObject *args, ...@@ -974,11 +1041,11 @@ posix_do_stat(PyObject *self, PyObject *args,
/* Remove trailing slash or backslash, unless it's the current /* Remove trailing slash or backslash, unless it's the current
drive root (/ or \) or a specific drive's root (like c:\ or c:/). drive root (/ or \) or a specific drive's root (like c:\ or c:/).
*/ */
if (pathlen > 0 && if (pathlen > 0) {
(path[pathlen-1]== '\\' || path[pathlen-1] == '/')) { if (ISSLASHA(path[pathlen-1])) {
/* It does end with a slash -- exempt the root drive cases. */ /* 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 */; /* leave it alone */;
else { else {
/* nuke the trailing backslash */ /* nuke the trailing backslash */
...@@ -987,6 +1054,15 @@ posix_do_stat(PyObject *self, PyObject *args, ...@@ -987,6 +1054,15 @@ posix_do_stat(PyObject *self, PyObject *args,
path = pathcopy; 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 */ #endif /* MS_WINDOWS */
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
......
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