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 | } |
