1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1985-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* Phong Vo <kpv@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * Glenn Fowler
1N/A * AT&T Research
1N/A *
1N/A * pwd library support
1N/A */
1N/A
1N/A#include <ast.h>
1N/A
1N/A#if _WINIX
1N/A
1N/ANoN(getcwd)
1N/A
1N/A#else
1N/A
1N/A#include "FEATURE/syscall"
1N/A
1N/A#if defined(SYSGETCWD)
1N/A
1N/A#include <error.h>
1N/A
1N/A#define ERROR(e) { errno = e; return 0; }
1N/A
1N/Achar*
1N/Agetcwd(char* buf, size_t len)
1N/A{
1N/A size_t n;
1N/A size_t r;
1N/A int oerrno;
1N/A
1N/A if (buf)
1N/A return SYSGETCWD(buf, len) < 0 ? 0 : buf;
1N/A oerrno = errno;
1N/A n = PATH_MAX;
1N/A for (;;)
1N/A {
1N/A if (!(buf = newof(buf, char, n, 0)))
1N/A ERROR(ENOMEM);
1N/A if (SYSGETCWD(buf, n) >= 0)
1N/A {
1N/A if ((r = strlen(buf) + len + 1) != n && !(buf = newof(buf, char, r, 0)))
1N/A ERROR(ENOMEM);
1N/A break;
1N/A }
1N/A if (errno != ERANGE)
1N/A {
1N/A free(buf);
1N/A return 0;
1N/A }
1N/A n += PATH_MAX / 4;
1N/A }
1N/A errno = oerrno;
1N/A return buf;
1N/A}
1N/A
1N/A#else
1N/A
1N/A#include <ast_dir.h>
1N/A#include <error.h>
1N/A#include <fs3d.h>
1N/A
1N/A#ifndef ERANGE
1N/A#define ERANGE E2BIG
1N/A#endif
1N/A
1N/A#define ERROR(e) { errno = e; goto error; }
1N/A
1N/Astruct dirlist /* long path chdir(2) component */
1N/A{
1N/A struct dirlist* next; /* next component */
1N/A int index; /* index from end of buf */
1N/A};
1N/A
1N/A/*
1N/A * pop long dir component chdir stack
1N/A */
1N/A
1N/Astatic int
1N/Apopdir(register struct dirlist* d, register char* end)
1N/A{
1N/A register struct dirlist* dp;
1N/A int v;
1N/A
1N/A v = 0;
1N/A while (dp = d)
1N/A {
1N/A d = d->next;
1N/A if (!v)
1N/A {
1N/A if (d) *(end - d->index - 1) = 0;
1N/A v = chdir(end - dp->index);
1N/A if (d) *(end - d->index - 1) = '/';
1N/A }
1N/A free(dp);
1N/A }
1N/A return v;
1N/A}
1N/A
1N/A/*
1N/A * push long dir component onto stack
1N/A */
1N/A
1N/Astatic struct dirlist*
1N/Apushdir(register struct dirlist* d, char* dots, char* path, char* end)
1N/A{
1N/A register struct dirlist* p;
1N/A
1N/A if (!(p = newof(0, struct dirlist, 1, 0)) || chdir(dots))
1N/A {
1N/A if (p) free(p);
1N/A if (d) popdir(d, end);
1N/A return 0;
1N/A }
1N/A p->index = end - path;
1N/A p->next = d;
1N/A return p;
1N/A}
1N/A
1N/A/*
1N/A * return a pointer to the absolute path name of .
1N/A * this path name may be longer than PATH_MAX
1N/A *
1N/A * a few environment variables are checked before the search algorithm
1N/A * return value is placed in buf of len chars
1N/A * if buf is 0 then space is allocated via malloc() with
1N/A * len extra chars after the path name
1N/A * 0 is returned on error with errno set as appropriate
1N/A */
1N/A
1N/Achar*
1N/Agetcwd(char* buf, size_t len)
1N/A{
1N/A register char* d;
1N/A register char* p;
1N/A register char* s;
1N/A DIR* dirp = 0;
1N/A int n;
1N/A int x;
1N/A size_t namlen;
1N/A ssize_t extra = -1;
1N/A struct dirent* entry;
1N/A struct dirlist* dirstk = 0;
1N/A struct stat* cur;
1N/A struct stat* par;
1N/A struct stat* tmp;
1N/A struct stat curst;
1N/A struct stat parst;
1N/A struct stat tstst;
1N/A char dots[PATH_MAX];
1N/A
1N/A static struct
1N/A {
1N/A char* name;
1N/A char* path;
1N/A dev_t dev;
1N/A ino_t ino;
1N/A } env[] =
1N/A {
1N/A { /*previous*/0 },
1N/A { "PWD" },
1N/A { "HOME" },
1N/A };
1N/A
1N/A if (buf && !len) ERROR(EINVAL);
1N/A if (fs3d(FS3D_TEST) && (namlen = mount(".", dots, FS3D_GET|FS3D_VIEW|FS3D_SIZE(sizeof(dots)), NiL)) > 1 && namlen < sizeof(dots))
1N/A {
1N/A p = dots;
1N/A easy:
1N/A namlen++;
1N/A if (buf)
1N/A {
1N/A if (len < namlen) ERROR(ERANGE);
1N/A }
1N/A else if (!(buf = newof(0, char, namlen, len))) ERROR(ENOMEM);
1N/A return (char*)memcpy(buf, p, namlen);
1N/A }
1N/A cur = &curst;
1N/A par = &parst;
1N/A if (stat(".", par)) ERROR(errno);
1N/A for (n = 0; n < elementsof(env); n++)
1N/A {
1N/A if ((env[n].name && (p = getenv(env[n].name)) || (p = env[n].path)) && *p == '/' && !stat(p, cur))
1N/A {
1N/A env[n].path = p;
1N/A env[n].dev = cur->st_dev;
1N/A env[n].ino = cur->st_ino;
1N/A if (cur->st_ino == par->st_ino && cur->st_dev == par->st_dev)
1N/A {
1N/A namlen = strlen(p);
1N/A goto easy;
1N/A }
1N/A }
1N/A }
1N/A if (!buf)
1N/A {
1N/A extra = len;
1N/A len = PATH_MAX;
1N/A if (!(buf = newof(0, char, len, extra))) ERROR(ENOMEM);
1N/A }
1N/A d = dots;
1N/A p = buf + len - 1;
1N/A *p = 0;
1N/A n = elementsof(env);
1N/A for (;;)
1N/A {
1N/A tmp = cur;
1N/A cur = par;
1N/A par = tmp;
1N/A if ((d - dots) > (PATH_MAX - 4))
1N/A {
1N/A if (!(dirstk = pushdir(dirstk, dots, p, buf + len - 1))) ERROR(ERANGE);
1N/A d = dots;
1N/A }
1N/A *d++ = '.';
1N/A *d++ = '.';
1N/A *d = 0;
1N/A if (!(dirp = opendir(dots))) ERROR(errno);
1N/A#if !_dir_ok || _mem_dd_fd_DIR
1N/A if (fstat(dirp->dd_fd, par)) ERROR(errno);
1N/A#else
1N/A if (stat(dots, par)) ERROR(errno);
1N/A#endif
1N/A *d++ = '/';
1N/A if (par->st_dev == cur->st_dev)
1N/A {
1N/A if (par->st_ino == cur->st_ino)
1N/A {
1N/A closedir(dirp);
1N/A *--p = '/';
1N/A pop:
1N/A if (p != buf)
1N/A {
1N/A d = buf;
1N/A while (*d++ = *p++);
1N/A len = d - buf;
1N/A if (extra >= 0 && !(buf = newof(buf, char, len, extra))) ERROR(ENOMEM);
1N/A }
1N/A if (dirstk && popdir(dirstk, buf + len - 1))
1N/A {
1N/A dirstk = 0;
1N/A ERROR(errno);
1N/A }
1N/A if (env[0].path)
1N/A free(env[0].path);
1N/A env[0].path = strdup(buf);
1N/A return buf;
1N/A }
1N/A#ifdef D_FILENO
1N/A while (entry = readdir(dirp))
1N/A if (D_FILENO(entry) == cur->st_ino)
1N/A {
1N/A namlen = D_NAMLEN(entry);
1N/A goto found;
1N/A }
1N/A#endif
1N/A
1N/A /*
1N/A * this fallthrough handles logical naming
1N/A */
1N/A
1N/A rewinddir(dirp);
1N/A }
1N/A do
1N/A {
1N/A if (!(entry = readdir(dirp))) ERROR(ENOENT);
1N/A namlen = D_NAMLEN(entry);
1N/A if ((d - dots) > (PATH_MAX - 1 - namlen))
1N/A {
1N/A *d = 0;
1N/A if (namlen >= PATH_MAX || !(dirstk = pushdir(dirstk, dots + 3, p, buf + len - 1))) ERROR(ERANGE);
1N/A d = dots + 3;
1N/A }
1N/A memcpy(d, entry->d_name, namlen + 1);
1N/A } while (stat(dots, &tstst) || tstst.st_ino != cur->st_ino || tstst.st_dev != cur->st_dev);
1N/A found:
1N/A if (*p) *--p = '/';
1N/A while ((p -= namlen) <= (buf + 1))
1N/A {
1N/A x = (buf + len - 1) - (p += namlen);
1N/A s = buf + len;
1N/A if (extra < 0 || !(buf = newof(buf, char, len += PATH_MAX, extra))) ERROR(ERANGE);
1N/A p = buf + len;
1N/A while (p > buf + len - 1 - x) *--p = *--s;
1N/A }
1N/A if (n < elementsof(env))
1N/A {
1N/A memcpy(p, env[n].path, namlen);
1N/A goto pop;
1N/A }
1N/A memcpy(p, entry->d_name, namlen);
1N/A closedir(dirp);
1N/A dirp = 0;
1N/A for (n = 0; n < elementsof(env); n++)
1N/A if (env[n].ino == par->st_ino && env[n].dev == par->st_dev)
1N/A {
1N/A namlen = strlen(env[n].path);
1N/A goto found;
1N/A }
1N/A }
1N/A error:
1N/A if (buf)
1N/A {
1N/A if (dirstk) popdir(dirstk, buf + len - 1);
1N/A if (extra >= 0) free(buf);
1N/A }
1N/A if (dirp) closedir(dirp);
1N/A return 0;
1N/A}
1N/A
1N/A#endif
1N/A
1N/A#endif