From 5355625ed626bd8c713ebe035bc29873fa19e8a6 Mon Sep 17 00:00:00 2001 From: weishu Date: Thu, 29 Feb 2024 19:22:54 +0800 Subject: [PATCH] ksud: correctly copy chr device and keep xattr. close #1397 --- userspace/ksud/Cargo.lock | 7 --- userspace/ksud/Cargo.toml | 1 - userspace/ksud/src/module.rs | 8 +-- userspace/ksud/src/utils.rs | 101 ++++++++++++++++++++++++++++++++++- 4 files changed, 100 insertions(+), 17 deletions(-) diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock index 64203927..927a0f03 100644 --- a/userspace/ksud/Cargo.lock +++ b/userspace/ksud/Cargo.lock @@ -537,12 +537,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -806,7 +800,6 @@ dependencies = [ "encoding_rs", "env_logger", "extattr", - "fs_extra", "getopts", "hole-punch", "humansize", diff --git a/userspace/ksud/Cargo.toml b/userspace/ksud/Cargo.toml index c914e6e7..d7e08a09 100644 --- a/userspace/ksud/Cargo.toml +++ b/userspace/ksud/Cargo.toml @@ -37,7 +37,6 @@ sha256 = "1" tempdir = "0.3" chrono = "0.4" hole-punch = { git = "https://github.com/tiann/hole-punch" } -fs_extra = "1.3" [target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies] rustix = { git = "https://github.com/Kernel-SU/rustix.git", branch = "main", features = ["all-apis"] } diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs index e8bcdafe..900c931d 100644 --- a/userspace/ksud/src/module.rs +++ b/userspace/ksud/src/module.rs @@ -392,13 +392,7 @@ fn _install_module(zip: &str) -> Result<()> { create_module_image(tmp_module_img, sparse_image_size, journal_size)?; let _dontdrop = mount::AutoMountExt4::try_new(tmp_module_img, module_update_tmp_dir, true)?; - fs_extra::dir::copy( - defs::MODULE_DIR, - module_update_tmp_dir, - &fs_extra::dir::CopyOptions::new() - .overwrite(true) - .content_only(true), - )?; + utils::copy_module_files(defs::MODULE_DIR, module_update_tmp_dir)?; } else { utils::copy_sparse_file(modules_img, tmp_module_img, true).with_context(|| { format!( diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs index 6ab1ff09..acfd4d01 100644 --- a/userspace/ksud/src/utils.rs +++ b/userspace/ksud/src/utils.rs @@ -15,14 +15,16 @@ use std::os::unix::prelude::PermissionsExt; use hole_punch::*; use std::io::{Read, Seek, SeekFrom}; +use jwalk::WalkDir; + #[cfg(any(target_os = "linux", target_os = "android"))] use rustix::{ process, thread::{move_into_link_name_space, unshare, LinkNameSpaceType, UnshareFlags}, }; -pub fn ensure_clean_dir(dir: &str) -> Result<()> { - let path = Path::new(dir); +pub fn ensure_clean_dir(dir: impl AsRef) -> Result<()> { + let path = dir.as_ref(); log::debug!("ensure_clean_dir: {}", path.display()); if path.exists() { log::debug!("ensure_clean_dir: {} exists, remove it", path.display()); @@ -241,3 +243,98 @@ pub fn copy_sparse_file, Q: AsRef>( Ok(()) } + +#[cfg(any(target_os = "linux", target_os = "android"))] +fn copy_xattrs(src_path: impl AsRef, dest_path: impl AsRef) -> Result<()> { + use rustix::path::Arg; + let std::result::Result::Ok(xattrs) = extattr::llistxattr(src_path.as_ref()) else { + return Ok(()); + }; + for xattr in xattrs { + let std::result::Result::Ok(value) = extattr::lgetxattr(src_path.as_ref(), &xattr) else { + continue; + }; + log::info!( + "Set {:?} xattr {} = {}", + dest_path.as_ref(), + xattr.to_string_lossy(), + value.to_string_lossy(), + ); + extattr::lsetxattr(dest_path.as_ref(), &xattr, &value, extattr::Flags::empty()) + .with_context(|| format!("Failed to set xattr for {:?}", dest_path.as_ref()))?; + } + Ok(()) +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn copy_module_files(source: impl AsRef, destination: impl AsRef) -> Result<()> { + use rustix::fs::FileTypeExt; + use rustix::fs::MetadataExt; + + for entry in WalkDir::new(source.as_ref()).into_iter() { + let entry = entry.context("Failed to access entry")?; + let source_path = entry.path(); + let relative_path = source_path + .strip_prefix(source.as_ref()) + .context("Failed to generate relative path")?; + let dest_path = destination.as_ref().join(relative_path); + + if let Some(parent) = dest_path.parent() { + std::fs::create_dir_all(parent).context("Failed to create directory")?; + } + + if entry.file_type().is_file() { + std::fs::copy(&source_path, &dest_path).with_context(|| { + format!( + "Failed to copy file from {source_path:?} to {dest_path:?}", + ) + })?; + copy_xattrs(&source_path, &dest_path)?; + } else if entry.file_type().is_symlink() { + if dest_path.exists() { + std::fs::remove_file(&dest_path).context("Failed to remove file")?; + } + let target = std::fs::read_link(entry.path()).context("Failed to read symlink")?; + log::info!("Symlink: {:?} -> {:?}", dest_path, target); + std::os::unix::fs::symlink(target, &dest_path).context("Failed to create symlink")?; + copy_xattrs(&source_path, &dest_path)?; + } else if entry.file_type().is_dir() { + create_dir_all(&dest_path)?; + copy_xattrs(&source_path, &dest_path)?; + } else if entry.file_type().is_char_device() { + if dest_path.exists() { + std::fs::remove_file(&dest_path).context("Failed to remove file")?; + } + let metadata = std::fs::metadata(&source_path).context("Failed to read metadata")?; + let mode = metadata.permissions().mode(); + let dev = metadata.rdev(); + if dev == 0 { + log::info!( + "Found a char device with major 0: {}", + entry.path().display() + ); + rustix::fs::mknodat( + rustix::fs::CWD, + &dest_path, + rustix::fs::FileType::CharacterDevice, + mode.into(), + dev, + ) + .with_context(|| format!("Failed to create device file at {dest_path:?}"))?; + copy_xattrs(&source_path, &dest_path)?; + } + } else { + log::info!( + "Unknown file type: {:?}, {:?},", + entry.file_type(), + entry.path(), + ); + } + } + Ok(()) +} + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +pub fn copy_module_files(_source: impl AsRef, _destination: impl AsRef) -> Result<()> { + unimplemented!() +} \ No newline at end of file