From 11a3b1459df3ac8aebc0bdc5b61c8742db001c06 Mon Sep 17 00:00:00 2001 From: Brendan Moloney Date: Mon, 24 Feb 2014 21:50:59 -0800 Subject: [PATCH] BF: Fix is_dir/is_file for symlinks (Issue #4) in Linux We need to do an os.stat call for symlinks to see if they point at a file or directory. I am not sure if there is a more efficient way to do this in windows. I went ahead and added caching of the os.stat result too. --- scandir.py | 50 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/scandir.py b/scandir.py index 1e34f8e..2eb5afa 100644 --- a/scandir.py +++ b/scandir.py @@ -305,40 +305,60 @@ class Dirent(ctypes.Structure): file_system_encoding = sys.getfilesystemencoding() class PosixDirEntry(object): - __slots__ = ('name', '_d_type', '_lstat', '_path') + __slots__ = ('name', '_d_type', '_lstat', '_stat', '_path') def __init__(self, path, name, d_type): self._path = path self.name = name self._d_type = d_type self._lstat = None + self._stat = None def lstat(self): if self._lstat is None: self._lstat = lstat(join(self._path, self.name)) return self._lstat + + def stat(self): + if self._stat is None: + self._stat = os.stat(join(self._path, self.name)) + return self._stat # Ridiculous duplication between these is* functions -- helps a little # bit with os.walk() performance compared to calling another function. def is_dir(self): d_type = self._d_type - if d_type != DT_UNKNOWN: - return d_type == DT_DIR - try: - self.lstat() - except OSError: - return False - return self._lstat.st_mode & 0o170000 == S_IFDIR + if d_type == DT_DIR: + return True + elif self.is_symlink(): + try: + self.stat() + except OSError: + return False + return self._stat.st_mode & 0o170000 == S_IFDIR + else: + try: + self.lstat() + except OSError: + return False + return self._lstat.st_mode & 0o170000 == S_IFDIR def is_file(self): d_type = self._d_type - if d_type != DT_UNKNOWN: - return d_type == DT_REG - try: - self.lstat() - except OSError: - return False - return self._lstat.st_mode & 0o170000 == S_IFREG + if d_type == DT_REG: + return True + elif self.is_symlink(): + try: + self.stat() + except OSError: + return False + return self._stat.st_mode & 0o170000 == S_IFREG + else: + try: + self.lstat() + except OSError: + return False + return self._lstat.st_mode & 0o170000 == S_IFREG def is_symlink(self): d_type = self._d_type