diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2011-04-05 09:52:32 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2011-04-05 09:52:32 -0700 |
commit | 4266051ac3a82f0a3bdfcf73c7f566e007676a0c (patch) | |
tree | 5ec06f00b04a056dd9cc8fc66debcfc845568e0b /lib/areadlinkat.c | |
parent | eccf108c763da99625bbe6bf221a13508798ce1a (diff) | |
download | gnulib-4266051ac3a82f0a3bdfcf73c7f566e007676a0c.tar.gz |
areadlink, areadlinkat: rewrite in terms of careadlinkat
* lib/areadlink.c, lib/areadlinkat.c: Include careadlinkat.h
instead of errno.h, limits.h, stdint.h, stdlib.h, string.h, unistd.h.
(SSIZE_MAX, INITIAL_BUF_SIZE): Remove.
(malloc, realloc): Remove #undefs.
(areadlink, areadlinkat): Rewrite in terms of careadlinkat.
* modules/areadlink (Depends-on): Add careadlinkat. Remove
readlink, ssize_t, stdint, unistd.
* modules/areadlinkat (Depends-on): Add careadlinkat. Remove
areadlink, stdint.
careadlinkat: new module
* lib/allocator.h, lib/careadlinkat.h, lib/careadlinkat.c:
* modules/careadlinkat: New files, written by me with
a review and feedback from Ben Pfaff in
<http://lists.gnu.org/archive/html/bug-gnulib/2011-04/msg00008.html>.
Diffstat (limited to 'lib/areadlinkat.c')
-rw-r--r-- | lib/areadlinkat.c | 86 |
1 files changed, 3 insertions, 83 deletions
diff --git a/lib/areadlinkat.c b/lib/areadlinkat.c index a13c0e506d..2c227f36d9 100644 --- a/lib/areadlinkat.c +++ b/lib/areadlinkat.c @@ -25,101 +25,21 @@ /* Specification. */ #include "areadlink.h" -#include <errno.h> -#include <limits.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#ifndef SSIZE_MAX -# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) -#endif +#include "careadlinkat.h" #if HAVE_READLINKAT -/* The initial buffer size for the link value. A power of 2 - detects arithmetic overflow earlier, but is not required. */ -enum { - INITIAL_BUF_SIZE = 1024 -}; - /* Call readlinkat to get the symbolic link value of FILENAME relative to FD. Return a pointer to that NUL-terminated string in malloc'd storage. If readlinkat fails, return NULL and set errno (although failure to change directory will issue a diagnostic and exit). - If realloc fails, or if the link value is longer than SIZE_MAX :-), + If allocation fails, or if the link value is longer than SIZE_MAX :-), return NULL and set errno to ENOMEM. */ char * areadlinkat (int fd, char const *filename) { - /* Allocate the initial buffer on the stack. This way, in the common - case of a symlink of small size, we get away with a single small malloc() - instead of a big malloc() followed by a shrinking realloc(). */ - char initial_buf[INITIAL_BUF_SIZE]; - - char *buffer = initial_buf; - size_t buf_size = sizeof initial_buf; - - while (1) - { - /* Attempt to read the link into the current buffer. */ - ssize_t link_length = readlinkat (fd, filename, buffer, buf_size); - - /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1 - with errno == ERANGE if the buffer is too small. */ - if (link_length < 0 && errno != ERANGE) - { - if (buffer != initial_buf) - { - int saved_errno = errno; - free (buffer); - errno = saved_errno; - } - return NULL; - } - - if ((size_t) link_length < buf_size) - { - buffer[link_length++] = '\0'; - - /* Return it in a chunk of memory as small as possible. */ - if (buffer == initial_buf) - { - buffer = (char *) malloc (link_length); - if (buffer == NULL) - /* errno is ENOMEM. */ - return NULL; - memcpy (buffer, initial_buf, link_length); - } - else - { - /* Shrink buffer before returning it. */ - if ((size_t) link_length < buf_size) - { - char *smaller_buffer = (char *) realloc (buffer, link_length); - - if (smaller_buffer != NULL) - buffer = smaller_buffer; - } - } - return buffer; - } - - if (buffer != initial_buf) - free (buffer); - buf_size *= 2; - if (SSIZE_MAX < buf_size || (SIZE_MAX / 2 < SSIZE_MAX && buf_size == 0)) - { - errno = ENOMEM; - return NULL; - } - buffer = (char *) malloc (buf_size); - if (buffer == NULL) - /* errno is ENOMEM. */ - return NULL; - } + return careadlinkat (fd, filename, NULL, 0, NULL, readlinkat); } #else /* !HAVE_READLINKAT */ |