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;
}