From 12b128bcdb67f7427c1e216ec6f42c45281bfccf Mon Sep 17 00:00:00 2001 From: Matt Colyer Date: Tue, 7 Oct 2008 09:32:28 -0700 Subject: Initial commit. --- src/Makefile.am | 9 ++ src/ifuse.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 381 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/ifuse.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..67e2806 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,9 @@ +INCLUDES = -I$(top_srcdir)/include + +AM_CFLAGS = $(libglib2_CFLAGS) $(libfuse_CFLAGS) -g +AM_LDFLAGS = $(libglib2_LIBS) $(libfuse_LIBS) -liphone + +bin_PROGRAMS = mount.fuse.ifuse + +mount_fuse_ifuse_SOURCES = ifuse.c +mount_fuse_ifuse_LDADD = libiphone.la diff --git a/src/ifuse.c b/src/ifuse.c new file mode 100644 index 0000000..dff6bbe --- /dev/null +++ b/src/ifuse.c @@ -0,0 +1,372 @@ +/* + * ifuse.c + * A Fuse filesystem which exposes the iPhone's filesystem. + * + * Copyright (c) 2008 Matt Colyer All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FUSE_USE_VERSION 26 + +#include +#include +#include +#include +#include +#include +#include + +#include + +GHashTable *file_handles; +int fh_index = 0; + +iphone_device_t phone = NULL; +iphone_lckd_client_t control = NULL; + +int debug = 0; + +static int ifuse_getattr(const char *path, struct stat *stbuf) +{ + int res = 0; + + iphone_afc_client_t afc = fuse_get_context()->private_data; + iphone_error_t ret = iphone_afc_get_file_attr(afc, path, stbuf); + stbuf->st_dev = 200; + + if (ret != IPHONE_E_SUCCESS) + res = -ENOENT; + + return res; +} + +static int ifuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) +{ + int i; + char **dirs = NULL; + iphone_afc_client_t afc = fuse_get_context()->private_data; + + iphone_afc_get_dir_list(afc, path, &dirs); + + if (!dirs) + return -ENOENT; + + for (i = 0; dirs[i]; i++) { + filler(buf, dirs[i], NULL, 0); + } + + free_dictionary(dirs); + + return 0; +} + +static int ifuse_create(const char *path, mode_t mode, struct fuse_file_info *fi) +{ + // exactly the same as open but using a different mode + iphone_afc_file_t file = NULL; + iphone_afc_client_t afc = fuse_get_context()->private_data; + + iphone_afc_open_file(afc, path, IPHONE_AFC_FILE_WRITE, &file); + fh_index++; + fi->fh = fh_index; + g_hash_table_insert(file_handles, &fh_index, file); + return 0; +} + +static int ifuse_open(const char *path, struct fuse_file_info *fi) +{ + iphone_afc_file_t file = NULL; + iphone_afc_client_t afc = fuse_get_context()->private_data; + uint32_t mode = 0; + + if ((fi->flags & 3) == O_RDWR || (fi->flags & 3) == O_WRONLY) { + mode = IPHONE_AFC_FILE_READ; + } else if ((fi->flags & 3) == O_RDONLY) { + mode = IPHONE_AFC_FILE_READ; + } else { + mode = IPHONE_AFC_FILE_READ; + } + + iphone_afc_open_file(afc, path, mode, &file); + + fh_index++; + fi->fh = fh_index; + g_hash_table_insert(file_handles, &fh_index, file); + + return 0; +} + +static int ifuse_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) +{ + int bytes = 0; + iphone_afc_file_t file; + iphone_afc_client_t afc = fuse_get_context()->private_data; + + if (size == 0) + return 0; + + file = g_hash_table_lookup(file_handles, &(fi->fh)); + if (!file) { + return -ENOENT; + } + + if (IPHONE_E_SUCCESS == iphone_afc_seek_file(afc, file, offset)) + iphone_afc_read_file(afc, file, buf, size, &bytes); + return bytes; +} + +static int ifuse_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) +{ + int bytes = 0; + iphone_afc_file_t file = NULL; + iphone_afc_client_t afc = fuse_get_context()->private_data; + + if (size == 0) + return 0; + + file = g_hash_table_lookup(file_handles, &(fi->fh)); + if (!file) + return -ENOENT; + + if (IPHONE_E_SUCCESS == iphone_afc_seek_file(afc, file, offset)) + iphone_afc_write_file(afc, file, buf, size, &bytes); + return bytes; +} + +static int ifuse_fsync(const char *path, int datasync, struct fuse_file_info *fi) +{ + return 0; +} + +static int ifuse_release(const char *path, struct fuse_file_info *fi) +{ + iphone_afc_file_t file = NULL; + iphone_afc_client_t afc = fuse_get_context()->private_data; + + file = g_hash_table_lookup(file_handles, &(fi->fh)); + if (!file) { + return -ENOENT; + } + iphone_afc_close_file(afc, file); + + g_hash_table_remove(file_handles, &(fi->fh)); + + return 0; +} + +void *ifuse_init_with_service(struct fuse_conn_info *conn, const char *service_name) +{ + int port = 0; + iphone_afc_client_t afc = NULL; + + conn->async_read = 0; + + file_handles = g_hash_table_new(g_int_hash, g_int_equal); + + iphone_get_device(&phone); + if (!phone) { + fprintf(stderr, "No iPhone found, is it connected?\n"); + return NULL; + } + + + if (IPHONE_E_SUCCESS != iphone_lckd_new_client(phone, &control)) { + iphone_free_device(phone); + fprintf(stderr, "Something went wrong in the lockdownd client.\n"); + return NULL; + } + + if (IPHONE_E_SUCCESS == iphone_lckd_start_service(control, service_name, &port) && !port) { + iphone_lckd_free_client(control); + iphone_free_device(phone); + fprintf(stderr, "Something went wrong when starting AFC."); + return NULL; + } + + iphone_afc_new_client(phone, 3432, port, &afc); + + return afc; +} + +void ifuse_cleanup(void *data) +{ + iphone_afc_client_t afc = (iphone_afc_client_t) data; + + iphone_afc_free_client(afc); + iphone_lckd_free_client(control); + iphone_free_device(phone); +} + +int ifuse_flush(const char *path, struct fuse_file_info *fi) +{ + return 0; +} + +int ifuse_statfs(const char *path, struct statvfs *stats) +{ + iphone_afc_client_t afc = fuse_get_context()->private_data; + char **info_raw = NULL; + uint32_t totalspace = 0, freespace = 0, blocksize = 0, i = 0; + + iphone_afc_get_devinfo(afc, &info_raw); + if (!info_raw) + return -ENOENT; + + for (i = 0; info_raw[i]; i++) { + if (!strcmp(info_raw[i], "FSTotalBytes")) { + totalspace = atoi(info_raw[i + 1]); + } else if (!strcmp(info_raw[i], "FSFreeBytes")) { + freespace = atoi(info_raw[i + 1]); + } else if (!strcmp(info_raw[i], "FSBlockSize")) { + blocksize = atoi(info_raw[i + 1]); + } + } + free_dictionary(info_raw); + + // Now to fill the struct. + stats->f_bsize = stats->f_frsize = blocksize; + stats->f_blocks = totalspace / blocksize; // gets the blocks by dividing bytes by blocksize + stats->f_bfree = stats->f_bavail = freespace / blocksize; // all bytes are free to everyone, I guess. + stats->f_namemax = 255; // blah + stats->f_files = stats->f_ffree = 1000000000; // make up any old thing, I guess + return 0; +} + +int ifuse_truncate(const char *path, off_t size) +{ + int result = 0; + iphone_afc_client_t afc = fuse_get_context()->private_data; + iphone_afc_file_t tfile = NULL; + iphone_afc_open_file(afc, path, IPHONE_AFC_FILE_READ, &tfile); + if (!tfile) + return -1; + + result = iphone_afc_truncate_file(afc, tfile, size); + iphone_afc_close_file(afc, tfile); + return result; +} + +int ifuse_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) +{ + iphone_afc_client_t afc = fuse_get_context()->private_data; + iphone_afc_file_t file = g_hash_table_lookup(file_handles, &fi->fh); + if (!file) + return -ENOENT; + + return iphone_afc_truncate_file(afc, file, size); +} + +int ifuse_unlink(const char *path) +{ + iphone_afc_client_t afc = fuse_get_context()->private_data; + if (IPHONE_E_SUCCESS == iphone_afc_delete_file(afc, path)) + return 0; + else + return -1; +} + +int ifuse_rename(const char *from, const char *to) +{ + iphone_afc_client_t afc = fuse_get_context()->private_data; + if (IPHONE_E_SUCCESS == iphone_afc_rename_file(afc, from, to)) + return 0; + else + return -1; +} + +int ifuse_mkdir(const char *dir, mode_t ignored) +{ + iphone_afc_client_t afc = fuse_get_context()->private_data; + if (IPHONE_E_SUCCESS == iphone_afc_mkdir(afc, dir)) + return 0; + else + return -1; +} + +void *ifuse_init(struct fuse_conn_info *conn) +{ + if (ifuse_init_with_service(conn, "com.apple.afc2")){ + return; + }else{ + return ifuse_init_with_service(conn, "com.apple.afc"); + } +} + +static struct fuse_operations ifuse_oper = { + .getattr = ifuse_getattr, + .statfs = ifuse_statfs, + .readdir = ifuse_readdir, + .mkdir = ifuse_mkdir, + .rmdir = ifuse_unlink, // AFC uses the same op for both. + .create = ifuse_create, + .open = ifuse_open, + .read = ifuse_read, + .write = ifuse_write, + .truncate = ifuse_truncate, + .ftruncate = ifuse_ftruncate, + .unlink = ifuse_unlink, + .rename = ifuse_rename, + .fsync = ifuse_fsync, + .release = ifuse_release, + .init = ifuse_init, + .destroy = ifuse_cleanup +}; + +static int ifuse_opt_proc(void *data, const char *arg, int key, + struct fuse_args *outargs) +{ + char *tmp; + static int option_num = 0; + (void) data; + + fprintf(stderr, "%s\n", arg); + switch (key) { + case FUSE_OPT_KEY_OPT: + if (strcmp(arg, "allow_other") == 0) + return 1; + else + return 0; + break; + case FUSE_OPT_KEY_NONOPT: + option_num++; + + // Throw the first nameless option away (the mountpoint) + if (option_num == 1) + return 0; + else + return 1; + } + return 1; +} + +int main(int argc, char *argv[]) +{ + char **ammended_argv; + int i, j; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + + if (fuse_opt_parse(&args, NULL, NULL, ifuse_opt_proc) == -1){ + exit(-1); + } + + //fuse_opt_add_arg(&args, "-o allow_other"); + char *argument = malloc((strlen(argv[1])+ 10) * sizeof(char)); + sprintf(argument, "-ofsname=%s", argv[1]); + fuse_opt_add_arg(&args, argument); + fuse_opt_add_arg(&args, "-osubtype=ifuse"); + + return fuse_main(args.argc, args.argv, &ifuse_oper, NULL); +} -- cgit v1.1-32-gdbae