diff options
Diffstat (limited to 'sdcard/sdcard.c')
| -rw-r--r-- | sdcard/sdcard.c | 156 |
1 files changed, 141 insertions, 15 deletions
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 9dda0ea..21a44ce 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -25,6 +25,7 @@ #include <sys/statfs.h> #include <sys/uio.h> #include <dirent.h> +#include <ctype.h> #include <private/android_filesystem_config.h> @@ -108,6 +109,11 @@ struct fuse { char rootpath[1024]; }; +/* true if file names should be squashed to lower case */ +static int force_lower_case = 0; +static unsigned uid = -1; +static unsigned gid = -1; + #define PATH_BUFFER_SIZE 1024 /* @@ -442,6 +448,84 @@ void lookup_entry(struct fuse *fuse, struct node *node, fuse_reply(fuse, unique, &out, sizeof(out)); } +static int name_needs_normalizing(const char* name) { + char ch; + while ((ch = *name++) != 0) { + if (ch != tolower(ch)) + return 1; + } + return 0; +} + +static void normalize_name(char *name) +{ + if (force_lower_case) { + char ch; + while ((ch = *name) != 0) + *name++ = tolower(ch); + } +} + +static void recursive_fix_files(const char* path) { + DIR* dir; + struct dirent* entry; + char pathbuf[PATH_MAX]; + char oldpath[PATH_MAX]; + int pathLength = strlen(path); + int pathRemaining; + char* fileSpot; + + if (pathLength >= sizeof(pathbuf) - 1) { + ERROR("path too long: %s\n", path); + return; + } + strcpy(pathbuf, path); + if (pathbuf[pathLength - 1] != '/') { + pathbuf[pathLength++] = '/'; + } + fileSpot = pathbuf + pathLength; + pathRemaining = sizeof(pathbuf) - pathLength - 1; + + dir = opendir(path); + if (!dir) { + ERROR("opendir %s failed: %s", path, strerror(errno)); + return; + } + + while ((entry = readdir(dir))) { + const char* name = entry->d_name; + int nameLength; + + // ignore "." and ".." + if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { + continue; + } + + nameLength = strlen(name); + if (nameLength > pathRemaining) { + ERROR("path %s/%s too long\n", path, name); + continue; + } + strcpy(fileSpot, name); + + // make sure owner and group are correct + chown(pathbuf, uid, gid); + + if (name_needs_normalizing(name)) { + /* rename file to lower case file name */ + strlcpy(oldpath, pathbuf, sizeof(oldpath)); + normalize_name(pathbuf); + rename(oldpath, pathbuf); + } + + if (entry->d_type == DT_DIR) { + /* recurse to subdirectories */ + recursive_fix_files(pathbuf); + } + } + closedir(dir); +} + void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *data, unsigned len) { struct node *node; @@ -465,6 +549,7 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da switch (hdr->opcode) { case FUSE_LOOKUP: { /* bytez[] -> entry_out */ + normalize_name((char*) data); TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data); lookup_entry(fuse, node, (char*) data, hdr->unique); return; @@ -523,6 +608,9 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da char *path, buffer[PATH_BUFFER_SIZE]; char *name = ((char*) data) + sizeof(*req); int res; + + normalize_name(name); + TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid); path = node_get_path(node, buffer, name); @@ -541,6 +629,9 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da char *path, buffer[PATH_BUFFER_SIZE]; char *name = ((char*) data) + sizeof(*req); int res; + + normalize_name(name); + TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode); path = node_get_path(node, buffer, name); @@ -556,6 +647,7 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da case FUSE_UNLINK: { /* bytez[] -> */ char *path, buffer[PATH_BUFFER_SIZE]; int res; + normalize_name((char*) data); TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid); path = node_get_path(node, buffer, (char*) data); res = unlink(path); @@ -565,6 +657,7 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da case FUSE_RMDIR: { /* bytez[] -> */ char *path, buffer[PATH_BUFFER_SIZE]; int res; + normalize_name((char*) data); TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid); path = node_get_path(node, buffer, (char*) data); res = rmdir(path); @@ -581,6 +674,9 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da struct node *newparent; int res; + normalize_name(oldname); + normalize_name(newname); + TRACE("RENAME %s->%s @ %llx\n", oldname, newname, hdr->nodeid); target = lookup_child_by_name(node, oldname); @@ -627,6 +723,7 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da return; } + normalize_name(buffer); path = node_get_path(node, buffer, 0); TRACE("OPEN %llx '%s' 0%o fh=%p\n", hdr->nodeid, path, req->flags, h); h->fd = open(path, req->flags); @@ -652,7 +749,7 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da fuse_status(fuse, hdr->unique, -EINVAL); return; } - res = pread(h->fd, buffer, req->size, req->offset); + res = pread64(h->fd, buffer, req->size, req->offset); if (res < 0) { fuse_status(fuse, hdr->unique, errno); return; @@ -666,7 +763,7 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da struct handle *h = id_to_ptr(req->fh); int res; TRACE("WRITE %p(%d) %u@%llu\n", h, h->fd, req->size, req->offset); - res = pwrite(h->fd, ((char*) data) + sizeof(*req), req->size, req->offset); + res = pwrite64(h->fd, ((char*) data) + sizeof(*req), req->size, req->offset); if (res < 0) { fuse_status(fuse, hdr->unique, errno); return; @@ -728,6 +825,7 @@ void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *da return; } + normalize_name(buffer); path = node_get_path(node, buffer, 0); TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path); h->d = opendir(path); @@ -822,30 +920,55 @@ void handle_fuse_requests(struct fuse *fuse) } } +static int usage() +{ + ERROR("usage: sdcard [-l -f] <path> <uid> <gid>\n\n\t-l force file names to lower case when creating new files\n\t-f fix up file system before starting (repairs bad file name case and group ownership)\n"); + return -1; +} + int main(int argc, char **argv) { struct fuse fuse; char opts[256]; int fd; int res; - unsigned uid; - unsigned gid; - const char *path; - - if (argc != 4) { - ERROR("usage: sdcard <path> <uid> <gid>\n"); - return -1; + const char *path = NULL; + int fix_files = 0; + int i; + + for (i = 1; i < argc; i++) { + char* arg = argv[i]; + if (arg[0] == '-') { + if (!strcmp(arg, "-l")) { + force_lower_case = 1; + } else if (!strcmp(arg, "-f")) { + fix_files = 1; + } else { + return usage(); + } + } else { + if (!path) + path = arg; + else if (uid == -1) + uid = strtoul(arg, 0, 10); + else if (gid == -1) + gid = strtoul(arg, 0, 10); + else { + ERROR("too many arguments\n"); + return usage(); + } + } } - uid = strtoul(argv[2], 0, 10); - gid = strtoul(argv[3], 0, 10); - if (!uid || !gid) { + if (!path) { + ERROR("no path specified\n"); + return usage(); + } + if (uid <= 0 || gid <= 0) { ERROR("uid and gid must be nonzero\n"); - return -1; + return usage(); } - path = argv[1]; - /* cleanup from previous instance, if necessary */ umount2(MOUNT_POINT, 2); @@ -864,6 +987,9 @@ int main(int argc, char **argv) return -1; } + if (fix_files) + recursive_fix_files(path); + if (setgid(gid) < 0) { ERROR("cannot setgid!\n"); return -1; |
