adb: implement adb_writev.

Change-Id: I55258c155d7b07368ebb45577b2e01ca804cf258
Test: adb_test
Test: python test_device.py
diff --git a/sysdeps_win32.cpp b/sysdeps_win32.cpp
index 7d35fb6..433a59d 100644
--- a/sysdeps_win32.cpp
+++ b/sysdeps_win32.cpp
@@ -36,6 +36,7 @@
 
 #include <android-base/errors.h>
 #include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/utf8.h>
@@ -43,6 +44,8 @@
 #include "adb.h"
 #include "adb_utils.h"
 
+#include "sysdeps/uio.h"
+
 extern void fatal(const char *fmt, ...);
 
 /* forward declarations */
@@ -57,6 +60,7 @@
     int (*_fh_lseek)(FH, int, int);
     int (*_fh_read)(FH, void*, int);
     int (*_fh_write)(FH, const void*, int);
+    int (*_fh_writev)(FH, const adb_iovec*, int);
 } FHClassRec;
 
 static void _fh_file_init(FH);
@@ -64,6 +68,7 @@
 static int _fh_file_lseek(FH, int, int);
 static int _fh_file_read(FH, void*, int);
 static int _fh_file_write(FH, const void*, int);
+static int _fh_file_writev(FH, const adb_iovec*, int);
 
 static const FHClassRec _fh_file_class = {
     _fh_file_init,
@@ -71,6 +76,7 @@
     _fh_file_lseek,
     _fh_file_read,
     _fh_file_write,
+    _fh_file_writev,
 };
 
 static void _fh_socket_init(FH);
@@ -78,6 +84,7 @@
 static int _fh_socket_lseek(FH, int, int);
 static int _fh_socket_read(FH, void*, int);
 static int _fh_socket_write(FH, const void*, int);
+static int _fh_socket_writev(FH, const adb_iovec*, int);
 
 static const FHClassRec _fh_socket_class = {
     _fh_socket_init,
@@ -85,6 +92,7 @@
     _fh_socket_lseek,
     _fh_socket_read,
     _fh_socket_write,
+    _fh_socket_writev,
 };
 
 #define assert(cond)                                                                       \
@@ -248,57 +256,88 @@
 /**************************************************************************/
 /**************************************************************************/
 
-static void _fh_file_init( FH  f ) {
+static void _fh_file_init(FH f) {
     f->fh_handle = INVALID_HANDLE_VALUE;
 }
 
-static int _fh_file_close( FH  f ) {
-    CloseHandle( f->fh_handle );
+static int _fh_file_close(FH f) {
+    CloseHandle(f->fh_handle);
     f->fh_handle = INVALID_HANDLE_VALUE;
     return 0;
 }
 
-static int _fh_file_read( FH  f,  void*  buf, int   len ) {
-    DWORD  read_bytes;
+static int _fh_file_read(FH f, void* buf, int len) {
+    DWORD read_bytes;
 
-    if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
-        D( "adb_read: could not read %d bytes from %s", len, f->name );
+    if (!ReadFile(f->fh_handle, buf, (DWORD)len, &read_bytes, NULL)) {
+        D("adb_read: could not read %d bytes from %s", len, f->name);
         errno = EIO;
         return -1;
     } else if (read_bytes < (DWORD)len) {
         f->eof = 1;
     }
-    return (int)read_bytes;
+    return read_bytes;
 }
 
-static int _fh_file_write( FH  f,  const void*  buf, int   len ) {
-    DWORD  wrote_bytes;
+static int _fh_file_write(FH f, const void* buf, int len) {
+    DWORD wrote_bytes;
 
-    if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
-        D( "adb_file_write: could not write %d bytes from %s", len, f->name );
+    if (!WriteFile(f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL)) {
+        D("adb_file_write: could not write %d bytes from %s", len, f->name);
         errno = EIO;
         return -1;
     } else if (wrote_bytes < (DWORD)len) {
         f->eof = 1;
     }
-    return  (int)wrote_bytes;
+    return wrote_bytes;
 }
 
-static int _fh_file_lseek( FH  f, int  pos, int  origin ) {
-    DWORD  method;
-    DWORD  result;
+static int _fh_file_writev(FH f, const adb_iovec* iov, int iovcnt) {
+    if (iovcnt <= 0) {
+        errno = EINVAL;
+        return -1;
+    }
 
-    switch (origin)
-    {
-        case SEEK_SET:  method = FILE_BEGIN; break;
-        case SEEK_CUR:  method = FILE_CURRENT; break;
-        case SEEK_END:  method = FILE_END; break;
+    DWORD wrote_bytes = 0;
+
+    for (int i = 0; i < iovcnt; ++i) {
+        ssize_t rc = _fh_file_write(f, iov[i].iov_base, iov[i].iov_len);
+        if (rc == -1) {
+            return wrote_bytes > 0 ? wrote_bytes : -1;
+        } else if (rc == 0) {
+            return wrote_bytes;
+        }
+
+        wrote_bytes += rc;
+
+        if (static_cast<size_t>(rc) < iov[i].iov_len) {
+            return wrote_bytes;
+        }
+    }
+
+    return wrote_bytes;
+}
+
+static int _fh_file_lseek(FH f, int pos, int origin) {
+    DWORD method;
+    DWORD result;
+
+    switch (origin) {
+        case SEEK_SET:
+            method = FILE_BEGIN;
+            break;
+        case SEEK_CUR:
+            method = FILE_CURRENT;
+            break;
+        case SEEK_END:
+            method = FILE_END;
+            break;
         default:
             errno = EINVAL;
             return -1;
     }
 
-    result = SetFilePointer( f->fh_handle, pos, NULL, method );
+    result = SetFilePointer(f->fh_handle, pos, NULL, method);
     if (result == INVALID_SET_FILE_POINTER) {
         errno = EIO;
         return -1;
@@ -308,7 +347,6 @@
     return (int)result;
 }
 
-
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/
@@ -424,22 +462,18 @@
     return _fh_to_int(f);
 }
 
-
-int  adb_read(int  fd, void* buf, int len)
-{
-    FH     f = _fh_from_int(fd, __func__);
+int adb_read(int fd, void* buf, int len) {
+    FH f = _fh_from_int(fd, __func__);
 
     if (f == NULL) {
         return -1;
     }
 
-    return f->clazz->_fh_read( f, buf, len );
+    return f->clazz->_fh_read(f, buf, len);
 }
 
-
-int  adb_write(int  fd, const void*  buf, int  len)
-{
-    FH     f = _fh_from_int(fd, __func__);
+int adb_write(int fd, const void* buf, int len) {
+    FH f = _fh_from_int(fd, __func__);
 
     if (f == NULL) {
         return -1;
@@ -448,6 +482,16 @@
     return f->clazz->_fh_write(f, buf, len);
 }
 
+ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt) {
+    FH f = _fh_from_int(fd, __func__);
+
+    if (f == NULL) {
+        errno = EBADF;
+        return -1;
+    }
+
+    return f->clazz->_fh_writev(f, iov, iovcnt);
+}
 
 int  adb_lseek(int  fd, int  pos, int  where)
 {
@@ -582,7 +626,7 @@
     f->fh_socket = INVALID_SOCKET;
 }
 
-static int _fh_socket_close( FH  f ) {
+static int _fh_socket_close(FH f) {
     if (f->fh_socket != INVALID_SOCKET) {
         /* gently tell any peer that we're closing the socket */
         if (shutdown(f->fh_socket, SD_BOTH) == SOCKET_ERROR) {
@@ -603,13 +647,13 @@
     return 0;
 }
 
-static int _fh_socket_lseek( FH  f, int pos, int origin ) {
+static int _fh_socket_lseek(FH f, int pos, int origin) {
     errno = EPIPE;
     return -1;
 }
 
 static int _fh_socket_read(FH f, void* buf, int len) {
-    int  result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
+    int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
         // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -621,11 +665,11 @@
         _socket_set_errno(err);
         result = -1;
     }
-    return  result;
+    return result;
 }
 
 static int _fh_socket_write(FH f, const void* buf, int len) {
-    int  result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
+    int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
         // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
@@ -639,13 +683,44 @@
     } else {
         // According to https://code.google.com/p/chromium/issues/detail?id=27870
         // Winsock Layered Service Providers may cause this.
-        CHECK_LE(result, len) << "Tried to write " << len << " bytes to "
-                              << f->name << ", but " << result
-                              << " bytes reportedly written";
+        CHECK_LE(result, len) << "Tried to write " << len << " bytes to " << f->name << ", but "
+                              << result << " bytes reportedly written";
     }
     return result;
 }
 
+// Make sure that adb_iovec is compatible with WSABUF.
+static_assert(sizeof(adb_iovec) == sizeof(WSABUF), "");
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_len) == SIZEOF_MEMBER(WSABUF, len), "");
+static_assert(offsetof(adb_iovec, iov_len) == offsetof(WSABUF, len), "");
+
+static_assert(SIZEOF_MEMBER(adb_iovec, iov_base) == SIZEOF_MEMBER(WSABUF, buf), "");
+static_assert(offsetof(adb_iovec, iov_base) == offsetof(WSABUF, buf), "");
+
+static int _fh_socket_writev(FH f, const adb_iovec* iov, int iovcnt) {
+    if (iovcnt <= 0) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    WSABUF* wsabuf = reinterpret_cast<WSABUF*>(const_cast<adb_iovec*>(iov));
+    DWORD bytes_written = 0;
+    int result = WSASend(f->fh_socket, wsabuf, iovcnt, &bytes_written, 0, nullptr, nullptr);
+    if (result == SOCKET_ERROR) {
+        const DWORD err = WSAGetLastError();
+        // WSAEWOULDBLOCK is normal with a non-blocking socket, so don't trace
+        // that to reduce spam and confusion.
+        if (err != WSAEWOULDBLOCK) {
+            D("send fd %d failed: %s", _fh_to_int(f),
+              android::base::SystemErrorCodeToString(err).c_str());
+        }
+        _socket_set_errno(err);
+        result = -1;
+    }
+    CHECK_GE(static_cast<DWORD>(std::numeric_limits<int>::max()), bytes_written);
+    return static_cast<int>(bytes_written);
+}
+
 /**************************************************************************/
 /**************************************************************************/
 /*****                                                                *****/