]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Patch #954115: Fix os.stat handling of UNC roots.
authorMartin v. Löwis <martin@v.loewis.de>
Wed, 2 Jun 2004 10:07:01 +0000 (10:07 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Wed, 2 Jun 2004 10:07:01 +0000 (10:07 +0000)
Closes #513572.

Misc/NEWS
Modules/posixmodule.c

index 223b89ea40d077f7ed63a661b3f37f09ed7d0792..62be689ff76fa8216b1a841a2e08f4c5675173e2 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -7,6 +7,16 @@ Python News
 What's New in Python 2.3.4 (final)?
 ===================================
 
+*Release date: xx-xxx-2004*
+
+Extension modules
+-----------------
+
+- Patch #954115: Properly handle UNC roots in nt.stat.
+
+What's New in Python 2.3.4 (final)?
+===================================
+
 *Release date: 27-May-2004*
 
 What's New in Python 2.3.4rc1?
index 4738d800979f5c0a93817cc25573f35df6521683..26c827a6f46086ece96e60c2dcbac454334e4515 100644 (file)
@@ -902,6 +902,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,
@@ -941,15 +1001,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
@@ -984,16 +1051,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;
                }
        }