aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvg <vgm+dev@devys.org>2020-12-13 16:32:19 +0100
committervg <vgm+dev@devys.org>2020-12-13 16:32:19 +0100
commite79dd839dad0e33a0998d27441523fd732775cf5 (patch)
treea59739e488e9bc735f928be034ae283eec03cd49
parent5658d17ed31b8446cc9052ee8f8a9e61937c0324 (diff)
downloadscripts-e79dd839dad0e33a0998d27441523fd732775cf5.tar.gz
scripts-e79dd839dad0e33a0998d27441523fd732775cf5.tar.bz2
scripts-e79dd839dad0e33a0998d27441523fd732775cf5.zip
add script to tag and display tagged crc32 xattr
-rwxr-xr-xscripts/xattr_user_crc3284
1 files changed, 84 insertions, 0 deletions
diff --git a/scripts/xattr_user_crc32 b/scripts/xattr_user_crc32
new file mode 100755
index 0000000..a13840f
--- /dev/null
+++ b/scripts/xattr_user_crc32
@@ -0,0 +1,84 @@
+#!/usr/bin/env python3
+# Copyright 2020 vg
+# SPDX-License-Identifier: MIT
+
+'''
+Description
+===========
+
+Tag given files with their crc32 and display the tagged crc32 then the new
+crc32 and then the filename to stdout.
+
+Usage
+=====
+
+Usage: {progname} [-z] [--] [FILENAME...]
+ {progname} -h|--help
+
+Options:
+
+ -h, --help
+ Show the complete help
+
+ -z
+ Null instead of LF as filename separator for in and out
+'''
+
+### standard modules
+import contextlib
+import functools
+import itertools
+import operator
+import os
+import sys
+
+### external modules
+import docopt
+
+
+# This script is not compatible below python3.7.2, always abort (not in main
+# since the syntax itself can cause the script to fail later inconveniently).
+assert sys.hexversion >= 0x03070200
+
+
+def stream_split(sep='\n', stream=sys.stdin, *, rem='', chunksize=4096):
+ if stream.isatty():
+ # workaround the double Ctrl-D issue for interactive entry where perf
+ # should not be an issue thus reading 1 by 1 is ok.
+ chunksize = 1
+ for data in iter(functools.partial(stream.read, chunksize), ''):
+ splitted = ''.join((rem, data)).split(sep)
+ for part in itertools.islice(splitted, len(splitted)-1):
+ yield part
+ rem = splitted[-1]
+ yield rem
+
+
+def filenames(arg_filenames, separator):
+ yield from filter(bool, arg_filenames or stream_split(separator))
+
+
+def get_crc32(filename):
+ from zlib import crc32
+ with open(filename, 'rb') as stream:
+ return '%08X' % functools.reduce(
+ lambda a, b: crc32(b, a),
+ iter(functools.partial(stream.read, 4096), b''),
+ 0
+ )
+
+
+def main():
+ args = docopt.docopt(__doc__.format(progname=os.path.basename(sys.argv[0])))
+ separator = '\0' if args['-z'] else '\n'
+ for filename in filenames(args['FILENAME'], separator):
+ tag_crc32 = None
+ with contextlib.suppress(OSError):
+ tag_crc32 = os.getxattr(filename, 'user.crc32').decode('utf8')
+ calculated_crc32 = get_crc32(filename)
+ os.setxattr(filename, 'user.crc32', calculated_crc32.encode('utf8'))
+ print('%-8s %-8s %s'
+ % (tag_crc32, calculated_crc32, filename), end=separator)
+
+
+main()