|
|
1.1 ! root 1: /* ! 2: getcwd -- get current working directory name (POSIX and SVID compatible) ! 3: ! 4: last edit: 21-Sep-1987 D A Gwyn ! 5: ! 6: This public-domain getcwd() routine can be used to replace the UNIX ! 7: System V library routine (which uses popen() to capture the output of ! 8: the "pwd" command). Once that is done, "pwd" can be reimplemented as ! 9: just puts(getcwd()). ! 10: ! 11: This implementation depends on every directory having entries for ! 12: "." and "..". It also depends on the internals of the <dirent.h> ! 13: data structures to some degree. ! 14: ! 15: I considered using chdir() to ascend the hierarchy, followed by a ! 16: final chdir() to the path being returned by getcwd() to restore the ! 17: location, but decided that error recovery was too difficult that way. ! 18: The algorithm I settled on was inspired by my rewrite of the "pwd" ! 19: utility, combined with the dotdots[] array trick from the SVR2 shell. ! 20: */ ! 21: ! 22: #include <sys/types.h> ! 23: #include <sys/stat.h> ! 24: #include "usr.dirent.h" ! 25: #include <errno.h> ! 26: ! 27: typedef char *pointer; /* (void *) if you have it */ ! 28: ! 29: extern void free(); ! 30: extern pointer malloc(); ! 31: extern int fstat(), stat(); ! 32: ! 33: extern int errno; /* normally done by <errno.h> */ ! 34: ! 35: #ifndef NULL ! 36: #define NULL 0 /* amorphous null pointer constant */ ! 37: #endif ! 38: ! 39: #ifndef NAME_MAX ! 40: #define NAME_MAX 255 /* maximum directory entry size */ ! 41: #endif ! 42: ! 43: char * ! 44: getcwd( buf, size ) /* returns pointer to CWD pathname */ ! 45: char *buf; /* where to put name (NULL to malloc) */ ! 46: int size; /* size of buf[] or malloc()ed memory */ ! 47: { ! 48: static char dotdots[] = ! 49: "../../../../../../../../../../../../../../../../../../../../../../../../../.."; ! 50: char *dotdot; /* -> dotdots[.], right to left */ ! 51: DIR *dirp; /* -> parent directory stream */ ! 52: struct dirent *dir; /* -> directory entry */ ! 53: struct stat stat1, stat2; /* info from stat() */ ! 54: struct stat *d = &stat1; /* -> info about "." */ ! 55: struct stat *dd = &stat2; /* -> info about ".." */ ! 56: register char *buffer; /* local copy of buf, or malloc()ed */ ! 57: char *bufend; /* -> buffer[size] */ ! 58: register char *endp; /* -> end of reversed string */ ! 59: register char *dname; /* entry name ("" for root) */ ! 60: int serrno = errno; /* save entry errno */ ! 61: ! 62: if ( size == 0 ) ! 63: { ! 64: errno = EINVAL; /* invalid argument */ ! 65: return NULL; ! 66: } ! 67: ! 68: if ( (buffer = buf) == NULL /* wants us to malloc() the string */ ! 69: && (buffer = (char *)malloc( (unsigned)size )) == NULL ! 70: ) { ! 71: errno = ENOMEM; /* cannot malloc() specified size */ ! 72: return NULL; ! 73: } ! 74: ! 75: if ( stat( ".", dd ) != 0 ) /* prime the pump */ ! 76: goto error; /* errno already set */ ! 77: ! 78: endp = buffer; /* initially, empty string */ ! 79: bufend = &buffer[size]; ! 80: ! 81: for ( dotdot = &dotdots[sizeof(dotdots)]; dotdot != dotdots; ) ! 82: { ! 83: dotdot -= 3; /* include one more "/.." section */ ! 84: /* (first time is actually "..") */ ! 85: ! 86: /* swap stat() info buffers */ ! 87: { ! 88: register struct stat *temp = d; ! 89: ! 90: d = dd; /* new current dir is old parent dir */ ! 91: dd = temp; ! 92: } ! 93: ! 94: if ( (dirp = opendir( dotdot )) == NULL ) /* new parent */ ! 95: goto error; /* errno already set */ ! 96: ! 97: if ( fstat( dirp->dd_fd, dd ) != 0 ) ! 98: { ! 99: serrno = errno; /* set by fstat() */ ! 100: (void)closedir( dirp ); ! 101: errno = serrno; /* in case closedir() clobbered it */ ! 102: goto error; ! 103: } ! 104: ! 105: if ( d->st_dev == dd->st_dev ) ! 106: { /* not crossing a mount point */ ! 107: if ( d->st_ino == dd->st_ino ) ! 108: { /* root directory */ ! 109: dname = ""; ! 110: goto append; ! 111: } ! 112: ! 113: do ! 114: if ( (dir = readdir( dirp )) == NULL ) ! 115: { ! 116: (void)closedir( dirp ); ! 117: errno = ENOENT; /* missing entry */ ! 118: goto error; ! 119: } ! 120: while ( dir->d_ino != d->st_ino ); ! 121: } ! 122: else { /* crossing a mount point */ ! 123: struct stat t; /* info re. test entry */ ! 124: char name[sizeof(dotdots) + 1 + NAME_MAX]; ! 125: ! 126: (void)strcpy( name, dotdot ); ! 127: dname = &name[strlen( name )]; ! 128: *dname++ = '/'; ! 129: ! 130: do { ! 131: if ( (dir = readdir( dirp )) == NULL ) ! 132: { ! 133: (void)closedir( dirp ); ! 134: errno = ENOENT; /* missing entry */ ! 135: goto error; ! 136: } ! 137: ! 138: (void)strcpy( dname, dir->d_name ); ! 139: /* must fit if NAME_MAX is not a lie */ ! 140: } ! 141: while ( stat( name, &t ) != 0 ! 142: || t.st_ino != d->st_ino ! 143: || t.st_dev != d->st_dev ! 144: ); ! 145: } ! 146: ! 147: dname = dir->d_name; ! 148: ! 149: /* append "/" and reversed dname string onto buffer */ ! 150: append: ! 151: if ( endp != buffer /* avoid trailing / in final name */ ! 152: || dname[0] == '\0' /* but allow "/" when CWD is root */ ! 153: ) ! 154: *endp++ = '/'; ! 155: ! 156: { ! 157: register char *app; /* traverses dname string */ ! 158: ! 159: for ( app = dname; *app != '\0'; ++app ) ! 160: ; ! 161: ! 162: if ( app - dname >= bufend - endp ) ! 163: { ! 164: (void)closedir( dirp ); ! 165: errno = ERANGE; /* won't fit allotted space */ ! 166: goto error; ! 167: } ! 168: ! 169: while ( app != dname ) ! 170: *endp++ = *--app; ! 171: } ! 172: ! 173: (void)closedir( dirp ); ! 174: ! 175: if ( dname[0] == '\0' ) /* reached root; wrap it up */ ! 176: { ! 177: register char *startp; /* -> buffer[.] */ ! 178: ! 179: *endp = '\0'; /* plant null terminator */ ! 180: ! 181: /* straighten out reversed pathname string */ ! 182: for ( startp = buffer; --endp > startp; ++startp ) ! 183: { ! 184: char temp = *endp; ! 185: ! 186: *endp = *startp; ! 187: *startp = temp; ! 188: } ! 189: ! 190: errno = serrno; /* restore entry errno */ ! 191: return buffer; ! 192: } ! 193: } ! 194: ! 195: errno = ENOMEM; /* actually, algorithm failure */ ! 196: ! 197: error: ! 198: if ( buf == NULL ) ! 199: free( (pointer)buffer ); ! 200: ! 201: return NULL; ! 202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.