0

I have a list of files as :<volume name>:<directory inode>:<file name>. For example, :Foo:33103829:IMG_2837.JPG. How can I get the file path?

I found an answer here that looks to be exactly what I want, but I can't get it to work. The answer says that on OS X there is a 'magic' directory /.vol that works on inodes. ls tells me that /.vol exists, but doesn't contain anything, even when accessed by inodes:

# verify that /.vol exists:
~$ ls -ld /.vol
drwxr-xr-x@ 2 root  wheel  68 May 18  2009 /.vol/

# get inode of volume Foo
~$ ls -id /Volumes/Foo
32659974 /Volumes/Foo@

# access volume Foo by idnode
~$ ls /.vol/32659974
ls: /.vol/32659974: No such file or directory

# access volume Foo by idnode
~$ cd /.vol/32659974
cd: /.vol/32659974: No such file or directory

# access volume by inode using GetFileInfo
~$ GetFileInfo /.vol/32659974
GetFileInfo: could not refer to file (-43)
Community
  • 1
  • 1
jetset
  • 388
  • 4
  • 14
  • 1
    Did you see the `GetFileInfo` answer in that question? Even though the _accepted_ answer doesn't work for you (not a surprise, since it's specific to directories -- and doesn't hide that limitation) doesn't mean the others aren't worth investigating. – Charles Duffy Sep 25 '14 at 22:29
  • possible duplicate of [Is there any function to retrieve the path associated with an inode?](http://stackoverflow.com/questions/11951328/is-there-any-function-to-retrieve-the-path-associated-with-an-inode) – Michael Robinson Sep 25 '14 at 22:30
  • BTW, while for directories it's safe to assume that there exists only one path per inode, that's not at all a safe assumption for files. – Charles Duffy Sep 25 '14 at 22:31
  • Hi @CharlesDuffy, the GetFileInfo is equivalent since it also relies on `/.vol` working. I can add that to my question. – jetset Sep 25 '14 at 22:32
  • In my case, I'm trying to proceed methodically, so step 1 is verifying that I can access a volume by its inode (per the example in the other answer), and I can't. If I could, I'd then try to access the directory, and if I could, then I'd access the file by its name, which I have. – jetset Sep 25 '14 at 22:35
  • *nod*. In _most_ unixlike operating systems, no reverse map exists (since inode <-> filename is not a 1:1 relationship); OS X is somewhat of an oddball in this by virtue of providing a mechanism to do so at all. – Charles Duffy Sep 25 '14 at 22:36

2 Answers2

3

Turns out the problem is that I was getting the inode number of the volume from ls -i which isn't usable to access via /.vol, which needs the device ID. When I instead get the device ID of the volume using stat (as I saw in an answer here), it works.

# ls -id returns inode as '32659974'
~$ ls -id /Volumes/Foo
32659974 /Volumes/Foo@

# stat returns device ID as '234881026' and confirms inode is '32659974'
~$ stat /Volumes/Foo
234881026 32659974 lrwxr-xr-x 1 root admin 0 1 "Sep 16 14:31:52 2014" "Sep 16 14:31:52 2014" "Sep 16 14:31:52 2014" "Sep 16 14:31:52 2014" 4096 8 0 /Volumes/Foo

# access file using ./vol/<device ID>/<inode>
~$ cd /.vol/234881026/1017800
:../Prague 2011 March$
Community
  • 1
  • 1
jetset
  • 388
  • 4
  • 14
  • 1
    The first number output by `stat` is not an inode, it's the device ID. Compare the output when using `stat -s` to the documented fields of the `struct stat` on the [`stat(2)` man page](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/stat.2.html). You'll notice that `stat` also reported the inode number, but inode numbers are only meaningful in the context of a given device, which is why the `/.vol` file system requires that you supply the device ID first and then an inode. – Ken Thomases Sep 25 '14 at 22:56
  • I was just reading the lstat() man page and was going to update my answer, but you beat me to it, @KenThomases. The clue should have been that the second number returned by `stat` is the same as what `ls -id` returns; that's what made me start reading the man page for `stat`, leading to `lstat` and the light bulb about device ID versus inode. – jetset Sep 25 '14 at 23:04
0

You can use this script

#!/bin/sh
export PATH=/bin:/usr/bin
while IFS=: read -r vol inode name
do
    [[ -e "/Volumes/$vol" ]] || continue
    eval $(stat -s "/Volumes/$vol")
    fpath=$(GetFileInfo "/.vol/$st_dev/$inode" | perl -ne 'print "$2\n" if m/^(directory|file):\s*"(.*)"/;')
    printf "%s:%s:%s:%s" "$vol" $inode "$name" "$fpath"
    bname=$(basename "$fpath")
    [[ "$bname" == "$name" ]] && printf "\n" || printf " #DIFF NAMES\n"
done
  • save it as v2p.sh
  • chmod 755 v2p.sh
  • use it as ./v2p.sh < your_input_file >output_file

from the input like

jhdd:60533283:aliases
jhdd:60526259:apache2
Tunnelblick Uninstaller:19:Online Documentation.webloc
jhdd:68032325:auto_smb
jhdd:60526617:bashrc

produces

jhdd:60533283:aliases:/private/etc/postfix/aliases
jhdd:60526259:apache2:/private/etc/apache2
Tunnelblick Uninstaller:19:Online Documentation.webloc:/Volumes/Tunnelblick Uninstaller/Online Documentation.webloc
jhdd:68032325:auto_smb:/private/etc/auto_smb
jhdd:60526617:bashrc:/private/etc/bashrc

e.g. adds the path to the end as an new colon delimited field

clt60
  • 62,119
  • 17
  • 107
  • 194