I know of this command:
find /path/to/mountpoint -inum <inode number>
but it is a very slow search, I feel like there has to be a faster way to do this. Does anybody know a faster method?
For an ext4 filesystem, you can use debugfs
as in the following example:
$ sudo debugfs -R 'ncheck 393094' /dev/sda2 2>/dev/null
Inode Pathname
393094 /home/enzotib/examples.desktop
The answer is not immediate, but seems to be faster than find
.
The output of debugfs
can be easily parsed to obtain the file names:
$ sudo debugfs -R 'ncheck 393094' /dev/sda2 | cut -f2 | tail -n2 > filenames
debugfs: Bad magic number in super-block while trying to open /dev/sda2 /dev/sda2 contains a crypto_LUKS file system ncheck: Filesystem not open
Commented
Feb 5, 2021 at 3:12
/dev/mapper/sda2_crypt
.
man btrfs-inspect-internal
says:
inode-resolve [-v] <ino> <path>
(needs root privileges)
resolve paths to all files with given inode number ino in a given
subvolume at path, ie. all hardlinks
Options
-v
verbose mode, print count of returned paths and ioctl()
return value
Example:
sudo btrfs inspect-internal inode-resolve 15380 /home
sudo apt install btrfs-tools
but I haven't verified it mysellf. fsck had already destroyed half my files before I realized I could check which inodes it was going to "fix" so never tried it out.
Commented
Sep 4, 2020 at 18:30
The basic problem is that there is no index in most filesystems that work in this direction. If you need to do this kind of thing frequently your best bet is to set up a scheduled task that scans the filesystem for the information you need, create a database (using sqlite3 for example) which has the information you need and create an index on the inode number to locate file(s) quickly.
Example:
#!/bin/bash
# Generate an index file
#
SCAN_DIRECTORY=/
DB_DIRECTORY=~/my-sqlite-databases
if [ ! -d ${DB_DIRECTORY} ] ; then
mkdir ${DB_DIRECTORY}
fi
# Remove any old database - or use one created with a filename based on the date
rm ${DB_DIRECTORY}/files-index.db
(
# Output a command to create a table file_info in the database to hold the information we are interested in
echo 'create table file_info ( inode INTEGER, filepath, filename, numlinks INTEGER, size INTEGER);'
# Use find to scan the directory and locate all the objects - saving the inode, file path, file name, number of links and file size
# This could be reduced to just the inode, file path and file name ... if you are looking for files with multiple links the numlinks is useful (select * from file_info where numlinks > 1)
# Find output formats
#
# %i = inode
# %h = path to file (directory path)
# %f = filename (no directory path)
# %n = number of hard links
# %s = size
# Use find to generate the SQL commands to add the data to the database table.
find $SCAN_DIRECTORY -printf "insert into file_info (inode, filepath, filename, numlinks, size) values ( %i, '%h', '%f', %n, %s);\n"
# Finally create an index on the inode number so we can locate values quickly
echo 'create index inode_index on file_info(inode);'
# Pipe all the above commands into sqlite3 and have sqlite3 create and populate a database
) | sqlite3 ${DB_DIRECTORY}/files-index.db
# Once you have this in place, you can search the index for an inode number as follows
echo 'select * from file_info where inode = 1384238234;' | sqlite3 ${DB_DIRECTORY}/files-index.db
locate
(which may actually be mlocate
or plocate
) with the advantage that the filesystem needs to be scanned only once and databases are updated very fast if only few files have changed.
For XFS this seems to be done using xfs_db(1)
and the blockget
and ncheck
commands:
blockget [-npvs] [-b bno] ... [-i ino] ...
Get block usage and check filesystem consistency. The information is saved for use by a subsequent blockuse, ncheck, or blocktrash command. See xfs_check(8) for more information.ncheck [-s] [-i ino] ...
Print name-inode pairs. A blockget -n command must be run first to gather the information.
Example:
# xfs_db -c 'blockget -n -i 123456' /dev/sde1
inode 123456 add link, now 1
inode 123456 mode 0100644 fmt extents afmt extents nex 1 anex 0 nblk 1 sz 135
inode 123456 nlink 6 not dir
inode 123456 extent [0,822682790,1,0]
setting inode to 6594903486 for block 3/17376422
inode 123456 add link, now 2
inode 123456 add link, now 3
inode 123456 add link, now 4
inode 123456 add link, now 5
inode 123456 add link, now 6
inode 123456 name dir/subdir/foo.bar
-c 'blockget -n -i 6594903486' -c 'ncheck -i 6594903486'
, but it does not add relevant information by using ncheck
, too. The -n
flag of blockget
returns already the filename. PS Works only if the filesystem is unmounted, is slow as well (not sure if as slow as find
) and returns only one filename, even if multiple hardlinks exist (find
even returns hardlinks).
You could look at the fsdb command, found on most Unices, and available somewhere for Linux I am sure. This is a powerful command allowing you to to access the in-core inode structure of files, so be careful. The syntax is also very terse.
While fsdb won't actually let you discover the filename of the inode, it does allow you to directly access the inode when you specify it, in essence "porting" you to the file itself (or at least it's data block pointers) so it's quicker in that respect than the find ;-).
Your question doesn't specify what you want to do with the file. Are you perchance decoding NFS filehandles?
sc.
find
works, it's just so slow.
find / -inum <inode>
. It is much more portable thandebugfs
and also works much more reliably (it can find paths that are not belonging to files on the hard drive, like devices, for instance).