|
|
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.