Sunday, May 07, 2017

readlink system call fails on other files besides symbolic links

I just write this post to remind myself that the readlink system call fails on non symbolic links. I was expecting that it would work on files and directories but it doesn't.

man 2 readlink says in one of the errno:

EINVAL The named file is not a symbolic link.

So the next step is to check if the path is a symbolic link or not. The first choice would be to use stat on the path, but stat will give you results from the dereferenced file, not the symbolic link. So using stat system call on a file will never tell you if the file is a symbolic link.

lstat()  is  identical  to  stat(), except that if pathname is a symbolic link, then it returns
       information about the link itself, not the file that it refers to.


There you have it for future reference:

std::string MountHandler::doReadlink(std::string const& path) {
    char buff[PATH_MAX];
    struct stat stat_buf = {};
    if (lstat(path.c_str(), &stat_buf) == -1)
        throw std::runtime_error(fmtString("Could not stat path %s. Errno: %s",
        path.c_str(), strerror(errno)));

    if (!S_ISLNK(stat_buf.st_mode))
        return path;

    ssize_t len = readlink(path.c_str(), buff, sizeof (buff) - 1);
    if (len == -1) {
        throw std::runtime_error(fmtString("Readlink failed on %s. errno %s",
            path.c_str(), strerror(errno)));
    }
    buff[len] = '\0';
    return std::string(buff);
}