1/* xreadlink.c -- readlink wrapper to return the link name in malloc'd storage
2
3   Copyright (C) 2001, 2003, 2005-2006 Free Software Foundation, Inc.
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2, or (at your option)
8   any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; see the file COPYING.
17   If not, write to the Free Software Foundation,
18   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19
20/* Written by Jim Meyering <jim@meyering.net>
21   and Bruno Haible <bruno@clisp.org>.  */
22
23#include <config.h>
24
25/* Specification.  */
26#include "xreadlink.h"
27
28#include <stdio.h>
29#include <string.h>
30#include <errno.h>
31#include <limits.h>
32#include <sys/types.h>
33#include <stdlib.h>
34#if HAVE_UNISTD_H
35# include <unistd.h>
36#endif
37
38#ifndef SIZE_MAX
39# define SIZE_MAX ((size_t) -1)
40#endif
41#ifndef SSIZE_MAX
42# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
43#endif
44
45#ifdef NO_XMALLOC
46# define xmalloc malloc
47#else
48# include "xalloc.h"
49#endif
50
51/* Call readlink to get the symbolic link value of FILENAME.
52   Return a pointer to that NUL-terminated string in malloc'd storage.
53   If readlink fails, return NULL (caller may use errno to diagnose).
54   If realloc fails, or if the link value is longer than SIZE_MAX :-),
55   give a diagnostic and exit.  */
56
57char *
58xreadlink (char const *filename)
59{
60  /* The initial buffer size for the link value.  A power of 2
61     detects arithmetic overflow earlier, but is not required.  */
62#define INITIAL_BUF_SIZE 1024
63
64  /* Allocate the initial buffer on the stack.  This way, in the common
65     case of a symlink of small size, we get away with a single small malloc()
66     instead of a big malloc() followed by a shrinking realloc().  */
67  char initial_buf[INITIAL_BUF_SIZE];
68
69  char *buffer = initial_buf;
70  size_t buf_size = sizeof (initial_buf);
71
72  while (1)
73    {
74      /* Attempt to read the link into the current buffer.  */
75      ssize_t link_length = readlink (filename, buffer, buf_size);
76
77      if (link_length < 0)
78	{
79	  if (buffer != initial_buf)
80	    {
81	      int saved_errno = errno;
82	      free (buffer);
83	      errno = saved_errno;
84	    }
85	  return NULL;
86	}
87
88      if ((size_t) link_length < buf_size)
89	{
90	  buffer[link_length++] = '\0';
91
92	  /* Return it in a chunk of memory as small as possible.  */
93	  if (buffer == initial_buf)
94	    {
95	      buffer = (char *) xmalloc (link_length);
96#ifdef NO_XMALLOC
97	      if (buffer == NULL)
98		return NULL;
99#endif
100	      memcpy (buffer, initial_buf, link_length);
101	    }
102	  else
103	    {
104	      /* Shrink buffer before returning it.  */
105	      if ((size_t) link_length < buf_size)
106		{
107		  char *smaller_buffer = (char *) realloc (buffer, link_length);
108
109		  if (smaller_buffer != NULL)
110		    buffer = smaller_buffer;
111		}
112	    }
113	  return buffer;
114	}
115
116      if (buffer != initial_buf)
117	free (buffer);
118      buf_size *= 2;
119      if (SSIZE_MAX < buf_size || (SIZE_MAX / 2 < SSIZE_MAX && buf_size == 0))
120#ifdef NO_XMALLOC
121	return NULL;
122#else
123	xalloc_die ();
124#endif
125      buffer = (char *) xmalloc (buf_size);
126#ifdef NO_XMALLOC
127      if (buffer == NULL)
128	return NULL;
129#endif
130    }
131}
132