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