fastboot: Cap max size sent to libsparse

This is required for large (>INT_MAX) sparse limit reported by
the target.

Also, patch up return chains of "int" that need to deal with sizes
bigger than 2GB as well as return negative error codes.

Test: -S works with large max-download-size
Test: Flash 3GB system.img with max-download-size 2.5GB

Bug: 36810152
Change-Id: I562a50eabd706bd5b97c71a1aef07c1ffd1a2e5c
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 728dcb8..9f7d226 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -328,11 +328,11 @@
     queue_action(OP_WAIT_FOR_DISCONNECT, "");
 }
 
-int fb_execute_queue(Transport* transport)
+int64_t fb_execute_queue(Transport* transport)
 {
     Action *a;
     char resp[FB_RESPONSE_SZ+1];
-    int status = 0;
+    int64_t status = 0;
 
     a = action_list;
     if (!a)
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 704dc43..cb8e5c0 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -78,6 +78,10 @@
 static const char* cmdline = nullptr;
 static unsigned short vendor_id = 0;
 static int long_listing = 0;
+// Don't resparse files in too-big chunks.
+// libsparse will support INT_MAX, but this results in large allocations, so
+// let's keep it at 1GB to avoid memory pressure on the host.
+static constexpr int64_t RESPARSE_LIMIT = 1 * 1024 * 1024 * 1024;
 static int64_t sparse_limit = -1;
 static int64_t target_sparse_limit = -1;
 
@@ -789,7 +793,7 @@
     }
 
     if (size > limit) {
-        return limit;
+        return std::min(limit, RESPARSE_LIMIT);
     }
 
     return 0;
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 6699b6a..b62a2d8 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -41,7 +41,7 @@
 /* protocol.c - fastboot protocol */
 int fb_command(Transport* transport, const char* cmd);
 int fb_command_response(Transport* transport, const char* cmd, char* response);
-int fb_download_data(Transport* transport, const void* data, uint32_t size);
+int64_t fb_download_data(Transport* transport, const void* data, uint32_t size);
 int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
 const std::string fb_get_error();
 
@@ -64,7 +64,7 @@
 void fb_queue_download(const char *name, void *data, uint32_t size);
 void fb_queue_notice(const char *notice);
 void fb_queue_wait_for_disconnect(void);
-int fb_execute_queue(Transport* transport);
+int64_t fb_execute_queue(Transport* transport);
 void fb_set_active(const char *slot);
 
 /* util stuff */
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index bfa83b0..bf0479e 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -48,7 +48,7 @@
     return g_error;
 }
 
-static int check_response(Transport* transport, uint32_t size, char* response) {
+static int64_t check_response(Transport* transport, uint32_t size, char* response) {
     char status[65];
 
     while (true) {
@@ -105,7 +105,7 @@
     return -1;
 }
 
-static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
+static int64_t _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
     size_t cmdsize = strlen(cmd);
     if (cmdsize > 64) {
         g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
@@ -125,14 +125,14 @@
     return check_response(transport, size, response);
 }
 
-static int _command_data(Transport* transport, const void* data, uint32_t size) {
-    int r = transport->Write(data, size);
+static int64_t _command_data(Transport* transport, const void* data, uint32_t size) {
+    int64_t r = transport->Write(data, size);
     if (r < 0) {
         g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
         transport->Close();
         return -1;
     }
-    if (r != ((int) size)) {
+    if (r != static_cast<int64_t>(size)) {
         g_error = "data transfer failure (short transfer)";
         transport->Close();
         return -1;
@@ -140,17 +140,17 @@
     return r;
 }
 
-static int _command_end(Transport* transport) {
+static int64_t _command_end(Transport* transport) {
     return check_response(transport, 0, 0) < 0 ? -1 : 0;
 }
 
-static int _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
+static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size,
                          char* response) {
     if (size == 0) {
         return -1;
     }
 
-    int r = _command_start(transport, cmd, size, response);
+    int64_t r = _command_start(transport, cmd, size, response);
     if (r < 0) {
         return -1;
     }
@@ -180,7 +180,7 @@
     return _command_send_no_data(transport, cmd, response);
 }
 
-int fb_download_data(Transport* transport, const void* data, uint32_t size) {
+int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) {
     char cmd[64];
     snprintf(cmd, sizeof(cmd), "download:%08x", size);
     return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0;
@@ -242,7 +242,8 @@
 
 static int fb_download_data_sparse_flush(Transport* transport) {
     if (transport_buf_len > 0) {
-        if (_command_data(transport, transport_buf, transport_buf_len) != transport_buf_len) {
+        int64_t r = _command_data(transport, transport_buf, transport_buf_len);
+        if (r != static_cast<int64_t>(transport_buf_len)) {
             return -1;
         }
         transport_buf_len = 0;