c++error-handlingrealpath

Why does realpath() return error EEXIST?


My program is running in a Linux environment, compiled with gcc version 4.4.7.

I am using realpath() to "canonicalize" file paths. The path of every directory and file I feed to realpath() definitely exists, which of course is essential for realpath() to work properly.

However, sometimes realpath() will fail with error code 17, name EEXIST, string description "File exists".

That baffles me. Of course it exists, I scream at realpath(). But realpath() is unmoved by my ranting.

Documentation for realpath() at http://pubs.opengroup.org/onlinepubs/009695399/functions/realpath.html lists the errors that cause it to fail, but EEXIST is not one of them.

Why does realpath() fail in this way?

Examples of directory and file paths that cause the EEXIST error:

But those examples are not definitive, because other files with those exact same patterns, and in the same directories, will succeeed.

There does not seem to be any rhyme or reason to what directory or file will cause the EEXIST error. The error typically only happens for the first file path I try to canonicalize, and then not for subsequent ones. However, I cannot kludge around it by merely trying to canonicalize that first file again; the error will keep happening just for it.

Program snippet:

#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>    // for PATH_MAX

using std;

string PathCanonicalize( string const & path )
{
  string result;

  char szResult[ PATH_MAX ];
  ::realpath( path.c_str(), szResult );
  if ( errno == EEXIST )
  {
    // Why?
    cerr << "realpath: error code " << errno << ", " << ::strerror( errno ) << ": '" << path << "'.  Of course the file exists!" << endl;

    result = path;
  }
  else if ( errno )
  {
    cerr << "realpath: error code " << errno << ", " << ::strerror( errno ) << ": '" << path << "'" << endl;

    result = path;
  }
  else
  {
    result = szResult;
  }

  return result;      
}

Solution

  • You should never, ever check errno without a specific reason.

    Perhaps whatever internal operation realpath happened to do last failed with EEXIST. Or maybe errno happened to be EEXIST from some previous operation that failed and realpath didn't change it.

    If this didn't cause realpath to fail, why do you care?

    From your own link:

    Upon successful completion, realpath() shall return a pointer to the resolved name. Otherwise, realpath() shall return a null pointer and set errno to indicate the error, and the contents of the buffer pointed to by resolved_name are undefined.

    Notice it doesn't say that errno is set to anything in particular if realpath succeeds. So why are you checking errno before checking if realpath succeeded?