about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/core/filter_stack.py31
-rw-r--r--ranger/ext/hash.py29
2 files changed, 36 insertions, 24 deletions
diff --git a/ranger/core/filter_stack.py b/ranger/core/filter_stack.py
index 5d40825f..9b4d2779 100644
--- a/ranger/core/filter_stack.py
+++ b/ranger/core/filter_stack.py
@@ -14,11 +14,11 @@ try:
 except ImportError:
     from itertools import zip_longest
 # pylint: enable=invalid-name
-from os import listdir
-from os.path import abspath, isdir
+from os.path import abspath
 
 from ranger.container.directory import accept_file, InodeFilterConstants
 from ranger.core.shared import FileManagerAware
+from ranger.ext.hash import hash_chunks
 
 # pylint: disable=too-few-public-methods
 
@@ -84,36 +84,19 @@ class HashFilter(BaseFilter, FileManagerAware):
         # TODO: Lazily generated list would be more efficient, a generator
         #       isn't enough because this object is reused for every fsobject
         #       in the current directory.
-        self.filehash = list(self.hash_chunks(abspath(self.filepath)))
+        self.filehash = list(hash_chunks(abspath(self.filepath)))
 
-    # pylint: disable=invalid-name
     def __call__(self, fobj):
-        for (c1, c2) in zip_longest(self.filehash,
-                                    self.hash_chunks(fobj.path),
-                                    fillvalue=''):
-            if c1 != c2:
+        for (chunk1, chunk2) in zip_longest(self.filehash,
+                                            hash_chunks(fobj.path),
+                                            fillvalue=''):
+            if chunk1 != chunk2:
                 return False
         return True
 
     def __str__(self):
         return "<Filter: hash {}>".format(self.filepath)
 
-    def hash_chunks(self, filepath):
-        from hashlib import sha256
-        if isdir(filepath):
-            yield filepath
-            for fp in listdir(filepath):
-                self.hash_chunks(fp)
-        else:
-            with open(filepath, 'rb') as f:
-                h = sha256()
-                # Read the file in ~64KiB chunks (multiple of sha256's block
-                # size that works well enough with HDDs and SSDs)
-                for chunk in iter(lambda: f.read(h.block_size * 1024), b''):
-                    h.update(chunk)
-                    yield h.hexdigest()
-    # pylint: enable=invalid-name
-
 
 @stack_filter("type")
 class TypeFilter(BaseFilter):
diff --git a/ranger/ext/hash.py b/ranger/ext/hash.py
new file mode 100644
index 00000000..20059dbf
--- /dev/null
+++ b/ranger/ext/hash.py
@@ -0,0 +1,29 @@
+# This file is part of ranger, the console file manager.
+# License: GNU GPL version 3, see the file "AUTHORS" for details.
+
+from __future__ import (absolute_import, division, print_function)
+
+from os import listdir
+from os.path import getsize, isdir
+from hashlib import sha256
+
+# pylint: disable=invalid-name
+
+
+def hash_chunks(filepath, h=None):
+    if not h:
+        h = sha256()
+    if isdir(filepath):
+        h.update(filepath)
+        yield h.hexdigest()
+        for fp in listdir(filepath):
+            hash_chunks(fp, h=h)
+    elif getsize(filepath) == 0:
+        yield h.hexdigest()
+    else:
+        with open(filepath, 'rb') as f:
+            # Read the file in ~64KiB chunks (multiple of sha256's block
+            # size that works well enough with HDDs and SSDs)
+            for chunk in iter(lambda: f.read(h.block_size * 1024), b''):
+                h.update(chunk)
+                yield h.hexdigest()