summaryrefslogtreecommitdiffstats
path: root/sdcard/sdcard.c
diff options
context:
space:
mode:
Diffstat (limited to 'sdcard/sdcard.c')
-rw-r--r--sdcard/sdcard.c88
1 files changed, 53 insertions, 35 deletions
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 05fbfba..844ca65 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -14,39 +14,41 @@
* limitations under the License.
*/
+#define LOG_TAG "sdcard"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/fuse.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
+#include <sys/inotify.h>
#include <sys/mount.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statfs.h>
-#include <sys/uio.h>
-#include <dirent.h>
-#include <limits.h>
-#include <ctype.h>
-#include <pthread.h>
#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/inotify.h>
+#include <sys/uio.h>
+#include <unistd.h>
#include <cutils/fs.h>
#include <cutils/hashmap.h>
+#include <cutils/log.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
-#include "fuse.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
+ * 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.
@@ -91,12 +93,12 @@
#define FUSE_TRACE 0
#if FUSE_TRACE
-#define TRACE(x...) fprintf(stderr,x)
+#define TRACE(x...) ALOGD(x)
#else
#define TRACE(x...) do {} while (0)
#endif
-#define ERROR(x...) fprintf(stderr,x)
+#define ERROR(x...) ALOGE(x)
#define FUSE_UNKNOWN_INO 0xffffffff
@@ -200,7 +202,7 @@ static bool str_icase_equals(void *keyA, void *keyB) {
}
static int int_hash(void *key) {
- return (int) key;
+ return (int) (uintptr_t) key;
}
static bool int_equals(void *keyA, void *keyB) {
@@ -232,7 +234,7 @@ struct fuse_handler {
* buffer at the same time. This allows us to share the underlying storage. */
union {
__u8 request_buffer[MAX_REQUEST_SIZE];
- __u8 read_buffer[MAX_READ];
+ __u8 read_buffer[MAX_READ + PAGESIZE];
};
};
@@ -487,7 +489,7 @@ static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
break;
case PERM_ANDROID_DATA:
case PERM_ANDROID_OBB:
- appid = (appid_t) hashmapGet(fuse->package_to_appid, node->name);
+ appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
if (appid != 0) {
node->uid = multiuser_get_uid(parent->userid, appid);
}
@@ -511,7 +513,7 @@ static bool get_caller_has_rw_locked(struct fuse* fuse, const struct fuse_in_hea
}
appid_t appid = multiuser_get_app_id(hdr->uid);
- return hashmapContainsKey(fuse->appid_with_rw, (void*) appid);
+ return hashmapContainsKey(fuse->appid_with_rw, (void*) (uintptr_t) appid);
}
/* Kernel has already enforced everything we returned through
@@ -1218,6 +1220,7 @@ static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
__u32 size = req->size;
__u64 offset = req->offset;
int res;
+ __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGESIZE) & ~((uintptr_t)PAGESIZE-1));
/* Don't access any other fields of hdr or req beyond this point, the read buffer
* overlaps the request buffer and will clobber data in the request. This
@@ -1225,14 +1228,14 @@ static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
h, h->fd, size, offset);
- if (size > sizeof(handler->read_buffer)) {
+ if (size > MAX_READ) {
return -EINVAL;
}
- res = pread64(h->fd, handler->read_buffer, size, offset);
+ res = pread64(h->fd, read_buffer, size, offset);
if (res < 0) {
return -errno;
}
- fuse_reply(fuse, unique, handler->read_buffer, res);
+ fuse_reply(fuse, unique, read_buffer, res);
return NO_STATUS;
}
@@ -1243,6 +1246,12 @@ static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
struct fuse_write_out out;
struct handle *h = id_to_ptr(req->fh);
int res;
+ __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGESIZE)));
+
+ if (req->flags & O_DIRECT) {
+ memcpy(aligned_buffer, buffer, req->size);
+ buffer = (const __u8*) aligned_buffer;
+ }
TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
h, h->fd, req->size, req->offset);
@@ -1300,14 +1309,23 @@ static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
{
- int is_data_sync = req->fsync_flags & 1;
- struct handle *h = id_to_ptr(req->fh);
- int res;
+ bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
+ bool is_data_sync = req->fsync_flags & 1;
- TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
- h, h->fd, is_data_sync);
- res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
- if (res < 0) {
+ int fd = -1;
+ if (is_dir) {
+ struct dirhandle *dh = id_to_ptr(req->fh);
+ fd = dirfd(dh->d);
+ } else {
+ struct handle *h = 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);
+ int res = is_data_sync ? fdatasync(fd) : fsync(fd);
+ if (res == -1) {
return -errno;
}
return 0;
@@ -1496,7 +1514,8 @@ static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
return handle_release(fuse, handler, hdr, req);
}
- case FUSE_FSYNC: {
+ case FUSE_FSYNC:
+ case FUSE_FSYNCDIR: {
const struct fuse_fsync_in *req = data;
return handle_fsync(fuse, handler, hdr, req);
}
@@ -1524,7 +1543,6 @@ static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
return handle_releasedir(fuse, handler, hdr, req);
}
-// case FUSE_FSYNCDIR:
case FUSE_INIT: { /* init_in -> init_out */
const struct fuse_init_in *req = data;
return handle_init(fuse, handler, hdr, req);
@@ -1621,12 +1639,12 @@ static int read_package_list(struct fuse *fuse) {
if (sscanf(buf, "%s %d %*d %*s %*s %s", package_name, &appid, gids) == 3) {
char* package_name_dup = strdup(package_name);
- hashmapPut(fuse->package_to_appid, package_name_dup, (void*) appid);
+ hashmapPut(fuse->package_to_appid, package_name_dup, (void*) (uintptr_t) appid);
char* token = strtok(gids, ",");
while (token != NULL) {
if (strtoul(token, NULL, 10) == fuse->write_gid) {
- hashmapPut(fuse->appid_with_rw, (void*) appid, (void*) 1);
+ hashmapPut(fuse->appid_with_rw, (void*) (uintptr_t) appid, (void*) (uintptr_t) 1);
break;
}
token = strtok(NULL, ",");