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