dwipe 1.0.3__py3-none-any.whl → 1.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dwipe/main.py +57 -76
- {dwipe-1.0.3.dist-info → dwipe-1.0.5.dist-info}/METADATA +8 -10
- dwipe-1.0.5.dist-info/RECORD +8 -0
- {dwipe-1.0.3.dist-info → dwipe-1.0.5.dist-info}/WHEEL +1 -2
- dwipe-1.0.5.dist-info/entry_points.txt +3 -0
- dwipe-1.0.3.dist-info/RECORD +0 -9
- dwipe-1.0.3.dist-info/entry_points.txt +0 -2
- dwipe-1.0.3.dist-info/top_level.txt +0 -1
- {dwipe-1.0.3.dist-info → dwipe-1.0.5.dist-info/licenses}/LICENSE +0 -0
dwipe/main.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
"""
|
|
3
|
+
dwipe: curse based tool to wipe physical disks or partitions including
|
|
4
|
+
markers to know their state when wiped.
|
|
5
5
|
"""
|
|
6
6
|
# pylint: disable=too-many-branches,too-many-statements,import-outside-toplevel
|
|
7
7
|
# pylint: disable=too-many-instance-attributes,invalid-name
|
|
@@ -79,6 +79,7 @@ class WipeJob:
|
|
|
79
79
|
self.total_written = 0
|
|
80
80
|
self.wr_hists = [] # list of (mono, written)
|
|
81
81
|
self.done = False
|
|
82
|
+
self.exception = None # in case of issues
|
|
82
83
|
|
|
83
84
|
@staticmethod
|
|
84
85
|
def start_job(device_path, total_size, opts):
|
|
@@ -185,38 +186,43 @@ class WipeJob:
|
|
|
185
186
|
self.total_written = 0 # Track total bytes written
|
|
186
187
|
is_random = self.opts.random
|
|
187
188
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
189
|
+
try:
|
|
190
|
+
with open(self.device_path, 'wb') as device:
|
|
191
|
+
# for loop in range(10000000000):
|
|
192
|
+
offset = 0
|
|
193
|
+
chunk = memoryview(WipeJob.zero_buffer)
|
|
194
|
+
while True:
|
|
195
|
+
# foo = 1/0 # to force exception only
|
|
196
|
+
if self.do_abort:
|
|
197
|
+
break
|
|
198
|
+
if is_random:
|
|
199
|
+
offset = random.randint(0, WipeJob.BUFFER_SIZE - WipeJob.WRITE_SIZE)
|
|
200
|
+
# Use memoryview to avoid copying the data
|
|
201
|
+
chunk = memoryview(WipeJob.buffer)[offset:offset + WipeJob.WRITE_SIZE]
|
|
202
|
+
|
|
203
|
+
if self.opts.dry_run:
|
|
204
|
+
bytes_written = self.total_size // 120
|
|
205
|
+
time.sleep(0.25)
|
|
206
|
+
else:
|
|
207
|
+
try:
|
|
208
|
+
bytes_written = device.write(chunk)
|
|
209
|
+
except Exception:
|
|
210
|
+
bytes_written = 0
|
|
211
|
+
self.total_written += bytes_written
|
|
212
|
+
# Optional: Check for errors or incomplete writes
|
|
213
|
+
if bytes_written < WipeJob.WRITE_SIZE:
|
|
214
|
+
break
|
|
215
|
+
if self.opts.dry_run and self.total_written >= self.total_size:
|
|
216
|
+
break
|
|
217
|
+
# clear the beginning of device whether aborted or not
|
|
218
|
+
# if we have started writing + status in JSON
|
|
219
|
+
if not self.opts.dry_run and self.total_written > 0:
|
|
220
|
+
device.seek(0)
|
|
221
|
+
# chunk = memoryview(WipeJob.zero_buffer)
|
|
222
|
+
bytes_written = device.write(self.prep_marker_buffer(is_random))
|
|
223
|
+
except Exception:
|
|
224
|
+
self.exception = traceback.format_exc()
|
|
225
|
+
|
|
220
226
|
self.done = True
|
|
221
227
|
|
|
222
228
|
class DeviceInfo:
|
|
@@ -284,6 +290,7 @@ class DeviceInfo:
|
|
|
284
290
|
entry.fstype = device.get('fstype', '')
|
|
285
291
|
if entry.fstype is None:
|
|
286
292
|
entry.fstype = ''
|
|
293
|
+
entry.type = device.get('type', '')
|
|
287
294
|
entry.label = device.get('label', '')
|
|
288
295
|
if not entry.label:
|
|
289
296
|
entry.label=device.get('partlabel', '')
|
|
@@ -313,7 +320,7 @@ class DeviceInfo:
|
|
|
313
320
|
|
|
314
321
|
# Run the `lsblk` command and get its output in JSON format with additional columns
|
|
315
322
|
result = subprocess.run(['lsblk', '-J', '--bytes', '-o',
|
|
316
|
-
'NAME,MAJ:MIN,FSTYPE,LABEL,PARTLABEL,FSUSE%,SIZE,MOUNTPOINTS', ],
|
|
323
|
+
'NAME,MAJ:MIN,FSTYPE,TYPE,LABEL,PARTLABEL,FSUSE%,SIZE,MOUNTPOINTS', ],
|
|
317
324
|
stdout=subprocess.PIPE, text=True, check=False)
|
|
318
325
|
parsed_data = json.loads(result.stdout)
|
|
319
326
|
entries = {}
|
|
@@ -407,47 +414,10 @@ class DeviceInfo:
|
|
|
407
414
|
|
|
408
415
|
def get_disk_partitions(self, nss):
|
|
409
416
|
""" Determine which partitions we want some are bogus like zram """
|
|
410
|
-
|
|
411
|
-
def whitelisted(device_name):
|
|
412
|
-
"""Check if device_name matches any pattern in whitelist
|
|
413
|
-
which are the disk devices."""
|
|
414
|
-
WHITELIST = ['nvme*', 'sd*', 'hd*', 'mmcblk*']
|
|
415
|
-
for pattern in WHITELIST:
|
|
416
|
-
if fnmatch(device_name, pattern):
|
|
417
|
-
return True
|
|
418
|
-
return False
|
|
419
|
-
|
|
420
|
-
def blacklisted(device_name):
|
|
421
|
-
"""Check if device_name matches any pattern in black list
|
|
422
|
-
which are know not to be physical disks."""
|
|
423
|
-
BLACKLIST = ['zram*', 'ram*', 'dm-*', 'loop*', 'sr*']
|
|
424
|
-
for pattern in BLACKLIST:
|
|
425
|
-
if fnmatch(device_name, pattern):
|
|
426
|
-
return 'blkLst'
|
|
427
|
-
return ''
|
|
428
|
-
|
|
429
|
-
def writable(device_name):
|
|
430
|
-
"""Check if the device is writable."""
|
|
431
|
-
device_path = f'/dev/{device_name}'
|
|
432
|
-
try: # Check if the device file exists and is writable
|
|
433
|
-
return os.access(device_path, os.W_OK)
|
|
434
|
-
except FileNotFoundError:
|
|
435
|
-
return False
|
|
436
|
-
|
|
437
417
|
ok_nss = {}
|
|
438
418
|
for name, ns in nss.items():
|
|
439
|
-
if ns.
|
|
419
|
+
if ns.type in ('disk', 'part'):
|
|
440
420
|
ok_nss[name] = ns
|
|
441
|
-
continue
|
|
442
|
-
if blacklisted(name):
|
|
443
|
-
continue
|
|
444
|
-
if writable(name):
|
|
445
|
-
if self.DB:
|
|
446
|
-
print(r'DB:include {repr(name)} [not white/black but writable]')
|
|
447
|
-
ok_nss[name] = ns
|
|
448
|
-
continue
|
|
449
|
-
if self.DB:
|
|
450
|
-
print(r'DB:exclude {repr(name)} [not white/black but unwritable]')
|
|
451
421
|
return ok_nss
|
|
452
422
|
|
|
453
423
|
def compute_field_widths(self, nss):
|
|
@@ -755,6 +725,8 @@ class DiskWipe:
|
|
|
755
725
|
line += ' Stop' if self.job_cnt > 0 else ''
|
|
756
726
|
line += f' quit ?:help /{self.prev_filter} Mode='
|
|
757
727
|
line += f'{"Random" if self.opts.random else "Zeros"}'
|
|
728
|
+
if self.opts.dry_run:
|
|
729
|
+
line += ' DRY-RUN'
|
|
758
730
|
# for action in self.actions:
|
|
759
731
|
# line += f' {action[0]}:{action}'
|
|
760
732
|
return line[1:]
|
|
@@ -834,15 +806,24 @@ class DiskWipe:
|
|
|
834
806
|
to='s' if partition.job.do_abort else 'W'
|
|
835
807
|
self.set_state(partition, to=to)
|
|
836
808
|
partition.dflt = to
|
|
837
|
-
partition.job = None
|
|
838
809
|
partition.mounts = []
|
|
839
810
|
self.job_cnt -= 1
|
|
811
|
+
if partition.job.exception:
|
|
812
|
+
self.win.stop_curses()
|
|
813
|
+
print('\n\n\n========== ALERT =========\n')
|
|
814
|
+
print(f' FAILED: wipe {repr(partition.name)}')
|
|
815
|
+
print(partition.job.exception)
|
|
816
|
+
input('\n\n===== Press ENTER to continue ====> ')
|
|
817
|
+
self.win._start_curses()
|
|
818
|
+
|
|
819
|
+
partition.job = None
|
|
840
820
|
if partition.job:
|
|
841
821
|
elapsed, pct, rate, until = partition.job.get_status()
|
|
842
822
|
partition.state = pct
|
|
843
823
|
partition.mounts = [f'{elapsed} {rate} REM:{until}']
|
|
844
824
|
|
|
845
|
-
if partition.parent and
|
|
825
|
+
if partition.parent and partition.parent in self.partitions and (
|
|
826
|
+
self.partitions[partition.parent].state == 'Lock'):
|
|
846
827
|
continue
|
|
847
828
|
|
|
848
829
|
if wanted(name) or partition.job:
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dwipe
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
4
4
|
Summary: A tool to wipe disks and partitions for Linux
|
|
5
|
-
Author-email: Joe Defen <joedef@google.com>
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/joedefen/dwipe
|
|
8
|
-
Project-URL: Bug Tracker, https://github.com/joedefen/dwipe/issues
|
|
9
5
|
Keywords: disk,partition,wipe,clean,scrub
|
|
6
|
+
Author-email: Joe Defen <joedef@google.com>
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
10
9
|
Classifier: Programming Language :: Python :: 3
|
|
11
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
11
|
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
-
Requires-Python: >=3.8
|
|
14
|
-
Description-Content-Type: text/markdown
|
|
15
12
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist:
|
|
17
|
-
|
|
13
|
+
Requires-Dist: importlib-metadata; python_version<"3.8"
|
|
14
|
+
Project-URL: Bug Tracker, https://github.com/joedefen/dwipe/issues
|
|
15
|
+
Project-URL: Homepage, https://github.com/joedefen/dwipe
|
|
18
16
|
|
|
19
17
|
# dwipe
|
|
20
18
|
`dwipe` is tool to wipe disks and partitions for Linux helps secure you data. `dwipes` aims to reduce mistakes by providing ample information about your devices during selection.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
dwipe/PowerWindow.py,sha256=pQGXsAMeuiHn-vtEiVG0rgW1eCslh3ukC-VrPhH_j3k,28587
|
|
2
|
+
dwipe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
dwipe/main.py,sha256=MutcKcddLhBJeegULUwjHOzZRV2gR-QluA1UarRHyIU,33909
|
|
4
|
+
dwipe-1.0.5.dist-info/entry_points.txt,sha256=SZHFezmse2c-jxG-BJ0TXy_TZ8vVFf0lPJWs0cdxz6Y,41
|
|
5
|
+
dwipe-1.0.5.dist-info/licenses/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
|
|
6
|
+
dwipe-1.0.5.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
7
|
+
dwipe-1.0.5.dist-info/METADATA,sha256=hrmh76lFi0rfExxRmCzGSIeEWFTwy1DfLfko7DKofS8,4496
|
|
8
|
+
dwipe-1.0.5.dist-info/RECORD,,
|
dwipe-1.0.3.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
dwipe/PowerWindow.py,sha256=pQGXsAMeuiHn-vtEiVG0rgW1eCslh3ukC-VrPhH_j3k,28587
|
|
2
|
-
dwipe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
dwipe/main.py,sha256=6Ooj1i7hCrFxVUkvjRphH_-Dxz3dpm201VrZVybiI8A,34309
|
|
4
|
-
dwipe-1.0.3.dist-info/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
|
|
5
|
-
dwipe-1.0.3.dist-info/METADATA,sha256=OBoF-WviZm4MNxeIpHWqF9QeeLnfb1BtQItlk93QBdU,4538
|
|
6
|
-
dwipe-1.0.3.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
|
|
7
|
-
dwipe-1.0.3.dist-info/entry_points.txt,sha256=s-gAs_OhS9lr-oVMKii2ZjsLfCSO4-oHV7Wa9oJe-2g,42
|
|
8
|
-
dwipe-1.0.3.dist-info/top_level.txt,sha256=nJT1SUDcOmULgmF9JmYwIIQLmXAIn6qAWW8EdWuxsAg,6
|
|
9
|
-
dwipe-1.0.3.dist-info/RECORD,,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dwipe
|
|
File without changes
|