-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsha1sum.py
More file actions
130 lines (107 loc) · 4.18 KB
/
sha1sum.py
File metadata and controls
130 lines (107 loc) · 4.18 KB
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3
'''
Name: Hamdy Abou El Anein
Email: hamdy.aea@protonmail.com
Date of creation: 22-11-2024
Last update: 22-11-2024
Version: 1.0
Description: The sha1sum command from GNU coreutils in Python3.
Example of use: python sha1sum.py file1.txt
'''
import sys
import argparse
import hashlib
from pathlib import Path
def calculate_sha1(file_path, binary_output=False):
"""
Calculate SHA1 hash for a given file.
Args:
file_path (Path): Path to the file
binary_output (bool): Whether to output binary hash
Returns:
tuple: (hash_value, error_message)
"""
try:
sha1_hash = hashlib.sha1()
with open(file_path, 'rb') as file:
# Read in chunks for memory efficiency
for chunk in iter(lambda: file.read(4096), b''):
sha1_hash.update(chunk)
# Return hash in requested format
return (sha1_hash.digest() if binary_output
else sha1_hash.hexdigest()), None
except Exception as e:
return None, str(e)
def main():
"""
Main function to handle SHA1 hash calculation.
"""
parser = argparse.ArgumentParser(description='Calculate SHA1 hash sums')
# Input files and modes
parser.add_argument('files', nargs='+', type=Path,
help='Files to calculate hash sums')
parser.add_argument('-b', '--binary',
action='store_true',
help='Print binary digest')
parser.add_argument('--check',
action='store_true',
help='Read checksums and verify')
parser.add_argument('-q', '--quiet',
action='store_true',
help='Suppress OK/FAILED output')
args = parser.parse_args()
# Verify mode
if args.check:
check_files(args.files, args.quiet)
return
# Hash calculation mode
for file_path in args.files:
if not file_path.exists():
print(f"{file_path}: No such file", file=sys.stderr)
continue
hash_value, error = calculate_sha1(file_path, args.binary)
if error:
print(f"Error processing {file_path}: {error}", file=sys.stderr)
elif args.binary:
sys.stdout.buffer.write(hash_value)
else:
print(f"{hash_value} {file_path}")
def check_files(checksum_files, quiet=False):
"""
Verify checksums from files.
Args:
checksum_files (list): List of files containing checksums
quiet (bool): Suppress detailed output
"""
for checksum_file in checksum_files:
try:
with open(checksum_file, 'r') as f:
for line in f:
line = line.strip()
try:
# Parse standard checksum file format
stored_hash, filename = line.split(' ', 1)
file_path = Path(filename)
# Skip non-existent files
if not file_path.exists():
if not quiet:
print(f"{filename}: FAILED open")
continue
# Calculate current hash
current_hash, error = calculate_sha1(file_path)
# Compare hashes
if error:
if not quiet:
print(f"{filename}: FAILED (error: {error})")
elif current_hash == stored_hash:
if not quiet:
print(f"{filename}: OK")
else:
if not quiet:
print(f"{filename}: FAILED")
except ValueError:
print(f"Invalid line format in {checksum_file}")
except Exception as e:
print(f"Error reading {checksum_file}: {e}", file=sys.stderr)
if __name__ == '__main__':
main()