Blame gnulib-tests/getcwd-lgpl.c

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