]>
Commit | Line | Data |
---|---|---|
224c7076 A |
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 @@ | |
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; | |
94 | @@ -91,31 +166,25 @@ | |
8e029c65 A |
95 | } |
96 | ept = pt + size; | |
97 | } else { | |
98 | - if ((pt = malloc(ptsize = 1024 - 4)) == NULL) | |
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 A |
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; | |
224c7076 A |
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 | +} |