diff options
-rw-r--r-- | libc/sysdeps/linux/common/syscalls.c | 8 | ||||
-rw-r--r-- | libc/unistd/getcwd.c | 134 |
2 files changed, 72 insertions, 70 deletions
diff --git a/libc/sysdeps/linux/common/syscalls.c b/libc/sysdeps/linux/common/syscalls.c index 5d826927e..542ec1b96 100644 --- a/libc/sysdeps/linux/common/syscalls.c +++ b/libc/sysdeps/linux/common/syscalls.c @@ -1613,7 +1613,13 @@ _syscall3(int, chown, const char *, path, uid_t, owner, gid_t, group); #endif //#define __NR_getcwd 183 -// See unistd/getcwd.c -- we don't use this syscall, even when it is available... +#ifdef L_getcwd +# ifdef __NR_getcwd + _syscall2(int, getcwd, char *, buf, unsigned long, size); +# else +// See unistd/getcwd.c if this syscall is not available... +# endif +#endif //#define __NR_capget 184 #ifdef L_capget diff --git a/libc/unistd/getcwd.c b/libc/unistd/getcwd.c index b5bfeaae8..fd1e29445 100644 --- a/libc/unistd/getcwd.c +++ b/libc/unistd/getcwd.c @@ -1,85 +1,25 @@ +/* These functions find the absolute path to the current working directory. */ + #include <stdlib.h> #include <errno.h> #include <sys/stat.h> #include <dirent.h> #include <string.h> +#include <sys/syscall.h> -/* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */ - - -/* These functions find the absolute path to the current working directory. */ - -static char *recurser(); /* Routine to go up tree */ -static char *search_dir(); /* Routine to find the step back down */ -static char *path_buf; -static int path_size; - -static dev_t root_dev; -static ino_t root_ino; - -static struct stat st; - -char *getcwd( char *buf, int size) -{ - path_size = size; - - if (size < 3) { - __set_errno(ERANGE); - return NULL; - } - - if (buf != NULL) - path_buf = buf; - else - { - path_buf = malloc (size); - if (path_buf == NULL) - return NULL; - } - - strcpy(path_buf, "."); - - if (stat("/", &st) < 0) - return NULL; - - root_dev = st.st_dev; - root_ino = st.st_ino; - - return recurser(); -} - -static char *recurser() -{ - dev_t this_dev; - ino_t this_ino; - - if (stat(path_buf, &st) < 0) - return 0; - this_dev = st.st_dev; - this_ino = st.st_ino; - if (this_dev == root_dev && this_ino == root_ino) { - strcpy(path_buf, "/"); - return path_buf; - } - if (strlen(path_buf) + 4 > path_size) { - __set_errno(ERANGE); - return 0; - } - strcat(path_buf, "/.."); - if (recurser() == 0) - return 0; +/* if the syscall is not present, we have to recurse up */ +#ifndef __NR_getcwd - return search_dir(this_dev, this_ino); -} +/* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */ -static char *search_dir(this_dev, this_ino) -dev_t this_dev; -ino_t this_ino; +/* Routine to find the step back down */ +static char *search_dir(dev_t this_dev, ino_t this_ino, char *path_buf, int path_size) { DIR *dp; struct dirent *d; char *ptr; int slen; + struct stat st; #ifdef FAST_DIR_SEARCH_POSSIBLE /* The test is for ELKS lib 0.0.9, this should be fixed in the real kernel */ @@ -133,3 +73,59 @@ ino_t this_ino; __set_errno(ENOENT); return 0; } + +/* Routine to go up tree */ +static char *recurser(char *path_buf, int path_size, dev_t root_dev, ino_t root_ino) +{ + struct stat st; + dev_t this_dev; + ino_t this_ino; + + if (stat(path_buf, &st) < 0) + return 0; + this_dev = st.st_dev; + this_ino = st.st_ino; + if (this_dev == root_dev && this_ino == root_ino) { + strcpy(path_buf, "/"); + return path_buf; + } + if (strlen(path_buf) + 4 > path_size) { + __set_errno(ERANGE); + return 0; + } + strcat(path_buf, "/.."); + if (recurser(path_buf, path_size, root_dev, root_ino) == 0) + return 0; + + return search_dir(this_dev, this_ino, path_buf, path_size); +} + + +char *getcwd(char *buf, int size) +{ + struct stat st; + + if (size == 0) { + __set_errno(EINVAL); + return NULL; + } + if (size < 3) { + __set_errno(ERANGE); + return NULL; + } + + if (buf == NULL) { + buf = malloc (size); + if (buf == NULL) + return NULL; + } + + strcpy(buf, "."); + if (stat("/", &st) < 0) { + return NULL; + } + + return recurser(buf, size, st.st_dev, st.st_ino); +} + +#endif |