File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libiconv / srclib / areadlink.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:57:48 2012 UTC (12 years, 5 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>