summaryrefslogtreecommitdiff
path: root/sdcard
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-09-12 09:44:48 -0700
committerJeff Sharkey <jsharkey@android.com>2013-09-20 14:21:09 -0700
commit44d6342caa0db1f613809e9ba1ea8d9af0183b74 (patch)
treeaba3444fdb6ae17f890eb043ec0af72715be3d84 /sdcard
parent7b445a8e3a21055a5735585ca0890d14977032f0 (diff)
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
Diffstat (limited to 'sdcard')
-rw-r--r--sdcard/sdcard.c110
1 files changed, 59 insertions, 51 deletions
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 9a1dd17b7..3f1e268e6 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 @@ static int str_hash(void *key) {
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) {
@@ -401,6 +403,20 @@ static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const s
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 +445,37 @@ static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
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 +521,9 @@ static bool check_caller_access_to_name(struct fuse* fuse,
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 +533,9 @@ static bool check_caller_access_to_name(struct fuse* fuse,
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;
}
@@ -696,9 +713,10 @@ static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
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->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
@@ -706,7 +724,7 @@ static void fuse_init(struct fuse *fuse, int fd, const char *source_path,
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->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 +770,7 @@ static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
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 +995,25 @@ static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
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);
}