* miscfuncs.cc (check_iovec_for_read): Don't check buffer when zero length

iov_len.
(check_iovec_for_write): Ditto.
* fhandler.h (fhandler_base::readv): New method.
(fhandler_base::writev): Ditto.
* fhandler.cc (fhandler_base::readv): New method.
(fhandler_base::writev): Ditto.
* syscalls.cc (_read): Delegate to readv(2).
(_write): Ditto, mutatis mutandi.
(readv): Rewrite, based on the old _read code, to use the new
fhandler_base::readv method.  Improve access mode handling and ensure all calls
reach the final strace statement.
(writev): Ditto, mutatis mutandi.
* include/sys/uio.h (struct iovec): Change field types to match SUSv3.
* winsup.h (check_iovec_for_read): New function.
(check_iovec_for_write): Ditto.
* miscfuncs.cc (check_iovec_for_read): Ditto.
(check_iovec_for_write): Ditto.
This commit is contained in:
Christopher Faylor
2002-08-30 15:47:10 +00:00
parent 70c306d781
commit ab7f9b938f
8 changed files with 288 additions and 130 deletions

View File

@ -321,15 +321,42 @@ getsid (pid_t pid)
extern "C" ssize_t
_read (int fd, void *ptr, size_t len)
{
if (len == 0)
return 0;
const struct iovec iov =
{
iov_base: ptr,
iov_len: len
};
if (__check_null_invalid_struct_errno (ptr, len))
return -1;
return readv (fd, &iov, 1);
}
int res;
extern "C" ssize_t
_write (int fd, const void *ptr, size_t len)
{
const struct iovec iov =
{
iov_base: (void *) ptr, // const_cast
iov_len: len
};
return writev (fd, &iov, 1);
}
extern "C" ssize_t
readv (int fd, const struct iovec *const iov, const int iovcnt)
{
extern int sigcatchers;
int e = get_errno ();
const int e = get_errno ();
int res = -1;
const ssize_t tot = check_iovec_for_read (iov, iovcnt);
if (tot <= 0)
{
res = tot;
goto done;
}
while (1)
{
@ -337,13 +364,19 @@ _read (int fd, void *ptr, size_t len)
cygheap_fdget cfd (fd);
if (cfd < 0)
return -1;
break;
if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
{
set_errno (EBADF);
break;
}
DWORD wait = cfd->is_nonblocking () ? 0 : INFINITE;
/* Could block, so let user know we at least got here. */
syscall_printf ("read (%d, %p, %d) %sblocking, sigcatchers %d",
fd, ptr, len, wait ? "" : "non", sigcatchers);
syscall_printf ("readv (%d, %p, %d) %sblocking, sigcatchers %d",
fd, iov, iovcnt, wait ? "" : "non", sigcatchers);
if (wait && (!cfd->is_slow () || cfd->get_r_no_interrupt ()))
debug_printf ("no need to call ready_for_read\n");
@ -357,177 +390,91 @@ _read (int fd, void *ptr, size_t len)
ensure that an fd, closed in another thread, aborts I/O
operations. */
if (!cfd.isopen ())
return -1;
break;
/* Check to see if this is a background read from a "tty",
sending a SIGTTIN, if appropriate */
res = cfd->bg_check (SIGTTIN);
if (!cfd.isopen ())
return -1;
{
res = -1;
break;
}
if (res > bg_eof)
{
myself->process_state |= PID_TTYIN;
if (!cfd.isopen ())
return -1;
res = cfd->read (ptr, len);
{
res = -1;
break;
}
res = cfd->readv (iov, iovcnt, tot);
myself->process_state &= ~PID_TTYIN;
}
out:
if (res && get_errno () == EACCES &&
!(cfd->get_flags () & (O_RDONLY | O_RDWR)))
{
set_errno (EBADF);
break;
}
if (res >= 0 || get_errno () != EINTR || !thisframe.call_signal_handler ())
break;
set_errno (e);
}
syscall_printf ("%d = read (%d, %p, %d), errno %d", res, fd, ptr, len,
done:
syscall_printf ("%d = readv (%d, %p, %d), errno %d", res, fd, iov, iovcnt,
get_errno ());
MALLOC_CHECK;
return res;
}
extern "C" ssize_t
_write (int fd, const void *ptr, size_t len)
writev (const int fd, const struct iovec *const iov, const int iovcnt)
{
int res = -1;
const ssize_t tot = check_iovec_for_write (iov, iovcnt);
sigframe thisframe (mainthread);
cygheap_fdget cfd (fd);
if (cfd < 0)
goto done;
/* No further action required for len == 0 */
if (len == 0)
if (tot <= 0)
{
res = 0;
res = tot;
goto done;
}
if (len && __check_invalid_read_ptr_errno (ptr, len))
goto done;
if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
{
set_errno (EBADF);
goto done;
}
/* Could block, so let user know we at least got here. */
if (fd == 1 || fd == 2)
paranoid_printf ("write (%d, %p, %d)", fd, ptr, len);
paranoid_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
else
syscall_printf ("write (%d, %p, %d)", fd, ptr, len);
syscall_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
res = cfd->bg_check (SIGTTOU);
if (res > bg_eof)
{
myself->process_state |= PID_TTYOU;
res = cfd->write (ptr, len);
res = cfd->writev (iov, iovcnt, tot);
myself->process_state &= ~PID_TTYOU;
if (res && get_errno () == EACCES &&
!(cfd->get_flags () & (O_WRONLY | O_RDWR)))
set_errno (EBADF);
}
done:
if (fd == 1 || fd == 2)
paranoid_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len);
paranoid_printf ("%d = write (%d, %p, %d), errno %d",
res, fd, iov, iovcnt, get_errno ());
else
syscall_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len);
syscall_printf ("%d = write (%d, %p, %d), errno %d",
res, fd, iov, iovcnt, get_errno ());
return (ssize_t) res;
}
/*
* FIXME - should really move this interface into fhandler, and implement
* write in terms of it. There are devices in Win32 that could do this with
* overlapped I/O much more efficiently - we should eventually use
* these.
*/
extern "C" ssize_t
writev (int fd, const struct iovec *iov, int iovcnt)
{
int i;
ssize_t len, total;
char *base;
if (iovcnt < 1 || iovcnt > IOV_MAX)
{
set_errno (EINVAL);
return -1;
}
/* Ensure that the sum of the iov_len values is less than
SSIZE_MAX (per spec), if so, we must fail with no output (per spec).
*/
total = 0;
for (i = 0; i < iovcnt; ++i)
{
total += iov[i].iov_len;
if (total > SSIZE_MAX)
{
set_errno (EINVAL);
return -1;
}
}
/* Now write the data */
for (i = 0, total = 0; i < iovcnt; i++, iov++)
{
len = iov->iov_len;
base = iov->iov_base;
while (len > 0)
{
register int nbytes;
nbytes = write (fd, base, len);
if (nbytes < 0 && total == 0)
return -1;
if (nbytes <= 0)
return total;
len -= nbytes;
total += nbytes;
base += nbytes;
}
}
return total;
}
/*
* FIXME - should really move this interface into fhandler, and implement
* read in terms of it. There are devices in Win32 that could do this with
* overlapped I/O much more efficiently - we should eventually use
* these.
*/
extern "C" ssize_t
readv (int fd, const struct iovec *iov, int iovcnt)
{
int i;
ssize_t len, total;
char *base;
for (i = 0, total = 0; i < iovcnt; i++, iov++)
{
len = iov->iov_len;
base = iov->iov_base;
while (len > 0)
{
register int nbytes;
nbytes = read (fd, base, len);
if (nbytes < 0 && total == 0)
return -1;
if (nbytes <= 0)
return total;
len -= nbytes;
total += nbytes;
base += nbytes;
}
}
return total;
MALLOC_CHECK;
return res;
}
/* _open */