1/* xreadlink.c -- readlink wrapper to return the link name in malloc'd storage 2 3 Copyright (C) 2001, 2003, 2005 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#ifdef HAVE_CONFIG_H 24# include <config.h> 25#endif 26 27/* Specification. */ 28#include "xreadlink.h" 29 30#include <stdio.h> 31#include <string.h> 32#include <errno.h> 33#include <limits.h> 34#include <sys/types.h> 35#if HAVE_STDLIB_H 36# include <stdlib.h> 37#endif 38#if HAVE_UNISTD_H 39# include <unistd.h> 40#endif 41 42#ifndef SIZE_MAX 43# define SIZE_MAX ((size_t) -1) 44#endif 45#ifndef SSIZE_MAX 46# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) 47#endif 48 49#ifdef NO_XMALLOC 50# define xmalloc malloc 51#else 52# include "xalloc.h" 53#endif 54 55/* Call readlink to get the symbolic link value of FILENAME. 56 Return a pointer to that NUL-terminated string in malloc'd storage. 57 If readlink fails, return NULL (caller may use errno to diagnose). 58 If realloc fails, or if the link value is longer than SIZE_MAX :-), 59 give a diagnostic and exit. */ 60 61char * 62xreadlink (char const *filename) 63{ 64 /* The initial buffer size for the link value. A power of 2 65 detects arithmetic overflow earlier, but is not required. */ 66#define INITIAL_BUF_SIZE 1024 67 68 /* Allocate the initial buffer on the stack. This way, in the common 69 case of a symlink of small size, we get away with a single small malloc() 70 instead of a big malloc() followed by a shrinking realloc(). */ 71 char initial_buf[INITIAL_BUF_SIZE]; 72 73 char *buffer = initial_buf; 74 size_t buf_size = sizeof (initial_buf); 75 76 while (1) 77 { 78 /* Attempt to read the link into the current buffer. */ 79 ssize_t link_length = readlink (filename, buffer, buf_size); 80 81 if (link_length < 0) 82 { 83 if (buffer != initial_buf) 84 { 85 int saved_errno = errno; 86 free (buffer); 87 errno = saved_errno; 88 } 89 return NULL; 90 } 91 92 if ((size_t) link_length < buf_size) 93 { 94 buffer[link_length++] = '\0'; 95 96 /* Return it in a chunk of memory as small as possible. */ 97 if (buffer == initial_buf) 98 { 99 buffer = (char *) xmalloc (link_length); 100#ifdef NO_XMALLOC 101 if (buffer == NULL) 102 return NULL; 103#endif 104 memcpy (buffer, initial_buf, link_length); 105 } 106 else 107 { 108 /* Shrink buffer before returning it. */ 109 if ((size_t) link_length < buf_size) 110 { 111 char *smaller_buffer = (char *) realloc (buffer, link_length); 112 113 if (smaller_buffer != NULL) 114 buffer = smaller_buffer; 115 } 116 } 117 return buffer; 118 } 119 120 if (buffer != initial_buf) 121 free (buffer); 122 buf_size *= 2; 123 if (SSIZE_MAX < buf_size || (SIZE_MAX / 2 < SSIZE_MAX && buf_size == 0)) 124#ifdef NO_XMALLOC 125 return NULL; 126#else 127 xalloc_die (); 128#endif 129 buffer = (char *) xmalloc (buf_size); 130#ifdef NO_XMALLOC 131 if (buffer == NULL) 132 return NULL; 133#endif 134 } 135} 136