1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1985-2011 AT&T Intellectual Property * 5* and is licensed under the * 6* Eclipse Public License, Version 1.0 * 7* by AT&T Intellectual Property * 8* * 9* A copy of the License is available at * 10* http://www.eclipse.org/org/documents/epl-v10.html * 11* (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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 34NoN(getcwd) 35 36#else 37 38#include "FEATURE/syscall" 39 40#if defined(SYSGETCWD) 41 42#include <error.h> 43 44#define ERROR(e) { errno = e; return 0; } 45 46char* 47getcwd(char* buf, size_t len) 48{ 49 size_t n; 50 size_t r; 51 int oerrno; 52 53 if (buf) 54 return SYSGETCWD(buf, len) < 0 ? 0 : buf; 55 oerrno = errno; 56 n = PATH_MAX; 57 for (;;) 58 { 59 if (!(buf = newof(buf, char, n, 0))) 60 ERROR(ENOMEM); 61 if (SYSGETCWD(buf, n) >= 0) 62 { 63 if ((r = strlen(buf) + len + 1) != n && !(buf = newof(buf, char, r, 0))) 64 ERROR(ENOMEM); 65 break; 66 } 67 if (errno != ERANGE) 68 { 69 free(buf); 70 return 0; 71 } 72 n += PATH_MAX / 4; 73 } 74 errno = oerrno; 75 return buf; 76} 77 78#else 79 80#include <ast_dir.h> 81#include <error.h> 82#include <fs3d.h> 83 84#ifndef ERANGE 85#define ERANGE E2BIG 86#endif 87 88#define ERROR(e) { errno = e; goto error; } 89 90struct dirlist /* long path chdir(2) component */ 91{ 92 struct dirlist* next; /* next component */ 93 int index; /* index from end of buf */ 94}; 95 96/* 97 * pop long dir component chdir stack 98 */ 99 100static int 101popdir(register struct dirlist* d, register char* end) 102{ 103 register struct dirlist* dp; 104 int v; 105 106 v = 0; 107 while (dp = d) 108 { 109 d = d->next; 110 if (!v) 111 { 112 if (d) *(end - d->index - 1) = 0; 113 v = chdir(end - dp->index); 114 if (d) *(end - d->index - 1) = '/'; 115 } 116 free(dp); 117 } 118 return v; 119} 120 121/* 122 * push long dir component onto stack 123 */ 124 125static struct dirlist* 126pushdir(register struct dirlist* d, char* dots, char* path, char* end) 127{ 128 register struct dirlist* p; 129 130 if (!(p = newof(0, struct dirlist, 1, 0)) || chdir(dots)) 131 { 132 if (p) free(p); 133 if (d) popdir(d, end); 134 return 0; 135 } 136 p->index = end - path; 137 p->next = d; 138 return p; 139} 140 141/* 142 * return a pointer to the absolute path name of . 143 * this path name may be longer than PATH_MAX 144 * 145 * a few environment variables are checked before the search algorithm 146 * return value is placed in buf of len chars 147 * if buf is 0 then space is allocated via malloc() with 148 * len extra chars after the path name 149 * 0 is returned on error with errno set as appropriate 150 */ 151 152char* 153getcwd(char* buf, size_t len) 154{ 155 register char* d; 156 register char* p; 157 register char* s; 158 DIR* dirp = 0; 159 int n; 160 int x; 161 size_t namlen; 162 ssize_t extra = -1; 163 struct dirent* entry; 164 struct dirlist* dirstk = 0; 165 struct stat* cur; 166 struct stat* par; 167 struct stat* tmp; 168 struct stat curst; 169 struct stat parst; 170 struct stat tstst; 171 char dots[PATH_MAX]; 172 173 static struct 174 { 175 char* name; 176 char* path; 177 dev_t dev; 178 ino_t ino; 179 } env[] = 180 { 181 { /*previous*/0 }, 182 { "PWD" }, 183 { "HOME" }, 184 }; 185 186 if (buf && !len) ERROR(EINVAL); 187 if (fs3d(FS3D_TEST) && (namlen = mount(".", dots, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sizeof(dots)), NiL)) > 1 && namlen < sizeof(dots)) 188 { 189 p = dots; 190 easy: 191 namlen++; 192 if (buf) 193 { 194 if (len < namlen) ERROR(ERANGE); 195 } 196 else if (!(buf = newof(0, char, namlen, len))) ERROR(ENOMEM); 197 return (char*)memcpy(buf, p, namlen); 198 } 199 cur = &curst; 200 par = &parst; 201 if (stat(".", par)) ERROR(errno); 202 for (n = 0; n < elementsof(env); n++) 203 { 204 if ((env[n].name && (p = getenv(env[n].name)) || (p = env[n].path)) && *p == '/' && !stat(p, cur)) 205 { 206 env[n].path = p; 207 env[n].dev = cur->st_dev; 208 env[n].ino = cur->st_ino; 209 if (cur->st_ino == par->st_ino && cur->st_dev == par->st_dev) 210 { 211 namlen = strlen(p); 212 goto easy; 213 } 214 } 215 } 216 if (!buf) 217 { 218 extra = len; 219 len = PATH_MAX; 220 if (!(buf = newof(0, char, len, extra))) ERROR(ENOMEM); 221 } 222 d = dots; 223 p = buf + len - 1; 224 *p = 0; 225 n = elementsof(env); 226 for (;;) 227 { 228 tmp = cur; 229 cur = par; 230 par = tmp; 231 if ((d - dots) > (PATH_MAX - 4)) 232 { 233 if (!(dirstk = pushdir(dirstk, dots, p, buf + len - 1))) ERROR(ERANGE); 234 d = dots; 235 } 236 *d++ = '.'; 237 *d++ = '.'; 238 *d = 0; 239 if (!(dirp = opendir(dots))) ERROR(errno); 240#if !_dir_ok || _mem_dd_fd_DIR 241 if (fstat(dirp->dd_fd, par)) ERROR(errno); 242#else 243 if (stat(dots, par)) ERROR(errno); 244#endif 245 *d++ = '/'; 246 if (par->st_dev == cur->st_dev) 247 { 248 if (par->st_ino == cur->st_ino) 249 { 250 closedir(dirp); 251 *--p = '/'; 252 pop: 253 if (p != buf) 254 { 255 d = buf; 256 while (*d++ = *p++); 257 len = d - buf; 258 if (extra >= 0 && !(buf = newof(buf, char, len, extra))) ERROR(ENOMEM); 259 } 260 if (dirstk && popdir(dirstk, buf + len - 1)) 261 { 262 dirstk = 0; 263 ERROR(errno); 264 } 265 if (env[0].path) 266 free(env[0].path); 267 env[0].path = strdup(buf); 268 return buf; 269 } 270#ifdef D_FILENO 271 while (entry = readdir(dirp)) 272 if (D_FILENO(entry) == cur->st_ino) 273 { 274 namlen = D_NAMLEN(entry); 275 goto found; 276 } 277#endif 278 279 /* 280 * this fallthrough handles logical naming 281 */ 282 283 rewinddir(dirp); 284 } 285 do 286 { 287 if (!(entry = readdir(dirp))) ERROR(ENOENT); 288 namlen = D_NAMLEN(entry); 289 if ((d - dots) > (PATH_MAX - 1 - namlen)) 290 { 291 *d = 0; 292 if (namlen >= PATH_MAX || !(dirstk = pushdir(dirstk, dots + 3, p, buf + len - 1))) ERROR(ERANGE); 293 d = dots + 3; 294 } 295 memcpy(d, entry->d_name, namlen + 1); 296 } while (stat(dots, &tstst) || tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev); 297 found: 298 if (*p) *--p = '/'; 299 while ((p -= namlen) <= (buf + 1)) 300 { 301 x = (buf + len - 1) - (p += namlen); 302 s = buf + len; 303 if (extra < 0 || !(buf = newof(buf, char, len += PATH_MAX, extra))) ERROR(ERANGE); 304 p = buf + len; 305 while (p > buf + len - 1 - x) *--p = *--s; 306 } 307 if (n < elementsof(env)) 308 { 309 memcpy(p, env[n].path, namlen); 310 goto pop; 311 } 312 memcpy(p, entry->d_name, namlen); 313 closedir(dirp); 314 dirp = 0; 315 for (n = 0; n < elementsof(env); n++) 316 if (env[n].ino == par->st_ino && env[n].dev == par->st_dev) 317 { 318 namlen = strlen(env[n].path); 319 goto found; 320 } 321 } 322 error: 323 if (buf) 324 { 325 if (dirstk) popdir(dirstk, buf + len - 1); 326 if (extra >= 0) free(buf); 327 } 328 if (dirp) closedir(dirp); 329 return 0; 330} 331 332#endif 333 334#endif 335