1use anyhow::{Context, Result};
4use std::fs;
5use std::os::unix::fs::PermissionsExt;
6use std::path::Path;
7
8use crate::paths::find_library;
9
10pub fn make_executable(path: &Path) -> Result<()> {
12 let mut perms = fs::metadata(path)
13 .with_context(|| format!("Failed to read metadata: {}", path.display()))?
14 .permissions();
15 perms.set_mode(0o755);
16 fs::set_permissions(path, perms)
17 .with_context(|| format!("Failed to set permissions: {}", path.display()))?;
18 Ok(())
19}
20
21pub fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<u64> {
25 let mut total_size: u64 = 0;
26
27 if !src.is_dir() {
28 return Ok(0);
29 }
30
31 fs::create_dir_all(dst)?;
32
33 for entry in fs::read_dir(src)? {
34 let entry = entry?;
35 let path = entry.path();
36 let dest_path = dst.join(entry.file_name());
37
38 if path.is_dir() {
39 total_size += copy_dir_recursive(&path, &dest_path)?;
40 } else if path.is_symlink() {
41 let target = fs::read_link(&path)?;
42 if !dest_path.exists() && !dest_path.is_symlink() {
43 std::os::unix::fs::symlink(&target, &dest_path)?;
44 }
45 } else {
46 fs::copy(&path, &dest_path)?;
47 if let Ok(meta) = fs::metadata(&dest_path) {
48 total_size += meta.len();
49 }
50 }
51 }
52
53 Ok(total_size)
54}
55
56pub fn copy_library_to(
61 source_root: &Path,
62 lib_name: &str,
63 dest_root: &Path,
64 dest_lib64_path: &str,
65 dest_lib_path: &str,
66 extra_lib_paths: &[&str],
67) -> Result<()> {
68 let src = find_library(source_root, lib_name, extra_lib_paths).with_context(|| {
69 format!(
70 "Could not find library '{}' in source (searched lib64, lib, systemd paths)",
71 lib_name
72 )
73 })?;
74
75 let dest_path = if src.to_string_lossy().contains("lib64/systemd")
77 || src.to_string_lossy().contains("lib/systemd")
78 {
79 let dest_dir = dest_root.join(dest_lib64_path).join("systemd");
81 fs::create_dir_all(&dest_dir)?;
82 dest_dir.join(lib_name)
83 } else if src.to_string_lossy().contains("lib64") {
84 dest_root.join(dest_lib64_path).join(lib_name)
85 } else {
86 dest_root.join(dest_lib_path).join(lib_name)
87 };
88
89 if dest_path.exists() {
90 return Ok(()); }
92
93 if src.is_symlink() {
95 let link_target = fs::read_link(&src)?;
96
97 let actual_src = if link_target.is_relative() {
99 src.parent()
100 .context("Library path has no parent")?
101 .join(&link_target)
102 } else {
103 source_root.join(link_target.to_str().unwrap().trim_start_matches('/'))
104 };
105
106 if actual_src.exists() {
107 let target_name = link_target.file_name().unwrap_or(link_target.as_os_str());
109 let target_dest = dest_path.parent().unwrap().join(target_name);
110 if !target_dest.exists() {
111 fs::copy(&actual_src, &target_dest)?;
112 }
113 if !dest_path.exists() {
115 std::os::unix::fs::symlink(&link_target, &dest_path)?;
116 }
117 } else {
118 fs::copy(&src, &dest_path)?;
120 }
121 } else {
122 fs::copy(&src, &dest_path)?;
123 }
124
125 Ok(())
126}
127
128pub fn create_symlink_if_missing(target: &Path, link: &Path) -> Result<bool> {
133 if link.exists() || link.is_symlink() {
134 return Ok(false);
135 }
136 std::os::unix::fs::symlink(target, link).with_context(|| {
137 format!(
138 "Failed to create symlink {} -> {}",
139 link.display(),
140 target.display()
141 )
142 })?;
143 Ok(true)
144}