diff options
Diffstat (limited to 'lib/safe-read.c')
-rw-r--r-- | lib/safe-read.c | 46 |
1 files changed, 22 insertions, 24 deletions
diff --git a/lib/safe-read.c b/lib/safe-read.c index c21d1cf1..9caf8466 100644 --- a/lib/safe-read.c +++ b/lib/safe-read.c | |||
@@ -1,5 +1,7 @@ | |||
1 | /* An interface to read and write that retries after interrupts. | 1 | /* An interface to read and write that retries after interrupts. |
2 | Copyright (C) 1993, 1994, 1998, 2002-2003 Free Software Foundation, Inc. | 2 | |
3 | Copyright (C) 1993, 1994, 1998, 2002, 2003, 2004, 2005 Free Software | ||
4 | Foundation, Inc. | ||
3 | 5 | ||
4 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 7 | it under the terms of the GNU General Public License as published by |
@@ -13,9 +15,9 @@ | |||
13 | 15 | ||
14 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
15 | along with this program; if not, write to the Free Software Foundation, | 17 | along with this program; if not, write to the Free Software Foundation, |
16 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | 18 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
17 | 19 | ||
18 | #if HAVE_CONFIG_H | 20 | #ifdef HAVE_CONFIG_H |
19 | # include <config.h> | 21 | # include <config.h> |
20 | #endif | 22 | #endif |
21 | 23 | ||
@@ -28,14 +30,9 @@ | |||
28 | 30 | ||
29 | /* Get ssize_t. */ | 31 | /* Get ssize_t. */ |
30 | #include <sys/types.h> | 32 | #include <sys/types.h> |
31 | #if HAVE_UNISTD_H | 33 | #include <unistd.h> |
32 | # include <unistd.h> | ||
33 | #endif | ||
34 | 34 | ||
35 | #include <errno.h> | 35 | #include <errno.h> |
36 | #ifndef errno | ||
37 | extern int errno; | ||
38 | #endif | ||
39 | 36 | ||
40 | #ifdef EINTR | 37 | #ifdef EINTR |
41 | # define IS_EINTR(x) ((x) == EINTR) | 38 | # define IS_EINTR(x) ((x) == EINTR) |
@@ -61,22 +58,23 @@ extern int errno; | |||
61 | size_t | 58 | size_t |
62 | safe_rw (int fd, void const *buf, size_t count) | 59 | safe_rw (int fd, void const *buf, size_t count) |
63 | { | 60 | { |
64 | ssize_t result; | 61 | /* Work around a bug in Tru64 5.1. Attempting to read more than |
62 | INT_MAX bytes fails with errno == EINVAL. See | ||
63 | <http://lists.gnu.org/archive/html/bug-gnu-utils/2002-04/msg00010.html>. | ||
64 | When decreasing COUNT, keep it block-aligned. */ | ||
65 | enum { BUGGY_READ_MAXIMUM = INT_MAX & ~8191 }; | ||
65 | 66 | ||
66 | /* POSIX limits COUNT to SSIZE_MAX, but we limit it further, requiring | 67 | for (;;) |
67 | that COUNT <= INT_MAX, to avoid triggering a bug in Tru64 5.1. | ||
68 | When decreasing COUNT, keep the file pointer block-aligned. | ||
69 | Note that in any case, read(write) may succeed, yet read(write) | ||
70 | fewer than COUNT bytes, so the caller must be prepared to handle | ||
71 | partial results. */ | ||
72 | if (count > INT_MAX) | ||
73 | count = INT_MAX & ~8191; | ||
74 | |||
75 | do | ||
76 | { | 68 | { |
77 | result = rw (fd, buf, count); | 69 | ssize_t result = rw (fd, buf, count); |
78 | } | ||
79 | while (result < 0 && IS_EINTR (errno)); | ||
80 | 70 | ||
81 | return (size_t) result; | 71 | if (0 <= result) |
72 | return result; | ||
73 | else if (IS_EINTR (errno)) | ||
74 | continue; | ||
75 | else if (errno == EINVAL && BUGGY_READ_MAXIMUM < count) | ||
76 | count = BUGGY_READ_MAXIMUM; | ||
77 | else | ||
78 | return result; | ||
79 | } | ||
82 | } | 80 | } |