#include "db_config.h"
#include "db_int.h"
#ifdef HAVE_SYSTEM_INCLUDE_FILES
#if HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# if HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# if HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# if HAVE_NDIR_H
# include <ndir.h>
# endif
#endif
#endif
#define ISDOT(dp) \
(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
#ifndef dirfd
#define dirfd(dirp) ((dirp)->dd_fd)
#endif
char *
getcwd(pt, size)
char *pt;
size_t size;
{
register struct dirent *dp;
register DIR *dir;
register dev_t dev;
register ino_t ino;
register int first;
register char *bpt, *bup;
struct stat s;
dev_t root_dev;
ino_t root_ino;
size_t ptsize, upsize;
int ret, save_errno;
char *ept, *eup, *up;
if (pt) {
ptsize = 0;
if (!size) {
__os_set_errno(EINVAL);
return (NULL);
}
if (size == 1) {
__os_set_errno(ERANGE);
return (NULL);
}
ept = pt + size;
} else {
if ((ret =
__os_malloc(NULL, ptsize = 1024 - 4, &pt)) != 0) {
__os_set_errno(ret);
return (NULL);
}
ept = pt + ptsize;
}
bpt = ept - 1;
*bpt = '\0';
if ((ret = __os_malloc(NULL, upsize = 1024 - 4, &up)) != 0)
goto err;
eup = up + 1024;
bup = up;
up[0] = '.';
up[1] = '\0';
if (stat("/", &s))
goto err;
root_dev = s.st_dev;
root_ino = s.st_ino;
__os_set_errno(0);
for (first = 1;; first = 0) {
if (lstat(up, &s))
goto err;
ino = s.st_ino;
dev = s.st_dev;
if (root_dev == dev && root_ino == ino) {
*--bpt = PATH_SEPARATOR[0];
bcopy(bpt, pt, ept - bpt);
__os_free(NULL, up);
return (pt);
}
if (bup + 3 + MAXNAMLEN + 1 >= eup) {
if (__os_realloc(NULL, upsize *= 2, &up) != 0)
goto err;
bup = up;
eup = up + upsize;
}
*bup++ = '.';
*bup++ = '.';
*bup = '\0';
if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))
goto err;
*bup++ = PATH_SEPARATOR[0];
save_errno = 0;
if (s.st_dev == dev) {
for (;;) {
if (!(dp = readdir(dir)))
goto notfound;
if (dp->d_fileno == ino)
break;
}
} else
for (;;) {
if (!(dp = readdir(dir)))
goto notfound;
if (ISDOT(dp))
continue;
bcopy(dp->d_name, bup, dp->d_namlen + 1);
if (lstat(up, &s)) {
if (save_errno == 0)
save_errno = __os_get_errno();
__os_set_errno(0);
continue;
}
if (s.st_dev == dev && s.st_ino == ino)
break;
}
if (bpt - pt < dp->d_namlen + (first ? 1 : 2)) {
size_t len, off;
if (!ptsize) {
__os_set_errno(ERANGE);
goto err;
}
off = bpt - pt;
len = ept - bpt;
if (__os_realloc(NULL, ptsize *= 2, &pt) != 0)
goto err;
bpt = pt + off;
ept = pt + ptsize;
bcopy(bpt, ept - len, len);
bpt = ept - len;
}
if (!first)
*--bpt = PATH_SEPARATOR[0];
bpt -= dp->d_namlen;
bcopy(dp->d_name, bpt, dp->d_namlen);
(void)closedir(dir);
*bup = '\0';
}
notfound:
if (__os_get_errno_ret_zero() == 0)
__os_set_errno(save_errno == 0 ? ENOENT : save_errno);
err:
if (ptsize)
__os_free(NULL, pt);
__os_free(NULL, up);
return (NULL);
}