Add libtar to TWRP instead of using busybox tar
Add proper mkdosfs tool
Add fuse to TWRP
Add experimental exfat-fuse to TWRP
Convert all system() functions to use new Exec_Cmd function
diff --git a/fuse/ulockmgr.c b/fuse/ulockmgr.c
new file mode 100644
index 0000000..4a049d5
--- /dev/null
+++ b/fuse/ulockmgr.c
@@ -0,0 +1,440 @@
+/*
+  libulockmgr: Userspace Lock Manager Library
+  Copyright (C) 2006  Miklos Szeredi <miklos@szeredi.hu>
+
+  This program can be distributed under the terms of the GNU LGPLv2.
+  See the file COPYING.LIB
+*/
+
+/* #define DEBUG 1 */
+
+#include "ulockmgr.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+struct message {
+	unsigned intr : 1;
+	unsigned nofd : 1;
+	pthread_t thr;
+	int cmd;
+	int fd;
+	struct flock lock;
+	int error;
+};
+
+struct fd_store {
+	struct fd_store *next;
+	int fd;
+	int inuse;
+};
+
+struct owner {
+	struct owner *next;
+	struct owner *prev;
+	struct fd_store *fds;
+	void *id;
+	size_t id_len;
+	int cfd;
+};
+
+static pthread_mutex_t ulockmgr_lock;
+static int ulockmgr_cfd = -1;
+static struct owner owner_list = { .next = &owner_list, .prev = &owner_list };
+
+#define MAX_SEND_FDS 2
+
+static void list_del_owner(struct owner *owner)
+{
+	struct owner *prev = owner->prev;
+	struct owner *next = owner->next;
+	prev->next = next;
+	next->prev = prev;
+}
+
+static void list_add_owner(struct owner *owner, struct owner *next)
+{
+	struct owner *prev = next->prev;
+	owner->next = next;
+	owner->prev = prev;
+	prev->next = owner;
+	next->prev = owner;
+}
+
+/*
+ * There's a bug in the linux kernel (< 2.6.22) recv() implementation
+ * on AF_UNIX, SOCK_STREAM sockets, that could cause it to return
+ * zero, even if data was available.  Retrying the recv will return
+ * the data in this case.
+ */
+static int do_recv(int sock, void *buf, size_t len, int flags)
+{
+	int res = recv(sock, buf, len, flags);
+	if (res == 0)
+		res = recv(sock, buf, len, flags);
+
+	return res;
+}
+
+static int ulockmgr_send_message(int sock, void *buf, size_t buflen,
+				 int *fdp, int numfds)
+{
+	struct msghdr msg;
+	struct cmsghdr *p_cmsg;
+	struct iovec vec;
+	size_t cmsgbuf[CMSG_SPACE(sizeof(int) * MAX_SEND_FDS) / sizeof(size_t)];
+	int res;
+
+	assert(numfds <= MAX_SEND_FDS);
+	msg.msg_control = cmsgbuf;
+	msg.msg_controllen = sizeof(cmsgbuf);
+	p_cmsg = CMSG_FIRSTHDR(&msg);
+	p_cmsg->cmsg_level = SOL_SOCKET;
+	p_cmsg->cmsg_type = SCM_RIGHTS;
+	p_cmsg->cmsg_len = CMSG_LEN(sizeof(int) * numfds);
+	memcpy(CMSG_DATA(p_cmsg), fdp, sizeof(int) * numfds);
+	msg.msg_controllen = p_cmsg->cmsg_len;
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+	msg.msg_iov = &vec;
+	msg.msg_iovlen = 1;
+	msg.msg_flags = 0;
+	vec.iov_base = buf;
+	vec.iov_len = buflen;
+	res = sendmsg(sock, &msg, MSG_NOSIGNAL);
+	if (res == -1) {
+		perror("libulockmgr: sendmsg");
+		return -1;
+	}
+	if ((size_t) res != buflen) {
+		fprintf(stderr, "libulockmgr: sendmsg short\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int ulockmgr_start_daemon(void)
+{
+	int sv[2];
+	int res;
+	char tmp[64];
+
+	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+	if (res == -1) {
+		perror("libulockmgr: socketpair");
+		return -1;
+	}
+	snprintf(tmp, sizeof(tmp), "exec ulockmgr_server %i", sv[0]);
+	res = system(tmp);
+	close(sv[0]);
+	if (res == -1 || !WIFEXITED(res) || WEXITSTATUS(res) != 0) {
+		close(sv[1]);
+		return -1;
+	}
+	ulockmgr_cfd = sv[1];
+	return 0;
+}
+
+static struct owner *ulockmgr_new_owner(const void *id, size_t id_len)
+{
+	int sv[2];
+	int res;
+	char c = 'm';
+	struct owner *o;
+
+	if (ulockmgr_cfd == -1 && ulockmgr_start_daemon() == -1)
+		return NULL;
+
+	o = calloc(1, sizeof(struct owner) + id_len);
+	if (!o) {
+		fprintf(stderr, "libulockmgr: failed to allocate memory\n");
+		return NULL;
+	}
+	o->id = o + 1;
+	o->id_len = id_len;
+	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+	if (res == -1) {
+		perror("libulockmgr: socketpair");
+		goto out_free;
+	}
+	res = ulockmgr_send_message(ulockmgr_cfd, &c, sizeof(c), &sv[0], 1);
+	close(sv[0]);
+	if (res == -1) {
+		close(ulockmgr_cfd);
+		ulockmgr_cfd = -1;
+		goto out_close;
+	}
+
+	o->cfd = sv[1];
+	memcpy(o->id, id, id_len);
+	list_add_owner(o, &owner_list);
+
+	return o;
+
+out_close:
+	close(sv[1]);
+out_free:
+	free(o);
+	return NULL;
+}
+
+static int ulockmgr_send_request(struct message *msg, const void *id,
+				 size_t id_len)
+{
+	int sv[2];
+	int cfd;
+	struct owner *o;
+	struct fd_store *f = NULL;
+	struct fd_store *newf = NULL;
+	struct fd_store **fp;
+	int fd = msg->fd;
+	int cmd = msg->cmd;
+	int res;
+	int unlockall = (cmd == F_SETLK && msg->lock.l_type == F_UNLCK &&
+			 msg->lock.l_start == 0 && msg->lock.l_len == 0);
+
+	for (o = owner_list.next; o != &owner_list; o = o->next)
+		if (o->id_len == id_len && memcmp(o->id, id, id_len) == 0)
+			break;
+
+	if (o == &owner_list)
+		o = NULL;
+
+	if (!o && cmd != F_GETLK && msg->lock.l_type != F_UNLCK)
+		o = ulockmgr_new_owner(id, id_len);
+
+	if (!o) {
+		if (cmd == F_GETLK) {
+			res = fcntl(msg->fd, F_GETLK, &msg->lock);
+			return (res == -1) ? -errno : 0;
+		} else if (msg->lock.l_type == F_UNLCK)
+			return 0;
+		else
+			return -ENOLCK;
+	}
+
+	if (unlockall)
+		msg->nofd = 1;
+	else {
+		for (fp = &o->fds; *fp; fp = &(*fp)->next) {
+			f = *fp;
+			if (f->fd == fd) {
+				msg->nofd = 1;
+				break;
+			}
+		}
+	}
+
+	if (!msg->nofd) {
+		newf = f = calloc(1, sizeof(struct fd_store));
+		if (!f) {
+			fprintf(stderr, "libulockmgr: failed to allocate memory\n");
+			return -ENOLCK;
+		}
+	}
+
+	res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+	if (res == -1) {
+		perror("libulockmgr: socketpair");
+		free(newf);
+		return -ENOLCK;
+	}
+
+	cfd = sv[1];
+	sv[1] = msg->fd;
+	res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
+				    msg->nofd ? 1 : 2);
+	close(sv[0]);
+	if (res == -1) {
+		free(newf);
+		close(cfd);
+		return -EIO;
+	}
+
+	if (newf) {
+		newf->fd = msg->fd;
+		newf->next = o->fds;
+		o->fds = newf;
+	}
+	if (f)
+		f->inuse++;
+
+	res = do_recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
+	if (res == -1) {
+		perror("libulockmgr: recv");
+		msg->error = EIO;
+	} else if (res != sizeof(struct message)) {
+		fprintf(stderr, "libulockmgr: recv short\n");
+		msg->error = EIO;
+	} else if (cmd == F_SETLKW && msg->error == EAGAIN) {
+		pthread_mutex_unlock(&ulockmgr_lock);
+		while (1) {
+			sigset_t old;
+			sigset_t unblock;
+			int errno_save;
+
+			sigemptyset(&unblock);
+			sigaddset(&unblock, SIGUSR1);
+			pthread_sigmask(SIG_UNBLOCK, &unblock, &old);
+			res = do_recv(cfd, msg, sizeof(struct message),
+				      MSG_WAITALL);
+			errno_save = errno;
+			pthread_sigmask(SIG_SETMASK, &old, NULL);
+			if (res == sizeof(struct message))
+				break;
+			else if (res >= 0) {
+				fprintf(stderr, "libulockmgr: recv short\n");
+				msg->error = EIO;
+				break;
+			} else if (errno_save != EINTR) {
+				errno = errno_save;
+				perror("libulockmgr: recv");
+				msg->error = EIO;
+				break;
+			}
+			msg->intr = 1;
+			res = send(o->cfd, msg, sizeof(struct message),
+				   MSG_NOSIGNAL);
+			if (res == -1) {
+				perror("libulockmgr: send");
+				msg->error = EIO;
+				break;
+			}
+			if (res != sizeof(struct message)) {
+				fprintf(stderr, "libulockmgr: send short\n");
+				msg->error = EIO;
+				break;
+			}
+		}
+		pthread_mutex_lock(&ulockmgr_lock);
+
+	}
+	if (f)
+		f->inuse--;
+	close(cfd);
+	if (unlockall) {
+		for (fp = &o->fds; *fp;) {
+			f = *fp;
+			if (f->fd == fd && !f->inuse) {
+				*fp = f->next;
+				free(f);
+			} else
+				fp = &f->next;
+		}
+		if (!o->fds) {
+			list_del_owner(o);
+			close(o->cfd);
+			free(o);
+		}
+		/* Force OK on unlock-all, since it _will_ succeed once the
+		   owner is deleted */
+		msg->error = 0;
+	}
+
+	return -msg->error;
+}
+
+#ifdef DEBUG
+static uint32_t owner_hash(const unsigned char *id, size_t id_len)
+{
+	uint32_t h = 0;
+	size_t i;
+	for (i = 0; i < id_len; i++)
+		h = ((h << 8) | (h >> 24)) ^ id[i];
+
+	return h;
+}
+#endif
+
+static int ulockmgr_canonicalize(int fd, struct flock *lock)
+{
+	off64_t offset;
+	if (lock->l_whence == SEEK_CUR) {
+		offset = lseek(fd, 0, SEEK_CUR);
+		if (offset == (off64_t) -1)
+			return -errno;
+	} else if (lock->l_whence == SEEK_END) {
+		struct stat stbuf;
+		int res = fstat(fd, &stbuf);
+		if (res == -1)
+			return -errno;
+
+		offset = stbuf.st_size;
+	} else
+		offset = 0;
+
+	lock->l_whence = SEEK_SET;
+	lock->l_start += offset;
+
+	if (lock->l_start < 0)
+		return -EINVAL;
+
+	if (lock->l_len < 0) {
+		lock->l_start += lock->l_len;
+		if (lock->l_start < 0)
+			return -EINVAL;
+		lock->l_len = -lock->l_len;
+	}
+	if (lock->l_len && lock->l_start + lock->l_len - 1 < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+int ulockmgr_op(int fd, int cmd, struct flock *lock, const void *owner,
+		size_t owner_len)
+{
+	int err;
+	struct message msg;
+	sigset_t old;
+	sigset_t block;
+
+	if (cmd != F_GETLK && cmd != F_SETLK && cmd != F_SETLKW)
+		return -EINVAL;
+
+	if (lock->l_whence != SEEK_SET && lock->l_whence != SEEK_CUR &&
+	    lock->l_whence != SEEK_END)
+		return -EINVAL;
+
+#ifdef DEBUG
+	fprintf(stderr, "libulockmgr: %i %i %i %lli %lli own: 0x%08x\n",
+		cmd, lock->l_type, lock->l_whence, lock->l_start, lock->l_len,
+		owner_hash(owner, owner_len));
+#endif
+
+	/* Unlock should never block anyway */
+	if (cmd == F_SETLKW && lock->l_type == F_UNLCK)
+		cmd = F_SETLK;
+
+	memset(&msg, 0, sizeof(struct message));
+	msg.cmd = cmd;
+	msg.fd = fd;
+	msg.lock = *lock;
+	err = ulockmgr_canonicalize(fd, &msg.lock);
+	if (err)
+		return err;
+
+	sigemptyset(&block);
+	sigaddset(&block, SIGUSR1);
+	pthread_sigmask(SIG_BLOCK, &block, &old);
+	pthread_mutex_lock(&ulockmgr_lock);
+	err = ulockmgr_send_request(&msg, owner, owner_len);
+	pthread_mutex_unlock(&ulockmgr_lock);
+	pthread_sigmask(SIG_SETMASK, &old, NULL);
+	if (!err && cmd == F_GETLK) {
+		if (msg.lock.l_type == F_UNLCK)
+			lock->l_type = F_UNLCK;
+		else
+			*lock = msg.lock;
+	}
+
+	return err;
+}