diff options
Diffstat (limited to 'dmake/unix/sysvr3/pwd/getcwd.c')
-rw-r--r-- | dmake/unix/sysvr3/pwd/getcwd.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/dmake/unix/sysvr3/pwd/getcwd.c b/dmake/unix/sysvr3/pwd/getcwd.c new file mode 100644 index 000000000000..f2359bcc795b --- /dev/null +++ b/dmake/unix/sysvr3/pwd/getcwd.c @@ -0,0 +1,231 @@ +/* + getcwd -- get pathname of current working directory + + public-domain implementation + + last edit: 03-Nov-1990 Gwyn@BRL.MIL + + complies with the following standards: + IEEE Std 1003.1-1988 + SVID Issue 3 + X/Open Portability Guide Issue 2 (when "XPG2" is defined) + X/Open Portability Guide Issue 3 + + This implementation of getcwd() can be used to replace the UNIX + System V library routine (which uses popen() to capture the output of + the "pwd" command). Once that is done, "pwd" can be reimplemented as + just puts(getcwd((char*)0,0)), assuming "XPG2" is defined below. + + This implementation depends on every directory having entries for + "." and "..". It also depends on the internals of the <dirent.h> + data structures to some degree. + + I considered using chdir() to ascend the hierarchy, followed by a + final chdir() to the path being returned by getcwd() to restore the + location, but decided that error recovery was too difficult that way. + The algorithm I settled on was inspired by my rewrite of the "pwd" + utility, combined with the dotdots[] array trick from the SVR2 shell. +*/ +#define XPG2 /* define to support obsolete XPG2-mandated feature */ + + +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef M_XENIX +# include <sys/ndir.h> +# define dirent direct +#else +# include <dirent.h> +#endif + +#include <errno.h> +#include <string.h> + +typedef char *pointer; /* (void *) if you have it */ + +extern void free(); +extern pointer malloc(); +extern int fstat(), stat(); + +extern int errno; /* normally done by <errno.h> */ + +#ifndef NULL +#define NULL 0 /* amorphous null pointer constant */ +#endif + +#ifndef NAME_MAX +#define NAME_MAX 255 /* maximum directory entry size */ +#endif + + +char * +getcwd( buf, size ) /* returns pointer to CWD pathname */ + char *buf; /* where to put name (NULL to malloc) */ + int size; /* size of buf[] or malloc()ed memory */ + { + static char dotdots[] = +"../../../../../../../../../../../../../../../../../../../../../../../../../.."; + char *dotdot; /* -> dotdots[.], right to left */ + DIR *dirp; /* -> parent directory stream */ + struct dirent *dir; /* -> directory entry */ + struct stat stat1, + stat2; /* info from stat() */ + struct stat *d = &stat1; /* -> info about "." */ + struct stat *dd = &stat2; /* -> info about ".." */ + register char *buffer; /* local copy of buf, or malloc()ed */ + char *bufend; /* -> buffer[size] */ + register char *endp; /* -> end of reversed string */ + register char *dname; /* entry name ("" for root) */ + int serrno = errno; /* save entry errno */ + + if ( buf != NULL && size <= 0 +#ifndef XPG2 + || buf == NULL +#endif + ) { + errno = EINVAL; /* invalid argument */ + return NULL; + } + + buffer = buf; +#ifdef XPG2 + if ( buf == NULL /* wants us to malloc() the string */ + && (buffer = (char *) malloc( (unsigned) size )) == NULL + /* XXX -- actually should probably not pay attention to "size" arg */ + ) { + errno = ENOMEM; /* cannot malloc() specified size */ + return NULL; + } +#endif + + if ( stat( ".", dd ) != 0 ) /* prime the pump */ + goto error; /* errno already set */ + + endp = buffer; /* initially, empty string */ + bufend = &buffer[size]; + + for ( dotdot = &dotdots[sizeof dotdots]; dotdot != dotdots; ) + { + dotdot -= 3; /* include one more "/.." section */ + /* (first time is actually "..") */ + + /* swap stat() info buffers */ + { + register struct stat *temp = d; + + d = dd; /* new current dir is old parent dir */ + dd = temp; + } + + if ( (dirp = opendir( dotdot )) == NULL ) /* new parent */ + goto error; /* errno already set */ + + if ( fstat( dirp->dd_fd, dd ) != 0 ) + { + serrno = errno; /* set by fstat() */ + (void)closedir( dirp ); + errno = serrno; /* in case closedir() clobbered it */ + goto error; + } + + if ( d->st_dev == dd->st_dev ) + { /* not crossing a mount point */ + if ( d->st_ino == dd->st_ino ) + { /* root directory */ + dname = ""; + goto append; + } + + do + if ( (dir = readdir( dirp )) == NULL ) + { + (void)closedir( dirp ); + errno = ENOENT; /* missing entry */ + goto error; + } + while ( dir->d_ino != d->st_ino ); + } + else { /* crossing a mount point */ + struct stat t; /* info re. test entry */ + char name[sizeof dotdots + 1 + NAME_MAX]; + + (void)strcpy( name, dotdot ); + dname = &name[strlen( name )]; + *dname++ = '/'; + + do { + if ( (dir = readdir( dirp )) == NULL ) + { + (void)closedir( dirp ); + errno = ENOENT; /* missing entry */ + goto error; + } + + (void)strcpy( dname, dir->d_name ); + /* must fit if NAME_MAX is not a lie */ + } + while ( stat( name, &t ) != 0 + || t.st_ino != d->st_ino + || t.st_dev != d->st_dev + ); + } + + dname = dir->d_name; + + /* append "/" and reversed dname string onto buffer */ + append: + if ( endp != buffer /* avoid trailing / in final name */ + || dname[0] == '\0' /* but allow "/" when CWD is root */ + ) + *endp++ = '/'; + + { + register char *app; /* traverses dname string */ + + for ( app = dname; *app != '\0'; ++app ) + ; + + if ( app - dname >= bufend - endp ) + { + (void)closedir( dirp ); + errno = ERANGE; /* won't fit allotted space */ + goto error; + } + + while ( app != dname ) + *endp++ = *--app; + } + + (void)closedir( dirp ); + + if ( dname[0] == '\0' ) /* reached root; wrap it up */ + { + register char *startp; /* -> buffer[.] */ + + *endp = '\0'; /* plant null terminator */ + + /* straighten out reversed pathname string */ + for ( startp = buffer; --endp > startp; ++startp ) + { + char temp = *endp; + + *endp = *startp; + *startp = temp; + } + + errno = serrno; /* restore entry errno */ + /* XXX -- if buf==NULL, realloc here? */ + return buffer; + } + } + + errno = ENOMEM; /* actually, algorithm failure */ + + error: + if ( buf == NULL ) + free( (pointer)buffer ); + + return NULL; + } + |