All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] UBIFS unpacker v0
@ 2015-10-31 11:15 Richard Weinberger
  2015-10-31 11:15 ` [PATCH 01/11] ubifs: add complete version of list.h Richard Weinberger
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst

Hi!

This is the first public release of the UBIFS unpack tool.
Using this tool you can unpack an UBIFS to a local directory,
it can operate directly on UBI volumes (i.e. /dev/ubiX_Y)
or nanddumps (without OOB!). If you dump from a nandump,
you have to specify the UBI volume ID you want to dump from.
So far it is rather strict and refuses to unpack if the filesystem
is corrupted. We plan to implement also a "fuzzy unpack" mode.

The patches apply on Yang's mtd-utils restructure work.

Thanks,
//richard

David Gstir (10):
      ubifs: fix typo in ubifs_read
      Make cli byte parsing from ubi-utils available for all tools
      ubifs: add decompression functions
      ubifs: remove ununsed ubifs context from key helpers
      ubifs: keep scan buffer in ubifs_info
      ubifs: extend master scanning code
      ubifs: add missing include to defs.h
      ubifs: Add more key helper functions
      ubifs: add emubi, a minimal UBI emulation layer
      ubifs: add ubifs_unpack

Richard Weinberger (1):
      ubifs: add complete version of list.h

 Makefile                                |  11 +-
 include/common.h                        |  90 ++++
 ubi-utils/include/ubiutils-common.h     |   2 -
 ubi-utils/mtdinfo.c                     |   6 +-
 ubi-utils/ubiattach.c                   |   6 +-
 ubi-utils/ubiformat.c                   |   8 +-
 ubi-utils/ubimkvol.c                    |   6 +-
 ubi-utils/ubinfo.c                      |  10 +-
 ubi-utils/ubinize.c                     |  10 +-
 ubi-utils/ubirsvol.c                    |   2 +-
 ubi-utils/ubiutils-common.c             |  93 ----
 ubifs-utils/include/compr.h             |   1 +
 ubifs-utils/include/defs.h              |   1 +
 ubifs-utils/include/emubi.h             |  82 +++
 ubifs-utils/include/io.h                |   2 +
 ubifs-utils/include/key.h               | 102 +++-
 ubifs-utils/include/list.h              | 305 +++++++----
 ubifs-utils/include/list_sort.h         |  11 +
 ubifs-utils/include/master.h            |   7 +
 ubifs-utils/include/ubifs.h             |  62 +++
 ubifs-utils/lib/compr.c                 |  75 +++
 ubifs-utils/lib/emubi.c                 | 371 ++++++++++++++
 ubifs-utils/lib/io.c                    |  65 ++-
 ubifs-utils/lib/list_sort.c             | 157 ++++++
 ubifs-utils/lib/master.c                | 311 ++++++++++++
 ubifs-utils/lib/scan.c                  |  20 +-
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c     |  66 +--
 ubifs-utils/ubifs_dump/ubifs_dump.c     |  89 +---
 ubifs-utils/ubifs_unpack/index.c        | 648 ++++++++++++++++++++++++
 ubifs-utils/ubifs_unpack/replay.c       | 865 ++++++++++++++++++++++++++++++++
 ubifs-utils/ubifs_unpack/ubifs_unpack.c | 619 +++++++++++++++++++++++
 ubifs-utils/ubifs_unpack/ubifs_unpack.h | 107 ++++
 32 files changed, 3832 insertions(+), 378 deletions(-)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 01/11] ubifs: add complete version of list.h
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 02/11] ubifs: fix typo in ubifs_read Richard Weinberger
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

See http://lists.infradead.org/pipermail/linux-mtd/2015-October/062421.html

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/include/list.h | 305 +++++++++++++++++++++++++++++++--------------
 1 file changed, 213 insertions(+), 92 deletions(-)

diff --git a/ubifs-utils/include/list.h b/ubifs-utils/include/list.h
index 0cffa33..080ea39 100644
--- a/ubifs-utils/include/list.h
+++ b/ubifs-utils/include/list.h
@@ -17,6 +17,10 @@
 #ifndef _LINUX_LIST_H
 #define _LINUX_LIST_H
 
+struct list_head {
+	struct list_head *next, *prev;
+};
+
 #define LIST_POISON1  ((struct list_head *) 0x00100100)
 #define LIST_POISON2  ((struct list_head *) 0x00200200)
 
@@ -30,10 +34,6 @@
  * using the generic single-entry routines.
  */
 
-struct list_head {
-	struct list_head *next, *prev;
-};
-
 #define LIST_HEAD_INIT(name) { &(name), &(name) }
 
 #define LIST_HEAD(name) \
@@ -52,17 +52,17 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
  * the prev/next entries already!
  */
 #ifndef CONFIG_DEBUG_LIST
-static inline void __list_add(struct list_head *xnew,
+static inline void __list_add(struct list_head *new,
 			      struct list_head *prev,
 			      struct list_head *next)
 {
-	next->prev = xnew;
-	xnew->next = next;
-	xnew->prev = prev;
-	prev->next = xnew;
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
 }
 #else
-extern void __list_add(struct list_head *xnew,
+extern void __list_add(struct list_head *new,
 			      struct list_head *prev,
 			      struct list_head *next);
 #endif
@@ -75,14 +75,10 @@ extern void __list_add(struct list_head *xnew,
  * Insert a new entry after the specified head.
  * This is good for implementing stacks.
  */
-#ifndef CONFIG_DEBUG_LIST
-static inline void list_add(struct list_head *xnew, struct list_head *head)
+static inline void list_add(struct list_head *new, struct list_head *head)
 {
-	__list_add(xnew, head, head->next);
+	__list_add(new, head, head->next);
 }
-#else
-extern void list_add(struct list_head *xnew, struct list_head *head);
-#endif
 
 
 /**
@@ -93,9 +89,9 @@ extern void list_add(struct list_head *xnew, struct list_head *head);
  * Insert a new entry before the specified head.
  * This is useful for implementing queues.
  */
-static inline void list_add_tail(struct list_head *xnew, struct list_head *head)
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
 {
-	__list_add(xnew, head->prev, head);
+	__list_add(new, head->prev, head);
 }
 
 /*
@@ -114,10 +110,15 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
 /**
  * list_del - deletes entry from list.
  * @entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is
+ * Note: list_empty() on entry does not return true after this, the entry is
  * in an undefined state.
  */
 #ifndef CONFIG_DEBUG_LIST
+static inline void __list_del_entry(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
 static inline void list_del(struct list_head *entry)
 {
 	__list_del(entry->prev, entry->next);
@@ -125,6 +126,7 @@ static inline void list_del(struct list_head *entry)
 	entry->prev = LIST_POISON2;
 }
 #else
+extern void __list_del_entry(struct list_head *entry);
 extern void list_del(struct list_head *entry);
 #endif
 
@@ -132,30 +134,32 @@ extern void list_del(struct list_head *entry);
  * list_replace - replace old entry by new one
  * @old : the element to be replaced
  * @new : the new element to insert
- * Note: if 'old' was empty, it will be overwritten.
+ *
+ * If @old was empty, it will be overwritten.
  */
 static inline void list_replace(struct list_head *old,
-				struct list_head *xnew)
+				struct list_head *new)
 {
-	xnew->next = old->next;
-	xnew->next->prev = xnew;
-	xnew->prev = old->prev;
-	xnew->prev->next = xnew;
+	new->next = old->next;
+	new->next->prev = new;
+	new->prev = old->prev;
+	new->prev->next = new;
 }
 
 static inline void list_replace_init(struct list_head *old,
-					struct list_head *xnew)
+					struct list_head *new)
 {
-	list_replace(old, xnew);
+	list_replace(old, new);
 	INIT_LIST_HEAD(old);
 }
+
 /**
  * list_del_init - deletes entry from list and reinitialize it.
  * @entry: the element to delete from the list.
  */
 static inline void list_del_init(struct list_head *entry)
 {
-	__list_del(entry->prev, entry->next);
+	__list_del_entry(entry);
 	INIT_LIST_HEAD(entry);
 }
 
@@ -166,8 +170,8 @@ static inline void list_del_init(struct list_head *entry)
  */
 static inline void list_move(struct list_head *list, struct list_head *head)
 {
-        __list_del(list->prev, list->next);
-        list_add(list, head);
+	__list_del_entry(list);
+	list_add(list, head);
 }
 
 /**
@@ -178,8 +182,8 @@ static inline void list_move(struct list_head *list, struct list_head *head)
 static inline void list_move_tail(struct list_head *list,
 				  struct list_head *head)
 {
-        __list_del(list->prev, list->next);
-        list_add_tail(list, head);
+	__list_del_entry(list);
+	list_add_tail(list, head);
 }
 
 /**
@@ -221,6 +225,69 @@ static inline int list_empty_careful(const struct list_head *head)
 	return (next == head) && (next == head->prev);
 }
 
+/**
+ * list_rotate_left - rotate the list to the left
+ * @head: the head of the list
+ */
+static inline void list_rotate_left(struct list_head *head)
+{
+	struct list_head *first;
+
+	if (!list_empty(head)) {
+		first = head->next;
+		list_move_tail(first, head);
+	}
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+	return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	struct list_head *new_first = entry->next;
+	list->next = head->next;
+	list->next->prev = list;
+	list->prev = entry;
+	entry->next = list;
+	head->next = new_first;
+	new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ *	and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ *
+ */
+static inline void list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	if (list_empty(head))
+		return;
+	if (list_is_singular(head) &&
+		(head->next != entry && head != entry))
+		return;
+	if (entry == head)
+		INIT_LIST_HEAD(list);
+	else
+		__list_cut_position(list, head, entry);
+}
+
 static inline void __list_splice(const struct list_head *list,
 				 struct list_head *prev,
 				 struct list_head *next)
@@ -236,11 +303,12 @@ static inline void __list_splice(const struct list_head *list,
 }
 
 /**
- * list_splice - join two lists
+ * list_splice - join two lists, this is designed for stacks
  * @list: the new list to add.
  * @head: the place to add it in the first list.
  */
-static inline void list_splice(struct list_head *list, struct list_head *head)
+static inline void list_splice(const struct list_head *list,
+				struct list_head *head)
 {
 	if (!list_empty(list))
 		__list_splice(list, head, head->next);
@@ -295,7 +363,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * list_entry - get the struct for this entry
  * @ptr:	the &struct list_head pointer.
  * @type:	the type of the struct this is embedded in.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  */
 #define list_entry(ptr, type, member) \
 	container_of(ptr, type, member)
@@ -304,7 +372,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * list_first_entry - get the first element from a list
  * @ptr:	the list head to take the element from.
  * @type:	the type of the struct this is embedded in.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  *
  * Note, that list is expected to be not empty.
  */
@@ -312,35 +380,49 @@ static inline void list_splice_tail_init(struct list_head *list,
 	list_entry((ptr)->next, type, member)
 
 /**
- * list_next_entry - get the next element from a list
+ * list_last_entry - get the last element from a list
  * @ptr:	the list head to take the element from.
- * @member:	the name of the list_struct within the struct.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_head within the struct.
  *
- * Note, that next is expected to be not null.
+ * Note, that list is expected to be not empty.
  */
-#define list_next_entry(ptr, member) \
-	list_entry((ptr)->member.next, typeof(*ptr), member)
+#define list_last_entry(ptr, type, member) \
+	list_entry((ptr)->prev, type, member)
 
 /**
- * list_for_each	-	iterate over a list
- * @pos:	the &struct list_head to use as a loop cursor.
- * @head:	the head for your list.
+ * list_first_entry_or_null - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Note that if the list is empty, it returns NULL.
  */
-#define list_for_each(pos, head) \
-	for (pos = (head)->next; pos != (head); \
-        	pos = pos->next)
+#define list_first_entry_or_null(ptr, type, member) \
+	(!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos:	the type * to cursor
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+	list_entry((pos)->member.next, typeof(*(pos)), member)
 
 /**
- * __list_for_each	-	iterate over a list
+ * list_prev_entry - get the prev element in list
+ * @pos:	the type * to cursor
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_prev_entry(pos, member) \
+	list_entry((pos)->member.prev, typeof(*(pos)), member)
+
+/**
+ * list_for_each	-	iterate over a list
  * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
  */
-#define __list_for_each(pos, head) \
+#define list_for_each(pos, head) \
 	for (pos = (head)->next; pos != (head); pos = pos->next)
 
 /**
@@ -349,8 +431,7 @@ static inline void list_splice_tail_init(struct list_head *list,
  * @head:	the head for your list.
  */
 #define list_for_each_prev(pos, head) \
-	for (pos = (head)->prev; pos != (head); \
-        	pos = pos->prev)
+	for (pos = (head)->prev; pos != (head); pos = pos->prev)
 
 /**
  * list_for_each_safe - iterate over a list safe against removal of list entry
@@ -363,34 +444,45 @@ static inline void list_splice_tail_init(struct list_head *list,
 		pos = n, n = pos->next)
 
 /**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+	for (pos = (head)->prev, n = pos->prev; \
+	     pos != (head); \
+	     pos = n, n = pos->prev)
+
+/**
  * list_for_each_entry	-	iterate over list of given type
  * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  */
 #define list_for_each_entry(pos, head, member)				\
-	for (pos = list_entry((head)->next, typeof(*pos), member);	\
-	     &pos->member != (head); 	\
-	     pos = list_entry(pos->member.next, typeof(*pos), member))
+	for (pos = list_first_entry(head, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
 
 /**
  * list_for_each_entry_reverse - iterate backwards over list of given type.
  * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  */
 #define list_for_each_entry_reverse(pos, head, member)			\
-	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
-	     &pos->member != (head); 	\
-	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+	for (pos = list_last_entry(head, typeof(*pos), member);		\
+	     &pos->member != (head); 					\
+	     pos = list_prev_entry(pos, member))
 
 /**
- * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
  * @pos:	the type * to use as a start point
  * @head:	the head of the list
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  *
- * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
  */
 #define list_prepare_entry(pos, head, member) \
 	((pos) ? : list_entry(head, typeof(*pos), member))
@@ -399,86 +491,115 @@ static inline void list_splice_tail_init(struct list_head *list,
  * list_for_each_entry_continue - continue iteration over list of given type
  * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  *
  * Continue to iterate over list of given type, continuing after
  * the current position.
  */
 #define list_for_each_entry_continue(pos, head, member) 		\
-	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
-	     &pos->member != (head);	\
-	     pos = list_entry(pos->member.next, typeof(*pos), member))
+	for (pos = list_next_entry(pos, member);			\
+	     &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)		\
+	for (pos = list_prev_entry(pos, member);			\
+	     &pos->member != (head);					\
+	     pos = list_prev_entry(pos, member))
 
 /**
  * list_for_each_entry_from - iterate over list of given type from the current point
  * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  *
  * Iterate over list of given type, continuing from current position.
  */
 #define list_for_each_entry_from(pos, head, member) 			\
-	for (; &pos->member != (head);	\
-	     pos = list_entry(pos->member.next, typeof(*pos), member))
+	for (; &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
 
 /**
  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  */
 #define list_for_each_entry_safe(pos, n, head, member)			\
-	for (pos = list_entry((head)->next, typeof(*pos), member),	\
-		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	for (pos = list_first_entry(head, typeof(*pos), member),	\
+		n = list_next_entry(pos, member);			\
 	     &pos->member != (head); 					\
-	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+	     pos = n, n = list_next_entry(n, member))
 
 /**
- * list_for_each_entry_safe_continue
+ * list_for_each_entry_safe_continue - continue list iteration safe against removal
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  *
  * Iterate over list of given type, continuing after current point,
  * safe against removal of list entry.
  */
 #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
-	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
-		n = list_entry(pos->member.next, typeof(*pos), member);		\
+	for (pos = list_next_entry(pos, member), 				\
+		n = list_next_entry(pos, member);				\
 	     &pos->member != (head);						\
-	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+	     pos = n, n = list_next_entry(n, member))
 
 /**
- * list_for_each_entry_safe_from
+ * list_for_each_entry_safe_from - iterate over list from current point safe against removal
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  *
  * Iterate over list of given type from current point, safe against
  * removal of list entry.
  */
 #define list_for_each_entry_safe_from(pos, n, head, member) 			\
-	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
+	for (n = list_next_entry(pos, member);					\
 	     &pos->member != (head);						\
-	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+	     pos = n, n = list_next_entry(n, member))
 
 /**
- * list_for_each_entry_safe_reverse
+ * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
- * @member:	the name of the list_struct within the struct.
+ * @member:	the name of the list_head within the struct.
  *
  * Iterate backwards over list of given type, safe against removal
  * of list entry.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
-	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
-		n = list_entry(pos->member.prev, typeof(*pos), member);	\
+	for (pos = list_last_entry(head, typeof(*pos), member),		\
+		n = list_prev_entry(pos, member);			\
 	     &pos->member != (head); 					\
-	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+	     pos = n, n = list_prev_entry(n, member))
+
+/**
+ * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
+ * @pos:	the loop cursor used in the list_for_each_entry_safe loop
+ * @n:		temporary storage used in list_for_each_entry_safe
+ * @member:	the name of the list_head within the struct.
+ *
+ * list_safe_reset_next is not safe to use in general if the list may be
+ * modified concurrently (eg. the lock is dropped in the loop body). An
+ * exception to this is if the cursor element (pos) is pinned in the list,
+ * and list_safe_reset_next is called after re-taking the lock and before
+ * completing the current iteration of the loop body.
+ */
+#define list_safe_reset_next(pos, n, member)				\
+	n = list_next_entry(pos, member)
 
 #endif
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 02/11] ubifs: fix typo in ubifs_read
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
  2015-10-31 11:15 ` [PATCH 01/11] ubifs: add complete version of list.h Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 03/11] Make cli byte parsing from ubi-utils available for all tools Richard Weinberger
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/lib/io.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ubifs-utils/lib/io.c b/ubifs-utils/lib/io.c
index d05cf86..c2e0d63 100644
--- a/ubifs-utils/lib/io.c
+++ b/ubifs-utils/lib/io.c
@@ -145,7 +145,7 @@ int ubifs_read(loff_t offset, int len, void *buf)
 		return sys_err_msg("lseek failed seeking %"PRIdoff_t, offset);
 
 	if (read(out_fd, buf, len) != len)
-		return sys_err_msg("write failed writing %d bytes at pos %"PRIdoff_t,
+		return sys_err_msg("read failed reading %d bytes at pos %"PRIdoff_t,
 				   len, offset);
 
 	return 0;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 03/11] Make cli byte parsing from ubi-utils available for all tools
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
  2015-10-31 11:15 ` [PATCH 01/11] ubifs: add complete version of list.h Richard Weinberger
  2015-10-31 11:15 ` [PATCH 02/11] ubifs: fix typo in ubifs_read Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 04/11] ubifs: add decompression functions Richard Weinberger
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

ubiutils_get_bytes(str) parses strings like "12MiB" and returns the value in
bytes. We want this function to be available to all tools not just ubi specific
ones. The function is now simply named parse_bytes

ubiutils_print_bytes() performs the reverse and is now named print_bytes.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 include/common.h                    | 90 +++++++++++++++++++++++++++++++++++
 ubi-utils/include/ubiutils-common.h |  2 -
 ubi-utils/mtdinfo.c                 |  6 +--
 ubi-utils/ubiattach.c               |  6 +--
 ubi-utils/ubiformat.c               |  8 ++--
 ubi-utils/ubimkvol.c                |  6 +--
 ubi-utils/ubinfo.c                  | 10 ++--
 ubi-utils/ubinize.c                 | 10 ++--
 ubi-utils/ubirsvol.c                |  2 +-
 ubi-utils/ubiutils-common.c         | 93 -------------------------------------
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c | 66 ++------------------------
 11 files changed, 119 insertions(+), 180 deletions(-)

diff --git a/include/common.h b/include/common.h
index fb0ca83..460d2aa 100644
--- a/include/common.h
+++ b/include/common.h
@@ -213,6 +213,96 @@ do { \
 	printf("%s %s\n", PROGRAM_NAME, VERSION); \
 } while (0)
 
+/**
+ * get_multiplier - convert size specifier to an integer multiplier.
+ * @str: the size specifier string
+ *
+ * This function parses the @str size specifier, which may be one of
+ * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
+ * size multiplier in case of success and %-1 in case of failure.
+ */
+static inline int get_multiplier(const char *str)
+{
+	if (!str)
+		return 1;
+
+	/* Remove spaces before the specifier */
+	while (*str == ' ' || *str == '\t')
+		str += 1;
+
+	if (!strcmp(str, "KiB"))
+		return 1024;
+	if (!strcmp(str, "MiB"))
+		return 1024 * 1024;
+	if (!strcmp(str, "GiB"))
+		return 1024 * 1024 * 1024;
+
+	return -1;
+}
+
+/**
+ * parse_bytes - convert a string containing amount of bytes into an
+ * integer
+ * @str: string to convert
+ *
+ * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB'
+ * size specifiers. Returns positive amount of bytes in case of success and %-1
+ * in case of failure.
+ */
+static inline long long parse_bytes(const char *str)
+{
+	char *endp;
+	long long bytes = strtoull(str, &endp, 0);
+
+	if (endp == str || bytes < 0)
+		return errmsg("incorrect amount of bytes: \"%s\"\n", str);
+
+	if (*endp != '\0') {
+		int mult = get_multiplier(endp);
+
+		if (mult == -1)
+			return errmsg("bad size specifier: \"%s\" - "
+			        "should be 'KiB', 'MiB' or 'GiB'\n", endp);
+		bytes *= mult;
+	}
+
+	return bytes;
+}
+
+/**
+ * print_bytes - print bytes.
+ * @bytes: variable to print
+ * @bracket: whether brackets have to be put or not
+ *
+ * This is a helper function which prints amount of bytes in a human-readable
+ * form, i.e., it prints the exact amount of bytes following by the approximate
+ * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
+ * is.
+ */
+static inline void print_bytes(long long bytes, int bracket)
+{
+	const char *p;
+
+	if (bracket)
+		p = " (";
+	else
+		p = ", ";
+
+	printf("%lld bytes", bytes);
+
+	if (bytes > 1024 * 1024 * 1024)
+		printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024));
+	else if (bytes > 1024 * 1024)
+		printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024));
+	else if (bytes > 1024 && bytes != 0)
+		printf("%s%.1f KiB", p, (double)bytes / 1024);
+	else
+		return;
+
+	if (bracket)
+		printf(")");
+}
+
 #include "xalloc.h"
 
 #ifdef __cplusplus
diff --git a/ubi-utils/include/ubiutils-common.h b/ubi-utils/include/ubiutils-common.h
index 9762837..a86ca2f 100644
--- a/ubi-utils/include/ubiutils-common.h
+++ b/ubi-utils/include/ubiutils-common.h
@@ -23,8 +23,6 @@
 extern "C" {
 #endif
 
-long long ubiutils_get_bytes(const char *str);
-void ubiutils_print_bytes(long long bytes, int bracket);
 void ubiutils_print_text(FILE *stream, const char *txt, int len);
 int ubiutils_srand(void);
 
diff --git a/ubi-utils/mtdinfo.c b/ubi-utils/mtdinfo.c
index a86abd1..e360fcd 100644
--- a/ubi-utils/mtdinfo.c
+++ b/ubi-utils/mtdinfo.c
@@ -172,7 +172,7 @@ static void print_ubi_info(const struct mtd_info *mtd_info,
 	printf("Default UBI VID header offset:  %d\n", ui.vid_hdr_offs);
 	printf("Default UBI data offset:        %d\n", ui.data_offs);
 	printf("Default UBI LEB size:           ");
-	ubiutils_print_bytes(ui.leb_size, 0);
+	print_bytes(ui.leb_size, 0);
 	printf("\n");
 	printf("Maximum UBI volumes count:      %d\n", ui.max_volumes);
 }
@@ -306,10 +306,10 @@ static int print_dev_info(libmtd_t libmtd, const struct mtd_info *mtd_info, int
 	printf("Name:                           %s\n", mtd.name);
 	printf("Type:                           %s\n", mtd.type_str);
 	printf("Eraseblock size:                ");
-	ubiutils_print_bytes(mtd.eb_size, 0);
+	print_bytes(mtd.eb_size, 0);
 	printf("\n");
 	printf("Amount of eraseblocks:          %d (", mtd.eb_cnt);
-	ubiutils_print_bytes(mtd.size, 0);
+	print_bytes(mtd.size, 0);
 	printf(")\n");
 	printf("Minimum input/output unit size: %d %s\n",
 	       mtd.min_io_size, mtd.min_io_size > 1 ? "bytes" : "byte");
diff --git a/ubi-utils/ubiattach.c b/ubi-utils/ubiattach.c
index a7c62d0..a4844fa 100644
--- a/ubi-utils/ubiattach.c
+++ b/ubi-utils/ubiattach.c
@@ -238,11 +238,11 @@ int main(int argc, char * const argv[])
 	}
 
 	printf("UBI device number %d, total %d LEBs (", dev_info.dev_num, dev_info.total_lebs);
-	ubiutils_print_bytes(dev_info.total_bytes, 0);
+	print_bytes(dev_info.total_bytes, 0);
 	printf("), available %d LEBs (", dev_info.avail_lebs);
-	ubiutils_print_bytes(dev_info.avail_bytes, 0);
+	print_bytes(dev_info.avail_bytes, 0);
 	printf("), LEB size ");
-	ubiutils_print_bytes(dev_info.leb_size, 1);
+	print_bytes(dev_info.leb_size, 1);
 	printf("\n");
 
 	libubi_close(libubi);
diff --git a/ubi-utils/ubiformat.c b/ubi-utils/ubiformat.c
index 21409ca..4064da0 100644
--- a/ubi-utils/ubiformat.c
+++ b/ubi-utils/ubiformat.c
@@ -143,7 +143,7 @@ static int parse_opt(int argc, char * const argv[])
 
 		switch (key) {
 		case 's':
-			args.subpage_size = ubiutils_get_bytes(optarg);
+			args.subpage_size = parse_bytes(optarg);
 			if (args.subpage_size <= 0)
 				return errmsg("bad sub-page size: \"%s\"", optarg);
 			if (!is_power_of_2(args.subpage_size))
@@ -170,7 +170,7 @@ static int parse_opt(int argc, char * const argv[])
 			break;
 
 		case 'S':
-			args.image_sz = ubiutils_get_bytes(optarg);
+			args.image_sz = parse_bytes(optarg);
 			if (args.image_sz <= 0)
 				return errmsg("bad image-size: \"%s\"", optarg);
 			break;
@@ -791,9 +791,9 @@ int main(int argc, char * const argv[])
 
 	if (!args.quiet) {
 		normsg_cont("mtd%d (%s), size ", mtd.mtd_num, mtd.type_str);
-		ubiutils_print_bytes(mtd.size, 1);
+		print_bytes(mtd.size, 1);
 		printf(", %d eraseblocks of ", mtd.eb_cnt);
-		ubiutils_print_bytes(mtd.eb_size, 1);
+		print_bytes(mtd.eb_size, 1);
 		printf(", min. I/O size %d bytes\n", mtd.min_io_size);
 	}
 
diff --git a/ubi-utils/ubimkvol.c b/ubi-utils/ubimkvol.c
index 7c2a234..84cb65a 100644
--- a/ubi-utils/ubimkvol.c
+++ b/ubi-utils/ubimkvol.c
@@ -137,7 +137,7 @@ static int parse_opt(int argc, char * const argv[])
 			break;
 
 		case 's':
-			args.bytes = ubiutils_get_bytes(optarg);
+			args.bytes = parse_bytes(optarg);
 			if (args.bytes <= 0)
 				return errmsg("bad volume size: \"%s\"", optarg);
 			break;
@@ -278,9 +278,9 @@ int main(int argc, char * const argv[])
 	}
 
 	printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs);
-	ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+	print_bytes(vol_info.rsvd_bytes, 0);
 	printf("), LEB size ");
-	ubiutils_print_bytes(vol_info.leb_size, 1);
+	print_bytes(vol_info.leb_size, 1);
 	printf(", %s, name \"%s\", alignment %d\n",
 	       req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
 	       vol_info.name, vol_info.alignment);
diff --git a/ubi-utils/ubinfo.c b/ubi-utils/ubinfo.c
index cb88f53..bd97198 100644
--- a/ubi-utils/ubinfo.c
+++ b/ubi-utils/ubinfo.c
@@ -211,12 +211,12 @@ static int print_vol_info(libubi_t libubi, int dev_num, int vol_id)
 	printf("Alignment:   %d\n", vol_info.alignment);
 
 	printf("Size:        %d LEBs (", vol_info.rsvd_lebs);
-	ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
+	print_bytes(vol_info.rsvd_bytes, 0);
 	printf(")\n");
 
 	if (vol_info.type == UBI_STATIC_VOLUME) {
 		printf("Data bytes:  ");
-		ubiutils_print_bytes(vol_info.data_bytes, 1);
+		print_bytes(vol_info.data_bytes, 1);
 		printf("\n");
 	}
 	printf("State:       %s\n", vol_info.corrupted ? "corrupted" : "OK");
@@ -240,15 +240,15 @@ static int print_dev_info(libubi_t libubi, int dev_num, int all)
 	printf("ubi%d\n", dev_info.dev_num);
 	printf("Volumes count:                           %d\n", dev_info.vol_count);
 	printf("Logical eraseblock size:                 ");
-	ubiutils_print_bytes(dev_info.leb_size, 0);
+	print_bytes(dev_info.leb_size, 0);
 	printf("\n");
 
 	printf("Total amount of logical eraseblocks:     %d (", dev_info.total_lebs);
-	ubiutils_print_bytes(dev_info.total_bytes, 0);
+	print_bytes(dev_info.total_bytes, 0);
 	printf(")\n");
 
 	printf("Amount of available logical eraseblocks: %d (", dev_info.avail_lebs);
-	ubiutils_print_bytes(dev_info.avail_bytes, 0);
+	print_bytes(dev_info.avail_bytes, 0);
 	printf(")\n");
 
 	printf("Maximum count of volumes                 %d\n", dev_info.max_vol_count);
diff --git a/ubi-utils/ubinize.c b/ubi-utils/ubinize.c
index 34f465a..e7c0a36 100644
--- a/ubi-utils/ubinize.c
+++ b/ubi-utils/ubinize.c
@@ -176,13 +176,13 @@ static int parse_opt(int argc, char * const argv[])
 			break;
 
 		case 'p':
-			args.peb_size = ubiutils_get_bytes(optarg);
+			args.peb_size = parse_bytes(optarg);
 			if (args.peb_size <= 0)
 				return errmsg("bad physical eraseblock size: \"%s\"", optarg);
 			break;
 
 		case 'm':
-			args.min_io_size = ubiutils_get_bytes(optarg);
+			args.min_io_size = parse_bytes(optarg);
 			if (args.min_io_size <= 0)
 				return errmsg("bad min. I/O unit size: \"%s\"", optarg);
 			if (!is_power_of_2(args.min_io_size))
@@ -190,7 +190,7 @@ static int parse_opt(int argc, char * const argv[])
 			break;
 
 		case 's':
-			args.subpage_size = ubiutils_get_bytes(optarg);
+			args.subpage_size = parse_bytes(optarg);
 			if (args.subpage_size <= 0)
 				return errmsg("bad sub-page size: \"%s\"", optarg);
 			if (!is_power_of_2(args.subpage_size))
@@ -368,7 +368,7 @@ static int read_section(const struct ubigen_info *ui, const char *sname,
 	sprintf(buf, "%s:vol_size", sname);
 	p = iniparser_getstring(args.dict, buf, NULL);
 	if (p) {
-		vi->bytes = ubiutils_get_bytes(p);
+		vi->bytes = parse_bytes(p);
 		if (vi->bytes <= 0)
 			return errmsg("bad \"vol_size\" key value \"%s\" (section \"%s\")",
 				      p, sname);
@@ -397,7 +397,7 @@ static int read_section(const struct ubigen_info *ui, const char *sname,
 
 		normsg_cont("volume size was not specified in section \"%s\", assume"
 			    " minimum to fit image \"%s\"", sname, *img);
-		ubiutils_print_bytes(vi->bytes, 1);
+		print_bytes(vi->bytes, 1);
 		printf("\n");
 	}
 
diff --git a/ubi-utils/ubirsvol.c b/ubi-utils/ubirsvol.c
index c469060..d60cf49 100644
--- a/ubi-utils/ubirsvol.c
+++ b/ubi-utils/ubirsvol.c
@@ -114,7 +114,7 @@ static int parse_opt(int argc, char * const argv[])
 
 		switch (key) {
 		case 's':
-			args.bytes = ubiutils_get_bytes(optarg);
+			args.bytes = parse_bytes(optarg);
 			if (args.bytes <= 0)
 				return errmsg("bad volume size: \"%s\"", optarg);
 			break;
diff --git a/ubi-utils/ubiutils-common.c b/ubi-utils/ubiutils-common.c
index 6609a6b..d9ea3b7 100644
--- a/ubi-utils/ubiutils-common.c
+++ b/ubi-utils/ubiutils-common.c
@@ -34,99 +34,6 @@
 #include <unistd.h>
 #include "common.h"
 
-/**
- * get_multiplier - convert size specifier to an integer multiplier.
- * @str: the size specifier string
- *
- * This function parses the @str size specifier, which may be one of
- * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
- * size multiplier in case of success and %-1 in case of failure.
- */
-static int get_multiplier(const char *str)
-{
-	if (!str)
-		return 1;
-
-	/* Remove spaces before the specifier */
-	while (*str == ' ' || *str == '\t')
-		str += 1;
-
-	if (!strcmp(str, "KiB"))
-		return 1024;
-	if (!strcmp(str, "MiB"))
-		return 1024 * 1024;
-	if (!strcmp(str, "GiB"))
-		return 1024 * 1024 * 1024;
-
-	return -1;
-}
-
-/**
- * ubiutils_get_bytes - convert a string containing amount of bytes into an
- * integer
- * @str: string to convert
- *
- * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB'
- * size specifiers. Returns positive amount of bytes in case of success and %-1
- * in case of failure.
- */
-long long ubiutils_get_bytes(const char *str)
-{
-	char *endp;
-	long long bytes = strtoull(str, &endp, 0);
-
-	if (endp == str || bytes < 0) {
-		fprintf(stderr, "incorrect amount of bytes: \"%s\"\n", str);
-		return -1;
-	}
-
-	if (*endp != '\0') {
-		int mult = get_multiplier(endp);
-
-		if (mult == -1) {
-			fprintf(stderr, "bad size specifier: \"%s\" - "
-			        "should be 'KiB', 'MiB' or 'GiB'\n", endp);
-			return -1;
-		}
-		bytes *= mult;
-	}
-
-	return bytes;
-}
-
-/**
- * ubiutils_print_bytes - print bytes.
- * @bytes: variable to print
- * @bracket: whether brackets have to be put or not
- *
- * This is a helper function which prints amount of bytes in a human-readable
- * form, i.e., it prints the exact amount of bytes following by the approximate
- * amount of Kilobytes, Megabytes, or Gigabytes, depending on how big @bytes
- * is.
- */
-void ubiutils_print_bytes(long long bytes, int bracket)
-{
-	const char *p;
-
-	if (bracket)
-		p = " (";
-	else
-		p = ", ";
-
-	printf("%lld bytes", bytes);
-
-	if (bytes > 1024 * 1024 * 1024)
-		printf("%s%.1f GiB", p, (double)bytes / (1024 * 1024 * 1024));
-	else if (bytes > 1024 * 1024)
-		printf("%s%.1f MiB", p, (double)bytes / (1024 * 1024));
-	else if (bytes > 1024 && bytes != 0)
-		printf("%s%.1f KiB", p, (double)bytes / 1024);
-	else
-		return;
-
-	if (bracket)
-		printf(")");
-}
 
 /**
  * ubiutils_print_text - print text and fold it.
diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
index b19646f..8a3baea 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
@@ -390,62 +390,6 @@ static int validate_options(void)
 	return 0;
 }
 
-/**
- * get_multiplier - convert size specifier to an integer multiplier.
- * @str: the size specifier string
- *
- * This function parses the @str size specifier, which may be one of
- * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive
- * size multiplier in case of success and %-1 in case of failure.
- */
-static int get_multiplier(const char *str)
-{
-	if (!str)
-		return 1;
-
-	/* Remove spaces before the specifier */
-	while (*str == ' ' || *str == '\t')
-		str += 1;
-
-	if (!strcmp(str, "KiB"))
-		return 1024;
-	if (!strcmp(str, "MiB"))
-		return 1024 * 1024;
-	if (!strcmp(str, "GiB"))
-		return 1024 * 1024 * 1024;
-
-	return -1;
-}
-
-/**
- * get_bytes - convert a string containing amount of bytes into an
- *             integer.
- * @str: string to convert
- *
- * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' size
- * specifiers. Returns positive amount of bytes in case of success and %-1 in
- * case of failure.
- */
-static long long get_bytes(const char *str)
-{
-	char *endp;
-	long long bytes = strtoull(str, &endp, 0);
-
-	if (endp == str || bytes < 0)
-		return err_msg("incorrect amount of bytes: \"%s\"", str);
-
-	if (*endp != '\0') {
-		int mult = get_multiplier(endp);
-
-		if (mult == -1)
-			return err_msg("bad size specifier: \"%s\" - "
-				       "should be 'KiB', 'MiB' or 'GiB'", endp);
-		bytes *= mult;
-	}
-
-	return bytes;
-}
-
 static int get_options(int argc, char**argv)
 {
 	int opt, i;
@@ -493,17 +437,17 @@ static int get_options(int argc, char**argv)
 						   root);
 			break;
 		case 'm':
-			c->min_io_size = get_bytes(optarg);
+			c->min_io_size = parse_bytes(optarg);
 			if (c->min_io_size <= 0)
 				return err_msg("bad min. I/O size");
 			break;
 		case 'e':
-			c->leb_size = get_bytes(optarg);
+			c->leb_size = parse_bytes(optarg);
 			if (c->leb_size <= 0)
 				return err_msg("bad LEB size");
 			break;
 		case 'c':
-			c->max_leb_cnt = get_bytes(optarg);
+			c->max_leb_cnt = parse_bytes(optarg);
 			if (c->max_leb_cnt <= 0)
 				return err_msg("bad maximum LEB count");
 			break;
@@ -585,12 +529,12 @@ static int get_options(int argc, char**argv)
 					       optarg);
 			break;
 		case 'j':
-			c->max_bud_bytes = get_bytes(optarg);
+			c->max_bud_bytes = parse_bytes(optarg);
 			if (c->max_bud_bytes <= 0)
 				return err_msg("bad maximum amount of buds");
 			break;
 		case 'R':
-			c->rp_size = get_bytes(optarg);
+			c->rp_size = parse_bytes(optarg);
 			if (c->rp_size < 0)
 				return err_msg("bad reserved bytes count");
 			break;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 04/11] ubifs: add decompression functions
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (2 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 03/11] Make cli byte parsing from ubi-utils available for all tools Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers Richard Weinberger
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

This enables decompression of lzo and zlib compressed data in addition to the
existin compression functions.

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/include/compr.h |  1 +
 ubifs-utils/lib/compr.c     | 75 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/ubifs-utils/include/compr.h b/ubifs-utils/include/compr.h
index d44a2ba..9f6a173 100644
--- a/ubifs-utils/include/compr.h
+++ b/ubifs-utils/include/compr.h
@@ -39,6 +39,7 @@ enum compression_type
 };
 
 int compress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len, int type, int lzo_percent);
+int decompress_data(void *in_buf, size_t in_len, void *out_buf, size_t *out_len, int type);
 int init_compression(void);
 void destroy_compression(void);
 
diff --git a/ubifs-utils/lib/compr.c b/ubifs-utils/lib/compr.c
index 35cc447..a4591f8 100644
--- a/ubifs-utils/lib/compr.c
+++ b/ubifs-utils/lib/compr.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2008 Nokia Corporation.
  * Copyright (C) 2008 University of Szeged, Hungary
+ * Copyright (C) 2015 sigma star gmbh
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 as published by
@@ -18,6 +19,8 @@
  * Authors: Artem Bityutskiy
  *          Adrian Hunter
  *          Zoltan Sogor
+ *          Richard Weinberger
+ *          David Gstir
  */
 
 #include "ubifs_common.h"
@@ -79,6 +82,47 @@ static int zlib_deflate(void *in_buf, size_t in_len, void *out_buf,
 	return 0;
 }
 
+static int zlib_inflate(void *in_buf, size_t in_len, void *out_buf,
+			size_t *out_len)
+{
+	z_stream strm;
+
+	strm.zalloc = NULL;
+	strm.zfree = NULL;
+
+	/*
+	 * Match exactly the zlib parameters used by the Linux kernel crypto
+	 * API.
+	 */
+        if (inflateInit2(&strm, -DEFLATE_DEF_WINBITS)) {
+		errcnt += 1;
+		return -1;
+	}
+
+	strm.next_in = in_buf;
+	strm.avail_in = in_len;
+	strm.total_in = 0;
+
+	strm.next_out = out_buf;
+	strm.avail_out = *out_len;
+	strm.total_out = 0;
+
+	if (inflate(&strm, Z_FINISH) != Z_STREAM_END) {
+		inflateEnd(&strm);
+		errcnt += 1;
+		return -1;
+	}
+
+	if (inflateEnd(&strm) != Z_OK) {
+		errcnt += 1;
+		return -1;
+	}
+
+	*out_len = strm.total_out;
+
+	return 0;
+}
+
 static int lzo_compress(void *in_buf, size_t in_len, void *out_buf,
 			size_t *out_len)
 {
@@ -189,6 +233,37 @@ int compress_data(void *in_buf, size_t in_len, void *out_buf,
 	return type;
 }
 
+int decompress_data(void *in_buf, size_t in_len, void *out_buf,
+		    size_t *out_len, int type)
+{
+	int err = 0;
+
+	switch (type) {
+	case UBIFS_COMPR_NONE:
+		if (*out_len < in_len) {
+			err = -1;
+			goto out;
+		}
+		memcpy(out_buf, in_buf, in_len);
+		*out_len = in_len;
+		break;
+	case UBIFS_COMPR_LZO:
+		err = lzo1x_decompress_safe(in_buf, in_len, (unsigned char *)out_buf, out_len, NULL);
+		err = (err == LZO_E_OK) ? 0 : -1;
+		break;
+	case UBIFS_COMPR_ZLIB:
+		err = zlib_inflate(in_buf, in_len, out_buf, out_len);
+		break;
+	default:
+		errcnt += 1;
+		err = 1;
+		break;
+	}
+
+out:
+	return err;
+}
+
 int init_compression(void)
 {
 	lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (3 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 04/11] ubifs: add decompression functions Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-11-02  1:28   ` Dongsheng Yang
  2015-10-31 11:15 ` [PATCH 06/11] ubifs: keep scan buffer in ubifs_info Richard Weinberger
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

Various key helper functions in ubifs-utils/include/key.h require the
ubifs_info context. Since this context is never used, so we can remove it.

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/include/key.h           | 24 ++++++------------------
 ubifs-utils/lib/scan.c              | 10 ++++------
 ubifs-utils/ubifs_dump/ubifs_dump.c | 22 +++++++++++-----------
 3 files changed, 21 insertions(+), 35 deletions(-)

diff --git a/ubifs-utils/include/key.h b/ubifs-utils/include/key.h
index 779981a..9ee7597 100644
--- a/ubifs-utils/include/key.h
+++ b/ubifs-utils/include/key.h
@@ -92,7 +92,6 @@ static inline uint32_t key_test_hash(const char *str, int len)
 
 /**
  * ino_key_init - initialize inode key.
- * @c: UBIFS file-system description object
  * @key: key to initialize
  * @inum: inode number
  */
@@ -190,12 +189,10 @@ static inline int keys_cmp(const union ubifs_key *key1,
 
 /**
  * key_read - transform a key to in-memory format.
- * @c: UBIFS file-system description object
  * @from: the key to transform
  * @to: the key to store the result
  */
-static inline void key_read(const struct ubifs_info *c __attribute__((unused)), const void *from,
-			    union ubifs_key *to)
+static inline void key_read(const void *from, union ubifs_key *to)
 {
 	const union ubifs_key *f = from;
 
@@ -205,45 +202,38 @@ static inline void key_read(const struct ubifs_info *c __attribute__((unused)),
 
 /**
  * invalid_key_init - initialize invalid node key.
- * @c: UBIFS file-system description object
  * @key: key to initialize
  *
  * This is a helper function which marks a @key object as invalid.
  */
-static inline void invalid_key_init(const struct ubifs_info *c __attribute__((unused)),
-				    union ubifs_key *key)
+static inline void invalid_key_init(union ubifs_key *key)
 {
 	key->u32[0] = 0xDEADBEAF;
 	key->u32[1] = UBIFS_INVALID_KEY;
 }
 /**
  * key_type - get key type.
- * @c: UBIFS file-system description object
  * @key: key to get type of
  */
-static inline int key_type(const struct ubifs_info *c __attribute__((unused)),
-			   const union ubifs_key *key)
+static inline int key_type(const union ubifs_key *key)
 {
 	return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS;
 }
 
 /*
  * key_hash - get directory entry hash.
- * @c: UBIFS file-system description object
  * @key: the key to get hash from
  */
-static inline uint32_t key_hash(const struct ubifs_info *c __attribute__((unused)),
-				const union ubifs_key *key)
+static inline uint32_t key_hash(const union ubifs_key *key)
 {
 	return key->u32[1] & UBIFS_S_KEY_HASH_MASK;
 }
 
 /**
  * key_inum - fetch inode number from key.
- * @c: UBIFS file-system description object
  * @k: key to fetch inode number from
  */
-static inline ino_t key_inum(const struct ubifs_info *c __attribute__((unused)), const void *k)
+static inline ino_t key_inum(const void *k)
 {
 	const union ubifs_key *key = k;
 
@@ -252,11 +242,9 @@ static inline ino_t key_inum(const struct ubifs_info *c __attribute__((unused)),
 
 /**
  * key_block - get data block number.
- * @c: UBIFS file-system description object
  * @key: the key to get the block number from
  */
-static inline unsigned int key_block(const struct ubifs_info *c __attribute__((unused)),
-				     const union ubifs_key *key)
+static inline unsigned int key_block(const union ubifs_key *key)
 {
 	return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK;
 }
diff --git a/ubifs-utils/lib/scan.c b/ubifs-utils/lib/scan.c
index 69c84d1..3c5be2c 100644
--- a/ubifs-utils/lib/scan.c
+++ b/ubifs-utils/lib/scan.c
@@ -162,15 +162,13 @@ void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 
 /**
  * ubifs_add_snod - add a scanned node to LEB scanning information.
- * @c: UBIFS file-system description object
  * @sleb: scanning information
  * @buf: buffer containing node
  * @offs: offset of node on flash
  *
  * This function returns %0 on success and a negative error code on failure.
  */
-int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
-		   void *buf, int offs)
+int ubifs_add_snod(struct ubifs_scan_leb *sleb, void *buf, int offs)
 {
 	struct ubifs_ch *ch = buf;
 	struct ubifs_ino_node *ino = buf;
@@ -195,10 +193,10 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 		 * The key is in the same place in all keyed
 		 * nodes.
 		 */
-		key_read(c, &ino->key, &snod->key);
+		key_read(&ino->key, &snod->key);
 		break;
 	default:
-		invalid_key_init(c, &snod->key);
+		invalid_key_init(&snod->key);
 		break;
 	}
 	list_add_tail(&snod->list, &sleb->nodes);
@@ -267,7 +265,7 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
 			goto error;
 		}
 
-		err = ubifs_add_snod(c, sleb, buf, offs);
+		err = ubifs_add_snod(sleb, buf, offs);
 		if (err)
 			goto error;
 
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index eaf8daf..68c2895 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -91,30 +91,30 @@ const char *dbg_snprintf_key(const struct ubifs_info *c,
 			     const union ubifs_key *key, char *buffer, int len)
 {
 	char *p = buffer;
-	int type = key_type(c, key);
+	int type = key_type(key);
 
 	if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
 		switch (type) {
 
 		case UBIFS_INO_KEY:
 			len -= snprintf(p, len, "(%lu, %s)",
-					(unsigned long)key_inum(c, key),
+					(unsigned long)key_inum(key),
 					get_key_type(type));
 			break;
 		case UBIFS_DENT_KEY:
 		case UBIFS_XENT_KEY:
 			len -= snprintf(p, len, "(%lu, %s, %#08x)",
-					(unsigned long)key_inum(c, key),
-					get_key_type(type), key_hash(c, key));
+					(unsigned long)key_inum(key),
+					get_key_type(type), key_hash(key));
 			break;
 		case UBIFS_DATA_KEY:
 			len -= snprintf(p, len, "(%lu, %s, %u)",
-					(unsigned long)key_inum(c, key),
-					get_key_type(type), key_block(c, key));
+					(unsigned long)key_inum(key),
+					get_key_type(type), key_block(key));
 			break;
 		case UBIFS_TRUN_KEY:
 			len -= snprintf(p, len, "(%lu, %s)",
-					(unsigned long)key_inum(c, key),
+					(unsigned long)key_inum(key),
 					get_key_type(type));
 			break;
 		default:
@@ -252,7 +252,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
 	{
 		const struct ubifs_ino_node *ino = node;
 
-		key_read(c, &ino->key, &key);
+		key_read(&ino->key, &key);
 		printf("\t\tkey \t\t\t\t%s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 		printf("\t\tcreat_sqnum \t\t\t%llu\n",
@@ -287,7 +287,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
 		const struct ubifs_dent_node *dent = node;
 		int nlen = le16_to_cpu(dent->nlen);
 
-		key_read(c, &dent->key, &key);
+		key_read(&dent->key, &key);
 		printf("\t\tkey \t\t\t\t%s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 		printf("\t\tinum \t\t\t\t%llu\n",
@@ -311,7 +311,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
 		const struct ubifs_data_node *dn = node;
 		int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
 
-		key_read(c, &dn->key, &key);
+		key_read(&dn->key, &key);
 		printf("\t\tkey \t\t\t\t%s\n",
 		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
 		printf("\t\tsize \t\t\t\t%u\n", le32_to_cpu(dn->size));
@@ -347,7 +347,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
 			const struct ubifs_branch *br;
 
 			br = ubifs_idx_branch(c, idx, i);
-			key_read(c, &br->key, &key);
+			key_read(&br->key, &key);
 			printf("\t\t%d: LEB %d:%d len %d key %s\n",
 			       i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
 			       le32_to_cpu(br->len),
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 06/11] ubifs: keep scan buffer in ubifs_info
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (4 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 07/11] ubifs: extend master scanning code Richard Weinberger
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

Like in der kernel's UBIFS code, we keep a single scan buffer in the ubifs_info
struct for all scan-related functions to use.

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/include/ubifs.h         | 2 ++
 ubifs-utils/ubifs_dump/ubifs_dump.c | 1 +
 2 files changed, 3 insertions(+)

diff --git a/ubifs-utils/include/ubifs.h b/ubifs-utils/include/ubifs.h
index 3696f1a..d2ddd0a 100644
--- a/ubifs-utils/include/ubifs.h
+++ b/ubifs-utils/include/ubifs.h
@@ -320,6 +320,7 @@ enum {
  * @vi: UBI volume information
  *
  * @gc_lnum: LEB number used for garbage collection
+ * @sbuf: a buffer of LEB size used by GC and replay for scanning
  * @rp_size: reserved pool size
  *
  * @space_bits: number of bits needed to record free or dirty space
@@ -398,6 +399,7 @@ struct ubifs_info
 	struct ubi_vol_info vi;
 
 	int gc_lnum;
+	void *sbuf;
 	long long rp_size;
 
 	int space_bits;
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index 68c2895..c8e3439 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -994,6 +994,7 @@ static int dump()
 		err = -ENOMEM;
 		goto out;
 	}
+	c->sbuf = leb_buf;
 
 	err = dump_master();
 	if (err)
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 07/11] ubifs: extend master scanning code
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (5 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 06/11] ubifs: keep scan buffer in ubifs_info Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 08/11] ubifs: add missing include to defs.h Richard Weinberger
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

Move to dedicated file and add master node validation

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 Makefile                            |   2 +-
 ubifs-utils/include/master.h        |   7 +
 ubifs-utils/include/ubifs.h         |  24 +++
 ubifs-utils/lib/master.c            | 311 ++++++++++++++++++++++++++++++++++++
 ubifs-utils/ubifs_dump/ubifs_dump.c |  66 +-------
 5 files changed, 344 insertions(+), 66 deletions(-)
 create mode 100644 ubifs-utils/include/master.h
 create mode 100644 ubifs-utils/lib/master.c

diff --git a/Makefile b/Makefile
index e3b670d..91f9820 100644
--- a/Makefile
+++ b/Makefile
@@ -133,7 +133,7 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 $(foreach v,crc16.o lpt.o compr.o devtable.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
 
 obj-ubifs_dump = $(UBIFS_LIBS)
-obj-ubifs_dump += ../lib/scan.o ../lib/lprops.o ../lib/hexdump.o
+obj-ubifs_dump += ../lib/scan.o ../lib/master.o ../lib/lprops.o ../lib/hexdump.o
 LDFLAGS_ubifs_dump = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_ubifs_dump = -lz -llzo2 -lm -luuid
 $(call mkdep,ubifs-utils/ubifs_dump/,ubifs_dump,,ubi-utils/libubi.a)
diff --git a/ubifs-utils/include/master.h b/ubifs-utils/include/master.h
new file mode 100644
index 0000000..0e51455
--- /dev/null
+++ b/ubifs-utils/include/master.h
@@ -0,0 +1,7 @@
+#ifndef __UBIFS_MASTER_H__
+#define __UBIFS_MASTER_H__
+
+int scan_for_master(struct ubifs_info *c, struct ubifs_mst_node *mst_node);
+int ubifs_read_master(struct ubifs_info *c);
+
+#endif
diff --git a/ubifs-utils/include/ubifs.h b/ubifs-utils/include/ubifs.h
index d2ddd0a..d4794cf 100644
--- a/ubifs-utils/include/ubifs.h
+++ b/ubifs-utils/include/ubifs.h
@@ -32,9 +32,23 @@
 /* Maximum logical eraseblock size in bytes */
 #define UBIFS_MAX_LEB_SZ (2*1024*1024)
 
+/* "File system end of life" sequence number watermark */
+#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL
+#define SQNUM_WATERMARK      0xFFFFFFFFFF000000ULL
+
 /* Minimum amount of data UBIFS writes to the flash */
 #define MIN_WRITE_SZ (UBIFS_DATA_NODE_SZ + 8)
 
+/*
+ * Currently we do not support inode number overlapping and re-using, so this
+ * watermark defines dangerous inode number level. This should be fixed later,
+ * although it is difficult to exceed current limit. Another option is to use
+ * 64-bit inode numbers, but this means more overhead.
+ */
+#define INUM_WARN_WATERMARK 0xFFF00000
+#define INUM_WATERMARK      0xFFFFFF00
+
+
 /* Largest key size supported in this implementation */
 #define CUR_MAX_KEY_LEN UBIFS_SK_LEN
 
@@ -281,6 +295,10 @@ enum {
  *
  * @highest_inum: highest used inode number
  * @max_sqnum: current global sequence number
+ * @cmt_no: commit number of the last successfully completed commit, protected
+ *          by @commit_sem
+ *
+ * @lhead_lnum: log head logical eraseblock number
  *
  * @jhead_cnt: count of journal heads
  * @max_bud_bytes: maximum number of bytes allowed in buds
@@ -354,11 +372,15 @@ enum {
  * @lsave_offs: offset of LPT's save table
  * @lsave: LPT's save table
  * @lscan_lnum: LEB number of last LPT scan
+ * @verbose: verbose mode enabled
  */
 struct ubifs_info
 {
 	ino_t highest_inum;
 	unsigned long long max_sqnum;
+	unsigned long long cmt_no;
+
+	int lhead_lnum;
 
 	int jhead_cnt;
 	long long max_bud_bytes;
@@ -442,6 +464,8 @@ struct ubifs_info
 	int max_idx_node_sz;
 
 	int max_znode_sz;
+
+	int verbose;
 };
 /**
  * struct ubifs_scan_node - UBIFS scanned node information.
diff --git a/ubifs-utils/lib/master.c b/ubifs-utils/lib/master.c
new file mode 100644
index 0000000..ee640c7
--- /dev/null
+++ b/ubifs-utils/lib/master.c
@@ -0,0 +1,311 @@
+/*
+ * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ */
+/*
+ * Modifications for mtd-utils.
+ *
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
+/* This file implements reading and writing the master node */
+
+#define PROGRAM_NAME "master"
+
+#include "ubifs_common.h"
+#include "common.h"
+#include "ubifs.h"
+#include "scan.h"
+#include "master.h"
+
+
+/**
+ * scan_for_master - search the valid master node.
+ * @c: UBIFS file-system description object
+ * @mst_node: output master node
+ *
+ * This function scans the master node LEBs and search for the latest master
+ * node. Returns zero in case of success, %-EUCLEAN if there master area is
+ * corrupted and requires recovery, and a negative error code in case of
+ * failure.
+ */
+int scan_for_master(struct ubifs_info *c, struct ubifs_mst_node *mst_node)
+{
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	int lnum, offs = 0, nodes_cnt;
+	int err = -EUCLEAN;
+
+	lnum = UBIFS_MST_LNUM;
+
+	sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
+	if (IS_ERR(sleb)) {
+		err = PTR_ERR(sleb);
+		goto out;
+	}
+	nodes_cnt = sleb->nodes_cnt;
+	if (nodes_cnt > 0) {
+		snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+				  list);
+		if (snod->type != UBIFS_MST_NODE)
+			goto out_dump;
+		memcpy(mst_node, snod->node, snod->len);
+		offs = snod->offs;
+	}
+	ubifs_scan_destroy(sleb);
+
+	lnum += 1;
+
+	sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
+	if (IS_ERR(sleb)) {
+		err = PTR_ERR(sleb);
+		goto out;
+	}
+	if (sleb->nodes_cnt != nodes_cnt)
+		goto out_destroy;
+	if (!sleb->nodes_cnt)
+		goto out_destroy;
+	snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
+	if (snod->type != UBIFS_MST_NODE)
+		goto out_dump;
+	if (snod->offs != offs)
+		goto out_destroy;
+	if (memcmp((void *)mst_node + UBIFS_CH_SZ,
+		   (void *)snod->node + UBIFS_CH_SZ,
+		   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
+		goto out_destroy;
+
+	err = 0;
+
+out_destroy:
+	ubifs_scan_destroy(sleb);
+out:
+	return err;
+
+out_dump:
+	errmsg("unexpected node type %d master LEB %d:%d",
+		  snod->type, lnum, snod->offs);
+	err = -EINVAL;
+	goto out_destroy;
+}
+/**
+ * validate_master - validate master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function validates data which was read from master node. Returns zero
+ * if the data is all right and %-EINVAL if not.
+ */
+static int validate_master(const struct ubifs_info *c)
+{
+	long long main_sz;
+	int err;
+
+	if (c->max_sqnum >= SQNUM_WATERMARK) {
+		err = 1;
+		goto out;
+	}
+
+	if (c->cmt_no >= c->max_sqnum) {
+		err = 2;
+		goto out;
+	}
+
+	if (c->highest_inum >= INUM_WATERMARK) {
+		err = 3;
+		goto out;
+	}
+
+	if (c->lhead_lnum < UBIFS_LOG_LNUM ||
+	    c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs) {
+		err = 4;
+		goto out;
+	}
+
+	if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||
+	    c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {
+		err = 5;
+		goto out;
+	}
+
+	if (c->zroot.len < UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ ||
+	    c->zroot.len > INT_MAX) {
+		err = 6;
+		goto out;
+	}
+
+	if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {
+		err = 7;
+		goto out;
+	}
+
+	if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||
+	    c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||
+	    c->ihead_offs > c->leb_size || c->ihead_offs & 7) {
+		err = 8;
+		goto out;
+	}
+
+	main_sz = (long long)c->main_lebs * c->leb_size;
+
+	if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||
+	    c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {
+		err = 10;
+		goto out;
+	}
+
+	if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||
+	    c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||
+	    c->nhead_offs > c->leb_size) {
+		err = 11;
+		goto out;
+	}
+
+	if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||
+	    c->ltab_offs < 0 ||
+	    c->ltab_offs + c->ltab_sz > c->leb_size) {
+		err = 12;
+		goto out;
+	}
+
+	if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||
+	    c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||
+	    c->lsave_offs + c->lsave_sz > c->leb_size)) {
+		err = 13;
+		goto out;
+	}
+
+	if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {
+		err = 14;
+		goto out;
+	}
+
+	if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
+		err = 15;
+		goto out;
+	}
+
+	if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
+		err = 16;
+		goto out;
+	}
+
+	if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
+	    c->lst.total_free & 7) {
+		err = 17;
+		goto out;
+	}
+
+	if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
+		err = 18;
+		goto out;
+	}
+
+	if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
+		err = 19;
+		goto out;
+	}
+
+	if (c->lst.total_free + c->lst.total_dirty +
+	    c->lst.total_used > main_sz) {
+		err = 20;
+		goto out;
+	}
+
+	if (c->lst.total_dead < 0 ||
+	    c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
+	    c->lst.total_dead & 7) {
+		err = 22;
+		goto out;
+	}
+
+	if (c->lst.total_dark < 0 ||
+	    c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
+	    c->lst.total_dark & 7) {
+		err = 23;
+		goto out;
+	}
+
+	return 0;
+
+out:
+	errmsg("bad master node, error %d", err);
+	return -EINVAL;
+}
+
+/**
+ * ubifs_read_master - read master node.
+ * @c: UBIFS file-system description object
+ *
+ * This function finds and reads the master node during file-system mount. If
+ * the flash is empty, it creates default master node as well. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+int ubifs_read_master(struct ubifs_info *c)
+{
+	int err;
+	struct ubifs_mst_node mst;
+
+	err = scan_for_master(c, &mst);
+	if (err) {
+		if (err == -EUCLEAN) {
+			normsg("master node requires recovery");
+			// TODO recover master node
+			// err = ubifs_recover_master_node(c);
+		} else
+			errmsg("failed to load master node");
+
+		if (err)
+			return err;
+	}
+
+	c->max_sqnum       = le64_to_cpu(mst.ch.sqnum);
+	c->highest_inum    = le64_to_cpu(mst.highest_inum);
+	c->cmt_no          = le64_to_cpu(mst.cmt_no);
+	c->zroot.lnum      = le32_to_cpu(mst.root_lnum);
+	c->zroot.offs      = le32_to_cpu(mst.root_offs);
+	c->zroot.len       = le32_to_cpu(mst.root_len);
+	c->lhead_lnum      = le32_to_cpu(mst.log_lnum);
+	c->gc_lnum         = le32_to_cpu(mst.gc_lnum);
+	c->ihead_lnum      = le32_to_cpu(mst.ihead_lnum);
+	c->ihead_offs      = le32_to_cpu(mst.ihead_offs);
+	c->lpt_lnum        = le32_to_cpu(mst.lpt_lnum);
+	c->lpt_offs        = le32_to_cpu(mst.lpt_offs);
+	c->nhead_lnum      = le32_to_cpu(mst.nhead_lnum);
+	c->nhead_offs      = le32_to_cpu(mst.nhead_offs);
+	c->ltab_lnum       = le32_to_cpu(mst.ltab_lnum);
+	c->ltab_offs       = le32_to_cpu(mst.ltab_offs);
+	c->lsave_lnum      = le32_to_cpu(mst.lsave_lnum);
+	c->lsave_offs      = le32_to_cpu(mst.lsave_offs);
+	c->lscan_lnum      = le32_to_cpu(mst.lscan_lnum);
+	c->lst.empty_lebs  = le32_to_cpu(mst.empty_lebs);
+	c->lst.idx_lebs    = le32_to_cpu(mst.idx_lebs);
+	c->lst.total_free  = le64_to_cpu(mst.total_free);
+	c->lst.total_dirty = le64_to_cpu(mst.total_dirty);
+	c->lst.total_used  = le64_to_cpu(mst.total_used);
+	c->lst.total_dead  = le64_to_cpu(mst.total_dead);
+	c->lst.total_dark  = le64_to_cpu(mst.total_dark);
+
+	verbose(c->verbose, "found master node with max sqnum %llu", c->max_sqnum);
+
+	return validate_master(c);
+}
diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
index c8e3439..2ac7fd8 100644
--- a/ubifs-utils/ubifs_dump/ubifs_dump.c
+++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
@@ -8,6 +8,7 @@
 #include "lpt.h"
 #include "scan.h"
 #include "hexdump.h"
+#include "master.h"
 
 #define DBG_KEY_BUF_LEN		48
 
@@ -483,71 +484,6 @@ static int dump_super(void)
 	return init_constants_sb(c);
 }
 
-/**
- * scan_for_master - search the valid master node.
- * @c: UBIFS file-system description object
- *
- * This function scans the master node LEBs and search for the latest master
- * node. Returns zero in case of success, %-EUCLEAN if there master area is
- * corrupted and requires recovery, and a negative error code in case of
- * failure.
- */
-static int scan_for_master(struct ubifs_info *c, struct ubifs_mst_node *mst_node)
-{
-	struct ubifs_scan_leb *sleb;
-	struct ubifs_scan_node *snod;
-	int lnum, offs = 0, nodes_cnt;
-	int err = 0;
-	
-	lnum = UBIFS_MST_LNUM;
-
-	sleb = ubifs_scan(c, lnum, 0, leb_buf, 1);
-	if (IS_ERR(sleb)) {
-		err = PTR_ERR(sleb);
-		goto out;
-	}
-	nodes_cnt = sleb->nodes_cnt;
-	if (nodes_cnt > 0) {
-		snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
-				  list);
-		if (snod->type != UBIFS_MST_NODE) {
-			err = -EINVAL;
-			goto out;
-		}
-		memcpy(mst_node, snod->node, snod->len);
-		offs = snod->offs;
-	}
-	ubifs_scan_destroy(sleb);
-
-	lnum += 1;
-
-	sleb = ubifs_scan(c, lnum, 0, leb_buf, 1);
-	if (IS_ERR(sleb)) {
-		err = PTR_ERR(sleb);
-		goto out;
-	}
-	err = -EUCLEAN;
-	if (sleb->nodes_cnt != nodes_cnt)
-		goto out;
-	if (!sleb->nodes_cnt)
-		goto out;
-	snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);
-	if (snod->type != UBIFS_MST_NODE) {
-		err = -EINVAL;
-		goto out;
-	}
-	if (snod->offs != offs)
-		goto out;
-	if (memcmp((void *)mst_node + UBIFS_CH_SZ,
-		   (void *)snod->node + UBIFS_CH_SZ,
-		   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
-		goto out;
-	err = 0;
-
-out:
-	ubifs_scan_destroy(sleb);
-	return err;
-}
 
 static int dump_master(void)
 {
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 08/11] ubifs: add missing include to defs.h
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (6 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 07/11] ubifs: extend master scanning code Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 09/11] ubifs: Add more key helper functions Richard Weinberger
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/include/defs.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ubifs-utils/include/defs.h b/ubifs-utils/include/defs.h
index 91ef175..93ff912 100644
--- a/ubifs-utils/include/defs.h
+++ b/ubifs-utils/include/defs.h
@@ -16,6 +16,7 @@
 #include <stddef.h>
 #include <linux/types.h>
 #include <stdint.h>
+#include <limits.h>
 
 #include <features.h>
 
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 09/11] ubifs: Add more key helper functions
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (7 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 08/11] ubifs: add missing include to defs.h Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:15 ` [PATCH 10/11] ubifs: add emubi, a minimal UBI emulation layer Richard Weinberger
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/include/key.h | 78 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/ubifs-utils/include/key.h b/ubifs-utils/include/key.h
index 9ee7597..77f840d 100644
--- a/ubifs-utils/include/key.h
+++ b/ubifs-utils/include/key.h
@@ -120,6 +120,17 @@ static inline void dent_key_init(const struct ubifs_info *c __attribute__((unuse
 }
 
 /**
+ * lowest_dent_key - get the lowest possible directory entry key.
+ * @key: where to store the lowest key
+ * @inum: parent inode number
+ */
+static inline void lowest_dent_key(union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS;
+}
+
+/**
  * data_key_init - initialize data key.
  * @c: UBIFS file-system description object
  * @key: key to initialize
@@ -164,6 +175,17 @@ static inline void key_write_idx(const union ubifs_key *from, void *to)
 }
 
 /**
+ * key_copy - copy a key.
+ * @c: UBIFS file-system description object
+ * @from: the key to copy from
+ * @to: the key to copy to
+ */
+static inline void key_copy(const union ubifs_key *from, union ubifs_key *to)
+{
+	to->u64[0] = from->u64[0];
+}
+
+/**
  * keys_cmp - compare keys.
  * @c: UBIFS file-system description object
  * @key1: the first key to compare
@@ -201,6 +223,22 @@ static inline void key_read(const void *from, union ubifs_key *to)
 }
 
 /**
+ * trun_key_init - initialize truncation node key.
+ * @c: UBIFS file-system description object
+ * @key: key to initialize
+ * @inum: inode number
+ *
+ * Note, UBIFS does not have truncation keys on the media and this function is
+ * only used for purposes of replay.
+ */
+static inline void trun_key_init(const struct ubifs_info *c __attribute__((unused)),
+				 union ubifs_key *key, ino_t inum)
+{
+	key->u32[0] = inum;
+	key->u32[1] = UBIFS_TRUN_KEY << UBIFS_S_KEY_BLOCK_BITS;
+}
+
+/**
  * invalid_key_init - initialize invalid node key.
  * @key: key to initialize
  *
@@ -220,6 +258,18 @@ static inline int key_type(const union ubifs_key *key)
 	return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS;
 }
 
+/**
+ * key_type_flash - get type of a on-flash formatted key.
+ * @c: UBIFS file-system description object
+ * @k: key to get type of
+ */
+static inline int key_type_flash(const void *k)
+{
+	const union ubifs_key *key = k;
+
+	return le32_to_cpu(key->j32[1]) >> UBIFS_S_KEY_BLOCK_BITS;
+}
+
 /*
  * key_hash - get directory entry hash.
  * @key: the key to get hash from
@@ -248,4 +298,32 @@ static inline unsigned int key_block(const union ubifs_key *key)
 {
 	return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK;
 }
+
+/**
+ * is_hash_key - is a key vulnerable to hash collisions.
+ * @key: key
+ *
+ * This function returns %1 if @key is a hashed key or %0 otherwise.
+ */
+static inline int is_hash_key(const union ubifs_key *key)
+{
+	int type = key_type(key);
+
+	return type == UBIFS_DENT_KEY || type == UBIFS_XENT_KEY;
+}
+
+/**
+ * key_max_inode_size - get maximum file size allowed by current key format.
+ * @c: UBIFS file-system description object
+ */
+static inline unsigned long long key_max_inode_size(const struct ubifs_info *c)
+{
+	switch (c->key_fmt) {
+	case UBIFS_SIMPLE_KEY_FMT:
+		return (1ULL << UBIFS_S_KEY_BLOCK_BITS) * UBIFS_BLOCK_SIZE;
+	default:
+		return 0;
+	}
+}
+
 #endif /* !__UBIFS_KEY_H__ */
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 10/11] ubifs: add emubi, a minimal UBI emulation layer
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (8 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 09/11] ubifs: Add more key helper functions Richard Weinberger
@ 2015-10-31 11:15 ` Richard Weinberger
  2015-10-31 11:16 ` [PATCH 11/11] ubifs: add ubifs_unpack Richard Weinberger
  2015-11-02  1:31 ` [RFC] UBIFS unpacker v0 Dongsheng Yang
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:15 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

emubi enables processing of ubi images (e.g. created using nanddump) as input
instead of using the ubi volume directly.

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 Makefile                    |   2 +-
 ubifs-utils/include/emubi.h |  81 ++++++++++
 ubifs-utils/include/io.h    |   2 +
 ubifs-utils/include/ubifs.h |   4 +
 ubifs-utils/lib/emubi.c     | 351 ++++++++++++++++++++++++++++++++++++++++++++
 ubifs-utils/lib/io.c        |  63 +++++++-
 ubifs-utils/lib/scan.c      |  10 +-
 7 files changed, 510 insertions(+), 3 deletions(-)
 create mode 100644 ubifs-utils/include/emubi.h
 create mode 100644 ubifs-utils/lib/emubi.c

diff --git a/Makefile b/Makefile
index 91f9820..72681f4 100644
--- a/Makefile
+++ b/Makefile
@@ -130,7 +130,7 @@ $(foreach v,$(UBI_BINS),$(eval $(call mkdep,ubi-utils/,$(v),libubi.a ubiutils-co
 #
 # Utils in ubifs-utils subdir
 #
-$(foreach v,crc16.o lpt.o compr.o devtable.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
+$(foreach v,crc16.o lpt.o compr.o devtable.o emubi.o io.o hashtable.o hashtable_itr.o,$(eval UBIFS_LIBS += ../lib/$(v)))
 
 obj-ubifs_dump = $(UBIFS_LIBS)
 obj-ubifs_dump += ../lib/scan.o ../lib/master.o ../lib/lprops.o ../lib/hexdump.o
diff --git a/ubifs-utils/include/emubi.h b/ubifs-utils/include/emubi.h
new file mode 100644
index 0000000..e06ba7d
--- /dev/null
+++ b/ubifs-utils/include/emubi.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
+#ifndef __UBIFS_EMUBI_H__
+#define __UBIFS_EMUBI_H__
+
+#include <assert.h>
+#include "list.h"
+
+enum {
+	EMUBI_MODE_FILE,
+	EMUBI_MODE_MMAP
+};
+
+/*
+ * LEB to PEB mapping.
+ * @pnum: PEB number this LEB belongs to, (for mode EMUBI_MODE_FILE)
+ * @data: pointer to start of PEB data (for mode EMUBI_MODE_MMAP)
+ */
+union emubi_eba {
+	int pnum;
+	char *data;
+};
+
+/*
+ * embui context
+ * @peb_size: PEB size in bytes
+ * @page_size: min I/O size used for UBI data (this is not the sub-page size)
+ * @vol_id: volume id
+ * @flash_fd: file descriptor of input file
+ * @mode: emubi mode
+ * @flash_mmap: mmap-ed input file when mode is set to EMUBI_MODE_MMAP
+ * @flash_size: total flash size in bytes
+ * @peb_count: total number of PEBs
+ * @leb_start: offset where LEB data starts
+ * @ff_peb: empty PEB
+ * @eba: eraseblock association table
+ * @scan_lebs: list of scanned LEBs
+ */
+struct emubi_ctx {
+	int peb_size;
+	int page_size;
+	int vol_id;
+
+	int flash_fd;
+	int mode;
+	char *flash_mmap;
+	unsigned long flash_size;
+
+	unsigned int peb_count;
+	unsigned int leb_start;
+	char *ff_peb;
+	union emubi_eba *eba;
+
+	struct list_head scan_lebs;
+};
+
+void emubi_print(struct emubi_ctx *ctx);
+int emubi_scan(struct emubi_ctx *ctx);
+int emubi_open(struct emubi_ctx *ctx, char *file);
+int emubi_leb_read(struct emubi_ctx *ctx, unsigned int lnum, unsigned int offset,
+		   char *lbuf, size_t len);
+
+#endif
diff --git a/ubifs-utils/include/io.h b/ubifs-utils/include/io.h
index 11f568c..e5c3d6c 100644
--- a/ubifs-utils/include/io.h
+++ b/ubifs-utils/include/io.h
@@ -18,4 +18,6 @@ int open_target(struct ubifs_info *c, int yes);
 int open_ubi(struct ubifs_info *c, const char *node);
 
 int ubifs_read(loff_t offset, int len, void *buf);
+int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
+		   int len);
 #endif
diff --git a/ubifs-utils/include/ubifs.h b/ubifs-utils/include/ubifs.h
index d4794cf..ed04383 100644
--- a/ubifs-utils/include/ubifs.h
+++ b/ubifs-utils/include/ubifs.h
@@ -28,6 +28,7 @@
 #include "defs.h"
 #include "list.h"
 #include "libubi.h"
+#include "emubi.h"
 
 /* Maximum logical eraseblock size in bytes */
 #define UBIFS_MAX_LEB_SZ (2*1024*1024)
@@ -372,6 +373,8 @@ enum {
  * @lsave_offs: offset of LPT's save table
  * @lsave: LPT's save table
  * @lscan_lnum: LEB number of last LPT scan
+ *
+ * @emubi: emubi context for working with image files
  * @verbose: verbose mode enabled
  */
 struct ubifs_info
@@ -465,6 +468,7 @@ struct ubifs_info
 
 	int max_znode_sz;
 
+	struct emubi_ctx *emubi;
 	int verbose;
 };
 /**
diff --git a/ubifs-utils/lib/emubi.c b/ubifs-utils/lib/emubi.c
new file mode 100644
index 0000000..1c88eea
--- /dev/null
+++ b/ubifs-utils/lib/emubi.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
+#define PROGRAM_NAME "emubi"
+
+#include <sys/mman.h>
+
+#include "emubi.h"
+#include "common.h"
+#include "ubifs_common.h"
+#include "crc32.h"
+#include "xalloc.h"
+
+struct ubi_scan_leb {
+	struct list_head l;
+	int lnum;
+	int pnum;
+	unsigned long long sqnum;
+	unsigned int copy_flag:1;
+};
+
+static inline int get_peb(struct emubi_ctx *ctx, unsigned int pnum, char **pbuf,
+			  unsigned int offset, unsigned int len)
+{
+	off_t pos;
+
+	if (pnum >= ctx->peb_count)
+		errmsg_die("Invalid PEB number %u", pnum);
+
+	if (offset >= ctx->peb_size)
+		errmsg_die("Invalid read offset %u (PEB size %u)", offset, ctx->peb_size);
+
+	if (len > ctx->peb_size - offset)
+		return errmsg("Invalid read outside of PEB (size %u, offset %u, read len %u)",
+			      ctx->peb_size, offset, len);
+
+	pos = (pnum * ctx->peb_size) + offset;
+	switch (ctx->mode) {
+	case EMUBI_MODE_MMAP:
+		*pbuf = ctx->flash_mmap + pos;
+		break;
+	case EMUBI_MODE_FILE:
+		if (!*pbuf)
+			errmsg_die("pbuf must not be null!");
+
+		if (lseek(ctx->flash_fd, pos, SEEK_SET) != pos)
+			return errmsg("Failed to lseek input file: %m");
+
+		if (read(ctx->flash_fd, *pbuf, len) != len)
+			return errmsg("Failed to read from input file: %m");
+
+		break;
+	default:
+		return errmsg("Invalid emubi mode %d", ctx->mode);
+	}
+
+	return 0;
+}
+
+int emubi_leb_read(struct emubi_ctx *ctx, unsigned int lnum, unsigned int offset,
+		   char *lbuf, size_t len)
+{
+	char *leb;
+	int err;
+
+	if (lnum >= ctx->peb_count)
+		return errmsg("LEB number invalid %u!", lnum);
+
+	switch (ctx->mode) {
+	case EMUBI_MODE_MMAP:
+		if (ctx->eba[lnum].data)
+			leb = ctx->eba[lnum].data;
+		else
+			leb = ctx->ff_peb;
+
+		memcpy(lbuf, leb + ctx->leb_start + offset, len);
+		break;
+	case EMUBI_MODE_FILE:
+		if (ctx->eba[lnum].pnum == -1) {
+			memset(lbuf, 0xFF, len);
+		} else {
+			err = get_peb(ctx, ctx->eba[lnum].pnum, &lbuf,
+				      ctx->leb_start + offset, len);
+			if (err)
+				return errmsg("LEB read failed: %m");
+		}
+
+		break;
+	default:
+		errmsg_die("Unknown emubi mode!");
+	}
+
+	return 0;
+}
+
+static struct ubi_scan_leb *scan_leb_new(int pnum, struct ubi_vid_hdr *vh)
+{
+	struct ubi_scan_leb *sl = xmalloc(sizeof(*sl));
+
+	sl->lnum = be32toh(vh->lnum);
+	sl->sqnum = be64toh(vh->sqnum);
+	sl->pnum = pnum;
+	sl->copy_flag = !!vh->copy_flag;
+
+	return sl;
+}
+
+static int scan_leb_crc_check(struct emubi_ctx *ctx, int pnum, struct ubi_vid_hdr *vh, char *pbuf)
+{
+	int data_len;
+	uint32_t data_crc, crc;
+
+	if (!vh->copy_flag)
+		return 0;
+
+	data_len = be32toh(vh->data_size);
+	if (!data_len)
+		return 0;
+
+	assert(data_len <= ctx->peb_size - ctx->leb_start);
+
+	data_crc = be32toh(vh->data_crc);
+	crc = mtd_crc32(UBI_CRC32_INIT, pbuf + ctx->leb_start, data_len);
+
+	if (crc != data_crc) {
+		errmsg("crc mismatch in peb %i", pnum);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void scan_leb_apply(struct emubi_ctx *ctx, int pnum, struct ubi_vid_hdr *scan_vh, char *pbuf)
+{
+	struct ubi_scan_leb *tmp_sl, *sl, *dup_sl = NULL;
+	int lnum = be32toh(scan_vh->lnum);
+
+	if (scan_leb_crc_check(ctx, pnum, scan_vh, pbuf) < 0)
+		return;
+
+	list_for_each_entry(tmp_sl, &ctx->scan_lebs, l) {
+		if (tmp_sl->lnum == lnum) {
+			dup_sl = tmp_sl;
+			break;
+		}
+	}
+
+	sl = scan_leb_new(pnum, scan_vh);
+
+	if (sl->lnum >= ctx->peb_count) {
+		warnmsg("Found a LEB >= PEB count! Image truncated?");
+		return;
+	}
+
+	if (!dup_sl) {
+		list_add_tail(&sl->l, &ctx->scan_lebs);
+
+		return;
+	}
+
+	if (dup_sl->sqnum == sl->sqnum)
+		errmsg_die("Duplicate LEB with identical UBI sequence number!");
+
+	if (dup_sl->sqnum > sl->sqnum) {
+		free(sl);
+	} else {
+		list_del(&dup_sl->l);
+		free(dup_sl);
+		list_add_tail(&sl->l, &ctx->scan_lebs);
+	}
+}
+
+static int eba_from_scan(struct emubi_ctx *ctx)
+{
+	struct ubi_scan_leb *sl;
+
+	list_for_each_entry(sl, &ctx->scan_lebs, l) {
+		switch (ctx->mode) {
+		case EMUBI_MODE_MMAP:
+			ctx->eba[sl->lnum].data = ctx->flash_mmap + (sl->pnum * ctx->peb_size);
+			break;
+		case EMUBI_MODE_FILE:
+			ctx->eba[sl->lnum].pnum = sl->pnum;
+			break;
+		default:
+			return errmsg("Invalid emubi mode %d", ctx->mode);
+		}
+	}
+
+	return 0;
+}
+
+void emubi_print(struct emubi_ctx *ctx)
+{
+	normsg("flash metadata:");
+	printf("\tPEB size: ");
+	print_bytes(ctx->peb_size, 0);
+	printf("\n\tmin. I/O unit size: ");
+	print_bytes(ctx->page_size, 0);
+	printf("\n\tvolume ID: %d", ctx->vol_id);
+
+	if (ctx->flash_mmap) {
+		printf("\n\tflash size: ");
+		print_bytes(ctx->flash_size, 0);
+		printf("\n\tPEB count: %u", ctx->peb_count);
+		printf("\n\tdata offset: %u", ctx->leb_start);
+	}
+	printf("\n\temubi mode: %s\n", (ctx->mode == EMUBI_MODE_MMAP) ? "mmap" : "file");
+}
+
+static int is_empty(struct emubi_ctx *ctx, char *pbuf, size_t len)
+{
+	return memcmp(pbuf, ctx->ff_peb, len) == 0;
+}
+
+static inline void init_eba(struct emubi_ctx *ctx, int leb_start)
+{
+	int i;
+	//TODO: replace peb_count by correct value from vol table
+	ctx->eba = xcalloc(ctx->peb_count, sizeof(ctx->eba[0]));
+	ctx->leb_start = leb_start;
+
+	if (ctx->mode == EMUBI_MODE_FILE) {
+		for (i = 0; i < ctx->peb_count; i++) {
+			ctx->eba[i].pnum = -1;
+		}
+	}
+}
+
+int emubi_scan(struct emubi_ctx *ctx)
+{
+	int n, err;
+	char *pbuf = NULL;
+
+	INIT_LIST_HEAD(&ctx->scan_lebs);
+
+	if (ctx->mode == EMUBI_MODE_FILE)
+		pbuf = xmalloc(ctx->peb_size);
+
+	normsg("scanning for logical erase blocks...");
+	for (n = 0; n < ctx->peb_count; n++) {
+		err = get_peb(ctx, n, &pbuf, 0, ctx->peb_size);
+		if (err)
+			goto out;
+
+		struct ubi_ec_hdr *ec = (struct ubi_ec_hdr *)pbuf;
+		struct ubi_vid_hdr *vid;
+
+		if (be32toh(ec->magic) != UBI_EC_HDR_MAGIC) {
+			errmsg("PEB %u contains no valid EC header\n", n);
+			continue;
+		}
+
+		vid = (struct ubi_vid_hdr *)(pbuf + be32toh(ec->vid_hdr_offset));
+		if (be32toh(vid->magic) != UBI_VID_HDR_MAGIC) {
+			/* skip over pebs with empty vid header */
+			if (is_empty(ctx, (char *)vid, ctx->page_size))
+				continue;
+
+			errmsg("PEB %u contains invalid VID header\n", n);
+		}
+
+		if (!ctx->eba) {
+			init_eba(ctx, be32toh(ec->data_offset));
+		}
+
+		if (be32toh(vid->vol_id) == ctx->vol_id)
+			scan_leb_apply(ctx, n, vid, pbuf);
+	}
+
+	err = eba_from_scan(ctx);
+
+out:
+	if (ctx->mode == EMUBI_MODE_FILE)
+		free(pbuf);
+
+	return err;
+}
+
+int emubi_open(struct emubi_ctx *ctx, char *file)
+{
+	int err;
+	int fd;
+	struct stat stbuf;
+
+	normsg("opening UBI image file %s...", file);
+	fd = open(file, O_RDONLY);
+	if (fd < 0) {
+		errmsg("Unable to open %s: %m", file);
+		err = -1;
+		goto out;
+	}
+
+	memset(&stbuf, 0, sizeof(stbuf));
+	if (fstat(fd, &stbuf) != 0) {
+		errmsg("Unable to stat %s: %m", file);
+		close(fd);
+		err = -1;
+		goto out;
+	}
+	ctx->flash_size = stbuf.st_size;
+	if (ctx->flash_size % ctx->peb_size) {
+		errmsg("Image size is not a multiple of PEB size %u", ctx->peb_size);
+		close(fd);
+		err = -1;
+		goto out;
+	}
+
+	if (ctx->mode == EMUBI_MODE_MMAP) {
+		ctx->flash_mmap = mmap(NULL, ctx->flash_size, PROT_READ, MAP_PRIVATE, fd, 0);
+		if (ctx->flash_mmap == MAP_FAILED) {
+			errmsg("Unable to mmap %s: %m. Falling back to file mode", file);
+			ctx->flash_mmap = NULL;
+			ctx->mode = EMUBI_MODE_FILE;
+		} else {
+			/* we won't need that anymore */
+			close(fd);
+		}
+	}
+
+	if (ctx->mode == EMUBI_MODE_FILE) {
+		ctx->flash_mmap = NULL;
+		ctx->flash_fd = fd;
+	}
+
+	ctx->eba = NULL;
+	ctx->peb_count = ctx->flash_size / ctx->peb_size;
+	ctx->ff_peb = xmalloc(ctx->peb_size);
+	memset(ctx->ff_peb, 0xFF, ctx->peb_size);
+
+	err = 0;
+out:
+	return err;
+}
diff --git a/ubifs-utils/lib/io.c b/ubifs-utils/lib/io.c
index c2e0d63..28d8504 100644
--- a/ubifs-utils/lib/io.c
+++ b/ubifs-utils/lib/io.c
@@ -1,7 +1,39 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation.
+ * Copyright (C) 2008 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy
+ *          Zoltan Sogor
+ */
+/*
+ * Modifications for mtd-utils.
+ *
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
 #include "io.h"
 #define PROGRAM_NAME "ubifs-io"
-#include <common.h>
+#include "common.h"
+#include "emubi.h"
 
+// TODO: move these to struct ubifs_info ?
 int out_fd;
 int out_ubi;
 libubi_t ubi;
@@ -150,3 +182,32 @@ int ubifs_read(loff_t offset, int len, void *buf)
 
 	return 0;
 }
+
+/*
+ * ubifs_leb_read - read LEB data
+ * @c: ubifs context
+ * @lnum: LEB number
+ * @buf: output buffer
+ * @offs: offset in LEB
+ * @len: length of data to read
+ */
+
+int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
+		   int len)
+{
+	int seek_offs;
+
+	if (c->emubi) {
+		emubi_leb_read(c->emubi, lnum, offs, buf, len);
+	} else {
+		seek_offs = (lnum * c->leb_size) + offs;
+		if (lseek(out_fd, seek_offs, SEEK_SET) != seek_offs)
+			return sys_err_msg("lseek failed seeking %d", seek_offs);
+
+		if (read(out_fd, buf, len) != len)
+			return sys_err_msg("read failed reading %d bytes at pos %d",
+					   len, seek_offs);
+	}
+
+	return 0;
+}
diff --git a/ubifs-utils/lib/scan.c b/ubifs-utils/lib/scan.c
index 3c5be2c..1811e4a 100644
--- a/ubifs-utils/lib/scan.c
+++ b/ubifs-utils/lib/scan.c
@@ -16,6 +16,14 @@
  * this program; if not, write to the Free Software Foundation, Inc., 51
  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
+/*
+ * Modifications for mtd-utils.
+ *
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
 
 /*
  * This file implements the scan which is a general-purpose function for
@@ -131,7 +139,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
 	INIT_LIST_HEAD(&sleb->nodes);
 	sleb->buf = sbuf;
 
-	err = ubifs_read(lnum * c->leb_size + offs, c->leb_size - offs, sbuf + offs);
+	err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs);
 	if (err && err != -EBADMSG) {
 		kfree(sleb);
 		return ERR_PTR(err);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 11/11] ubifs: add ubifs_unpack
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (9 preceding siblings ...)
  2015-10-31 11:15 ` [PATCH 10/11] ubifs: add emubi, a minimal UBI emulation layer Richard Weinberger
@ 2015-10-31 11:16 ` Richard Weinberger
  2015-11-02  1:31 ` [RFC] UBIFS unpacker v0 Dongsheng Yang
  11 siblings, 0 replies; 16+ messages in thread
From: Richard Weinberger @ 2015-10-31 11:16 UTC (permalink / raw)
  To: linux-mtd; +Cc: david, yangds.fnst, Richard Weinberger

From: David Gstir <david@sigma-star.at>

ubifs_unpack allows unpacking of ubifs volumes. Input can be either a image
file created from nanddump or a ubi volume.

ubifs_unpack also performs necessary sanity checks and prints a detailed report
of the FS-state.

Signed-off-by: David Gstir <david@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 Makefile                                |   7 +-
 ubifs-utils/include/emubi.h             |   1 +
 ubifs-utils/include/list_sort.h         |  11 +
 ubifs-utils/include/ubifs.h             |  32 ++
 ubifs-utils/lib/emubi.c                 |  20 +
 ubifs-utils/lib/list_sort.c             | 157 ++++++
 ubifs-utils/ubifs_unpack/index.c        | 648 ++++++++++++++++++++++++
 ubifs-utils/ubifs_unpack/replay.c       | 865 ++++++++++++++++++++++++++++++++
 ubifs-utils/ubifs_unpack/ubifs_unpack.c | 619 +++++++++++++++++++++++
 ubifs-utils/ubifs_unpack/ubifs_unpack.h | 107 ++++
 10 files changed, 2466 insertions(+), 1 deletion(-)
 create mode 100644 ubifs-utils/include/list_sort.h
 create mode 100644 ubifs-utils/lib/list_sort.c
 create mode 100644 ubifs-utils/ubifs_unpack/index.c
 create mode 100644 ubifs-utils/ubifs_unpack/replay.c
 create mode 100644 ubifs-utils/ubifs_unpack/ubifs_unpack.c
 create mode 100644 ubifs-utils/ubifs_unpack/ubifs_unpack.h

diff --git a/Makefile b/Makefile
index 72681f4..ea8dcee 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,8 @@ UBI_BINS = \
 	ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock
 UBIFS_BINS = \
 	mkfs.ubifs/mkfs.ubifs \
-	ubifs_dump/ubifs_dump
+	ubifs_dump/ubifs_dump \
+	ubifs_unpack/ubifs_unpack
 JFFSX_BINS = \
 	mkfs.jffs2 sumtool jffs2reader jffs2dump
 FLASH_BINS = \
@@ -138,6 +139,10 @@ LDFLAGS_ubifs_dump = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_ubifs_dump = -lz -llzo2 -lm -luuid
 $(call mkdep,ubifs-utils/ubifs_dump/,ubifs_dump,,ubi-utils/libubi.a)
 
+obj-ubifs_unpack = $(UBIFS_LIBS) ../lib/list_sort.o ../lib/scan.o ../lib/lpt.o ../lib/master.o ../../lib/libcrc32.o replay.o index.o
+LDFLAGS_ubifs_unpack = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS) -lz -llzo2
+$(call mkdep,ubifs-utils/ubifs_unpack/,ubifs_unpack,,ubi-utils/libubi.a)
+
 obj-mkfs.ubifs = $(UBIFS_LIBS)
 LDFLAGS_mkfs.ubifs = $(ZLIBLDFLAGS) $(LZOLDFLAGS) $(UUIDLDFLAGS)
 LDLIBS_mkfs.ubifs = -lz -llzo2 -lm -luuid
diff --git a/ubifs-utils/include/emubi.h b/ubifs-utils/include/emubi.h
index e06ba7d..a2883ce 100644
--- a/ubifs-utils/include/emubi.h
+++ b/ubifs-utils/include/emubi.h
@@ -73,6 +73,7 @@ struct emubi_ctx {
 };
 
 void emubi_print(struct emubi_ctx *ctx);
+void emubi_close(struct emubi_ctx *ctx);
 int emubi_scan(struct emubi_ctx *ctx);
 int emubi_open(struct emubi_ctx *ctx, char *file);
 int emubi_leb_read(struct emubi_ctx *ctx, unsigned int lnum, unsigned int offset,
diff --git a/ubifs-utils/include/list_sort.h b/ubifs-utils/include/list_sort.h
new file mode 100644
index 0000000..60c4217
--- /dev/null
+++ b/ubifs-utils/include/list_sort.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_LIST_SORT_H
+#define _LINUX_LIST_SORT_H
+
+#include "list.h"
+
+struct list_head;
+
+void list_sort(void *priv, struct list_head *head,
+	       int (*cmp)(void *priv, struct list_head *a,
+			  struct list_head *b));
+#endif
diff --git a/ubifs-utils/include/ubifs.h b/ubifs-utils/include/ubifs.h
index ed04383..d9a5c97 100644
--- a/ubifs-utils/include/ubifs.h
+++ b/ubifs-utils/include/ubifs.h
@@ -53,6 +53,9 @@
 /* Largest key size supported in this implementation */
 #define CUR_MAX_KEY_LEN UBIFS_SK_LEN
 
+/* Maximum possible inode number (only 32-bit inodes are supported now) */
+#define MAX_INUM 0xFFFFFFFF
+
 #define NONDATA_JHEADS_CNT 2
 /*
  * There is no notion of truncation key because truncation nodes do not exist
@@ -332,6 +335,8 @@ enum {
  * @old_idx_sz: size of index on flash
  * @lst: lprops statistics
  *
+ * @max_inode_sz: maximum possible inode size in bytes
+ *
  * @dead_wm: LEB dead space watermark
  * @dark_wm: LEB dark space watermark
  *
@@ -374,6 +379,10 @@ enum {
  * @lsave: LPT's save table
  * @lscan_lnum: LEB number of last LPT scan
  *
+ * @replay_list: temporary list used during journal replay
+ * @replay_buds: list of buds to replay
+ * @cs_sqnum: sequence number of first node in the log (commit start node)
+ *
  * @emubi: emubi context for working with image files
  * @verbose: verbose mode enabled
  */
@@ -417,6 +426,8 @@ struct ubifs_info
 	unsigned long long old_idx_sz;
 	struct ubifs_lp_stats lst;
 
+	long long max_inode_sz;
+
 	int dead_wm;
 	int dark_wm;
 
@@ -468,6 +479,10 @@ struct ubifs_info
 
 	int max_znode_sz;
 
+	struct list_head replay_list;
+	struct list_head replay_buds;
+	unsigned long long cs_sqnum;
+
 	struct emubi_ctx *emubi;
 	int verbose;
 };
@@ -550,6 +565,23 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
 				       (UBIFS_BRANCH_SZ + c->key_len) * bnum);
 }
 
+/**
+ * ubifs_next_log_lnum - switch to the next log LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: current log LEB
+ *
+ * This helper function returns the log LEB number which goes next after LEB
+ * 'lnum'.
+ */
+static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
+{
+	lnum += 1;
+	if (lnum > UBIFS_LOG_LNUM + c->log_lebs - 1)
+		lnum = UBIFS_LOG_LNUM;
+
+	return lnum;
+}
+
 /* Callback used by the 'ubifs_lpt_scan_nolock()' function */
 typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
 				       const struct ubifs_lprops *lprops,
diff --git a/ubifs-utils/lib/emubi.c b/ubifs-utils/lib/emubi.c
index 1c88eea..895f60c 100644
--- a/ubifs-utils/lib/emubi.c
+++ b/ubifs-utils/lib/emubi.c
@@ -225,6 +225,26 @@ void emubi_print(struct emubi_ctx *ctx)
 	printf("\n\temubi mode: %s\n", (ctx->mode == EMUBI_MODE_MMAP) ? "mmap" : "file");
 }
 
+static void destroy_scan_lebs(struct list_head *scan_lebs)
+{
+	struct ubi_scan_leb *sleb, *ltmp;
+
+	if (!list_empty(scan_lebs)) {
+		list_for_each_entry_safe(sleb, ltmp, scan_lebs, l) {
+			list_del(&sleb->l);
+			free(sleb);
+		}
+	}
+
+}
+
+void emubi_close(struct emubi_ctx *ctx)
+{
+	free(ctx->eba);
+	free(ctx->ff_peb);
+	destroy_scan_lebs(&ctx->scan_lebs);
+}
+
 static int is_empty(struct emubi_ctx *ctx, char *pbuf, size_t len)
 {
 	return memcmp(pbuf, ctx->ff_peb, len) == 0;
diff --git a/ubifs-utils/lib/list_sort.c b/ubifs-utils/lib/list_sort.c
new file mode 100644
index 0000000..7579f12
--- /dev/null
+++ b/ubifs-utils/lib/list_sort.c
@@ -0,0 +1,157 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#define PROGRAM_NAME "list_sort"
+
+#include "list_sort.h"
+#include "common.h"
+#include "defs.h"
+
+#define MAX_LIST_LENGTH_BITS 20
+
+/*
+ * Returns a list organized in an intermediate format suited
+ * to chaining of merge() calls: null-terminated, no reserved or
+ * sentinel head node, "prev" links not maintained.
+ */
+static struct list_head *merge(void *priv,
+				int (*cmp)(void *priv, struct list_head *a,
+					struct list_head *b),
+				struct list_head *a, struct list_head *b)
+{
+	struct list_head head, *tail = &head;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(priv, a, b) <= 0) {
+			tail->next = a;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a?:b;
+	return head.next;
+}
+
+/*
+ * Combine final list merge with restoration of standard doubly-linked
+ * list structure.  This approach duplicates code from merge(), but
+ * runs faster than the tidier alternatives of either a separate final
+ * prev-link restoration pass, or maintaining the prev links
+ * throughout.
+ */
+static void merge_and_restore_back_links(void *priv,
+				int (*cmp)(void *priv, struct list_head *a,
+					struct list_head *b),
+				struct list_head *head,
+				struct list_head *a, struct list_head *b)
+{
+	struct list_head *tail = head;
+	u8 count = 0;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(priv, a, b) <= 0) {
+			tail->next = a;
+			a->prev = tail;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b->prev = tail;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a ? : b;
+
+	do {
+		/*
+		 * In worst cases this loop may run many iterations.
+		 * Continue callbacks to the client even though no
+		 * element comparison is needed, so the client's cmp()
+		 * routine can invoke cond_resched() periodically.
+		 */
+		if (unlikely(!(++count)))
+			(*cmp)(priv, tail->next, tail->next);
+
+		tail->next->prev = tail;
+		tail = tail->next;
+	} while (tail->next);
+
+	tail->next = head;
+	head->prev = tail;
+}
+
+/**
+ * list_sort - sort a list
+ * @priv: private data, opaque to list_sort(), passed to @cmp
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function implements "merge sort", which has O(nlog(n))
+ * complexity.
+ *
+ * The comparison function @cmp must return a negative value if @a
+ * should sort before @b, and a positive value if @a should sort after
+ * @b. If @a and @b are equivalent, and their original relative
+ * ordering is to be preserved, @cmp must return 0.
+ */
+void list_sort(void *priv, struct list_head *head,
+		int (*cmp)(void *priv, struct list_head *a,
+			struct list_head *b))
+{
+	struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+						-- last slot is a sentinel */
+	int lev;  /* index into part[] */
+	int max_lev = 0;
+	struct list_head *list;
+
+	if (list_empty(head))
+		return;
+
+	memset(part, 0, sizeof(part));
+
+	head->prev->next = NULL;
+	list = head->next;
+
+	while (list) {
+		struct list_head *cur = list;
+		list = list->next;
+		cur->next = NULL;
+
+		for (lev = 0; part[lev]; lev++) {
+			cur = merge(priv, cmp, part[lev], cur);
+			part[lev] = NULL;
+		}
+		if (lev > max_lev) {
+			if (lev >= ARRAY_SIZE(part)-1) {
+				printf("list too long for efficiency\n");
+				lev--;
+			}
+			max_lev = lev;
+		}
+		part[lev] = cur;
+	}
+
+	for (lev = 0; lev < max_lev; lev++)
+		if (part[lev])
+			list = merge(priv, cmp, part[lev], list);
+
+	merge_and_restore_back_links(priv, cmp, head, part[max_lev], list);
+}
diff --git a/ubifs-utils/ubifs_unpack/index.c b/ubifs-utils/ubifs_unpack/index.c
new file mode 100644
index 0000000..e60e32f
--- /dev/null
+++ b/ubifs-utils/ubifs_unpack/index.c
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
+#define PROGRAM_NAME "index"
+
+#include "ubifs_unpack.h"
+
+
+struct ubifs_ino_list {
+	ino_t ino;
+	struct list_head *start;
+	struct list_head l;
+};
+
+static LIST_HEAD(leaf_index);
+static LIST_HEAD(ino_index);
+
+
+static void get_key(struct ubifs_branch *zbr, union ubifs_key *key)
+{
+	union ubifs_key *tmp_key;
+
+	tmp_key = (union ubifs_key *)zbr->key;
+	key->u32[0] = le32toh(tmp_key->j32[0]);
+	key->u32[1] = le32toh(tmp_key->j32[1]);
+}
+
+static void index_add_leaf(union ubifs_key *key, unsigned int lnum,
+			   unsigned int offs, unsigned int len)
+{
+	struct ubifs_leaf *ul = xmalloc(sizeof(*ul));
+	struct ubifs_leaf *last_ul = NULL;
+
+	if (!list_empty(&leaf_index))
+		last_ul = list_last_entry(&leaf_index, struct ubifs_leaf, l);
+
+	ul->lnum = lnum;
+	ul->offs = offs;
+	ul->len = len;
+	key_copy(key, &ul->key);
+
+	if (!last_ul || key->u32[0] != last_ul->key.u32[0]) {
+		struct ubifs_ino_list *uil = xmalloc(sizeof(*uil));
+		uil->ino = key_inum(key);
+		uil->start = leaf_index.prev;
+
+
+		list_add_tail(&uil->l, &ino_index);
+	}
+
+	list_add_tail(&ul->l, &leaf_index);
+}
+
+/*
+ * ubifs_destroy_index - Cleanup index
+ * @c: ubifs context
+ */
+void ubifs_destroy_index()
+{
+	struct ubifs_leaf *leaf, *ltmp;
+	struct ubifs_ino_list *uil, *itmp;
+
+	if (!list_empty(&leaf_index)) {
+		list_for_each_entry_safe(leaf, ltmp, &leaf_index, l) {
+			list_del(&leaf->l);
+			free(leaf);
+		}
+	}
+
+	if (!list_empty(&ino_index)) {
+		list_for_each_entry_safe(uil, itmp, &ino_index, l) {
+			list_del(&uil->l);
+			free(uil);
+		}
+	}
+}
+
+/*
+ * ubifs_load_index - Load full index from media
+ * @c: ubifs context
+ * @lnum: LEB where index node is located
+ * @offs: offset in LEB
+ * @len: len if index node
+ */
+void ubifs_load_index(struct ubifs_info *c, unsigned int lnum,
+		      unsigned int offs, unsigned int len)
+{
+	struct ubifs_idx_node *idx;
+	union ubifs_key tmp_key;
+	struct ubifs_ch ch;
+	unsigned int i;
+
+	idx = xmalloc(len);
+	get_idx_node(c, idx, lnum, offs, len);
+
+	for (i = 0; i < le16toh(idx->child_cnt); i++) {
+		struct ubifs_branch *br = get_branch(idx, i);
+		unsigned int br_lnum = le32toh(br->lnum);
+		unsigned int br_offs = le32toh(br->offs);
+		unsigned int br_len = le32toh(br->len);
+
+		if (le16toh(idx->level) == 0) {
+			get_key(br, &tmp_key);
+			index_add_leaf(&tmp_key, br_lnum, br_offs, br_len);
+		}
+
+		ubifs_leb_read(c, br_lnum, &ch, br_offs, sizeof(ch));
+		if (ch.node_type == UBIFS_IDX_NODE)
+			ubifs_load_index(c, br_lnum, br_offs, br_len);
+	}
+
+	free(idx);
+}
+
+static struct ubifs_ino_list *lookup_ino_list(ino_t ino)
+{
+	struct ubifs_ino_list *uil;
+
+	list_for_each_entry(uil, &ino_index, l) {
+		if (uil->ino == ino)
+			return uil;
+	}
+
+	return NULL;
+}
+
+static struct ubifs_leaf *lookup_leaf(union ubifs_key *key, int *exact)
+{
+	struct ubifs_leaf *ul, *prev_ul = NULL;
+	struct list_head *start = NULL;
+	struct ubifs_ino_list *uil;
+	int res;
+
+	*exact = 0;
+
+	uil = lookup_ino_list(key_inum(key));
+	if (!uil)
+		return NULL;
+
+	start = uil->start;
+	assert(start);
+
+	list_for_each_entry(ul, start, l) {
+		res = keys_cmp(&ul->key, key);
+		if (res == 0) {
+			*exact = 1;
+			return ul;
+		}
+
+		if (res > 0) {
+			if (is_hash_key(key))
+				return prev_ul;
+			else
+				return NULL;
+		}
+
+		prev_ul = ul;
+	}
+
+	return NULL;
+}
+
+/*
+ * ubifs_lookup_ino_node - find INO node
+ * @c: ubifs context
+ * @ino: inode number
+ *
+ * Returns pointer to found ubifs_ino_node or NULL, if node was not found.
+ */
+struct ubifs_ino_node *ubifs_lookup_ino_node(struct ubifs_info *c, ino_t ino)
+{
+	struct ubifs_ino_node *i;
+	struct ubifs_leaf *leaf;
+	union ubifs_key key;
+	int exact;
+
+	ino_key_init(&key, ino);
+
+	leaf = lookup_leaf(&key, &exact);
+	if (!leaf || !exact)
+		return NULL;
+
+	i = xmalloc(leaf->len);
+	get_ino_node(c, i, leaf->lnum, leaf->offs, leaf->len);
+
+	return i;
+}
+
+/*
+ * ubifs_lookup_data_node - find DATA node
+ * @c: ubifs context
+ * @ino: inode number
+ * @block: block number
+ *
+ * Returns pointer to found ubifs_data_node or NULL, if node was not found.
+ */
+struct ubifs_data_node *ubifs_lookup_data_node(struct ubifs_info *c, ino_t ino,
+					       unsigned int block)
+{
+	struct ubifs_data_node *d;
+	struct ubifs_leaf *leaf;
+	union ubifs_key key;
+	int exact;
+
+	data_key_init(&key, ino, block);
+
+	leaf = lookup_leaf(&key, &exact);
+	if (!leaf || !exact)
+		return NULL;
+
+	d = xmalloc(leaf->len);
+	get_data_node(c, d, leaf->lnum, leaf->offs, leaf->len);
+
+	return d;
+}
+
+/*
+ * ubifs_next_leaf - Find the next leaf node after @ul which belongs to @ino.
+ * @ul: current leaf
+ * @ino: ino of current leaf
+ *
+ * If the end is reached, NULL is returned.
+ * If @ul is NULL, the first leaf node matching @ino is returned.
+ */
+struct ubifs_leaf *ubifs_next_leaf(struct ubifs_leaf *ul, ino_t ino)
+{
+	struct ubifs_leaf *next = NULL;
+	struct ubifs_ino_list *uil;
+
+	if (ul) {
+		next = list_next_entry(ul, l);
+		if (key_inum(&next->key) != ino)
+			next = NULL;
+	} else {
+		/* we don't have a leaf yet, so find the first */
+		uil = lookup_ino_list(ino);
+		if (uil && uil->start)
+			next = list_first_entry(uil->start, struct ubifs_leaf, l);
+	}
+
+	return next;
+}
+
+/*
+ * match_name - Compare @nm with name of node @leaf.
+ * @c: ubifs context
+ * @leaf: leaf node which name we want to match. It must use a hash key
+ * @nm: required name to match on
+ *
+ * This helps to resolve collisions for hash keys where duplicate keys are
+ * possible.
+ * Returns %-1 on error, %0 on full match and %1 on no match.
+ */
+static int match_name(struct ubifs_info *c, struct ubifs_leaf *leaf,
+		      struct qstr *nm)
+{
+	int len, ret;
+	struct ubifs_dent_node *dent;
+	assert(is_hash_key(&leaf->key));
+
+	if (!nm->name)
+		return -1;
+
+	dent = xmalloc(leaf->len);
+	get_dent_node(c, dent, leaf->lnum, leaf->offs, leaf->len);
+
+	len = (nm->len > le16toh(dent->nlen)) ? nm->len : dent->nlen;
+	ret = (memcmp(nm->name, dent->name, len) == 0) ? 0 : 1;
+
+	free(dent);
+
+	return ret;
+}
+
+/*
+ * index_remove_leaf - Safely remove a leaf from the skip list
+ * @leaf: the leaf to remove
+ * @uil: the ino_list entry. If NULL, will be search.
+ *
+ * Updates and removes ino_list entries accordingly.
+ * Returns %0 on success, %1 when last leaf was removed successfully and a
+ * value < 0 on error
+ */
+static int index_remove_leaf(struct ubifs_leaf *leaf, struct ubifs_ino_list *uil)
+{
+	struct ubifs_ino_list *next_uil;
+
+	if (!uil)
+		uil = lookup_ino_list(key_inum(&leaf->key));
+
+	if (!uil)
+		return -ENOENT;
+
+	/* fix ->start of next ino_list if we remove last node for this ino */
+	if (!list_is_last(&uil->l, &ino_index)) {
+		next_uil = list_next_entry(uil, l);
+		if (next_uil->start == &leaf->l)
+			next_uil->start = leaf->l.prev;
+	}
+
+	list_del(&leaf->l);
+	free(leaf);
+
+	/* if this was the last leaf, remove ino_list entry too */
+	leaf = list_first_entry(uil->start, struct ubifs_leaf, l);
+	if (key_inum(&leaf->key) != uil->ino) {
+		list_del(&uil->l);
+		free(uil);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * ubifs_remove_inode - Remove all nodes for @ino from index
+ * @c: ubifs context
+ * @ino: the inode number to remove
+ *
+ * Returns %0 on success or when @ino was not found, %-1 on error
+ */
+int ubifs_remove_inode(struct ubifs_info *c, ino_t ino)
+{
+	struct ubifs_ino_list *uil;
+	struct ubifs_leaf *ul;
+	int err = 0;
+
+	verbose(c->verbose, "remove all nodes of ino %lu", ino);
+
+	uil = lookup_ino_list(ino);
+	if (!uil)
+		goto out;
+
+	/* remove all leafs of this inode */
+	ul = list_first_entry(uil->start, struct ubifs_leaf, l);
+	while (key_inum(&ul->key) == ino) {
+		err = index_remove_leaf(ul, uil);
+		if (err) {
+			if (err == 1)
+				/* last entry was removed, we're done */
+				err = 0;
+			goto out;
+		}
+
+		ul = list_first_entry(uil->start, struct ubifs_leaf, l);
+	}
+
+out:
+	return err;
+}
+
+/*
+ * ubifs_remove_node_nm - Remove node with @key from index
+ * @c: ubifs context
+ * @key: the key of the node to remove
+ * @nm: when @key is a hash key, this file name is used to resolve collisions
+ *
+ * Returns %0 on success or when no matching node can be found in the index.
+ */
+int ubifs_remove_node_nm(struct ubifs_info *c, union ubifs_key *key,
+			 struct qstr *nm)
+{
+	ino_t ino;
+	struct ubifs_leaf *ul = NULL;
+	int match = -1, err = 0;
+
+	assert(c);
+	assert(key);
+	assert(nm);
+
+	ino = key_inum(key);
+	verbose(c->verbose, "remove node 0x%lx (ino %lu, type %d blk/hash %d, hash_key %d name %s)",
+		key->u64[0], ino, key_type(key), key_block(key), is_hash_key(key), nm->name);
+
+	while ((ul = ubifs_next_leaf(ul, ino))) {
+		match = keys_cmp(&ul->key, key);
+
+		/* no need to search further */
+		if (match > 0) {
+			normsg("ignoring remove of non-existant leaf from index (ino %lu)", ino);
+			break;
+		}
+
+		if (is_hash_key(key) && match == 0) {
+			match = match_name(c, ul, nm);
+			if (match < 0) {
+				err = match;
+				errmsg("name matching failed for key 0x%lx", key->u64[0]);
+				goto out;
+			}
+		}
+
+		if (match == 0) {
+			err = index_remove_leaf(ul, NULL);
+			if (err < 0)
+				errmsg("failed to remove leaf (ino %lu type %d)", ino, key_type(key));
+			/* there can only be a single match */
+			break;
+		}
+	}
+
+out:
+	return err;
+}
+
+/*
+ * ubifs_remove_node - Remove node with @key from index
+ * @c: ubifs context
+ * @key: key of node to remove
+ *
+ * This equivalent to ubifs_remove_node_nm() however, it can only be used for
+ * keys which will never collide.
+ */
+int ubifs_remove_node(struct ubifs_info *c, union ubifs_key *key)
+{
+	struct qstr empty = { .name = NULL };
+
+	if (!is_hash_key(key)) {
+		errmsg("requested key is not hash key!\n");
+		return -EINVAL;
+	}
+
+	return ubifs_remove_node_nm(c, key, &empty);
+}
+
+/**
+ * key_in_range - determine if a key falls within a range of keys.
+ * @key: key to check
+ * @from_key: lowest key in range
+ * @to_key: highest key in range
+ *
+ * This function returns %1 if the key is in range and %0 otherwise.
+ */
+static int key_in_range(union ubifs_key *key, union ubifs_key *from_key,
+			union ubifs_key *to_key)
+{
+	if (keys_cmp(key, from_key) < 0)
+		return 0;
+	if (keys_cmp(key, to_key) > 0)
+		return 0;
+	return 1;
+}
+
+/*
+ * ubifs_remove_node_range - Remove all nodes within the given key range
+ * @c: ubifs context
+ * @from_key: first key in range (min)
+ * @to_key: last key in range to remove (max)
+ *
+ * The keys must be for the same inode. No hash keys are supported.
+ */
+int ubifs_remove_node_range(struct ubifs_info *c, union ubifs_key *from_key,
+			    union ubifs_key *to_key)
+{
+	ino_t ino;
+	struct ubifs_ino_list *uil;
+	struct ubifs_leaf *ul, *rm_ul;
+	int err = 0;
+
+	ino = key_inum(from_key);
+	verbose(c->verbose, "remove node range for ino %lu type %d blk %d - %d",
+		ino, key_type(from_key), key_block(from_key), key_block(to_key));
+
+	uil = lookup_ino_list(ino);
+	if (!uil)
+		goto out;
+
+	ul = list_first_entry(uil->start, struct ubifs_leaf, l);
+	while (key_inum(&ul->key) == ino) {
+		rm_ul = ul;
+		ul = list_next_entry(ul, l);
+		if (key_in_range(&rm_ul->key, from_key, to_key)) {
+			err = index_remove_leaf(rm_ul, uil);
+			if (err) {
+				if (err == 1)
+					/* last entry was removed, we're done */
+					err = 0;
+				goto out;
+			}
+		}
+	}
+
+out:
+	return err;
+}
+
+static void index_insert_ino(struct ubifs_ino_list *uil)
+{
+	struct ubifs_ino_list *i;
+
+	list_for_each_entry(i, &ino_index, l) {
+		if (i->ino > uil->ino)
+			break;
+	}
+
+	if (&i->l != &ino_index) {
+		list_add_tail(&uil->l, &i->l);
+		uil->start = i->start;
+	} else {
+		list_add_tail(&uil->l, &ino_index);
+		uil->start = leaf_index.prev;
+	}
+}
+
+/*
+ * index_insert_leaf - Insert new leaf at correct position in sorted leaf list
+ * @c: ubifs context
+ * @key: key to insert
+ * @lnum: LEB number of new node
+ * @offs: offset in LEB @lnum
+ * @len: length of new node
+ * @nm: file name to resolve key collisions
+ *
+ * In case a corresponding leaf with the same key already exists, this leaf is
+ * just updated and no new leaf is created.
+ * Retruns %0 on succces, or a value < 0 on error.
+ */
+static int index_insert_leaf(struct ubifs_info *c,union ubifs_key *key,
+			     unsigned int lnum, unsigned int offs, unsigned int len,
+			     struct qstr *nm)
+{
+	int match, err, new_ino = 0;
+	ino_t ino = key_inum(key);
+	struct ubifs_ino_list *uil;
+	struct ubifs_leaf *leaf, *ul = NULL;
+	struct list_head *prev;
+
+	verbose(c->verbose, "add replay inode %lu on LEB %d:%d type %d", ino, lnum, offs, key_type(key));
+
+	uil = lookup_ino_list(ino);
+	if (!uil) {
+		uil = xcalloc(1, sizeof(*uil));
+		uil->ino = ino;
+		new_ino = 1;
+		goto insert;
+	}
+
+	/* find position in leaf list */
+	assert(uil->start);
+	prev = uil->start;
+	ul = list_first_entry(uil->start, struct ubifs_leaf, l);
+	do {
+		match = keys_cmp(&ul->key, key);
+
+		/* for hash keys with colliding key values, we insert the new
+		 * leaf right after the colliding ones */
+		if (match > 0)
+			break;
+
+		/* we have a collision, so check the name to
+		 * ensure this is the node we want */
+		if (is_hash_key(key) && match == 0) {
+			match = match_name(c, ul, nm);
+			if (match < 0) {
+				err = match;
+				goto out;
+			}
+		}
+
+		/* just update the existing leaf */
+		if (match == 0) {
+			ul->lnum = lnum;
+			ul->offs = offs;
+			ul->len = len;
+			err = 0;
+			goto out;
+		}
+
+		prev = &ul->l;
+		ul = ubifs_next_leaf(ul, ino);
+	} while (ul);
+
+insert:
+	leaf = xmalloc(sizeof(*leaf));
+	leaf->lnum = lnum;
+	leaf->offs = offs;
+	leaf->len = len;
+	key_copy(key, &leaf->key);
+
+	if (new_ino) {
+		index_insert_ino(uil);
+		prev = uil->start;
+	}
+
+	list_add(&leaf->l, prev);
+
+	/* move skip pointer of next ino when appending to last leaf of ino
+	 * list */
+	if (!ul && !list_is_last(&uil->l, &ino_index)) {
+		uil = list_next_entry(uil, l);
+		uil->start = &leaf->l;
+	}
+	err = 0;
+out:
+	return err;
+}
+
+/*
+ * ubifs_add_node - Add new node to index
+ * @c: ubifs context
+ * @key: key of new node
+ * @lnum: LEB where node is located
+ * @off: offset in LEB where new node starts
+ * @len: length of new node
+ *
+ * This only works for non-hash keys.
+ * Returns %0 on success, or a value < 0 on error.
+ */
+int ubifs_add_node(struct ubifs_info *c, union ubifs_key *key, int lnum,
+		   int offs, unsigned int len)
+{
+	struct qstr empty = { .name = NULL };
+	return index_insert_leaf(c, key, lnum, offs, len, &empty);
+}
+
+/*
+ * ubifs_add_node_nm - Add new node to index with collision resolution
+ * @c: ubifs context
+ * @key: key of new node
+ * @lnum: LEB where new node is located
+ * @offs: offset in LEB where node starts
+ * @len: length of new node
+ * @nm: file name used to resolve collision
+ *
+ * Returns %0 on success, or a value < 0 on error.
+ */
+int ubifs_add_node_nm(struct ubifs_info *c, union ubifs_key *key, int lnum,
+		      int offs, unsigned int len, struct qstr *nm)
+{
+	return index_insert_leaf(c, key, lnum, offs, len, nm);
+}
diff --git a/ubifs-utils/ubifs_unpack/replay.c b/ubifs-utils/ubifs_unpack/replay.c
new file mode 100644
index 0000000..a5fbce9
--- /dev/null
+++ b/ubifs-utils/ubifs_unpack/replay.c
@@ -0,0 +1,865 @@
+/*
+ * This file is a modified copy of fs/ubifs/replay.c from the Linux Kernel UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Adrian Hunter
+ *          Artem Bityutskiy (Битюцкий Артём)
+ */
+/*
+ * Modifications for mtd-utils.
+ *
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
+/*
+ * This file contains journal replay code. It runs when the file-system is being
+ * mounted and requires no locking.
+ *
+ * The larger is the journal, the longer it takes to scan it, so the longer it
+ * takes to mount UBIFS. This is why the journal has limited size which may be
+ * changed depending on the system requirements. But a larger journal gives
+ * faster I/O speed because it writes the index less frequently. So this is a
+ * trade-off. Also, the journal is indexed by the in-memory index (TNC), so the
+ * larger is the journal, the more memory its index may consume.
+ */
+
+#define PROGRAM_NAME "replay"
+
+#include "ubifs_unpack.h"
+#include "key.h"
+#include "list_sort.h"
+
+/**
+ * struct replay_entry - replay list entry.
+ * @lnum: logical eraseblock number of the node
+ * @offs: node offset
+ * @len: node length
+ * @deletion: non-zero if this entry corresponds to a node deletion
+ * @sqnum: node sequence number
+ * @list: links the replay list
+ * @key: node key
+ * @nm: directory entry name
+ * @old_size: truncation old size
+ * @new_size: truncation new size
+ *
+ * The replay process first scans all buds and builds the replay list, then
+ * sorts the replay list in nodes sequence number order, and then inserts all
+ * the replay entries to the TNC.
+ */
+struct replay_entry {
+	int lnum;
+	int offs;
+	int len;
+	unsigned int deletion:1;
+	unsigned long long sqnum;
+	struct list_head list;
+	union ubifs_key key;
+	union {
+		struct qstr nm;
+		struct {
+			loff_t old_size;
+			loff_t new_size;
+		};
+	};
+};
+
+/**
+ * struct ubifs_bud - bud logical eraseblock used for replay.
+ * @lnum: logical eraseblock number
+ * @start: where the (uncommitted) bud data starts
+ * @jhead: journal head number this bud belongs to
+ * @sqnum: reference node sequence number
+ * @list: link in the list buds belonging to the same journal head
+ */
+struct ubifs_bud {
+	int lnum;
+	int start;
+	int jhead;
+	unsigned long long sqnum;
+	struct list_head list;
+};
+
+/**
+ * ubifs_search_bud - search bud LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: logical eraseblock number to search
+ *
+ * This function searches bud LEB @lnum. Returns bud description object in case
+ * of success and %NULL if there is no bud with this LEB number.
+ */
+static struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum)
+{
+	struct ubifs_bud *bud;
+
+	list_for_each_entry(bud, &c->replay_buds, list) {
+		if (lnum == bud->lnum)
+			return bud;
+	}
+
+	return NULL;
+}
+/**
+ * trun_remove_range - apply a replay entry for a truncation to the TNC.
+ * @c: UBIFS file-system description object
+ * @r: replay entry of truncation
+ */
+static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
+{
+	unsigned min_blk, max_blk;
+	union ubifs_key min_key, max_key;
+	ino_t ino;
+
+	min_blk = r->new_size / UBIFS_BLOCK_SIZE;
+	if (r->new_size & (UBIFS_BLOCK_SIZE - 1))
+		min_blk += 1;
+
+	max_blk = r->old_size / UBIFS_BLOCK_SIZE;
+	if ((r->old_size & (UBIFS_BLOCK_SIZE - 1)) == 0)
+		max_blk -= 1;
+
+	ino = key_inum(&r->key);
+
+	data_key_init(&min_key, ino, min_blk);
+	data_key_init(&max_key, ino, max_blk);
+
+	return ubifs_remove_node_range(c, &min_key, &max_key);
+}
+
+/**
+ * apply_replay_entry - apply a replay entry to the TNC.
+ * @c: UBIFS file-system description object
+ * @r: replay entry to apply
+ *
+ * Apply a replay entry to the TNC.
+ */
+static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+{
+	int err;
+
+	verbose(c->verbose, "LEB %d:%d len %d deletion %d sqnum %llu key 0x%lx",
+		 r->lnum, r->offs, r->len, r->deletion, r->sqnum, r->key.u64[0]);
+
+	if (is_hash_key(&r->key)) {
+		if (r->deletion)
+			err = ubifs_remove_node_nm(c, &r->key, &r->nm);
+		else
+			err = ubifs_add_node_nm(c, &r->key, r->lnum, r->offs,
+					        r->len, &r->nm);
+	} else {
+		if (r->deletion)
+			switch (key_type(&r->key)) {
+			case UBIFS_INO_KEY:
+			{
+				ino_t inum = key_inum(&r->key);
+
+				err = ubifs_remove_inode(c, inum);
+				break;
+			}
+			case UBIFS_TRUN_KEY:
+				err = trun_remove_range(c, r);
+				break;
+			default:
+				err = ubifs_remove_node(c, &r->key);
+				break;
+			}
+		else
+			err = ubifs_add_node(c, &r->key, r->lnum, r->offs, r->len);
+		if (err)
+			return err;
+	}
+
+	return err;
+}
+
+/**
+ * replay_entries_cmp - compare 2 replay entries.
+ * @priv: UBIFS file-system description object
+ * @a: first replay entry
+ * @a: second replay entry
+ *
+ * This is a comparios function for 'list_sort()' which compares 2 replay
+ * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has
+ * greater sequence number and %-1 otherwise.
+ */
+static int replay_entries_cmp(void *priv __attribute__((unused)),
+			      struct list_head *a, struct list_head *b)
+{
+	struct replay_entry *ra, *rb;
+
+	if (a == b)
+		return 0;
+
+	ra = list_entry(a, struct replay_entry, list);
+	rb = list_entry(b, struct replay_entry, list);
+	ubifs_assert(ra->sqnum != rb->sqnum);
+	if (ra->sqnum > rb->sqnum)
+		return 1;
+	return -1;
+}
+
+/**
+ * apply_replay_list - apply the replay list to the TNC.
+ * @c: UBIFS file-system description object
+ *
+ * Apply all entries in the replay list to the TNC. Returns zero in case of
+ * success and a negative error code in case of failure.
+ */
+static int apply_replay_list(struct ubifs_info *c)
+{
+	struct replay_entry *r;
+	int err;
+
+	list_sort(c, &c->replay_list, &replay_entries_cmp);
+
+	list_for_each_entry(r, &c->replay_list, list) {
+
+		err = apply_replay_entry(c, r);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+/**
+ * destroy_replay_list - destroy the replay.
+ * @c: UBIFS file-system description object
+ *
+ * Destroy the replay list.
+ */
+static void destroy_replay_list(struct ubifs_info *c)
+{
+	struct replay_entry *r, *tmp;
+
+	list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
+		if (is_hash_key(&r->key))
+			kfree(r->nm.name);
+		list_del(&r->list);
+		kfree(r);
+	}
+}
+
+/**
+ * insert_node - insert a node to the replay list
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @len: node length
+ * @key: node key
+ * @sqnum: sequence number
+ * @deletion: non-zero if this is a deletion
+ * @used: number of bytes in use in a LEB
+ * @old_size: truncation old size
+ * @new_size: truncation new size
+ *
+ * This function inserts a scanned non-direntry node to the replay list. The
+ * replay list contains @struct replay_entry elements, and we sort this list in
+ * sequence number order before applying it. The replay list is applied at the
+ * very end of the replay process. Since the list is sorted in sequence number
+ * order, the older modifications are applied first. This function returns zero
+ * in case of success and a negative error code in case of failure.
+ */
+static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+		       union ubifs_key *key, unsigned long long sqnum,
+		       int deletion, int *used, loff_t old_size,
+		       loff_t new_size)
+{
+	struct replay_entry *r;
+
+	verbose(c->verbose, "add LEB %d:%d, key 0x%lx", lnum, offs, key->u64[0]);
+
+	if (key_inum(key) >= c->highest_inum)
+		c->highest_inum = key_inum(key);
+
+	r = calloc(1, sizeof(struct replay_entry));
+	if (!r)
+		return -ENOMEM;
+
+	if (!deletion)
+		*used += ALIGN(len, 8);
+	r->lnum = lnum;
+	r->offs = offs;
+	r->len = len;
+	r->deletion = !!deletion;
+	r->sqnum = sqnum;
+	key_copy(key, &r->key);
+	r->old_size = old_size;
+	r->new_size = new_size;
+
+	list_add_tail(&r->list, &c->replay_list);
+	return 0;
+}
+
+/**
+ * insert_dent - insert a directory entry node into the replay list.
+ * @c: UBIFS file-system description object
+ * @lnum: node logical eraseblock number
+ * @offs: node offset
+ * @len: node length
+ * @key: node key
+ * @name: directory entry name
+ * @nlen: directory entry name length
+ * @sqnum: sequence number
+ * @deletion: non-zero if this is a deletion
+ * @used: number of bytes in use in a LEB
+ *
+ * This function inserts a scanned directory entry node or an extended
+ * attribute entry to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+		       union ubifs_key *key, const char *name, int nlen,
+		       unsigned long long sqnum, int deletion, int *used)
+{
+	struct replay_entry *r;
+	char *nbuf;
+
+	verbose(c->verbose, "add LEB %d:%d, key 0x%lx ", lnum, offs, key->u64[0]);
+	if (key_inum(key) >= c->highest_inum)
+		c->highest_inum = key_inum(key);
+
+	r = calloc(1, sizeof(struct replay_entry));
+	if (!r)
+		return -ENOMEM;
+
+	nbuf = malloc(nlen + 1);
+	if (!nbuf) {
+		free(r);
+		return -ENOMEM;
+	}
+
+	if (!deletion)
+		*used += ALIGN(len, 8);
+	r->lnum = lnum;
+	r->offs = offs;
+	r->len = len;
+	r->deletion = !!deletion;
+	r->sqnum = sqnum;
+	key_copy(key, &r->key);
+	r->nm.len = nlen;
+	memcpy(nbuf, name, nlen);
+	nbuf[nlen] = '\0';
+	r->nm.name = nbuf;
+
+	list_add_tail(&r->list, &c->replay_list);
+	return 0;
+}
+
+/**
+ * ubifs_validate_entry - validate directory or extended attribute entry node.
+ * @c: UBIFS file-system description object
+ * @dent: the node to validate
+ *
+ * This function validates directory or extended attribute entry node @dent.
+ * Returns zero if the node is all right and a %-EINVAL if not.
+ */
+int ubifs_validate_entry(struct ubifs_info *c __attribute__((unused)),
+			 const struct ubifs_dent_node *dent)
+{
+	int key_type = key_type_flash(dent->key);
+	int nlen = le16_to_cpu(dent->nlen);
+
+	if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
+	    dent->type >= UBIFS_ITYPES_CNT ||
+	    nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
+	    strnlen((const char *)dent->name, nlen) != nlen ||
+	    le64_to_cpu(dent->inum) > MAX_INUM) {
+		errmsg("bad %s node", key_type == UBIFS_DENT_KEY ?
+			  "directory entry" : "extended attribute entry");
+		return -EINVAL;
+	}
+
+	if (key_type != UBIFS_DENT_KEY && key_type != UBIFS_XENT_KEY) {
+		errmsg("bad key type %d", key_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * replay_bud - replay a bud logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @b: bud entry which describes the bud
+ *
+ * This function replays bud @bud, recovers it if needed, and adds all nodes
+ * from this bud to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+static int replay_bud(struct ubifs_info *c, struct ubifs_bud *b)
+{
+	int err = 0, used = 0, lnum = b->lnum, offs = b->start;
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+
+	verbose(c->verbose, "replay bud LEB %d, head %d, offs %d",
+		lnum, b->jhead, offs);
+
+	// TODO LEB recovery for last bud of each journal head
+	//if (is_last)
+		/*
+		 * Recover only last LEBs in the journal heads, because power
+		 * cuts may cause corruptions only in these LEBs, because only
+		 * these LEBs could possibly be written to at the power cut
+		 * time.
+		 */
+		//sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead);
+	//else
+		sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
+
+	if (IS_ERR(sleb))
+		return PTR_ERR(sleb);
+
+	/*
+	 * The bud does not have to start from offset zero - the beginning of
+	 * the 'lnum' LEB may contain previously committed data. One of the
+	 * things we have to do in replay is to correctly update lprops with
+	 * newer information about this LEB.
+	 *
+	 * At this point lprops thinks that this LEB has 'c->leb_size - offs'
+	 * bytes of free space because it only contain information about
+	 * committed data.
+	 *
+	 * But we know that real amount of free space is 'c->leb_size -
+	 * sleb->endpt', and the space in the 'lnum' LEB between 'offs' and
+	 * 'sleb->endpt' is used by bud data. We have to correctly calculate
+	 * how much of these data are dirty and update lprops with this
+	 * information.
+	 *
+	 * The dirt in that LEB region is comprised of padding nodes, deletion
+	 * nodes, truncation nodes and nodes which are obsoleted by subsequent
+	 * nodes in this LEB. So instead of calculating clean space, we
+	 * calculate used space ('used' variable).
+	 */
+
+	list_for_each_entry(snod, &sleb->nodes, list) {
+		int deletion = 0;
+
+		// TODO remove watermark check for unpack
+		if (snod->sqnum >= SQNUM_WATERMARK) {
+			errmsg("file system's life ended");
+			goto out_dump;
+		}
+
+		if (snod->sqnum > c->max_sqnum)
+			c->max_sqnum = snod->sqnum;
+
+		switch (snod->type) {
+		case UBIFS_INO_NODE:
+		{
+			struct ubifs_ino_node *ino = snod->node;
+			loff_t new_size = le64_to_cpu(ino->size);
+
+			if (le32_to_cpu(ino->nlink) == 0)
+				deletion = 1;
+			err = insert_node(c, lnum, snod->offs, snod->len,
+					  &snod->key, snod->sqnum, deletion,
+					  &used, 0, new_size);
+			break;
+		}
+		case UBIFS_DATA_NODE:
+		{
+			struct ubifs_data_node *dn = snod->node;
+			loff_t new_size = le32_to_cpu(dn->size) +
+					  key_block(&snod->key) *
+					  UBIFS_BLOCK_SIZE;
+
+			err = insert_node(c, lnum, snod->offs, snod->len,
+					  &snod->key, snod->sqnum, deletion,
+					  &used, 0, new_size);
+			break;
+		}
+		case UBIFS_DENT_NODE:
+		case UBIFS_XENT_NODE:
+		{
+			struct ubifs_dent_node *dent = snod->node;
+
+			err = ubifs_validate_entry(c, dent);
+			if (err)
+				goto out_dump;
+
+			err = insert_dent(c, lnum, snod->offs, snod->len,
+					  &snod->key, (const char *)dent->name,
+					  le16_to_cpu(dent->nlen), snod->sqnum,
+					  !le64_to_cpu(dent->inum), &used);
+			break;
+		}
+		case UBIFS_TRUN_NODE:
+		{
+			struct ubifs_trun_node *trun = snod->node;
+			loff_t old_size = le64_to_cpu(trun->old_size);
+			loff_t new_size = le64_to_cpu(trun->new_size);
+			union ubifs_key key;
+
+			/* Validate truncation node */
+			if (old_size < 0 || old_size > c->max_inode_sz ||
+			    new_size < 0 || new_size > c->max_inode_sz ||
+			    old_size <= new_size) {
+				errmsg("bad truncation node");
+				goto out_dump;
+			}
+
+			/*
+			 * Create a fake truncation key just to use the same
+			 * functions which expect nodes to have keys.
+			 */
+			trun_key_init(c, &key, le32_to_cpu(trun->inum));
+			err = insert_node(c, lnum, snod->offs, snod->len,
+					  &key, snod->sqnum, 1, &used,
+					  old_size, new_size);
+			break;
+		}
+		default:
+			errmsg("unexpected node type %d in bud LEB %d:%d",
+				  snod->type, lnum, snod->offs);
+			err = -EINVAL;
+			goto out_dump;
+		}
+		if (err)
+			goto out;
+	}
+
+	assert(ubifs_search_bud(c, lnum));
+	assert(sleb->endpt - offs >= used);
+	assert(sleb->endpt % c->min_io_size == 0);
+
+out:
+	ubifs_scan_destroy(sleb);
+	return err;
+
+out_dump:
+	errmsg("bad node is at LEB %d:%d", lnum, snod->offs);
+	ubifs_scan_destroy(sleb);
+	return -EINVAL;
+}
+
+/**
+ * replay_buds - replay all buds.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int replay_buds(struct ubifs_info *c)
+{
+	struct ubifs_bud *bud;
+	int err;
+	unsigned long long prev_sqnum = 0;
+
+	list_for_each_entry(bud, &c->replay_buds, list) {
+		err = replay_bud(c, bud);
+		if (err)
+			return err;
+
+		assert(bud->sqnum > prev_sqnum);
+		prev_sqnum = bud->sqnum;
+	}
+
+	return 0;
+}
+
+/**
+ * destroy_bud_list - destroy the list of buds to replay.
+ * @c: UBIFS file-system description object
+ */
+static void destroy_bud_list(struct ubifs_info *c)
+{
+	struct ubifs_bud *b;
+
+	while (!list_empty(&c->replay_buds)) {
+		b = list_entry(c->replay_buds.next, struct ubifs_bud, list);
+		list_del(&b->list);
+		kfree(b);
+	}
+}
+
+/**
+ * add_replay_bud - add a bud to the list of buds to replay.
+ * @c: UBIFS file-system description object
+ * @lnum: bud logical eraseblock number to replay
+ * @offs: bud start offset
+ * @jhead: journal head to which this bud belongs
+ * @sqnum: reference node sequence number
+ *
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+			  unsigned long long sqnum)
+{
+	struct ubifs_bud *bud;
+
+	verbose(c->verbose, "add replay bud LEB %d:%d, head %d", lnum, offs, jhead);
+
+	bud = malloc(sizeof(struct ubifs_bud));
+	if (!bud)
+		return -ENOMEM;
+
+	bud->lnum = lnum;
+	bud->start = offs;
+	bud->jhead = jhead;
+	bud->sqnum = sqnum;
+	list_add_tail(&bud->list, &c->replay_buds);
+
+	return 0;
+}
+
+/**
+ * validate_ref - validate a reference node.
+ * @c: UBIFS file-system description object
+ * @ref: the reference node to validate
+ * @ref_lnum: LEB number of the reference node
+ * @ref_offs: reference node offset
+ *
+ * This function returns %1 if a bud reference already exists for the LEB. %0 is
+ * returned if the reference node is new, otherwise %-EINVAL is returned if
+ * validation failed.
+ */
+static int validate_ref(struct ubifs_info *c, const struct ubifs_ref_node *ref)
+{
+	struct ubifs_bud *bud;
+	int lnum = le32_to_cpu(ref->lnum);
+	unsigned int offs = le32_to_cpu(ref->offs);
+	unsigned int jhead = le32_to_cpu(ref->jhead);
+
+	/*
+	 * ref->offs may point to the end of LEB when the journal head points
+	 * to the end of LEB and we write reference node for it during commit.
+	 * So this is why we require 'offs > c->leb_size'.
+	 */
+	if (jhead >= c->jhead_cnt || lnum >= c->leb_cnt ||
+	    lnum < c->main_first || offs > c->leb_size ||
+	    offs & (c->min_io_size - 1))
+		return -EINVAL;
+
+	/* Make sure we have not already looked at this bud */
+	bud = ubifs_search_bud(c, lnum);
+	if (bud) {
+		if (bud->jhead == jhead && bud->start <= offs)
+			return 1;
+		errmsg("bud at LEB %d:%d was already referred", lnum, offs);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * replay_log_leb - replay a log logical eraseblock.
+ * @c: UBIFS file-system description object
+ * @lnum: log logical eraseblock to replay
+ * @offs: offset to start replaying from
+ * @sbuf: scan buffer
+ *
+ * This function replays a log LEB and returns zero in case of success, %1 if
+ * this is the last LEB in the log, and a negative error code in case of
+ * failure.
+ */
+static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
+{
+	int err;
+	struct ubifs_scan_leb *sleb;
+	struct ubifs_scan_node *snod;
+	const struct ubifs_cs_node *node;
+
+	verbose(c->verbose, "replay log LEB %d:%d", lnum, offs);
+	sleb = ubifs_scan(c, lnum, offs, sbuf, !c->verbose);
+	if (IS_ERR(sleb)) {
+		if (PTR_ERR(sleb) != -EUCLEAN)
+			return PTR_ERR(sleb);
+		/*
+		 * Note, the below function will recover this log LEB only if
+		 * it is the last, because unclean reboots can possibly corrupt
+		 * only the tail of the log.
+		 */
+		// TODO implement recovery
+		//sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf);
+		//if (IS_ERR(sleb))
+			return PTR_ERR(sleb);
+	}
+
+	if (sleb->nodes_cnt == 0) {
+		err = 1;
+		goto out;
+	}
+
+	node = sleb->buf;
+	snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
+	if (c->cs_sqnum == 0) {
+		/*
+		 * This is the first log LEB we are looking at, make sure that
+		 * the first node is a commit start node. Also record its
+		 * sequence number so that UBIFS can determine where the log
+		 * ends, because all nodes which were have higher sequence
+		 * numbers.
+		 */
+		if (snod->type != UBIFS_CS_NODE) {
+			errmsg("first log node at LEB %d:%d is not CS node",
+				  lnum, offs);
+			goto out_dump;
+		}
+		if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
+			errmsg("first CS node at LEB %d:%d has wrong commit number %llu expected %llu",
+				  lnum, offs,
+				  (unsigned long long)le64_to_cpu(node->cmt_no),
+				  c->cmt_no);
+			goto out_dump;
+		}
+
+		c->cs_sqnum = le64_to_cpu(node->ch.sqnum);
+		verbose(c->verbose, "commit start sqnum %llu", c->cs_sqnum);
+	}
+
+	if (snod->sqnum < c->cs_sqnum) {
+		/*
+		 * This means that we reached end of log and now
+		 * look to the older log data, which was already
+		 * committed but the eraseblock was not erased (UBIFS
+		 * only un-maps it). So this basically means we have to
+		 * exit with "end of log" code.
+		 */
+		err = 1;
+		goto out;
+	}
+
+	/* Make sure the first node sits at offset zero of the LEB */
+	if (snod->offs != 0) {
+		errmsg("first node is not at zero offset");
+		goto out_dump;
+	}
+
+	list_for_each_entry(snod, &sleb->nodes, list) {
+		// TODO remove this check since we still might be able to
+		// unpack a end-of-life UBIFS!
+		if (snod->sqnum >= SQNUM_WATERMARK) {
+			errmsg("file system's life ended");
+			goto out_dump;
+		}
+
+		if (snod->sqnum < c->cs_sqnum) {
+			errmsg("bad sqnum %llu, commit sqnum %llu",
+				  snod->sqnum, c->cs_sqnum);
+			goto out_dump;
+		}
+
+		if (snod->sqnum > c->max_sqnum)
+			c->max_sqnum = snod->sqnum;
+
+		switch (snod->type) {
+		case UBIFS_REF_NODE: {
+			const struct ubifs_ref_node *ref = snod->node;
+
+			err = validate_ref(c, ref);
+			if (err == 1)
+				break; /* Already have this bud */
+			if (err)
+				goto out_dump;
+
+			err = add_replay_bud(c, le32_to_cpu(ref->lnum),
+					     le32_to_cpu(ref->offs),
+					     le32_to_cpu(ref->jhead),
+					     snod->sqnum);
+			if (err)
+				goto out;
+
+			break;
+		}
+		case UBIFS_CS_NODE:
+			/* Make sure it sits at the beginning of LEB */
+			if (snod->offs != 0) {
+				errmsg("unexpected node in log");
+				goto out_dump;
+			}
+			break;
+		default:
+			errmsg("unexpected node in log");
+			goto out_dump;
+		}
+	}
+
+	if (sleb->endpt) {
+		c->lhead_lnum = lnum;
+	}
+
+	err = !sleb->endpt;
+out:
+	ubifs_scan_destroy(sleb);
+	return err;
+
+out_dump:
+	errmsg("log error detected while replaying the log at LEB %d:%d",
+		  lnum, offs + snod->offs);
+	ubifs_scan_destroy(sleb);
+	return -EINVAL;
+}
+
+/**
+ * ubifs_replay_journal - replay journal.
+ * @c: UBIFS file-system description object
+ *
+ * This function scans the journal, replays and cleans it up. It makes sure all
+ * memory data structures related to uncommitted journal are built (dirty TNC
+ * tree, tree of buds, modified lprops, etc).
+ */
+int ubifs_replay_journal(struct ubifs_info *c)
+{
+	int err, lnum, ltail_lnum;
+
+	verbose(c->verbose, "start replaying the journal");
+	lnum = ltail_lnum = c->lhead_lnum;
+
+	do {
+		err = replay_log_leb(c, lnum, 0, c->sbuf);
+		if (err == 1) {
+			if (lnum != c->lhead_lnum)
+				/* We hit the end of the log */
+				break;
+
+			/*
+			 * The head of the log must always start with the
+			 * "commit start" node on a properly formatted UBIFS.
+			 * But we found no nodes at all, which means that
+			 * someting went wrong and we cannot proceed mounting
+			 * the file-system.
+			 */
+			errmsg("no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",
+				  lnum, 0);
+			err = -EINVAL;
+		}
+		if (err)
+			goto out;
+		lnum = ubifs_next_log_lnum(c, lnum);
+	} while (lnum != ltail_lnum);
+
+	err = replay_buds(c);
+	if (err)
+		goto out;
+
+	err = apply_replay_list(c);
+	if (err)
+		goto out;
+
+	verbose(c->verbose, "finished, log head LEB %d, max_sqnum %llu, highest_inum %lu",
+		c->lhead_lnum, c->max_sqnum, (unsigned long)c->highest_inum);
+out:
+	destroy_replay_list(c);
+	destroy_bud_list(c);
+	return err;
+}
diff --git a/ubifs-utils/ubifs_unpack/ubifs_unpack.c b/ubifs-utils/ubifs_unpack/ubifs_unpack.c
new file mode 100644
index 0000000..321a42f
--- /dev/null
+++ b/ubifs-utils/ubifs_unpack/ubifs_unpack.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
+#define PROGRAM_NAME "ubifs_unpack"
+
+#include "ubifs_common.h"
+#include "ubifs_unpack.h"
+
+#include "crc32.h"
+#include "lpt.h"
+#include "key.h"
+#include "emubi.h"
+#include "master.h"
+#include "ubiutils-common.h"
+#include "compr.h"
+
+#include <getopt.h>
+#include <sys/mman.h>
+#include <lzo/lzo1x.h>
+
+extern char *optarg;
+extern int optind;
+
+struct unpack_args {
+	int peb_size;
+	int page_size;
+	int vol_id;
+	char *ubi_dev;
+
+	int emubi_mode;
+	int verbose;
+	char *out_root;
+};
+
+static const char doc[] = PROGRAM_NAME " version " VERSION
+			  " - a tool to unpack UBIFS images.";
+
+static const char optionsstr[] =
+"-o, --output=<output dir>    root directory where extracted files will be\n"
+"                             extracted to (required)\n"
+"-p, --peb-size=<bytes>       size of the physical eraseblock of the flash\n"
+"                             this UBI image is created for in bytes,\n"
+"                             kilobytes (KiB), or megabytes (MiB)\n"
+"                             (required)\n"
+"-m, --min-io-size=<bytes>    minimum input/output unit size of the flash\n"
+"                             in bytes (required)\n"
+"-n, --vol-id=<volume ID>     UBI volume ID (defaults to 0)\n"
+"-u, --ubi-dev=<device path>  UBI volume device to read from\n"
+"-e, --emubi-mode=<mode>      EMUBI mode: 'mmap' or 'file' (defaults to 'file')\n"
+"-v, --verbose                verbose output\n"
+"-h, --help                   print help message\n"
+"-V, --version                print program version";
+
+static const char usage[] =
+"Usage: " PROGRAM_NAME " [-o <output dir>] [-p <bytes>] [-m <bytes>] [-n <volume ID>] [-v]\n"
+"\t\t[--output=<output dir>] [--peb-size=<bytes>] [--min-io-size=<bytes>]\n"
+"\t\t[--vol-id=<volume ID>] [--verbose] [--help] [--version] source\n"
+"Example: " PROGRAM_NAME " -p 16KiB -m 512 ubifs.img - unpack volume 1 of image\n"
+"         'ubifs.img'";
+
+static const struct option long_opts[] = {
+	{ .name = "output",         .has_arg = 1, .flag = NULL, .val = 'o' },
+	{ .name = "peb-size",       .has_arg = 1, .flag = NULL, .val = 'p' },
+	{ .name = "min-io-size",    .has_arg = 1, .flag = NULL, .val = 'm' },
+	{ .name = "vol-id",         .has_arg = 1, .flag = NULL, .val = 'n' },
+	{ .name = "ubi-dev",        .has_arg = 1, .flag = NULL, .val = 'u' },
+	{ .name = "emubi-mode",     .has_arg = 1, .flag = NULL, .val = 'e' },
+	{ .name = "verbose",        .has_arg = 0, .flag = NULL, .val = 'v' },
+	{ .name = "help",           .has_arg = 0, .flag = NULL, .val = 'h' },
+	{ .name = "version",        .has_arg = 0, .flag = NULL, .val = 'V' },
+	{ NULL, 0, NULL, 0 }
+};
+
+// TODO replace all assert()s with proper error handling
+// TODO cleanup logging - esp. unify key logging
+
+static int write_block(struct ubifs_info *c, struct ubifs_dent_node *dent,
+		       int block, char *dst)
+{
+	struct ubifs_data_node *d;
+	size_t out_len = UBIFS_BLOCK_SIZE;
+	int data_len, ret;
+
+	d = ubifs_lookup_data_node(c, le64toh(dent->inum), block);
+	if (!d) {
+		/* file hole */
+		return 0;
+	}
+
+	data_len = le32toh(d->ch.len) - UBIFS_DATA_NODE_SZ;
+	ret = decompress_data(d->data, data_len, dst, &out_len, d->compr_type);
+	free(d);
+
+	return ret;
+}
+
+static void __set_attributes(struct ubifs_ino_node *ino, int target_fd)
+{
+	fchmod(target_fd, le32toh(ino->mode));
+	fchown(target_fd, le32toh(ino->uid), le32toh(ino->gid));
+}
+
+static void set_attributes(struct ubifs_info *c, struct ubifs_dent_node *dent,
+			   int target_fd)
+{
+	struct ubifs_ino_node *ino;
+
+	ino = ubifs_lookup_ino_node(c, le64toh(dent->inum));
+	__set_attributes(ino, target_fd);
+	free(ino);
+}
+
+static void write_symlink(struct ubifs_info *c, struct ubifs_dent_node *dent,
+			  int parent_fd)
+{
+	struct ubifs_ino_node *ino;
+	char *link_tgt;
+	int len;
+
+	ino = ubifs_lookup_ino_node(c, le64toh(dent->inum));
+	assert(ino);
+
+	len = le32toh(ino->data_len);
+	if (len > PATH_MAX) {
+		free(ino);
+		return;
+	}
+
+	link_tgt = xmalloc(len + 1);
+	memcpy(link_tgt, ino->data, len);
+	link_tgt[len] = '\0';
+
+	symlinkat(link_tgt, parent_fd, (char *)dent->name);
+
+	free(link_tgt);
+	free(ino);
+}
+
+static void write_file(struct ubifs_info *c, struct ubifs_dent_node *dent,
+		       int parent_fd)
+{
+	int fd, i, errs;
+	char *tgt;
+	struct ubifs_ino_node *ino;
+	char nul[1] = { 0 };
+	unsigned int file_len;
+	int num_blocks;
+
+	ino = ubifs_lookup_ino_node(c, le64toh(dent->inum));
+	assert(ino);
+	file_len = le64toh(ino->size);
+
+	num_blocks = (file_len + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+
+	fd = openat(parent_fd, (const char *)dent->name, O_CREAT|O_RDWR|O_TRUNC, 0700);
+	assert(fd);
+
+	if (!file_len) {
+		free(ino);
+		close(fd);
+		return;
+	}
+
+	lseek(fd, file_len - 1, SEEK_SET);
+	write(fd, nul, 1);
+
+	tgt = mmap(NULL, file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+	assert(tgt != MAP_FAILED);
+	__set_attributes(ino, fd);
+	free(ino);
+	close(fd);
+
+	errs = 0;
+	for (i = 0; i < num_blocks; i++)
+		if (write_block(c, dent, i, tgt + (UBIFS_BLOCK_SIZE * i)) != 0)
+			errs++;
+
+	if (errs)
+		errmsg("decompress of %d data nodes of %s failed", errs, dent->name);
+
+	munmap(tgt, file_len);
+}
+
+static inline dev_t new_decode_dev(uint32_t dev)
+{
+	unsigned major = (dev & 0xfff00) >> 8;
+	unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+
+	return makedev(major, minor);
+}
+
+static void write_devnode(struct ubifs_info *c, struct ubifs_dent_node *dent,
+			  int parent_fd)
+{
+	struct ubifs_ino_node *ino;
+	union ubifs_dev_desc *devd;
+	dev_t rdev;
+
+	ino = ubifs_lookup_ino_node(c, le64toh(dent->inum));
+	assert(ino);
+
+	devd = (union ubifs_dev_desc *)ino->data;
+
+	if (ino->data_len == sizeof(devd->new))
+		rdev = new_decode_dev(devd->new);
+	else if (ino->data_len == sizeof(devd->huge))
+		rdev = new_decode_dev(devd->huge);
+	else {
+		errmsg("Invalid inode data len!\n");
+		goto out;
+	}
+
+	mknodat(parent_fd, (const char *)dent->name, le32toh(ino->mode), rdev);
+
+out:
+	free(ino);
+}
+
+static void write_fifo(struct ubifs_info *c, struct ubifs_dent_node *dent,
+		       int parent_fd)
+{
+	struct ubifs_ino_node *ino;
+
+	ino = ubifs_lookup_ino_node(c, le64toh(dent->inum));
+	assert(ino);
+
+	mknodat(parent_fd, (const char *)dent->name, le32toh(ino->mode), 0);
+
+	free(ino);
+}
+
+static void unpack_dir(struct ubifs_info *c, ino_t dir_ino, int parent_fd, int depth)
+{
+	int fd;
+	struct ubifs_dent_node *dent;
+	struct ubifs_leaf *leaf = NULL;
+
+	for (;;) {
+		leaf = ubifs_next_leaf(leaf, dir_ino);
+		if (!leaf)
+			/* end of list */
+			break;
+
+		/* skip any nodes other than UBIFS_DENT_NODE. E.g extended
+		 * attribute nodes */
+		if (key_type(&leaf->key) != UBIFS_DENT_KEY)
+			continue;
+
+		dent = xmalloc(leaf->len);
+		get_dent_node(c, dent, leaf->lnum, leaf->offs, leaf->len);
+		bareverbose(c->verbose, "%.*s", depth, "                 ");
+		switch (dent->type) {
+		case UBIFS_ITYPE_REG:
+			bareverbose(c->verbose, "%s\n", dent->name);
+			write_file(c, dent, parent_fd);
+			break;
+		case UBIFS_ITYPE_DIR:
+			bareverbose(c->verbose, "[%s]\n", dent->name);
+
+			if (mkdirat(parent_fd, (const char *)dent->name, 0755) == -1) {
+				warnmsg("Unable to create %s: %m\n", dent->name);
+				continue;
+			}
+
+			fd = openat(parent_fd, (const char *)dent->name, O_RDONLY);
+			if (fd == -1) {
+				sys_errmsg_die("unpack of %s failed", dent->name);
+			}
+
+			unpack_dir(c, le64toh(dent->inum), fd, depth + 1);
+			set_attributes(c, dent, fd);
+			close(fd);
+			break;
+		case UBIFS_ITYPE_LNK:
+			write_symlink(c, dent, parent_fd);
+			break;
+		case UBIFS_ITYPE_CHR:
+		case UBIFS_ITYPE_BLK:
+			write_devnode(c, dent, parent_fd);
+			break;
+		case UBIFS_ITYPE_FIFO:
+			write_fifo(c, dent, parent_fd);
+			break;
+		case UBIFS_ITYPE_SOCK:
+			warnmsg("Ignoring UNIX domain socket %s", dent->name);
+			break;
+		default:
+			/* TODO handle other inode types (link, devices etc) */
+			warnmsg("Unsupported DENT type: %d", dent->type);
+		}
+
+		free(dent);
+	}
+}
+
+//TODO: make this common with ubifs_dump
+static void destroy_ubifs_info(struct ubifs_info *c)
+{
+	free(c->sbuf);
+}
+
+/*
+ * init_constants_sb - initialize UBIFS constants.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function which initializes various UBIFS constants after
+ * the superblock has been read. It also checks various UBIFS parameters and
+ * makes sure they are all right. Returns zero in case of success and a
+ * negative error code in case of failure.
+ */
+//TODO: make this common with ubifs_dump
+static int init_constants_sb(struct ubifs_info *c)
+{
+	int tmp, err;
+
+	tmp = ubifs_idx_node_sz(c, 1);
+	c->min_idx_node_sz = ALIGN(tmp, 8);
+
+	tmp = ubifs_idx_node_sz(c, c->fanout);
+	c->max_idx_node_sz = ALIGN(tmp, 8);
+
+	c->max_znode_sz = sizeof(struct ubifs_znode) +
+			c->fanout * sizeof(struct ubifs_zbranch);
+	/* Make sure LEB size is large enough to fit full commit */
+	tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
+	tmp = ALIGN(tmp, c->min_io_size);
+	if (tmp > c->leb_size) {
+		errmsg("too small LEB size %d, at least %d needed",
+			  c->leb_size, tmp);
+		return -EINVAL;
+	}
+
+	err = ubifs_calc_lpt_geom(c);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+//TODO: make this common with ubifs_dump
+static int init_ubifs_info(struct ubifs_info *c, struct ubifs_sb_node *sb)
+{
+	int err;
+	unsigned long sup_flags;
+
+        switch (sb->key_hash) {
+        case UBIFS_KEY_HASH_R5:
+                c->key_hash = key_r5_hash;
+                c->key_hash_type = UBIFS_KEY_HASH_R5;
+                break;
+
+        case UBIFS_KEY_HASH_TEST:
+                c->key_hash = key_test_hash;
+                c->key_hash_type = UBIFS_KEY_HASH_TEST;
+                break;
+        };
+
+	c->key_fmt = sb->key_fmt;
+
+	switch (c->key_fmt) {
+	case UBIFS_SIMPLE_KEY_FMT:
+		c->key_len = UBIFS_SK_LEN;
+		break;
+	default:
+		errmsg("unsupported UBIFS key format");
+		err = -EINVAL;
+		goto out;
+	}
+
+	c->leb_size	 = le32_to_cpu(sb->leb_size);
+	c->min_io_size	 = le32_to_cpu(sb->min_io_size);
+	c->leb_cnt       = le32_to_cpu(sb->leb_cnt);
+	c->max_leb_cnt   = le32_to_cpu(sb->max_leb_cnt);
+	c->max_bud_bytes = le64_to_cpu(sb->max_bud_bytes);
+	c->log_lebs      = le32_to_cpu(sb->log_lebs);
+	c->lpt_lebs      = le32_to_cpu(sb->lpt_lebs);
+	c->orph_lebs     = le32_to_cpu(sb->orph_lebs);
+	c->jhead_cnt     = le32_to_cpu(sb->jhead_cnt) + NONDATA_JHEADS_CNT;
+	c->fanout        = le32_to_cpu(sb->fanout);
+	c->lsave_cnt     = le32_to_cpu(sb->lsave_cnt);
+	c->rp_size       = le64_to_cpu(sb->rp_size);
+	sup_flags        = le32_to_cpu(sb->flags);
+	c->cs_sqnum      = 0;
+
+	c->default_compr = le16_to_cpu(sb->default_compr);
+
+	c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
+	c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+
+	c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
+	c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
+	c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+	c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
+	c->main_first = c->leb_cnt - c->main_lebs;
+
+	c->max_inode_sz = key_max_inode_size(c);
+
+	err = init_constants_sb(c);
+
+	c->sbuf = xmalloc(c->leb_size);
+
+	INIT_LIST_HEAD(&c->replay_list);
+	INIT_LIST_HEAD(&c->replay_buds);
+out:
+	return err;
+}
+
+static int ubifs_read_sb(struct ubifs_info *c)
+{
+	struct ubifs_sb_node sb;
+
+	ubifs_leb_read(c, UBIFS_SB_LNUM, &sb, 0, sizeof(sb));
+	if (le32toh(sb.ch.magic) != UBIFS_NODE_MAGIC) {
+		return errmsg("invalid superblock node");
+	}
+
+	init_ubifs_info(c, &sb);
+
+	// TODO call validate_sb() here to properly check the sb node.
+	return 0;
+}
+
+static int unpack(struct ubifs_info *c, char *out_root)
+{
+	int fd, err = 0;
+
+	normsg("reading superblock node...");
+	err = ubifs_read_sb(c);
+	if (err)
+		goto out;
+
+	normsg("reading master node...");
+	err = ubifs_read_master(c);
+	if (err)
+		goto out;
+
+	normsg("reading on-flash index...");
+	ubifs_load_index(c, c->zroot.lnum, c->zroot.offs, c->zroot.len);
+
+	normsg("replaying journal...");
+	err = ubifs_replay_journal(c);
+	if (err)
+		goto out;
+
+	normsg("unpacking files...");
+	fd = open(out_root, O_RDONLY);
+	if (fd == -1)
+		return sys_errmsg("open of output folder failed");
+
+	unpack_dir(c, 1, fd, 0);
+
+out:
+	return err;
+}
+
+static int parse_opt(int argc, char *argv[], struct unpack_args *args)
+{
+	long long val;
+	int key, err;
+
+	while ((key = getopt_long(argc, argv, "o:p:m:n:u:e:vhV", long_opts, NULL)) != -1) {
+		switch (key) {
+		case 'o':
+			args->out_root = optarg;
+			err = mkdir(args->out_root, 0755);
+			if (err && errno == EEXIST)
+				return errmsg("output directory exists");
+			else if (err)
+				return sys_errmsg("mkdir of %s failed", optarg);
+			break;
+		case 'p':
+			val = parse_bytes(optarg);
+			if (val <= 0 || val > UINT_MAX)
+				return errmsg("bad physical eraseblock size: \"%s\"", optarg);
+			args->peb_size = val;
+			break;
+		case 'm':
+			val = parse_bytes(optarg);
+			if (val <= 0 || val > UINT_MAX)
+				return errmsg("bad min. I/O unit size: \"%s\"", optarg);
+			if (!is_power_of_2(val))
+				return errmsg("min. I/O unit size must be power of 2");
+			args->page_size = val;
+			break;
+		case 'n':
+			args->vol_id = atoi(optarg);
+			if (args->vol_id < 0)
+				return errmsg("bad volume ID: \"%s\"", optarg);
+			break;
+		case 'u':
+			args->ubi_dev = optarg;
+			break;
+		case 'e':
+			if (strcasecmp(optarg, "mmap") == 0)
+				args->emubi_mode = EMUBI_MODE_MMAP;
+			else if (strcasecmp(optarg, "file") == 0)
+				args->emubi_mode = EMUBI_MODE_FILE;
+			else
+				return errmsg("invalid emubi mode %s (use 'file' or 'mmap')", optarg);
+			break;
+		case 'v':
+			args->verbose = 1;
+			break;
+		case 'h':
+			printf("%s\n\n", doc);
+			printf("%s\n\n", usage);
+			printf("%s\n\n", optionsstr);
+			exit(EXIT_SUCCESS);
+		case 'V':
+			common_print_version();
+			exit(EXIT_SUCCESS);
+		default:
+			return errmsg("unknown option. Use -h for help");
+		}
+
+	}
+
+	if (!args->out_root)
+		return errmsg("no output directory specified");
+
+	if (!args->ubi_dev) {
+		if (optind == argc)
+			return errmsg("image file is missing (use -h for help)");
+
+		if (args->peb_size < 0)
+			return errmsg("physical eraseblock size was not specified (use -p <bytes>)");
+
+		if (args->page_size < 0)
+			return errmsg("min. I/O unit size was not specified (use -m <bytes>)");
+
+		if (args->peb_size % args->page_size)
+			return errmsg("physical eraseblock size must be multiple of min. I/O unit size");
+	}
+
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int err;
+	struct ubifs_info info;
+	struct emubi_ctx emubi;
+	struct unpack_args args = {
+		.peb_size = -1,
+		.page_size = -1,
+		.vol_id = 0,
+		.ubi_dev = NULL,
+		.verbose = 0,
+		.out_root = NULL,
+		.emubi_mode = EMUBI_MODE_FILE,
+	};
+
+	err = parse_opt(argc, argv, &args);
+	if (err)
+		return EXIT_FAILURE;
+
+	emubi.mode = args.emubi_mode;
+	if (args.ubi_dev) {
+		output = xstrdup(args.ubi_dev);
+		open_ubi(&info, output);
+		if (open_target(&info, 1)) {
+			errmsg("Unable to open UBI volume device\n");
+			return EXIT_FAILURE;
+		}
+	}
+	else {
+		emubi.peb_size = args.peb_size;
+		emubi.page_size = args.page_size;
+		emubi.vol_id = args.vol_id;
+		info.emubi = &emubi;
+		info.verbose = args.verbose;
+
+		err = emubi_open(&emubi, argv[optind]);
+		if (err)
+			goto out;
+
+		err = emubi_scan(&emubi);
+		if (err)
+			goto out;
+
+
+		emubi_print(&emubi);
+	}
+
+	err = unpack(&info, args.out_root);
+
+out:
+	if (args.ubi_dev)
+		close_target();
+
+	ubifs_destroy_index();
+	emubi_close(&emubi);
+	destroy_ubifs_info(&info);
+
+	if (err) {
+		errmsg("unpack failed");
+		return EXIT_FAILURE;
+	}
+
+	normsg("unpack finished");
+	return EXIT_SUCCESS;
+}
diff --git a/ubifs-utils/ubifs_unpack/ubifs_unpack.h b/ubifs-utils/ubifs_unpack/ubifs_unpack.h
new file mode 100644
index 0000000..5c033e8
--- /dev/null
+++ b/ubifs-utils/ubifs_unpack/ubifs_unpack.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 sigma star gmbh
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Richard Weinberger
+ *          David Gstir
+ */
+
+#ifndef __UBIFS_UNPACK_H__
+#define __UBIFS_UNPACK_H__
+
+#include "ubifs_common.h"
+#include "common.h"
+#include "ubifs.h"
+#include "scan.h"
+#include "key.h"
+#include "xalloc.h"
+#include "io.h"
+
+struct ubifs_leaf {
+	union ubifs_key key;
+	unsigned int lnum;
+	unsigned int offs;
+	unsigned int len;
+	struct list_head l;
+};
+
+static inline void get_idx_node(struct ubifs_info *c, struct ubifs_idx_node *n,
+				unsigned int lnum, unsigned int offset,
+				unsigned int len)
+{
+	ubifs_leb_read(c, lnum, n, offset, len);
+	assert(le32toh(n->ch.magic) == UBIFS_NODE_MAGIC);
+	assert(n->ch.node_type == UBIFS_IDX_NODE);
+}
+
+static inline void get_dent_node(struct ubifs_info *c, struct ubifs_dent_node *n,
+				 unsigned int lnum, unsigned int offset,
+				 unsigned int len)
+{
+	ubifs_leb_read(c, lnum, n, offset, len);
+	assert(le32toh(n->ch.magic) == UBIFS_NODE_MAGIC);
+	assert(n->ch.node_type == UBIFS_DENT_NODE);
+}
+
+static inline void get_ino_node(struct ubifs_info *c, struct ubifs_ino_node *n,
+				unsigned int lnum, unsigned int offset,
+				unsigned int len)
+{
+	ubifs_leb_read(c, lnum, n, offset, len);
+	assert(le32toh(n->ch.magic) == UBIFS_NODE_MAGIC);
+	assert(n->ch.node_type == UBIFS_INO_NODE);
+}
+
+static inline void get_data_node(struct ubifs_info *c, struct ubifs_data_node *n,
+				 unsigned int lnum, unsigned int offset,
+				 unsigned int len)
+{
+	ubifs_leb_read(c, lnum, n, offset, len);
+	assert(le32toh(n->ch.magic) == UBIFS_NODE_MAGIC);
+	assert(n->ch.node_type == UBIFS_DATA_NODE);
+}
+
+static inline struct ubifs_branch *get_branch(struct ubifs_idx_node *idx,
+					      unsigned int n)
+{
+	return (struct ubifs_branch *)(idx->branches
+		 + ((UBIFS_BRANCH_SZ + UBIFS_SK_LEN) * n));
+}
+
+/* replay.c */
+int ubifs_replay_journal(struct ubifs_info *c);
+
+/* index.c */
+void ubifs_destroy_index();
+void ubifs_load_index(struct ubifs_info *c, unsigned int lnum,
+		      unsigned int offset, unsigned int len);
+struct ubifs_ino_node *ubifs_lookup_ino_node(struct ubifs_info *c, ino_t ino);
+struct ubifs_data_node *ubifs_lookup_data_node(struct ubifs_info *c, ino_t ino,
+					       unsigned int block);
+struct ubifs_leaf *ubifs_next_leaf(struct ubifs_leaf *ul, ino_t ino);
+
+int ubifs_add_node(struct ubifs_info *c, union ubifs_key *key, int lnum,
+		   int offs, unsigned int len);
+int ubifs_add_node_nm(struct ubifs_info *c, union ubifs_key *key, int lnum,
+		      int offs, unsigned int len, struct qstr *nm);
+int ubifs_remove_inode(struct ubifs_info *c, ino_t ino);
+int ubifs_remove_node(struct ubifs_info *c, union ubifs_key *key);
+int ubifs_remove_node_nm(struct ubifs_info *c, union ubifs_key *key,
+			 struct qstr *nm);
+int ubifs_remove_node_range(struct ubifs_info *c, union ubifs_key *min_key,
+			    union ubifs_key *max_key);
+
+
+#endif
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers
  2015-10-31 11:15 ` [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers Richard Weinberger
@ 2015-11-02  1:28   ` Dongsheng Yang
  2015-11-02 15:38     ` Artem Bityutskiy
  0 siblings, 1 reply; 16+ messages in thread
From: Dongsheng Yang @ 2015-11-02  1:28 UTC (permalink / raw)
  To: Richard Weinberger, linux-mtd, Artem Bityutskiy; +Cc: david

Yes, all ubifs_info *c in key.h are not used, But I am
not sure about is that intentional or not.

Ping Artem...

Yang

On 10/31/2015 07:15 PM, Richard Weinberger wrote:
> From: David Gstir <david@sigma-star.at>
>
> Various key helper functions in ubifs-utils/include/key.h require the
> ubifs_info context. Since this context is never used, so we can remove it.
>
> Signed-off-by: David Gstir <david@sigma-star.at>
> Signed-off-by: Richard Weinberger <richard@nod.at>
> ---
>   ubifs-utils/include/key.h           | 24 ++++++------------------
>   ubifs-utils/lib/scan.c              | 10 ++++------
>   ubifs-utils/ubifs_dump/ubifs_dump.c | 22 +++++++++++-----------
>   3 files changed, 21 insertions(+), 35 deletions(-)
>
> diff --git a/ubifs-utils/include/key.h b/ubifs-utils/include/key.h
> index 779981a..9ee7597 100644
> --- a/ubifs-utils/include/key.h
> +++ b/ubifs-utils/include/key.h
> @@ -92,7 +92,6 @@ static inline uint32_t key_test_hash(const char *str, int len)
>
>   /**
>    * ino_key_init - initialize inode key.
> - * @c: UBIFS file-system description object
>    * @key: key to initialize
>    * @inum: inode number
>    */
> @@ -190,12 +189,10 @@ static inline int keys_cmp(const union ubifs_key *key1,
>
>   /**
>    * key_read - transform a key to in-memory format.
> - * @c: UBIFS file-system description object
>    * @from: the key to transform
>    * @to: the key to store the result
>    */
> -static inline void key_read(const struct ubifs_info *c __attribute__((unused)), const void *from,
> -			    union ubifs_key *to)
> +static inline void key_read(const void *from, union ubifs_key *to)
>   {
>   	const union ubifs_key *f = from;
>
> @@ -205,45 +202,38 @@ static inline void key_read(const struct ubifs_info *c __attribute__((unused)),
>
>   /**
>    * invalid_key_init - initialize invalid node key.
> - * @c: UBIFS file-system description object
>    * @key: key to initialize
>    *
>    * This is a helper function which marks a @key object as invalid.
>    */
> -static inline void invalid_key_init(const struct ubifs_info *c __attribute__((unused)),
> -				    union ubifs_key *key)
> +static inline void invalid_key_init(union ubifs_key *key)
>   {
>   	key->u32[0] = 0xDEADBEAF;
>   	key->u32[1] = UBIFS_INVALID_KEY;
>   }
>   /**
>    * key_type - get key type.
> - * @c: UBIFS file-system description object
>    * @key: key to get type of
>    */
> -static inline int key_type(const struct ubifs_info *c __attribute__((unused)),
> -			   const union ubifs_key *key)
> +static inline int key_type(const union ubifs_key *key)
>   {
>   	return key->u32[1] >> UBIFS_S_KEY_BLOCK_BITS;
>   }
>
>   /*
>    * key_hash - get directory entry hash.
> - * @c: UBIFS file-system description object
>    * @key: the key to get hash from
>    */
> -static inline uint32_t key_hash(const struct ubifs_info *c __attribute__((unused)),
> -				const union ubifs_key *key)
> +static inline uint32_t key_hash(const union ubifs_key *key)
>   {
>   	return key->u32[1] & UBIFS_S_KEY_HASH_MASK;
>   }
>
>   /**
>    * key_inum - fetch inode number from key.
> - * @c: UBIFS file-system description object
>    * @k: key to fetch inode number from
>    */
> -static inline ino_t key_inum(const struct ubifs_info *c __attribute__((unused)), const void *k)
> +static inline ino_t key_inum(const void *k)
>   {
>   	const union ubifs_key *key = k;
>
> @@ -252,11 +242,9 @@ static inline ino_t key_inum(const struct ubifs_info *c __attribute__((unused)),
>
>   /**
>    * key_block - get data block number.
> - * @c: UBIFS file-system description object
>    * @key: the key to get the block number from
>    */
> -static inline unsigned int key_block(const struct ubifs_info *c __attribute__((unused)),
> -				     const union ubifs_key *key)
> +static inline unsigned int key_block(const union ubifs_key *key)
>   {
>   	return key->u32[1] & UBIFS_S_KEY_BLOCK_MASK;
>   }
> diff --git a/ubifs-utils/lib/scan.c b/ubifs-utils/lib/scan.c
> index 69c84d1..3c5be2c 100644
> --- a/ubifs-utils/lib/scan.c
> +++ b/ubifs-utils/lib/scan.c
> @@ -162,15 +162,13 @@ void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
>
>   /**
>    * ubifs_add_snod - add a scanned node to LEB scanning information.
> - * @c: UBIFS file-system description object
>    * @sleb: scanning information
>    * @buf: buffer containing node
>    * @offs: offset of node on flash
>    *
>    * This function returns %0 on success and a negative error code on failure.
>    */
> -int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
> -		   void *buf, int offs)
> +int ubifs_add_snod(struct ubifs_scan_leb *sleb, void *buf, int offs)
>   {
>   	struct ubifs_ch *ch = buf;
>   	struct ubifs_ino_node *ino = buf;
> @@ -195,10 +193,10 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
>   		 * The key is in the same place in all keyed
>   		 * nodes.
>   		 */
> -		key_read(c, &ino->key, &snod->key);
> +		key_read(&ino->key, &snod->key);
>   		break;
>   	default:
> -		invalid_key_init(c, &snod->key);
> +		invalid_key_init(&snod->key);
>   		break;
>   	}
>   	list_add_tail(&snod->list, &sleb->nodes);
> @@ -267,7 +265,7 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
>   			goto error;
>   		}
>
> -		err = ubifs_add_snod(c, sleb, buf, offs);
> +		err = ubifs_add_snod(sleb, buf, offs);
>   		if (err)
>   			goto error;
>
> diff --git a/ubifs-utils/ubifs_dump/ubifs_dump.c b/ubifs-utils/ubifs_dump/ubifs_dump.c
> index eaf8daf..68c2895 100644
> --- a/ubifs-utils/ubifs_dump/ubifs_dump.c
> +++ b/ubifs-utils/ubifs_dump/ubifs_dump.c
> @@ -91,30 +91,30 @@ const char *dbg_snprintf_key(const struct ubifs_info *c,
>   			     const union ubifs_key *key, char *buffer, int len)
>   {
>   	char *p = buffer;
> -	int type = key_type(c, key);
> +	int type = key_type(key);
>
>   	if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
>   		switch (type) {
>
>   		case UBIFS_INO_KEY:
>   			len -= snprintf(p, len, "(%lu, %s)",
> -					(unsigned long)key_inum(c, key),
> +					(unsigned long)key_inum(key),
>   					get_key_type(type));
>   			break;
>   		case UBIFS_DENT_KEY:
>   		case UBIFS_XENT_KEY:
>   			len -= snprintf(p, len, "(%lu, %s, %#08x)",
> -					(unsigned long)key_inum(c, key),
> -					get_key_type(type), key_hash(c, key));
> +					(unsigned long)key_inum(key),
> +					get_key_type(type), key_hash(key));
>   			break;
>   		case UBIFS_DATA_KEY:
>   			len -= snprintf(p, len, "(%lu, %s, %u)",
> -					(unsigned long)key_inum(c, key),
> -					get_key_type(type), key_block(c, key));
> +					(unsigned long)key_inum(key),
> +					get_key_type(type), key_block(key));
>   			break;
>   		case UBIFS_TRUN_KEY:
>   			len -= snprintf(p, len, "(%lu, %s)",
> -					(unsigned long)key_inum(c, key),
> +					(unsigned long)key_inum(key),
>   					get_key_type(type));
>   			break;
>   		default:
> @@ -252,7 +252,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
>   	{
>   		const struct ubifs_ino_node *ino = node;
>
> -		key_read(c, &ino->key, &key);
> +		key_read(&ino->key, &key);
>   		printf("\t\tkey \t\t\t\t%s\n",
>   		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
>   		printf("\t\tcreat_sqnum \t\t\t%llu\n",
> @@ -287,7 +287,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
>   		const struct ubifs_dent_node *dent = node;
>   		int nlen = le16_to_cpu(dent->nlen);
>
> -		key_read(c, &dent->key, &key);
> +		key_read(&dent->key, &key);
>   		printf("\t\tkey \t\t\t\t%s\n",
>   		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
>   		printf("\t\tinum \t\t\t\t%llu\n",
> @@ -311,7 +311,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
>   		const struct ubifs_data_node *dn = node;
>   		int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
>
> -		key_read(c, &dn->key, &key);
> +		key_read(&dn->key, &key);
>   		printf("\t\tkey \t\t\t\t%s\n",
>   		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
>   		printf("\t\tsize \t\t\t\t%u\n", le32_to_cpu(dn->size));
> @@ -347,7 +347,7 @@ void dump_node(const struct ubifs_info *c, const void *node)
>   			const struct ubifs_branch *br;
>
>   			br = ubifs_idx_branch(c, idx, i);
> -			key_read(c, &br->key, &key);
> +			key_read(&br->key, &key);
>   			printf("\t\t%d: LEB %d:%d len %d key %s\n",
>   			       i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
>   			       le32_to_cpu(br->len),
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC] UBIFS unpacker v0
  2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
                   ` (10 preceding siblings ...)
  2015-10-31 11:16 ` [PATCH 11/11] ubifs: add ubifs_unpack Richard Weinberger
@ 2015-11-02  1:31 ` Dongsheng Yang
  11 siblings, 0 replies; 16+ messages in thread
From: Dongsheng Yang @ 2015-11-02  1:31 UTC (permalink / raw)
  To: Richard Weinberger, linux-mtd; +Cc: david

Hi Richard,
	I updated my work, then I can't apply your
patch on my latest branch now. Could you rebase them
against:

https://github.com/yangdongsheng/mtd-utils ubifs_dump_v2.1

I will give a try to play with the unpack tool :).

Yang

On 10/31/2015 07:15 PM, Richard Weinberger wrote:
> Hi!
>
> This is the first public release of the UBIFS unpack tool.
> Using this tool you can unpack an UBIFS to a local directory,
> it can operate directly on UBI volumes (i.e. /dev/ubiX_Y)
> or nanddumps (without OOB!). If you dump from a nandump,
> you have to specify the UBI volume ID you want to dump from.
> So far it is rather strict and refuses to unpack if the filesystem
> is corrupted. We plan to implement also a "fuzzy unpack" mode.
>
> The patches apply on Yang's mtd-utils restructure work.
>
> Thanks,
> //richard
>
> David Gstir (10):
>        ubifs: fix typo in ubifs_read
>        Make cli byte parsing from ubi-utils available for all tools
>        ubifs: add decompression functions
>        ubifs: remove ununsed ubifs context from key helpers
>        ubifs: keep scan buffer in ubifs_info
>        ubifs: extend master scanning code
>        ubifs: add missing include to defs.h
>        ubifs: Add more key helper functions
>        ubifs: add emubi, a minimal UBI emulation layer
>        ubifs: add ubifs_unpack
>
> Richard Weinberger (1):
>        ubifs: add complete version of list.h
>
>   Makefile                                |  11 +-
>   include/common.h                        |  90 ++++
>   ubi-utils/include/ubiutils-common.h     |   2 -
>   ubi-utils/mtdinfo.c                     |   6 +-
>   ubi-utils/ubiattach.c                   |   6 +-
>   ubi-utils/ubiformat.c                   |   8 +-
>   ubi-utils/ubimkvol.c                    |   6 +-
>   ubi-utils/ubinfo.c                      |  10 +-
>   ubi-utils/ubinize.c                     |  10 +-
>   ubi-utils/ubirsvol.c                    |   2 +-
>   ubi-utils/ubiutils-common.c             |  93 ----
>   ubifs-utils/include/compr.h             |   1 +
>   ubifs-utils/include/defs.h              |   1 +
>   ubifs-utils/include/emubi.h             |  82 +++
>   ubifs-utils/include/io.h                |   2 +
>   ubifs-utils/include/key.h               | 102 +++-
>   ubifs-utils/include/list.h              | 305 +++++++----
>   ubifs-utils/include/list_sort.h         |  11 +
>   ubifs-utils/include/master.h            |   7 +
>   ubifs-utils/include/ubifs.h             |  62 +++
>   ubifs-utils/lib/compr.c                 |  75 +++
>   ubifs-utils/lib/emubi.c                 | 371 ++++++++++++++
>   ubifs-utils/lib/io.c                    |  65 ++-
>   ubifs-utils/lib/list_sort.c             | 157 ++++++
>   ubifs-utils/lib/master.c                | 311 ++++++++++++
>   ubifs-utils/lib/scan.c                  |  20 +-
>   ubifs-utils/mkfs.ubifs/mkfs.ubifs.c     |  66 +--
>   ubifs-utils/ubifs_dump/ubifs_dump.c     |  89 +---
>   ubifs-utils/ubifs_unpack/index.c        | 648 ++++++++++++++++++++++++
>   ubifs-utils/ubifs_unpack/replay.c       | 865 ++++++++++++++++++++++++++++++++
>   ubifs-utils/ubifs_unpack/ubifs_unpack.c | 619 +++++++++++++++++++++++
>   ubifs-utils/ubifs_unpack/ubifs_unpack.h | 107 ++++
>   32 files changed, 3832 insertions(+), 378 deletions(-)
> .
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers
  2015-11-02  1:28   ` Dongsheng Yang
@ 2015-11-02 15:38     ` Artem Bityutskiy
  2015-12-20  3:01       ` Dongsheng Yang
  0 siblings, 1 reply; 16+ messages in thread
From: Artem Bityutskiy @ 2015-11-02 15:38 UTC (permalink / raw)
  To: Dongsheng Yang, Richard Weinberger, linux-mtd; +Cc: david

On Mon, 2015-11-02 at 09:28 +0800, Dongsheng Yang wrote:
> Yes, all ubifs_info *c in key.h are not used, But I am
> not sure about is that intentional or not.

Hi,

the intention was that there would be multiple key formats supported,
and these functions would look at something like c->key_format to
figure out how to work with this key.

Right now there is only one key type, so these are not needed as of
today.

Artem.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers
  2015-11-02 15:38     ` Artem Bityutskiy
@ 2015-12-20  3:01       ` Dongsheng Yang
  0 siblings, 0 replies; 16+ messages in thread
From: Dongsheng Yang @ 2015-12-20  3:01 UTC (permalink / raw)
  To: dedekind1, Richard Weinberger, linux-mtd; +Cc: david

On 11/02/2015 11:38 PM, Artem Bityutskiy wrote:
> On Mon, 2015-11-02 at 09:28 +0800, Dongsheng Yang wrote:
>> Yes, all ubifs_info *c in key.h are not used, But I am
>> not sure about is that intentional or not.
>
> Hi,
>
> the intention was that there would be multiple key formats supported,
> and these functions would look at something like c->key_format to
> figure out how to work with this key.

Thanx Artem,

Then, David and Richard, what about keep this parameter here for
scalability?

I would like to add a comment about it to point out what is that for.

Yang
>
> Right now there is only one key type, so these are not needed as of
> today.
>
> Artem.
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2015-12-20  3:09 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-31 11:15 [RFC] UBIFS unpacker v0 Richard Weinberger
2015-10-31 11:15 ` [PATCH 01/11] ubifs: add complete version of list.h Richard Weinberger
2015-10-31 11:15 ` [PATCH 02/11] ubifs: fix typo in ubifs_read Richard Weinberger
2015-10-31 11:15 ` [PATCH 03/11] Make cli byte parsing from ubi-utils available for all tools Richard Weinberger
2015-10-31 11:15 ` [PATCH 04/11] ubifs: add decompression functions Richard Weinberger
2015-10-31 11:15 ` [PATCH 05/11] ubifs: remove ununsed ubifs context from key helpers Richard Weinberger
2015-11-02  1:28   ` Dongsheng Yang
2015-11-02 15:38     ` Artem Bityutskiy
2015-12-20  3:01       ` Dongsheng Yang
2015-10-31 11:15 ` [PATCH 06/11] ubifs: keep scan buffer in ubifs_info Richard Weinberger
2015-10-31 11:15 ` [PATCH 07/11] ubifs: extend master scanning code Richard Weinberger
2015-10-31 11:15 ` [PATCH 08/11] ubifs: add missing include to defs.h Richard Weinberger
2015-10-31 11:15 ` [PATCH 09/11] ubifs: Add more key helper functions Richard Weinberger
2015-10-31 11:15 ` [PATCH 10/11] ubifs: add emubi, a minimal UBI emulation layer Richard Weinberger
2015-10-31 11:16 ` [PATCH 11/11] ubifs: add ubifs_unpack Richard Weinberger
2015-11-02  1:31 ` [RFC] UBIFS unpacker v0 Dongsheng Yang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.