Exemple #1
0
char *
__getcwd (char *buf, size_t size)
{
  char tmpbuf[PATH_MAX];

  if (INLINE_SYSCALL (getcwd, 2, tmpbuf, PATH_MAX) >= 0)
    {
      size_t len = strlen (tmpbuf) + 1;

      if (size == 0)
	{
	  if (__builtin_expect (buf != NULL, 0))
	    {
	      __set_errno (EINVAL);
	      return NULL;
	    }

	  buf = (char *) malloc (len);
	  if (__builtin_expect (buf == NULL, 0))
	    {
	      __set_errno (ENOMEM);
	      return NULL;
	    }
	}
      else
	{
	  if (size < len)
	    {
	      __set_errno (ERANGE);
	      return NULL;
	    }

	  if (buf == NULL)
	    {
	      buf = (char *) malloc (size);
	      if (__builtin_expect (buf == NULL, 0))
		{
		  __set_errno (ENOMEM);
		  return NULL;
		}
	    }
	}

      memcpy (buf, tmpbuf, len);
      return buf;
    }
  return generic_getcwd (buf, size);
}
char *
__getcwd (char *buf, size_t size)
{
  char *path;
  int n;
  char *result;

  if (no_syscall_getcwd && !have_new_dcache)
    return generic_getcwd (buf, size);

#ifndef NO_ALLOCATION
  size_t alloc_size = size;
  if (size == 0)
    {
      if (buf != NULL)
	{
	  __set_errno (EINVAL);
	  return NULL;
	}

      alloc_size = PATH_MAX;
    }

  if (buf == NULL)
    {
      path = malloc (alloc_size);
      if (path == NULL)
	return NULL;
    }
  else
#else
# define alloc_size size
#endif
    path = buf;

#if defined __NR_getcwd || __LINUX_GETCWD_SYSCALL > 0
  if (!no_syscall_getcwd)
    {
      int retval;

      retval = INLINE_SYSCALL (getcwd, 2, CHECK_STRING (path), alloc_size);
      if (retval >= 0)
	{
# ifndef NO_ALLOCATION
	  if (buf == NULL && size == 0)
	    /* Ensure that the buffer is only as large as necessary.  */
	    buf = realloc (path, (size_t) retval);

	  if (buf == NULL)
	    /* Either buf was NULL all along, or `realloc' failed but
	       we still have the original string.  */
	    buf = path;
# endif

	  return buf;
	}

# if __ASSUME_GETCWD_SYSCALL
      /* It should never happen that the `getcwd' syscall failed because
	 the buffer is too small if we allocated the buffer ourselves
	 large enough.  */
      assert (errno != ERANGE || buf != NULL || size != 0);

#  ifndef NO_ALLOCATION
      if (buf == NULL)
	free (path);
#  endif

      return NULL;
# else
      if (errno == ENOSYS)
	{
	   no_syscall_getcwd = 1;
	   have_new_dcache = 1;	/* Now we will try the /proc method.  */
	}
      else if (errno != ERANGE || buf != NULL)
	{
#  ifndef NO_ALLOCATION
	  if (buf == NULL)
	    free (path);
#  endif
	  return NULL;
	}
# endif
    }
#endif

  n = __readlink ("/proc/self/cwd", path, alloc_size - 1);
  if (n != -1)
    {
      if (path[0] == '/')
	{
	  if ((size_t) n >= alloc_size - 1)
	    {
#ifndef NO_ALLOCATION
	      if (buf == NULL)
		free (path);
#endif
	      return NULL;
	    }

	  path[n] = '\0';
#ifndef NO_ALLOCATION
	  if (buf == NULL && size == 0)
	    /* Ensure that the buffer is only as large as necessary.  */
	    buf = realloc (path, (size_t) n + 1);
	  if (buf == NULL)
	    /* Either buf was NULL all along, or `realloc' failed but
	       we still have the original string.  */
	    buf = path;
#endif

	  return buf;
	}
#ifndef have_new_dcache
      else
	have_new_dcache = 0;
#endif
    }

#if __ASSUME_GETCWD_SYSCALL == 0
  /* Set to have_new_dcache only if error indicates that proc doesn't
     exist.  */
  if (errno != EACCES && errno != ENAMETOOLONG)
    have_new_dcache = 0;
#endif

#ifndef NO_ALLOCATION
  /* Don't put restrictions on the length of the path unless the user does.  */
  if (size == 0)
    {
      free (path);
      path = NULL;
    }
#endif

  result = generic_getcwd (path, size);

#ifndef NO_ALLOCATION
  if (result == NULL && buf == NULL && size != 0)
    free (path);
#endif

  return result;
}
Exemple #3
0
char *
__getcwd (char *buf, size_t size)
{
  char *path;
  char *result;

#ifndef NO_ALLOCATION
  size_t alloc_size = size;
  if (size == 0)
    {
      if (buf != NULL)
	{
	  __set_errno (EINVAL);
	  return NULL;
	}

      alloc_size = MAX (PATH_MAX, __getpagesize ());
    }

  if (buf == NULL)
    {
      path = malloc (alloc_size);
      if (path == NULL)
	return NULL;
    }
  else
#else
# define alloc_size size
#endif
    path = buf;

  int retval;

  retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size);
  if (retval >= 0)
    {
#ifndef NO_ALLOCATION
      if (buf == NULL && size == 0)
	/* Ensure that the buffer is only as large as necessary.  */
	buf = realloc (path, (size_t) retval);

      if (buf == NULL)
	/* Either buf was NULL all along, or `realloc' failed but
	   we still have the original string.  */
	buf = path;
#endif

      return buf;
    }

  /* The system call cannot handle paths longer than a page.
     Neither can the magic symlink in /proc/self.  Just use the
     generic implementation right away.  */
  if (errno == ENAMETOOLONG)
    {
#ifndef NO_ALLOCATION
      if (buf == NULL && size == 0)
	{
	  free (path);
	  path = NULL;
	}
#endif

      result = generic_getcwd (path, size);

#ifndef NO_ALLOCATION
      if (result == NULL && buf == NULL && size != 0)
	free (path);
#endif

      return result;
    }

  /* It should never happen that the `getcwd' syscall failed because
     the buffer is too small if we allocated the buffer ourselves
     large enough.  */
  assert (errno != ERANGE || buf != NULL || size != 0);

#ifndef NO_ALLOCATION
  if (buf == NULL)
    free (path);
#endif

  return NULL;
}