aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2011-03-31 23:28:48 -0700
committerPaul Eggert2011-03-31 23:28:48 -0700
commitd1fdcab7425f36a34ddeaf304e2c6e3c471ba8db (patch)
treef59643a560ce58433a9a92dfe615dd18aecc0457
parent63139bfa89692ec666815f57d0658996577a80d3 (diff)
downloademacs-d1fdcab7425f36a34ddeaf304e2c6e3c471ba8db.tar.gz
emacs-d1fdcab7425f36a34ddeaf304e2c6e3c471ba8db.zip
Replace two copies of readlink code with single gnulib version.
-rw-r--r--ChangeLog7
-rw-r--r--Makefile.in2
-rw-r--r--lib/allocator.h45
-rw-r--r--lib/careadlinkat.c179
-rw-r--r--lib/careadlinkat.h67
-rw-r--r--lib/gnulib.mk10
-rw-r--r--m4/gl-comp.m410
-rw-r--r--m4/ssize_t.m423
-rw-r--r--src/ChangeLog12
-rw-r--r--src/fileio.c36
-rw-r--r--src/filelock.c38
-rw-r--r--src/lisp.h2
-rw-r--r--src/sysdep.c18
13 files changed, 390 insertions, 59 deletions
diff --git a/ChangeLog b/ChangeLog
index bf7a6af63b6..979b3efd89e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
12011-04-01 Paul Eggert <eggert@cs.ucla.edu>
2
3 Replace two copies of readlink code with single gnulib version.
4 * Makefile.in (GNULIB_MODULES): Add careadlinkat.
5 * lib/allocator.h, lib/careadlinkat.c, lib/careadlinkat.h:
6 * m4/ssize_t.m4: New files, automatically generated from gnulib.
7
12011-03-28 Glenn Morris <rgm@gnu.org> 82011-03-28 Glenn Morris <rgm@gnu.org>
2 9
3 * autogen/update_autogen: Pass -f to autoreconf. 10 * autogen/update_autogen: Pass -f to autoreconf.
diff --git a/Makefile.in b/Makefile.in
index 699589c6920..1ac77ed66ac 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -331,7 +331,7 @@ DOS_gnulib_comp.m4 = gl-comp.m4
331# $(gnulib_srcdir) (relative to $(srcdir) and should have build tools 331# $(gnulib_srcdir) (relative to $(srcdir) and should have build tools
332# as per $(gnulib_srcdir)/DEPENDENCIES. 332# as per $(gnulib_srcdir)/DEPENDENCIES.
333GNULIB_MODULES = \ 333GNULIB_MODULES = \
334 crypto/md5 dtoastr filemode getloadavg getopt-gnu \ 334 careadlinkat crypto/md5 dtoastr filemode getloadavg getopt-gnu \
335 ignore-value intprops lstat mktime readlink \ 335 ignore-value intprops lstat mktime readlink \
336 socklen stdio strftime symlink sys_stat 336 socklen stdio strftime symlink sys_stat
337GNULIB_TOOL_FLAGS = \ 337GNULIB_TOOL_FLAGS = \
diff --git a/lib/allocator.h b/lib/allocator.h
new file mode 100644
index 00000000000..54cc5ff66f0
--- /dev/null
+++ b/lib/allocator.h
@@ -0,0 +1,45 @@
1/* Memory allocators such as malloc+free.
2
3 Copyright (C) 2011 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 3 of the License, or
8 (at your option) 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. If not, see <http://www.gnu.org/licenses/>. */
17
18/* Written by Paul Eggert. */
19
20#ifndef _GL_ALLOCATOR_H
21
22#include <stddef.h>
23
24struct allocator
25{
26 /* Call MALLOC to allocate memory, like 'malloc'. On failure MALLOC
27 should return NULL, though not necessarily set errno. When given
28 a zero size it may return NULL even if successful. */
29 void *(*malloc) (size_t);
30
31 /* If nonnull, call REALLOC to reallocate memory, like 'realloc'.
32 On failure REALLOC should return NULL, though not necessarily set
33 errno. When given a zero size it may return NULL even if
34 successful. */
35 void *(*realloc) (void *, size_t);
36
37 /* Call FREE to free memory, like 'free'. */
38 void (*free) (void *);
39
40 /* If nonnull, call DIE if MALLOC or REALLOC fails. DIE should
41 not return. */
42 void (*die) (void);
43};
44
45#endif
diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c
new file mode 100644
index 00000000000..828c0508db7
--- /dev/null
+++ b/lib/careadlinkat.c
@@ -0,0 +1,179 @@
1/* Read symbolic links into a buffer without size limitation, relative to fd.
2
3 Copyright (C) 2001, 2003-2004, 2007, 2009-2011 Free Software Foundation,
4 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 Paul Eggert, Bruno Haible, and Jim Meyering. */
20
21#include <config.h>
22
23#include "careadlinkat.h"
24
25#include "allocator.h"
26
27#include <errno.h>
28#include <limits.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32
33/* Use the system functions, not the gnulib overrides, because this
34 module does not depend on GNU or POSIX semantics. */
35#undef malloc
36#undef realloc
37
38/* Define this independently so that stdint.h is not a prerequisite. */
39#ifndef SIZE_MAX
40# define SIZE_MAX ((size_t) -1)
41#endif
42
43#ifndef SSIZE_MAX
44# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
45#endif
46
47#if ! HAVE_READLINKAT
48/* Ignore FD. Get the symbolic link value of FILENAME and put it into
49 BUFFER, with size BUFFER_SIZE. This function acts like readlink
50 but has readlinkat's signature. */
51ssize_t
52careadlinkatcwd (int fd, char const *filename, char *buffer,
53 size_t buffer_size)
54{
55 (void) fd;
56 return readlink (filename, buffer, buffer_size);
57}
58#endif
59
60/* Assuming the current directory is FD, get the symbolic link value
61 of FILENAME as a null-terminated string and put it into a buffer.
62 If FD is AT_FDCWD, FILENAME is interpreted relative to the current
63 working directory, as in openat.
64
65 If the link is small enough to fit into BUFFER put it there.
66 BUFFER's size is BUFFER_SIZE, and BUFFER can be null
67 if BUFFER_SIZE is zero.
68
69 If the link is not small, put it into a dynamically allocated
70 buffer managed by ALLOC. It is the caller's responsibility to free
71 the returned value if it is nonnull and is not BUFFER. A null
72 ALLOC stands for the standard allocator.
73
74 The PREADLINKAT function specifies how to read links.
75
76 If successful, return the buffer address; otherwise return NULL and
77 set errno. */
78
79char *
80careadlinkat (int fd, char const *filename,
81 char *buffer, size_t buffer_size,
82 struct allocator const *alloc,
83 ssize_t (*preadlinkat) (int, char const *, char *, size_t))
84{
85 char *buf;
86 size_t buf_size;
87 size_t buf_size_max =
88 SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
89 char stack_buf[1024];
90
91 void *(*pmalloc) (size_t) = malloc;
92 void *(*prealloc) (void *, size_t) = realloc;
93 void (*pfree) (void *) = free;
94 void (*pdie) (void) = NULL;
95 if (alloc)
96 {
97 pmalloc = alloc->malloc;
98 prealloc = alloc->realloc;
99 pfree = alloc->free;
100 pdie = alloc->die;
101 }
102
103 if (! buffer_size)
104 {
105 /* Allocate the initial buffer on the stack. This way, in the
106 common case of a symlink of small size, we get away with a
107 single small malloc() instead of a big malloc() followed by a
108 shrinking realloc(). */
109 buffer = stack_buf;
110 buffer_size = sizeof stack_buf;
111 }
112
113 buf = buffer;
114 buf_size = buffer_size;
115
116 do
117 {
118 /* Attempt to read the link into the current buffer. */
119 ssize_t link_length = preadlinkat (fd, filename, buf, buf_size);
120 size_t link_size;
121 if (link_length < 0)
122 {
123 /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
124 with errno == ERANGE if the buffer is too small. */
125 int readlinkat_errno = errno;
126 if (readlinkat_errno != ERANGE)
127 {
128 if (buf != buffer)
129 {
130 pfree (buf);
131 errno = readlinkat_errno;
132 }
133 return NULL;
134 }
135 }
136
137 link_size = link_length;
138
139 if (link_size < buf_size)
140 {
141 buf[link_size++] = '\0';
142
143 if (buf == stack_buf)
144 {
145 char *b = (char *) pmalloc (link_size);
146 if (! b)
147 break;
148 memcpy (b, buf, link_size);
149 buf = b;
150 }
151 else if (link_size < buf_size && buf != buffer && prealloc)
152 {
153 /* Shrink BUF before returning it. */
154 char *b = (char *) prealloc (buf, link_size);
155 if (b)
156 buf = b;
157 }
158
159 return buf;
160 }
161
162 if (buf != buffer)
163 pfree (buf);
164
165 if (buf_size <= buf_size_max / 2)
166 buf_size *= 2;
167 else if (buf_size < buf_size_max)
168 buf_size = buf_size_max;
169 else
170 break;
171 buf = (char *) pmalloc (buf_size);
172 }
173 while (buf);
174
175 if (pdie)
176 pdie ();
177 errno = ENOMEM;
178 return NULL;
179}
diff --git a/lib/careadlinkat.h b/lib/careadlinkat.h
new file mode 100644
index 00000000000..c5e4bcfc15f
--- /dev/null
+++ b/lib/careadlinkat.h
@@ -0,0 +1,67 @@
1/* Read symbolic links into a buffer without size limitation, relative to fd.
2
3 Copyright (C) 2011 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 3 of the License, or
8 (at your option) 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. If not, see <http://www.gnu.org/licenses/>. */
17
18/* Written by Paul Eggert, Bruno Haible, and Jim Meyering. */
19
20#ifndef _GL_CAREADLINKAT_H
21
22#include <fcntl.h>
23#include <unistd.h>
24
25struct allocator;
26
27/* Assuming the current directory is FD, get the symbolic link value
28 of FILENAME as a null-terminated string and put it into a buffer.
29 If FD is AT_FDCWD, FILENAME is interpreted relative to the current
30 working directory, as in openat.
31
32 If the link is small enough to fit into BUFFER put it there.
33 BUFFER's size is BUFFER_SIZE, and BUFFER can be null
34 if BUFFER_SIZE is zero.
35
36 If the link is not small, put it into a dynamically allocated
37 buffer managed by ALLOC. It is the caller's responsibility to free
38 the returned value if it is nonnull and is not BUFFER.
39
40 The PREADLINKAT function specifies how to read links.
41
42 If successful, return the buffer address; otherwise return NULL and
43 set errno. */
44
45char *careadlinkat (int fd, char const *filename,
46 char *buffer, size_t buffer_size,
47 struct allocator const *alloc,
48 ssize_t (*preadlinkat) (int, char const *,
49 char *, size_t));
50
51/* Suitable values for careadlinkat's FD and PREADLINKAT arguments,
52 when doing a plain readlink. */
53#if HAVE_READLINKAT
54# define careadlinkatcwd readlinkat
55#else
56/* Define AT_FDCWD independently, so that the careadlinkat module does
57 not depend on the fcntl-h module. The value does not matter, since
58 careadlinkatcwd ignores it, but we might as well use the same value
59 as fcntl-h. */
60# ifndef AT_FDCWD
61# define AT_FDCWD (-3041965)
62# endif
63ssize_t careadlinkatcwd (int fd, char const *filename,
64 char *buffer, size_t buffer_size);
65#endif
66
67#endif /* _GL_CAREADLINKAT_H */
diff --git a/lib/gnulib.mk b/lib/gnulib.mk
index 030f95b7a68..bb5bdcf852e 100644
--- a/lib/gnulib.mk
+++ b/lib/gnulib.mk
@@ -9,7 +9,7 @@
9# the same distribution terms as the rest of that program. 9# the same distribution terms as the rest of that program.
10# 10#
11# Generated by gnulib-tool. 11# Generated by gnulib-tool.
12# 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 12# 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
13 13
14 14
15MOSTLYCLEANFILES += core *.stackdump 15MOSTLYCLEANFILES += core *.stackdump
@@ -69,6 +69,14 @@ EXTRA_DIST += $(top_srcdir)/./c++defs.h
69 69
70## end gnulib module c++defs 70## end gnulib module c++defs
71 71
72## begin gnulib module careadlinkat
73
74libgnu_a_SOURCES += careadlinkat.c
75
76EXTRA_DIST += allocator.h careadlinkat.h
77
78## end gnulib module careadlinkat
79
72## begin gnulib module crypto/md5 80## begin gnulib module crypto/md5
73 81
74 82
diff --git a/m4/gl-comp.m4 b/m4/gl-comp.m4
index af3cae75abb..43cce9b3676 100644
--- a/m4/gl-comp.m4
+++ b/m4/gl-comp.m4
@@ -28,6 +28,7 @@ AC_DEFUN([gl_EARLY],
28 AC_REQUIRE([AC_PROG_RANLIB]) 28 AC_REQUIRE([AC_PROG_RANLIB])
29 # Code from module arg-nonnull: 29 # Code from module arg-nonnull:
30 # Code from module c++defs: 30 # Code from module c++defs:
31 # Code from module careadlinkat:
31 # Code from module crypto/md5: 32 # Code from module crypto/md5:
32 # Code from module dosname: 33 # Code from module dosname:
33 # Code from module dtoastr: 34 # Code from module dtoastr:
@@ -46,6 +47,7 @@ AC_DEFUN([gl_EARLY],
46 # Code from module multiarch: 47 # Code from module multiarch:
47 # Code from module readlink: 48 # Code from module readlink:
48 # Code from module socklen: 49 # Code from module socklen:
50 # Code from module ssize_t:
49 # Code from module stat: 51 # Code from module stat:
50 # Code from module stdbool: 52 # Code from module stdbool:
51 # Code from module stddef: 53 # Code from module stddef:
@@ -79,6 +81,8 @@ AC_DEFUN([gl_INIT],
79 gl_source_base='lib' 81 gl_source_base='lib'
80 # Code from module arg-nonnull: 82 # Code from module arg-nonnull:
81 # Code from module c++defs: 83 # Code from module c++defs:
84 # Code from module careadlinkat:
85 AC_CHECK_FUNCS_ONCE([readlinkat])
82 # Code from module crypto/md5: 86 # Code from module crypto/md5:
83 gl_MD5 87 gl_MD5
84 # Code from module dosname: 88 # Code from module dosname:
@@ -115,6 +119,8 @@ AC_DEFUN([gl_INIT],
115 gl_UNISTD_MODULE_INDICATOR([readlink]) 119 gl_UNISTD_MODULE_INDICATOR([readlink])
116 # Code from module socklen: 120 # Code from module socklen:
117 gl_TYPE_SOCKLEN_T 121 gl_TYPE_SOCKLEN_T
122 # Code from module ssize_t:
123 gt_TYPE_SSIZE_T
118 # Code from module stat: 124 # Code from module stat:
119 gl_FUNC_STAT 125 gl_FUNC_STAT
120 gl_SYS_STAT_MODULE_INDICATOR([stat]) 126 gl_SYS_STAT_MODULE_INDICATOR([stat])
@@ -287,6 +293,9 @@ AC_DEFUN([gl_FILE_LIST], [
287 build-aux/arg-nonnull.h 293 build-aux/arg-nonnull.h
288 build-aux/c++defs.h 294 build-aux/c++defs.h
289 build-aux/warn-on-use.h 295 build-aux/warn-on-use.h
296 lib/allocator.h
297 lib/careadlinkat.c
298 lib/careadlinkat.h
290 lib/dosname.h 299 lib/dosname.h
291 lib/dtoastr.c 300 lib/dtoastr.c
292 lib/filemode.c 301 lib/filemode.c
@@ -335,6 +344,7 @@ AC_DEFUN([gl_FILE_LIST], [
335 m4/multiarch.m4 344 m4/multiarch.m4
336 m4/readlink.m4 345 m4/readlink.m4
337 m4/socklen.m4 346 m4/socklen.m4
347 m4/ssize_t.m4
338 m4/st_dm_mode.m4 348 m4/st_dm_mode.m4
339 m4/stat.m4 349 m4/stat.m4
340 m4/stdbool.m4 350 m4/stdbool.m4
diff --git a/m4/ssize_t.m4 b/m4/ssize_t.m4
new file mode 100644
index 00000000000..d7127521ebe
--- /dev/null
+++ b/m4/ssize_t.m4
@@ -0,0 +1,23 @@
1# ssize_t.m4 serial 5 (gettext-0.18.2)
2dnl Copyright (C) 2001-2003, 2006, 2010-2011 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7dnl From Bruno Haible.
8dnl Test whether ssize_t is defined.
9
10AC_DEFUN([gt_TYPE_SSIZE_T],
11[
12 AC_CACHE_CHECK([for ssize_t], [gt_cv_ssize_t],
13 [AC_COMPILE_IFELSE(
14 [AC_LANG_PROGRAM(
15 [[#include <sys/types.h>]],
16 [[int x = sizeof (ssize_t *) + sizeof (ssize_t);
17 return !x;]])],
18 [gt_cv_ssize_t=yes], [gt_cv_ssize_t=no])])
19 if test $gt_cv_ssize_t = no; then
20 AC_DEFINE([ssize_t], [int],
21 [Define as a signed type of the same size as size_t.])
22 fi
23])
diff --git a/src/ChangeLog b/src/ChangeLog
index c2e28251cb0..5649c8819d3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,15 @@
12011-04-01 Paul Eggert <eggert@cs.ucla.edu>
2
3 Replace two copies of readlink code with single gnulib version.
4 The gnulib version avoids calling malloc in the usual case,
5 and on 64-bit hosts doesn't have some arbitrary 32-bit limits.
6 * fileio.c (Ffile_symlink_p): Use emacs_readlink.
7 * filelock.c (current_lock_owner): Likewise.
8 * lisp.h (READLINK_BUFSIZE, emacs_readlink): New function.
9 * sysdep.c: Include allocator.h, careadlinkat.h.
10 (emacs_no_realloc_allocator): New static constant.
11 (emacs_readlink): New function.
12
12011-03-31 Juanma Barranquero <lekktu@gmail.com> 132011-03-31 Juanma Barranquero <lekktu@gmail.com>
2 14
3 * xdisp.c (redisplay_internal): Fix prototype. 15 * xdisp.c (redisplay_internal): Fix prototype.
diff --git a/src/fileio.c b/src/fileio.c
index 85431dfd5b1..552044f7272 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2579,9 +2579,8 @@ points to a nonexistent file. */)
2579{ 2579{
2580 Lisp_Object handler; 2580 Lisp_Object handler;
2581 char *buf; 2581 char *buf;
2582 int bufsize;
2583 int valsize;
2584 Lisp_Object val; 2582 Lisp_Object val;
2583 char readlink_buf[READLINK_BUFSIZE];
2585 2584
2586 CHECK_STRING (filename); 2585 CHECK_STRING (filename);
2587 filename = Fexpand_file_name (filename, Qnil); 2586 filename = Fexpand_file_name (filename, Qnil);
@@ -2594,36 +2593,15 @@ points to a nonexistent file. */)
2594 2593
2595 filename = ENCODE_FILE (filename); 2594 filename = ENCODE_FILE (filename);
2596 2595
2597 bufsize = 50; 2596 buf = emacs_readlink (SSDATA (filename), readlink_buf);
2598 buf = NULL; 2597 if (! buf)
2599 do 2598 return Qnil;
2600 {
2601 bufsize *= 2;
2602 buf = (char *) xrealloc (buf, bufsize);
2603 memset (buf, 0, bufsize);
2604
2605 errno = 0;
2606 valsize = readlink (SSDATA (filename), buf, bufsize);
2607 if (valsize == -1)
2608 {
2609#ifdef ERANGE
2610 /* HP-UX reports ERANGE if buffer is too small. */
2611 if (errno == ERANGE)
2612 valsize = bufsize;
2613 else
2614#endif
2615 {
2616 xfree (buf);
2617 return Qnil;
2618 }
2619 }
2620 }
2621 while (valsize >= bufsize);
2622 2599
2623 val = make_string (buf, valsize); 2600 val = build_string (buf);
2624 if (buf[0] == '/' && strchr (buf, ':')) 2601 if (buf[0] == '/' && strchr (buf, ':'))
2625 val = concat2 (build_string ("/:"), val); 2602 val = concat2 (build_string ("/:"), val);
2626 xfree (buf); 2603 if (buf != readlink_buf)
2604 xfree (buf);
2627 val = DECODE_FILE (val); 2605 val = DECODE_FILE (val);
2628 return val; 2606 return val;
2629} 2607}
diff --git a/src/filelock.c b/src/filelock.c
index 2138eaa502b..13b27c72f19 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -396,36 +396,16 @@ within_one_second (time_t a, time_t b)
396static int 396static int
397current_lock_owner (lock_info_type *owner, char *lfname) 397current_lock_owner (lock_info_type *owner, char *lfname)
398{ 398{
399 int len, ret; 399 int ret;
400 size_t len;
400 int local_owner = 0; 401 int local_owner = 0;
401 char *at, *dot, *colon; 402 char *at, *dot, *colon;
402 char *lfinfo = 0; 403 char readlink_buf[READLINK_BUFSIZE];
403 int bufsize = 50; 404 char *lfinfo = emacs_readlink (lfname, readlink_buf);
404 /* Read arbitrarily-long contents of symlink. Similar code in
405 file-symlink-p in fileio.c. */
406 do
407 {
408 bufsize *= 2;
409 lfinfo = (char *) xrealloc (lfinfo, bufsize);
410 errno = 0;
411 len = readlink (lfname, lfinfo, bufsize);
412#ifdef ERANGE
413 /* HP-UX reports ERANGE if the buffer is too small. */
414 if (len == -1 && errno == ERANGE)
415 len = bufsize;
416#endif
417 }
418 while (len >= bufsize);
419 405
420 /* If nonexistent lock file, all is well; otherwise, got strange error. */ 406 /* If nonexistent lock file, all is well; otherwise, got strange error. */
421 if (len == -1) 407 if (!lfinfo)
422 { 408 return errno == ENOENT ? 0 : -1;
423 xfree (lfinfo);
424 return errno == ENOENT ? 0 : -1;
425 }
426
427 /* Link info exists, so `len' is its length. Null terminate. */
428 lfinfo[len] = 0;
429 409
430 /* Even if the caller doesn't want the owner info, we still have to 410 /* Even if the caller doesn't want the owner info, we still have to
431 read it to determine return value, so allocate it. */ 411 read it to determine return value, so allocate it. */
@@ -441,7 +421,8 @@ current_lock_owner (lock_info_type *owner, char *lfname)
441 dot = strrchr (lfinfo, '.'); 421 dot = strrchr (lfinfo, '.');
442 if (!at || !dot) 422 if (!at || !dot)
443 { 423 {
444 xfree (lfinfo); 424 if (lfinfo != readlink_buf)
425 xfree (lfinfo);
445 return -1; 426 return -1;
446 } 427 }
447 len = at - lfinfo; 428 len = at - lfinfo;
@@ -467,7 +448,8 @@ current_lock_owner (lock_info_type *owner, char *lfname)
467 owner->host[len] = 0; 448 owner->host[len] = 0;
468 449
469 /* We're done looking at the link info. */ 450 /* We're done looking at the link info. */
470 xfree (lfinfo); 451 if (lfinfo != readlink_buf)
452 xfree (lfinfo);
471 453
472 /* On current host? */ 454 /* On current host? */
473 if (STRINGP (Fsystem_name ()) 455 if (STRINGP (Fsystem_name ())
diff --git a/src/lisp.h b/src/lisp.h
index 85838d111db..63f346f6a25 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3340,6 +3340,8 @@ extern int emacs_open (const char *, int, int);
3340extern int emacs_close (int); 3340extern int emacs_close (int);
3341extern int emacs_read (int, char *, unsigned int); 3341extern int emacs_read (int, char *, unsigned int);
3342extern int emacs_write (int, const char *, unsigned int); 3342extern int emacs_write (int, const char *, unsigned int);
3343enum { READLINK_BUFSIZE = 1024 };
3344extern char *emacs_readlink (const char *, char [READLINK_BUFSIZE]);
3343#ifndef HAVE_MEMSET 3345#ifndef HAVE_MEMSET
3344extern void *memset (void *, int, size_t); 3346extern void *memset (void *, int, size_t);
3345#endif 3347#endif
diff --git a/src/sysdep.c b/src/sysdep.c
index 1bb400421f0..a165a9ca52f 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -31,6 +31,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
31#endif /* HAVE_LIMITS_H */ 31#endif /* HAVE_LIMITS_H */
32#include <unistd.h> 32#include <unistd.h>
33 33
34#include <allocator.h>
35#include <careadlinkat.h>
34#include <ignore-value.h> 36#include <ignore-value.h>
35 37
36#include "lisp.h" 38#include "lisp.h"
@@ -1866,6 +1868,22 @@ emacs_write (int fildes, const char *buf, unsigned int nbyte)
1866 } 1868 }
1867 return (bytes_written); 1869 return (bytes_written);
1868} 1870}
1871
1872static struct allocator const emacs_norealloc_allocator =
1873 { xmalloc, NULL, xfree, memory_full };
1874
1875/* Get the symbolic link value of FILENAME. Return a pointer to a
1876 NUL-terminated string. If readlink fails, return NULL and set
1877 errno. If the value fits in INITIAL_BUF, return INITIAL_BUF.
1878 Otherwise, allocate memory and return a pointer to that memory. If
1879 memory allocation fails, diagnose and fail without returning. If
1880 successful, store the length of the symbolic link into *LINKLEN. */
1881char *
1882emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE])
1883{
1884 return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE,
1885 &emacs_norealloc_allocator, careadlinkatcwd);
1886}
1869 1887
1870#ifdef USG 1888#ifdef USG
1871/* 1889/*