Search code examples
c++symlinkstd-filesystem

why is is_regular_file reporting true for symbolic link


Why is it that is_regular_file function that is part of std::filesystem reports true for a symbolic link? I have looked at the documentation for the call and can't find the reason and the examples on cppreference exhibit the same behaviour.

As an example, if we look at the binary pidof; It exists as /usr/sbin/pidof and correctly labelled as a symbolic link as shown here by stat:

[@rhel9 ~]$ stat /usr/sbin/pidof 
  File: /usr/sbin/pidof -> /usr/bin/pidof
  Size: 14          Blocks: 0          IO Block: 4096   symbolic link
Device: fd00h/64768d    Inode: 34952482    Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Context: system_u:object_r:bin_t:s0
Access: 2024-02-05 15:46:24.124158991 +0000
Modify: 2023-01-28 09:40:21.000000000 +0000
Change: 2023-05-09 17:34:59.432002380 +0100
 Birth: 2023-05-09 17:34:59.432002380 +0100

If we follow the link and run stat on it:

[@rhel9 ~]$ stat /usr/bin/pidof 
  File: /usr/bin/pidof
  Size: 23760       Blocks: 48         IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 18153014    Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Context: system_u:object_r:bin_t:s0
Access: 2024-02-02 15:12:41.804334284 +0000
Modify: 2023-01-28 09:40:21.000000000 +0000
Change: 2023-05-09 17:34:59.418002380 +0100
 Birth: 2023-05-09 17:34:59.417002380 +0100

If we run the following code:

const std::filesystem::path fsBin("/usr/sbin/pidof");
if (true == std::filesystem::is_regular_file(fsBin))
{
    std::cout << "Regular File" << std::endl;
}
else if(true == std::filesystem::is_symlink(fsBin))
{
    std::cout << "Symbolic Link" << std::endl;
}

The code always prints "Regular File" despite the path being a symbolic link. If I switch the cases around (have is_symlink as the first check), it reports correctly that it is a symlink. What is interesting too is that if I use a std::filesystem::status objects instead of the std::filesystem::path, it never reports a symlink regardless of the order.

Is there an explanation for this behaviour that I'm maybe overlooking?


Solution

  • As documented on cppreference, the function

    bool std::filesystem::is_regular_file(const std::filesystem::path& p);
    

    is equivalent to

    std::filesystem::is_regular_file(std::filesystem::status(p))
    

    where the std::filesystem::status function

    Determines the type and attributes of the filesystem object identified by p as if by POSIX stat (symlinks are followed to their targets).

    Whereas the std::filesystem::symlink_status function

    is the same as the std::filesystem::status function, except that the behavior is as if the POSIX lstat is used (symlinks are not followed).

    Thus, the correct usage in your case would be:

    if (std::filesystem::is_regular_file(std::filesystem::symlink_status(fsBin)))
    {
        // ...
    }