[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.33 and 1.34

version 1.33, 2005/01/06 00:07:41 version 1.34, 2005/01/06 23:43:32
Line 204  err2: (void)close(fd);
Line 204  err2: (void)close(fd);
         return (NULL);          return (NULL);
 }  }
   
 #ifdef OLD_GETCWD  
   
 char *  
 getcwd(pt, size)  
         char *pt;  
         size_t size;  
 {  
         struct dirent *dp;  
         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, *nup;  
         size_t dlen;  
   
         /*  
          * If no buffer specified by the user, allocate one as necessary.  
          * 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) {  
                 ptsize = 0;  
                 if (!size) {  
                         errno = EINVAL;  
                         return (NULL);  
                 }  
                 ept = pt + size;  
         } else {  
                 if ((pt = malloc(ptsize = 1024 - 4)) == NULL)  
                         return (NULL);  
                 ept = pt + ptsize;  
         }  
         bpt = ept - 1;  
         *bpt = '\0';  
   
         /*  
          * Allocate bytes 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 = malloc(upsize = MAXPATHLEN)) == NULL)  
                 goto err;  
         eup = up + upsize;  
         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.  
                          */  
                         memmove(pt, bpt,  (size_t)(ept - bpt));  
                         free(up);  
                         return (pt);  
                 }  
   
                 /*  
                  * 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 ((nup = realloc(up, upsize *= 2)) == NULL)  
                                 goto err;  
                         bup = nup + (buf - up);  
                         up = nup;  
                         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) {  
 #if defined(__SVR4) || defined(__svr4__) || defined(__linux__)  
                                         dlen = strlen(dp->d_name);  
 #else  
                                         dlen = dp->d_namlen;  
 #endif  
                                         break;  
                                 }  
                         }  
                 } else  
                         for (;;) {  
                                 if (!(dp = readdir(dir)))  
                                         goto notfound;  
                                 if (ISDOT(dp))  
                                         continue;  
 #if defined(__SVR4) || defined(__svr4__) || defined(__linux__)  
                                 dlen = strlen(dp->d_name);  
 #else  
                                 dlen = dp->d_namlen;  
 #endif  
                                 memmove(bup, dp->d_name, dlen + 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 <= dlen + (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 -= dlen;  
                 memmove(bpt, dp->d_name, dlen);  
                 (void)closedir(dir);  
   
                 /* Truncate any file name. */  
                 *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);  
 }  
   
 #else /* New getcwd */  
   
 char *  char *
 getcwd(pt, size)  getcwd(pt, size)
         char *pt;          char *pt;
Line 443  getcwd(pt, size)
Line 246  getcwd(pt, size)
         else          else
                 return pt;                  return pt;
 }  }
   
 #endif  

Legend:
Removed from v.1.33  
changed lines
  Added in v.1.34

CVSweb <webmaster@jp.NetBSD.org>