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:
/alpha/bravo/charlie/delta
/alpha/bravo/charlie/foo.txt
../../charlie/foo.txt
/alpha/bravo/Charlie/./foo.txt
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;
}
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?