#include <config.h>
#if !defined (HAVE_GETCWD)
#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
#pragma alloca
#endif
#include <bashtypes.h>
#include <errno.h>
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <posixdir.h>
#include <posixstat.h>
#include <maxpath.h>
#include <memalloc.h>
#include <bashansi.h>
#include <xmalloc.h>
#if !defined (errno)
extern int errno;
#endif
#if !defined (HAVE_LSTAT)
# define lstat stat
#endif
#if !defined (NULL)
# define NULL 0
#endif
#if defined (__STDC__)
char *
getcwd (char *buf, size_t size)
#else
char *
getcwd (buf, size)
char *buf;
size_t size;
#endif
{
static const char dots[]
= "../../../../../../../../../../../../../../../../../../../../../../../\
../../../../../../../../../../../../../../../../../../../../../../../../../../\
../../../../../../../../../../../../../../../../../../../../../../../../../..";
const char *dotp, *dotlist;
size_t dotsize;
dev_t rootdev, thisdev;
ino_t rootino, thisino;
char path[PATH_MAX + 1];
register char *pathp;
char *pathbuf;
size_t pathsize;
struct stat st;
int saved_errno;
if (buf != NULL && size == 0)
{
errno = EINVAL;
return ((char *)NULL);
}
pathsize = sizeof (path);
pathp = &path[pathsize];
*--pathp = '\0';
pathbuf = path;
if (stat (".", &st) < 0)
return ((char *)NULL);
thisdev = st.st_dev;
thisino = st.st_ino;
if (stat ("/", &st) < 0)
return ((char *)NULL);
rootdev = st.st_dev;
rootino = st.st_ino;
saved_errno = 0;
dotsize = sizeof (dots) - 1;
dotp = &dots[sizeof (dots)];
dotlist = dots;
while (!(thisdev == rootdev && thisino == rootino))
{
register DIR *dirstream;
register struct dirent *d;
dev_t dotdev;
ino_t dotino;
char mount_point;
int namlen;
if (dotp == dotlist)
{
char *new;
if (dotlist == dots)
{
new = (char *)malloc (dotsize * 2 + 1);
if (new == NULL)
goto lose;
memcpy (new, dots, dotsize);
}
else
{
new = (char *)realloc ((PTR_T) dotlist, dotsize * 2 + 1);
if (new == NULL)
goto lose;
}
memcpy (&new[dotsize], new, dotsize);
dotp = &new[dotsize];
dotsize *= 2;
new[dotsize] = '\0';
dotlist = new;
}
dotp -= 3;
if (stat (dotp, &st) < 0)
goto lose;
dotdev = st.st_dev;
dotino = st.st_ino;
mount_point = dotdev != thisdev;
dirstream = opendir (dotp);
if (dirstream == NULL)
goto lose;
while ((d = readdir (dirstream)) != NULL)
{
if (d->d_name[0] == '.' &&
(d->d_name[1] == '\0' ||
(d->d_name[1] == '.' && d->d_name[2] == '\0')))
continue;
if (mount_point || d->d_fileno == thisino)
{
char *name;
namlen = D_NAMLEN(d);
name = (char *)
alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
memcpy (name, dotp, dotlist + dotsize - dotp);
name[dotlist + dotsize - dotp] = '/';
memcpy (&name[dotlist + dotsize - dotp + 1],
d->d_name, namlen + 1);
if (lstat (name, &st) < 0)
{
#if 0
int save = errno;
(void) closedir (dirstream);
errno = save;
goto lose;
#else
saved_errno = errno;
#endif
}
if (st.st_dev == thisdev && st.st_ino == thisino)
break;
}
}
if (d == NULL)
{
#if 0
int save = errno;
#else
int save = errno ? errno : saved_errno;
#endif
(void) closedir (dirstream);
errno = save;
goto lose;
}
else
{
size_t space;
while ((space = pathp - pathbuf) <= namlen)
{
char *new;
if (pathbuf == path)
{
new = (char *)malloc (pathsize * 2);
if (!new)
goto lose;
}
else
{
new = (char *)realloc ((PTR_T) pathbuf, (pathsize * 2));
if (!new)
goto lose;
pathp = new + space;
}
(void) memcpy (new + pathsize + space, pathp, pathsize - space);
pathp = new + pathsize + space;
pathbuf = new;
pathsize *= 2;
}
pathp -= namlen;
(void) memcpy (pathp, d->d_name, namlen);
*--pathp = '/';
(void) closedir (dirstream);
}
thisdev = dotdev;
thisino = dotino;
}
if (pathp == &path[sizeof(path) - 1])
*--pathp = '/';
if (dotlist != dots)
free ((PTR_T) dotlist);
{
size_t len = pathbuf + pathsize - pathp;
if (buf == NULL && size <= 0)
size = len;
if ((size_t) size < len)
{
errno = ERANGE;
goto lose2;
}
if (buf == NULL)
{
buf = (char *) malloc (size);
if (buf == NULL)
goto lose2;
}
(void) memcpy((PTR_T) buf, (PTR_T) pathp, len);
}
if (pathbuf != path)
free (pathbuf);
return (buf);
lose:
if ((dotlist != dots) && dotlist)
{
int e = errno;
free ((PTR_T) dotlist);
errno = e;
}
lose2:
if ((pathbuf != path) && pathbuf)
{
int e = errno;
free ((PTR_T) pathbuf);
errno = e;
}
return ((char *)NULL);
}
#if defined (TEST)
# include <stdio.h>
main (argc, argv)
int argc;
char **argv;
{
char b[PATH_MAX];
if (getcwd(b, sizeof(b)))
{
printf ("%s\n", b);
exit (0);
}
else
{
perror ("cwd: getcwd");
exit (1);
}
}
#endif
#endif