summaryrefslogtreecommitdiffstats
path: root/src/util/fs.rs
blob: 266cb9cc5b012b010d6b1029dce265cafd60413c (plain)
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
use std::{
	fs, io,
	path::{Path, PathBuf},
};

use nix::mount::{self, MsFlags};

use crate::util::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<()> {
	rm_rf::ensure_removed(path.as_ref())
		.map_err(Error::new)
		.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())
}

#[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: &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,
		Some(fstype),
		flags,
		data,
	)
	.with_context(|| format!("Failed to mount {:?}", canon_target))?;
	Ok(Mount(canon_target))
}