summaryrefslogtreecommitdiffstats
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
authorMartin v. Löwis <martin@v.loewis.de>2004-06-02 09:57:56 (GMT)
committerMartin v. Löwis <martin@v.loewis.de>2004-06-02 09:57:56 (GMT)
commitd8948725d2e0693809c69d19417b9ffc2f525517 (patch)
treec2374507c4efc2868385c875aaaa77d3c6cd83dc /Modules/posixmodule.c
parent0659452b8b273fb04fc6efee2f5b262837251818 (diff)
downloadcpython-d8948725d2e0693809c69d19417b9ffc2f525517.zip
cpython-d8948725d2e0693809c69d19417b9ffc2f525517.tar.gz
cpython-d8948725d2e0693809c69d19417b9ffc2f525517.tar.bz2
Patch #954115: Fix os.stat handling of UNC roots.
Will backport to 2.3.
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c112
1 files changed, 94 insertions, 18 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 1df5af0..42bc767 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -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,15 +991,22 @@ 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'/')) {
- /* 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':'))
- /* leave it alone */;
- else {
- /* nuke the trailing backslash */
- wpath[pathlen-1] = L'\0';
+ if (pathlen > 0) {
+ if (ISSLASHW(wpath[pathlen-1])) {
+ /* It does end with a slash -- exempt the root drive cases. */
+ 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
@@ -974,16 +1041,25 @@ 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] == '/')) {
- /* 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] == ':'))
- /* leave it alone */;
- else {
- /* nuke the trailing backslash */
+ if (pathlen > 0) {
+ if (ISSLASHA(path[pathlen-1])) {
+ /* It does end with a slash -- exempt the root drive cases. */
+ if (pathlen == 1 || (pathlen == 3 && path[1] == ':') ||
+ IsUNCRootA(path, pathlen))
+ /* leave it alone */;
+ else {
+ /* nuke the trailing backslash */
+ strncpy(pathcopy, path, pathlen);
+ pathcopy[pathlen-1] = '\0';
+ 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-1] = '\0';
+ pathcopy[pathlen++] = '\\';
+ pathcopy[pathlen] = '\0';
path = pathcopy;
}
}