1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-21 10:24:55 +00:00

Replace two copies of readlink code with single gnulib version.

This commit is contained in:
Paul Eggert 2011-03-31 23:28:48 -07:00
parent 63139bfa89
commit d1fdcab742
13 changed files with 390 additions and 59 deletions

View File

@ -1,3 +1,10 @@
2011-04-01 Paul Eggert <eggert@cs.ucla.edu>
Replace two copies of readlink code with single gnulib version.
* Makefile.in (GNULIB_MODULES): Add careadlinkat.
* lib/allocator.h, lib/careadlinkat.c, lib/careadlinkat.h:
* m4/ssize_t.m4: New files, automatically generated from gnulib.
2011-03-28 Glenn Morris <rgm@gnu.org>
* autogen/update_autogen: Pass -f to autoreconf.

View File

@ -331,7 +331,7 @@ DOS_gnulib_comp.m4 = gl-comp.m4
# $(gnulib_srcdir) (relative to $(srcdir) and should have build tools
# as per $(gnulib_srcdir)/DEPENDENCIES.
GNULIB_MODULES = \
crypto/md5 dtoastr filemode getloadavg getopt-gnu \
careadlinkat crypto/md5 dtoastr filemode getloadavg getopt-gnu \
ignore-value intprops lstat mktime readlink \
socklen stdio strftime symlink sys_stat
GNULIB_TOOL_FLAGS = \

45
lib/allocator.h Normal file
View File

@ -0,0 +1,45 @@
/* Memory allocators such as malloc+free.
Copyright (C) 2011 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Paul Eggert. */
#ifndef _GL_ALLOCATOR_H
#include <stddef.h>
struct allocator
{
/* Call MALLOC to allocate memory, like 'malloc'. On failure MALLOC
should return NULL, though not necessarily set errno. When given
a zero size it may return NULL even if successful. */
void *(*malloc) (size_t);
/* If nonnull, call REALLOC to reallocate memory, like 'realloc'.
On failure REALLOC should return NULL, though not necessarily set
errno. When given a zero size it may return NULL even if
successful. */
void *(*realloc) (void *, size_t);
/* Call FREE to free memory, like 'free'. */
void (*free) (void *);
/* If nonnull, call DIE if MALLOC or REALLOC fails. DIE should
not return. */
void (*die) (void);
};
#endif

179
lib/careadlinkat.c Normal file
View File

@ -0,0 +1,179 @@
/* Read symbolic links into a buffer without size limitation, relative to fd.
Copyright (C) 2001, 2003-2004, 2007, 2009-2011 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
#include <config.h>
#include "careadlinkat.h"
#include "allocator.h"
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* Use the system functions, not the gnulib overrides, because this
module does not depend on GNU or POSIX semantics. */
#undef malloc
#undef realloc
/* Define this independently so that stdint.h is not a prerequisite. */
#ifndef SIZE_MAX
# define SIZE_MAX ((size_t) -1)
#endif
#ifndef SSIZE_MAX
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
#endif
#if ! HAVE_READLINKAT
/* Ignore FD. Get the symbolic link value of FILENAME and put it into
BUFFER, with size BUFFER_SIZE. This function acts like readlink
but has readlinkat's signature. */
ssize_t
careadlinkatcwd (int fd, char const *filename, char *buffer,
size_t buffer_size)
{
(void) fd;
return readlink (filename, buffer, buffer_size);
}
#endif
/* Assuming the current directory is FD, get the symbolic link value
of FILENAME as a null-terminated string and put it into a buffer.
If FD is AT_FDCWD, FILENAME is interpreted relative to the current
working directory, as in openat.
If the link is small enough to fit into BUFFER put it there.
BUFFER's size is BUFFER_SIZE, and BUFFER can be null
if BUFFER_SIZE is zero.
If the link is not small, put it into a dynamically allocated
buffer managed by ALLOC. It is the caller's responsibility to free
the returned value if it is nonnull and is not BUFFER. A null
ALLOC stands for the standard allocator.
The PREADLINKAT function specifies how to read links.
If successful, return the buffer address; otherwise return NULL and
set errno. */
char *
careadlinkat (int fd, char const *filename,
char *buffer, size_t buffer_size,
struct allocator const *alloc,
ssize_t (*preadlinkat) (int, char const *, char *, size_t))
{
char *buf;
size_t buf_size;
size_t buf_size_max =
SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
char stack_buf[1024];
void *(*pmalloc) (size_t) = malloc;
void *(*prealloc) (void *, size_t) = realloc;
void (*pfree) (void *) = free;
void (*pdie) (void) = NULL;
if (alloc)
{
pmalloc = alloc->malloc;
prealloc = alloc->realloc;
pfree = alloc->free;
pdie = alloc->die;
}
if (! buffer_size)
{
/* 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(). */
buffer = stack_buf;
buffer_size = sizeof stack_buf;
}
buf = buffer;
buf_size = buffer_size;
do
{
/* Attempt to read the link into the current buffer. */
ssize_t link_length = preadlinkat (fd, filename, buf, buf_size);
size_t link_size;
if (link_length < 0)
{
/* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
with errno == ERANGE if the buffer is too small. */
int readlinkat_errno = errno;
if (readlinkat_errno != ERANGE)
{
if (buf != buffer)
{
pfree (buf);
errno = readlinkat_errno;
}
return NULL;
}
}
link_size = link_length;
if (link_size < buf_size)
{
buf[link_size++] = '\0';
if (buf == stack_buf)
{
char *b = (char *) pmalloc (link_size);
if (! b)
break;
memcpy (b, buf, link_size);
buf = b;
}
else if (link_size < buf_size && buf != buffer && prealloc)
{
/* Shrink BUF before returning it. */
char *b = (char *) prealloc (buf, link_size);
if (b)
buf = b;
}
return buf;
}
if (buf != buffer)
pfree (buf);
if (buf_size <= buf_size_max / 2)
buf_size *= 2;
else if (buf_size < buf_size_max)
buf_size = buf_size_max;
else
break;
buf = (char *) pmalloc (buf_size);
}
while (buf);
if (pdie)
pdie ();
errno = ENOMEM;
return NULL;
}

67
lib/careadlinkat.h Normal file
View File

@ -0,0 +1,67 @@
/* Read symbolic links into a buffer without size limitation, relative to fd.
Copyright (C) 2011 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
#ifndef _GL_CAREADLINKAT_H
#include <fcntl.h>
#include <unistd.h>
struct allocator;
/* Assuming the current directory is FD, get the symbolic link value
of FILENAME as a null-terminated string and put it into a buffer.
If FD is AT_FDCWD, FILENAME is interpreted relative to the current
working directory, as in openat.
If the link is small enough to fit into BUFFER put it there.
BUFFER's size is BUFFER_SIZE, and BUFFER can be null
if BUFFER_SIZE is zero.
If the link is not small, put it into a dynamically allocated
buffer managed by ALLOC. It is the caller's responsibility to free
the returned value if it is nonnull and is not BUFFER.
The PREADLINKAT function specifies how to read links.
If successful, return the buffer address; otherwise return NULL and
set errno. */
char *careadlinkat (int fd, char const *filename,
char *buffer, size_t buffer_size,
struct allocator const *alloc,
ssize_t (*preadlinkat) (int, char const *,
char *, size_t));
/* Suitable values for careadlinkat's FD and PREADLINKAT arguments,
when doing a plain readlink. */
#if HAVE_READLINKAT
# define careadlinkatcwd readlinkat
#else
/* Define AT_FDCWD independently, so that the careadlinkat module does
not depend on the fcntl-h module. The value does not matter, since
careadlinkatcwd ignores it, but we might as well use the same value
as fcntl-h. */
# ifndef AT_FDCWD
# define AT_FDCWD (-3041965)
# endif
ssize_t careadlinkatcwd (int fd, char const *filename,
char *buffer, size_t buffer_size);
#endif
#endif /* _GL_CAREADLINKAT_H */

View File

@ -9,7 +9,7 @@
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --makefile-name=gnulib.mk --no-libtool --macro-prefix=gl --no-vc-files crypto/md5 dtoastr filemode getloadavg getopt-gnu ignore-value intprops lstat mktime readlink socklen stdio strftime symlink sys_stat
# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=. --makefile-name=gnulib.mk --no-libtool --macro-prefix=gl --no-vc-files careadlinkat crypto/md5 dtoastr filemode getloadavg getopt-gnu ignore-value intprops lstat mktime readlink socklen stdio strftime symlink sys_stat
MOSTLYCLEANFILES += core *.stackdump
@ -69,6 +69,14 @@ EXTRA_DIST += $(top_srcdir)/./c++defs.h
## end gnulib module c++defs
## begin gnulib module careadlinkat
libgnu_a_SOURCES += careadlinkat.c
EXTRA_DIST += allocator.h careadlinkat.h
## end gnulib module careadlinkat
## begin gnulib module crypto/md5

View File

@ -28,6 +28,7 @@ AC_DEFUN([gl_EARLY],
AC_REQUIRE([AC_PROG_RANLIB])
# Code from module arg-nonnull:
# Code from module c++defs:
# Code from module careadlinkat:
# Code from module crypto/md5:
# Code from module dosname:
# Code from module dtoastr:
@ -46,6 +47,7 @@ AC_DEFUN([gl_EARLY],
# Code from module multiarch:
# Code from module readlink:
# Code from module socklen:
# Code from module ssize_t:
# Code from module stat:
# Code from module stdbool:
# Code from module stddef:
@ -79,6 +81,8 @@ AC_DEFUN([gl_INIT],
gl_source_base='lib'
# Code from module arg-nonnull:
# Code from module c++defs:
# Code from module careadlinkat:
AC_CHECK_FUNCS_ONCE([readlinkat])
# Code from module crypto/md5:
gl_MD5
# Code from module dosname:
@ -115,6 +119,8 @@ AC_DEFUN([gl_INIT],
gl_UNISTD_MODULE_INDICATOR([readlink])
# Code from module socklen:
gl_TYPE_SOCKLEN_T
# Code from module ssize_t:
gt_TYPE_SSIZE_T
# Code from module stat:
gl_FUNC_STAT
gl_SYS_STAT_MODULE_INDICATOR([stat])
@ -287,6 +293,9 @@ AC_DEFUN([gl_FILE_LIST], [
build-aux/arg-nonnull.h
build-aux/c++defs.h
build-aux/warn-on-use.h
lib/allocator.h
lib/careadlinkat.c
lib/careadlinkat.h
lib/dosname.h
lib/dtoastr.c
lib/filemode.c
@ -335,6 +344,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/multiarch.m4
m4/readlink.m4
m4/socklen.m4
m4/ssize_t.m4
m4/st_dm_mode.m4
m4/stat.m4
m4/stdbool.m4

23
m4/ssize_t.m4 Normal file
View File

@ -0,0 +1,23 @@
# ssize_t.m4 serial 5 (gettext-0.18.2)
dnl Copyright (C) 2001-2003, 2006, 2010-2011 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl From Bruno Haible.
dnl Test whether ssize_t is defined.
AC_DEFUN([gt_TYPE_SSIZE_T],
[
AC_CACHE_CHECK([for ssize_t], [gt_cv_ssize_t],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <sys/types.h>]],
[[int x = sizeof (ssize_t *) + sizeof (ssize_t);
return !x;]])],
[gt_cv_ssize_t=yes], [gt_cv_ssize_t=no])])
if test $gt_cv_ssize_t = no; then
AC_DEFINE([ssize_t], [int],
[Define as a signed type of the same size as size_t.])
fi
])

View File

@ -1,3 +1,15 @@
2011-04-01 Paul Eggert <eggert@cs.ucla.edu>
Replace two copies of readlink code with single gnulib version.
The gnulib version avoids calling malloc in the usual case,
and on 64-bit hosts doesn't have some arbitrary 32-bit limits.
* fileio.c (Ffile_symlink_p): Use emacs_readlink.
* filelock.c (current_lock_owner): Likewise.
* lisp.h (READLINK_BUFSIZE, emacs_readlink): New function.
* sysdep.c: Include allocator.h, careadlinkat.h.
(emacs_no_realloc_allocator): New static constant.
(emacs_readlink): New function.
2011-03-31 Juanma Barranquero <lekktu@gmail.com>
* xdisp.c (redisplay_internal): Fix prototype.

View File

@ -2579,9 +2579,8 @@ points to a nonexistent file. */)
{
Lisp_Object handler;
char *buf;
int bufsize;
int valsize;
Lisp_Object val;
char readlink_buf[READLINK_BUFSIZE];
CHECK_STRING (filename);
filename = Fexpand_file_name (filename, Qnil);
@ -2594,36 +2593,15 @@ points to a nonexistent file. */)
filename = ENCODE_FILE (filename);
bufsize = 50;
buf = NULL;
do
{
bufsize *= 2;
buf = (char *) xrealloc (buf, bufsize);
memset (buf, 0, bufsize);
buf = emacs_readlink (SSDATA (filename), readlink_buf);
if (! buf)
return Qnil;
errno = 0;
valsize = readlink (SSDATA (filename), buf, bufsize);
if (valsize == -1)
{
#ifdef ERANGE
/* HP-UX reports ERANGE if buffer is too small. */
if (errno == ERANGE)
valsize = bufsize;
else
#endif
{
xfree (buf);
return Qnil;
}
}
}
while (valsize >= bufsize);
val = make_string (buf, valsize);
val = build_string (buf);
if (buf[0] == '/' && strchr (buf, ':'))
val = concat2 (build_string ("/:"), val);
xfree (buf);
if (buf != readlink_buf)
xfree (buf);
val = DECODE_FILE (val);
return val;
}

View File

@ -396,36 +396,16 @@ within_one_second (time_t a, time_t b)
static int
current_lock_owner (lock_info_type *owner, char *lfname)
{
int len, ret;
int ret;
size_t len;
int local_owner = 0;
char *at, *dot, *colon;
char *lfinfo = 0;
int bufsize = 50;
/* Read arbitrarily-long contents of symlink. Similar code in
file-symlink-p in fileio.c. */
do
{
bufsize *= 2;
lfinfo = (char *) xrealloc (lfinfo, bufsize);
errno = 0;
len = readlink (lfname, lfinfo, bufsize);
#ifdef ERANGE
/* HP-UX reports ERANGE if the buffer is too small. */
if (len == -1 && errno == ERANGE)
len = bufsize;
#endif
}
while (len >= bufsize);
char readlink_buf[READLINK_BUFSIZE];
char *lfinfo = emacs_readlink (lfname, readlink_buf);
/* If nonexistent lock file, all is well; otherwise, got strange error. */
if (len == -1)
{
xfree (lfinfo);
return errno == ENOENT ? 0 : -1;
}
/* Link info exists, so `len' is its length. Null terminate. */
lfinfo[len] = 0;
if (!lfinfo)
return errno == ENOENT ? 0 : -1;
/* Even if the caller doesn't want the owner info, we still have to
read it to determine return value, so allocate it. */
@ -441,7 +421,8 @@ current_lock_owner (lock_info_type *owner, char *lfname)
dot = strrchr (lfinfo, '.');
if (!at || !dot)
{
xfree (lfinfo);
if (lfinfo != readlink_buf)
xfree (lfinfo);
return -1;
}
len = at - lfinfo;
@ -467,7 +448,8 @@ current_lock_owner (lock_info_type *owner, char *lfname)
owner->host[len] = 0;
/* We're done looking at the link info. */
xfree (lfinfo);
if (lfinfo != readlink_buf)
xfree (lfinfo);
/* On current host? */
if (STRINGP (Fsystem_name ())

View File

@ -3340,6 +3340,8 @@ extern int emacs_open (const char *, int, int);
extern int emacs_close (int);
extern int emacs_read (int, char *, unsigned int);
extern int emacs_write (int, const char *, unsigned int);
enum { READLINK_BUFSIZE = 1024 };
extern char *emacs_readlink (const char *, char [READLINK_BUFSIZE]);
#ifndef HAVE_MEMSET
extern void *memset (void *, int, size_t);
#endif

View File

@ -31,6 +31,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#endif /* HAVE_LIMITS_H */
#include <unistd.h>
#include <allocator.h>
#include <careadlinkat.h>
#include <ignore-value.h>
#include "lisp.h"
@ -1866,6 +1868,22 @@ emacs_write (int fildes, const char *buf, unsigned int nbyte)
}
return (bytes_written);
}
static struct allocator const emacs_norealloc_allocator =
{ xmalloc, NULL, xfree, memory_full };
/* Get the symbolic link value of FILENAME. Return a pointer to a
NUL-terminated string. If readlink fails, return NULL and set
errno. If the value fits in INITIAL_BUF, return INITIAL_BUF.
Otherwise, allocate memory and return a pointer to that memory. If
memory allocation fails, diagnose and fail without returning. If
successful, store the length of the symbolic link into *LINKLEN. */
char *
emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE])
{
return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE,
&emacs_norealloc_allocator, careadlinkatcwd);
}
#ifdef USG
/*