diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 9 | ||||
| -rw-r--r-- | src/ifuse.c | 372 | 
2 files changed, 381 insertions, 0 deletions
| 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 <fuse.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <glib.h> +#include <unistd.h> + +#include <libiphone/libiphone.h> + +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); +} | 
