Commits

Jason R. Coombs committed 7ba2601

Extracted Windows directory detection from NullImporter.__init__. This greatly simplifies the code and fixes issue6727.

  • Participants
  • Parent commits ce303f7
  • Branches 3.2

Comments (0)

Files changed (1)

File Python/import.c

     {0, 0}
 };
 
-#ifdef HAVE_STAT
+/* The following definitions of isdir and Py_PathIsDir implement platform-
+ * specific implementations of directory detection.
+ * see issue1293 and issue3677:
+ * stat() on Windows doesn't recognise paths like
+ * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs.
+ * Also reference issue6727:
+ * stat() on Windows is broken and doesn't resolve symlinks properly.
+ */
+
+#ifndef MS_WINDOWS
 int isdir(char *path) {
     struct stat statbuf;
     return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode);
 }
 #else
 int isdir(char *path) {
-    return 0;
+    DWORD rv;
+    rv = GetFileAttributesA(path);
+    return rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY;
+}
+#endif
+
+/* Py_PathIsDir:
+    in (PyObject *): Pointer to PyBytes on Unix and PyUnicode on Windows.
+    out (int *): Pointer to result (1 if path exists and is a dir).
+    Return 1 if succeeded; 0 if an exception occurred.
+    */
+#ifndef MS_WINDOWS
+int Py_PathIsDir(PyObject *path, int *path_isdir) {
+    *path_isdir = isdir(PyBytes_AS_STRING(path));
+    return 1;
+}
+#else
+int Py_PathIsDir(PyObject *path, int *path_isdir) {
+    DWORD rv;
+    wchar_t *path_chars;
+
+    path_chars = PyUnicode_AsWideCharString(path, NULL);
+    if (path_chars == NULL)
+        return 0;
+    rv = GetFileAttributesW(path_chars);
+    PyMem_Free(path_chars);
+    *path_isdir = rv != INVALID_FILE_ATTRIBUTES && rv & FILE_ATTRIBUTE_DIRECTORY;
+    return 1;
 }
 #endif
 
 static int
 NullImporter_init(NullImporter *self, PyObject *args, PyObject *kwds)
 {
-#ifndef MS_WINDOWS
     PyObject *path;
-    struct stat statbuf;
-    int rv;
+    int path_isdir;
+    int path_size;
 
     if (!_PyArg_NoKeywords("NullImporter()", kwds))
         return -1;
 
+#ifndef MS_WINDOWS
     if (!PyArg_ParseTuple(args, "O&:NullImporter",
                           PyUnicode_FSConverter, &path))
         return -1;
 
-    if (PyBytes_GET_SIZE(path) == 0) {
-        Py_DECREF(path);
-        PyErr_SetString(PyExc_ImportError, "empty pathname");
+    path_size = PyBytes_GET_SIZE(path);
+#else
+    if (!PyArg_ParseTuple(args, "U:NullImporter",
+                          &path))
+        return -1;
+
+    path_size = PyUnicode_GET_SIZE(path);
+#endif
+
+    if (!Py_PathIsDir(path, &path_isdir)) {
         return -1;
     }
 
-    rv = stat(PyBytes_AS_STRING(path), &statbuf);
+#ifndef MS_WINDOWS
     Py_DECREF(path);
-    if (rv == 0) {
-        /* it exists */
-        if (S_ISDIR(statbuf.st_mode)) {
-            /* it's a directory */
-            PyErr_SetString(PyExc_ImportError, "existing directory");
-            return -1;
-        }
-    }
-#else /* MS_WINDOWS */
-    PyObject *pathobj;
-    DWORD rv;
-    wchar_t *path;
-
-    if (!_PyArg_NoKeywords("NullImporter()", kwds))
-        return -1;
-
-    if (!PyArg_ParseTuple(args, "U:NullImporter",
-                          &pathobj))
-        return -1;
-
-    if (PyUnicode_GET_SIZE(pathobj) == 0) {
-        PyErr_SetString(PyExc_ImportError, "empty pathname");
+#endif
+
+    if (path_isdir) {
+        PyErr_SetString(PyExc_ImportError, "existing directory");
         return -1;
     }
 
-    path = PyUnicode_AsWideCharString(pathobj, NULL);
-    if (path == NULL)
-        return -1;
-    /* see issue1293 and issue3677:
-     * stat() on Windows doesn't recognise paths like
-     * "e:\\shared\\" and "\\\\whiterab-c2znlh\\shared" as dirs.
-     */
-    rv = GetFileAttributesW(path);
-    PyMem_Free(path);
-    if (rv != INVALID_FILE_ATTRIBUTES) {
-        /* it exists */
-        if (rv & FILE_ATTRIBUTE_DIRECTORY) {
-            /* it's a directory */
-            PyErr_SetString(PyExc_ImportError, "existing directory");
-            return -1;
-        }
-    }
-#endif
     return 0;
 }