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