Blame sysdeps/unix/sysv/linux/getcwd.c

Packit 6c4009
/* Determine current working directory.  Linux version.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <sys/syscall.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* If we compile the file for use in ld.so we don't need the feature
Packit 6c4009
   that getcwd() allocates the buffers itself.  */
Packit 6c4009
#if IS_IN (rtld)
Packit 6c4009
# define NO_ALLOCATION	1
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The "proc" filesystem provides an easy method to retrieve the value.
Packit 6c4009
   For each process, the corresponding directory contains a symbolic link
Packit 6c4009
   named `cwd'.  Reading the content of this link immediate gives us the
Packit 6c4009
   information.  But we have to take care for systems which do not have
Packit 6c4009
   the proc filesystem mounted.  Use the POSIX implementation in this case.  */
Packit 6c4009
static char *generic_getcwd (char *buf, size_t size);
Packit 6c4009
Packit 6c4009
char *
Packit 6c4009
__getcwd (char *buf, size_t size)
Packit 6c4009
{
Packit 6c4009
  char *path;
Packit 6c4009
  char *result;
Packit 6c4009
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
  size_t alloc_size = size;
Packit 6c4009
  if (size == 0)
Packit 6c4009
    {
Packit 6c4009
      if (buf != NULL)
Packit 6c4009
	{
Packit 6c4009
	  __set_errno (EINVAL);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      alloc_size = MAX (PATH_MAX, __getpagesize ());
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (buf == NULL)
Packit 6c4009
    {
Packit 6c4009
      path = malloc (alloc_size);
Packit 6c4009
      if (path == NULL)
Packit 6c4009
	return NULL;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
#else
Packit 6c4009
# define alloc_size size
Packit 6c4009
#endif
Packit 6c4009
    path = buf;
Packit 6c4009
Packit 6c4009
  int retval;
Packit 6c4009
Packit 6c4009
  retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size);
Packit 6c4009
  if (retval > 0 && path[0] == '/')
Packit 6c4009
    {
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
      if (buf == NULL && size == 0)
Packit 6c4009
	/* Ensure that the buffer is only as large as necessary.  */
Packit 6c4009
	buf = realloc (path, (size_t) retval);
Packit 6c4009
Packit 6c4009
      if (buf == NULL)
Packit 6c4009
	/* Either buf was NULL all along, or `realloc' failed but
Packit 6c4009
	   we still have the original string.  */
Packit 6c4009
	buf = path;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      return buf;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* The system call either cannot handle paths longer than a page
Packit 6c4009
     or can succeed without returning an absolute path.  Just use the
Packit 6c4009
     generic implementation right away.  */
Packit 6c4009
  if (retval >= 0 || errno == ENAMETOOLONG)
Packit 6c4009
    {
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
      if (buf == NULL && size == 0)
Packit 6c4009
	{
Packit 6c4009
	  free (path);
Packit 6c4009
	  path = NULL;
Packit 6c4009
	}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      result = generic_getcwd (path, size);
Packit 6c4009
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
      if (result == NULL && buf == NULL && size != 0)
Packit 6c4009
	free (path);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      return result;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* It should never happen that the `getcwd' syscall failed because
Packit 6c4009
     the buffer is too small if we allocated the buffer ourselves
Packit 6c4009
     large enough.  */
Packit 6c4009
  assert (errno != ERANGE || buf != NULL || size != 0);
Packit 6c4009
Packit 6c4009
#ifndef NO_ALLOCATION
Packit 6c4009
  if (buf == NULL)
Packit 6c4009
    free (path);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
weak_alias (__getcwd, getcwd)
Packit 6c4009
Packit 6c4009
/* Get the code for the generic version.  */
Packit 6c4009
#define GETCWD_RETURN_TYPE	static char *
Packit 6c4009
#define __getcwd		generic_getcwd
Packit 6c4009
#include <sysdeps/posix/getcwd.c>