summaryrefslogtreecommitdiffstats
path: root/sdcard/sdcard.c
diff options
context:
space:
mode:
Diffstat (limited to 'sdcard/sdcard.c')
-rw-r--r--sdcard/sdcard.c156
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;