add Berkeley specific header; written by Sam Leffler
[unix-history] / usr / src / lib / libc / gen / getcwd.c
index b4ca68a..3e2c41f 100644 (file)
-/*     @(#)getcwd.c    4.4     (Berkeley)      %G%     */
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getcwd.c   5.2 (Berkeley) %G%";
+#endif LIBC_SCCS and not lint
 
 /*
 
 /*
- * Getwd
+ * getwd() returns the pathname of the current working directory. On error
+ * an error message is copied to pathname and null pointer is returned.
  */
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/dir.h>
 
  */
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/dir.h>
 
-#define        dot     "."
-#define        dotdot  ".."
-
-#define        prexit(s)       { strcpy(np, s); return (NULL); }
-
-static char *name;
+#define GETWDERR(s)    strcpy(pathname, (s));
 
 
-static DIR *file;
-static int off;
-static struct stat d, dd;
-static struct direct *dir;
+char *strcpy();
+static int pathsize;                   /* pathname length */
 
 char *
 
 char *
-getwd(np)
-       char *np;
+getwd(pathname)
+       char *pathname;
 {
 {
-       dev_t rdev;
-       ino_t rino;
+       char pathbuf[MAXPATHLEN];               /* temporary pathname buffer */
+       char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
+       char curdir[MAXPATHLEN];        /* current directory buffer */
+       char *dptr = curdir;            /* directory pointer */
+       char *prepend();                /* prepend dirname to pathname */
+       dev_t cdev, rdev;               /* current & root device number */
+       ino_t cino, rino;               /* current & root inode number */
+       DIR *dirp;                      /* directory stream */
+       struct direct *dir;             /* directory entry struct */
+       struct stat d, dd;              /* file status struct */
 
 
-       off = -1;
-       *np++ = '/';
-       name = np;
-       stat("/", &d);
+       pathsize = 0;
+       *pnptr = '\0';
+       if (stat("/", &d) < 0) {
+               GETWDERR("getwd: can't stat /");
+               return (NULL);
+       }
        rdev = d.st_dev;
        rino = d.st_ino;
        rdev = d.st_dev;
        rino = d.st_ino;
+       strcpy(dptr, "./");
+       dptr += 2;
+       if (stat(curdir, &d) < 0) {
+               GETWDERR("getwd: can't stat .");
+               return (NULL);
+       }
        for (;;) {
        for (;;) {
-               stat(dot, &d);
-               if (d.st_ino==rino && d.st_dev==rdev)
-                       goto done;
-               if ((file = opendir(dotdot)) == NULL)
-                       prexit("getwd: cannot open ..");
-               fstat(file->dd_fd, &dd);
-               if (chdir(dotdot) < 0)
-                       prexit("getwd: cannot chdir to ..");
-               if (d.st_dev == dd.st_dev) {
-                       if(d.st_ino == dd.st_ino)
-                               goto done;
-                       do
-                               if ((dir = readdir(file)) == NULL)
-                                       prexit("getwd: read error in ..");
-                       while (dir->d_ino != d.st_ino);
+               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);
+               }
+               fstat(dirp->dd_fd, &d);
+               if (cdev == d.st_dev) {
+                       if (cino == d.st_ino) {
+                               /* reached root directory */
+                               closedir(dirp);
+                               break;
+                       }
+                       do {
+                               if ((dir = readdir(dirp)) == NULL) {
+                                       closedir(dirp);
+                                       GETWDERR("getwd: read error in ..");
+                                       return (NULL);
+                               }
+                       } while (dir->d_ino != cino);
                } else
                        do {
                } else
                        do {
-                               if ((dir = readdir(file)) == NULL)
-                                       prexit("getwd: read error in ..");
-                               stat(dir->d_name, &dd);
-                       } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
-               closedir(file);
-               cat();
+                               if ((dir = readdir(dirp)) == NULL) {
+                                       closedir(dirp);
+                                       GETWDERR("getwd: read error in ..");
+                                       return (NULL);
+                               }
+                               strcpy(dptr, dir->d_name);
+                               lstat(curdir, &dd);
+                       } while(dd.st_ino != cino || dd.st_dev != cdev);
+               closedir(dirp);
+               pnptr = prepend("/", prepend(dir->d_name, pnptr));
        }
        }
-done:
-       name--;
-       if (chdir(name) < 0)
-               prexit("getwd: can't change back");
-       return (name);
+       if (*pnptr == '\0')             /* current dir == root dir */
+               strcpy(pathname, "/");
+       else
+               strcpy(pathname, pnptr);
+       return (pathname);
 }
 
 }
 
-cat()
+/*
+ * prepend() tacks a directory name onto the front of a pathname.
+ */
+static char *
+prepend(dirname, pathname)
+       register char *dirname;
+       register char *pathname;
 {
 {
-       register i, j;
+       register int i;                 /* directory name size counter */
 
 
-       i = -1;
-       while (dir->d_name[++i] != 0);
-       if ((off+i+2) > 1024-1)
-               return;
-       for(j=off+1; j>=0; --j)
-               name[j+i+1] = name[j];
-       if (off >= 0)
-               name[i] = '/';
-       off=i+off+1;
-       name[off] = 0;
-       for(--i; i>=0; --i)
-               name[i] = dir->d_name[i];
+       for (i = 0; *dirname != '\0'; i++, dirname++)
+               continue;
+       if ((pathsize += i) < MAXPATHLEN)
+               while (i-- > 0)
+                       *--pathname = *--dirname;
+       return (pathname);
 }
 }