1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2008 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 /* 24 * Glenn Fowler 25 * AT&T Research 26 * 27 * pwd library support 28 */ 29 30 #include <ast.h> 31 32 #if _WINIX 33 34 NoN(getcwd) 35 36 #else 37 38 #include <ast_dir.h> 39 #include <error.h> 40 #include <fs3d.h> 41 42 #ifndef ERANGE 43 #define ERANGE E2BIG 44 #endif 45 46 #define ERROR(e) { errno = e; goto error; } 47 48 struct dirlist /* long path chdir(2) component */ 49 { 50 struct dirlist* next; /* next component */ 51 int index; /* index from end of buf */ 52 }; 53 54 /* 55 * pop long dir component chdir stack 56 */ 57 58 static int 59 popdir(register struct dirlist* d, register char* end) 60 { 61 register struct dirlist* dp; 62 int v; 63 64 v = 0; 65 while (dp = d) 66 { 67 d = d->next; 68 if (!v) 69 { 70 if (d) *(end - d->index - 1) = 0; 71 v = chdir(end - dp->index); 72 if (d) *(end - d->index - 1) = '/'; 73 } 74 free(dp); 75 } 76 return v; 77 } 78 79 /* 80 * push long dir component onto stack 81 */ 82 83 static struct dirlist* 84 pushdir(register struct dirlist* d, char* dots, char* path, char* end) 85 { 86 register struct dirlist* p; 87 88 if (!(p = newof(0, struct dirlist, 1, 0)) || chdir(dots)) 89 { 90 if (p) free(p); 91 if (d) popdir(d, end); 92 return 0; 93 } 94 p->index = end - path; 95 p->next = d; 96 return p; 97 } 98 99 /* 100 * return a pointer to the absolute path name of . 101 * this path name may be longer than PATH_MAX 102 * 103 * a few environment variables are checked before the search algorithm 104 * return value is placed in buf of len chars 105 * if buf is 0 then space is allocated via malloc() with 106 * len extra chars after the path name 107 * 0 is returned on error with errno set as appropriate 108 */ 109 110 char* 111 getcwd(char* buf, size_t len) 112 { 113 register char* d; 114 register char* p; 115 register char* s; 116 DIR* dirp = 0; 117 int n; 118 int x; 119 size_t namlen; 120 ssize_t extra = -1; 121 struct dirent* entry; 122 struct dirlist* dirstk = 0; 123 struct stat* cur; 124 struct stat* par; 125 struct stat* tmp; 126 struct stat curst; 127 struct stat parst; 128 struct stat tstst; 129 char dots[PATH_MAX]; 130 131 static struct 132 { 133 char* name; 134 char* path; 135 dev_t dev; 136 ino_t ino; 137 } env[] = 138 { 139 { /*previous*/0 }, 140 { "PWD" }, 141 { "HOME" }, 142 }; 143 144 if (buf && !len) ERROR(EINVAL); 145 if (fs3d(FS3D_TEST) && (namlen = mount(".", dots, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sizeof(dots)), NiL)) > 1 && namlen < sizeof(dots)) 146 { 147 p = dots; 148 easy: 149 namlen++; 150 if (buf) 151 { 152 if (len < namlen) ERROR(ERANGE); 153 } 154 else if (!(buf = newof(0, char, namlen, len))) ERROR(ENOMEM); 155 return (char*)memcpy(buf, p, namlen); 156 } 157 cur = &curst; 158 par = &parst; 159 if (stat(".", par)) ERROR(errno); 160 for (n = 0; n < elementsof(env); n++) 161 { 162 if ((env[n].name && (p = getenv(env[n].name)) || (p = env[n].path)) && *p == '/' && !stat(p, cur)) 163 { 164 env[n].path = p; 165 env[n].dev = cur->st_dev; 166 env[n].ino = cur->st_ino; 167 if (cur->st_ino == par->st_ino && cur->st_dev == par->st_dev) 168 { 169 namlen = strlen(p); 170 goto easy; 171 } 172 } 173 } 174 if (!buf) 175 { 176 extra = len; 177 len = PATH_MAX; 178 if (!(buf = newof(0, char, len, extra))) ERROR(ENOMEM); 179 } 180 d = dots; 181 p = buf + len - 1; 182 *p = 0; 183 n = elementsof(env); 184 for (;;) 185 { 186 tmp = cur; 187 cur = par; 188 par = tmp; 189 if ((d - dots) > (PATH_MAX - 4)) 190 { 191 if (!(dirstk = pushdir(dirstk, dots, p, buf + len - 1))) ERROR(ERANGE); 192 d = dots; 193 } 194 *d++ = '.'; 195 *d++ = '.'; 196 *d = 0; 197 if (!(dirp = opendir(dots))) ERROR(errno); 198 #if !_dir_ok || _mem_dd_fd_DIR 199 if (fstat(dirp->dd_fd, par)) ERROR(errno); 200 #else 201 if (stat(dots, par)) ERROR(errno); 202 #endif 203 *d++ = '/'; 204 if (par->st_dev == cur->st_dev) 205 { 206 if (par->st_ino == cur->st_ino) 207 { 208 closedir(dirp); 209 *--p = '/'; 210 pop: 211 if (p != buf) 212 { 213 d = buf; 214 while (*d++ = *p++); 215 len = d - buf; 216 if (extra >= 0 && !(buf = newof(buf, char, len, extra))) ERROR(ENOMEM); 217 } 218 if (dirstk && popdir(dirstk, buf + len - 1)) 219 { 220 dirstk = 0; 221 ERROR(errno); 222 } 223 if (env[0].path) 224 free(env[0].path); 225 env[0].path = strdup(buf); 226 return buf; 227 } 228 #ifdef D_FILENO 229 while (entry = readdir(dirp)) 230 if (D_FILENO(entry) == cur->st_ino) 231 { 232 namlen = D_NAMLEN(entry); 233 goto found; 234 } 235 #endif 236 237 /* 238 * this fallthrough handles logical naming 239 */ 240 241 rewinddir(dirp); 242 } 243 do 244 { 245 if (!(entry = readdir(dirp))) ERROR(ENOENT); 246 namlen = D_NAMLEN(entry); 247 if ((d - dots) > (PATH_MAX - 1 - namlen)) 248 { 249 *d = 0; 250 if (namlen >= PATH_MAX || !(dirstk = pushdir(dirstk, dots + 3, p, buf + len - 1))) ERROR(ERANGE); 251 d = dots + 3; 252 } 253 memcpy(d, entry->d_name, namlen + 1); 254 } while (stat(dots, &tstst) || tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev); 255 found: 256 if (*p) *--p = '/'; 257 while ((p -= namlen) <= (buf + 1)) 258 { 259 x = (buf + len - 1) - (p += namlen); 260 s = buf + len; 261 if (extra < 0 || !(buf = newof(buf, char, len += PATH_MAX, extra))) ERROR(ERANGE); 262 p = buf + len; 263 while (p > buf + len - 1 - x) *--p = *--s; 264 } 265 if (n < elementsof(env)) 266 { 267 memcpy(p, env[n].path, namlen); 268 goto pop; 269 } 270 memcpy(p, entry->d_name, namlen); 271 closedir(dirp); 272 dirp = 0; 273 for (n = 0; n < elementsof(env); n++) 274 if (env[n].ino == par->st_ino && env[n].dev == par->st_dev) 275 { 276 namlen = strlen(env[n].path); 277 goto found; 278 } 279 } 280 error: 281 if (buf) 282 { 283 if (dirstk) popdir(dirstk, buf + len - 1); 284 if (extra >= 0) free(buf); 285 } 286 if (dirp) closedir(dirp); 287 return 0; 288 } 289 290 #endif 291