- for (;;) {
- if (d.st_ino == rino && d.st_dev == rdev)
- break; /* reached root directory */
- cino = d.st_ino;
- cdev = d.st_dev;
- strcpy(dptr, "../");
- dptr += 3;
- if ((dirp = opendir(curdir)) == NULL) {
- GETWDERR("getwd: can't open ..");
- return (NULL);
+ bpt = ept - 1;
+ *bpt = '\0';
+
+ /*
+ * Allocate bytes (1024 - malloc space) for the string of "../"'s.
+ * Should always be enough (it's 340 levels). If it's not, allocate
+ * as necessary. Special * case the first stat, it's ".", not "..".
+ */
+ if (!(up = (char *)malloc(upsize = 1024 - 4)))
+ goto err;
+ eup = up + MAXPATHLEN;
+ bup = up;
+ up[0] = '.';
+ up[1] = '\0';
+
+ /* Save root values, so know when to stop. */
+ if (stat("/", &s))
+ goto err;
+ root_dev = s.st_dev;
+ root_ino = s.st_ino;
+
+ errno = 0; /* XXX readdir has no error return. */
+
+ for (first = 1;; first = 0) {
+ /* Stat the current level. */
+ if (lstat(up, &s))
+ goto err;
+
+ /* Save current node values. */
+ ino = s.st_ino;
+ dev = s.st_dev;
+
+ /* Check for reaching root. */
+ if (root_dev == dev && root_ino == ino) {
+ *--bpt = '/';
+ /*
+ * It's unclear that it's a requirement to copy the
+ * path to the beginning of the buffer, but it's always
+ * been that way and stuff would probably break.
+ */
+ (void)bcopy(bpt, pt, ept - bpt);
+ free(up);
+ return(pt);