Skip to main content

btrfs_cli/inspect/
logical_resolve.rs

1use crate::{Format, Runnable};
2use anyhow::{Context, Result};
3use clap::Parser;
4use std::{fs::File, os::unix::io::AsFd, path::PathBuf};
5
6/// Get file system paths for the given logical address
7#[derive(Parser, Debug)]
8pub struct LogicalResolveCommand {
9    /// Logical address
10    logical: u64,
11
12    /// Path to a file or directory on the btrfs filesystem
13    path: PathBuf,
14
15    /// Skip the path resolving and print the inodes instead
16    #[clap(short = 'P', long)]
17    skip_paths: bool,
18
19    /// Ignore offsets when matching references
20    #[clap(short = 'o', long)]
21    ignore_offset: bool,
22
23    /// Set inode container's size
24    #[clap(short = 's', long)]
25    bufsize: Option<u64>,
26}
27
28impl Runnable for LogicalResolveCommand {
29    fn run(&self, _format: Format, _dry_run: bool) -> Result<()> {
30        let file = File::open(&self.path).with_context(|| {
31            format!("failed to open '{}'", self.path.display())
32        })?;
33        let fd = file.as_fd();
34
35        let results = btrfs_uapi::inode::logical_ino(
36            fd,
37            self.logical,
38            self.ignore_offset,
39            self.bufsize,
40        )
41        .context(
42            "failed to look up logical address (is this a btrfs filesystem?)",
43        )?;
44
45        if results.is_empty() {
46            eprintln!("no results found for logical address {}", self.logical);
47        } else if self.skip_paths {
48            // Just print inode, offset, root
49            for result in results {
50                println!(
51                    "inode {} offset {} root {}",
52                    result.inode, result.offset, result.root
53                );
54            }
55        } else {
56            // Resolve paths for each inode
57            for result in results {
58                match btrfs_uapi::inode::ino_paths(fd, result.inode) {
59                    Ok(paths) => {
60                        if paths.is_empty() {
61                            println!(
62                                "inode {} offset {} root {} <no path>",
63                                result.inode, result.offset, result.root
64                            );
65                        } else {
66                            for path in paths {
67                                println!("{}", path);
68                            }
69                        }
70                    }
71                    Err(_) => {
72                        println!(
73                            "inode {} offset {} root {} <error resolving path>",
74                            result.inode, result.offset, result.root
75                        );
76                    }
77                }
78            }
79        }
80
81        Ok(())
82    }
83}