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/libtar/libtar_list.c b/libtar/libtar_list.c
new file mode 100644
index 0000000..2c5febb
--- /dev/null
+++ b/libtar/libtar_list.c
@@ -0,0 +1,458 @@
+/* listhash/libtar_list.c.  Generated from list.c.in by configure. */
+
+/*
+**  Copyright 1998-2002 University of Illinois Board of Trustees
+**  Copyright 1998-2002 Mark D. Roth
+**  All rights reserved.
+**
+**  libtar_list.c - linked list routines
+**
+**  Mark D. Roth <roth@uiuc.edu>
+**  Campus Information Technologies and Educational Services
+**  University of Illinois at Urbana-Champaign
+*/
+
+#include <config.h>
+#include <compat.h>
+
+#include <libtar_listhash.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+
+/*
+** libtar_listptr_reset() - reset a list pointer
+*/
+void
+libtar_listptr_reset(libtar_listptr_t *lp)
+{
+	*lp = NULL;
+}
+
+
+/*
+** libtar_listptr_data() - retrieve the data pointed to by lp
+*/
+void *
+libtar_listptr_data(libtar_listptr_t *lp)
+{
+	return (*lp)->data;
+}
+
+
+/*
+** libtar_list_new() - create a new, empty list
+*/
+libtar_list_t *
+libtar_list_new(int flags, libtar_cmpfunc_t cmpfunc)
+{
+	libtar_list_t *newlist;
+
+#ifdef DS_DEBUG
+	printf("in libtar_list_new(%d, 0x%lx)\n", flags, cmpfunc);
+#endif
+
+	if (flags != LIST_USERFUNC
+	    && flags != LIST_STACK
+	    && flags != LIST_QUEUE)
+	{
+		errno = EINVAL;
+		return NULL;
+	}
+
+	newlist = (libtar_list_t *)calloc(1, sizeof(libtar_list_t));
+	if (cmpfunc != NULL)
+		newlist->cmpfunc = cmpfunc;
+	else
+		newlist->cmpfunc = (libtar_cmpfunc_t)strcmp;
+	newlist->flags = flags;
+
+	return newlist;
+}
+
+
+/*
+** libtar_list_iterate() - call a function for every element
+**				      in a list
+*/
+int
+libtar_list_iterate(libtar_list_t *l,
+			       libtar_iterate_func_t plugin,
+			       void *state)
+{
+	libtar_listptr_t n;
+
+	if (l == NULL)
+		return -1;
+
+	for (n = l->first; n != NULL; n = n->next)
+	{
+		if ((*plugin)(n->data, state) == -1)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+** libtar_list_empty() - empty the list
+*/
+void
+libtar_list_empty(libtar_list_t *l, libtar_freefunc_t freefunc)
+{
+	libtar_listptr_t n;
+
+	for (n = l->first; n != NULL; n = l->first)
+	{
+		l->first = n->next;
+		if (freefunc != NULL)
+			(*freefunc)(n->data);
+		free(n);
+	}
+
+	l->nents = 0;
+}
+
+
+/*
+** libtar_list_free() - remove and free() the whole list
+*/
+void
+libtar_list_free(libtar_list_t *l, libtar_freefunc_t freefunc)
+{
+	libtar_list_empty(l, freefunc);
+	free(l);
+}
+
+
+/*
+** libtar_list_nents() - return number of elements in the list
+*/
+unsigned int
+libtar_list_nents(libtar_list_t *l)
+{
+	return l->nents;
+}
+
+
+/*
+** libtar_list_add() - adds an element to the list
+** returns:
+**	0			success
+**	-1 (and sets errno)	failure
+*/
+int
+libtar_list_add(libtar_list_t *l, void *data)
+{
+	libtar_listptr_t n, m;
+
+#ifdef DS_DEBUG
+	printf("==> libtar_list_add(\"%s\")\n", (char *)data);
+#endif
+
+	n = (libtar_listptr_t)malloc(sizeof(struct libtar_node));
+	if (n == NULL)
+		return -1;
+	n->data = data;
+	l->nents++;
+
+#ifdef DS_DEBUG
+	printf("    libtar_list_add(): allocated data\n");
+#endif
+
+	/* if the list is empty */
+	if (l->first == NULL)
+	{
+		l->last = l->first = n;
+		n->next = n->prev = NULL;
+#ifdef DS_DEBUG
+		printf("<== libtar_list_add(): list was empty; "
+		       "added first element and returning 0\n");
+#endif
+		return 0;
+	}
+
+#ifdef DS_DEBUG
+	printf("    libtar_list_add(): list not empty\n");
+#endif
+
+	if (l->flags == LIST_STACK)
+	{
+		n->prev = NULL;
+		n->next = l->first;
+		if (l->first != NULL)
+			l->first->prev = n;
+		l->first = n;
+#ifdef DS_DEBUG
+		printf("<== libtar_list_add(): LIST_STACK set; "
+		       "added in front\n");
+#endif
+		return 0;
+	}
+
+	if (l->flags == LIST_QUEUE)
+	{
+		n->prev = l->last;
+		n->next = NULL;
+		if (l->last != NULL)
+			l->last->next = n;
+		l->last = n;
+#ifdef DS_DEBUG
+		printf("<== libtar_list_add(): LIST_QUEUE set; "
+		       "added at end\n");
+#endif
+		return 0;
+	}
+
+	for (m = l->first; m != NULL; m = m->next)
+		if ((*(l->cmpfunc))(data, m->data) < 0)
+		{
+			/*
+			** if we find one that's bigger,
+			** insert data before it
+			*/
+#ifdef DS_DEBUG
+			printf("    libtar_list_add(): gotcha..."
+			       "inserting data\n");
+#endif
+			if (m == l->first)
+			{
+				l->first = n;
+				n->prev = NULL;
+				m->prev = n;
+				n->next = m;
+#ifdef DS_DEBUG
+				printf("<== libtar_list_add(): "
+				       "added first, returning 0\n");
+#endif
+				return 0;
+			}
+			m->prev->next = n;
+			n->prev = m->prev;
+			m->prev = n;
+			n->next = m;
+#ifdef DS_DEBUG
+			printf("<== libtar_list_add(): added middle,"
+			       " returning 0\n");
+#endif
+			return 0;
+		}
+
+#ifdef DS_DEBUG
+	printf("    libtar_list_add(): new data larger than current "
+	       "list elements\n");
+#endif
+
+	/* if we get here, data is bigger than everything in the list */
+	l->last->next = n;
+	n->prev = l->last;
+	l->last = n;
+	n->next = NULL;
+#ifdef DS_DEBUG
+	printf("<== libtar_list_add(): added end, returning 0\n");
+#endif
+	return 0;
+}
+
+
+/*
+** libtar_list_del() - remove the element pointed to by n
+**				  from the list l
+*/
+void
+libtar_list_del(libtar_list_t *l, libtar_listptr_t *n)
+{
+	libtar_listptr_t m;
+
+#ifdef DS_DEBUG
+	printf("==> libtar_list_del()\n");
+#endif
+
+	l->nents--;
+
+	m = (*n)->next;
+
+	if ((*n)->prev)
+		(*n)->prev->next = (*n)->next;
+	else
+		l->first = (*n)->next;
+	if ((*n)->next)
+		(*n)->next->prev = (*n)->prev;
+	else
+		l->last = (*n)->prev;
+
+	free(*n);
+	*n = m;
+}
+
+
+/*
+** libtar_list_next() - get the next element in the list
+** returns:
+**	1			success
+**	0			end of list
+*/
+int
+libtar_list_next(libtar_list_t *l,
+			    libtar_listptr_t *n)
+{
+	if (*n == NULL)
+		*n = l->first;
+	else
+		*n = (*n)->next;
+
+	return (*n != NULL ? 1 : 0);
+}
+
+
+/*
+** libtar_list_prev() - get the previous element in the list
+** returns:
+**	1			success
+**	0			end of list
+*/
+int
+libtar_list_prev(libtar_list_t *l,
+			    libtar_listptr_t *n)
+{
+	if (*n == NULL)
+		*n = l->last;
+	else
+		*n = (*n)->prev;
+
+	return (*n != NULL ? 1 : 0);
+}
+
+
+/*
+** libtar_str_match() - string matching function
+** returns:
+**	1			match
+**	0			no match
+*/
+int
+libtar_str_match(char *check, char *data)
+{
+	return !strcmp(check, data);
+}
+
+
+/*
+** libtar_list_add_str() - splits string str into delim-delimited
+**				      elements and adds them to list l
+** returns:
+**	0			success
+**	-1 (and sets errno)	failure
+*/
+int
+libtar_list_add_str(libtar_list_t *l,
+			       char *str, char *delim)
+{
+	char tmp[10240];
+	char *tokp, *nextp = tmp;
+
+	strlcpy(tmp, str, sizeof(tmp));
+	while ((tokp = strsep(&nextp, delim)) != NULL)
+	{
+		if (*tokp == '\0')
+			continue;
+		if (libtar_list_add(l, strdup(tokp)))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+/*
+** libtar_list_search() - find an entry in a list
+** returns:
+**	1			match found
+**	0			no match
+*/
+int
+libtar_list_search(libtar_list_t *l,
+			      libtar_listptr_t *n, void *data,
+			      libtar_matchfunc_t matchfunc)
+{
+#ifdef DS_DEBUG
+	printf("==> libtar_list_search(l=0x%lx, n=0x%lx, \"%s\")\n",
+	       l, n, (char *)data);
+#endif
+
+	if (matchfunc == NULL)
+		matchfunc = (libtar_matchfunc_t)libtar_str_match;
+
+	if (*n == NULL)
+		*n = l->first;
+	else
+		*n = (*n)->next;
+
+	for (; *n != NULL; *n = (*n)->next)
+	{
+#ifdef DS_DEBUG
+		printf("checking against \"%s\"\n", (char *)(*n)->data);
+#endif
+		if ((*(matchfunc))(data, (*n)->data) != 0)
+			return 1;
+	}
+
+#ifdef DS_DEBUG
+	printf("no matches found\n");
+#endif
+	return 0;
+}
+
+
+/*
+** libtar_list_dup() - copy an existing list
+*/
+libtar_list_t *
+libtar_list_dup(libtar_list_t *l)
+{
+	libtar_list_t *newlist;
+	libtar_listptr_t n;
+
+	newlist = libtar_list_new(l->flags, l->cmpfunc);
+	for (n = l->first; n != NULL; n = n->next)
+		libtar_list_add(newlist, n->data);
+
+#ifdef DS_DEBUG
+	printf("returning from libtar_list_dup()\n");
+#endif
+	return newlist;
+}
+
+
+/*
+** libtar_list_merge() - merge two lists into a new list
+*/
+libtar_list_t *
+libtar_list_merge(libtar_cmpfunc_t cmpfunc, int flags,
+			     libtar_list_t *list1,
+			     libtar_list_t *list2)
+{
+	libtar_list_t *newlist;
+	libtar_listptr_t n;
+
+	newlist = libtar_list_new(flags, cmpfunc);
+
+	n = NULL;
+	while (libtar_list_next(list1, &n) != 0)
+		libtar_list_add(newlist, n->data);
+	n = NULL;
+	while (libtar_list_next(list2, &n) != 0)
+		libtar_list_add(newlist, n->data);
+
+	return newlist;
+}
+
+