btrfs_cli/subvolume/
flags.rs1use crate::{Format, Runnable};
2use anyhow::{Context, Result};
3use btrfs_uapi::subvolume::{
4 SubvolumeFlags, subvolume_flags_get, subvolume_flags_set,
5};
6use clap::Parser;
7use std::{fs::File, 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, _format: Format, _dry_run: bool) -> Result<()> {
34 let file = File::open(&self.path).with_context(|| {
35 format!("failed to open '{}'", self.path.display())
36 })?;
37
38 let flags = subvolume_flags_get(file.as_fd()).with_context(|| {
39 format!("failed to get flags for '{}'", self.path.display())
40 })?;
41
42 println!("{}", flags);
43
44 Ok(())
45 }
46}
47
48#[derive(Parser, Debug)]
50pub struct SubvolumeSetFlagsCommand {
51 pub flags: ParsedSubvolumeFlags,
53
54 pub path: PathBuf,
56}
57
58impl Runnable for SubvolumeSetFlagsCommand {
59 fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
60 let file = File::open(&self.path).with_context(|| {
61 format!("failed to open '{}'", self.path.display())
62 })?;
63
64 subvolume_flags_set(file.as_fd(), self.flags.0).with_context(|| {
65 format!("failed to set flags on '{}'", self.path.display())
66 })?;
67
68 println!("Set flags to {} on '{}'", self.flags.0, self.path.display());
69
70 Ok(())
71 }
72}