]> git.saurik.com Git - apple/libc.git/blame - gen/FreeBSD/getcwd.c.patch
Libc-763.13.tar.gz
[apple/libc.git] / gen / FreeBSD / getcwd.c.patch
CommitLineData
1f2f436a
A
1--- getcwd.c.bsdnew 2009-11-08 15:25:00.000000000 -0800
2+++ getcwd.c 2009-11-08 15:30:17.000000000 -0800
3@@ -50,12 +50,87 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/get
9385eb3d
A
4 (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
5 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
6
7-extern int __getcwd(char *, size_t);
8e029c65
A
8+/*
9+ * If __getcwd() ever becomes a syscall, we can remove this workaround.
10+ * The problem here is that fcntl() assumes a buffer of size MAXPATHLEN,
11+ * if size is less than MAXPATHLEN, we need to use a temporary buffer
12+ * and see if it fits. We also have to assume that open() or fcntl()
13+ * don't fail with errno=ERANGE.
14+ */
15+static inline int
16+__getcwd(char *buf, size_t size)
17+{
18+ int fd, err, save;
19+ struct stat dot, pt;
20+ char *b;
21+
22+ if ((fd = open(".", O_RDONLY)) < 0)
23+ return -1;
24+ if (fstat(fd, &dot) < 0) {
25+ save = errno;
26+ close(fd);
27+ errno = save;
28+ return -1;
29+ }
30+ /* check that the device and inode are non-zero, otherwise punt */
31+ if (dot.st_dev == 0 || dot.st_ino == 0) {
32+ close(fd);
33+ errno = EINVAL;
34+ return -1;
35+ }
36+ if (size < MAXPATHLEN) {
37+ /* the hard case; allocate a buffer of size MAXPATHLEN to use */
38+ b = (char *)alloca(MAXPATHLEN);
39+ if (b == NULL) {
40+ close(fd);
41+ errno = ENOMEM; /* make sure it isn't ERANGE */
42+ return -1;
43+ }
44+ } else
45+ b = buf;
224c7076
A
46
47-char *
48-getcwd(pt, size)
8e029c65
A
49+ err = fcntl(fd, F_GETPATH, b);
50+ if (err) {
51+ save = errno;
52+ close(fd);
53+ errno = save;
54+ return err;
55+ }
56+ close(fd);
57+ /*
58+ * now double-check that the path returned by fcntl() has the same
59+ * device and inode number as '.'.
60+ */
61+ if (stat(b, &pt) < 0)
62+ return -1;
63+ /*
64+ * Since dot.st_dev and dot.st_ino are non-zero, we don't need to
65+ * separately test for pt.st_dev and pt.st_ino being non-zero, because
66+ * they have to match
67+ */
68+ if (dot.st_dev != pt.st_dev || dot.st_ino != pt.st_ino) {
69+ errno = EINVAL;
70+ return -1;
71+ }
72+ /*
73+ * For the case where we allocated a buffer, check that it can fit
74+ * in the real buffer, and copy it over.
75+ */
76+ if (size < MAXPATHLEN) {
77+ if (strlen(b) >= size) {
78+ errno = ERANGE;
79+ return -1;
80+ }
81+ strcpy(buf, b);
82+ }
83+ return 0;
84+}
224c7076
A
85+
86+__private_extern__ char *
87+__private_getcwd(pt, size, usegetpath)
88 char *pt;
89 size_t size;
90+ int usegetpath;
91 {
92 struct dirent *dp;
93 DIR *dir = NULL;
1f2f436a 94@@ -87,33 +162,27 @@ getcwd(pt, size)
8e029c65
A
95 }
96 ept = pt + size;
97 } else {
1f2f436a 98- if ((pt = malloc(ptsize = PATH_MAX)) == NULL)
8e029c65 99+ if ((pt = malloc(ptsize = MAXPATHLEN)) == NULL)
9385eb3d
A
100 return (NULL);
101 ept = pt + ptsize;
102 }
224c7076 103- if (__getcwd(pt, ept - pt) == 0) {
9385eb3d
A
104- if (*pt != '/') {
105- bpt = pt;
106- ept = pt + strlen(pt) - 1;
107- while (bpt < ept) {
108- c = *bpt;
109- *bpt++ = *ept;
110- *ept-- = c;
111- }
112- }
224c7076
A
113- return (pt);
114+ if (usegetpath) {
115+ if (__getcwd(pt, ept - pt) == 0) {
116+ return (pt);
117+ } else if (errno == ERANGE) /* failed because buffer too small */
118+ return NULL;
119 }
9385eb3d
A
120 bpt = ept - 1;
121 *bpt = '\0';
122
8e029c65 123 /*
1f2f436a
A
124- * Allocate 1024 bytes for the string of "../"'s.
125+ * Allocate MAXPATHLEN bytes for the string of "../"'s.
126 * Should always be enough. If it's not, allocate
8e029c65
A
127 * as necessary. Special case the first stat, it's ".", not "..".
128 */
1f2f436a 129- if ((up = malloc(upsize = 1024)) == NULL)
8e029c65
A
130+ if ((up = malloc(upsize = MAXPATHLEN)) == NULL)
131 goto err;
1f2f436a
A
132- eup = up + upsize;
133+ eup = up + MAXPATHLEN;
8e029c65 134 bup = up;
1f2f436a
A
135 up[0] = '.';
136 up[1] = '\0';
137@@ -255,3 +324,11 @@ err:
224c7076
A
138 errno = save_errno;
139 return (NULL);
140 }
141+
142+char *
143+getcwd(pt, size)
144+ char *pt;
145+ size_t size;
146+{
147+ return __private_getcwd(pt, size, 1);
148+}