Remove mkdir() side effect, add .nomedia, utils.

Before this change, FUSE lookup() would have the side effect of
creating the directory on behalf of apps.  This resulted in most
directories being created just by Settings trying to measure disk
space.  Instead, we're switching to have vold do directory creation
when an app doesn't have enough permissions.

Create fs_mkdirs() utility to create all parent directories in a
path as needed.  Allow traversal (+x) into /storage directories.

Fix FUSE derived permissions to be case insensitive.  Mark well-known
directories as .nomedia when created.

Bug: 10577808, 10330221
Change-Id: I53114f2e63ffbe6de4ba6a72d94a232523231cad
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 116526d..8d1da21 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,87 @@
     unlink(temp);
     return -1;
 }
+
+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;
+}