Is there any POSIX way through fstat(2)
to check whether a file is a symbolic link or not?
There is flag O_NOFOLLOW
in open(2)
which can check it, however, it's not POSIX.
There is S_ISLNK
in fstat(2)
, which is said in man fstat
:
The S_ISLNK() and S_ISSOCK() macros are not in POSIX.1-1996,
but both are present in POSIX.1-2001; the former is from SVID
4, the latter from SUSv2.
and the compile will fail on my machine.
Also, there is another S_IFLNK
in lstat(2)
, however, it won't work with fstat(2)
(which will follow the link to the file referred to).
No.
It's not true that fstat
follows symlinks. Instead, open
follows symlinks. Once you get to fstat
, it is too late and the information is gone.
Tell us why you need to know, and we can help with that problem. (Open another question.)
How files work:
Here is some pseudo-C / shell code:
system("echo 'Hello, World!' >A.txt");
system("ln A.txt B.txt");
system("ln -s A.txt C.txt");
fdes = open("C.txt");
unlink("A.txt");
unlink("C.txt");
data = read(fdes);
write(stdout, data);
The result: your program prints "Hello, world!"
. The state of the world looks like this:
+--Application--+ +--Kernel--+ +-------Disk-------+
| | | | | |
| fdes --------------> file ---------> inode #973 <-------+
| | | | | "Hello World!" | |
+---------------+ +----------+ | | |
| directory ---------+
| "B.txt" |
| |
+------------------+
As far as the kernel is concerned, the file open is "inode #973". The data structure in kernel memory has some additional information such as the current position, but it does NOT know the path. The kernel is not expected to know that information.
If you asked the kernel what the path is, it could say "you have B.txt" open. But you never opened "B.txt", you opened "C.txt" which was a symlink to "A.txt", and both "A.txt" and "C.txt" have been deleted (they were just names to begin with).
Simple analogy:
You get a phone call from an old friend. He asks, "Did I look up your number in the phone directory, did I memorize it, or did I have to ask someone for your number?"
You have no way of knowing the answer. All you know is who is on the other end of the line. Just like an open file doesn't store information about what it was named (hard link or symbolic link), it just has information about permissions and data.
The solution: Just use lstat
(yes, there is a race condition). If you didn't open the file yourself (e.g., you get it from a parent process or you get it over a socket), then it's more or less impossible to know if it was opened through a symbolic link.