Add close_file flag to OpenArchiveFd()

 * We should be able to keep fd alive after CloseArchive()

Change-Id: I1aa2c039bb2a590ae72f256acc9ba5401c2c59b1
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index b6fd0d2..afc122d 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -289,6 +289,7 @@
 struct ZipArchive {
   /* open Zip archive */
   const int fd;
+  const bool close_file;
 
   /* mapped central directory area */
   off64_t directory_offset;
@@ -306,8 +307,9 @@
   uint32_t hash_table_size;
   ZipEntryName* hash_table;
 
-  ZipArchive(const int fd) :
+  ZipArchive(const int fd, bool assume_ownership) :
       fd(fd),
+      close_file(assume_ownership),
       directory_offset(0),
       directory_map(NULL),
       num_entries(0),
@@ -315,7 +317,7 @@
       hash_table(NULL) {}
 
   ~ZipArchive() {
-    if (fd >= 0) {
+    if (close_file && fd >= 0) {
       close(fd);
     }
 
@@ -690,21 +692,22 @@
 }
 
 int32_t OpenArchiveFd(int fd, const char* debug_file_name,
-                      ZipArchiveHandle* handle) {
-  ZipArchive* archive = new ZipArchive(fd);
+                      ZipArchiveHandle* handle, bool assume_ownership) {
+  ZipArchive* archive = new ZipArchive(fd, assume_ownership);
   *handle = archive;
   return OpenArchiveInternal(archive, debug_file_name);
 }
 
 int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
   const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
-  ZipArchive* archive = new ZipArchive(fd);
+  ZipArchive* archive = new ZipArchive(fd, true);
   *handle = archive;
 
   if (fd < 0) {
     ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
     return kIoError;
   }
+
   return OpenArchiveInternal(archive, fileName);
 }
 
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 4775de0..c8dafa9 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -17,6 +17,7 @@
 #include "ziparchive/zip_archive.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -88,6 +89,26 @@
   ASSERT_EQ(-1, GetFileDescriptor(handle));
 }
 
+TEST(ziparchive, OpenAssumeFdOwnership) {
+  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
+  ASSERT_NE(-1, fd);
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
+  CloseArchive(handle);
+  ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
+  ASSERT_EQ(EBADF, errno);
+}
+
+TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
+  int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY);
+  ASSERT_NE(-1, fd);
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
+  CloseArchive(handle);
+  ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
+  close(fd);
+}
+
 TEST(ziparchive, Iteration) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));