diff options
Diffstat (limited to 'newlib/libc/sys/linux/realpath.c')
-rw-r--r-- | newlib/libc/sys/linux/realpath.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/newlib/libc/sys/linux/realpath.c b/newlib/libc/sys/linux/realpath.c new file mode 100644 index 0000000..8aa5eb4 --- /dev/null +++ b/newlib/libc/sys/linux/realpath.c @@ -0,0 +1,92 @@ +/* realpath.c - Return the canonicalized absolute pathname */ + +/* Written 2000 by Werner Almesberger */ + + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#include <errno.h> +#include <sys/stat.h> + + +/* FIXME: buffer overrun possible, loops forever on cyclic symlinks */ + + +/* + * Canonical name: never ends with a slash + */ + +static int resolve_path(char *path,char *result,char *pos) +{ + if (*path == '/') { + *result = '/'; + pos = result+1; + path++; + } + *pos = 0; + if (!*path) return 0; + while (1) { + char *slash; + struct stat st; + + slash = *path ? strchr(path,'/') : NULL; + if (slash) *slash = 0; + if (!path[0] || (path[0] == '.' && + (!path[1] || (path[1] == '.' && !path[2])))) { + pos--; + if (pos != result && path[0] && path[1]) + while (*--pos != '/'); + } + else { + strcpy(pos,path); + if (lstat(result,&st) < 0) return -1; + if (S_ISLNK(st.st_mode)) { + char buf[PATH_MAX]; + + if (readlink(result,buf,sizeof(buf)) < 0) return -1; + *pos = 0; + if (slash) { + *slash = '/'; + strcat(buf,slash); + } + strcpy(path,buf); + if (*path == '/') result[1] = 0; + pos = strchr(result,0); + continue; + } + pos = strchr(result,0); + } + if (slash) { + *pos++ = '/'; + path = slash+1; + } + *pos = 0; + if (!slash) break; + } + return 0; +} + + +char *realpath(const char *path,char *resolved_path) +{ + char cwd[PATH_MAX]; + char *path_copy; + int res; + + if (!*path) { + errno = ENOENT; /* SUSv2 */ + return NULL; + } + if (!getcwd(cwd,sizeof(cwd))) return NULL; + strcpy(resolved_path,"/"); + if (resolve_path(cwd,resolved_path,resolved_path)) return NULL; + strcat(resolved_path,"/"); + path_copy = strdup(path); + if (!path_copy) return NULL; + res = resolve_path(path_copy,resolved_path,strchr(resolved_path,0)); + free(path_copy); + if (res) return NULL; + return resolved_path; +} |