btrfs_cli/subvolume/
flags.rs1use crate::{RunContext, Runnable, util::open_path};
2use anyhow::{Context, Result};
3use btrfs_uapi::subvolume::{
4 SubvolumeFlags, subvolume_flags_get, subvolume_flags_set,
5};
6use clap::Parser;
7use std::{os::unix::io::AsFd, path::PathBuf};
8
9#[derive(Debug, Clone, Copy)]
11pub struct ParsedSubvolumeFlags(SubvolumeFlags);
12
13impl std::str::FromStr for ParsedSubvolumeFlags {
14 type Err = String;
15
16 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
17 match s {
18 "readonly" => Ok(Self(SubvolumeFlags::RDONLY)),
19 "-" | "" | "none" => Ok(Self(SubvolumeFlags::empty())),
20 _ => Err(format!("unknown flag '{s}'; expected 'readonly' or '-'")),
21 }
22 }
23}
24
25#[derive(Parser, Debug)]
27pub struct SubvolumeGetFlagsCommand {
28 pub path: PathBuf,
30}
31
32impl Runnable for SubvolumeGetFlagsCommand {
33 fn run(&self, _ctx: &RunContext) -> Result<()> {
34 let file = open_path(&self.path)?;
35
36 let flags = subvolume_flags_get(file.as_fd()).with_context(|| {
37 format!("failed to get flags for '{}'", self.path.display())
38 })?;
39
40 println!("{flags}");
41
42 Ok(())
43 }
44}
45
46#[derive(Parser, Debug)]
48pub struct SubvolumeSetFlagsCommand {
49 pub flags: ParsedSubvolumeFlags,
51
52 pub path: PathBuf,
54}
55
56impl Runnable for SubvolumeSetFlagsCommand {
57 fn run(&self, _ctx: &RunContext) -> Result<()> {
58 let file = open_path(&self.path)?;
59
60 subvolume_flags_set(file.as_fd(), self.flags.0).with_context(|| {
61 format!("failed to set flags on '{}'", self.path.display())
62 })?;
63
64 println!("Set flags to {} on '{}'", self.flags.0, self.path.display());
65
66 Ok(())
67 }
68}