1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
use std::{
fs::{self, File},
io,
os::unix::prelude::*,
path::{Path, PathBuf},
};
use nix::{
fcntl::OFlag,
mount::{self, MsFlags},
unistd,
};
use common::error::*;
pub fn open<P: AsRef<Path>>(path: P) -> Result<fs::File> {
fs::File::open(path.as_ref())
.with_context(|| format!("Failed to open file {:?} for reading", path.as_ref()))
}
pub fn create<P: AsRef<Path>>(path: P) -> Result<fs::File> {
fs::File::create(path.as_ref())
.with_context(|| format!("Failed to open file {:?} for writing", path.as_ref()))
}
pub fn rename<P1: AsRef<Path>, P2: AsRef<Path>>(from: P1, to: P2) -> Result<()> {
fs::rename(from.as_ref(), to.as_ref())
.with_context(|| format!("Failed to rename {:?} to {:?}", from.as_ref(), to.as_ref()))
}
// Unlike fs::copy, this doesn't preserve file flags
pub fn copy<P1: AsRef<Path>, P2: AsRef<Path>>(from: P1, to: P2) -> Result<()> {
(|| -> Result<()> {
let mut src = open(from.as_ref())?;
let mut dest = create(to.as_ref())?;
io::copy(&mut src, &mut dest)?;
dest.sync_all()?;
Ok(())
})()
.with_context(|| format!("Failed to copy {:?} to {:?}", from.as_ref(), to.as_ref()))
}
pub fn mkdir<P: AsRef<Path>>(path: P) -> Result<()> {
let mut builder = fs::DirBuilder::new();
builder.recursive(true);
builder
.create(path.as_ref())
.with_context(|| format!("Failed to create directory {:?}", path.as_ref()))
}
pub fn ensure_removed<P: AsRef<Path>>(path: P) -> Result<()> {
fs::remove_dir_all(path.as_ref())
.or_else(|err| match err.kind() {
io::ErrorKind::NotFound => Ok(()),
_ => Err(err),
})
.with_context(|| format!("Failed to delete directory {:?}", path.as_ref()))
}
pub fn is_dir_empty<P: AsRef<Path>>(path: P) -> Result<bool> {
Ok(fs::read_dir(path)?.next().is_none())
}
/// Fixes up weirdness of set-group-ID or bsdgroups
pub fn fixup_permissions<P: AsRef<Path>>(path: P) -> Result<()> {
let path = path.as_ref();
let gid = unistd::getegid();
let metadata = path
.metadata()
.with_context(|| format!("Failed to get metadata of {:?}", path))?;
if metadata.gid() != gid.as_raw() {
unistd::chown(path, None, Some(gid))
.with_context(|| format!("Failed to set group of {:?}", path))?;
}
let mut perms = metadata.permissions();
let mode = perms.mode();
if (mode & 0o777) != mode {
perms.set_mode(mode & 0o777);
std::fs::set_permissions(path, perms)
.with_context(|| format!("Failed to set mode of {:?}", path))?;
}
Ok(())
}
#[must_use]
pub struct Mount(PathBuf);
impl Drop for Mount {
fn drop(&mut self) {
mount::umount(&self.0)
.with_context(|| format!("Failed to unmount {:?}", self.0))
.unwrap();
}
}
pub fn mount<P1: AsRef<Path>, P2: AsRef<Path>>(
source: P1,
target: P2,
fstype: Option<&str>,
flags: MsFlags,
data: Option<&str>,
) -> Result<Mount> {
mkdir(target.as_ref()).with_context(|| format!("Failed to create {:?}", target.as_ref()))?;
let canon_target = target
.as_ref()
.canonicalize()
.with_context(|| format!("Failed to get absolute path for {:?}", target.as_ref()))?;
mount::mount(Some(source.as_ref()), &canon_target, fstype, flags, data)
.with_context(|| format!("Failed to mount {:?}", canon_target))?;
Ok(Mount(canon_target))
}
pub fn pipe() -> Result<(File, File)> {
unistd::pipe2(OFlag::O_CLOEXEC)
.context("pipe2()")
.map(|(piper, pipew)| unsafe { (File::from_raw_fd(piper), File::from_raw_fd(pipew)) })
}
|