diff options
Diffstat (limited to 'sdcard/sdcard.c')
-rw-r--r-- | sdcard/sdcard.c | 88 |
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, ","); |