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