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