xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/gnulib-lib/safe-read.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1*946379e7Schristos /* An interface to read and write that retries after interrupts.
2*946379e7Schristos 
3*946379e7Schristos    Copyright (C) 1993, 1994, 1998, 2002, 2003, 2004, 2005, 2006 Free
4*946379e7Schristos    Software Foundation, Inc.
5*946379e7Schristos 
6*946379e7Schristos    This program is free software; you can redistribute it and/or modify
7*946379e7Schristos    it under the terms of the GNU General Public License as published by
8*946379e7Schristos    the Free Software Foundation; either version 2, or (at your option)
9*946379e7Schristos    any later version.
10*946379e7Schristos 
11*946379e7Schristos    This program is distributed in the hope that it will be useful,
12*946379e7Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*946379e7Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*946379e7Schristos    GNU General Public License for more details.
15*946379e7Schristos 
16*946379e7Schristos    You should have received a copy of the GNU General Public License
17*946379e7Schristos    along with this program; if not, write to the Free Software Foundation,
18*946379e7Schristos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19*946379e7Schristos 
20*946379e7Schristos #include <config.h>
21*946379e7Schristos 
22*946379e7Schristos /* Specification.  */
23*946379e7Schristos #ifdef SAFE_WRITE
24*946379e7Schristos # include "safe-write.h"
25*946379e7Schristos #else
26*946379e7Schristos # include "safe-read.h"
27*946379e7Schristos #endif
28*946379e7Schristos 
29*946379e7Schristos /* Get ssize_t.  */
30*946379e7Schristos #include <sys/types.h>
31*946379e7Schristos #include <unistd.h>
32*946379e7Schristos 
33*946379e7Schristos #include <errno.h>
34*946379e7Schristos 
35*946379e7Schristos #ifdef EINTR
36*946379e7Schristos # define IS_EINTR(x) ((x) == EINTR)
37*946379e7Schristos #else
38*946379e7Schristos # define IS_EINTR(x) 0
39*946379e7Schristos #endif
40*946379e7Schristos 
41*946379e7Schristos #include <limits.h>
42*946379e7Schristos 
43*946379e7Schristos #ifdef SAFE_WRITE
44*946379e7Schristos # define safe_rw safe_write
45*946379e7Schristos # define rw write
46*946379e7Schristos #else
47*946379e7Schristos # define safe_rw safe_read
48*946379e7Schristos # define rw read
49*946379e7Schristos # undef const
50*946379e7Schristos # define const /* empty */
51*946379e7Schristos #endif
52*946379e7Schristos 
53*946379e7Schristos /* Read(write) up to COUNT bytes at BUF from(to) descriptor FD, retrying if
54*946379e7Schristos    interrupted.  Return the actual number of bytes read(written), zero for EOF,
55*946379e7Schristos    or SAFE_READ_ERROR(SAFE_WRITE_ERROR) upon error.  */
56*946379e7Schristos size_t
safe_rw(int fd,void const * buf,size_t count)57*946379e7Schristos safe_rw (int fd, void const *buf, size_t count)
58*946379e7Schristos {
59*946379e7Schristos   /* Work around a bug in Tru64 5.1.  Attempting to read more than
60*946379e7Schristos      INT_MAX bytes fails with errno == EINVAL.  See
61*946379e7Schristos      <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>.
62*946379e7Schristos      When decreasing COUNT, keep it block-aligned.  */
63*946379e7Schristos   enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 };
64*946379e7Schristos 
65*946379e7Schristos   for (;;)
66*946379e7Schristos     {
67*946379e7Schristos       ssize_t result = rw (fd, buf, count);
68*946379e7Schristos 
69*946379e7Schristos       if (0 <= result)
70*946379e7Schristos 	return result;
71*946379e7Schristos       else if (IS_EINTR (errno))
72*946379e7Schristos 	continue;
73*946379e7Schristos       else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count)
74*946379e7Schristos 	count = BUGGY_READ_MAXIMUM;
75*946379e7Schristos       else
76*946379e7Schristos 	return result;
77*946379e7Schristos     }
78*946379e7Schristos }
79