diff --git a/Cargo.lock b/Cargo.lock index 6c6361c..84998fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1065,6 +1065,7 @@ dependencies = [ "typetag", "url", "uuid", + "walkdir", "which", "xz2", ] diff --git a/Cargo.toml b/Cargo.toml index dfc0441..332c3a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ strum = { version = "0.24.1", features = ["derive"] } nix-config-parser = { version = "0.1.2", features = ["serde"] } which = "4.4.0" sysctl = "0.5.4" +walkdir = "2.3.3" [dev-dependencies] eyre = { version = "0.6.8", default-features = false, features = [ "track-caller" ] } diff --git a/src/action/base/fetch_and_unpack_nix.rs b/src/action/base/fetch_and_unpack_nix.rs index bc5ff70..69c6fd0 100644 --- a/src/action/base/fetch_and_unpack_nix.rs +++ b/src/action/base/fetch_and_unpack_nix.rs @@ -143,6 +143,9 @@ impl Action for FetchAndUnpackNix { let decoder = xz2::read::XzDecoder::new(bytes.reader()); let mut archive = tar::Archive::new(decoder); + archive.set_preserve_permissions(true); + archive.set_preserve_mtime(true); + archive.set_unpack_xattrs(true); archive .unpack(&dest_clone) .map_err(FetchUrlError::Unarchive) diff --git a/src/action/base/move_unpacked_nix.rs b/src/action/base/move_unpacked_nix.rs index a36f9a1..9e93253 100644 --- a/src/action/base/move_unpacked_nix.rs +++ b/src/action/base/move_unpacked_nix.rs @@ -1,6 +1,11 @@ -use std::path::{Path, PathBuf}; +use std::{ + fs::Permissions, + os::unix::prelude::PermissionsExt, + path::{Path, PathBuf}, +}; use tracing::{span, Span}; +use walkdir::WalkDir; use crate::action::{ Action, ActionDescription, ActionError, ActionErrorKind, ActionTag, StatefulAction, @@ -106,6 +111,25 @@ impl Action for MoveUnpackedNix { ActionErrorKind::Rename(entry.path().clone(), entry_dest.to_owned(), e) }) .map_err(Self::error)?; + + let perms: Permissions = PermissionsExt::from_mode(0o555); + for entry_item in WalkDir::new(&entry_dest) + .into_iter() + .filter_map(Result::ok) + .filter(|e| !e.file_type().is_symlink()) + { + tokio::fs::set_permissions(&entry_item.path(), perms.clone()) + .await + .map_err(|e| { + ActionErrorKind::SetPermissions( + perms.mode(), + entry_item.path().to_owned(), + e, + ) + }) + .map_err(Self::error)?; + } + // Leave a back link where we copied from since later we may need to know which packages we actually transferred // eg, know which `nix` version we installed when curing a user with several versions installed tokio::fs::symlink(&entry_dest, entry.path()) diff --git a/src/action/mod.rs b/src/action/mod.rs index 4dec577..04b4198 100644 --- a/src/action/mod.rs +++ b/src/action/mod.rs @@ -415,7 +415,7 @@ pub enum ActionErrorKind { std::path::PathBuf, #[source] std::io::Error, ), - #[error("Set mode `{0}` on `{1}`")] + #[error("Set mode `{0:#o}` on `{1}`")] SetPermissions(u32, std::path::PathBuf, #[source] std::io::Error), #[error("Remove file `{0}`")] Remove(std::path::PathBuf, #[source] std::io::Error),