hdiff_update_core/
fs_ops.rs1use std::path::Path;
2
3#[cfg(not(windows))]
4use std::fs;
5
6use crate::{error::io_path, Error, Result};
7
8#[cfg(windows)]
9use std::{ffi::OsStr, os::windows::ffi::OsStrExt};
10
11#[cfg(windows)]
12use windows_sys::Win32::Storage::FileSystem::{
13 MoveFileExW, MOVEFILE_REPLACE_EXISTING, MOVEFILE_WRITE_THROUGH,
14};
15
16pub(crate) fn replace_file(source: &Path, destination: &Path) -> Result<()> {
17 #[cfg(windows)]
18 {
19 let source_wide = wide_null(source.as_os_str()).map_err(|error| io_path(source, error))?;
20 let destination_wide =
21 wide_null(destination.as_os_str()).map_err(|error| io_path(destination, error))?;
22 let result = unsafe {
23 MoveFileExW(
24 source_wide.as_ptr(),
25 destination_wide.as_ptr(),
26 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH,
27 )
28 };
29 if result == 0 {
30 return Err(io_path(destination, std::io::Error::last_os_error()));
31 }
32 Ok(())
33 }
34
35 #[cfg(not(windows))]
36 {
37 fs::rename(source, destination).map_err(|error| io_path(destination, error))
38 }
39}
40
41pub fn ensure_available_space(path: &Path, required: u64) -> Result<u64> {
42 let available = fs2::available_space(path).map_err(|error| io_path(path, error))?;
43 if available < required {
44 return Err(Error::InsufficientDiskSpace {
45 path: path.to_path_buf(),
46 required,
47 available,
48 });
49 }
50 Ok(available)
51}
52
53#[cfg(windows)]
54fn wide_null(value: &OsStr) -> std::io::Result<Vec<u16>> {
55 let mut wide = Vec::new();
56 for unit in value.encode_wide() {
57 if unit == 0 {
58 return Err(std::io::Error::new(
59 std::io::ErrorKind::InvalidInput,
60 "path contains an embedded null character",
61 ));
62 }
63 wide.push(unit);
64 }
65 wide.push(0);
66 Ok(wide)
67}
68
69#[cfg(test)]
70mod tests {
71 use tempfile::tempdir;
72
73 use super::ensure_available_space;
74 use crate::Error;
75
76 #[test]
77 fn disk_preflight_rejects_impossible_requirements() {
78 let dir = tempdir().unwrap();
79 let error = ensure_available_space(dir.path(), u64::MAX).unwrap_err();
80 assert!(matches!(error, Error::InsufficientDiskSpace { .. }));
81 }
82}