Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 116aa0a4 authored by Josh Gao's avatar Josh Gao
Browse files

adb: implement adb_writev.

Change-Id: I55258c155d7b07368ebb45577b2e01ca804cf258
Test: adb_test
Test: python test_device.py
parent 1ce99576
Loading
Loading
Loading
Loading

adb/sysdeps/uio.h

0 → 100644
+39 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <sys/types.h>

#if defined(_WIN32)

// Layout of this struct must match struct WSABUF (verified via static assert in sysdeps_win32.cpp)
struct adb_iovec {
    size_t iov_len;
    void* iov_base;
};

ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt);

#else

#include <sys/uio.h>
using adb_iovec = struct iovec;
#define adb_writev writev

#endif

#pragma GCC poison writev
+115 −40
Original line number Diff line number Diff line
@@ -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 @@ typedef struct FHClassRec_ {
    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_close(FH);
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 @@ static const FHClassRec _fh_file_class = {
    _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_close(FH);
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 @@ static const FHClassRec _fh_socket_class = {
    _fh_socket_lseek,
    _fh_socket_read,
    _fh_socket_write,
    _fh_socket_writev,
};

#define assert(cond)                                                                       \
@@ -268,7 +276,7 @@ static int _fh_file_read( FH f, void* buf, int len ) {
    } 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) {
@@ -281,18 +289,49 @@ static int _fh_file_write( FH f, const void* buf, int len ) {
    } else if (wrote_bytes < (DWORD)len) {
        f->eof = 1;
    }
    return  (int)wrote_bytes;
    return wrote_bytes;
}

static int _fh_file_writev(FH f, const adb_iovec* iov, int iovcnt) {
    if (iovcnt <= 0) {
        errno = EINVAL;
        return -1;
    }

    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;
    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;
@@ -308,7 +347,6 @@ static int _fh_file_lseek( FH f, int pos, int origin ) {
    return (int)result;
}


/**************************************************************************/
/**************************************************************************/
/*****                                                                *****/
@@ -424,9 +462,7 @@ int adb_creat(const char* path, int mode)
    return _fh_to_int(f);
}


int  adb_read(int  fd, void* buf, int len)
{
int adb_read(int fd, void* buf, int len) {
    FH f = _fh_from_int(fd, __func__);

    if (f == NULL) {
@@ -436,9 +472,7 @@ int adb_read(int fd, void* buf, int len)
    return f->clazz->_fh_read(f, buf, len);
}


int  adb_write(int  fd, const void*  buf, int  len)
{
int adb_write(int fd, const void* buf, int len) {
    FH f = _fh_from_int(fd, __func__);

    if (f == NULL) {
@@ -448,6 +482,16 @@ int adb_write(int fd, const void* buf, int len)
    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)
{
@@ -639,13 +683,44 @@ static int _fh_socket_write(FH f, const void* buf, int len) {
    } 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);
}

/**************************************************************************/
/**************************************************************************/
/*****                                                                *****/