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(
65 source_root: &Path,
66 lib_name: &str,
67 dest_root: &Path,
68 dest_lib64_path: &str,
69 dest_lib_path: &str,
70 extra_lib_paths: &[&str],
71 private_lib_dirs: &[&str],
72) -> Result<()> {
73 let src = find_library(source_root, lib_name, extra_lib_paths).with_context(|| {
74 format!(
75 "Could not find library '{}' in source (searched lib64, lib, extra paths)",
76 lib_name
77 )
78 })?;
79
80 let src_str = src.to_string_lossy();
82 let private_dir = private_lib_dirs.iter().find(|dir| {
83 src_str.contains(&format!("lib64/{}", dir)) || src_str.contains(&format!("lib/{}", dir))
84 });
85
86 let dest_path = if let Some(dir) = private_dir {
87 let dest_dir = dest_root.join(dest_lib64_path).join(dir);
89 fs::create_dir_all(&dest_dir)?;
90 dest_dir.join(lib_name)
91 } else if src_str.contains("lib64") {
92 dest_root.join(dest_lib64_path).join(lib_name)
93 } else {
94 dest_root.join(dest_lib_path).join(lib_name)
95 };
96
97 if dest_path.exists() {
98 return Ok(()); }
100
101 if src.is_symlink() {
103 let link_target = fs::read_link(&src)?;
104
105 let actual_src = if link_target.is_relative() {
107 src.parent()
108 .context("Library path has no parent")?
109 .join(&link_target)
110 } else {
111 source_root.join(link_target.to_str().unwrap().trim_start_matches('/'))
112 };
113
114 if actual_src.exists() {
115 let target_name = link_target.file_name().unwrap_or(link_target.as_os_str());
117 let target_dest = dest_path.parent().unwrap().join(target_name);
118 if !target_dest.exists() {
119 fs::copy(&actual_src, &target_dest)?;
120 }
121 if !dest_path.exists() {
123 std::os::unix::fs::symlink(&link_target, &dest_path)?;
124 }
125 } else {
126 fs::copy(&src, &dest_path)?;
128 }
129 } else {
130 fs::copy(&src, &dest_path)?;
131 }
132
133 Ok(())
134}
135
136#[must_use = "return value indicates whether symlink was created"]
141pub fn create_symlink_if_missing(target: &Path, link: &Path) -> Result<bool> {
142 if link.exists() || link.is_symlink() {
143 return Ok(false);
144 }
145 std::os::unix::fs::symlink(target, link).with_context(|| {
146 format!(
147 "Failed to create symlink {} -> {}",
148 link.display(),
149 target.display()
150 )
151 })?;
152 Ok(true)
153}