[BACK]Return to getcwd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / gen

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libc/gen/getcwd.c between version 1.14 and 1.35

version 1.14, 1998/08/26 00:38:40 version 1.35, 2005/01/23 01:00:51
Line 15 
Line 15 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software   * 3. Neither the name of the University nor the names of its contributors
  *    must display the following acknowledgement:  
  *      This product includes software developed by the University of  
  *      California, Berkeley and its contributors.  
  * 4. Neither the name of the University nor the names of its contributors  
  *    may be used to endorse or promote products derived from this software   *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.   *    without specific prior written permission.
  *   *
Line 49  __RCSID("$NetBSD$");
Line 45  __RCSID("$NetBSD$");
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/stat.h>  #include <sys/stat.h>
   
   #include <assert.h>
 #include <dirent.h>  #include <dirent.h>
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
Line 57  __RCSID("$NetBSD$");
Line 54  __RCSID("$NetBSD$");
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
   
   #include "extern.h"
   
 #ifdef __weak_alias  #ifdef __weak_alias
 __weak_alias(getcwd,_getcwd);  __weak_alias(getcwd,_getcwd)
 __weak_alias(realpath,_realpath);  __weak_alias(realpath,_realpath)
 #endif  #endif
   
 #define ISDOT(dp) \  
         (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \  
             (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))  
   
   
 /*  /*
  * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);   * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
  *   *
Line 80  realpath(path, resolved)
Line 74  realpath(path, resolved)
         char *resolved;          char *resolved;
 {  {
         struct stat sb;          struct stat sb;
         int fd, n, rootd, serrno;          int fd, n, rootd, serrno, nlnk = 0;
         char *p, *q, wbuf[MAXPATHLEN];          char *p, *q, wbuf[MAXPATHLEN];
   
           _DIAGASSERT(path != NULL);
           _DIAGASSERT(resolved != NULL);
   
         /* Save the starting point. */          /* Save the starting point. */
         if ((fd = open(".", O_RDONLY)) < 0) {          if ((fd = open(".", O_RDONLY)) < 0) {
                 (void)strcpy(resolved, ".");                  (void)strlcpy(resolved, ".", MAXPATHLEN);
                 return (NULL);                  return (NULL);
         }          }
   
Line 97  realpath(path, resolved)
Line 94  realpath(path, resolved)
          *     if it is a directory, then change to that directory.           *     if it is a directory, then change to that directory.
          * get the current directory name and append the basename.           * get the current directory name and append the basename.
          */           */
         (void)strncpy(resolved, path, MAXPATHLEN - 1);          if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) {
         resolved[MAXPATHLEN - 1] = '\0';                  errno = ENAMETOOLONG;
                   goto err1;
           }
 loop:  loop:
         q = strrchr(resolved, '/');          q = strrchr(resolved, '/');
         if (q != NULL) {          if (q != NULL) {
Line 120  loop:
Line 119  loop:
         /* Deal with the last component. */          /* Deal with the last component. */
         if (lstat(p, &sb) == 0) {          if (lstat(p, &sb) == 0) {
                 if (S_ISLNK(sb.st_mode)) {                  if (S_ISLNK(sb.st_mode)) {
                         n = readlink(p, resolved, MAXPATHLEN);                          if (nlnk++ >= MAXSYMLINKS) {
                                   errno = ELOOP;
                                   goto err1;
                           }
                           n = readlink(p, resolved, MAXPATHLEN-1);
                         if (n < 0)                          if (n < 0)
                                 goto err1;                                  goto err1;
                         resolved[n] = '\0';                          resolved[n] = '\0';
Line 137  loop:
Line 140  loop:
          * Save the last component name and get the full pathname of           * Save the last component name and get the full pathname of
          * the current directory.           * the current directory.
          */           */
         (void)strncpy(wbuf, p, (sizeof(wbuf) - 1));          if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {
                   errno = ENAMETOOLONG;
                   goto err1;
           }
   
         /*          /*
          * Call the inernal internal version of getcwd which           * Call the inernal internal version of getcwd which
Line 156  loop:
Line 162  loop:
                 rootd = 0;                  rootd = 0;
   
         if (*wbuf) {          if (*wbuf) {
                 if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {                  if (strlen(resolved) + strlen(wbuf) + (rootd ? 0 : 1) + 1 >
                       MAXPATHLEN) {
                         errno = ENAMETOOLONG;                          errno = ENAMETOOLONG;
                         goto err1;                          goto err1;
                 }                  }
                 if (rootd == 0)                  if (rootd == 0)
                         (void)strcat(resolved, "/"); /* XXX: strcat is safe */                          if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) {
                 (void)strcat(resolved, wbuf);   /* XXX: strcat is safe */                                  errno = ENAMETOOLONG;
                                   goto err1;
                           }
                   if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) {
                           errno = ENAMETOOLONG;
                           goto err1;
                   }
         }          }
   
         /* Go back to where we came from. */          /* Go back to where we came from. */
Line 183  err2: (void)close(fd);
Line 196  err2: (void)close(fd);
 }  }
   
 char *  char *
 getcwd(pt, size)  getcwd(char *pt, size_t size)
         char *pt;  
         size_t size;  
 {  {
         struct dirent *dp;          char *npt;
         DIR *dir;  
         dev_t dev;  
         ino_t ino;  
         int first;  
         char *bpt, *bup;  
         struct stat s;  
         dev_t root_dev;  
         ino_t root_ino;  
         size_t ptsize, upsize;  
         int save_errno;  
         char *ept, *eup, *up;  
   
         /*          /*
          * If no buffer specified by the user, allocate one as necessary.           * If a buffer is specified, the size has to be non-zero.
          * If a buffer is specified, the size has to be non-zero.  The path  
          * is built from the end of the buffer backwards.  
          */           */
         if (pt) {          if (pt != NULL) {
                 ptsize = 0;                  if (size == 0) {
                 if (!size) {                          /* __getcwd(pt, 0) results ERANGE. */
                         errno = EINVAL;                          errno = EINVAL;
                         return (NULL);                          return (NULL);
                 }                  }
                 ept = pt + size;                  if (__getcwd(pt, size) >= 0)
         } else {                          return (pt);
                 if ((pt = malloc(ptsize = 1024 - 4)) == NULL)                  return (NULL);
                         return (NULL);  
                 ept = pt + ptsize;  
         }          }
         bpt = ept - 1;  
         *bpt = '\0';  
   
         /*          /*
          * Allocate bytes (1024 - malloc space) for the string of "../"'s.           * If no buffer specified by the user, allocate one as necessary.
          * 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 = malloc(upsize = 1024 - 4)) == NULL)          size = 1024 >> 1;
                 goto err;          do {
         eup = up + MAXPATHLEN;                  if ((npt = realloc(pt, size <<= 1)) == NULL)
         bup = up;                          break;
         up[0] = '.';                  pt = npt;
         up[1] = '\0';                  if (__getcwd(pt, size) >= 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.  
                          */  
                         memmove(pt, bpt,  (size_t)(ept - bpt));  
                         free(up);  
                         return (pt);                          return (pt);
                 }          } while (size <= MAXPATHLEN * 4 && errno == ERANGE);
   
                 /*  
                  * Build pointer to the parent directory, allocating memory  
                  * as necessary.  Max length is 3 for "../", the largest  
                  * possible component name, plus a trailing NULL.  
                  */  
                 if (bup + 3  + MAXNAMLEN + 1 >= eup) {  
                         if ((up = realloc(up, upsize *= 2)) == NULL)  
                                 goto err;  
                         bup = up;  
                         eup = up + upsize;  
                 }  
                 *bup++ = '.';  
                 *bup++ = '.';  
                 *bup = '\0';  
   
                 /* Open and stat parent directory. */  
                 if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))  
                         goto err;  
   
                 /* Add trailing slash for next directory. */  
                 *bup++ = '/';  
   
                 /*  
                  * If it's a mount point, have to stat each element because  
                  * the inode number in the directory is for the entry in the  
                  * parent directory, not the inode number of the mounted file.  
                  */  
                 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;  
                                 memmove(bup, dp->d_name,  
                                     (size_t)(dp->d_namlen + 1));  
   
                                 /* Save the first error for later. */  
                                 if (lstat(up, &s)) {  
                                         if (!save_errno)  
                                                 save_errno = errno;  
                                         errno = 0;  
                                         continue;  
                                 }  
                                 if (s.st_dev == dev && s.st_ino == ino)  
                                         break;  
                         }  
   
                 /*  
                  * Check for length of the current name, preceding slash,  
                  * leading slash.  
                  */  
                 if (bpt - pt <= dp->d_namlen + (first ? 1 : 2)) {  
                         size_t len, off;  
   
                         if (!ptsize) {  
                                 errno = ERANGE;  
                                 goto err;  
                         }  
                         off = bpt - pt;  
                         len = ept - bpt;  
                         if ((pt = realloc(pt, ptsize *= 2)) == NULL)  
                                 goto err;  
                         bpt = pt + off;  
                         ept = pt + ptsize;  
                         memmove(ept - len, bpt, len);  
                         bpt = ept - len;  
                 }  
                 if (!first)  
                         *--bpt = '/';  
                 bpt -= dp->d_namlen;  
                 memmove(bpt, dp->d_name, (size_t)dp->d_namlen);  
                 (void)closedir(dir);  
   
                 /* Truncate any file name. */          free(pt);
                 *bup = '\0';  
         }  
   
 notfound:  
         /*  
          * If readdir set errno, use it, not any saved error; otherwise,  
          * didn't find the current directory in its parent directory, set  
          * errno to ENOENT.  
          */  
         if (!errno)  
                 errno = save_errno ? save_errno : ENOENT;  
         /* FALLTHROUGH */  
 err:  
         if (ptsize)  
                 free(pt);  
         free(up);  
         return (NULL);          return (NULL);
 }  }

Legend:
Removed from v.1.14  
changed lines
  Added in v.1.35

CVSweb <webmaster@jp.NetBSD.org>