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:
- An absolute path to a directory:
/alpha/bravo/charlie/delta
- An absolute path to a file:
/alpha/bravo/charlie/foo.txt
- A relative path to a file:
../../charlie/foo.txt
- A path to a file that has a extra dot in it:
/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;
}