libc: add realpath (with ToaruOS path mechanics; not Unix)
This commit is contained in:
parent
a133f3e5af
commit
acdb4a71b9
@ -65,4 +65,9 @@ typedef struct { long int quot; long int rem; } ldiv_t;
|
||||
extern div_t div(int numerator, int denominator);
|
||||
extern ldiv_t ldiv(long numerator, long denominator);
|
||||
|
||||
/* These are supposed to be in limits, but gcc screwed us */
|
||||
#define PATH_MAX 4096
|
||||
#define NAME_MAX 255
|
||||
extern char *realpath(const char *path, char *resolved_path);
|
||||
|
||||
_End_C_Header
|
||||
|
102
libc/stdlib/realpath.c
Normal file
102
libc/stdlib/realpath.c
Normal file
@ -0,0 +1,102 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef __toaru__
|
||||
#undef realpath
|
||||
#define realpath _realpath_toaru
|
||||
#endif
|
||||
|
||||
#define SYMLINK_MAX 5
|
||||
|
||||
static void _append_dir(char *out, char *element) {
|
||||
strcat(out,"/");
|
||||
strcat(out,element);
|
||||
}
|
||||
|
||||
static void _remove_last(char * out) {
|
||||
char * last = strrchr(out,'/');
|
||||
if (last) {
|
||||
*last = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is accurate to how we handle paths in ToaruOS.
|
||||
* It's not correct for real symbolic link handling,
|
||||
* so it needs some work for that.
|
||||
*/
|
||||
char *realpath(const char *path, char *resolved_path) {
|
||||
/*
|
||||
* Basically the same as what we do in the kernel for canonicalize_path
|
||||
* but slightly more complicated because of the requirement to check
|
||||
* symlinks... this is going to get interesting.
|
||||
*/
|
||||
if (!path) {
|
||||
errno = -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!resolved_path) {
|
||||
/* Can't support this yet. */
|
||||
errno = -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If we're lucky, we can do this with no allocations, so let's start here... */
|
||||
char working_path[PATH_MAX+1];
|
||||
memcpy(working_path, path, strlen(path)+1);
|
||||
|
||||
*resolved_path = 0;
|
||||
|
||||
if (working_path[0] != '/') {
|
||||
/* Begin by retreiving the current working directory */
|
||||
char cwd[PATH_MAX+1];
|
||||
if (!getcwd(cwd, PATH_MAX)) {
|
||||
/* Not actually sure if this is the right choice for this, but whatever. */
|
||||
errno = -ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *save;
|
||||
char *tok = strtok_r(cwd,"/",&save);
|
||||
do {
|
||||
_append_dir(resolved_path, tok);
|
||||
} while ((tok = strtok_r(NULL,"/",&save)));
|
||||
}
|
||||
|
||||
char *save;
|
||||
char *tok = strtok_r(working_path,"/",&save);
|
||||
do {
|
||||
if (!strcmp(tok,".")) continue;
|
||||
if (!strcmp(tok,"..")) {
|
||||
_remove_last(resolved_path);
|
||||
continue;
|
||||
} else {
|
||||
_append_dir(resolved_path, tok);
|
||||
}
|
||||
} while ((tok = strtok_r(NULL,"/",&save)));
|
||||
|
||||
if (resolved_path[0] == '\0') {
|
||||
strcat(resolved_path,"/");
|
||||
}
|
||||
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
#ifndef __toaru__
|
||||
int main(int argc, char * argv[]) {
|
||||
char tmp[PATH_MAX+1];
|
||||
|
||||
if (!realpath(argv[1], tmp)) {
|
||||
fprintf(stderr, "invalid path, errno=%d\n", errno);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s=%s\n", argv[1], tmp);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user