Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/locallibrary/changes/loc-255-disk-image-windows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Fixed

- `format` to FAT32 on Windows no longer fails with "The device is not ready" after writing the new file system.
5 changes: 5 additions & 0 deletions crates/locallibrary/src/format/tests/disk_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,12 @@ mod os {
format!(r"\\.\PhysicalDrive{}", n.trim())
}

/// Windows keeps an attached image's file open, so one that's gone isn't attached. Asked about
/// a file that's gone, `Get-DiskImage` fails even with `SilentlyContinue`.
pub fn attached(file: &Path) -> Option<String> {
if !file.exists() {
return None;
}
let path = quote(&file.to_string_lossy());
let n = powershell(&format!(
"$i = Get-DiskImage -ImagePath {path} -ErrorAction SilentlyContinue\nif ($i.Attached) {{ $i.Number }}"
Expand Down
6 changes: 5 additions & 1 deletion crates/locallibrary/src/format/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,17 @@ pub fn format(disk: &Disk, t: &Target, ctx: &Ctx<'_>) -> Result<Option<PathBuf>>

#[cfg(windows)]
fn write_fat32(letter: char, layout: &fat32::Layout, label: &str, ctx: &Ctx<'_>) -> Result<()> {
use std::os::windows::fs::OpenOptionsExt;
use std::os::windows::io::AsRawHandle;

let path = format!(r"\\.\{letter}:");
// FILE_FLAG_WRITE_THROUGH: each write reaches the disk before it returns. The volume can't be
// flushed once it's dismounted (that fails as "The device is not ready"), and writes to a
// volume handle skip the cache already, so this is all the flushing they need.
let mut f = std::fs::OpenOptions::new()
.read(true)
.write(true)
.custom_flags(0x8000_0000)
.open(&path)
.map_err(|e| Error::Io { path: path.clone().into(), source: e })?;
// Explorer and indexers open new volumes briefly; retry the lock for a few seconds.
Expand All @@ -260,7 +265,6 @@ fn write_fat32(letter: char, layout: &fat32::Layout, label: &str, ctx: &Ctx<'_>)
.map_err(|e| Error::Io { path: path.clone().into(), source: e })?;
let volume_id = u32::from_le_bytes(uuid::Uuid::new_v4().as_bytes()[..4].try_into().expect("4 bytes"));
fat32::write(&mut f, 0, layout, label, volume_id, ctx)?;
f.sync_all().map_err(|e| Error::Io { path: path.into(), source: e })?;
// Closing the handle unlocks the volume; Windows mounts it as FAT32 on the next access.
Ok(())
}
Expand Down
Loading