]> granicus.if.org Git - python/commitdiff
Issue #25911: Backport os._DummyDirEntry fixes
authorVictor Stinner <victor.stinner@gmail.com>
Tue, 29 Mar 2016 11:38:22 +0000 (13:38 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Tue, 29 Mar 2016 11:38:22 +0000 (13:38 +0200)
* Fix test_os.BytesWalkTests on Windows
* Mimick better the reference os.DirEntry on Windows
* _DummyDirEntry now caches os.stat() result
* _DummyDirEntry constructor now tries to get os.stat()
* Fix os._DummyDirEntry.is_symlink(), don't follow symbolic links:
  use os.stat(path, follow_symlinks=False).

Lib/os.py

index e32cd6be32e63a34122b2d3f9a9ba5dc06d326a2..b4c651d24d23908c055af8a93b3a74caba755ca7 100644 (file)
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -425,13 +425,47 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
         yield top, dirs, nondirs
 
 class _DummyDirEntry:
+    """Dummy implementation of DirEntry
+
+    Only used internally by os.walk(bytes). Since os.walk() doesn't need the
+    follow_symlinks parameter: don't implement it, always follow symbolic
+    links.
+    """
+
     def __init__(self, dir, name):
         self.name = name
         self.path = path.join(dir, name)
+        # Mimick FindFirstFile/FindNextFile: we should get file attributes
+        # while iterating on a directory
+        self._stat = None
+        self._lstat = None
+        try:
+            self.stat(follow_symlinks=False)
+        except OSError:
+            pass
+
+    def stat(self, *, follow_symlinks=True):
+        if follow_symlinks:
+            if self._stat is None:
+                self._stat = stat(self.path)
+            return self._stat
+        else:
+            if self._lstat is None:
+                self._lstat = stat(self.path, follow_symlinks=False)
+            return self._lstat
+
     def is_dir(self):
-        return path.isdir(self.path)
+        if self._lstat is not None and not self.is_symlink():
+            # use the cache lstat
+            stat = self.stat(follow_symlinks=False)
+            return st.S_ISDIR(stat.st_mode)
+
+        stat = self.stat()
+        return st.S_ISDIR(stat.st_mode)
+
     def is_symlink(self):
-        return path.islink(self.path)
+        stat = self.stat(follow_symlinks=False)
+        return st.S_ISLNK(stat.st_mode)
 
 def _dummy_scandir(dir):
     # listdir-based implementation for bytes patches on Windows