Merge "libion: Use %zu for size_t"
diff --git a/include/private/pixelflinger/ggl_context.h b/include/private/pixelflinger/ggl_context.h
index 4864d5a..17bb3ed 100644
--- a/include/private/pixelflinger/ggl_context.h
+++ b/include/private/pixelflinger/ggl_context.h
@@ -121,7 +121,7 @@
 template<> struct CTA<true> { };
 
 #define GGL_CONTEXT(con, c)         context_t *con = static_cast<context_t *>(c)
-#define GGL_OFFSETOF(field)         int(&(((context_t*)0)->field))
+#define GGL_OFFSETOF(field)         uintptr_t(&(((context_t*)0)->field))
 #define GGL_INIT_PROC(p, f)         p.f = ggl_ ## f;
 #define GGL_BETWEEN(x, L, H)        (uint32_t((x)-(L)) <= ((H)-(L)))
 
@@ -480,7 +480,7 @@
     uint32_t    width;
     uint32_t    height;
     uint32_t    stride;
-    int32_t     data;
+    uintptr_t   data;
     int32_t     dsdx;
     int32_t     dtdx;
     int32_t     spill[2];
diff --git a/libpixelflinger/buffer.cpp b/libpixelflinger/buffer.cpp
index af7356b..cbdab5a 100644
--- a/libpixelflinger/buffer.cpp
+++ b/libpixelflinger/buffer.cpp
@@ -93,7 +93,7 @@
         gen.width   = s.width;
         gen.height  = s.height;
         gen.stride  = s.stride;
-        gen.data    = int32_t(s.data);
+        gen.data    = uintptr_t(s.data);
     }
 }
 
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index 607ed3c..92243da 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -99,8 +99,8 @@
         if (comment >= 0) {
             printf("; %s\n", mComments.valueAt(comment));
         }
-        printf("%08x:    %08x    ", int(i), int(i[0]));
-        ::disassemble((u_int)i);
+        printf("%08x:    %08x    ", uintptr_t(i), int(i[0]));
+        ::disassemble((uintptr_t)i);
         i++;
     }
 }
@@ -186,7 +186,7 @@
 
 #if defined(WITH_LIB_HARDWARE)
     if (__builtin_expect(mQemuTracing, 0)) {
-        int err = qemu_add_mapping(int(base()), name);
+        int err = qemu_add_mapping(uintptr_t(base()), name);
         mQemuTracing = (err >= 0);
     }
 #endif
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index 9663a2b..96a71f3 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -1717,7 +1717,7 @@
             gen.width   = t.surface.width;
             gen.height  = t.surface.height;
             gen.stride  = t.surface.stride;
-            gen.data    = int32_t(t.surface.data);
+            gen.data    = uintptr_t(t.surface.data);
             gen.dsdx = ti.dsdx;
             gen.dtdx = ti.dtdx;
         }
@@ -2125,7 +2125,7 @@
     int sR, sG, sB;
     uint32_t s, d;
 
-    if (ct==1 || uint32_t(dst)&2) {
+    if (ct==1 || uintptr_t(dst)&2) {
 last_one:
         s = GGL_RGBA_TO_HOST( *src++ );
         *dst++ = convertAbgr8888ToRgb565(s);
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index 31c6051..5d836a1 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -26,6 +26,7 @@
 LOCAL_SRC_FILES := ${source_files}
 
 LOCAL_STATIC_LIBRARIES := libz
+LOCAL_SHARED_LIBRARIES := libutils
 LOCAL_MODULE:= libziparchive
 
 LOCAL_C_INCLUDES += ${includes}
@@ -37,7 +38,7 @@
 LOCAL_SRC_FILES := ${source_files}
 LOCAL_C_INCLUDES += ${includes}
 
-LOCAL_STATIC_LIBRARIES := libz
+LOCAL_STATIC_LIBRARIES := libz libutils
 LOCAL_MODULE:= libziparchive-host
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -49,5 +50,20 @@
     -DGTEST_HAS_STD_STRING
 LOCAL_SRC_FILES := zip_archive_test.cc
 LOCAL_LDFLAGS := -llog
-LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main
+LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main libutils
 include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ziparchive-tests-host
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS += \
+    -DGTEST_OS_LINUX \
+    -DGTEST_HAS_STD_STRING
+LOCAL_SRC_FILES := zip_archive_test.cc
+LOCAL_STATIC_LIBRARIES := libziparchive-host \
+	libz \
+	libgtest_host \
+	libgtest_main_host \
+	liblog \
+	libutils
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libziparchive/testdata/valid.zip b/libziparchive/testdata/valid.zip
new file mode 100644
index 0000000..9e7cb78
--- /dev/null
+++ b/libziparchive/testdata/valid.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 83b7c5b..dddff1f 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -28,8 +28,8 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/mman.h>
 #include <unistd.h>
+#include <utils/FileMap.h>
 
 #include <JNIHelp.h>  // TEMP_FAILURE_RETRY may or may not be in unistd
 
@@ -86,7 +86,7 @@
 
 static const char* kErrorMessages[] = {
   "Unknown return code.",
-  "I/O Error",
+  "Iteration ended",
   "Zlib error",
   "Invalid file",
   "Invalid handle",
@@ -96,13 +96,13 @@
   "Invalid offset",
   "Inconsistent information",
   "Invalid entry name",
-  "Iteration ended",
+  "I/O Error",
+  "File mapping failed"
 };
 
 static const int32_t kErrorMessageUpperBound = 0;
 
-// An I/O related system call (read, lseek, ftruncate, map) failed.
-static const int32_t kIoError = -1;
+static const int32_t kIterationEnd = -1;
 
 // We encountered a Zlib error when inflating a stream from this file.
 // Usually indicates file corruption.
@@ -138,24 +138,15 @@
 // An invalid entry name was encountered.
 static const int32_t kInvalidEntryName = -10;
 
-static const int32_t kIterationEnd = -12;
+// An I/O related system call (read, lseek, ftruncate, map) failed.
+static const int32_t kIoError = -11;
+
+// We were not able to mmap the central directory or entry contents.
+static const int32_t kMmapFailed = -12;
 
 static const int32_t kErrorMessageLowerBound = -13;
 
-
-#ifdef PAGE_SHIFT
-#define SYSTEM_PAGE_SIZE (1 << PAGE_SHIFT)
-#else
-#define SYSTEM_PAGE_SIZE 4096
-#endif
-
-struct MemMapping {
-  uint8_t* addr;  // Start of data
-  size_t length;  // Length of data
-
-  uint8_t* base_address;  // page-aligned base address
-  size_t base_length;  // length of mapping
-};
+static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
 
 /*
  * A Read-only Zip archive.
@@ -182,7 +173,7 @@
 
   /* mapped central directory area */
   off64_t directory_offset;
-  MemMapping directory_map;
+  android::FileMap* directory_map;
 
   /* number of entries in the Zip archive */
   uint16_t num_entries;
@@ -198,43 +189,17 @@
 };
 
 // Returns 0 on success and negative values on failure.
-static int32_t MapFileSegment(const int fd, const off64_t start, const size_t length,
-                              const int prot, const int flags, MemMapping *mapping) {
-  /* adjust to be page-aligned */
-  const int adjust = start % SYSTEM_PAGE_SIZE;
-  const off64_t actual_start = start - adjust;
-  const off64_t actual_length = length + adjust;
-
-  void* map_addr = mmap(NULL, actual_length, prot, flags, fd, actual_start);
-  if (map_addr == MAP_FAILED) {
-    ALOGW("mmap(%llx, R, FILE|SHARED, %d, %llx) failed: %s",
-      actual_length, fd, actual_start, strerror(errno));
-    return kIoError;
+static android::FileMap* MapFileSegment(const int fd, const off64_t start,
+                                        const size_t length, const bool read_only,
+                                        const char* debug_file_name) {
+  android::FileMap* file_map = new android::FileMap;
+  const bool success = file_map->create(debug_file_name, fd, start, length, read_only);
+  if (!success) {
+    file_map->release();
+    return NULL;
   }
 
-  mapping->base_address = (uint8_t*) map_addr;
-  mapping->base_length = actual_length;
-  mapping->addr = (uint8_t*) map_addr + adjust;
-  mapping->length = length;
-
-  ALOGV("mmap seg (st=%d ln=%d): b=%p bl=%d ad=%p ln=%d",
-      start, length, mapping->base_address, mapping->base_length,
-      mapping->addr, mapping->length);
-
-  return 0;
-}
-
-static void ReleaseMappedSegment(MemMapping* map) {
-  if (map->base_address == 0 || map->base_length == 0) {
-    return;
-  }
-
-  if (munmap(map->base_address, map->base_length) < 0) {
-    ALOGW("munmap(%p, %d) failed: %s",
-        map->base_address, map->base_length, strerror(errno));
-  } else {
-    ALOGV("munmap(%p, %d) succeeded", map->base_address, map->base_length);
-  }
+  return file_map;
 }
 
 static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
@@ -243,7 +208,7 @@
 
   uint32_t count = 0;
   uint64_t crc = 0;
-  while (count <= length) {
+  while (count < length) {
     uint32_t remaining = length - count;
 
     // Safe conversion because kBufSize is narrow enough for a 32 bit signed
@@ -430,13 +395,14 @@
    * It all looks good.  Create a mapping for the CD, and set the fields
    * in archive.
    */
-  const int32_t result = MapFileSegment(fd, dir_offset, dir_size,
-                                        PROT_READ, MAP_FILE | MAP_SHARED,
-                                        &(archive->directory_map));
-  if (result) {
-    return result;
+  android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size,
+                                         true /* read only */, debug_file_name);
+  if (map == NULL) {
+    archive->directory_map = NULL;
+    return kMmapFailed;
   }
 
+  archive->directory_map = map;
   archive->num_entries = num_entries;
   archive->directory_offset = dir_offset;
 
@@ -506,8 +472,8 @@
  */
 static int32_t ParseZipArchive(ZipArchive* archive) {
   int32_t result = -1;
-  const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map.addr;
-  size_t cd_length = archive->directory_map.length;
+  const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
+  size_t cd_length = archive->directory_map->getDataLength();
   uint16_t num_entries = archive->num_entries;
 
   /*
@@ -621,7 +587,9 @@
     close(archive->fd);
   }
 
-  ReleaseMappedSegment(&archive->directory_map);
+  if (archive->directory_map != NULL) {
+    archive->directory_map->release();
+  }
   free(archive->hash_table);
 
   /* ensure nobody tries to use the ZipArchive after it's closed */
@@ -668,7 +636,7 @@
   // is Windows. Only recent versions of windows support unix like forks,
   // and even there the semantics are quite different.
   if (lseek64(fd, off, SEEK_SET) != off) {
-    ALOGW("Zip: failed seek to offset %lld", name_offset);
+    ALOGW("Zip: failed seek to offset %lld", off);
     return kIoError;
   }
 
@@ -691,8 +659,8 @@
   // the name that's in the hash table is a pointer to a location within
   // this mapped region.
   const unsigned char* base_ptr = (const unsigned char*)
-    archive->directory_map.addr;
-  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.length) {
+    archive->directory_map->getDataPtr();
+  if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
     ALOGW("Zip: Invalid entry pointer");
     return kInvalidOffset;
   }
@@ -850,7 +818,7 @@
     archive->hash_table_size, entryName, nameLen);
 
   if (ent < 0) {
-    ALOGW("Zip: Could not find entry %.*s", nameLen, entryName);
+    ALOGD("Zip: Could not find entry %.*s", nameLen, entryName);
     return ent;
   }
 
@@ -1045,18 +1013,16 @@
     return kIoError;
   }
 
-  MemMapping mapping;
-  int32_t error = MapFileSegment(fd, 0, declared_length,
-                                 PROT_READ | PROT_WRITE,
-                                 MAP_FILE | MAP_SHARED,
-                                 &mapping);
-  if (error) {
-    return error;
+  android::FileMap* map  = MapFileSegment(fd, 0, declared_length,
+                                          false, kTempMappingFileName);
+  if (map == NULL) {
+    return kMmapFailed;
   }
 
-  error = ExtractToMemory(handle, entry, mapping.addr,
-                          mapping.length);
-  ReleaseMappedSegment(&mapping);
+  const int32_t error = ExtractToMemory(handle, entry,
+                                        reinterpret_cast<uint8_t*>(map->getDataPtr()),
+                                        map->getDataLength());
+  map->release();
   return error;
 }
 
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index ea2d827..55cb755 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -16,31 +16,157 @@
 
 #include "ziparchive/zip_archive.h"
 
+#include "getopt.h"
 #include <stdio.h>
 #include <gtest/gtest.h>
 
-TEST(ziparchive, open) {
-  // Ignore this test, it's just a simple test involving
-  // the framework jar.
-  ZipArchiveHandle handle;
-  void* iterationCookie;
+static std::string test_data_dir;
 
-  ASSERT_EQ(0, OpenArchive("/sdcard/test.jar", &handle));
-  ASSERT_EQ(0, StartIteration(handle, &iterationCookie, NULL));
+static const std::string kValidZip = "valid.zip";
+
+static const uint8_t kATxtContents[] = {
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+  '\n'
+};
+
+static const uint8_t kBTxtContents[] = {
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+  '\n'
+};
+
+static int32_t OpenArchiveWrapper(const std::string& name,
+                                  ZipArchiveHandle* handle) {
+  const std::string abs_path = test_data_dir + "/" + name;
+  return OpenArchive(abs_path.c_str(), handle);
+}
+
+static void AssertNameEquals(const std::string& name_str,
+                             const ZipEntryName& name) {
+  ASSERT_EQ(name_str.size(), name.name_length);
+  ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
+}
+
+TEST(ziparchive, Open) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, Iteration) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  void* iteration_cookie;
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
 
   ZipEntry data;
   ZipEntryName name;
-  int ctr = 0;
-  while (Next(iterationCookie, &data, &name) == 0) {
-    printf("Found %.*s\n", name.name_length, name.name);
-    ctr++;
+
+  // b/c.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/c.txt", name);
+
+  // b/d.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/d.txt", name);
+
+  // a.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("a.txt", name);
+
+  // b.txt
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b.txt", name);
+
+  // b/
+  ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+  AssertNameEquals("b/", name);
+
+  // End of iteration.
+  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, FindEntry) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  ZipEntry data;
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
+
+  // Known facts about a.txt, from zipinfo -v.
+  ASSERT_EQ(63, data.offset);
+  ASSERT_EQ(kCompressDeflated, data.method);
+  ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
+  ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
+  ASSERT_EQ(0x950821c5, data.crc32);
+
+  // An entry that doesn't exist. Should be a negative return code.
+  ASSERT_LT(FindEntry(handle, "nonexistent.txt", &data), 0);
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, ExtractToMemory) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  // An entry that's deflated.
+  ZipEntry data;
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
+  const uint32_t a_size = data.uncompressed_length;
+  ASSERT_EQ(a_size, sizeof(kATxtContents));
+  uint8_t* buffer = new uint8_t[a_size];
+  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
+  ASSERT_EQ(0, memcmp(buffer, kATxtContents, a_size));
+  delete[] buffer;
+
+  // An entry that's stored.
+  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
+  const uint32_t b_size = data.uncompressed_length;
+  ASSERT_EQ(b_size, sizeof(kBTxtContents));
+  buffer = new uint8_t[b_size];
+  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
+  ASSERT_EQ(0, memcmp(buffer, kBTxtContents, b_size));
+  delete[] buffer;
+
+  CloseArchive(handle);
+}
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+
+  static struct option options[] = {
+    { "test_data_dir", required_argument, NULL, 't' },
+    { NULL, 0, NULL, 0 }
+  };
+
+  while (true) {
+    int option_index;
+    const int c = getopt_long_only(argc, argv, "", options, &option_index);
+    if (c == -1) {
+      break;
+    }
+
+    if (c == 't') {
+      test_data_dir = optarg;
+    }
   }
 
-  ASSERT_EQ(2245, ctr);
+  if (test_data_dir.size() == 0) {
+    printf("Test data flag (--test_data_dir) required\n\n");
+    return -1;
+  }
 
-  ASSERT_EQ(0, FindEntry(handle, "java/sql/Clob.class", &data));
-  ASSERT_EQ(-1, FindEntry(handle, "java/sql/Slob.class", &data));
+  if (test_data_dir[0] != '/') {
+    printf("Test data must be an absolute path, was %s\n\n",
+           test_data_dir.c_str());
+    return -2;
+  }
 
-  CloseArchive(&handle);
+  return RUN_ALL_TESTS();
 }
 
diff --git a/toolbox/ls.c b/toolbox/ls.c
index c736958..8467628 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -209,7 +209,7 @@
         break;
     case S_IFLNK: {
         char linkto[256];
-        int len;
+        ssize_t len;
 
         len = readlink(path, linkto, 256);
         if(len < 0) return -1;
@@ -235,7 +235,7 @@
     return 0;
 }
 
-static int listfile_maclabel(const char *path, struct stat *s, int flags)
+static int listfile_maclabel(const char *path, struct stat *s)
 {
     char mode[16];
     char user[32];
@@ -324,7 +324,7 @@
     }
 
     if ((flags & LIST_MACLABEL) != 0) {
-        return listfile_maclabel(pathname, &s, flags);
+        return listfile_maclabel(pathname, &s);
     } else if ((flags & LIST_LONG) != 0) {
         return listfile_long(pathname, &s, flags);
     } else /*((flags & LIST_SIZE) != 0)*/ {