Solved Getting the "VERY real" path of a folder (readlink())

  • Thread starter Deleted member 67440
  • Start date
D

Deleted member 67440

Guest
I ran into a little problem.
The /home directory is, very often, a symbolic link
In this example it is quite clear
Code:
root@aserver:/tmp/zp # ls -l /
total 173
-rw-r--r--   2 root  wheel   957 Oct 20  2018 .cshrc
-rw-r--r--   2 root  wheel   474 Oct 20  2018 .profile
-rw-------   1 root  wheel  1024 Aug  8  2017 .rnd
dr-xr-xr-x+  3 root  wheel     3 Jul 21  2017 .zfs
-r--r--r--   1 root  wheel  6197 Oct 20  2018 COPYRIGHT
drwxr-xr-x   2 root  wheel    47 Dec 27 16:16 bin
drwxr-xr-x   9 root  wheel    55 Nov 23 19:09 boot
dr-xr-xr-x  35 root  wheel   512 Nov 23 20:10 dev
-rw-------   1 root  wheel  4096 Nov 23 19:10 entropy
drwxr-xr-x  27 root  wheel   114 Jan 16  2019 etc
lrwxr-xr-x   1 root  wheel     8 Aug  8  2017 home -> usr/home

The readlink(2) function transforms /home into usr/home, and OK
BUT
the path, in order to access it, should actually be
/usr/home

Code:
root@aserver:/tmp/zp # readlink /home
usr/home
The first / is missing (arrrrgggghhh!!)

Code:
string my_readlink(std::string const& path) 
{
    char buf[PATH_MAX];
    ssize_t len=readlink(path.c_str(),buf,sizeof(buf)-1);
    if (len!=-1) 
    {
        buf[len] = '\0';
        return std::string(buf);
    }
    return path;
}

Is there some function (gcc) that allows to get the "really full" path of a link?
 
The first / is missing (arrrrgggghhh!!)
It's not missing. The symlink is relative, not absolute. An absolute symlink would indeed start with a /.

Code:
dice@lady3jane:/tmp/test % pwd
/tmp/test
dice@lady3jane:/tmp/test % ll
total 2
lrwxr-xr-x  1 dice  wheel   3 May 12 15:38 bar@ -> foo
lrwxr-xr-x  1 dice  wheel  13 May 12 15:38 bar2@ -> /tmp/test/foo
lrwxr-xr-x  1 dice  wheel  11 May 12 15:39 bar3@ -> ../test/foo
drwxr-xr-x  2 dice  wheel   3 May 12 15:38 foo/

Three different symlinks, two are relative, one is absolute. All pointing to the same directory. Absolute symlinks are a problem if I move that /tmp/test directory somewhere else. Both relative symlinks would still point to the foo directory, but the absolute one would be dangling.
 
Absolute symlinks are a problem if I move that /tmp/test directory somewhere else
Took some re-reading, a few times, to realize why this is correct.

I generally avoid symlinks if I can help it - they do contribute to spaghetti code. Kinda demonstrates the wisdom of a pretty basic principle: Keep It Simple, Stupid. ;)
 
It's not missing. The symlink is relative, not absolute. An absolute symlink would indeed start with a /.

Code:
dice@lady3jane:/tmp/test % pwd
/tmp/test
dice@lady3jane:/tmp/test % ll
total 2
lrwxr-xr-x  1 dice  wheel   3 May 12 15:38 bar@ -> foo
lrwxr-xr-x  1 dice  wheel  13 May 12 15:38 bar2@ -> /tmp/test/foo
lrwxr-xr-x  1 dice  wheel  11 May 12 15:39 bar3@ -> ../test/foo
drwxr-xr-x  2 dice  wheel   3 May 12 15:38 foo/

Three different symlinks, two are relative, one is absolute. All pointing to the same directory. Absolute symlinks are a problem if I move that /tmp/test directory somewhere else. Both relative symlinks would still point to the foo directory, but the absolute one would be dangling.
Relative to... what?
That's the problem
Not relative to the current directory

Code:
root@aserver:/tmp/zp # readlink "/home"
usr/home
root@aserver:/tmp/zp # ls usr/home
ls: usr/home: No such file or directory
root@aserver:/tmp/zp # ls /usr/home
.zfs            admin           ilaria          silvia          ufficio2
Pisca           administrator   scanner         tiziana         utente
root@aserver:/tmp/zp #
 
Relative to... what?
That's the problem
Not relative to the current directory

Code:
root@aserver:/tmp/zp # readlink "/home"
usr/home
root@aserver:/tmp/zp # ls usr/home
ls: usr/home: No such file or directory
root@aserver:/tmp/zp # ls /usr/home
.zfs            admin           ilaria          silvia          ufficio2
Pisca           administrator   scanner         tiziana         utente
root@aserver:/tmp/zp #
In the example provided by SirDice, the links are relative to the current directory. Yeah, this is something to think about, what the symlinks are relative to. In this case, your usage of ls happens to produce a different result than what you expected. Studying the manuals for correct usage, syntax and options (and the expected results) is your best bet. It does look like you got a little lost in the representation of files vs. directories. In UNIX, everything is a file, even directories.
Code:
root@aserver:/tmp/zp # ls /usr/home
.zfs            admin           ilaria          silvia          ufficio2
Pisca           administrator   scanner         tiziana         utente
root@aserver:/tmp/zp #
The output of ls /usr/home is NOT gonna be the same as ls -ld /usr/home/. Think about why not, and study the ls(1) manpage. Nail down correct usage and syntax by playing with the code a bit.

Edit: Where do you need to be so that the command # ls usr/home produces the same output as # ls /usr/home?
 
The problem arise in my little archiver, zpaqfranz, no needs to study ls syntax or what a file is
In fact I implement a little 'dir' command, because I am very, very lazy, and after 30 years of UNIX experience I still miss dir soooo much

I think the question is rather clear: a relative symlink... but relative to what?
It is relative to /, not to the current directory
Maybe to the zfs' mountpoint?

It is just curiosity, I already released on github and sourceforge the new build of zpaqfranz

Short version: I will read the source code of realpath and readlink to see exactly what run "behind the scene"
Thanks to all answers
 
30 years of UNIX experience I still miss dir soooo much

I think the question is rather clear: a relative symlink... but relative to what?
Cut the UNBELIEVABLE bullshit. Someone with 30 years of UNIX experience wouldn't have such newbie questions. 😩

It's OK to have newbie questions, people on the forums would be happy to help. But ZFS happens to be irrelevant to the symlinking topic of this thread. And it's pretty clear OP doesn't have a solid handle on how symlinks work in UNIX.

Edit: Where do you need to be so that the command # ls usr/home produces the same output as # ls /usr/home?
The correct answer to that is the root directory (/), BTW. No way someone with 30 years of UNIX experience would get THAT incorrect.
 
Relative to... what?
That's the problem
Not relative to the current directory
Consider a path such as "/a/b/c/d", where "/a/b" is a symlink.
If "/a/b" is a symlink to "x/y/z". the kernel will look up "/a/x/y/z/c/d".
If "/a/b" is a symlink to "/x/y/z", the kernel will look up "/x/y/z/c/d".

[Seems people no longer actually *try* things out; they just ask! If they actually tried things out, they might get a clearer understanding and remember accurately instead of getting a partial understanding!]
 
Cut the UNBELIEVABLE bullshit. Someone with 30 years of UNIX experience wouldn't have such newbie questions. 😩
I have to correct myself: 32 years, not 30
I get older every year :)

Can you tell me, please, which library function allows to get the path against which a symlink was created?
Because the thread is

VERY real path​

Which means NOT calling the realpath() function, but HOW IT WORKS

I suppose the "full" link is made of two "pieces"
1) the RELATIVE path (readlink()), for example usr/home
2) the RELATIVE TO WHAT (my question), for example /

To make the FULL path (realpath()?) you should have "something" (a library function) that return 2
Then you will juxtapose to readlink(), getting the full path (just like realpath(), I suppose)
Maybe there is a type function get_the_relative_to_what_of_a_symlink() or whatever

As said the solution is, trivial: look at the source of realpath () which, I suppose, will do exactly this

I admit that I haven't looked at this topic in more than 30 years.
I was hoping there was someone more experienced than me can save me a couple of minute of digging.
Because I'm so lazy

It's OK to have newbie questions, people on the forums would be happy to help. But ZFS happens to be irrelevant to the symlinking topic of this thread. And it's pretty clear OP doesn't have a solid handle on how symlinks work in UNIX.
Thank you very much, indeed
You seem to have no idea how zfs works, but that's okay, I'm not going to teach you

The correct answer to that is the root directory (/), BTW. No way someone with 30 years of UNIX experience would get THAT incorrect.
Since you are so experienced, can you give me suggestions if the implemented solution is reliable, or can be improved?
I haven't checked portability on ESX, QNAP and OSX yet
As I said I'm lazy, maybe you can put me on the right path
This is the source
Thank you
 
Consider a path such as "/a/b/c/d", where "/a/b" is a symlink.
If "/a/b" is a symlink to "x/y/z". the kernel will look up "/a/x/y/z/c/d".
If "/a/b" is a symlink to "/x/y/z", the kernel will look up "/x/y/z/c/d".

[Seems people no longer actually *try* things out; they just ask! If they actually tried things out, they might get a clearer understanding and remember accurately instead of getting a partial understanding!]
Thank you very much for your very helpful help too
I will treasure it
In fact, I hardly ever try, it's an amateur method
 
Today I learned a new thing
Code:
return (NULL);
So I can be satisfied
 
Thank you very much for your very helpful help too
I will treasure it
In fact, I hardly ever try, it's an amateur method
There's a difference between (confessing to an "ugly but functional hack" in comments of the source code of something that actually works) and (having the audacity to claim that something is an "amateur method" without having a good handle on what an "elegant method" even is)!

As for bringing in ZFS: What do you think would be the effect of #ln -s /usr/ports/www/apache24 /usr/home/?

Yeah, it would be interesting to know if ZFS can handle symlinks between two distinct datasets. Is that what OP had in mind for the code they're writing?
 
Yeah, it would be interesting to know if ZFS can handle symlinks between two distinct datasets.
Symlinks, as opposed to hardlinks, are completely independent of the filesystem, they just work with paths (absolute or relative).

And yep, I call bs on this thread...
 
Symlinks, as opposed to hardlinks, are completely independent of the filesystem, they just work with paths (absolute or relative).
Yes. A symlink or soft link is actually a real file with some information stored in it (the information points to the link's target). Hard links on the other hand 'manipulate' (for lack of a better word) the directory structure by creating a file entry and linking the data blocks of that 'new' file entry to the original file. This is why hardlinks cannot be used on directories and cannot cross filesystem boundaries.
 
There's a difference between (confessing to an "ugly but functional hack" in comments of the source code of something that actually works) and (having the audacity to claim that something is an "amateur method" without having a good handle on what an "elegant method" even is)!
I'm sorry but it is obviously, for your judgments, too difficult question for my level
In fact, I have
The "."
But, for a whole series of very long reasons to explain, it doesn't satisfy me
As for bringing in ZFS: What do you think would be the effect of #ln -s /usr/ports/www/apache24 /usr/home/?
I really do not know
Require dozen of hours to understand HOW
It's been several years since I did a little bit of zfs-source dig, but it was on Solaris.
Unfortunately I don't have time to update with today's versions
The older you get, the more career you make, the less time you have to devote to curiosities.
Sad but true
Maybe you feel that getting "something", without knowing HOW it is achieved (aka: "blackbox"), means a professional approach.
By my standards it's amateur
Of course I don't expect everyone to agree

Yeah, it would be interesting to know if ZFS can handle symlinks between two distinct datasets. Is that what OP had in mind for the code they're writing?
they?
 
Yes. A symlink or soft link is actually a real file with some information stored in it (the information points to the link's target). Hard links on the other hand 'manipulate' (for lack of a better word) the directory structure by creating a file entry and linking the data blocks of that 'new' file entry to the original file. This is why hardlinks cannot be used on directories and cannot cross filesystem boundaries.
Well, I am not so sure about what a zfs symlink REALLY is
You may or may not be right

Much of what was true of historical (ext-style) filesystems is not true on zfs, at all.
The latter SEEMS to work like an "old" ext2, but very often it is radically different, under the hood

Anyway thanks to everyone for the collaboration provided, I had never really seen a return (NULL) before and therefore I can be satisfied
 
OK, seems like OP really doesn't know what they're talking about. Efforts by other users on this forum to untangle OP's confusion about ZFS and symlinks have been met with "But I have 30 years' worth of UNIX experience, I know better than you!"...

I actually read obsigna 's earlier post and what they linked to. And yeah, if I wanted to solve the programming problem that OP posed (translating a symlink into an absolute path), those manpages would be sufficient.
 
Just so there's something useful added: realpath() is exactly the function designed for the job described here. Unfortunately, it's not perfectly portable (but will work fine on your most common systems).
 
In fact no, the answer should be
"Look at lstat"
And yes, I know much better than you
You seems to suffer a huge D-K effect
So sorry, but that's a fact
Thanks anyway for your support, very appreciated, albeit useless :)
 
In fact no, the answer should be
"Look at lstat"
That's utter nonsense. lstat() will give you lots of information about a symlink except for the one thing you need, its content, that's what readlink() is for. As you (maybe? I have doubts now) learned, resolving a canonical path from a symlink that's allowed to contain a relative path would be your job – or you just rely on the slightly less portable realpath() to do it.
 
Back
Top