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