Revert "Revert "adb: extend sync protocol's stat support.""

This reverts commit afa4b5d6eb45bbee8671a1bb93ea70506fb326e3.

Add functions to translate errno to and from the linux asm-generic
values, since mips has different values.

Bug: http://b/33058958
Test: python test_device.py with both old and new adbd
Change-Id: I1a122235f3e793ed10b3bf3ad293388015134150
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 7a92d2e..43c877e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -41,6 +41,7 @@
 #include "adb_io.h"
 #include "adb_utils.h"
 #include "security_log_tags.h"
+#include "sysdeps/errno.h"
 
 static bool should_use_fs_config(const std::string& path) {
     // TODO: use fs_config to configure permissions on /data.
@@ -98,18 +99,47 @@
     return true;
 }
 
-static bool do_stat(int s, const char* path) {
-    syncmsg msg;
-    msg.stat.id = ID_STAT;
+static bool do_lstat_v1(int s, const char* path) {
+    syncmsg msg = {};
+    msg.stat_v1.id = ID_LSTAT_V1;
 
     struct stat st = {};
-    // TODO: add a way to report that the stat failed!
     lstat(path, &st);
-    msg.stat.mode = st.st_mode;
-    msg.stat.size = st.st_size;
-    msg.stat.time = st.st_mtime;
+    msg.stat_v1.mode = st.st_mode;
+    msg.stat_v1.size = st.st_size;
+    msg.stat_v1.time = st.st_mtime;
+    return WriteFdExactly(s, &msg.stat_v1, sizeof(msg.stat_v1));
+}
 
-    return WriteFdExactly(s, &msg.stat, sizeof(msg.stat));
+static bool do_stat_v2(int s, uint32_t id, const char* path) {
+    syncmsg msg = {};
+    msg.stat_v2.id = id;
+
+    decltype(&stat) stat_fn;
+    if (id == ID_STAT_V2) {
+        stat_fn = stat;
+    } else {
+        stat_fn = lstat;
+    }
+
+    struct stat st = {};
+    int rc = stat_fn(path, &st);
+    if (rc == -1) {
+        msg.stat_v2.error = errno_to_wire(errno);
+    } else {
+        msg.stat_v2.dev = st.st_dev;
+        msg.stat_v2.ino = st.st_ino;
+        msg.stat_v2.mode = st.st_mode;
+        msg.stat_v2.nlink = st.st_nlink;
+        msg.stat_v2.uid = st.st_uid;
+        msg.stat_v2.gid = st.st_gid;
+        msg.stat_v2.size = st.st_size;
+        msg.stat_v2.atime = st.st_atime;
+        msg.stat_v2.mtime = st.st_mtime;
+        msg.stat_v2.ctime = st.st_ctime;
+    }
+
+    return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2));
 }
 
 static bool do_list(int s, const char* path) {
@@ -427,30 +457,34 @@
     D("sync: '%.4s' '%s'", id, name);
 
     switch (request.id) {
-      case ID_STAT:
-        if (!do_stat(fd, name)) return false;
-        break;
-      case ID_LIST:
-        if (!do_list(fd, name)) return false;
-        break;
-      case ID_SEND:
-        if (!do_send(fd, name, buffer)) return false;
-        break;
-      case ID_RECV:
-        if (!do_recv(fd, name, buffer)) return false;
-        break;
-      case ID_QUIT:
-        return false;
-      default:
-        SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
-                                                     id, request.id));
-        return false;
+        case ID_LSTAT_V1:
+            if (!do_lstat_v1(fd, name)) return false;
+            break;
+        case ID_LSTAT_V2:
+        case ID_STAT_V2:
+            if (!do_stat_v2(fd, request.id, name)) return false;
+            break;
+        case ID_LIST:
+            if (!do_list(fd, name)) return false;
+            break;
+        case ID_SEND:
+            if (!do_send(fd, name, buffer)) return false;
+            break;
+        case ID_RECV:
+            if (!do_recv(fd, name, buffer)) return false;
+            break;
+        case ID_QUIT:
+            return false;
+        default:
+            SendSyncFail(
+                fd, android::base::StringPrintf("unknown command '%.4s' (%08x)", id, request.id));
+            return false;
     }
 
     return true;
 }
 
-void file_sync_service(int fd, void* cookie) {
+void file_sync_service(int fd, void*) {
     std::vector<char> buffer(SYNC_DATA_MAX);
 
     while (handle_sync_command(fd, buffer)) {