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.