Blame gnulib-tests/getcwd-lgpl.c

Packit 33f14e
/* Copyright (C) 2011-2017 Free Software Foundation, Inc.
Packit 33f14e
   This file is part of gnulib.
Packit 33f14e
Packit 33f14e
   This program is free software: you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3 of the License, or
Packit 33f14e
   (at your option) any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License
Packit 33f14e
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
#include <config.h>
Packit 33f14e
Packit 33f14e
/* Specification */
Packit 33f14e
#include <unistd.h>
Packit 33f14e
Packit 33f14e
#include <errno.h>
Packit 33f14e
#include <stdlib.h>
Packit 33f14e
#include <string.h>
Packit 33f14e
Packit 33f14e
#if GNULIB_GETCWD
Packit 33f14e
/* Favor GPL getcwd.c if both getcwd and getcwd-lgpl modules are in use.  */
Packit 33f14e
typedef int dummy;
Packit 33f14e
#else
Packit 33f14e
Packit 33f14e
/* Get the name of the current working directory, and put it in SIZE
Packit 33f14e
   bytes of BUF.  Returns NULL if the directory couldn't be determined
Packit 33f14e
   (perhaps because the absolute name was longer than PATH_MAX, or
Packit 33f14e
   because of missing read/search permissions on parent directories)
Packit 33f14e
   or SIZE was too small.  If successful, returns BUF.  If BUF is
Packit 33f14e
   NULL, an array is allocated with 'malloc'; the array is SIZE bytes
Packit 33f14e
   long, unless SIZE == 0, in which case it is as big as
Packit 33f14e
   necessary.  */
Packit 33f14e
Packit 33f14e
# undef getcwd
Packit 33f14e
char *
Packit 33f14e
rpl_getcwd (char *buf, size_t size)
Packit 33f14e
{
Packit 33f14e
  char *ptr;
Packit 33f14e
  char *result;
Packit 33f14e
Packit 33f14e
  /* Handle single size operations.  */
Packit 33f14e
  if (buf)
Packit 33f14e
    {
Packit 33f14e
      if (!size)
Packit 33f14e
        {
Packit 33f14e
          errno = EINVAL;
Packit 33f14e
          return NULL;
Packit 33f14e
        }
Packit 33f14e
      return getcwd (buf, size);
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  if (size)
Packit 33f14e
    {
Packit 33f14e
      buf = malloc (size);
Packit 33f14e
      if (!buf)
Packit 33f14e
        {
Packit 33f14e
          errno = ENOMEM;
Packit 33f14e
          return NULL;
Packit 33f14e
        }
Packit 33f14e
      result = getcwd (buf, size);
Packit 33f14e
      if (!result)
Packit 33f14e
        {
Packit 33f14e
          int saved_errno = errno;
Packit 33f14e
          free (buf);
Packit 33f14e
          errno = saved_errno;
Packit 33f14e
        }
Packit 33f14e
      return result;
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
  /* Flexible sizing requested.  Avoid over-allocation for the common
Packit 33f14e
     case of a name that fits within a 4k page, minus some space for
Packit 33f14e
     local variables, to be sure we don't skip over a guard page.  */
Packit 33f14e
  {
Packit 33f14e
    char tmp[4032];
Packit 33f14e
    size = sizeof tmp;
Packit 33f14e
    ptr = getcwd (tmp, size);
Packit 33f14e
    if (ptr)
Packit 33f14e
      {
Packit 33f14e
        result = strdup (ptr);
Packit 33f14e
        if (!result)
Packit 33f14e
          errno = ENOMEM;
Packit 33f14e
        return result;
Packit 33f14e
      }
Packit 33f14e
    if (errno != ERANGE)
Packit 33f14e
      return NULL;
Packit 33f14e
  }
Packit 33f14e
Packit 33f14e
  /* My what a large directory name we have.  */
Packit 33f14e
  do
Packit 33f14e
    {
Packit 33f14e
      size <<= 1;
Packit 33f14e
      ptr = realloc (buf, size);
Packit 33f14e
      if (ptr == NULL)
Packit 33f14e
        {
Packit 33f14e
          free (buf);
Packit 33f14e
          errno = ENOMEM;
Packit 33f14e
          return NULL;
Packit 33f14e
        }
Packit 33f14e
      buf = ptr;
Packit 33f14e
      result = getcwd (buf, size);
Packit 33f14e
    }
Packit 33f14e
  while (!result && errno == ERANGE);
Packit 33f14e
Packit 33f14e
  if (!result)
Packit 33f14e
    {
Packit 33f14e
      int saved_errno = errno;
Packit 33f14e
      free (buf);
Packit 33f14e
      errno = saved_errno;
Packit 33f14e
    }
Packit 33f14e
  else
Packit 33f14e
    {
Packit 33f14e
      /* Trim to fit, if possible.  */
Packit 33f14e
      result = realloc (buf, strlen (buf) + 1);
Packit 33f14e
      if (!result)
Packit 33f14e
        result = buf;
Packit 33f14e
    }
Packit 33f14e
  return result;
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
#endif