diff options
author | Robert de Bath <rdebath@poboxes.com> | 1996-12-01 16:58:31 +0100 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2013-10-23 23:34:16 +0200 |
commit | f8de35da65c5d93bb733073cf40da154bc1c0748 (patch) | |
tree | d28c7644739a24402376d24cb0020ea410a9ccff /libc/misc/getcwd.c | |
parent | c218c617b5be443b7968308506969ad2b726d73c (diff) | |
download | dev86-f8de35da65c5d93bb733073cf40da154bc1c0748.tar.gz |
Import Dev86src-0.0.9.tar.gzv0.0.9
Diffstat (limited to 'libc/misc/getcwd.c')
-rw-r--r-- | libc/misc/getcwd.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/libc/misc/getcwd.c b/libc/misc/getcwd.c new file mode 100644 index 0000000..351214c --- /dev/null +++ b/libc/misc/getcwd.c @@ -0,0 +1,109 @@ + +#include <errno.h> +#include <sys/stat.h> +#include <dirent.h> +#include <string.h> +/* + * These functions find the absolute path to the current working directory. + * + * They don't use malloc or large amounts of stack space. + */ + +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(buf, size) +char * buf; +int size; +{ + path_buf = buf; + path_size = size; + + if( size < 3 ) { errno = ERANGE; return 0; } + strcpy(path_buf, "."); + + if( stat("/", &st) < 0 ) return 0; + + 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 ) { errno = ERANGE; return 0; } + strcat(path_buf, "/.."); + if( recurser() == 0 ) return 0; + + return search_dir(this_dev, this_ino); +} + +static char * +search_dir(this_dev, this_ino) +dev_t this_dev; +ino_t this_ino; +{ + DIR * dp; + struct dirent * d; + char * ptr; + int slen; + /* 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)); + + if( stat(path_buf, &st) < 0 ) return 0; + if( this_dev != st.st_dev ) slow_search = 1; + + slen = strlen(path_buf); + ptr = path_buf + slen -1; + if( *ptr != '/' ) + { + if( slen + 2 > path_size ) { errno = ERANGE; return 0; } + strcpy(++ptr, "/"); + slen++; + } + slen++; + + dp = opendir(path_buf); + if( dp == 0 ) return 0; + + while( (d=readdir(dp)) != 0 ) + { + if( slow_search || this_ino == d->d_ino ) + { + if( slen + strlen(d->d_name) > path_size ) + { 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; + } + } + } + + closedir(dp); + errno = ENOENT; + return 0; +} |