dwipe 3.0.0__py3-none-any.whl → 3.0.1__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/DeviceInfo.py CHANGED
@@ -112,7 +112,11 @@ class DeviceInfo:
112
112
  if ns.hw_caps_state == ProbeState.READY:
113
113
  return ns.hw_caps, ns.hw_nopes
114
114
 
115
- # 2. Skip probing if device has active job (would block on SATA wipe)
115
+ # 2. Skip probing non-wipeable devices (mounted/blocked)
116
+ if ns.state in ('Mnt', 'iMnt', 'Blk', 'iBlk', 'Busy'):
117
+ return ns.hw_caps, ns.hw_nopes
118
+
119
+ # 3. Skip probing if device has active job (would block on SATA wipe)
116
120
  if ns.job:
117
121
  return ns.hw_caps, ns.hw_nopes
118
122
 
dwipe/DeviceWorker.py CHANGED
@@ -111,11 +111,17 @@ class DeviceWorker(threading.Thread):
111
111
  self._running = False
112
112
  self._work_queue.put('stop')
113
113
 
114
- def request_hw_caps(self):
115
- """Request hardware capabilities probe (non-blocking)."""
114
+ def request_hw_caps(self, force=False):
115
+ """Request hardware capabilities probe (non-blocking).
116
+ Args:
117
+ force: If True, reset cached state and re-probe even if already done.
118
+ """
116
119
  with self._lock:
117
- if self._state['hw_caps_state'] == ProbeState.PENDING:
120
+ if force or self._state['hw_caps_state'] == ProbeState.PENDING:
118
121
  self._state['hw_caps_state'] = ProbeState.PROBING
122
+ self._state['hw_caps'] = ''
123
+ self._state['hw_caps_summary'] = ''
124
+ self._state['hw_nopes'] = ''
119
125
  self._work_queue.put('hw_caps')
120
126
 
121
127
  def set_want_marker(self, want):
@@ -460,12 +466,12 @@ class DeviceWorkerManager:
460
466
  worker.start()
461
467
  self._workers[name] = worker
462
468
 
463
- def request_hw_caps(self, device_name):
469
+ def request_hw_caps(self, device_name, force=False):
464
470
  """Request hardware capabilities probe for a device."""
465
471
  with self._lock:
466
472
  worker = self._workers.get(device_name)
467
473
  if worker:
468
- worker.request_hw_caps()
474
+ worker.request_hw_caps(force=force)
469
475
 
470
476
  def set_want_marker(self, device_name, want):
471
477
  """Set whether we want to monitor for a marker on a device.
dwipe/DiskWipe.py CHANGED
@@ -446,11 +446,10 @@ class DiskWipe:
446
446
  # Don't probe mounted/blocked devices
447
447
  if ns.state in ('Mnt', 'iMnt', 'Blk', 'iBlk'):
448
448
  continue
449
- # Reset state to PENDING to force a re-probe if needed
450
- # (state stays READY even after wipe clears results)
449
+ # Re-probe after wipe: worker state is still READY, need force
451
450
  if not (ns.hw_caps or ns.hw_nopes):
452
451
  ns.hw_caps_state = ProbeState.PENDING
453
- # Probe any device that might be ready (s, W, -, ^, or wipeable state)
452
+ self.worker_manager.request_hw_caps(ns.name, force=True)
454
453
  self.dev_info.get_hw_capabilities(ns)
455
454
 
456
455
  def _poll_hw_caps_updates(self):
@@ -506,6 +505,7 @@ class DiskWipe:
506
505
  self.partitions = info.assemble_partitions(self.partitions)
507
506
  # Start probing hw_caps immediately instead of waiting for first 3s refresh
508
507
  self.dev_info = info
508
+ self.worker_manager = worker_manager
509
509
  self.get_hw_caps_when_needed()
510
510
  if self.opts.dump_lsblk:
511
511
  DeviceInfo.dump(self.partitions, title="after assemble_partitions")
@@ -551,8 +551,6 @@ class DiskWipe:
551
551
 
552
552
  # Background device change monitor started above
553
553
 
554
- # self.dev_info already set during startup probe above
555
- self.worker_manager = worker_manager
556
554
  pick_range = info.get_pick_range()
557
555
  self.win.set_pick_range(pick_range[0], pick_range[1])
558
556
 
@@ -577,9 +575,20 @@ class DiskWipe:
577
575
  # This lets us show results quickly even though commands take 1-3 seconds
578
576
  self._poll_hw_caps_updates()
579
577
 
578
+ # Detect suspend/resume: loop runs every ~0.25s, so a large
579
+ # gap in monotonic time means the system was likely suspended
580
+ now_mono = time.monotonic()
581
+ loop_gap = now_mono - check_devices_mono
582
+ if loop_gap > 5.0 and hasattr(self, '_last_loop_mono'):
583
+ suspend_gap = now_mono - self._last_loop_mono
584
+ if suspend_gap > 5.0:
585
+ self.win.flash(f'Suspend detected ({suspend_gap:.0f}s gap), rescanning...', duration=1.5)
586
+ self.screens[MAIN_ST].scan_all_devices_ACTION()
587
+ self._last_loop_mono = now_mono
588
+
580
589
  # Check for device changes from background monitor
581
590
  devices_changed = device_monitor.get_and_clear()
582
- time_since_refresh = time.monotonic() - check_devices_mono
591
+ time_since_refresh = now_mono - check_devices_mono
583
592
 
584
593
  # Build current worker state for comparison
585
594
  current_worker_state = {}
@@ -1188,7 +1197,7 @@ class MainScreen(DiskWipeScreen):
1188
1197
  # Queue worker to re-probe this device's capabilities
1189
1198
  if partition.parent: # only need to do whole disks
1190
1199
  continue
1191
- self.app.worker_manager.request_hw_caps(partition.name)
1200
+ self.app.worker_manager.request_hw_caps(partition.name, force=True)
1192
1201
  # Clear cached values so UI refreshes with new probing state
1193
1202
  partition.hw_caps = ''
1194
1203
  partition.hw_nopes = ''
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dwipe
3
- Version: 3.0.0
3
+ Version: 3.0.1
4
4
  Summary: A tool to wipe disks and partitions for Linux
5
5
  Keywords: disk,partition,wipe,clean,scrub
6
6
  Author-email: Joe Defen <joedef@google.com>
@@ -81,7 +81,7 @@ Project-URL: Homepage, https://github.com/joedefen/dwipe
81
81
  1. **Drives and the OS often lie about drive type.** Outwit them both:
82
82
  * For spinning HDDs, **always** use `Rand` or `Zero` (interruptible, shows progress).
83
83
  * For SSDs, **always** use firmware wipes if available (faster, reaches hidden blocks).
84
- 1. **If a drive is 'Frozen'**, press `DEL` to detach it and, when gone, press `r` to rescan; it should come back unfrozen.
84
+ 1. **If a drive is 'Frozen'**, suspend your system briefly and resume; `dwipe` auto-detects the resume and rescans. Or press `r` to rescan manually. The drive should come back unfrozen.
85
85
  1. **If a drive is 'Locked'**, you must unlock it manually (see "Unlock Locked Device" section below). If `dwipe` locked it, the password is `NULL`; otherwise use the password that locked it.
86
86
  1. **Hot-swap workflow for SATA drives**: `DEL` to detach, physically swap drives, then `r` to rescan (if needed).
87
87
 
@@ -477,11 +477,10 @@ Press **ESC** from the main screen to clear the filter and return to showing all
477
477
  Firmware wipes (SATA/NVMe secure erase operations) have different characteristics than software wipes:
478
478
 
479
479
  **Frozen Drives:**
480
- - Firmware wipes sometimes report the drive as "Frozen" if the device is present (mounted or in use) when capabilities are detected
480
+ - SATA drives are typically frozen by the BIOS/UEFI during POST as a security measure
481
481
  - This is a drive-level security feature, not a `dwipe` limitation
482
- - **Solution**: Unmount the device, wait briefly (often just a few seconds of idle time is enough), then use **r** to rescan capabilities
483
- - The freeze state is usually temporary and clears after the device is no longer actively in use
484
- - If the drive remains frozen, try hot-swapping (remove and reinsert) or power-cycling the device
482
+ - **Solution**: Suspend your system briefly and resume; `dwipe` auto-detects the resume and rescans (or press **r** manually). The suspend/resume power-cycles the SATA link which clears the freeze.
483
+ - If the drive remains frozen after suspend/resume, try a full power-off (10+ minutes to drain drive capacitors) followed by boot and rescan
485
484
 
486
485
  **Device Quirks and Compatibility:**
487
486
  - Storage devices have various firmware implementations and hardware quirks that affect secure erase operations
@@ -1,7 +1,7 @@
1
1
  dwipe/DeviceChangeMonitor.py,sha256=0E8ie0ArhGQDq2g3bp_Sb-8Bo94PyoNzlGtWjotmqVU,8889
2
- dwipe/DeviceInfo.py,sha256=C5yNtXHJUUFhq0B8VtnvwFfcedcOqutRVS9NBhO5Jlk,47701
3
- dwipe/DeviceWorker.py,sha256=aHordCJCZXpq15tJ40VRbnzMqxBaBwd4sS5AGWuGNrE,21583
4
- dwipe/DiskWipe.py,sha256=awTlDIKBqNgh6LjbONxC-vPVFa-IsW3klv4AOxYnwOs,74269
2
+ dwipe/DeviceInfo.py,sha256=z0l_lQt75hTvj_VkE6QpcjTitEV5RrOL5jkJ1m7j3ZM,47873
3
+ dwipe/DeviceWorker.py,sha256=2ljht0f_i1q0PpSxdZyVXaTbOdFa7ul_abAOpJ7LPio,21875
4
+ dwipe/DiskWipe.py,sha256=Xyz7A9YVkwgWjCvcHGLYcTYkyCuX6J4_XzJoR20jMlM,74813
5
5
  dwipe/DrivePreChecker.py,sha256=txH-olWN7Xu2OZ6vV_Mz3cM8ffCxCd5KR0xtXdu65VM,8325
6
6
  dwipe/FirmwareWipeTask.py,sha256=zaMsICmpqAhceMnV5DIIGrQ_dk_KnklMxVIixVIiIO8,34387
7
7
  dwipe/NvmeTool.py,sha256=FdRNC9dhMoJxVjO2JdJ58DJai2WDRwuUavfiBG7-wAY,8510
@@ -17,8 +17,8 @@ dwipe/WipeTask.py,sha256=rISF7ZweQbELhf6tSLjtZp3FCaLhboSq1V3oAXDr6JU,5562
17
17
  dwipe/WriteTask.py,sha256=QyYvDovWyRcfli3bUZ-lrU91_sEG5mBJOTJduEJYLco,16178
18
18
  dwipe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  dwipe/main.py,sha256=vedLjuYZCMZ2-CV_kAJ_0yfVHw88r-SiY6mVHWcI1r0,3577
20
- dwipe-3.0.0.dist-info/entry_points.txt,sha256=SZHFezmse2c-jxG-BJ0TXy_TZ8vVFf0lPJWs0cdxz6Y,41
21
- dwipe-3.0.0.dist-info/licenses/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
22
- dwipe-3.0.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
23
- dwipe-3.0.0.dist-info/METADATA,sha256=XtzIZjSqytU8ukc1u9fabpSUz4bIYUnTlBXAcm2TFB4,31916
24
- dwipe-3.0.0.dist-info/RECORD,,
20
+ dwipe-3.0.1.dist-info/entry_points.txt,sha256=SZHFezmse2c-jxG-BJ0TXy_TZ8vVFf0lPJWs0cdxz6Y,41
21
+ dwipe-3.0.1.dist-info/licenses/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
22
+ dwipe-3.0.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
23
+ dwipe-3.0.1.dist-info/METADATA,sha256=pQ64vukpjVvWVH3D9uqA9RX1Ar64swbu4RQplgGo7II,31939
24
+ dwipe-3.0.1.dist-info/RECORD,,
File without changes