]> git.saurik.com Git - apple/libc.git/blob - gen/FreeBSD/getcwd.c.patch
Libc-498.1.5.tar.gz
[apple/libc.git] / gen / FreeBSD / getcwd.c.patch
1 --- getcwd.c.orig 2006-06-07 17:42:52.000000000 -0700
2 +++ getcwd.c 2006-06-07 17:44:47.000000000 -0700
3 @@ -54,12 +54,87 @@
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);
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;
46
47 -char *
48 -getcwd(pt, size)
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 +}
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;
94 @@ -91,31 +166,25 @@
95 }
96 ept = pt + size;
97 } else {
98 - if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
99 + if ((pt = malloc(ptsize = MAXPATHLEN)) == NULL)
100 return (NULL);
101 ept = pt + ptsize;
102 }
103 - if (__getcwd(pt, ept - pt) == 0) {
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 - }
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 }
120 bpt = ept - 1;
121 *bpt = '\0';
122
123 /*
124 - * Allocate bytes (1024 - malloc space) for the string of "../"'s.
125 + * Allocate bytes MAXPATHLEN) for the string of "../"'s.
126 * Should always be enough (it's 340 levels). If it's not, allocate
127 * as necessary. Special case the first stat, it's ".", not "..".
128 */
129 - if ((up = malloc(upsize = 1024 - 4)) == NULL)
130 + if ((up = malloc(upsize = MAXPATHLEN)) == NULL)
131 goto err;
132 eup = up + MAXPATHLEN;
133 bup = up;
134 @@ -259,3 +328,11 @@
135 errno = save_errno;
136 return (NULL);
137 }
138 +
139 +char *
140 +getcwd(pt, size)
141 + char *pt;
142 + size_t size;
143 +{
144 + return __private_getcwd(pt, size, 1);
145 +}