Merge "liblog: pmsg_read add validity checking for prio"
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index b12f3ee..f87e2d5 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -2,10 +2,10 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := sdcard.cpp fuse.c
+LOCAL_SRC_FILES := sdcard.cpp fuse.cpp
 LOCAL_MODULE := sdcard
 LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
-LOCAL_SHARED_LIBRARIES := liblog libcutils libpackagelistparser
+LOCAL_SHARED_LIBRARIES := libbase liblog libcutils libpackagelistparser
 
 LOCAL_SANITIZE := integer
 LOCAL_CLANG := true
diff --git a/sdcard/fuse.c b/sdcard/fuse.cpp
similarity index 90%
rename from sdcard/fuse.c
rename to sdcard/fuse.cpp
index bbf7284..1b6a5f1 100644
--- a/sdcard/fuse.c
+++ b/sdcard/fuse.cpp
@@ -51,7 +51,7 @@
             TRACE("DESTROY %p (%s)\n", node, node->name);
             remove_node_from_parent_locked(node);
 
-                /* TODO: remove debugging - poison memory */
+            /* TODO: remove debugging - poison memory */
             memset(node->name, 0xef, node->namelen);
             free(node->name);
             free(node->actual_name);
@@ -336,18 +336,18 @@
         return NULL;
     }
 
-    node = calloc(1, sizeof(struct node));
+    node = static_cast<struct node*>(calloc(1, sizeof(struct node)));
     if (!node) {
         return NULL;
     }
-    node->name = malloc(namelen + 1);
+    node->name = static_cast<char*>(malloc(namelen + 1));
     if (!node->name) {
         free(node);
         return NULL;
     }
     memcpy(node->name, name, namelen + 1);
     if (strcmp(name, actual_name)) {
-        node->actual_name = malloc(namelen + 1);
+        node->actual_name = static_cast<char*>(malloc(namelen + 1));
         if (!node->actual_name) {
             free(node->name);
             free(node);
@@ -377,13 +377,13 @@
     /* make the storage bigger without actually changing the name
      * in case an error occurs part way */
     if (namelen > node->namelen) {
-        char* new_name = realloc(node->name, namelen + 1);
+        char* new_name = static_cast<char*>(realloc(node->name, namelen + 1));
         if (!new_name) {
             return -ENOMEM;
         }
         node->name = new_name;
         if (need_actual_name && node->actual_name) {
-            char* new_actual_name = realloc(node->actual_name, namelen + 1);
+            char* new_actual_name = static_cast<char*>(realloc(node->actual_name, namelen + 1));
             if (!new_actual_name) {
                 return -ENOMEM;
             }
@@ -394,7 +394,7 @@
     /* update the name, taking care to allocate storage before overwriting the old name */
     if (need_actual_name) {
         if (!node->actual_name) {
-            node->actual_name = malloc(namelen + 1);
+            node->actual_name = static_cast<char*>(malloc(namelen + 1));
             if (!node->actual_name) {
                 return -ENOMEM;
             }
@@ -414,7 +414,7 @@
     if (nid == FUSE_ROOT_ID) {
         return &fuse->global->root;
     } else {
-        return id_to_ptr(nid);
+        return static_cast<struct node*>(id_to_ptr(nid));
     }
 }
 
@@ -572,7 +572,7 @@
     pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
+    TRACE("[%d] LOOKUP %s @ %" PRIx64 " (%s)\n", handler->token, name, hdr->nodeid,
         parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -594,7 +594,7 @@
 
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_by_id_locked(fuse, hdr->nodeid);
-    TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
+    TRACE("[%d] FORGET #%" PRIu64 " @ %" PRIx64 " (%s)\n", handler->token, req->nlookup,
             hdr->nodeid, node ? node->name : "?");
     if (node) {
         __u64 n = req->nlookup;
@@ -615,7 +615,7 @@
 
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] GETATTR flags=%x fh=%" PRIx64 " @ %" PRIx64 " (%s)\n", handler->token,
             req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -638,7 +638,7 @@
 
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] SETATTR fh=%" PRIx64 " valid=%x @ %" PRIx64 " (%s)\n", handler->token,
             req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -703,7 +703,7 @@
     pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] MKNOD %s 0%o @ %" PRIx64 " (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -732,7 +732,7 @@
     pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] MKDIR %s 0%o @ %" PRIx64 " (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -780,7 +780,7 @@
     pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] UNLINK %s @ %" PRIx64 " (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -802,7 +802,7 @@
     pthread_mutex_unlock(&fuse->global->lock);
     if (parent_node && child_node) {
         /* Tell all other views that node is gone */
-        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
+        TRACE("[%d] fuse_notify_delete parent=%" PRIx64 ", child=%" PRIx64 ", name=%s\n",
                 handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
         if (fuse != fuse->global->fuse_default) {
             fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
@@ -828,7 +828,7 @@
     pthread_mutex_lock(&fuse->global->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] RMDIR %s @ %" PRIx64 " (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -850,7 +850,7 @@
     pthread_mutex_unlock(&fuse->global->lock);
     if (parent_node && child_node) {
         /* Tell all other views that node is gone */
-        TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
+        TRACE("[%d] fuse_notify_delete parent=%" PRIx64 ", child=%" PRIx64 ", name=%s\n",
                 handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
         if (fuse != fuse->global->fuse_default) {
             fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
@@ -877,6 +877,7 @@
     char old_child_path[PATH_MAX];
     char new_child_path[PATH_MAX];
     const char* new_actual_name;
+    int search;
     int res;
 
     pthread_mutex_lock(&fuse->global->lock);
@@ -884,7 +885,7 @@
             old_parent_path, sizeof(old_parent_path));
     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
             new_parent_path, sizeof(new_parent_path));
-    TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] RENAME %s->%s @ %" PRIx64 " (%s) -> %" PRIx64 " (%s)\n", handler->token,
             old_name, new_name,
             hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
             req->newdir, new_parent_node ? new_parent_node->name : "?");
@@ -913,7 +914,7 @@
      * differing only by case.  In this case we don't want to look for a case
      * insensitive match.  This allows commands like "mv foo FOO" to work as expected.
      */
-    int search = old_parent_node != new_parent_node
+    search = old_parent_node != new_parent_node
             || strcasecmp(old_name, new_name);
     if (!(new_actual_name = find_file_within(new_parent_path, new_name,
             new_child_path, sizeof(new_child_path), search))) {
@@ -968,7 +969,7 @@
 
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] OPEN 0%o @ %" PRIx64 " (%s)\n", handler->token,
             req->flags, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -979,7 +980,7 @@
             open_flags_to_access_mode(req->flags))) {
         return -EACCES;
     }
-    h = malloc(sizeof(*h));
+    h = static_cast<struct handle*>(malloc(sizeof(*h)));
     if (!h) {
         return -ENOMEM;
     }
@@ -1005,7 +1006,7 @@
 static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_read_in* req)
 {
-    struct handle *h = id_to_ptr(req->fh);
+    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
     __u64 unique = hdr->unique;
     __u32 size = req->size;
     __u64 offset = req->offset;
@@ -1016,7 +1017,7 @@
      * overlaps the request buffer and will clobber data in the request.  This
      * saves us 128KB per request handler thread at the cost of this scary comment. */
 
-    TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
+    TRACE("[%d] READ %p(%d) %u@%" PRIu64 "\n", handler->token,
             h, h->fd, size, (uint64_t) offset);
     if (size > MAX_READ) {
         return -EINVAL;
@@ -1034,7 +1035,7 @@
         const void* buffer)
 {
     struct fuse_write_out out;
-    struct handle *h = id_to_ptr(req->fh);
+    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
     int res;
     __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
 
@@ -1043,7 +1044,7 @@
         buffer = (const __u8*) aligned_buffer;
     }
 
-    TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
+    TRACE("[%d] WRITE %p(%d) %u@%" PRIu64 "\n", handler->token,
             h, h->fd, req->size, req->offset);
     res = pwrite64(h->fd, buffer, req->size, req->offset);
     if (res < 0) {
@@ -1089,7 +1090,7 @@
 static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
 {
-    struct handle *h = id_to_ptr(req->fh);
+    struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
 
     TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
     close(h->fd);
@@ -1105,16 +1106,16 @@
 
     int fd = -1;
     if (is_dir) {
-      struct dirhandle *dh = id_to_ptr(req->fh);
+      struct dirhandle *dh = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
       fd = dirfd(dh->d);
     } else {
-      struct handle *h = id_to_ptr(req->fh);
+      struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
       fd = h->fd;
     }
 
     TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
             is_dir ? "FSYNCDIR" : "FSYNC",
-            id_to_ptr(req->fh), fd, is_data_sync);
+            static_cast<struct node*>(id_to_ptr(req->fh)), fd, is_data_sync);
     int res = is_data_sync ? fdatasync(fd) : fsync(fd);
     if (res == -1) {
         return -errno;
@@ -1139,7 +1140,7 @@
 
     pthread_mutex_lock(&fuse->global->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
+    TRACE("[%d] OPENDIR @ %" PRIx64 " (%s)\n", handler->token,
             hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->global->lock);
 
@@ -1149,7 +1150,7 @@
     if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
         return -EACCES;
     }
-    h = malloc(sizeof(*h));
+    h = static_cast<struct dirhandle*>(malloc(sizeof(*h)));
     if (!h) {
         return -ENOMEM;
     }
@@ -1178,7 +1179,7 @@
     char buffer[8192];
     struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
     struct dirent *de;
-    struct dirhandle *h = id_to_ptr(req->fh);
+    struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
 
     TRACE("[%d] READDIR %p\n", handler->token, h);
     if (req->offset == 0) {
@@ -1204,7 +1205,7 @@
 static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
         const struct fuse_in_header* hdr, const struct fuse_release_in* req)
 {
-    struct dirhandle *h = id_to_ptr(req->fh);
+    struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
 
     TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
     closedir(h->d);
@@ -1266,51 +1267,51 @@
 {
     switch (hdr->opcode) {
     case FUSE_LOOKUP: { /* bytez[] -> entry_out */
-        const char* name = data;
+        const char *name = static_cast<const char*>(data);
         return handle_lookup(fuse, handler, hdr, name);
     }
 
     case FUSE_FORGET: {
-        const struct fuse_forget_in *req = data;
+        const struct fuse_forget_in *req = static_cast<const struct fuse_forget_in*>(data);
         return handle_forget(fuse, handler, hdr, req);
     }
 
     case FUSE_GETATTR: { /* getattr_in -> attr_out */
-        const struct fuse_getattr_in *req = data;
+        const struct fuse_getattr_in *req = static_cast<const struct fuse_getattr_in*>(data);
         return handle_getattr(fuse, handler, hdr, req);
     }
 
     case FUSE_SETATTR: { /* setattr_in -> attr_out */
-        const struct fuse_setattr_in *req = data;
+        const struct fuse_setattr_in *req = static_cast<const struct fuse_setattr_in*>(data);
         return handle_setattr(fuse, handler, hdr, req);
     }
 
 //    case FUSE_READLINK:
 //    case FUSE_SYMLINK:
     case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
-        const struct fuse_mknod_in *req = data;
+        const struct fuse_mknod_in *req = static_cast<const struct fuse_mknod_in*>(data);
         const char *name = ((const char*) data) + sizeof(*req);
         return handle_mknod(fuse, handler, hdr, req, name);
     }
 
     case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
-        const struct fuse_mkdir_in *req = data;
+        const struct fuse_mkdir_in *req = static_cast<const struct fuse_mkdir_in*>(data);
         const char *name = ((const char*) data) + sizeof(*req);
         return handle_mkdir(fuse, handler, hdr, req, name);
     }
 
     case FUSE_UNLINK: { /* bytez[] -> */
-        const char* name = data;
+        const char *name = static_cast<const char*>(data);
         return handle_unlink(fuse, handler, hdr, name);
     }
 
     case FUSE_RMDIR: { /* bytez[] -> */
-        const char* name = data;
+        const char *name = static_cast<const char*>(data);
         return handle_rmdir(fuse, handler, hdr, name);
     }
 
     case FUSE_RENAME: { /* rename_in, oldname, newname ->  */
-        const struct fuse_rename_in *req = data;
+        const struct fuse_rename_in *req = static_cast<const struct fuse_rename_in*>(data);
         const char *old_name = ((const char*) data) + sizeof(*req);
         const char *new_name = old_name + strlen(old_name) + 1;
         return handle_rename(fuse, handler, hdr, req, old_name, new_name);
@@ -1318,17 +1319,17 @@
 
 //    case FUSE_LINK:
     case FUSE_OPEN: { /* open_in -> open_out */
-        const struct fuse_open_in *req = data;
+        const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
         return handle_open(fuse, handler, hdr, req);
     }
 
     case FUSE_READ: { /* read_in -> byte[] */
-        const struct fuse_read_in *req = data;
+        const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
         return handle_read(fuse, handler, hdr, req);
     }
 
     case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
-        const struct fuse_write_in *req = data;
+        const struct fuse_write_in *req = static_cast<const struct fuse_write_in*>(data);
         const void* buffer = (const __u8*)data + sizeof(*req);
         return handle_write(fuse, handler, hdr, req, buffer);
     }
@@ -1338,13 +1339,13 @@
     }
 
     case FUSE_RELEASE: { /* release_in -> */
-        const struct fuse_release_in *req = data;
+        const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
         return handle_release(fuse, handler, hdr, req);
     }
 
     case FUSE_FSYNC:
     case FUSE_FSYNCDIR: {
-        const struct fuse_fsync_in *req = data;
+        const struct fuse_fsync_in *req = static_cast<const struct fuse_fsync_in*>(data);
         return handle_fsync(fuse, handler, hdr, req);
     }
 
@@ -1357,27 +1358,27 @@
     }
 
     case FUSE_OPENDIR: { /* open_in -> open_out */
-        const struct fuse_open_in *req = data;
+        const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
         return handle_opendir(fuse, handler, hdr, req);
     }
 
     case FUSE_READDIR: {
-        const struct fuse_read_in *req = data;
+        const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
         return handle_readdir(fuse, handler, hdr, req);
     }
 
     case FUSE_RELEASEDIR: { /* release_in -> */
-        const struct fuse_release_in *req = data;
+        const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
         return handle_releasedir(fuse, handler, hdr, req);
     }
 
     case FUSE_INIT: { /* init_in -> init_out */
-        const struct fuse_init_in *req = data;
+        const struct fuse_init_in *req = static_cast<const struct fuse_init_in*>(data);
         return handle_init(fuse, handler, hdr, req);
     }
 
     default: {
-        TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
+        TRACE("[%d] NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
                 handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
         return -ENOSYS;
     }
@@ -1404,7 +1405,8 @@
             continue;
         }
 
-        const struct fuse_in_header *hdr = (void*)handler->request_buffer;
+        const struct fuse_in_header* hdr =
+            reinterpret_cast<const struct fuse_in_header*>(handler->request_buffer);
         if (hdr->len != (size_t)len) {
             ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
                     handler->token, (size_t)len, hdr->len);
diff --git a/sdcard/fuse.h b/sdcard/fuse.h
index e1347f9..d76c664 100644
--- a/sdcard/fuse.h
+++ b/sdcard/fuse.h
@@ -38,10 +38,6 @@
 
 #include <private/android_filesystem_config.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define FUSE_TRACE 0
 
 #if FUSE_TRACE
@@ -196,8 +192,4 @@
 void handle_fuse_requests(struct fuse_handler* handler);
 void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent);
 
-#ifdef __cplusplus
-}; /* extern "C" */
-#endif
-
 #endif  /* FUSE_H_ */
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index 00dcaf9..dd0c433 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -28,6 +28,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android-base/logging.h>
+
 #include <cutils/fs.h>
 #include <cutils/hashmap.h>
 #include <cutils/log.h>
@@ -36,37 +38,36 @@
 
 #include <private/android_filesystem_config.h>
 
-/* README
- *
- * What is this?
- *
- * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
- * directory permissions (all files are given fixed owner, group, and
- * permissions at creation, owner, group, and permissions are not
- * changeable, symlinks and hardlinks are not createable, etc.
- *
- * See usage() for command line options.
- *
- * It must be run as root, but will drop to requested UID/GID as soon as it
- * mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
- *
- * Things I believe to be true:
- *
- * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
- * CREAT) must bump that node's refcount
- * - don't forget that FORGET can forget multiple references (req->nlookup)
- * - if an op that returns a fuse_entry fails writing the reply to the
- * kernel, you must rollback the refcount to reflect the reference the
- * kernel did not actually acquire
- *
- * This daemon can also derive custom filesystem permissions based on directory
- * structure when requested. These custom permissions support several features:
- *
- * - Apps can access their own files in /Android/data/com.example/ without
- * requiring any additional GIDs.
- * - Separate permissions for protecting directories like Pictures and Music.
- * - Multi-user separation on the same physical device.
- */
+// README
+//
+// What is this?
+//
+// sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
+// directory permissions (all files are given fixed owner, group, and
+// permissions at creation, owner, group, and permissions are not
+// changeable, symlinks and hardlinks are not createable, etc.
+//
+// See usage() for command line options.
+//
+// It must be run as root, but will drop to requested UID/GID as soon as it
+// mounts a filesystem.  It will refuse to run if requested UID/GID are zero.
+//
+// Things I believe to be true:
+//
+// - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
+// CREAT) must bump that node's refcount
+// - don't forget that FORGET can forget multiple references (req->nlookup)
+// - if an op that returns a fuse_entry fails writing the reply to the
+// kernel, you must rollback the refcount to reflect the reference the
+// kernel did not actually acquire
+//
+// This daemon can also derive custom filesystem permissions based on directory
+// structure when requested. These custom permissions support several features:
+//
+// - Apps can access their own files in /Android/data/com.example/ without
+// requiring any additional GIDs.
+// - Separate permissions for protecting directories like Pictures and Music.
+// - Multi-user separation on the same physical device.
 
 #include "fuse.h"
 
@@ -121,7 +122,7 @@
 
     int nfd = inotify_init();
     if (nfd < 0) {
-        ERROR("inotify_init failed: %s\n", strerror(errno));
+        PLOG(ERROR) << "inotify_init failed";
         return;
     }
 
@@ -131,12 +132,12 @@
             int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF);
             if (res == -1) {
                 if (errno == ENOENT || errno == EACCES) {
-                    /* Framework may not have created yet, sleep and retry */
-                    ERROR("missing \"%s\"; retrying\n", PACKAGES_LIST_FILE);
+                    /* Framework may not have created the file yet, sleep and retry. */
+                    LOG(ERROR) << "missing \"" << PACKAGES_LIST_FILE << "\"; retrying...";
                     sleep(3);
                     continue;
                 } else {
-                    ERROR("inotify_add_watch failed: %s\n", strerror(errno));
+                    PLOG(ERROR) << "inotify_add_watch failed";
                     return;
                 }
             }
@@ -144,7 +145,7 @@
             /* Watch above will tell us about any future changes, so
              * read the current state. */
             if (read_package_list(global) == false) {
-                ERROR("read_package_list failed\n");
+                LOG(ERROR) << "read_package_list failed";
                 return;
             }
             active = true;
@@ -155,7 +156,7 @@
         if (res < (int) sizeof(*event)) {
             if (errno == EINTR)
                 continue;
-            ERROR("failed to read inotify event: %s\n", strerror(errno));
+            PLOG(ERROR) << "failed to read inotify event";
             return;
         }
 
@@ -182,7 +183,7 @@
 
     fuse->fd = open("/dev/fuse", O_RDWR);
     if (fuse->fd == -1) {
-        ERROR("failed to open fuse device: %s\n", strerror(errno));
+        PLOG(ERROR) << "failed to open fuse device";
         return -1;
     }
 
@@ -193,7 +194,7 @@
             fuse->fd, fuse->global->uid, fuse->global->gid);
     if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
             MS_NOATIME, opts) != 0) {
-        ERROR("failed to mount fuse filesystem: %s\n", strerror(errno));
+        PLOG(ERROR) << "failed to mount fuse filesystem";
         return -1;
     }
 
@@ -285,8 +286,7 @@
         if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
                 || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
                 || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
-            ERROR("failed to fuse_setup\n");
-            exit(1);
+            PLOG(FATAL) << "failed to fuse_setup";
         }
     } else {
         /* Physical storage is readable by all users on device, but
@@ -295,23 +295,19 @@
         if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
                 || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
                 || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
-            ERROR("failed to fuse_setup\n");
-            exit(1);
+            PLOG(FATAL) << "failed to fuse_setup";
         }
     }
 
-    /* Drop privs */
+    /* Drop privs. */
     if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
-        ERROR("cannot setgroups: %s\n", strerror(errno));
-        exit(1);
+        PLOG(FATAL) << "cannot setgroups";
     }
     if (setgid(gid) < 0) {
-        ERROR("cannot setgid: %s\n", strerror(errno));
-        exit(1);
+        PLOG(FATAL) << "cannot setgid";
     }
     if (setuid(uid) < 0) {
-        ERROR("cannot setuid: %s\n", strerror(errno));
-        exit(1);
+        PLOG(FATAL) << "cannot setuid";
     }
 
     if (multi_user) {
@@ -321,23 +317,20 @@
     if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
             || pthread_create(&thread_read, NULL, start_handler, &handler_read)
             || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
-        ERROR("failed to pthread_create\n");
-        exit(1);
+        LOG(FATAL) << "failed to pthread_create";
     }
 
     watch_package_list(&global);
-    ERROR("terminated prematurely\n");
-    exit(1);
+    LOG(FATAL) << "terminated prematurely";
 }
 
 static int usage() {
-    ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
-            "    -u: specify UID to run as\n"
-            "    -g: specify GID to run as\n"
-            "    -U: specify user ID that owns device\n"
-            "    -m: source_path is multi-user\n"
-            "    -w: runtime write mount has full write access\n"
-            "\n");
+    LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>"
+               << "    -u: specify UID to run as"
+               << "    -g: specify GID to run as"
+               << "    -U: specify user ID that owns device"
+               << "    -m: source_path is multi-user"
+               << "    -w: runtime write mount has full write access";
     return 1;
 }
 
@@ -384,32 +377,32 @@
         } else if (!label) {
             label = arg;
         } else {
-            ERROR("too many arguments\n");
+            LOG(ERROR) << "too many arguments";
             return usage();
         }
     }
 
     if (!source_path) {
-        ERROR("no source path specified\n");
+        LOG(ERROR) << "no source path specified";
         return usage();
     }
     if (!label) {
-        ERROR("no label specified\n");
+        LOG(ERROR) << "no label specified";
         return usage();
     }
     if (!uid || !gid) {
-        ERROR("uid and gid must be nonzero\n");
+        LOG(ERROR) << "uid and gid must be nonzero";
         return usage();
     }
 
     rlim.rlim_cur = 8192;
     rlim.rlim_max = 8192;
     if (setrlimit(RLIMIT_NOFILE, &rlim)) {
-        ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
+        PLOG(ERROR) << "setting RLIMIT_NOFILE failed";
     }
 
     while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
-        ERROR("installd fs upgrade not yet complete. Waiting...\n");
+        LOG(ERROR) << "installd fs upgrade not yet complete; waiting...";
         sleep(1);
     }