~jelmer/brz/reforma

« back to all changes in this revision

Viewing changes to crates/osutils/src/file.rs

  • Committer: The Breezy Bot
  • Author(s): Jelmer Vernooij
  • Date: 2023-04-17 17:26:53 UTC
  • mfrom: (7730.1.1 osutils)
  • Revision ID: the_breezy_bot-20230417172653-e7ipapvc2342wong
Move more osutils functionality to rust

by jelmer review by jelmer

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
use std::fs::{set_permissions, Permissions};
3
3
use std::io::Result;
4
4
use std::os::unix::fs::PermissionsExt;
5
 
use std::path::Path;
 
5
use std::path::{Path, PathBuf};
 
6
use walkdir::WalkDir;
6
7
 
7
8
pub fn make_writable<P: AsRef<Path>>(path: P) -> Result<()> {
8
9
    let path = path.as_ref();
45
46
        Ok(())
46
47
    }
47
48
}
 
49
 
 
50
#[cfg(unix)]
 
51
pub fn copy_ownership_from_path<P: AsRef<Path>>(dst: P, src: Option<&Path>) -> Result<()> {
 
52
    use libc::{chown, gid_t, uid_t};
 
53
    use std::os::unix::ffi::OsStrExt;
 
54
    use std::os::unix::fs::MetadataExt;
 
55
 
 
56
    let mut src = match src {
 
57
        Some(p) => p,
 
58
        None => dst.as_ref().parent().unwrap_or_else(|| Path::new(".")),
 
59
    };
 
60
 
 
61
    if src == Path::new("") {
 
62
        src = Path::new(".");
 
63
    }
 
64
 
 
65
    let s = std::fs::metadata(src)?;
 
66
    let uid = s.uid();
 
67
    let gid = s.gid();
 
68
 
 
69
    if unsafe {
 
70
        chown(
 
71
            dst.as_ref().as_os_str().as_bytes().as_ptr() as *const i8,
 
72
            uid as uid_t,
 
73
            gid as gid_t,
 
74
        )
 
75
    } != 0
 
76
    {
 
77
        debug!(
 
78
            "Unable to copy ownership from \"{}\" to \"{}\". \
 
79
               You may want to set it manually.",
 
80
            src.display(),
 
81
            dst.as_ref().display()
 
82
        );
 
83
    }
 
84
    Ok(())
 
85
}
 
86
 
 
87
pub fn is_dir(f: &std::path::Path) -> bool {
 
88
    match std::fs::symlink_metadata(f) {
 
89
        Ok(metadata) => metadata.is_dir(),
 
90
        Err(_) => false,
 
91
    }
 
92
}
 
93
 
 
94
pub fn is_file(f: &std::path::Path) -> bool {
 
95
    match std::fs::symlink_metadata(f) {
 
96
        Ok(metadata) => metadata.is_file(),
 
97
        Err(_) => false,
 
98
    }
 
99
}
 
100
 
 
101
pub fn is_link(f: &std::path::Path) -> bool {
 
102
    match std::fs::symlink_metadata(f) {
 
103
        Ok(metadata) => metadata.file_type().is_symlink(),
 
104
        Err(_) => false,
 
105
    }
 
106
}
 
107
 
 
108
#[cfg(unix)]
 
109
pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dest: Q) -> std::io::Result<()> {
 
110
    let src = src.as_ref();
 
111
    let dest = dest.as_ref();
 
112
    match std::fs::hard_link(src, dest) {
 
113
        Ok(_) => Ok(()),
 
114
        Err(e) => {
 
115
            // TODO(jelmer): This should really be checking for
 
116
            // e.kind() != std::io::ErrorKind::CrossesDeviceBoundary{
 
117
            // See https://github.com/rust-lang/rust/issues/86442
 
118
            if e.kind() != std::io::ErrorKind::Other {
 
119
                return Err(e);
 
120
            }
 
121
            std::fs::copy(src, dest)?;
 
122
            Ok(())
 
123
        }
 
124
    }
 
125
}
 
126
 
 
127
#[cfg(any(target_os = "windows", target_env = "cygwin", target_os = "macos"))]
 
128
pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dest: Q) -> io::Result<()> {
 
129
    std::fs::copy(src.as_ref(), dest.as_ref())?;
 
130
}
 
131
 
 
132
pub fn copy_tree<P: AsRef<Path>, Q: AsRef<Path>>(from_path: P, to_path: Q) -> std::io::Result<()> {
 
133
    for entry in WalkDir::new(from_path.as_ref()) {
 
134
        let entry = entry?;
 
135
        let path = entry.path();
 
136
        let dst_path = to_path
 
137
            .as_ref()
 
138
            .join(path.strip_prefix(from_path.as_ref()).unwrap());
 
139
        if entry.file_type().is_dir() {
 
140
            match std::fs::create_dir(&dst_path) {
 
141
                Ok(_) => {}
 
142
                Err(e) => {
 
143
                    if e.kind() != std::io::ErrorKind::AlreadyExists || dst_path != to_path.as_ref()
 
144
                    {
 
145
                        return Err(e);
 
146
                    }
 
147
                }
 
148
            }
 
149
        } else if entry.file_type().is_file() {
 
150
            std::fs::copy(path, dst_path)?;
 
151
        } else if entry.file_type().is_symlink() {
 
152
            let target = std::fs::read_link(path)?;
 
153
            let target = target
 
154
                .strip_prefix(from_path.as_ref())
 
155
                .unwrap_or(target.as_path());
 
156
            #[cfg(unix)]
 
157
            std::os::unix::fs::symlink(target, dst_path)?;
 
158
            #[cfg(windows)]
 
159
            std::os::windows::fs::symlink_file(target, dst_path)?;
 
160
        } else {
 
161
            return Err(std::io::Error::new(
 
162
                std::io::ErrorKind::Other,
 
163
                format!("Unsupported file type: {:?}", entry.file_type()),
 
164
            ));
 
165
        }
 
166
    }
 
167
    Ok(())
 
168
}