]> git.saurik.com Git - apple/libc.git/blobdiff - gen/FreeBSD/getcwd.c.patch
Libc-763.13.tar.gz
[apple/libc.git] / gen / FreeBSD / getcwd.c.patch
index d7515bf4ad2ecfa64d338a6ffacd0a1ea6b53a11..bd22ed845e4b56035c292b13970c50782a9e47fc 100644 (file)
---- getcwd.c.orig      Thu Jan  9 18:58:25 2003
-+++ getcwd.c   Sat May  3 14:04:22 2003
-@@ -54,8 +54,6 @@
+--- getcwd.c.bsdnew    2009-11-08 15:25:00.000000000 -0800
++++ getcwd.c   2009-11-08 15:30:17.000000000 -0800
+@@ -50,12 +50,87 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/get
        (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
            (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
  
 -extern int __getcwd(char *, size_t);
--
- char *
- getcwd(pt, size)
++/*
++ * If __getcwd() ever becomes a syscall, we can remove this workaround.
++ * The problem here is that fcntl() assumes a buffer of size MAXPATHLEN,
++ * if size is less than MAXPATHLEN, we need to use a temporary buffer
++ * and see if it fits.  We also have to assume that open() or fcntl()
++ * don't fail with errno=ERANGE.
++ */
++static inline int
++__getcwd(char *buf, size_t size)
++{
++      int fd, err, save;
++      struct stat dot, pt;
++      char *b;
++
++      if ((fd = open(".", O_RDONLY)) < 0)
++              return -1;
++      if (fstat(fd, &dot) < 0) {
++              save = errno;
++              close(fd);
++              errno = save;
++              return -1;
++      }
++      /* check that the device and inode are non-zero, otherwise punt */
++      if (dot.st_dev == 0 || dot.st_ino == 0) {
++              close(fd);
++              errno = EINVAL;
++              return -1;
++      }
++      if (size < MAXPATHLEN) {
++              /* the hard case; allocate a buffer of size MAXPATHLEN to use */
++              b = (char *)alloca(MAXPATHLEN);
++              if (b == NULL) {
++                      close(fd);
++                      errno = ENOMEM; /* make sure it isn't ERANGE */
++                      return -1;
++              }
++      } else
++              b = buf;
+-char *
+-getcwd(pt, size)
++      err = fcntl(fd, F_GETPATH, b);
++      if (err) {
++              save = errno;
++              close(fd);
++              errno = save;
++              return err;
++      }
++      close(fd);
++      /*
++       * now double-check that the path returned by fcntl() has the same
++       * device and inode number as '.'.
++       */
++      if (stat(b, &pt) < 0)
++              return -1;
++      /*
++       * Since dot.st_dev and dot.st_ino are non-zero, we don't need to
++       * separately test for pt.st_dev and pt.st_ino being non-zero, because
++       * they have to match
++       */
++      if (dot.st_dev != pt.st_dev || dot.st_ino != pt.st_ino) {
++              errno = EINVAL;
++              return -1;
++      }
++      /*
++       * For the case where we allocated a buffer, check that it can fit
++       * in the real buffer, and copy it over.
++       */
++      if (size < MAXPATHLEN) {
++              if (strlen(b) >= size) {
++                      errno = ERANGE;
++                      return -1;
++              }
++              strcpy(buf, b);
++      }
++      return 0;
++}
++
++__private_extern__ char *
++__private_getcwd(pt, size, usegetpath)
        char *pt;
-@@ -95,20 +93,6 @@
+       size_t size;
++      int usegetpath;
+ {
+       struct dirent *dp;
+       DIR *dir = NULL;
+@@ -87,33 +162,27 @@ getcwd(pt, size)
+               }
+               ept = pt + size;
+       } else {
+-              if ((pt = malloc(ptsize = PATH_MAX)) == NULL)
++              if ((pt = malloc(ptsize = MAXPATHLEN)) == NULL)
                        return (NULL);
                ept = pt + ptsize;
        }
--#if   !defined(__NETBSD_SYSCALLS)
 -      if (__getcwd(pt, ept - pt) == 0) {
 -              if (*pt != '/') {
 -                      bpt = pt;
 -                      }
 -              }
 -              return (pt);
--      }
--#endif
++      if (usegetpath) {
++              if (__getcwd(pt, ept - pt) == 0) {
++                      return (pt);
++              } else if (errno == ERANGE) /* failed because buffer too small */
++                      return NULL;
+       }
        bpt = ept - 1;
        *bpt = '\0';
  
+       /*
+-       * Allocate 1024 bytes for the string of "../"'s.
++       * Allocate MAXPATHLEN bytes for the string of "../"'s.
+        * Should always be enough.  If it's not, allocate
+        * as necessary.  Special case the first stat, it's ".", not "..".
+        */
+-      if ((up = malloc(upsize = 1024)) == NULL)
++      if ((up = malloc(upsize = MAXPATHLEN)) == NULL)
+               goto err;
+-      eup = up + upsize;
++      eup = up + MAXPATHLEN;
+       bup = up;
+       up[0] = '.';
+       up[1] = '\0';
+@@ -255,3 +324,11 @@ err:
+       errno = save_errno;
+       return (NULL);
+ }
++
++char *
++getcwd(pt, size)
++      char *pt;
++      size_t size;
++{
++      return __private_getcwd(pt, size, 1);
++}