#ifndef CHILON_FILESYSTEM_REALPATH_HPP
#define CHILON_FILESYSTEM_REALPATH_HPP
#include <chilon/iterator_range.hpp>
#include <algorithm>
#include <fcntl.h>
#include <limits.h>
namespace chilon { namespace filesystem {
typedef char realpath_type[PATH_MAX];
/// Like libc's realpath but ignore the last path component and
/// append it to the result.
static char *realpath_new(char const *path, realpath_type& can_path) {
auto path_end = chilon::end(path);
char *realpath_end;
realpath_type realpath_parent;
for (;;--path_end) {
if (path_end == path) {
realpath_parent[0] = '.';
realpath_end = realpath_parent + 1;
break;
}
else if (*path_end == '/') {
std::copy(path, path_end, realpath_parent);
realpath_end = realpath_parent + (path_end - path);
++path_end;
break;
}
}
*realpath_end = '\0';
if (! ::realpath(realpath_parent, can_path))
return 0;
realpath_end = chilon::end(can_path);
*realpath_end = '/';
for (++realpath_end; *path_end != '\0'; ++path_end) {
// TODO: check haven't overflown PATH_MAX
*realpath_end = *path_end;
++realpath_end;
}
*realpath_end = '\0';
return can_path;
}
/// Like libc's realpath but doesn't assume the last path component exists
static inline char *realpath(char const *path, realpath_type& can_path) {
return access(path, F_OK) ?
realpath_new(path, can_path) :
::realpath(path, can_path);
}
} }
#endif