1*56bb7041Schristos /* Copyright (C) 1991-1999, 2004-2020 Free Software Foundation, Inc.
2*56bb7041Schristos This file is part of the GNU C Library.
3*56bb7041Schristos
4*56bb7041Schristos This program is free software: you can redistribute it and/or modify
5*56bb7041Schristos it under the terms of the GNU General Public License as published by
6*56bb7041Schristos the Free Software Foundation; either version 3 of the License, or
7*56bb7041Schristos (at your option) any later version.
8*56bb7041Schristos
9*56bb7041Schristos This program is distributed in the hope that it will be useful,
10*56bb7041Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
11*56bb7041Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*56bb7041Schristos GNU General Public License for more details.
13*56bb7041Schristos
14*56bb7041Schristos You should have received a copy of the GNU General Public License
15*56bb7041Schristos along with this program. If not, see <https://www.gnu.org/licenses/>. */
16*56bb7041Schristos
17*56bb7041Schristos #if !_LIBC
18*56bb7041Schristos # include <config.h>
19*56bb7041Schristos # include <unistd.h>
20*56bb7041Schristos #endif
21*56bb7041Schristos
22*56bb7041Schristos #include <errno.h>
23*56bb7041Schristos #include <sys/types.h>
24*56bb7041Schristos #include <sys/stat.h>
25*56bb7041Schristos #include <stdbool.h>
26*56bb7041Schristos #include <stddef.h>
27*56bb7041Schristos
28*56bb7041Schristos #include <fcntl.h> /* For AT_FDCWD on Solaris 9. */
29*56bb7041Schristos
30*56bb7041Schristos /* If this host provides the openat function or if we're using the
31*56bb7041Schristos gnulib replacement function with a native fdopendir, then enable
32*56bb7041Schristos code below to make getcwd more efficient and robust. */
33*56bb7041Schristos #if defined HAVE_OPENAT || (defined GNULIB_OPENAT && defined HAVE_FDOPENDIR)
34*56bb7041Schristos # define HAVE_OPENAT_SUPPORT 1
35*56bb7041Schristos #else
36*56bb7041Schristos # define HAVE_OPENAT_SUPPORT 0
37*56bb7041Schristos #endif
38*56bb7041Schristos
39*56bb7041Schristos #ifndef __set_errno
40*56bb7041Schristos # define __set_errno(val) (errno = (val))
41*56bb7041Schristos #endif
42*56bb7041Schristos
43*56bb7041Schristos #include <dirent.h>
44*56bb7041Schristos #ifndef _D_EXACT_NAMLEN
45*56bb7041Schristos # define _D_EXACT_NAMLEN(d) strlen ((d)->d_name)
46*56bb7041Schristos #endif
47*56bb7041Schristos #ifndef _D_ALLOC_NAMLEN
48*56bb7041Schristos # define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1)
49*56bb7041Schristos #endif
50*56bb7041Schristos
51*56bb7041Schristos #include <unistd.h>
52*56bb7041Schristos #include <stdlib.h>
53*56bb7041Schristos #include <string.h>
54*56bb7041Schristos
55*56bb7041Schristos #if _LIBC
56*56bb7041Schristos # ifndef mempcpy
57*56bb7041Schristos # define mempcpy __mempcpy
58*56bb7041Schristos # endif
59*56bb7041Schristos #endif
60*56bb7041Schristos
61*56bb7041Schristos #ifndef MAX
62*56bb7041Schristos # define MAX(a, b) ((a) < (b) ? (b) : (a))
63*56bb7041Schristos #endif
64*56bb7041Schristos #ifndef MIN
65*56bb7041Schristos # define MIN(a, b) ((a) < (b) ? (a) : (b))
66*56bb7041Schristos #endif
67*56bb7041Schristos
68*56bb7041Schristos #include "pathmax.h"
69*56bb7041Schristos
70*56bb7041Schristos /* In this file, PATH_MAX only serves as a threshold for choosing among two
71*56bb7041Schristos algorithms. */
72*56bb7041Schristos #ifndef PATH_MAX
73*56bb7041Schristos # define PATH_MAX 8192
74*56bb7041Schristos #endif
75*56bb7041Schristos
76*56bb7041Schristos #if D_INO_IN_DIRENT
77*56bb7041Schristos # define MATCHING_INO(dp, ino) ((dp)->d_ino == (ino))
78*56bb7041Schristos #else
79*56bb7041Schristos # define MATCHING_INO(dp, ino) true
80*56bb7041Schristos #endif
81*56bb7041Schristos
82*56bb7041Schristos #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
83*56bb7041Schristos # include "msvc-inval.h"
84*56bb7041Schristos #endif
85*56bb7041Schristos
86*56bb7041Schristos #if !_LIBC
87*56bb7041Schristos # define __getcwd rpl_getcwd
88*56bb7041Schristos # define __lstat lstat
89*56bb7041Schristos # define __closedir closedir
90*56bb7041Schristos # define __opendir opendir
91*56bb7041Schristos # define __readdir readdir
92*56bb7041Schristos #endif
93*56bb7041Schristos
94*56bb7041Schristos /* The results of opendir() in this file are not used with dirfd and fchdir,
95*56bb7041Schristos and we do not leak fds to any single-threaded code that could use stdio,
96*56bb7041Schristos therefore save some unnecessary recursion in fchdir.c.
97*56bb7041Schristos FIXME - if the kernel ever adds support for multi-thread safety for
98*56bb7041Schristos avoiding standard fds, then we should use opendir_safer and
99*56bb7041Schristos openat_safer. */
100*56bb7041Schristos #ifdef GNULIB_defined_opendir
101*56bb7041Schristos # undef opendir
102*56bb7041Schristos #endif
103*56bb7041Schristos #ifdef GNULIB_defined_closedir
104*56bb7041Schristos # undef closedir
105*56bb7041Schristos #endif
106*56bb7041Schristos
107*56bb7041Schristos #ifdef _MSC_VER
108*56bb7041Schristos # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
109*56bb7041Schristos static char *
getcwd_nothrow(char * buf,size_t size)110*56bb7041Schristos getcwd_nothrow (char *buf, size_t size)
111*56bb7041Schristos {
112*56bb7041Schristos char *result;
113*56bb7041Schristos
114*56bb7041Schristos TRY_MSVC_INVAL
115*56bb7041Schristos {
116*56bb7041Schristos result = _getcwd (buf, size);
117*56bb7041Schristos }
118*56bb7041Schristos CATCH_MSVC_INVAL
119*56bb7041Schristos {
120*56bb7041Schristos result = NULL;
121*56bb7041Schristos errno = ERANGE;
122*56bb7041Schristos }
123*56bb7041Schristos DONE_MSVC_INVAL;
124*56bb7041Schristos
125*56bb7041Schristos return result;
126*56bb7041Schristos }
127*56bb7041Schristos # else
128*56bb7041Schristos # define getcwd_nothrow _getcwd
129*56bb7041Schristos # endif
130*56bb7041Schristos # define getcwd_system getcwd_nothrow
131*56bb7041Schristos #else
132*56bb7041Schristos # define getcwd_system getcwd
133*56bb7041Schristos #endif
134*56bb7041Schristos
135*56bb7041Schristos /* Get the name of the current working directory, and put it in SIZE
136*56bb7041Schristos bytes of BUF. Returns NULL with errno set if the directory couldn't be
137*56bb7041Schristos determined or SIZE was too small. If successful, returns BUF. In GNU,
138*56bb7041Schristos if BUF is NULL, an array is allocated with 'malloc'; the array is SIZE
139*56bb7041Schristos bytes long, unless SIZE == 0, in which case it is as big as necessary. */
140*56bb7041Schristos
141*56bb7041Schristos char *
__getcwd(char * buf,size_t size)142*56bb7041Schristos __getcwd (char *buf, size_t size)
143*56bb7041Schristos {
144*56bb7041Schristos /* Lengths of big file name components and entire file names, and a
145*56bb7041Schristos deep level of file name nesting. These numbers are not upper
146*56bb7041Schristos bounds; they are merely large values suitable for initial
147*56bb7041Schristos allocations, designed to be large enough for most real-world
148*56bb7041Schristos uses. */
149*56bb7041Schristos enum
150*56bb7041Schristos {
151*56bb7041Schristos BIG_FILE_NAME_COMPONENT_LENGTH = 255,
152*56bb7041Schristos BIG_FILE_NAME_LENGTH = MIN (4095, PATH_MAX - 1),
153*56bb7041Schristos DEEP_NESTING = 100
154*56bb7041Schristos };
155*56bb7041Schristos
156*56bb7041Schristos #if HAVE_OPENAT_SUPPORT
157*56bb7041Schristos int fd = AT_FDCWD;
158*56bb7041Schristos bool fd_needs_closing = false;
159*56bb7041Schristos #else
160*56bb7041Schristos char dots[DEEP_NESTING * sizeof ".." + BIG_FILE_NAME_COMPONENT_LENGTH + 1];
161*56bb7041Schristos char *dotlist = dots;
162*56bb7041Schristos size_t dotsize = sizeof dots;
163*56bb7041Schristos size_t dotlen = 0;
164*56bb7041Schristos #endif
165*56bb7041Schristos DIR *dirstream = NULL;
166*56bb7041Schristos dev_t rootdev, thisdev;
167*56bb7041Schristos ino_t rootino, thisino;
168*56bb7041Schristos char *dir;
169*56bb7041Schristos register char *dirp;
170*56bb7041Schristos struct stat st;
171*56bb7041Schristos size_t allocated = size;
172*56bb7041Schristos size_t used;
173*56bb7041Schristos
174*56bb7041Schristos #if HAVE_MINIMALLY_WORKING_GETCWD
175*56bb7041Schristos /* If AT_FDCWD is not defined, the algorithm below is O(N**2) and
176*56bb7041Schristos this is much slower than the system getcwd (at least on
177*56bb7041Schristos GNU/Linux). So trust the system getcwd's results unless they
178*56bb7041Schristos look suspicious.
179*56bb7041Schristos
180*56bb7041Schristos Use the system getcwd even if we have openat support, since the
181*56bb7041Schristos system getcwd works even when a parent is unreadable, while the
182*56bb7041Schristos openat-based approach does not.
183*56bb7041Schristos
184*56bb7041Schristos But on AIX 5.1..7.1, the system getcwd is not even minimally
185*56bb7041Schristos working: If the current directory name is slightly longer than
186*56bb7041Schristos PATH_MAX, it omits the first directory component and returns
187*56bb7041Schristos this wrong result with errno = 0. */
188*56bb7041Schristos
189*56bb7041Schristos # undef getcwd
190*56bb7041Schristos dir = getcwd_system (buf, size);
191*56bb7041Schristos if (dir || (size && errno == ERANGE))
192*56bb7041Schristos return dir;
193*56bb7041Schristos
194*56bb7041Schristos /* Solaris getcwd (NULL, 0) fails with errno == EINVAL, but it has
195*56bb7041Schristos internal magic that lets it work even if an ancestor directory is
196*56bb7041Schristos inaccessible, which is better in many cases. So in this case try
197*56bb7041Schristos again with a buffer that's almost always big enough. */
198*56bb7041Schristos if (errno == EINVAL && buf == NULL && size == 0)
199*56bb7041Schristos {
200*56bb7041Schristos char big_buffer[BIG_FILE_NAME_LENGTH + 1];
201*56bb7041Schristos dir = getcwd_system (big_buffer, sizeof big_buffer);
202*56bb7041Schristos if (dir)
203*56bb7041Schristos return strdup (dir);
204*56bb7041Schristos }
205*56bb7041Schristos
206*56bb7041Schristos # if HAVE_PARTLY_WORKING_GETCWD
207*56bb7041Schristos /* The system getcwd works, except it sometimes fails when it
208*56bb7041Schristos shouldn't, setting errno to ERANGE, ENAMETOOLONG, or ENOENT. */
209*56bb7041Schristos if (errno != ERANGE && errno != ENAMETOOLONG && errno != ENOENT)
210*56bb7041Schristos return NULL;
211*56bb7041Schristos # endif
212*56bb7041Schristos #endif
213*56bb7041Schristos
214*56bb7041Schristos if (size == 0)
215*56bb7041Schristos {
216*56bb7041Schristos if (buf != NULL)
217*56bb7041Schristos {
218*56bb7041Schristos __set_errno (EINVAL);
219*56bb7041Schristos return NULL;
220*56bb7041Schristos }
221*56bb7041Schristos
222*56bb7041Schristos allocated = BIG_FILE_NAME_LENGTH + 1;
223*56bb7041Schristos }
224*56bb7041Schristos
225*56bb7041Schristos if (buf == NULL)
226*56bb7041Schristos {
227*56bb7041Schristos dir = malloc (allocated);
228*56bb7041Schristos if (dir == NULL)
229*56bb7041Schristos return NULL;
230*56bb7041Schristos }
231*56bb7041Schristos else
232*56bb7041Schristos dir = buf;
233*56bb7041Schristos
234*56bb7041Schristos dirp = dir + allocated;
235*56bb7041Schristos *--dirp = '\0';
236*56bb7041Schristos
237*56bb7041Schristos if (__lstat (".", &st) < 0)
238*56bb7041Schristos goto lose;
239*56bb7041Schristos thisdev = st.st_dev;
240*56bb7041Schristos thisino = st.st_ino;
241*56bb7041Schristos
242*56bb7041Schristos if (__lstat ("/", &st) < 0)
243*56bb7041Schristos goto lose;
244*56bb7041Schristos rootdev = st.st_dev;
245*56bb7041Schristos rootino = st.st_ino;
246*56bb7041Schristos
247*56bb7041Schristos while (!(thisdev == rootdev && thisino == rootino))
248*56bb7041Schristos {
249*56bb7041Schristos struct dirent *d;
250*56bb7041Schristos dev_t dotdev;
251*56bb7041Schristos ino_t dotino;
252*56bb7041Schristos bool mount_point;
253*56bb7041Schristos int parent_status;
254*56bb7041Schristos size_t dirroom;
255*56bb7041Schristos size_t namlen;
256*56bb7041Schristos bool use_d_ino = true;
257*56bb7041Schristos
258*56bb7041Schristos /* Look at the parent directory. */
259*56bb7041Schristos #if HAVE_OPENAT_SUPPORT
260*56bb7041Schristos fd = openat (fd, "..", O_RDONLY);
261*56bb7041Schristos if (fd < 0)
262*56bb7041Schristos goto lose;
263*56bb7041Schristos fd_needs_closing = true;
264*56bb7041Schristos parent_status = fstat (fd, &st);
265*56bb7041Schristos #else
266*56bb7041Schristos dotlist[dotlen++] = '.';
267*56bb7041Schristos dotlist[dotlen++] = '.';
268*56bb7041Schristos dotlist[dotlen] = '\0';
269*56bb7041Schristos parent_status = __lstat (dotlist, &st);
270*56bb7041Schristos #endif
271*56bb7041Schristos if (parent_status != 0)
272*56bb7041Schristos goto lose;
273*56bb7041Schristos
274*56bb7041Schristos if (dirstream && __closedir (dirstream) != 0)
275*56bb7041Schristos {
276*56bb7041Schristos dirstream = NULL;
277*56bb7041Schristos goto lose;
278*56bb7041Schristos }
279*56bb7041Schristos
280*56bb7041Schristos /* Figure out if this directory is a mount point. */
281*56bb7041Schristos dotdev = st.st_dev;
282*56bb7041Schristos dotino = st.st_ino;
283*56bb7041Schristos mount_point = dotdev != thisdev;
284*56bb7041Schristos
285*56bb7041Schristos /* Search for the last directory. */
286*56bb7041Schristos #if HAVE_OPENAT_SUPPORT
287*56bb7041Schristos dirstream = fdopendir (fd);
288*56bb7041Schristos if (dirstream == NULL)
289*56bb7041Schristos goto lose;
290*56bb7041Schristos fd_needs_closing = false;
291*56bb7041Schristos #else
292*56bb7041Schristos dirstream = __opendir (dotlist);
293*56bb7041Schristos if (dirstream == NULL)
294*56bb7041Schristos goto lose;
295*56bb7041Schristos dotlist[dotlen++] = '/';
296*56bb7041Schristos #endif
297*56bb7041Schristos for (;;)
298*56bb7041Schristos {
299*56bb7041Schristos /* Clear errno to distinguish EOF from error if readdir returns
300*56bb7041Schristos NULL. */
301*56bb7041Schristos __set_errno (0);
302*56bb7041Schristos d = __readdir (dirstream);
303*56bb7041Schristos
304*56bb7041Schristos /* When we've iterated through all directory entries without finding
305*56bb7041Schristos one with a matching d_ino, rewind the stream and consider each
306*56bb7041Schristos name again, but this time, using lstat. This is necessary in a
307*56bb7041Schristos chroot on at least one system (glibc-2.3.6 + linux 2.6.12), where
308*56bb7041Schristos .., ../.., ../../.., etc. all had the same device number, yet the
309*56bb7041Schristos d_ino values for entries in / did not match those obtained
310*56bb7041Schristos via lstat. */
311*56bb7041Schristos if (d == NULL && errno == 0 && use_d_ino)
312*56bb7041Schristos {
313*56bb7041Schristos use_d_ino = false;
314*56bb7041Schristos rewinddir (dirstream);
315*56bb7041Schristos d = __readdir (dirstream);
316*56bb7041Schristos }
317*56bb7041Schristos
318*56bb7041Schristos if (d == NULL)
319*56bb7041Schristos {
320*56bb7041Schristos if (errno == 0)
321*56bb7041Schristos /* EOF on dirstream, which can mean e.g., that the current
322*56bb7041Schristos directory has been removed. */
323*56bb7041Schristos __set_errno (ENOENT);
324*56bb7041Schristos goto lose;
325*56bb7041Schristos }
326*56bb7041Schristos if (d->d_name[0] == '.' &&
327*56bb7041Schristos (d->d_name[1] == '\0' ||
328*56bb7041Schristos (d->d_name[1] == '.' && d->d_name[2] == '\0')))
329*56bb7041Schristos continue;
330*56bb7041Schristos
331*56bb7041Schristos if (use_d_ino)
332*56bb7041Schristos {
333*56bb7041Schristos bool match = (MATCHING_INO (d, thisino) || mount_point);
334*56bb7041Schristos if (! match)
335*56bb7041Schristos continue;
336*56bb7041Schristos }
337*56bb7041Schristos
338*56bb7041Schristos {
339*56bb7041Schristos int entry_status;
340*56bb7041Schristos #if HAVE_OPENAT_SUPPORT
341*56bb7041Schristos entry_status = fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW);
342*56bb7041Schristos #else
343*56bb7041Schristos /* Compute size needed for this file name, or for the file
344*56bb7041Schristos name ".." in the same directory, whichever is larger.
345*56bb7041Schristos Room for ".." might be needed the next time through
346*56bb7041Schristos the outer loop. */
347*56bb7041Schristos size_t name_alloc = _D_ALLOC_NAMLEN (d);
348*56bb7041Schristos size_t filesize = dotlen + MAX (sizeof "..", name_alloc);
349*56bb7041Schristos
350*56bb7041Schristos if (filesize < dotlen)
351*56bb7041Schristos goto memory_exhausted;
352*56bb7041Schristos
353*56bb7041Schristos if (dotsize < filesize)
354*56bb7041Schristos {
355*56bb7041Schristos /* My, what a deep directory tree you have, Grandma. */
356*56bb7041Schristos size_t newsize = MAX (filesize, dotsize * 2);
357*56bb7041Schristos size_t i;
358*56bb7041Schristos if (newsize < dotsize)
359*56bb7041Schristos goto memory_exhausted;
360*56bb7041Schristos if (dotlist != dots)
361*56bb7041Schristos free (dotlist);
362*56bb7041Schristos dotlist = malloc (newsize);
363*56bb7041Schristos if (dotlist == NULL)
364*56bb7041Schristos goto lose;
365*56bb7041Schristos dotsize = newsize;
366*56bb7041Schristos
367*56bb7041Schristos i = 0;
368*56bb7041Schristos do
369*56bb7041Schristos {
370*56bb7041Schristos dotlist[i++] = '.';
371*56bb7041Schristos dotlist[i++] = '.';
372*56bb7041Schristos dotlist[i++] = '/';
373*56bb7041Schristos }
374*56bb7041Schristos while (i < dotlen);
375*56bb7041Schristos }
376*56bb7041Schristos
377*56bb7041Schristos memcpy (dotlist + dotlen, d->d_name, _D_ALLOC_NAMLEN (d));
378*56bb7041Schristos entry_status = __lstat (dotlist, &st);
379*56bb7041Schristos #endif
380*56bb7041Schristos /* We don't fail here if we cannot stat() a directory entry.
381*56bb7041Schristos This can happen when (network) file systems fail. If this
382*56bb7041Schristos entry is in fact the one we are looking for we will find
383*56bb7041Schristos out soon as we reach the end of the directory without
384*56bb7041Schristos having found anything. */
385*56bb7041Schristos if (entry_status == 0 && S_ISDIR (st.st_mode)
386*56bb7041Schristos && st.st_dev == thisdev && st.st_ino == thisino)
387*56bb7041Schristos break;
388*56bb7041Schristos }
389*56bb7041Schristos }
390*56bb7041Schristos
391*56bb7041Schristos dirroom = dirp - dir;
392*56bb7041Schristos namlen = _D_EXACT_NAMLEN (d);
393*56bb7041Schristos
394*56bb7041Schristos if (dirroom <= namlen)
395*56bb7041Schristos {
396*56bb7041Schristos if (size != 0)
397*56bb7041Schristos {
398*56bb7041Schristos __set_errno (ERANGE);
399*56bb7041Schristos goto lose;
400*56bb7041Schristos }
401*56bb7041Schristos else
402*56bb7041Schristos {
403*56bb7041Schristos char *tmp;
404*56bb7041Schristos size_t oldsize = allocated;
405*56bb7041Schristos
406*56bb7041Schristos allocated += MAX (allocated, namlen);
407*56bb7041Schristos if (allocated < oldsize
408*56bb7041Schristos || ! (tmp = realloc (dir, allocated)))
409*56bb7041Schristos goto memory_exhausted;
410*56bb7041Schristos
411*56bb7041Schristos /* Move current contents up to the end of the buffer.
412*56bb7041Schristos This is guaranteed to be non-overlapping. */
413*56bb7041Schristos dirp = memcpy (tmp + allocated - (oldsize - dirroom),
414*56bb7041Schristos tmp + dirroom,
415*56bb7041Schristos oldsize - dirroom);
416*56bb7041Schristos dir = tmp;
417*56bb7041Schristos }
418*56bb7041Schristos }
419*56bb7041Schristos dirp -= namlen;
420*56bb7041Schristos memcpy (dirp, d->d_name, namlen);
421*56bb7041Schristos *--dirp = '/';
422*56bb7041Schristos
423*56bb7041Schristos thisdev = dotdev;
424*56bb7041Schristos thisino = dotino;
425*56bb7041Schristos }
426*56bb7041Schristos
427*56bb7041Schristos if (dirstream && __closedir (dirstream) != 0)
428*56bb7041Schristos {
429*56bb7041Schristos dirstream = NULL;
430*56bb7041Schristos goto lose;
431*56bb7041Schristos }
432*56bb7041Schristos
433*56bb7041Schristos if (dirp == &dir[allocated - 1])
434*56bb7041Schristos *--dirp = '/';
435*56bb7041Schristos
436*56bb7041Schristos #if ! HAVE_OPENAT_SUPPORT
437*56bb7041Schristos if (dotlist != dots)
438*56bb7041Schristos free (dotlist);
439*56bb7041Schristos #endif
440*56bb7041Schristos
441*56bb7041Schristos used = dir + allocated - dirp;
442*56bb7041Schristos memmove (dir, dirp, used);
443*56bb7041Schristos
444*56bb7041Schristos if (size == 0)
445*56bb7041Schristos /* Ensure that the buffer is only as large as necessary. */
446*56bb7041Schristos buf = (used < allocated ? realloc (dir, used) : dir);
447*56bb7041Schristos
448*56bb7041Schristos if (buf == NULL)
449*56bb7041Schristos /* Either buf was NULL all along, or 'realloc' failed but
450*56bb7041Schristos we still have the original string. */
451*56bb7041Schristos buf = dir;
452*56bb7041Schristos
453*56bb7041Schristos return buf;
454*56bb7041Schristos
455*56bb7041Schristos memory_exhausted:
456*56bb7041Schristos __set_errno (ENOMEM);
457*56bb7041Schristos lose:
458*56bb7041Schristos {
459*56bb7041Schristos int save = errno;
460*56bb7041Schristos if (dirstream)
461*56bb7041Schristos __closedir (dirstream);
462*56bb7041Schristos #if HAVE_OPENAT_SUPPORT
463*56bb7041Schristos if (fd_needs_closing)
464*56bb7041Schristos close (fd);
465*56bb7041Schristos #else
466*56bb7041Schristos if (dotlist != dots)
467*56bb7041Schristos free (dotlist);
468*56bb7041Schristos #endif
469*56bb7041Schristos if (buf == NULL)
470*56bb7041Schristos free (dir);
471*56bb7041Schristos __set_errno (save);
472*56bb7041Schristos }
473*56bb7041Schristos return NULL;
474*56bb7041Schristos }
475*56bb7041Schristos
476*56bb7041Schristos #ifdef weak_alias
477*56bb7041Schristos weak_alias (__getcwd, getcwd)
478*56bb7041Schristos #endif
479