from scratch; leave '/' on end of all pathnames
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Sun, 19 Mar 1989 01:47:22 +0000 (17:47 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Sun, 19 Mar 1989 01:47:22 +0000 (17:47 -0800)
SCCS-vsn: lib/libc/gen/getcwd.c 5.4

usr/src/lib/libc/gen/getcwd.c

index afa9e27..fd21b5a 100644 (file)
 /*
 /*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getcwd.c   5.3 (Berkeley) %G%";
-#endif LIBC_SCCS and not lint
+static char sccsid[] = "@(#)getcwd.c   5.4 (Berkeley) %G%";
+#endif /* LIBC_SCCS and not lint */
 
 
-/*
- * 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/param.h>
 #include <sys/stat.h>
-#include <sys/dir.h>
-
-#define GETWDERR(s)    strcpy(pathname, (s));
-
-char *strcpy();
-static int pathsize;                   /* pathname length */
+#include <dirent.h>
 
 char *
 
 char *
-getwd(pathname)
-       char *pathname;
+getwd(store)
+       char *store;
 {
 {
-       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 */
+       extern int errno;
+       register DIR *dir;
+       register struct dirent *dp;
+       register int first;
+       register char *pp, *pu;
+       struct stat s, tmp;
+       dev_t root_dev;
+       ino_t root_ino;
+       char path[MAXPATHLEN], up[MAXPATHLEN], *strerror();
 
 
-       pathsize = 0;
-       *pnptr = '\0';
-       if (stat("/", &d) < 0) {
-               GETWDERR("getwd: can't stat /");
-               return (NULL);
-       }
-       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 (;;) {
-               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);
+       if (stat("/", &s))
+               goto err;
+       root_dev = s.st_dev;
+       root_ino = s.st_ino;
+       if (stat(".", &s))
+               goto err;
+       pp = path + sizeof(path) - 1;
+       *pp = '\0';
+       for (pu = up, first = 1;; first = 0) {
+               if (root_dev == s.st_dev && root_ino == s.st_ino) {
+                       *store = '/';
+                       (void)strcpy(store + 1, pp);
+                       return(store);
                }
                }
-               fstat(dirp->dd_fd, &d);
-               if (cdev == d.st_dev) {
-                       if (cino == d.st_ino) {
-                               /* reached root directory */
-                               closedir(dirp);
+               *pu++ = '.';
+               *pu++ = '.';
+               *pu = '\0';
+               if (!(dir = opendir(up))) {
+                       (void)strcpy(path, "getwd: opendir failed.");
+                       return((char *)NULL);
+               }
+               *pu++ = '/';
+               while (dp = readdir(dir)) {
+                       if (dp->d_name[0] == '.' && (!dp->d_name[1] ||
+                           dp->d_name[1] == '.' && !dp->d_name[2]))
+                               continue;
+                       bcopy(dp->d_name, pu, dp->d_namlen + 1);
+                       if (lstat(up, &tmp))
+                               goto err;
+                       if (tmp.st_dev == s.st_dev && tmp.st_ino == s.st_ino) {
+                               if (!first)
+                                       *--pp = '/';
+                               pp -= dp->d_namlen;
+                               bcopy(dp->d_name, pp, dp->d_namlen);
                                break;
                        }
                                break;
                        }
-                       do {
-                               if ((dir = readdir(dirp)) == NULL) {
-                                       closedir(dirp);
-                                       GETWDERR("getwd: read error in ..");
-                                       return (NULL);
-                               }
-                       } while (dir->d_ino != cino);
-               } else
-                       do {
-                               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);
-               pnptr = prepend("/", prepend(dir->d_name, pnptr));
-               closedir(dirp);
+               }
+               closedir(dir);
+               *pu = '\0';
+               if (lstat(up, &s)) {
+err:                   (void)sprintf(path, "getwd: %s", strerror(errno));
+                       return((char *)NULL);
+               }
        }
        }
-       if (*pnptr == '\0')             /* current dir == root dir */
-               strcpy(pathname, "/");
-       else
-               strcpy(pathname, pnptr);
-       return (pathname);
-}
-
-/*
- * prepend() tacks a directory name onto the front of a pathname.
- */
-static char *
-prepend(dirname, pathname)
-       register char *dirname;
-       register char *pathname;
-{
-       register int i;                 /* directory name size counter */
-
-       for (i = 0; *dirname != '\0'; i++, dirname++)
-               continue;
-       if ((pathsize += i) < MAXPATHLEN)
-               while (i-- > 0)
-                       *--pathname = *--dirname;
-       return (pathname);
 }
 }