Merge "run-as: use mmap to read package list file"
diff --git a/run-as/package.c b/run-as/package.c
index ca08436..8f11646 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 #include <private/android_filesystem_config.h>
 #include "package.h"
 
@@ -43,9 +44,6 @@
 /* The file containing the list of installed packages on the system */
 #define PACKAGES_LIST_FILE  "/data/system/packages.list"
 
-/* This should be large enough to hold the content of the package database file */
-#define PACKAGES_LIST_BUFFER_SIZE  65536
-
 /* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
  * This function always zero-terminate the destination buffer unless
  * 'dstlen' is 0, even in case of overflow.
@@ -67,40 +65,63 @@
     *dst = '\0'; /* zero-terminate result */
 }
 
-/* Read up to 'buffsize' bytes into 'buff' from the file
- * named 'filename'. Return byte length on success, or -1
- * on error.
+/* Open 'filename' and map it into our address-space.
+ * Returns buffer address, or NULL on error
+ * On exit, *filesize will be set to the file's size, or 0 on error
  */
-static int
-read_file(const char* filename, char* buff, size_t buffsize)
+static void*
+map_file(const char* filename, size_t* filesize)
 {
-    int  fd, len, old_errno;
+    int  fd, ret, old_errno;
+    struct stat  st;
+    size_t  length = 0;
+    void*   address = NULL;
 
-    /* check the input buffer size */
-    if (buffsize >= INT_MAX) {
-        errno = EINVAL;
-        return -1;
-    }
+    *filesize = 0;
 
     /* open the file for reading */
-    do {
-        fd = open(filename, O_RDONLY);
-    } while (fd < 0 && errno == EINTR);
-
+    fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
     if (fd < 0)
-        return -1;
+        return NULL;
 
-    /* read the content */
-    do {
-        len = read(fd, buff, buffsize);
-    } while (len < 0 && errno == EINTR);
+    /* get its size */
+    ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
+    if (ret < 0)
+        goto EXIT;
 
+    /* Ensure that the size is not ridiculously large */
+    length = (size_t)st.st_size;
+    if ((off_t)length != st.st_size) {
+        errno = ENOMEM;
+        goto EXIT;
+    }
+
+    /* Memory-map the file now */
+    address = TEMP_FAILURE_RETRY(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0));
+    if (address == MAP_FAILED) {
+        address = NULL;
+        goto EXIT;
+    }
+
+    /* We're good, return size */
+    *filesize = length;
+
+EXIT:
     /* close the file, preserve old errno for better diagnostics */
     old_errno = errno;
     close(fd);
     errno = old_errno;
 
-    return len;
+    return address;
+}
+
+/* unmap the file, but preserve errno */
+static void
+unmap_file(void*  address, size_t  size)
+{
+    int old_errno = errno;
+    TEMP_FAILURE_RETRY(munmap(address, size));
+    errno = old_errno;
 }
 
 /* Check that a given directory:
@@ -371,18 +392,18 @@
 int
 get_package_info(const char* pkgName, PackageInfo *info)
 {
-    static char  buffer[PACKAGES_LIST_BUFFER_SIZE];
-    int          buffer_len;
+    char*        buffer;
+    size_t       buffer_len;
     const char*  p;
     const char*  buffer_end;
-    int          result;
+    int          result = -1;
 
     info->uid          = 0;
     info->isDebuggable = 0;
     info->dataDir[0]   = '\0';
 
-    buffer_len = read_file(PACKAGES_LIST_FILE, buffer, sizeof buffer);
-    if (buffer_len < 0)
+    buffer = map_file(PACKAGES_LIST_FILE, &buffer_len);
+    if (buffer == NULL)
         return -1;
 
     p          = buffer;
@@ -455,7 +476,8 @@
         string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
 
         /* Ignore the rest */
-        return 0;
+        result = 0;
+        goto EXIT;
 
     NEXT_LINE:
         p = next;
@@ -463,9 +485,14 @@
 
     /* the package is unknown */
     errno = ENOENT;
-    return -1;
+    result = -1;
+    goto EXIT;
 
 BAD_FORMAT:
     errno = EINVAL;
-    return -1;
+    result = -1;
+
+EXIT:
+    unmap_file(buffer, buffer_len);
+    return result;
 }