summaryrefslogtreecommitdiff
path: root/lib/safe-write.c
blob: 8c60bba39e0c0f83303c754b5eceb69e04ab7a37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/* An interface to write() that retries after interrupts.
   Copyright (C) 1993, 1994, 1998, 2002 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 2, 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, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#if HAVE_CONFIG_H
# include <config.h>
#endif

/* Specification.  */
#include "safe-write.h"

/* Get ssize_t.  */
#include <sys/types.h>
#if HAVE_UNISTD_H
# include <unistd.h>
#endif

#include <errno.h>
#ifndef errno
extern int errno;
#endif

#include <limits.h>

#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif

/* The extra casts work around common compiler bugs.  */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
   It is necessary at least when t == time_t.  */
#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
			      ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0))
#define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))

#ifndef INT_MAX
# define INT_MAX TYPE_MAXIMUM (int)
#endif

/* We don't pass an nbytes count > SSIZE_MAX to write() - POSIX says the
   effect would be implementation-defined.  Also we don't pass an nbytes
   count > INT_MAX but <= SSIZE_MAX to write() - this triggers a bug in
   Tru64 5.1.  */
#define MAX_BYTES_TO_READ INT_MAX

/* Write up to COUNT bytes at BUF to descriptor FD, retrying if interrupted.
   Return the actual number of bytes written, zero for EOF, or (size_t) -1
   for an error.  */
size_t
safe_write (int fd, const void *buf, size_t count)
{
  size_t nbytes_to_write = count;
  ssize_t result;

  /* Limit the number of bytes to write, to avoid running into unspecified
     behaviour.  But keep the file pointer block aligned when doing so.
     Note that in this case we don't need to call write() multiple times here,
     because the caller is prepared to partial results.  */
  if (nbytes_to_write > MAX_BYTES_TO_READ)
    nbytes_to_write = MAX_BYTES_TO_READ & ~8191;

  do
    {
      result = write (fd, buf, nbytes_to_write);
    }
#ifdef EINTR
  while (result < 0 && errno == EINTR);
#else
  while (0);
#endif

  return (size_t) result;
}