-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgocryptfs-rsync-pretty
More file actions
executable file
·149 lines (123 loc) · 4.56 KB
/
gocryptfs-rsync-pretty
File metadata and controls
executable file
·149 lines (123 loc) · 4.56 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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python3
#
# Usage: gocryptfs-rsync-pretty <ctlsock>
#
# Processes rsync verbose output from `stdin` and decrypts the paths to
# display a readable log.
#
import sys
import re
import subprocess
import json
if len(sys.argv) < 3:
print('Usage: gocryptfs-rsync-pretty <ctlsock> <encrypted-mount>', file=sys.stderr)
exit(1)
ctlsock = sys.argv[1]
encrypted_mount = sys.argv[2]
if not encrypted_mount.endswith('/'):
encrypted_mount += '/'
xray = subprocess.Popen(['gocryptfs-xray', '--decrypt-paths', ctlsock], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
#
# Setting `newline` to empty string causes universal newline to be enabled,
# but the original character to be returned.
#
# See <https://docs.python.org/3/library/io.html#io.TextIOWrapper>.
#
sys.stdin.reconfigure(newline='')
for line in sys.stdin:
# Means we reach the end, only stats after
if line == '\n':
sys.stdout.write(line)
break
#
# Progress lines, ignore.
#
# Typically it starts with a line with just "\r", then each progress update
# ends with "\r", and the final progress update ends with "\n". E.g.:
#
# "\r"
# " 0 0% 0.00kB/s 0:00:00 (xfr#0, ir-chk=1565/1577)\r"
# " 0 0% 0.00kB/s 0:00:00 (xfr#0, ir-chk=1000/485789)\n"
# ".d..t...... path/to/dir/\n"
# "\r"
# " 0 0% 0.00kB/s 0:00:00 (xfr#0, ir-chk=1160/485974)\n"
# "<f+++++++++ path/to/file\n"
# "\r"
# " 7,241,728 0% 411.62kB/s 327:22:24 \r"
# " 97,281,963,609 20% 2.15MB/s 11:57:46 (xfr#358224, ir-chk=1006/485789)\r"
# "100,333,522,717 20% 2.16MB/s 12:19:56 (xfr#358245, ir-chk=1164/485974)\n"
#
# Progress line can get big enough that it doesn't start with a space
# anymore, so we can't rely on that.
#
if line.startswith('\r') or line.endswith('\r') or line.startswith(' '):
sys.stdout.write(line)
continue
# Another progress marker
if 'xfr#' in line or ', ir-chk=' in line or ', to-chk=' in line:
sys.stdout.write(line)
continue
# Last fallback for progress line long enough to not start with space
if re.match(r'^\d+(,\d+)* ', line):
sys.stdout.write(line)
continue
# Special case for base directory, ignore early (messes with parsing otherwise)
if line == './\n':
sys.stdout.write(line)
continue
if line == 'sending incremental file list\n':
sys.stdout.write(line)
continue
if line.startswith('IO error encountered'):
sys.stdout.write(line)
continue
# See <http://www.staroceans.org/e-book/understanding-the-output-of-rsync-itemize-changes.html>
if line[0] in ['<', '>', '*', '.'] or (line[0] in ['c', 'h'] and line[3] in ['.', '+']):
# Info mode, file is the second part of the line
file = re.split(r'\s+', line)[1]
elif line.startswith('skipping non-regular file'):
# File is between quotes
file = line.split('"')[1]
elif line.startswith('rsync: [') and 'failed:' in line:
# File is between quotes and absolute from encrypted mount
file = line.split('"')[1]
if file.startswith(encrypted_mount):
file = file[len(encrypted_mount):]
else:
sys.stdout.write(line)
continue
elif line.startswith('deleting'):
# File is the second part of the line
file = re.split(r'\s+', line)[1]
else:
# Regular verbose mode, file is the whole line
file = line.rstrip()
# Top-level `gocryptfs.diriv` or `gocryptfs.conf`, ignore
if file == 'gocryptfs.diriv' or file == 'gocryptfs.conf':
sys.stdout.write(line)
continue
path = file
if file.endswith('/'):
path = file.rstrip('/')
elif file.endswith('/gocryptfs.diriv'):
path = file[0:-len('/gocryptfs.diriv')]
# Special case for base directory (info mode)
if path == '.':
sys.stdout.write(line)
continue
xray.stdin.write(path + '\n')
xray.stdin.flush()
decrypted = xray.stdout.readline().rstrip()
if decrypted.startswith('error at input line'):
print(decrypted)
print('Debug:', json.dumps(line))
continue
if file.endswith('/'):
decrypted += '/'
elif file.endswith('/gocryptfs.diriv'):
decrypted += '/gocryptfs.diriv'
sys.stdout.write(line.replace(file, decrypted))
# Print the rest as is
for line in sys.stdin:
sys.stdout.write(line)
xray.terminate()