1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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()
|