-/* Copyright (C) 1991 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
char *
DEFUN(getcwd, (buf, size), char *buf AND size_t size)
{
+ static CONST char dots[]
+ = "../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../..";
+ CONST char *dotp, *dotlist;
+ size_t dotsize;
dev_t rootdev, thisdev;
ino_t rootino, thisino;
- char path[PATH_MAX + 1];
+ char *path;
register char *pathp;
struct stat st;
- if (buf != NULL && size == 0)
+if (size == 0)
+ {
+ if (buf != NULL)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+ size = PATH_MAX + 1;
+ }
+
+ if (buf != NULL)
+ path = buf;
+ else
{
- errno = EINVAL;
- return NULL;
+ path = malloc (size);
+ if (path == NULL)
+ return NULL;
}
- pathp = &path[sizeof(path)];
+ pathp = path + size;
*--pathp = '\0';
- if (stat(".", &st) < 0)
+ if (stat (".", &st) < 0)
return NULL;
thisdev = st.st_dev;
thisino = st.st_ino;
- if (stat("/", &st) < 0)
+ if (stat ("/", &st) < 0)
return NULL;
rootdev = st.st_dev;
rootino = st.st_ino;
+ dotsize = sizeof (dots) - 1;
+ dotp = &dots[sizeof (dots)];
+ dotlist = dots;
while (!(thisdev == rootdev && thisino == rootino))
{
register DIR *dirstream;
ino_t dotino;
char mount_point;
- /* Move up a directory. */
- if (chdir("..") < 0)
+ /* Look at the parent directory. */
+ if (dotp == dotlist)
{
- if (pathp != &path[sizeof(path) - 1])
+ /* My, what a deep directory tree you have, Grandma. */
+ char *new;
+ if (dotlist == dots)
{
- /* Try to get back to the original directory.
- This is the only place where this is possible. */
- int save = errno;
- (void) chdir (pathp);
- errno = save;
+ new = malloc (dotsize * 2 + 1);
+ if (new == NULL)
+ return NULL;
+ memcpy (new, dots, dotsize);
}
- return NULL;
+ else
+ {
+ new = realloc ((PTR) 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;
+
/* Figure out if this directory is a mount point. */
- if (stat(".", &st) < 0)
- return NULL;
+ if (stat (dotp, &st) < 0)
+ goto lose;
dotdev = st.st_dev;
dotino = st.st_ino;
mount_point = dotdev != thisdev;
/* Search for the last directory. */
- dirstream = opendir(".");
+ dirstream = opendir (dotp);
if (dirstream == NULL)
- return NULL;
- while ((d = readdir(dirstream)) != NULL)
+ goto lose;
+ while ((d = readdir (dirstream)) != NULL)
{
if (d->d_name[0] == '.' &&
(d->d_namlen == 1 || (d->d_namlen == 2 && d->d_name[1] == '.')))
continue;
if (mount_point || d->d_fileno == thisino)
{
- if (stat(d->d_name, &st) < 0)
+ char *name = __alloca (dotlist + dotsize - dotp +
+ 1 + d->d_namlen + 1);
+ memcpy (name, dotp, dotlist + dotsize - dotp);
+ name[dotlist + dotsize - dotp] = '/';
+ memcpy (&name[dotlist + dotsize - dotp + 1],
+ d->d_name, d->d_namlen + 1);
+ if (stat (name, &st) < 0)
{
int save = errno;
- (void) closedir(dirstream);
+ (void) closedir (dirstream);
errno = save;
- return NULL;
+ goto lose;
}
if (st.st_dev == thisdev && st.st_ino == thisino)
break;
if (d == NULL)
{
int save = errno;
- (void) closedir(dirstream);
+ (void) closedir (dirstream);
errno = save;
- return NULL;
+ goto lose;
}
else
{
+ if (pathp - path < d->d_namlen + 1)
+ {
+ if (buf != NULL)
+ {
+ errno = ERANGE;
+ return NULL;
+ }
+ else
+ {
+ size *= 2;
+ buf = realloc (path, size);
+ if (buf == NULL)
+ {
+ (void) closedir (dirstream);
+ free (path);
+ errno = ENOMEM; /* closedir might have changed it. */
+ return NULL;
+ }
+ pathp = &buf[pathp - path];
+ path = buf;
+ }
+ }
pathp -= d->d_namlen;
- (void) memcpy(pathp, d->d_name, d->d_namlen);
+ (void) closedir (dirstream);
+ (void) memcpy (pathp, d->d_name, d->d_namlen);
*--pathp = '/';
- (void) closedir(dirstream);
+ (void) closedir (dirstream);
}
thisdev = dotdev;
thisino = dotino;
}
- if (pathp == &path[sizeof(path) - 1])
+ if (pathp == &path[size - 1])
*--pathp = '/';
- if (chdir(pathp) < 0)
- return NULL;
+ if (dotlist != dots)
+ free ((PTR) dotlist);
- {
- size_t len = &path[sizeof(path)] - pathp;
- if (buf == NULL)
- {
- if (len < (size_t) size)
- len = size;
- buf = (char *) malloc(len);
- if (buf == NULL)
- return NULL;
- }
- else if ((size_t) size < len)
- {
- errno = ERANGE;
- return NULL;
- }
- (void) memcpy((PTR) buf, (PTR) pathp, len);
- }
+ return memmove (path, pathp, path + size - pathp);
- return buf;
+ lose:
+ if (dotlist != dots)
+ free ((PTR) dotlist);
+ return NULL;
}