Index: win_toolchain/treehash/treehash.py |
diff --git a/win_toolchain/treehash/treehash.py b/win_toolchain/treehash/treehash.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ac821146114ca8123d607ac49592fac161cee953 |
--- /dev/null |
+++ b/win_toolchain/treehash/treehash.py |
@@ -0,0 +1,55 @@ |
+# Copyright 2014 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+# Python implementation for verification. Doesn't do timestamping, just the |
+# tree hash. |
+ |
+import ctypes.wintypes |
+import hashlib |
+import os |
+import sys |
+ |
+GetFileAttributes = ctypes.windll.kernel32.GetFileAttributesW |
+GetFileAttributes.argtypes = (ctypes.wintypes.LPWSTR,) |
+GetFileAttributes.restype = ctypes.wintypes.DWORD |
+FILE_ATTRIBUTE_HIDDEN = 0x2 |
+FILE_ATTRIBUTE_SYSTEM = 0x4 |
+ |
+ |
+def IsHidden(file_path): |
+ """Returns whether the given |file_path| has the 'system' or 'hidden' |
+ attribute set.""" |
+ p = GetFileAttributes(file_path) |
+ assert p != 0xffffffff |
+ return bool(p & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) |
+ |
+ |
+def GetFileList(root): |
+ """Gets a normalized list of files under |root|.""" |
+ assert not os.path.isabs(root) |
+ assert os.path.normpath(root) == root |
+ file_list = [] |
+ for base, _, files in os.walk(root): |
+ paths = [os.path.join(base, f) for f in files] |
+ file_list.extend(x.lower() for x in paths if not IsHidden(x)) |
+ return sorted(file_list) |
+ |
+ |
+def CalculateHash(root): |
+ """Calculates the sha1 of the paths to all files in the given |root| and the |
+ contents of those files, and returns as a hex string.""" |
+ file_list = GetFileList(root) |
+ digest = hashlib.sha1() |
+ for path in file_list: |
+ digest.update(path) |
+ with open(path, 'rb') as f: |
+ digest.update(f.read()) |
+ return digest.hexdigest() |
+ |
+ |
+def main(): |
+ print CalculateHash(sys.argv[1]) |
+ |
+if __name__ == '__main__': |
+ sys.exit(main()) |