[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.35 and 1.36

version 1.35, 2005/01/23 01:00:51 version 1.36, 2005/01/30 22:37:32
Line 46  __RCSID("$NetBSD$");
Line 46  __RCSID("$NetBSD$");
 #include <sys/stat.h>  #include <sys/stat.h>
   
 #include <assert.h>  #include <assert.h>
 #include <dirent.h>  
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  
 #include <stdio.h>  
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
Line 62  __weak_alias(realpath,_realpath)
Line 59  __weak_alias(realpath,_realpath)
 #endif  #endif
   
 /*  /*
  * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);   * char *realpath(const char *path, char resolved[MAXPATHLEN]);
  *   *
  * Find the real name of path, by removing all ".", ".." and symlink   * Find the real name of path, by removing all ".", ".." and symlink
  * components.  Returns (resolved) on success, or (NULL) on failure,   * components.  Returns (resolved) on success, or (NULL) on failure,
  * in which case the path which caused trouble is left in (resolved).   * in which case the path which caused trouble is left in (resolved).
  */   */
 char *  char *
 realpath(path, resolved)  realpath(const char *path, char *resolved)
         const char *path;  
         char *resolved;  
 {  {
         struct stat sb;          struct stat sb;
         int fd, n, rootd, serrno, nlnk = 0;          int idx = 0, n, nlnk = 0, serrno = errno;
         char *p, *q, wbuf[MAXPATHLEN];          const char *q;
           char *p, wbuf[2][MAXPATHLEN];
           size_t len;
   
         _DIAGASSERT(path != NULL);          _DIAGASSERT(path != NULL);
         _DIAGASSERT(resolved != NULL);          _DIAGASSERT(resolved != NULL);
   
         /* Save the starting point. */          /*
         if ((fd = open(".", O_RDONLY)) < 0) {           * Build real path one by one with paying an attention to .,
                 (void)strlcpy(resolved, ".", MAXPATHLEN);           * .. and symbolic link.
                 return (NULL);           */
         }  
   
         /*          /*
          * Find the dirname and basename from the path to be resolved.           * `p' is where we'll put a new component with prepending
          * Change directory to the dirname component.           * a delimiter.
          * lstat the basename part.  
          *     if it is a symlink, read in the value and loop.  
          *     if it is a directory, then change to that directory.  
          * get the current directory name and append the basename.  
          */           */
         if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) {          p = resolved;
                 errno = ENAMETOOLONG;  
                 goto err1;          if (*path == 0) {
                   *p = 0;
                   errno = ENOENT;
                   return (NULL);
         }          }
   
           /* If relative path, start from current working directory. */
           if (*path != '/') {
                   if (getcwd(resolved, MAXPATHLEN) == NULL) {
                           p[0] = '.';
                           p[1] = 0;
                           return (NULL);
                   }
                   len = strlen(resolved);
                   if (len > 1)
                           p += len;
           }
   
 loop:  loop:
         q = strrchr(resolved, '/');          /* Skip any slash. */
         if (q != NULL) {          while (*path == '/')
                 p = q + 1;                  path++;
                 if (q == resolved)  
                         q = "/";          if (*path == 0) {
                 else {                  if (p == resolved)
                         do {                          *p++ = '/';
                                 --q;                  *p = 0;
                         } while (q > resolved && *q == '/');                  return (resolved);
                         q[1] = '\0';          }
                         q = resolved;  
                 }          /* Find the end of this component. */
                 if (chdir(q) < 0)          q = path;
                         goto err1;          do
         } else                  q++;
                 p = resolved;          while (*q != '/' && *q != 0);
   
         /* Deal with the last component. */          /* Test . or .. */
         if (lstat(p, &sb) == 0) {          if (path[0] == '.') {
                 if (S_ISLNK(sb.st_mode)) {                  if (q - path == 1) {
                         if (nlnk++ >= MAXSYMLINKS) {                          path = q;
                                 errno = ELOOP;  
                                 goto err1;  
                         }  
                         n = readlink(p, resolved, MAXPATHLEN-1);  
                         if (n < 0)  
                                 goto err1;  
                         resolved[n] = '\0';  
                         goto loop;                          goto loop;
                 }                  }
                 if (S_ISDIR(sb.st_mode)) {                  if (path[1] == '.' && q - path == 2) {
                         if (chdir(p) < 0)                          /* Trim the last component. */
                                 goto err1;                          if (p != resolved)
                         p = "";                                  while (*--p != '/')
                                           ;
                           path = q;
                           goto loop;
                 }                  }
         }          }
   
         /*          /* Append this component. */
          * Save the last component name and get the full pathname of          if (p - resolved + 1 + q - path + 1 > MAXPATHLEN) {
          * the current directory.  
          */  
         if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) {  
                 errno = ENAMETOOLONG;                  errno = ENAMETOOLONG;
                 goto err1;                  if (p == resolved)
                           *p++ = '/';
                   *p = 0;
                   return (NULL);
         }          }
           p[0] = '/';
           memcpy(&p[1], path,
               /* LINTED We know q > path. */
               q - path);
           p[1 + q - path] = 0;
   
         /*          /*
          * Call the inernal internal version of getcwd which           * If this component is a symlink, toss it and prepend link
          * does a physical search rather than using the $PWD short-cut           * target to unresolved path.
          */           */
         if (getcwd(resolved, MAXPATHLEN) == 0)          if (lstat(resolved, &sb) == -1) {
                 goto err1;                  /* Allow nonexistent component if this is the last one. */
                   if (*q == 0 && errno == ENOENT) {
         /*                          errno = serrno;
          * Join the two strings together, ensuring that the right thing                          return (resolved);
          * happens if the last component is empty, or the dirname is root.  
          */  
         if (resolved[0] == '/' && resolved[1] == '\0')  
                 rootd = 1;  
         else  
                 rootd = 0;  
   
         if (*wbuf) {  
                 if (strlen(resolved) + strlen(wbuf) + (rootd ? 0 : 1) + 1 >  
                     MAXPATHLEN) {  
                         errno = ENAMETOOLONG;  
                         goto err1;  
                 }  
                 if (rootd == 0)  
                         if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) {  
                                 errno = ENAMETOOLONG;  
                                 goto err1;  
                         }  
                 if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) {  
                         errno = ENAMETOOLONG;  
                         goto err1;  
                 }                  }
                   return (NULL);
         }          }
           if (S_ISLNK(sb.st_mode)) {
                   if (nlnk++ >= MAXSYMLINKS) {
                           errno = ELOOP;
                           return (NULL);
                   }
                   n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1);
                   if (n < 0)
                           return (NULL);
                   if (n == 0) {
                           errno = ENOENT;
                           return (NULL);
                   }
   
         /* Go back to where we came from. */                  /* Append unresolved path to link target and switch to it. */
         if (fchdir(fd) < 0) {                  if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) {
                 serrno = errno;                          errno = ENAMETOOLONG;
                 goto err2;                          return (NULL);
                   }
                   memcpy(&wbuf[idx][n], q, len + 1);
                   path = wbuf[idx];
                   idx ^= 1;
   
                   /* If absolute symlink, start from root. */
                   if (*path == '/')
                           p = resolved;
                   goto loop;
         }          }
   
         /* It's okay if the close fails, what's an fd more or less? */          /* Advance both resolved and unresolved path. */
         (void)close(fd);          p += 1 + q - path;
         return (resolved);          path = q;
           goto loop;
 err1:   serrno = errno;  
         (void)fchdir(fd);  
 err2:   (void)close(fd);  
         errno = serrno;  
         return (NULL);  
 }  }
   
 char *  char *

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

CVSweb <webmaster@jp.NetBSD.org>