Skip to content

v0.4.7

Choose a tag to compare

@github-actions github-actions released this 23 Aug 00:02
· 5 commits to main since this release

Added

  • Manage menu (m) — quick, non-destructive actions for the selected disk, each run with the same disk-identity check as every other operation and reported in the progress dialog:

    • Assign or change a drive letter for any partition with a filesystem. The prompt lists the letters that are actually free (it also excludes mapped network drives, which Get-Volume would miss) and refuses A–C and letters in use.
    • Remove a drive letter — the volume is unmounted but its data is untouched; assign a letter again to use it.
    • Rename a volume label (characters invalid in labels are stripped; 32-character cap, FAT32's 11-character limit is left to Windows to report).
    • Bring online / take offline — an offline disk is left alone by Windows (no automount, no indexing), which is the safe state for a drive you are about to image or hand to another machine.
    • Safely eject — flushes and ejects through the shell's Eject verb (the same thing as the tray icon) and tells you when a program is still holding the drive open. A disk without any drive letter is taken offline instead, which also flushes it.
    • Clear the read-only flag (Set-Disk -IsReadOnly $false), with a pointer to the enclosure diagnostics when the device refuses.
      The system/boot disk and the disk hosting the app are refused unless the safety override is on; the menu needs an elevated terminal.
  • Notification when a scheduled backup finishes — the headless --scheduled-backup run now raises a Windows toast ("Disk Utility · Scheduled backup finished" with the image path and size, or "Scheduled backup FAILED" with the reason — disk not connected, folder unreachable, not enough space, write error…) so you no longer have to open diskutility.log to know whether last night's backup happened. Uses the built-in WinRT toast API through PowerShell; no extra dependency. Set "notify": false in config.json to silence it (default on). A failed toast is only logged and never affects the backup result.

  • Backups panel (Shift+B) — shows every backup in progress, across processes: the scheduled job (which runs in an invisible Task Scheduler process, so until now the app had no idea it existed) and manual backups started in other diskutility windows. Each row has kind, disk, image path, a progress gauge, speed/ETA, start time, elapsed time and pid; ↑↓ selects one and x stops it after a confirmation. Below that: the registered schedule (disk, cadence, destination, keep count, whether the task is actually registered) and the interrupted images that the next backup would resume, with how much of each is done. While a background backup runs, a one-line status bar with the same gauge sits above the footer (Shift+X also opens the panel).

  • How it works — every backup publishes %APPDATA%\diskutility\jobs\<pid>.json (rewritten every half second, heartbeated every 2 s, removed when the job ends) and polls for <pid>.cancel. Stopping a job from the panel drops that marker; the owning process notices within a heartbeat and aborts like Esc would — the partial image is kept for resuming, the disk is only ever read. A record whose heartbeat is older than 15 s belongs to a dead process and is discarded. This replaces the single scheduled-backup.json from earlier in this release.

  • Resumable backups — images are now written to <name>.img.partial with a <name>.img.partial.json sidecar recording the source disk's name, serial and size, and renamed to <name>.img only after the final flush. Consequences: a .img is always complete (previously a killed run left a truncated .img that i would happily restore and the retention pruner counted as a backup); and when a backup of the same disk into the same folder starts again — the next scheduled run, or s by hand — it finds the partial, trims any torn last chunk, seeks both the disk and the file to that offset and continues, with speed/ETA computed from this session only. Works after Esc, x in the Backups panel, a crash, a reboot or a full destination. The log states the resume explicitly, plus a reminder that the earlier part reflects the disk as it was when first read. A partial is only ever matched by serial + size (or name + size for disks without a serial); the scheduler's free-space check counts just the remainder.

  • No accidental overlapping backups — the scheduled runner skips its run while any other backup is live ("a manual backup is already running (pid …, 42%) — this run was skipped"; Task Scheduler already prevented two instances of the job itself, but a manual run could previously read the same disk twice concurrently). In the TUI, the s menu shows an inline warning listing the running backups, and choosing a destination then opens a confirmation — y starts anyway (logged), b jumps to the Backups panel, Esc aborts — so two backups only ever run together on purpose.

  • Pause scheduled backups — p in the Backups panel or in the schedule editor (a) opens a menu: pause for 1 hour, 6 hours, 24 hours, 7 days, or until you resume it; when paused, the first entry is Resume now. The pause is stored as paused_until in config.json; the Task Scheduler job stays registered and --scheduled-backup simply logs "skipped — paused until …" and exits (no notification) until the pause lifts by itself or is cleared. No elevation is needed to pause or resume, it survives reboots, and a backup already in progress keeps running. The schedule editor and the Backups panel both show the paused state.

Changed

  • Footer shows m manage; Help gained a line for it, plus a Shift+B line.

Fixed

  • --update / Shift+U failed with "checksums.txt has no entry for diskutility.exe" even though the release's checksums.txt was correct. GitHub serves release assets as application/octet-stream, so PowerShell's Invoke-WebRequest ... .Content returned the file as a byte[]; written to the pipe, that became one integer per line and the SHA-256 parser found no diskutility.exe entry. The updater now decodes the bytes as UTF-8 before parsing. install.ps1 had the same latent bug and is fixed the same way — use it (or winget upgrade) to get past v0.4.6, since the old binary cannot self-update.

Full Changelog: v0.4.6...v0.4.7