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
|
use std::{env, path::PathBuf};
use anyhow::{Context, Result};
use bch_bindgen::c::BCH_SUBVOL_SNAPSHOT_RO;
use clap::{Parser, Subcommand};
use crate::wrappers::handle::BcachefsHandle;
#[derive(Parser, Debug)]
pub struct Cli {
#[command(subcommand)]
subcommands: Subcommands,
}
/// Subvolumes-related commands
#[derive(Subcommand, Debug)]
enum Subcommands {
#[command(visible_aliases = ["new"])]
Create {
/// Paths
#[arg(required = true)]
targets: Vec<PathBuf>,
},
#[command(visible_aliases = ["del"])]
Delete {
/// Path
#[arg(required = true)]
targets: Vec<PathBuf>,
},
#[command(allow_missing_positional = true, visible_aliases = ["snap"])]
Snapshot {
/// Make snapshot read only
#[arg(long, short)]
read_only: bool,
source: Option<PathBuf>,
dest: PathBuf,
},
}
pub fn subvolume(argv: Vec<String>) -> Result<()> {
let cli = Cli::parse_from(argv);
match cli.subcommands {
Subcommands::Create { targets } => {
for target in targets {
let target = if target.is_absolute() {
target
} else {
env::current_dir()
.map(|p| p.join(target))
.context("unable to get current directory")?
};
if let Some(dirname) = target.parent() {
let fs = unsafe { BcachefsHandle::open(dirname) };
fs.create_subvolume(target)
.context("Failed to create the subvolume")?;
}
}
}
Subcommands::Delete { targets } => {
for target in targets {
let target = target
.canonicalize()
.context("subvolume path does not exist or can not be canonicalized")?;
if let Some(dirname) = target.parent() {
let fs = unsafe { BcachefsHandle::open(dirname) };
fs.delete_subvolume(target)
.context("Failed to delete the subvolume")?;
}
}
}
Subcommands::Snapshot {
read_only,
source,
dest,
} => {
if let Some(dirname) = dest.parent() {
let dot = PathBuf::from(".");
let dir = if dirname.as_os_str().is_empty() {
&dot
} else {
dirname
};
let fs = unsafe { BcachefsHandle::open(dir) };
fs.snapshot_subvolume(
if read_only {
BCH_SUBVOL_SNAPSHOT_RO
} else {
0x0
},
source,
dest,
)
.context("Failed to snapshot the subvolume")?;
}
}
}
Ok(())
}
|