Write until we fall over.

Implement enh's idea about repeating write() until it fails.  Use it
in the zip expander and dexopt, which have an above-average chance of
failing due to lack of disk space.

Replace a stray DEFAULT_PAGE_SIZE with SYSTEM_PAGE_SIZE.  Apparently I
missed that during the Great Page Size Unification.

Change-Id: Id173cb7669330deebe2f24ae23ece4009a90e3bd
diff --git a/libdex/SysUtil.c b/libdex/SysUtil.c
index bcba489..ca64c25 100644
--- a/libdex/SysUtil.c
+++ b/libdex/SysUtil.c
@@ -24,20 +24,13 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
-
 #ifdef HAVE_POSIX_FILEMAP
-#include <sys/mman.h>
+# include <sys/mman.h>
 #endif
-
 #include <limits.h>
 #include <errno.h>
 
-/*
- * Having trouble finding a portable way to get this.  sysconf(_SC_PAGE_SIZE)
- * seems appropriate, but we don't have that on the device.  Some systems
- * have getpagesize(2), though the linux man page has some odd cautions.
- */
-#define DEFAULT_PAGE_SIZE   4096
+#include <JNIHelp.h>        // TEMP_FAILURE_RETRY may or may not be in unistd
 
 
 /*
@@ -284,7 +277,7 @@
     assert(pMap != NULL);
 
     /* adjust to be page-aligned */
-    adjust = start % DEFAULT_PAGE_SIZE;
+    adjust = start % SYSTEM_PAGE_SIZE;
     actualStart = start - adjust;
     actualLength = length + adjust;
 
@@ -390,3 +383,27 @@
     memcpy(dst, src, sizeof(MemMapping));
 }
 
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg)
+{
+    while (count != 0) {
+        ssize_t actual = TEMP_FAILURE_RETRY(write(fd, buf, count));
+        if (actual < 0) {
+            int err = errno;
+            LOGE("%s: write failed: %s\n", logMsg, strerror(err));
+            return err;
+        } else if (actual != (ssize_t) count) {
+            LOGD("%s: partial write (will retry): (%d of %zd)\n",
+                logMsg, (int) actual, count);
+            buf = (const void*) (((const u1*) buf) + actual);
+        }
+        count -= actual;
+    }
+
+    return 0;
+}
+
diff --git a/libdex/SysUtil.h b/libdex/SysUtil.h
index 95e5be2..01b4e1a 100644
--- a/libdex/SysUtil.h
+++ b/libdex/SysUtil.h
@@ -106,4 +106,11 @@
  */
 void sysReleaseShmem(MemMapping* pMap);
 
+/*
+ * Write until all bytes have been written.
+ *
+ * Returns 0 on success, or an errno value on failure.
+ */
+int sysWriteFully(int fd, const void* buf, size_t count, const char* logMsg);
+
 #endif /*_DALVIK_SYSUTIL*/
diff --git a/libdex/ZipArchive.c b/libdex/ZipArchive.c
index c935f11..65bc6e9 100644
--- a/libdex/ZipArchive.c
+++ b/libdex/ZipArchive.c
@@ -648,17 +648,8 @@
             (zerr == Z_STREAM_END && zstream.avail_out != kBufSize))
         {
             size_t writeSize = zstream.next_out - writeBuf;
-            ssize_t actual =
-                TEMP_FAILURE_RETRY(write(outFd, writeBuf, writeSize));
-            if (actual != (ssize_t) writeSize) {
-                if (actual < 0) {
-                    LOGW("Zip: write failed in inflate: %s\n", strerror(errno));
-                } else {
-                    LOGW("Zip: partial write in inflate (%d vs %zd)\n",
-                        (int) actual, writeSize);
-                }
+            if (sysWriteFully(outFd, writeBuf, writeSize, "Zip inflate") != 0)
                 goto z_bail;
-            }
 
             zstream.next_out = writeBuf;
             zstream.avail_out = kBufSize;
@@ -702,13 +693,8 @@
             return -1;
         }
 
-        actual = TEMP_FAILURE_RETRY(write(outFd, buf, getSize));
-        if (actual != (ssize_t) getSize) {
-            /* could be disk out of space, so show errno in message */
-            LOGW("Zip: copy write failed (%d vs %zd): %s\n",
-                (int) actual, getSize, strerror(errno));
+        if (sysWriteFully(outFd, buf, getSize, "Zip copy") != 0)
             return -1;
-        }
 
         uncompLen -= getSize;
     }
diff --git a/vm/analysis/DexPrepare.c b/vm/analysis/DexPrepare.c
index 309e5f7..5756cd0 100644
--- a/vm/analysis/DexPrepare.c
+++ b/vm/analysis/DexPrepare.c
@@ -53,8 +53,6 @@
 static int writeDependencies(int fd, u4 modWhen, u4 crc);
 static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
     const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
-static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
-    int err);
 static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
 
 
@@ -671,11 +669,8 @@
 
     ssize_t actual;
     lseek(fd, 0, SEEK_SET);
-    actual = write(fd, &optHdr, sizeof(optHdr));
-    if (actual != sizeof(optHdr)) {
-        logFailedWrite(sizeof(optHdr), actual, "opt header", errno);
+    if (sysWriteFully(fd, &optHdr, sizeof(optHdr), "DexOpt opt header") != 0)
         goto bail;
-    }
 
     LOGV("Successfully wrote DEX header\n");
     result = true;
@@ -1297,13 +1292,7 @@
 
     assert(ptr == buf + bufLen);
 
-    actual = write(fd, buf, bufLen);
-    if (actual != bufLen) {
-        result = (errno != 0) ? errno : -1;
-        logFailedWrite(bufLen, actual, "dep info", errno);
-    } else {
-        result = 0;
-    }
+    result = sysWriteFully(fd, buf, bufLen, "DexOpt dep info");
 
     free(buf);
     return result;
@@ -1333,18 +1322,15 @@
 
     header.ts.type = type;
     header.ts.size = (u4) size;
-    actual = write(fd, &header, sizeof(header));
-    if (actual != sizeof(header)) {
-        logFailedWrite(size, actual, "aux chunk header write", errno);
+    if (sysWriteFully(fd, &header, sizeof(header),
+            "DexOpt aux chunk header write") != 0)
+    {
         return false;
     }
 
     if (size > 0) {
-        actual = write(fd, data, size);
-        if (actual != (ssize_t) size) {
-            logFailedWrite(size, actual, "aux chunk write", errno);
+        if (sysWriteFully(fd, data, size, "DexOpt aux chunk write") != 0)
             return false;
-        }
     }
 
     /* if necessary, pad to 64-bit alignment */
@@ -1404,16 +1390,6 @@
 }
 
 /*
- * Log a failed write.
- */
-static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
-    int err)
-{
-    LOGE("Write failed: %s (%d of %d): %s\n",
-        msg, (int)actual, (int)expected, strerror(err));
-}
-
-/*
  * Compute a checksum on a piece of an open file.
  *
  * File will be positioned at end of checksummed area.