Merge "crash_reporter: Run with supplemental groups"
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index e1e21ed..b92757f 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -276,10 +276,7 @@
     count--;
     while (count > 0) {
         int len = adb_read(fd, buf, count);
-        if (len == 0) {
-            break;
-        } else if (len < 0) {
-            if (errno == EINTR) continue;
+        if (len <= 0) {
             break;
         }
 
@@ -332,11 +329,7 @@
             break;
         }
         if (len < 0) {
-            if (errno == EINTR) {
-                D("copy_to_file() : EINTR, retrying\n");
-                continue;
-            }
-            D("copy_to_file() : error %d\n", errno);
+            D("copy_to_file(): read failed: %s\n", strerror(errno));
             break;
         }
         if (outFd == STDOUT_FILENO) {
@@ -386,12 +379,8 @@
         D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
         r = unix_read(fdi, buf, 1024);
         D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
-        if(r == 0) break;
-        if(r < 0) {
-            if(errno == EINTR) continue;
-            break;
-        }
-        for(n = 0; n < r; n++){
+        if (r <= 0) break;
+        for (n = 0; n < r; n++){
             switch(buf[n]) {
             case '\n':
                 state = 1;
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index e722d66..d25bbfb 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -205,8 +205,8 @@
 
     n = epoll_wait(epoll_fd, events, 256, -1);
 
-    if(n < 0) {
-        if(errno == EINTR) return;
+    if (n < 0) {
+        if (errno == EINTR) return;
         perror("epoll_wait");
         exit(1);
     }
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index ab11619..e70d550 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -203,13 +203,8 @@
     sbuf->id = ID_DATA;
     while (true) {
         int ret = adb_read(lfd, sbuf->data, sc.max);
-        if (!ret)
-            break;
-
-        if (ret < 0) {
-            if(errno == EINTR)
-                continue;
-            fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
+        if (ret <= 0) {
+            if (ret < 0) fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
             break;
         }
 
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 3e46447..6ca8ba1 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -128,101 +128,92 @@
     return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
 }
 
-static bool fail_message(int s, const std::string& reason) {
+static bool SendSyncFail(int fd, const std::string& reason) {
     D("sync: failure: %s\n", reason.c_str());
 
     syncmsg msg;
     msg.data.id = ID_FAIL;
     msg.data.size = reason.size();
-    return WriteFdExactly(s, &msg.data, sizeof(msg.data)) && WriteFdExactly(s, reason);
+    return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason);
 }
 
-// TODO: callers of this have already failed, and should probably ignore its
-// return value (http://b/23437039).
-static bool fail_errno(int s) {
-    return fail_message(s, strerror(errno));
+static bool SendSyncFailErrno(int fd, const std::string& reason) {
+    return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
 }
 
-static bool handle_send_file(int s, char *path, uid_t uid,
+static bool handle_send_file(int s, const char* path, uid_t uid,
                              gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {
     syncmsg msg;
     unsigned int timestamp = 0;
 
     int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
-    if(fd < 0 && errno == ENOENT) {
+    if (fd < 0 && errno == ENOENT) {
         if (!secure_mkdirs(path)) {
-            if (fail_errno(s)) return false;
-            fd = -1;
-        } else {
-            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+            SendSyncFailErrno(s, "secure_mkdirs failed");
+            goto fail;
         }
+        fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
     }
-    if(fd < 0 && errno == EEXIST) {
+    if (fd < 0 && errno == EEXIST) {
         fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
     }
-    if(fd < 0) {
-        if (fail_errno(s)) return false;
-        fd = -1;
+    if (fd < 0) {
+        SendSyncFailErrno(s, "couldn't create file");
+        goto fail;
     } else {
-        if(fchown(fd, uid, gid) != 0) {
-            fail_errno(s);
-            errno = 0;
+        if (fchown(fd, uid, gid) == -1) {
+            SendSyncFailErrno(s, "fchown failed");
+            goto fail;
         }
 
-        /*
-         * fchown clears the setuid bit - restore it if present.
-         * Ignore the result of calling fchmod. It's not supported
-         * by all filesystems. b/12441485
-         */
+        if (selinux_android_restorecon(path, 0) == -1) {
+            SendSyncFailErrno(s, "selinux_android_restorecon failed");
+            goto fail;
+        }
+
+        // fchown clears the setuid bit - restore it if present.
+        // Ignore the result of calling fchmod. It's not supported
+        // by all filesystems. b/12441485
         fchmod(fd, mode);
     }
 
     while (true) {
         unsigned int len;
 
-        if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
-            goto fail;
+        if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
 
-        if(msg.data.id != ID_DATA) {
-            if(msg.data.id == ID_DONE) {
+        if (msg.data.id != ID_DATA) {
+            if (msg.data.id == ID_DONE) {
                 timestamp = msg.data.size;
                 break;
             }
-            fail_message(s, "invalid data message");
+            SendSyncFail(s, "invalid data message");
             goto fail;
         }
         len = msg.data.size;
         if (len > buffer.size()) { // TODO: resize buffer?
-            fail_message(s, "oversize data message");
+            SendSyncFail(s, "oversize data message");
             goto fail;
         }
+
         if (!ReadFdExactly(s, &buffer[0], len)) goto fail;
 
-        if (fd < 0) continue;
-
         if (!WriteFdExactly(fd, &buffer[0], len)) {
-            int saved_errno = errno;
-            adb_close(fd);
-            if (do_unlink) adb_unlink(path);
-            fd = -1;
-            errno = saved_errno;
-            if (fail_errno(s)) return false;
+            SendSyncFailErrno(s, "write failed");
+            goto fail;
         }
     }
 
-    if(fd >= 0) {
-        struct utimbuf u;
-        adb_close(fd);
-        selinux_android_restorecon(path, 0);
-        u.actime = timestamp;
-        u.modtime = timestamp;
-        utime(path, &u);
+    adb_close(fd);
 
-        msg.status.id = ID_OKAY;
-        msg.status.msglen = 0;
-        if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
-    }
-    return true;
+    utimbuf u;
+    u.actime = timestamp;
+    u.modtime = timestamp;
+    utime(path, &u);
+
+    msg.status.id = ID_OKAY;
+    msg.status.msglen = 0;
+    return WriteFdExactly(s, &msg.status, sizeof(msg.status));
 
 fail:
     if (fd >= 0) adb_close(fd);
@@ -231,9 +222,9 @@
 }
 
 #if defined(_WIN32)
-extern bool handle_send_link(int s, char *path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
+extern bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
 #else
-static bool handle_send_link(int s, char *path, std::vector<char>& buffer) {
+static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
     syncmsg msg;
     unsigned int len;
     int ret;
@@ -241,27 +232,27 @@
     if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
 
     if (msg.data.id != ID_DATA) {
-        fail_message(s, "invalid data message: expected ID_DATA");
+        SendSyncFail(s, "invalid data message: expected ID_DATA");
         return false;
     }
 
     len = msg.data.size;
     if (len > buffer.size()) { // TODO: resize buffer?
-        fail_message(s, "oversize data message");
+        SendSyncFail(s, "oversize data message");
         return false;
     }
     if (!ReadFdExactly(s, &buffer[0], len)) return false;
 
-    ret = symlink(&buffer[0], path);
+    ret = symlink(&buffer[0], path.c_str());
     if (ret && errno == ENOENT) {
         if (!secure_mkdirs(path)) {
-            fail_errno(s);
+            SendSyncFailErrno(s, "secure_mkdirs failed");
             return false;
         }
-        ret = symlink(&buffer[0], path);
+        ret = symlink(&buffer[0], path.c_str());
     }
     if (ret) {
-        fail_errno(s);
+        SendSyncFailErrno(s, "symlink failed");
         return false;
     }
 
@@ -272,7 +263,7 @@
         msg.status.msglen = 0;
         if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
     } else {
-        fail_message(s, "invalid data message: expected ID_DONE");
+        SendFail(s, "invalid data message: expected ID_DONE");
         return false;
     }
 
@@ -280,59 +271,55 @@
 }
 #endif
 
-static bool do_send(int s, char* path, std::vector<char>& buffer) {
-    unsigned int mode;
-    bool is_link = false;
-    bool do_unlink;
-
-    char* tmp = strrchr(path,',');
-    if(tmp) {
-        *tmp = 0;
-        errno = 0;
-        mode = strtoul(tmp + 1, NULL, 0);
-        is_link = S_ISLNK((mode_t) mode);
-        mode &= 0777;
-    }
-    if(!tmp || errno) {
-        mode = 0644;
-        is_link = 0;
-        do_unlink = true;
-    } else {
-        struct stat st;
-        /* Don't delete files before copying if they are not "regular" */
-        do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
-        if (do_unlink) {
-            adb_unlink(path);
-        }
+static bool do_send(int s, const std::string& spec, std::vector<char>& buffer) {
+    // 'spec' is of the form "/some/path,0755". Break it up.
+    size_t comma = spec.find_last_of(',');
+    if (comma == std::string::npos) {
+        SendFail(s, "missing , in ID_SEND");
+        return false;
     }
 
-    if (is_link) {
-        return handle_send_link(s, path, buffer);
+    std::string path = spec.substr(0, comma);
+
+    errno = 0;
+    mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0);
+    if (errno != 0) {
+        SendFail(s, "bad mode");
+        return false;
     }
 
+    // Don't delete files before copying if they are not "regular" or symlinks.
+    struct stat st;
+    bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+    if (do_unlink) {
+        adb_unlink(path.c_str());
+    }
+
+    if (S_ISLNK(mode)) {
+        return handle_send_link(s, path.c_str(), buffer);
+    }
+
+    // Copy user permission bits to "group" and "other" permissions.
+    mode &= 0777;
+    mode |= ((mode >> 3) & 0070);
+    mode |= ((mode >> 3) & 0007);
+
     uid_t uid = -1;
     gid_t gid = -1;
     uint64_t cap = 0;
-
-    /* copy user permission bits to "group" and "other" permissions */
-    mode |= ((mode >> 3) & 0070);
-    mode |= ((mode >> 3) & 0007);
-
-    tmp = path;
-    if(*tmp == '/') {
-        tmp++;
-    }
     if (should_use_fs_config(path)) {
-        fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+        unsigned int broken_api_hack = mode;
+        fs_config(path.c_str(), 0, &uid, &gid, &broken_api_hack, &cap);
+        mode = broken_api_hack;
     }
-    return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
+    return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink);
 }
 
 static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
     int fd = adb_open(path, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
-        if (fail_errno(s)) return false;
-        return true;
+        SendSyncFailErrno(s, "open failed");
+        return false;
     }
 
     syncmsg msg;
@@ -341,10 +328,9 @@
         int r = adb_read(fd, &buffer[0], buffer.size());
         if (r <= 0) {
             if (r == 0) break;
-            if (errno == EINTR) continue;
-            bool status = fail_errno(s);
+            SendSyncFailErrno(s, "read failed");
             adb_close(fd);
-            return status;
+            return false;
         }
         msg.data.size = r;
         if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
@@ -365,17 +351,17 @@
 
     SyncRequest request;
     if (!ReadFdExactly(fd, &request, sizeof(request))) {
-        fail_message(fd, "command read failure");
+        SendSyncFail(fd, "command read failure");
         return false;
     }
     size_t path_length = request.path_length;
     if (path_length > 1024) {
-        fail_message(fd, "path too long");
+        SendSyncFail(fd, "path too long");
         return false;
     }
     char name[1025];
     if (!ReadFdExactly(fd, name, path_length)) {
-        fail_message(fd, "filename read failure");
+        SendSyncFail(fd, "filename read failure");
         return false;
     }
     name[path_length] = 0;
@@ -399,7 +385,7 @@
       case ID_QUIT:
         return false;
       default:
-        fail_message(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
+        SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
                                                      id, request.id));
         return false;
     }
diff --git a/adb/transport.cpp b/adb/transport.cpp
index ea673f2..afdab86 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -140,8 +140,7 @@
             len -= r;
             p += r;
         } else {
-            D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
-            if((r < 0) && (errno == EINTR)) continue;
+            D("%s: read_packet (fd=%d), error ret=%d: %s\n", name, fd, r, strerror(errno));
             return -1;
         }
     }
@@ -171,8 +170,7 @@
             len -= r;
             p += r;
         } else {
-            D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
-            if((r < 0) && (errno == EINTR)) continue;
+            D("%s: write_packet (fd=%d) error ret=%d: %s\n", name, fd, r, strerror(errno));
             return -1;
         }
     }
@@ -489,9 +487,7 @@
             len -= r;
             p   += r;
         } else {
-            if((r < 0) && (errno == EINTR)) continue;
-            D("transport_read_action: on fd %d, error %d: %s\n",
-              fd, errno, strerror(errno));
+            D("transport_read_action: on fd %d: %s\n", fd, strerror(errno));
             return -1;
         }
     }
@@ -511,9 +507,7 @@
             len -= r;
             p   += r;
         } else {
-            if((r < 0) && (errno == EINTR)) continue;
-            D("transport_write_action: on fd %d, error %d: %s\n",
-              fd, errno, strerror(errno));
+            D("transport_write_action: on fd %d: %s\n", fd, strerror(errno));
             return -1;
         }
     }
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c6ad00d..dc44f16 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -431,17 +431,12 @@
 static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
 {
     size_t count = 0;
-    int ret;
 
-    do {
-        ret = adb_write(bulk_in, buf + count, length - count);
-        if (ret < 0) {
-            if (errno != EINTR)
-                return ret;
-        } else {
-            count += ret;
-        }
-    } while (count < length);
+    while (count < length) {
+        int ret = adb_write(bulk_in, buf + count, length - count);
+        if (ret < 0) return -1;
+        count += ret;
+    }
 
     D("[ bulk_write done fd=%d ]\n", bulk_in);
     return count;
@@ -462,20 +457,15 @@
 static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
 {
     size_t count = 0;
-    int ret;
 
-    do {
-        ret = adb_read(bulk_out, buf + count, length - count);
+    while (count < length) {
+        int ret = adb_read(bulk_out, buf + count, length - count);
         if (ret < 0) {
-            if (errno != EINTR) {
-                D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n",
-                                           bulk_out, length, count);
-                return ret;
-            }
-        } else {
-            count += ret;
+            D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n", bulk_out, length, count);
+            return -1;
         }
-    } while (count < length);
+        count += ret;
+    }
 
     return count;
 }