* 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:
parent
70c306d781
commit
ab7f9b938f
@ -1,3 +1,27 @@
|
|||||||
|
2002-08-30 Christopher Faylor <cgf@redhat.com>
|
||||||
|
|
||||||
|
* miscfuncs.cc (check_iovec_for_read): Don't check buffer when zero
|
||||||
|
length iov_len.
|
||||||
|
(check_iovec_for_write): Ditto.
|
||||||
|
|
||||||
|
2002-08-27 Conrad Scott <conrad.scott@dsl.pipex.com>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2002-08-30 Corinna Vinschen <corinna@vinschen.de>
|
2002-08-30 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* cygwin.din: Add more prototypes for new wchar functions in newlib.
|
* cygwin.din: Add more prototypes for new wchar functions in newlib.
|
||||||
|
@ -13,6 +13,7 @@ details. */
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/cygwin.h>
|
#include <sys/cygwin.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#include "perprocess.h"
|
#include "perprocess.h"
|
||||||
@ -697,6 +698,109 @@ fhandler_base::write (const void *ptr, size_t len)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
fhandler_base::readv (const struct iovec *const iov, const int iovcnt,
|
||||||
|
ssize_t tot)
|
||||||
|
{
|
||||||
|
assert (iov);
|
||||||
|
assert (iovcnt >= 1);
|
||||||
|
|
||||||
|
if (iovcnt == 1)
|
||||||
|
return read (iov->iov_base, iov->iov_len);
|
||||||
|
|
||||||
|
if (tot == -1) // i.e. if not pre-calculated by the caller.
|
||||||
|
{
|
||||||
|
tot = 0;
|
||||||
|
const struct iovec *iovptr = iov + iovcnt;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
iovptr -= 1;
|
||||||
|
tot += iovptr->iov_len;
|
||||||
|
}
|
||||||
|
while (iovptr != iov);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (tot >= 0);
|
||||||
|
|
||||||
|
if (tot == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
char *buf = (char *) alloca (tot);
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
{
|
||||||
|
set_errno (ENOMEM);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssize_t res = read (buf, tot);
|
||||||
|
|
||||||
|
const struct iovec *iovptr = iov;
|
||||||
|
int nbytes = res;
|
||||||
|
|
||||||
|
while (nbytes > 0)
|
||||||
|
{
|
||||||
|
const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
|
||||||
|
memcpy (iovptr->iov_base, buf, frag);
|
||||||
|
buf += frag;
|
||||||
|
iovptr += 1;
|
||||||
|
nbytes -= frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
fhandler_base::writev (const struct iovec *const iov, const int iovcnt,
|
||||||
|
ssize_t tot)
|
||||||
|
{
|
||||||
|
assert (iov);
|
||||||
|
assert (iovcnt >= 1);
|
||||||
|
|
||||||
|
if (iovcnt == 1)
|
||||||
|
return write (iov->iov_base, iov->iov_len);
|
||||||
|
|
||||||
|
if (tot == -1) // i.e. if not pre-calculated by the caller.
|
||||||
|
{
|
||||||
|
tot = 0;
|
||||||
|
const struct iovec *iovptr = iov + iovcnt;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
iovptr -= 1;
|
||||||
|
tot += iovptr->iov_len;
|
||||||
|
}
|
||||||
|
while (iovptr != iov);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (tot >= 0);
|
||||||
|
|
||||||
|
if (tot == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
char *const buf = (char *) alloca (tot);
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
{
|
||||||
|
set_errno (ENOMEM);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *bufptr = buf;
|
||||||
|
const struct iovec *iovptr = iov;
|
||||||
|
int nbytes = tot;
|
||||||
|
|
||||||
|
while (nbytes != 0)
|
||||||
|
{
|
||||||
|
const int frag = min (nbytes, (ssize_t) iovptr->iov_len);
|
||||||
|
memcpy (bufptr, iovptr->iov_base, frag);
|
||||||
|
bufptr += frag;
|
||||||
|
iovptr += 1;
|
||||||
|
nbytes -= frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
return write (buf, tot);
|
||||||
|
}
|
||||||
|
|
||||||
__off64_t
|
__off64_t
|
||||||
fhandler_base::lseek (__off64_t offset, int whence)
|
fhandler_base::lseek (__off64_t offset, int whence)
|
||||||
{
|
{
|
||||||
|
@ -116,6 +116,7 @@ class path_conv;
|
|||||||
class fhandler_disk_file;
|
class fhandler_disk_file;
|
||||||
typedef struct __DIR DIR;
|
typedef struct __DIR DIR;
|
||||||
struct dirent;
|
struct dirent;
|
||||||
|
struct iovec;
|
||||||
|
|
||||||
enum bg_check_types
|
enum bg_check_types
|
||||||
{
|
{
|
||||||
@ -297,6 +298,8 @@ class fhandler_base
|
|||||||
virtual char const * ttyname () { return get_name(); }
|
virtual char const * ttyname () { return get_name(); }
|
||||||
virtual int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
|
virtual int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (3)));
|
||||||
virtual int write (const void *ptr, size_t len);
|
virtual int write (const void *ptr, size_t len);
|
||||||
|
virtual ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
|
||||||
|
virtual ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
|
||||||
virtual __off64_t lseek (__off64_t offset, int whence);
|
virtual __off64_t lseek (__off64_t offset, int whence);
|
||||||
virtual int lock (int, struct flock *);
|
virtual int lock (int, struct flock *);
|
||||||
virtual void dump ();
|
virtual void dump ();
|
||||||
|
@ -736,7 +736,9 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags)
|
|||||||
p = buf;
|
p = buf;
|
||||||
while (nb > 0)
|
while (nb > 0)
|
||||||
{
|
{
|
||||||
ssize_t cnt = min(nb, iov->iov_len);
|
ssize_t cnt = iov->iov_len;
|
||||||
|
if (nb < cnt)
|
||||||
|
cnt = nb;
|
||||||
memcpy (iov->iov_base, p, cnt);
|
memcpy (iov->iov_base, p, cnt);
|
||||||
p += cnt;
|
p += cnt;
|
||||||
nb -= cnt;
|
nb -= cnt;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* sys/uio.h
|
/* sys/uio.h
|
||||||
|
|
||||||
Copyright 1996, 2000, 2001 Red Hat, Inc.
|
Copyright 1996, 2000, 2001, 2002 Red Hat, Inc.
|
||||||
|
|
||||||
This file is part of Cygwin.
|
This file is part of Cygwin.
|
||||||
|
|
||||||
@ -24,9 +24,10 @@ __BEGIN_DECLS
|
|||||||
* Define the uio buffers used for writev, readv.
|
* Define the uio buffers used for writev, readv.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct iovec {
|
struct iovec
|
||||||
caddr_t iov_base;
|
{
|
||||||
int iov_len;
|
void *iov_base;
|
||||||
|
size_t iov_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ssize_t readv __P ((int filedes, const struct iovec *vector, int count));
|
extern ssize_t readv __P ((int filedes, const struct iovec *vector, int count));
|
||||||
|
@ -11,6 +11,9 @@ details. */
|
|||||||
#include "winsup.h"
|
#include "winsup.h"
|
||||||
#include "cygerrno.h"
|
#include "cygerrno.h"
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
#include <winnls.h>
|
#include <winnls.h>
|
||||||
|
|
||||||
@ -179,6 +182,76 @@ __check_invalid_read_ptr_errno (const void *s, unsigned sz)
|
|||||||
return set_errno (EFAULT);
|
return set_errno (EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
check_iovec_for_read (const struct iovec *iov, int iovcnt)
|
||||||
|
{
|
||||||
|
if (iovcnt <= 0 || iovcnt > IOV_MAX)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__check_invalid_read_ptr_errno (iov, iovcnt * sizeof (*iov)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size_t tot = 0;
|
||||||
|
|
||||||
|
while (iovcnt != 0)
|
||||||
|
{
|
||||||
|
if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iov->iov_len
|
||||||
|
&& __check_null_invalid_struct_errno (iov->iov_base, iov->iov_len))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
iov += 1;
|
||||||
|
iovcnt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (tot <= SSIZE_MAX);
|
||||||
|
|
||||||
|
return (ssize_t) tot;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
check_iovec_for_write (const struct iovec *iov, int iovcnt)
|
||||||
|
{
|
||||||
|
if (iovcnt <= 0 || iovcnt > IOV_MAX)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__check_invalid_read_ptr_errno (iov, iovcnt * sizeof (*iov)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size_t tot = 0;
|
||||||
|
|
||||||
|
while (iovcnt != 0)
|
||||||
|
{
|
||||||
|
if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX)
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iov->iov_len
|
||||||
|
&& __check_invalid_read_ptr_errno (iov->iov_base, iov->iov_len))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
iov += 1;
|
||||||
|
iovcnt -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert (tot <= SSIZE_MAX);
|
||||||
|
|
||||||
|
return (ssize_t) tot;
|
||||||
|
}
|
||||||
|
|
||||||
UINT
|
UINT
|
||||||
get_cp ()
|
get_cp ()
|
||||||
{
|
{
|
||||||
|
@ -321,15 +321,42 @@ getsid (pid_t pid)
|
|||||||
extern "C" ssize_t
|
extern "C" ssize_t
|
||||||
_read (int fd, void *ptr, size_t len)
|
_read (int fd, void *ptr, size_t len)
|
||||||
{
|
{
|
||||||
if (len == 0)
|
const struct iovec iov =
|
||||||
return 0;
|
{
|
||||||
|
iov_base: ptr,
|
||||||
|
iov_len: len
|
||||||
|
};
|
||||||
|
|
||||||
if (__check_null_invalid_struct_errno (ptr, len))
|
return readv (fd, &iov, 1);
|
||||||
return -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;
|
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)
|
while (1)
|
||||||
{
|
{
|
||||||
@ -337,13 +364,19 @@ _read (int fd, void *ptr, size_t len)
|
|||||||
|
|
||||||
cygheap_fdget cfd (fd);
|
cygheap_fdget cfd (fd);
|
||||||
if (cfd < 0)
|
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;
|
DWORD wait = cfd->is_nonblocking () ? 0 : INFINITE;
|
||||||
|
|
||||||
/* Could block, so let user know we at least got here. */
|
/* Could block, so let user know we at least got here. */
|
||||||
syscall_printf ("read (%d, %p, %d) %sblocking, sigcatchers %d",
|
syscall_printf ("readv (%d, %p, %d) %sblocking, sigcatchers %d",
|
||||||
fd, ptr, len, wait ? "" : "non", sigcatchers);
|
fd, iov, iovcnt, wait ? "" : "non", sigcatchers);
|
||||||
|
|
||||||
if (wait && (!cfd->is_slow () || cfd->get_r_no_interrupt ()))
|
if (wait && (!cfd->is_slow () || cfd->get_r_no_interrupt ()))
|
||||||
debug_printf ("no need to call ready_for_read\n");
|
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
|
ensure that an fd, closed in another thread, aborts I/O
|
||||||
operations. */
|
operations. */
|
||||||
if (!cfd.isopen ())
|
if (!cfd.isopen ())
|
||||||
return -1;
|
break;
|
||||||
|
|
||||||
/* Check to see if this is a background read from a "tty",
|
/* Check to see if this is a background read from a "tty",
|
||||||
sending a SIGTTIN, if appropriate */
|
sending a SIGTTIN, if appropriate */
|
||||||
res = cfd->bg_check (SIGTTIN);
|
res = cfd->bg_check (SIGTTIN);
|
||||||
|
|
||||||
if (!cfd.isopen ())
|
if (!cfd.isopen ())
|
||||||
return -1;
|
{
|
||||||
|
res = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (res > bg_eof)
|
if (res > bg_eof)
|
||||||
{
|
{
|
||||||
myself->process_state |= PID_TTYIN;
|
myself->process_state |= PID_TTYIN;
|
||||||
if (!cfd.isopen ())
|
if (!cfd.isopen ())
|
||||||
return -1;
|
{
|
||||||
res = cfd->read (ptr, len);
|
res = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res = cfd->readv (iov, iovcnt, tot);
|
||||||
myself->process_state &= ~PID_TTYIN;
|
myself->process_state &= ~PID_TTYIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
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 ())
|
if (res >= 0 || get_errno () != EINTR || !thisframe.call_signal_handler ())
|
||||||
break;
|
break;
|
||||||
set_errno (e);
|
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 ());
|
get_errno ());
|
||||||
MALLOC_CHECK;
|
MALLOC_CHECK;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" ssize_t
|
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;
|
int res = -1;
|
||||||
|
const ssize_t tot = check_iovec_for_write (iov, iovcnt);
|
||||||
|
|
||||||
sigframe thisframe (mainthread);
|
sigframe thisframe (mainthread);
|
||||||
cygheap_fdget cfd (fd);
|
cygheap_fdget cfd (fd);
|
||||||
if (cfd < 0)
|
if (cfd < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* No further action required for len == 0 */
|
if (tot <= 0)
|
||||||
if (len == 0)
|
|
||||||
{
|
{
|
||||||
res = 0;
|
res = tot;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len && __check_invalid_read_ptr_errno (ptr, len))
|
if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
|
||||||
goto done;
|
{
|
||||||
|
set_errno (EBADF);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Could block, so let user know we at least got here. */
|
/* Could block, so let user know we at least got here. */
|
||||||
if (fd == 1 || fd == 2)
|
if (fd == 1 || fd == 2)
|
||||||
paranoid_printf ("write (%d, %p, %d)", fd, ptr, len);
|
paranoid_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
|
||||||
else
|
else
|
||||||
syscall_printf ("write (%d, %p, %d)", fd, ptr, len);
|
syscall_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
|
||||||
|
|
||||||
res = cfd->bg_check (SIGTTOU);
|
res = cfd->bg_check (SIGTTOU);
|
||||||
|
|
||||||
if (res > bg_eof)
|
if (res > bg_eof)
|
||||||
{
|
{
|
||||||
myself->process_state |= PID_TTYOU;
|
myself->process_state |= PID_TTYOU;
|
||||||
res = cfd->write (ptr, len);
|
res = cfd->writev (iov, iovcnt, tot);
|
||||||
myself->process_state &= ~PID_TTYOU;
|
myself->process_state &= ~PID_TTYOU;
|
||||||
if (res && get_errno () == EACCES &&
|
|
||||||
!(cfd->get_flags () & (O_WRONLY | O_RDWR)))
|
|
||||||
set_errno (EBADF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (fd == 1 || fd == 2)
|
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
|
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;
|
MALLOC_CHECK;
|
||||||
}
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* _open */
|
/* _open */
|
||||||
|
@ -221,6 +221,10 @@ int __stdcall __check_invalid_read_ptr_errno (const void *s, unsigned sz) __attr
|
|||||||
#define check_null_invalid_struct_errno(s) \
|
#define check_null_invalid_struct_errno(s) \
|
||||||
__check_null_invalid_struct_errno ((s), sizeof (*(s)))
|
__check_null_invalid_struct_errno ((s), sizeof (*(s)))
|
||||||
|
|
||||||
|
struct iovec;
|
||||||
|
ssize_t check_iovec_for_read (const struct iovec *, int) __attribute__ ((regparm(2)));
|
||||||
|
ssize_t check_iovec_for_write (const struct iovec *, int) __attribute__ ((regparm(2)));
|
||||||
|
|
||||||
#define set_winsock_errno() __set_winsock_errno (__FUNCTION__, __LINE__)
|
#define set_winsock_errno() __set_winsock_errno (__FUNCTION__, __LINE__)
|
||||||
void __set_winsock_errno (const char *fn, int ln) __attribute__ ((regparm(2)));
|
void __set_winsock_errno (const char *fn, int ln) __attribute__ ((regparm(2)));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user