From b8d09d7cfc7a5aec2d510335313c0e5470df37c1 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Tue, 18 Jun 2002 20:43:49 +0000 Subject: Cleanup the getcwd implementation (again) since I broke it last night. Restore malloc-ing when buf=NULL for the syscall version... Move getcwd to libc/sysdeps/linux/common and out of syscalls.c so there is just one getcwd.o object present. -Erik --- libc/sysdeps/linux/common/Makefile | 2 +- libc/sysdeps/linux/common/getcwd.c | 172 +++++++++++++++++++++++++++++++++++ libc/sysdeps/linux/common/syscalls.c | 8 +- libc/unistd/Makefile | 2 +- libc/unistd/getcwd.c | 131 -------------------------- 5 files changed, 175 insertions(+), 140 deletions(-) create mode 100644 libc/sysdeps/linux/common/getcwd.c delete mode 100644 libc/unistd/getcwd.c (limited to 'libc') diff --git a/libc/sysdeps/linux/common/Makefile b/libc/sysdeps/linux/common/Makefile index e3098f409..a7a254cc5 100644 --- a/libc/sysdeps/linux/common/Makefile +++ b/libc/sysdeps/linux/common/Makefile @@ -29,7 +29,7 @@ ifeq ($(strip $(DOPIC)),true) SAFECFLAGS+=-fPIC endif -CSRC= waitpid.c statfix.c getdnnm.c gethstnm.c \ +CSRC= waitpid.c statfix.c getdnnm.c gethstnm.c getcwd.c \ mkfifo.c setegid.c wait.c getpagesize.c seteuid.c \ wait3.c setpgrp.c getdtablesize.c create_module.c ptrace.c \ cmsg_nxthdr.c statfix64.c longjmp.c open64.c ftruncate64.c \ diff --git a/libc/sysdeps/linux/common/getcwd.c b/libc/sysdeps/linux/common/getcwd.c new file mode 100644 index 000000000..1ec00a36e --- /dev/null +++ b/libc/sysdeps/linux/common/getcwd.c @@ -0,0 +1,172 @@ +/* These functions find the absolute path to the current working directory. */ + +#include +#include +#include +#include +#include +#include + +#ifdef __NR_getcwd +#define __NR___getcwd __NR_getcwd +static inline _syscall2(int, __getcwd, char *, buf, unsigned long, size); + +char *getcwd(char *buf, int size) +{ + int olderrno, ret; + char *allocbuf; + + if (size == 0) { + __set_errno(EINVAL); + return NULL; + } + if (size < 3) { + __set_errno(ERANGE); + return NULL; + } + allocbuf=NULL; + olderrno = errno; + if (buf == NULL) { + buf = allocbuf = malloc (size); + if (buf == NULL) + return NULL; + } + ret = __getcwd(buf, size); + if (ret < 0) { + if (allocbuf) { + free(allocbuf); + } + return NULL; + } + __set_errno(olderrno); + return buf; +} +#else + +/* If the syscall is not present, we have to walk up the + * directory tree till we hit the root. Now we _could_ + * use /proc/self/cwd if /proc is mounted... That approach + * is left an an exercise for the reader... */ + + +/* Seems a few broken filesystems (like coda) don't like this */ +/* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */ + + +/* 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 */ + int slow_search = (sizeof(ino_t) != sizeof(d->d_ino)); +#endif + + if (stat(path_buf, &st) < 0) + return 0; +#ifdef FAST_DIR_SEARCH_POSSIBLE + if (this_dev != st.st_dev) + slow_search = 1; +#endif + + slen = strlen(path_buf); + ptr = path_buf + slen - 1; + if (*ptr != '/') { + if (slen + 2 > path_size) { + __set_errno(ERANGE); + return 0; + } + strcpy(++ptr, "/"); + slen++; + } + slen++; + + dp = opendir(path_buf); + if (dp == 0) + return 0; + + while ((d = readdir(dp)) != 0) { +#ifdef FAST_DIR_SEARCH_POSSIBLE + if (slow_search || this_ino == d->d_ino) { +#endif + if (slen + strlen(d->d_name) > path_size) { + __set_errno(ERANGE); + return 0; + } + strcpy(ptr + 1, d->d_name); + if (stat(path_buf, &st) < 0) + continue; + if (st.st_ino == this_ino && st.st_dev == this_dev) { + closedir(dp); + return path_buf; + } +#ifdef FAST_DIR_SEARCH_POSSIBLE + } +#endif + } + + closedir(dp); + __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 diff --git a/libc/sysdeps/linux/common/syscalls.c b/libc/sysdeps/linux/common/syscalls.c index 542ec1b96..db17d045d 100644 --- a/libc/sysdeps/linux/common/syscalls.c +++ b/libc/sysdeps/linux/common/syscalls.c @@ -1613,13 +1613,7 @@ _syscall3(int, chown, const char *, path, uid_t, owner, gid_t, group); #endif //#define __NR_getcwd 183 -#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 +// See getcwd.c in this directory //#define __NR_capget 184 #ifdef L_capget diff --git a/libc/unistd/Makefile b/libc/unistd/Makefile index ee340214d..fbb35fbe5 100644 --- a/libc/unistd/Makefile +++ b/libc/unistd/Makefile @@ -25,7 +25,7 @@ TOPDIR=../../ include $(TOPDIR)Rules.mak DIRS:= -CSRC=execl.c execlp.c execv.c execvep.c execvp.c execle.c getcwd.c \ +CSRC=execl.c execlp.c execv.c execvep.c execvp.c execle.c \ sleep.c usleep.c getpass.c sysconf_src.c getlogin.c \ fpathconf.c confstr.c pathconf.c swab.c usershell.c ifeq ($(strip $(HAS_MMU)),true) diff --git a/libc/unistd/getcwd.c b/libc/unistd/getcwd.c deleted file mode 100644 index fd1e29445..000000000 --- a/libc/unistd/getcwd.c +++ /dev/null @@ -1,131 +0,0 @@ -/* These functions find the absolute path to the current working directory. */ - -#include -#include -#include -#include -#include -#include - -/* if the syscall is not present, we have to recurse up */ -#ifndef __NR_getcwd - -/* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */ - -/* 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 */ - int slow_search = (sizeof(ino_t) != sizeof(d->d_ino)); -#endif - - if (stat(path_buf, &st) < 0) - return 0; -#ifdef FAST_DIR_SEARCH_POSSIBLE - if (this_dev != st.st_dev) - slow_search = 1; -#endif - - slen = strlen(path_buf); - ptr = path_buf + slen - 1; - if (*ptr != '/') { - if (slen + 2 > path_size) { - __set_errno(ERANGE); - return 0; - } - strcpy(++ptr, "/"); - slen++; - } - slen++; - - dp = opendir(path_buf); - if (dp == 0) - return 0; - - while ((d = readdir(dp)) != 0) { -#ifdef FAST_DIR_SEARCH_POSSIBLE - if (slow_search || this_ino == d->d_ino) { -#endif - if (slen + strlen(d->d_name) > path_size) { - __set_errno(ERANGE); - return 0; - } - strcpy(ptr + 1, d->d_name); - if (stat(path_buf, &st) < 0) - continue; - if (st.st_ino == this_ino && st.st_dev == this_dev) { - closedir(dp); - return path_buf; - } -#ifdef FAST_DIR_SEARCH_POSSIBLE - } -#endif - } - - closedir(dp); - __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 -- cgit v1.2.3