merge in KQS81M
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 82c5798..f432f6a 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -53,6 +53,8 @@
 #define E2FSCK_BIN      "/system/bin/e2fsck"
 #define MKSWAP_BIN      "/system/bin/mkswap"
 
+#define FSCK_LOG_FILE   "/dev/fscklogs/log"
+
 #define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -92,6 +94,7 @@
     { "swapprio=",   MF_SWAPPRIO },
     { "zramsize=",   MF_ZRAMSIZE },
     { "verify",      MF_VERIFY },
+    { "noemulatedsd", MF_NOEMULATEDSD },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -427,6 +430,10 @@
 {
     int i;
 
+    if (!fstab) {
+        return;
+    }
+
     for (i = 0; i < fstab->num_entries; i++) {
         /* Free the pointers return by strdup(3) */
         free(fstab->recs[i].blk_device);
@@ -483,7 +490,8 @@
         INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
-                                      &status, true, LOG_KLOG, true);
+                                      &status, true, LOG_KLOG | LOG_FILE,
+                                      true, FSCK_LOG_FILE);
 
         if (ret < 0) {
             /* No need to check for error in fork, we can't really handle it now */
@@ -800,7 +808,7 @@
         /* Initialize the swap area */
         mkswap_argv[1] = fstab->recs[i].blk_device;
         err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
-                                      &status, true, LOG_KLOG, false);
+                                      &status, true, LOG_KLOG, false, NULL);
         if (err) {
             ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
             ret = -1;
@@ -931,3 +939,8 @@
 {
     return fstab->fs_mgr_flags & MF_CRYPT;
 }
+
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index f284ca6..59ffd78 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -72,6 +72,12 @@
 #define MF_SWAPPRIO     0x80
 #define MF_ZRAMSIZE     0x100
 #define MF_VERIFY       0x200
+/*
+ * There is no emulated sdcard daemon running on /data/media on this device,
+ * so treat the physical SD card as the only external storage device,
+ * a la the Nexus One.
+ */
+#define MF_NOEMULATEDSD 0x400
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 384d195..0f90c32 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -62,6 +62,7 @@
 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
 int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
 int fs_mgr_is_encryptable(struct fstab_rec *fstab);
+int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
 int fs_mgr_swapon_all(struct fstab *fstab);
 #ifdef __cplusplus
 }
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index fd5296b..d1d4cf2 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -55,6 +55,14 @@
  */
 extern int fs_write_atomic_int(const char* path, int value);
 
+/*
+ * Ensure that all directories along given path exist, creating parent
+ * directories as needed.  Validates that given path is absolute and that
+ * it contains no relative "." or ".." paths or symlinks.  Last path segment
+ * is treated as filename and ignored, unless the path ends with "/".
+ */
+extern int fs_mkdirs(const char* path, mode_t mode);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libmemtrack/include/memtrack.h b/include/memtrack/memtrack.h
similarity index 97%
rename from libmemtrack/include/memtrack.h
rename to include/memtrack/memtrack.h
index d6b370b..0f1f85e 100644
--- a/libmemtrack/include/memtrack.h
+++ b/include/memtrack/memtrack.h
@@ -19,6 +19,11 @@
 
 #include <sys/types.h>
 #include <stddef.h>
+#include <cutils/compiler.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /**
  * struct memtrack_proc
@@ -135,4 +140,8 @@
  */
 ssize_t memtrack_proc_other_pss(struct memtrack_proc *p);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 116526d..286a8eb 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -16,6 +16,11 @@
 
 #define LOG_TAG "cutils"
 
+/* These defines are only needed because prebuilt headers are out of date */
+#define __USE_XOPEN2K8 1
+#define _ATFILE_SOURCE 1
+#define _GNU_SOURCE 1
+
 #include <cutils/fs.h>
 #include <cutils/log.h>
 
@@ -27,6 +32,7 @@
 #include <string.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <dirent.h>
 
 #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
 #define BUF_SIZE 64
@@ -141,3 +147,91 @@
     unlink(temp);
     return -1;
 }
+
+#ifndef __APPLE__
+
+int fs_mkdirs(const char* path, mode_t mode) {
+    int res = 0;
+    int fd = 0;
+    struct stat sb;
+    char* buf = strdup(path);
+
+    if (*buf != '/') {
+        ALOGE("Relative paths are not allowed: %s", buf);
+        res = -EINVAL;
+        goto done;
+    }
+
+    if ((fd = open("/", 0)) == -1) {
+        ALOGE("Failed to open(/): %s", strerror(errno));
+        res = -errno;
+        goto done;
+    }
+
+    char* segment = buf + 1;
+    char* p = segment;
+    while (*p != '\0') {
+        if (*p == '/') {
+            *p = '\0';
+
+            if (!strcmp(segment, "..") || !strcmp(segment, ".") || !strcmp(segment, "")) {
+                ALOGE("Invalid path: %s", buf);
+                res = -EINVAL;
+                goto done_close;
+            }
+
+            if (fstatat(fd, segment, &sb, AT_SYMLINK_NOFOLLOW) != 0) {
+                if (errno == ENOENT) {
+                    /* Nothing there yet; let's create it! */
+                    if (mkdirat(fd, segment, mode) != 0) {
+                        if (errno == EEXIST) {
+                            /* We raced with someone; ignore */
+                        } else {
+                            ALOGE("Failed to mkdirat(%s): %s", buf, strerror(errno));
+                            res = -errno;
+                            goto done_close;
+                        }
+                    }
+                } else {
+                    ALOGE("Failed to fstatat(%s): %s", buf, strerror(errno));
+                    res = -errno;
+                    goto done_close;
+                }
+            } else {
+                if (S_ISLNK(sb.st_mode)) {
+                    ALOGE("Symbolic links are not allowed: %s", buf);
+                    res = -ELOOP;
+                    goto done_close;
+                }
+                if (!S_ISDIR(sb.st_mode)) {
+                    ALOGE("Existing segment not a directory: %s", buf);
+                    res = -ENOTDIR;
+                    goto done_close;
+                }
+            }
+
+            /* Yay, segment is ready for us to step into */
+            int next_fd;
+            if ((next_fd = openat(fd, segment, 0)) == -1) {
+                ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
+                res = -errno;
+                goto done_close;
+            }
+
+            close(fd);
+            fd = next_fd;
+
+            *p = '/';
+            segment = p + 1;
+        }
+        p++;
+    }
+
+done_close:
+    close(fd);
+done:
+    free(buf);
+    return res;
+}
+
+#endif
diff --git a/libmemtrack/Android.mk b/libmemtrack/Android.mk
index c23b6f4..a8fb3eb 100644
--- a/libmemtrack/Android.mk
+++ b/libmemtrack/Android.mk
@@ -3,10 +3,9 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 LOCAL_SRC_FILES := memtrack.c
 LOCAL_MODULE := libmemtrack
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include hardware/libhardware/include
+LOCAL_C_INCLUDES += hardware/libhardware/include
 LOCAL_SHARED_LIBRARIES := libhardware liblog
 LOCAL_CFLAGS := -Wall -Werror
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
index 2b2651a..9a656df 100644
--- a/libmemtrack/memtrack.c
+++ b/libmemtrack/memtrack.c
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <memtrack.h>
+#include <memtrack/memtrack.h>
 
 #define LOG_TAG "memtrack"
 
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
index f306f67..cd94bc5 100644
--- a/libmemtrack/memtrack_test.c
+++ b/libmemtrack/memtrack_test.c
@@ -19,7 +19,7 @@
 #include <string.h>
 #include <sys/types.h>
 
-#include <memtrack.h>
+#include <memtrack/memtrack.h>
 
 #include <pagemap/pagemap.h>
 
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 4b74889..ac8da88 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -61,12 +61,20 @@
 #define METHOD_IOCTL            1
 #define METHOD_SYSTEMTIME       2
 
+/*
+ * To debug/verify the timestamps returned by the kernel, change
+ * DEBUG_TIMESTAMP to 1 and call the timestamp routine from a single thread
+ * in the test program. b/10899829
+ */
+#define DEBUG_TIMESTAMP         0
+
 static const char *gettime_method_names[] = {
     "clock_gettime",
     "ioctl",
     "systemTime",
 };
 
+#if DEBUG_TIMESTAMP
 static inline void checkTimeStamps(int64_t timestamp,
                                    int64_t volatile *prevTimestampPtr,
                                    int volatile *prevMethodPtr,
@@ -93,6 +101,9 @@
     *prevMethodPtr = curMethod;
 #endif
 }
+#else
+#define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
+#endif
 
 /*
  * native public static long elapsedRealtimeNano();
@@ -103,8 +114,10 @@
     struct timespec ts;
     int result;
     int64_t timestamp;
+#if DEBUG_TIMESTAMP
     static volatile int64_t prevTimestamp;
     static volatile int prevMethod;
+#endif
 
 #if 0
     /*
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 3a1b281..a325692 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -90,10 +90,6 @@
 # Logged when the supplicant switches to a new state
 50023 wifi_supplicant_state_changed (supplicant_state|1|5)
 
-# Do not change these names without updating tag in:
-#//device/dalvik/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.c
-51000 socket_stats (send|1|2),(recv|1|2),(ip|1|5),(port|1|5),(close|1|5)
-
 # Database operation samples.
 # db: the filename of the database
 # sql: the executed query (without query args)
@@ -136,7 +132,7 @@
 80310 bionic_event_resolver_wrong_query (uid|1)
 
 # libcore failure logging
-90100 cert_pin_failure (certs|4)
+90100 exp_det_cert_pin_failure (certs|4)
 
 # NOTE - the range 1000000-2000000 is reserved for partners and others who
 # want to define their own log tags without conflicting with the core platform.
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 8087f0a..4307a30 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -44,11 +44,15 @@
  *           send a signal twice to signal the caller (once for the child, and
  *           once for the caller)
  *   log_target: Specify where to log the output of the child, either LOG_NONE,
- *           LOG_ALOG (for the Android system log) or LOG_KLOG (for the kernel
- *           log).
+ *           LOG_ALOG (for the Android system log), LOG_KLOG (for the kernel
+ *           log), or LOG_FILE (and you need to specify a pathname in the
+ *           file_path argument, otherwise pass NULL).  These are bit fields,
+ *           and can be OR'ed together to log to multiple places.
  *   abbreviated: If true, capture up to the first 100 lines and last 4K of
  *           output from the child.  The abbreviated output is not dumped to
  *           the specified log until the child has exited.
+ *   file_path: if log_target has the LOG_FILE bit set, then this parameter
+ *           must be set to the pathname of the file to log to.
  *
  * Return value:
  *   0 when logwrap successfully run the child process and captured its status
@@ -58,13 +62,14 @@
  *
  */
 
-/* Values for the log_target parameter android_fork_exec_ext() */
+/* Values for the log_target parameter android_fork_execvp_ext() */
 #define LOG_NONE        0
 #define LOG_ALOG        1
 #define LOG_KLOG        2
+#define LOG_FILE        4
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated);
+        int log_target, bool abbreviated, char *file_path);
 
 /* Similar to above, except abbreviated logging is not available, and if logwrap
  * is true, logging is to the Android system log, and if false, there is no
@@ -74,10 +79,9 @@
                                      bool ignore_int_quit, bool logwrap)
 {
     return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
-                                   (logwrap ? LOG_ALOG : LOG_NONE), false);
+                                   (logwrap ? LOG_ALOG : LOG_NONE), false, NULL);
 }
 
-
 __END_DECLS
 
 #endif /* __LIBS_LOGWRAP_H */
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 01cc9a1..4ca1db4 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -93,6 +93,7 @@
     char klog_fmt[MAX_KLOG_TAG * 2];
     char *btag;
     bool abbreviated;
+    FILE *fp;
     struct abbr_buf a_buf;
 };
 
@@ -158,11 +159,15 @@
 
 /* Log directly to the specified log */
 static void do_log_line(struct log_info *log_info, char *line) {
-    if (log_info->log_target == LOG_KLOG) {
+    if (log_info->log_target & LOG_KLOG) {
         klog_write(6, log_info->klog_fmt, line);
-    } else if (log_info->log_target == LOG_ALOG) {
+    }
+    if (log_info->log_target & LOG_ALOG) {
         ALOG(LOG_INFO, log_info->btag, "%s", line);
     }
+    if (log_info->log_target & LOG_FILE) {
+        fprintf(log_info->fp, "%s\n", line);
+    }
 }
 
 /* Log to either the abbreviated buf, or directly to the specified log
@@ -290,7 +295,7 @@
 }
 
 static int parent(const char *tag, int parent_read, pid_t pid,
-        int *chld_sts, int log_target, bool abbreviated) {
+        int *chld_sts, int log_target, bool abbreviated, char *file_path) {
     int status = 0;
     char buffer[4096];
     struct pollfd poll_fds[] = {
@@ -300,6 +305,7 @@
         },
     };
     int rc = 0;
+    int fd;
 
     struct log_info log_info;
 
@@ -309,8 +315,6 @@
     bool found_child = false;
     char tmpbuf[256];
 
-    log_info.log_target = log_target;
-    log_info.abbreviated = abbreviated;
     log_info.btag = basename(tag);
     if (!log_info.btag) {
         log_info.btag = (char*) tag;
@@ -323,11 +327,30 @@
         init_abbr_buf(&log_info.a_buf);
     }
 
-    if (log_target == LOG_KLOG) {
+    if (log_target & LOG_KLOG) {
         snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt),
                  "<6>%.*s: %%s", MAX_KLOG_TAG, log_info.btag);
     }
 
+    if ((log_target & LOG_FILE) && !file_path) {
+        /* No file_path specified, clear the LOG_FILE bit */
+        log_target &= ~LOG_FILE;
+    }
+
+    if (log_target & LOG_FILE) {
+        fd = open(file_path, O_WRONLY | O_CREAT, 0664);
+        if (fd < 0) {
+            ERROR("Cannot log to file %s\n", file_path);
+            log_target &= ~LOG_FILE;
+        } else {
+            lseek(fd, 0, SEEK_END);
+            log_info.fp = fdopen(fd, "a");
+        }
+    }
+
+    log_info.log_target = log_target;
+    log_info.abbreviated = abbreviated;
+
     while (!found_child) {
         if (TEMP_FAILURE_RETRY(poll(poll_fds, ARRAY_SIZE(poll_fds), -1)) < 0) {
             ERROR("poll failed\n");
@@ -432,6 +455,9 @@
 
 err_waitpid:
 err_poll:
+    if (log_target & LOG_FILE) {
+        fclose(log_info.fp); /* Also closes underlying fd */
+    }
     if (abbreviated) {
         free_abbr_buf(&log_info.a_buf);
     }
@@ -451,7 +477,7 @@
 }
 
 int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
-        int log_target, bool abbreviated) {
+        int log_target, bool abbreviated, char *file_path) {
     pid_t pid;
     int parent_ptty;
     int child_ptty;
@@ -523,7 +549,8 @@
             sigaction(SIGQUIT, &ignact, &quitact);
         }
 
-        rc = parent(argv[0], parent_ptty, pid, status, log_target, abbreviated);
+        rc = parent(argv[0], parent_ptty, pid, status, log_target,
+                    abbreviated, file_path);
     }
 
     if (ignore_int_quit) {
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index d1c6240..d0d8d14 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -80,7 +80,7 @@
     }
 
     rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
-                                 log_target, abbreviated);
+                                 log_target, abbreviated, NULL);
     if (!rc) {
         if (WIFEXITED(status))
             rc = WEXITSTATUS(status);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index be74f6f..86e124f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -61,7 +61,8 @@
 
     # See storage config details at http://source.android.com/tech/storage/
     mkdir /mnt/shell 0700 shell shell
-    mkdir /storage 0050 root sdcard_r
+    mkdir /mnt/media_rw 0700 media_rw media_rw
+    mkdir /storage 0751 root sdcard_r
 
     # Directory for putting things only root should see.
     mkdir /mnt/secure 0700 root root
@@ -133,6 +134,10 @@
 # This is needed by any process that uses socket tagging.
     chmod 0644 /dev/xt_qtaguid
 
+# Create location for fs_mgr to store abbreviated output from filesystem
+# checker programs.
+    mkdir /dev/fscklogs 0770 root system
+
 on post-fs
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 9a1dd17..05fbfba 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -32,6 +32,7 @@
 #include <sys/resource.h>
 #include <sys/inotify.h>
 
+#include <cutils/fs.h>
 #include <cutils/hashmap.h>
 #include <cutils/multiuser.h>
 
@@ -193,8 +194,9 @@
     return hashmapHash(key, strlen(key));
 }
 
-static bool str_equals(void *keyA, void *keyB) {
-    return strcmp(keyA, keyB) == 0;
+/** Test if two string keys are equal ignoring case */
+static bool str_icase_equals(void *keyA, void *keyB) {
+    return strcasecmp(keyA, keyB) == 0;
 }
 
 static int int_hash(void *key) {
@@ -213,6 +215,7 @@
     int fd;
     derive_t derive;
     bool split_perms;
+    gid_t write_gid;
     struct node root;
     char obbpath[PATH_MAX];
 
@@ -401,6 +404,20 @@
     attr->mode = (attr->mode & S_IFMT) | filtered_mode;
 }
 
+static int touch(char* path, mode_t mode) {
+    int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
+    if (fd == -1) {
+        if (errno == EEXIST) {
+            return 0;
+        } else {
+            ERROR("Failed to open(%s): %s\n", path, strerror(errno));
+            return -1;
+        }
+    }
+    close(fd);
+    return 0;
+}
+
 static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
         struct node *node) {
     appid_t appid;
@@ -429,37 +446,37 @@
     case PERM_ROOT:
         /* Assume masked off by default. */
         node->mode = 0770;
-        if (!strcmp(node->name, "Android")) {
+        if (!strcasecmp(node->name, "Android")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID;
             node->mode = 0771;
         } else if (fuse->split_perms) {
-            if (!strcmp(node->name, "DCIM")
-                    || !strcmp(node->name, "Pictures")) {
+            if (!strcasecmp(node->name, "DCIM")
+                    || !strcasecmp(node->name, "Pictures")) {
                 node->gid = AID_SDCARD_PICS;
-            } else if (!strcmp(node->name, "Alarms")
-                    || !strcmp(node->name, "Movies")
-                    || !strcmp(node->name, "Music")
-                    || !strcmp(node->name, "Notifications")
-                    || !strcmp(node->name, "Podcasts")
-                    || !strcmp(node->name, "Ringtones")) {
+            } else if (!strcasecmp(node->name, "Alarms")
+                    || !strcasecmp(node->name, "Movies")
+                    || !strcasecmp(node->name, "Music")
+                    || !strcasecmp(node->name, "Notifications")
+                    || !strcasecmp(node->name, "Podcasts")
+                    || !strcasecmp(node->name, "Ringtones")) {
                 node->gid = AID_SDCARD_AV;
             }
         }
         break;
     case PERM_ANDROID:
-        if (!strcmp(node->name, "data")) {
+        if (!strcasecmp(node->name, "data")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_DATA;
             node->mode = 0771;
-        } else if (!strcmp(node->name, "obb")) {
+        } else if (!strcasecmp(node->name, "obb")) {
             /* App-specific directories inside; let anyone traverse */
             node->perm = PERM_ANDROID_OBB;
             node->mode = 0771;
             /* Single OBB directory is always shared */
             node->graft_path = fuse->obbpath;
             node->graft_pathlen = strlen(fuse->obbpath);
-        } else if (!strcmp(node->name, "user")) {
+        } else if (!strcasecmp(node->name, "user")) {
             /* User directories must only be accessible to system, protected
              * by sdcard_all. Zygote will bind mount the appropriate user-
              * specific path. */
@@ -505,9 +522,9 @@
         const char* name, int mode, bool has_rw) {
     /* Always block security-sensitive files at root */
     if (parent_node && parent_node->perm == PERM_ROOT) {
-        if (!strcmp(name, "autorun.inf")
-                || !strcmp(name, ".android_secure")
-                || !strcmp(name, "android_secure")) {
+        if (!strcasecmp(name, "autorun.inf")
+                || !strcasecmp(name, ".android_secure")
+                || !strcasecmp(name, "android_secure")) {
             return false;
         }
     }
@@ -517,8 +534,9 @@
         return true;
     }
 
-    /* Root or shell always have access */
-    if (hdr->uid == 0 || hdr->uid == AID_SHELL) {
+    /* Root always has access; access for any other UIDs should always
+     * be controlled through packages.list. */
+    if (hdr->uid == 0) {
         return true;
     }
 
@@ -664,13 +682,14 @@
 }
 
 static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
-        gid_t fs_gid, derive_t derive, bool split_perms) {
+        gid_t write_gid, derive_t derive, bool split_perms) {
     pthread_mutex_init(&fuse->lock, NULL);
 
     fuse->fd = fd;
     fuse->next_generation = 0;
     fuse->derive = derive;
     fuse->split_perms = split_perms;
+    fuse->write_gid = write_gid;
 
     memset(&fuse->root, 0, sizeof(fuse->root));
     fuse->root.nid = FUSE_ROOT_ID; /* 1 */
@@ -695,18 +714,19 @@
          * just below that. Shared OBB path is also at top level. */
         fuse->root.perm = PERM_LEGACY_PRE_ROOT;
         fuse->root.mode = 0771;
-        fuse->root.gid = fs_gid;
-        fuse->package_to_appid = hashmapCreate(256, str_hash, str_equals);
+        fuse->root.gid = AID_SDCARD_R;
+        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
         fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
         snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/obb", source_path);
+        fs_prepare_dir(fuse->obbpath, 0775, getuid(), getgid());
         break;
     case DERIVE_UNIFIED:
         /* Unified multiuser layout which places secondary user_id under
          * /Android/user and shared OBB path under /Android/obb. */
         fuse->root.perm = PERM_ROOT;
         fuse->root.mode = 0771;
-        fuse->root.gid = fs_gid;
-        fuse->package_to_appid = hashmapCreate(256, str_hash, str_equals);
+        fuse->root.gid = AID_SDCARD_R;
+        fuse->package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
         fuse->appid_with_rw = hashmapCreate(128, int_hash, int_equals);
         snprintf(fuse->obbpath, sizeof(fuse->obbpath), "%s/Android/obb", source_path);
         break;
@@ -752,36 +772,7 @@
     struct stat s;
 
     if (lstat(path, &s) < 0) {
-        /* But wait! We'll automatically create a directory if its
-         * a valid package name under data or obb, since apps may not
-         * have enough permissions to create for themselves. */
-        if (errno == ENOENT && (parent->perm == PERM_ANDROID_DATA
-                || parent->perm == PERM_ANDROID_OBB)) {
-            TRACE("automatically creating %s\n", path);
-
-            pthread_mutex_lock(&fuse->lock);
-            bool validPackage = hashmapContainsKey(fuse->package_to_appid, (char*) name);
-            pthread_mutex_unlock(&fuse->lock);
-
-            if (!validPackage) {
-                return -ENOENT;
-            }
-            if (mkdir(path, 0775) == -1) {
-                /* We might have raced with ourselves and already created */
-                if (errno != EEXIST) {
-                    ERROR("failed to mkdir(%s): %s\n", name, strerror(errno));
-                    return -ENOENT;
-                }
-            }
-
-            /* It should exist this time around! */
-            if (lstat(path, &s) < 0) {
-                ERROR("failed to lstat(%s): %s\n", name, strerror(errno));
-                return -errno;
-            }
-        } else {
-            return -errno;
-        }
+        return -errno;
     }
 
     pthread_mutex_lock(&fuse->lock);
@@ -1006,6 +997,25 @@
     if (mkdir(child_path, mode) < 0) {
         return -errno;
     }
+
+    /* When creating /Android/data and /Android/obb, mark them as .nomedia */
+    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
+        char nomedia[PATH_MAX];
+        snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
+        if (touch(nomedia, 0664) != 0) {
+            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
+            return -ENOENT;
+        }
+    }
+    if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
+        char nomedia[PATH_MAX];
+        snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->obbpath);
+        if (touch(nomedia, 0664) != 0) {
+            ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
+            return -ENOENT;
+        }
+    }
+
     return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
 }
 
@@ -1615,7 +1625,7 @@
 
             char* token = strtok(gids, ",");
             while (token != NULL) {
-                if (strtoul(token, NULL, 10) == AID_SDCARD_RW) {
+                if (strtoul(token, NULL, 10) == fuse->write_gid) {
                     hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 1);
                     break;
                 }
@@ -1624,7 +1634,7 @@
         }
     }
 
-    TRACE("read_package_list: found %d packages, %d with sdcard_rw\n",
+    TRACE("read_package_list: found %d packages, %d with write_gid\n",
             hashmapSize(fuse->package_to_appid),
             hashmapSize(fuse->appid_with_rw));
     fclose(file);
@@ -1741,7 +1751,7 @@
     ERROR("usage: sdcard [OPTIONS] <source_path> <dest_path>\n"
             "    -u: specify UID to run as\n"
             "    -g: specify GID to run as\n"
-            "    -G: specify default GID for files (default sdcard_r, requires -d or -l)\n"
+            "    -w: specify GID required to write (default sdcard_rw, requires -d or -l)\n"
             "    -t: specify number of threads to use (default %d)\n"
             "    -d: derive file permissions based on path\n"
             "    -l: derive file permissions based on legacy internal layout\n"
@@ -1751,7 +1761,8 @@
 }
 
 static int run(const char* source_path, const char* dest_path, uid_t uid,
-        gid_t gid, gid_t fs_gid, int num_threads, derive_t derive, bool split_perms) {
+        gid_t gid, gid_t write_gid, int num_threads, derive_t derive,
+        bool split_perms) {
     int fd;
     char opts[256];
     int res;
@@ -1794,7 +1805,7 @@
         goto error;
     }
 
-    fuse_init(&fuse, fd, source_path, fs_gid, derive, split_perms);
+    fuse_init(&fuse, fd, source_path, write_gid, derive, split_perms);
 
     umask(0);
     res = ignite_fuse(&fuse, num_threads);
@@ -1814,7 +1825,7 @@
     const char *dest_path = NULL;
     uid_t uid = 0;
     gid_t gid = 0;
-    gid_t fs_gid = AID_SDCARD_R;
+    gid_t write_gid = AID_SDCARD_RW;
     int num_threads = DEFAULT_NUM_THREADS;
     derive_t derive = DERIVE_NONE;
     bool split_perms = false;
@@ -1822,7 +1833,7 @@
     struct rlimit rlim;
 
     int opt;
-    while ((opt = getopt(argc, argv, "u:g:G:t:dls")) != -1) {
+    while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
         switch (opt) {
             case 'u':
                 uid = strtoul(optarg, NULL, 10);
@@ -1830,8 +1841,8 @@
             case 'g':
                 gid = strtoul(optarg, NULL, 10);
                 break;
-            case 'G':
-                fs_gid = strtoul(optarg, NULL, 10);
+            case 'w':
+                write_gid = strtoul(optarg, NULL, 10);
                 break;
             case 't':
                 num_threads = strtoul(optarg, NULL, 10);
@@ -1894,6 +1905,6 @@
         ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
     }
 
-    res = run(source_path, dest_path, uid, gid, fs_gid, num_threads, derive, split_perms);
+    res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
     return res < 0 ? 1 : 0;
 }