btrfs_cli/filesystem/
resize.rs1use crate::{Format, Runnable, util::parse_size_with_suffix};
2use anyhow::{Context, Result};
3use btrfs_uapi::filesystem::{ResizeAmount, ResizeArgs, resize};
4use clap::Parser;
5use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
6
7#[derive(Parser, Debug)]
9pub struct FilesystemResizeCommand {
10 #[clap(long)]
12 pub enqueue: bool,
13
14 #[clap(long)]
16 pub offline: bool,
17
18 pub size: String,
21
22 pub path: PathBuf,
23}
24
25fn parse_resize_amount(s: &str) -> Result<ResizeAmount> {
26 if s == "cancel" {
27 return Ok(ResizeAmount::Cancel);
28 }
29 if s == "max" {
30 return Ok(ResizeAmount::Max);
31 }
32 let (modifier, rest) = if let Some(r) = s.strip_prefix('+') {
33 (1i32, r)
34 } else if let Some(r) = s.strip_prefix('-') {
35 (-1i32, r)
36 } else {
37 (0i32, s)
38 };
39 let bytes = parse_size_with_suffix(rest)?;
40 Ok(match modifier {
41 1 => ResizeAmount::Add(bytes),
42 -1 => ResizeAmount::Sub(bytes),
43 _ => ResizeAmount::Set(bytes),
44 })
45}
46
47fn parse_resize_args(s: &str) -> Result<ResizeArgs> {
48 if let Some(colon) = s.find(':') {
49 if let Ok(devid) = s[..colon].parse::<u64>() {
50 let amount = parse_resize_amount(&s[colon + 1..])?;
51 return Ok(ResizeArgs::new(amount).with_devid(devid));
52 }
53 }
54 Ok(ResizeArgs::new(parse_resize_amount(s)?))
55}
56
57impl Runnable for FilesystemResizeCommand {
58 fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
59 if self.offline {
60 anyhow::bail!("--offline is not yet implemented");
61 }
62
63 if self.enqueue {
64 anyhow::bail!("--enqueue is not yet implemented");
65 }
66
67 let args = parse_resize_args(&self.size).with_context(|| {
68 format!("invalid resize argument: '{}'", self.size)
69 })?;
70
71 let file = File::open(&self.path).with_context(|| {
72 format!("failed to open '{}'", self.path.display())
73 })?;
74
75 resize(file.as_fd(), args).with_context(|| {
76 format!("resize failed on '{}'", self.path.display())
77 })?;
78
79 Ok(())
80 }
81}