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')]
17    skip_paths: bool,
18
19    /// Ignore offsets when matching references
20    #[clap(short = 'o')]
21    ignore_offset: bool,
22
23    /// Set inode container's size
24    #[clap(short = 's')]
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)
31            .with_context(|| format!("failed to open '{}'", self.path.display()))?;
32        let fd = file.as_fd();
33
34        let results =
35            btrfs_uapi::inode::logical_ino(fd, self.logical, self.ignore_offset, self.bufsize)
36                .context("failed to look up logical address (is this a btrfs filesystem?)")?;
37
38        if results.is_empty() {
39            eprintln!("no results found for logical address {}", self.logical);
40        } else if self.skip_paths {
41            // Just print inode, offset, root
42            for result in results {
43                println!(
44                    "inode {} offset {} root {}",
45                    result.inode, result.offset, result.root
46                );
47            }
48        } else {
49            // Resolve paths for each inode
50            for result in results {
51                match btrfs_uapi::inode::ino_paths(fd, result.inode) {
52                    Ok(paths) => {
53                        if paths.is_empty() {
54                            println!(
55                                "inode {} offset {} root {} <no path>",
56                                result.inode, result.offset, result.root
57                            );
58                        } else {
59                            for path in paths {
60                                println!("{}", path);
61                            }
62                        }
63                    }
64                    Err(_) => {
65                        println!(
66                            "inode {} offset {} root {} <error resolving path>",
67                            result.inode, result.offset, result.root
68                        );
69                    }
70                }
71            }
72        }
73
74        Ok(())
75    }
76}