]>
Commit | Line | Data |
---|---|---|
7cc27f44 | 1 | /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. |
47707456 | 2 | This file is part of the GNU C Library. |
28f540f4 | 3 | |
47707456 UD |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public License as | |
6 | published by the Free Software Foundation; either version 2 of the | |
7 | License, or (at your option) any later version. | |
28f540f4 | 8 | |
47707456 UD |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Library General Public License for more details. | |
28f540f4 | 13 | |
47707456 UD |
14 | You should have received a copy of the GNU Library General Public |
15 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
16 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
17 | Boston, MA 02111-1307, USA. */ | |
28f540f4 RM |
18 | |
19 | /* Wants: | |
20 | AC_STDC_HEADERS | |
21 | AC_DIR_HEADER | |
22 | AC_UNISTD_H | |
23 | AC_MEMORY_H | |
24 | AC_CONST | |
25 | AC_ALLOCA | |
26 | */ | |
27 | ||
28 | /* AIX requires this to be the first thing in the file. */ | |
29 | #if defined (_AIX) && !defined (__GNUC__) | |
30 | #pragma alloca | |
31 | #endif | |
32 | ||
33 | #ifdef HAVE_CONFIG_H | |
34 | #include "config.h" | |
35 | #endif | |
36 | ||
37 | #include <errno.h> | |
38 | #include <sys/types.h> | |
39 | #include <sys/stat.h> | |
40 | ||
41 | #ifdef STDC_HEADERS | |
42 | #include <stddef.h> | |
43 | #endif | |
44 | ||
45 | #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) | |
46 | extern int errno; | |
47 | #endif | |
c4029823 UD |
48 | #ifndef __set_errno |
49 | #define __set_errno(val) errno = (val) | |
50 | #endif | |
28f540f4 RM |
51 | |
52 | #ifndef NULL | |
53 | #define NULL 0 | |
54 | #endif | |
55 | ||
56 | #if defined (USGr3) && !defined (DIRENT) | |
57 | #define DIRENT | |
58 | #endif /* USGr3 */ | |
59 | #if defined (Xenix) && !defined (SYSNDIR) | |
60 | #define SYSNDIR | |
61 | #endif /* Xenix */ | |
62 | ||
63 | #if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__) | |
64 | #include <dirent.h> | |
65 | #ifndef __GNU_LIBRARY__ | |
66 | #define D_NAMLEN(d) strlen((d)->d_name) | |
67 | #else | |
68 | #define HAVE_D_NAMLEN | |
69 | #define D_NAMLEN(d) ((d)->d_namlen) | |
70 | #endif | |
71 | #else /* not POSIX or DIRENT */ | |
72 | #define dirent direct | |
73 | #define D_NAMLEN(d) ((d)->d_namlen) | |
74 | #define HAVE_D_NAMLEN | |
75 | #if defined (USG) && !defined (sgi) | |
76 | #if defined (SYSNDIR) | |
77 | #include <sys/ndir.h> | |
78 | #else /* Not SYSNDIR */ | |
79 | #include "ndir.h" | |
80 | #endif /* SYSNDIR */ | |
81 | #else /* not USG */ | |
82 | #include <sys/dir.h> | |
83 | #endif /* USG */ | |
84 | #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */ | |
85 | ||
1d8dc429 | 86 | #if defined (HAVE_UNISTD_H) || defined (__GNU_LIBRARY__) |
28f540f4 RM |
87 | #include <unistd.h> |
88 | #endif | |
89 | ||
90 | #if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) \ | |
91 | || defined (POSIX)) | |
92 | #include <stdlib.h> | |
93 | #include <string.h> | |
94 | #define ANSI_STRING | |
95 | #else /* No standard headers. */ | |
96 | ||
97 | #ifdef USG | |
98 | ||
99 | #include <string.h> | |
100 | #ifdef NEED_MEMORY_H | |
101 | #include <memory.h> | |
102 | #endif | |
103 | #define ANSI_STRING | |
104 | ||
105 | #else /* Not USG. */ | |
106 | ||
107 | #ifdef NeXT | |
108 | ||
109 | #include <string.h> | |
110 | ||
111 | #else /* Not NeXT. */ | |
112 | ||
113 | #include <strings.h> | |
114 | ||
115 | #ifndef bcmp | |
116 | extern int bcmp (); | |
117 | #endif | |
118 | #ifndef bzero | |
119 | extern void bzero (); | |
120 | #endif | |
121 | #ifndef bcopy | |
122 | extern void bcopy (); | |
123 | #endif | |
124 | ||
125 | #endif /* NeXT. */ | |
126 | ||
127 | #endif /* USG. */ | |
128 | ||
129 | extern char *malloc (), *realloc (); | |
130 | extern void free (); | |
131 | ||
132 | #endif /* Standard headers. */ | |
133 | ||
134 | #ifndef ANSI_STRING | |
135 | #define memcpy(d, s, n) bcopy((s), (d), (n)) | |
136 | #define memmove memcpy | |
137 | #endif /* Not ANSI_STRING. */ | |
138 | ||
139 | #if !defined(__alloca) && !defined(__GNU_LIBRARY__) | |
140 | ||
141 | #ifdef __GNUC__ | |
142 | #undef alloca | |
143 | #define alloca(n) __builtin_alloca (n) | |
144 | #else /* Not GCC. */ | |
145 | #if defined (sparc) || defined (HAVE_ALLOCA_H) | |
146 | #include <alloca.h> | |
147 | #else /* Not sparc or HAVE_ALLOCA_H. */ | |
148 | #ifndef _AIX | |
149 | extern char *alloca (); | |
150 | #endif /* Not _AIX. */ | |
151 | #endif /* sparc or HAVE_ALLOCA_H. */ | |
152 | #endif /* GCC. */ | |
153 | ||
154 | #define __alloca alloca | |
155 | ||
156 | #endif | |
157 | ||
158 | #if (defined (HAVE_LIMITS_H) || defined (STDC_HEADERS) || \ | |
159 | defined (__GNU_LIBRARY__)) | |
160 | #include <limits.h> | |
161 | #else | |
162 | #include <sys/param.h> | |
163 | #endif | |
164 | ||
165 | #ifndef PATH_MAX | |
166 | #ifdef MAXPATHLEN | |
167 | #define PATH_MAX MAXPATHLEN | |
168 | #else | |
169 | #define PATH_MAX 1024 | |
170 | #endif | |
171 | #endif | |
172 | ||
b86199fb | 173 | #if !defined (STDC_HEADERS) && !defined (__GNU_LIBRARY__) |
28f540f4 RM |
174 | #undef size_t |
175 | #define size_t unsigned int | |
176 | #endif | |
177 | ||
178 | #if !__STDC__ && !defined (const) | |
179 | #define const | |
180 | #endif | |
181 | ||
182 | #ifndef __GNU_LIBRARY__ | |
183 | #define __lstat stat | |
184 | #endif | |
185 | \f | |
7f811679 RM |
186 | #ifndef _LIBC |
187 | #define __getcwd getcwd | |
188 | #endif | |
189 | ||
190 | /* Get the pathname of the current working directory, and put it in SIZE | |
28f540f4 RM |
191 | bytes of BUF. Returns NULL if the directory couldn't be determined or |
192 | SIZE was too small. If successful, returns BUF. In GNU, if BUF is | |
193 | NULL, an array is allocated with `malloc'; the array is SIZE bytes long, | |
194 | unless SIZE <= 0, in which case it is as big as necessary. */ | |
195 | ||
196 | char * | |
7f811679 | 197 | __getcwd (buf, size) |
28f540f4 RM |
198 | char *buf; |
199 | size_t size; | |
200 | { | |
201 | static const char dots[] | |
202 | = "../../../../../../../../../../../../../../../../../../../../../../../\ | |
203 | ../../../../../../../../../../../../../../../../../../../../../../../../../../\ | |
204 | ../../../../../../../../../../../../../../../../../../../../../../../../../.."; | |
205 | const char *dotp, *dotlist; | |
206 | size_t dotsize; | |
207 | dev_t rootdev, thisdev; | |
208 | ino_t rootino, thisino; | |
209 | char *path; | |
210 | register char *pathp; | |
211 | struct stat st; | |
212 | ||
213 | if (size == 0) | |
214 | { | |
215 | if (buf != NULL) | |
216 | { | |
c4029823 | 217 | __set_errno (EINVAL); |
28f540f4 RM |
218 | return NULL; |
219 | } | |
220 | ||
221 | size = PATH_MAX + 1; | |
222 | } | |
223 | ||
224 | if (buf != NULL) | |
225 | path = buf; | |
226 | else | |
227 | { | |
228 | path = malloc (size); | |
229 | if (path == NULL) | |
230 | return NULL; | |
231 | } | |
232 | ||
233 | pathp = path + size; | |
234 | *--pathp = '\0'; | |
235 | ||
7f811679 | 236 | if (__lstat (".", &st) < 0) |
28f540f4 RM |
237 | return NULL; |
238 | thisdev = st.st_dev; | |
239 | thisino = st.st_ino; | |
240 | ||
241 | if (__lstat ("/", &st) < 0) | |
242 | return NULL; | |
243 | rootdev = st.st_dev; | |
244 | rootino = st.st_ino; | |
245 | ||
246 | dotsize = sizeof (dots) - 1; | |
247 | dotp = &dots[sizeof (dots)]; | |
248 | dotlist = dots; | |
249 | while (!(thisdev == rootdev && thisino == rootino)) | |
250 | { | |
251 | register DIR *dirstream; | |
a18f587d | 252 | struct dirent *d; |
28f540f4 RM |
253 | dev_t dotdev; |
254 | ino_t dotino; | |
255 | char mount_point; | |
256 | ||
257 | /* Look at the parent directory. */ | |
258 | if (dotp == dotlist) | |
259 | { | |
260 | /* My, what a deep directory tree you have, Grandma. */ | |
261 | char *new; | |
262 | if (dotlist == dots) | |
263 | { | |
264 | new = malloc (dotsize * 2 + 1); | |
265 | if (new == NULL) | |
266 | return NULL; | |
267 | memcpy (new, dots, dotsize); | |
268 | } | |
269 | else | |
270 | { | |
271 | new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1); | |
272 | if (new == NULL) | |
273 | goto lose; | |
274 | } | |
275 | memcpy (&new[dotsize], new, dotsize); | |
276 | dotp = &new[dotsize]; | |
277 | dotsize *= 2; | |
278 | new[dotsize] = '\0'; | |
279 | dotlist = new; | |
280 | } | |
281 | ||
282 | dotp -= 3; | |
283 | ||
284 | /* Figure out if this directory is a mount point. */ | |
285 | if (__lstat (dotp, &st) < 0) | |
286 | goto lose; | |
287 | dotdev = st.st_dev; | |
288 | dotino = st.st_ino; | |
289 | mount_point = dotdev != thisdev; | |
290 | ||
291 | /* Search for the last directory. */ | |
23396375 | 292 | dirstream = __opendir (dotp); |
28f540f4 RM |
293 | if (dirstream == NULL) |
294 | goto lose; | |
10dc2a90 | 295 | while ((d = __readdir (dirstream)) != NULL) |
28f540f4 RM |
296 | { |
297 | if (d->d_name[0] == '.' && | |
92777700 RM |
298 | (d->d_name[1] == '\0' || |
299 | (d->d_name[1] == '.' && d->d_name[2] == '\0'))) | |
28f540f4 | 300 | continue; |
d68171ed | 301 | if (mount_point || (ino_t) d->d_ino == thisino) |
28f540f4 | 302 | { |
92777700 | 303 | char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)]; |
28f540f4 RM |
304 | memcpy (name, dotp, dotlist + dotsize - dotp); |
305 | name[dotlist + dotsize - dotp] = '/'; | |
92777700 | 306 | strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name); |
28f540f4 RM |
307 | if (__lstat (name, &st) < 0) |
308 | { | |
309 | int save = errno; | |
23396375 | 310 | (void) __closedir (dirstream); |
c4029823 | 311 | __set_errno (save); |
28f540f4 RM |
312 | goto lose; |
313 | } | |
314 | if (st.st_dev == thisdev && st.st_ino == thisino) | |
315 | break; | |
316 | } | |
317 | } | |
318 | if (d == NULL) | |
319 | { | |
320 | int save = errno; | |
23396375 | 321 | (void) __closedir (dirstream); |
c4029823 | 322 | __set_errno (save); |
28f540f4 RM |
323 | goto lose; |
324 | } | |
325 | else | |
326 | { | |
92777700 RM |
327 | size_t namlen = _D_EXACT_NAMLEN (d); |
328 | ||
d68171ed | 329 | if ((size_t) (pathp - path) < namlen) |
28f540f4 RM |
330 | { |
331 | if (buf != NULL) | |
332 | { | |
7cc27f44 | 333 | (void) __closedir (dirstream); |
c4029823 | 334 | __set_errno (ERANGE); |
7cc27f44 | 335 | goto lose; |
28f540f4 RM |
336 | } |
337 | else | |
338 | { | |
339 | size *= 2; | |
340 | buf = realloc (path, size); | |
341 | if (buf == NULL) | |
342 | { | |
23396375 | 343 | (void) __closedir (dirstream); |
28f540f4 | 344 | free (path); |
c4029823 | 345 | __set_errno (ENOMEM);/* closedir might have changed it.*/ |
7cc27f44 | 346 | goto lose; |
28f540f4 | 347 | } |
8a523922 | 348 | pathp = &buf[pathp - path + size / 2]; |
28f540f4 | 349 | path = buf; |
8a523922 UD |
350 | /* Move current contents up to the end of the buffer. |
351 | This is guaranteed to be non-overlapping. */ | |
352 | memcpy (pathp, pathp - size / 2, path + size - pathp); | |
28f540f4 RM |
353 | } |
354 | } | |
92777700 RM |
355 | pathp -= namlen; |
356 | (void) memcpy (pathp, d->d_name, namlen); | |
28f540f4 | 357 | *--pathp = '/'; |
23396375 | 358 | (void) __closedir (dirstream); |
28f540f4 RM |
359 | } |
360 | ||
361 | thisdev = dotdev; | |
362 | thisino = dotino; | |
363 | } | |
364 | ||
365 | if (pathp == &path[size - 1]) | |
366 | *--pathp = '/'; | |
367 | ||
368 | if (dotlist != dots) | |
369 | free ((__ptr_t) dotlist); | |
370 | ||
371 | memmove (path, pathp, path + size - pathp); | |
372 | return path; | |
373 | ||
374 | lose: | |
375 | if (dotlist != dots) | |
376 | free ((__ptr_t) dotlist); | |
377 | return NULL; | |
378 | } | |
3ec41e03 RM |
379 | |
380 | #ifdef _LIBC | |
381 | weak_alias (__getcwd, getcwd) | |
382 | #endif |