Change output_write() to writebuf(), add readbuf() helper.

* src/misc.c (writebuf, readbuf): Create helper functions that will
reliably write a buffer to a file descriptor in the face of EINTR
causing short writes, and read from a file descriptor into a buffer
in the face of EINTR causing short reads.
* src/makeint.h: Declare these functions.
* src/output.c: Remove output_write() and replace with writebuf().
(_outputs, out_of_memory): Call writebuf(), not output_write().
* src/arscan.c (ar_scan): Call readbuf() instead of read(2).
(ar_member_touch): Remove duplicate header write, call writebuf()
instead of output_write(), and readbuf() instead of read(2).
This commit is contained in:
Paul Smith 2018-09-16 01:04:10 -04:00
parent ac11ec5497
commit 5d6508a475
4 changed files with 66 additions and 45 deletions

View file

@ -425,7 +425,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
{
char buf[SARMAG];
int nread;
EINTRLOOP (nread, read (desc, buf, SARMAG));
nread = readbuf (desc, buf, SARMAG);
if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG))
goto invalid;
}
@ -433,7 +433,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
#ifdef AIAMAG
{
int nread;
EINTRLOOP (nread, read (desc, &fl_header, FL_HSZ));
nread = readbuf (desc, &fl_header, FL_HSZ);
if (nread != FL_HSZ)
goto invalid;
@ -452,7 +452,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
goto invalid;
/* re-read the header into the "big" structure */
EINTRLOOP (nread, read (desc, &fl_header_big, FL_HSZ_BIG));
nread = readbuf (desc, &fl_header_big, FL_HSZ_BIG);
if (nread != FL_HSZ_BIG)
goto invalid;
}
@ -470,7 +470,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
unsigned short int buf;
#endif
int nread;
EINTRLOOP (nread, read (desc, &buf, sizeof (buf)));
nread = readbuf (desc, &buf, sizeof (buf));
if (nread != sizeof (buf) || buf != ARMAG)
goto invalid;
}
@ -550,8 +550,8 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
#ifdef AIAMAGBIG
if (big_archive)
{
EINTRLOOP (nread, read (desc, &member_header_big,
AR_MEMHDR_SZ(member_header_big)));
nread = readbuf (desc, &member_header_big,
AR_MEMHDR_SZ(member_header_big));
if (nread != AR_MEMHDR_SZ(member_header_big))
goto invalid;
@ -560,7 +560,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
if (name_len < 1 || name_len > ARNAME_MAX)
goto invalid;
EINTRLOOP (nread, read (desc, name, name_len));
nread = readbuf (desc, name, name_len);
if (nread != name_len)
goto invalid;
@ -578,8 +578,8 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
else
#endif
{
EINTRLOOP (nread, read (desc, &member_header,
AR_MEMHDR_SZ(member_header)));
nread = readbuf (desc, &member_header,
AR_MEMHDR_SZ(member_header));
if (nread != AR_MEMHDR_SZ(member_header))
goto invalid;
@ -588,7 +588,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
if (name_len < 1 || name_len > ARNAME_MAX)
goto invalid;
EINTRLOOP (nread, read (desc, name, name_len));
nread = readbuf (desc, name, name_len);
if (nread != name_len)
goto invalid;
@ -612,7 +612,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
eltmode, arg);
#else /* Not AIAMAG. */
EINTRLOOP (nread, read (desc, &member_header, AR_HDR_SIZE));
nread = readbuf (desc, &member_header, AR_HDR_SIZE);
if (nread == 0)
/* No data left means end of file; that is OK. */
break;
@ -691,7 +691,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
goto invalid;
name = alloca (name_len + 1);
EINTRLOOP (nread, read (desc, name, name_len));
nread = readbuf (desc, name, name_len);
if (nread != name_len)
goto invalid;
@ -759,7 +759,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
if (eltsize > INT_MAX)
goto invalid;
namemap = alloca (eltsize + 1);
EINTRLOOP (nread, read (desc, namemap, eltsize));
nread = readbuf (desc, namemap, eltsize);
if (nread != eltsize)
goto invalid;
namemap_size = eltsize;
@ -897,14 +897,7 @@ ar_member_touch (const char *arname, const char *memname)
EINTRLOOP (o, lseek (fd, pos, 0));
if (o < 0)
goto lose;
EINTRLOOP (r, read (fd, &ar_hdr, AR_HDR_SIZE));
if (r != AR_HDR_SIZE)
goto lose;
/* Write back the header, thus touching the archive file. */
EINTRLOOP (o, lseek (fd, pos, 0));
if (o < 0)
goto lose;
r = output_write (fd, &ar_hdr, AR_HDR_SIZE);
r = readbuf (fd, &ar_hdr, AR_HDR_SIZE);
if (r != AR_HDR_SIZE)
goto lose;
/* The file's mtime is the time we we want. */
@ -926,7 +919,7 @@ ar_member_touch (const char *arname, const char *memname)
EINTRLOOP (o, lseek (fd, pos, 0));
if (o < 0)
goto lose;
r = output_write (fd, &ar_hdr, AR_HDR_SIZE);
r = writebuf (fd, &ar_hdr, AR_HDR_SIZE);
if (r != AR_HDR_SIZE)
goto lose;
close (fd);

View file

@ -529,6 +529,8 @@ void print_spaces (unsigned int);
char *find_percent (char *);
const char *find_percent_cached (const char **);
FILE *get_tmpfile (char **, const char *);
ssize_t writebuf (int, const void*, size_t);
ssize_t readbuf (int, void*, size_t);
#ifndef NO_ARCHIVES
int ar_name (const char *);

View file

@ -335,6 +335,52 @@ find_next_token (const char **ptr, size_t *lengthptr)
return (char *)p;
}
/* Write a BUFFER of size LEN to file descriptor FD.
Retry short writes from EINTR. Return LEN, or -1 on error. */
ssize_t
writebuf (int fd, const void *buffer, size_t len)
{
const char *msg = buffer;
size_t l = len;
while (l)
{
ssize_t r;
EINTRLOOP (r, write (fd, msg, l));
if (r < 0)
return r;
l -= r;
msg += r;
}
return (ssize_t)len;
}
/* Read until we get LEN bytes from file descriptor FD, into BUFFER.
Retry short reads on EINTR. If we get an error, return it.
Return 0 at EOF. */
ssize_t
readbuf (int fd, void *buffer, size_t len)
{
char *msg = buffer;
while (len)
{
ssize_t r;
EINTRLOOP (r, read (fd, msg, len));
if (r < 0)
return r;
if (r == 0)
break;
len -= r;
msg += r;
}
return (ssize_t)(msg - (char*)buffer);
}
/* Copy a chain of 'struct dep'. For 2nd expansion deps, dup the name. */

View file

@ -53,26 +53,6 @@ unsigned int stdio_traced = 0;
# define STREAM_OK(_s) 1
#endif
/* Write a BUFFER of size LEN to file descriptor FD.
Handle EINTR and other short writes. If we get an error, ignore it. */
int
output_write (int fd, const void *buffer, size_t len)
{
const char *msg = buffer;
while (1)
{
ssize_t r;
EINTRLOOP (r, write (fd, msg, len));
if (r < 0 || (size_t)r == len)
return r;
len -= r;
msg += r;
}
}
/* Write a string to the current STDOUT or STDERR. */
static void
_outputs (struct output *out, int is_err, const char *msg)
@ -89,7 +69,7 @@ _outputs (struct output *out, int is_err, const char *msg)
size_t len = strlen (msg);
int r;
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
output_write (fd, msg, len);
writebuf (fd, msg, len);
}
}
@ -696,7 +676,7 @@ pfatal_with_name (const char *name)
void
out_of_memory ()
{
output_write (FD_STDOUT, program, strlen (program));
output_write (FD_STDOUT, STRING_SIZE_TUPLE (": *** virtual memory exhausted\n"));
writebuf (FD_STDOUT, program, strlen (program));
writebuf (FD_STDOUT, STRING_SIZE_TUPLE (": *** virtual memory exhausted\n"));
exit (MAKE_FAILURE);
}