fs: ubifs: Making ubifs image
authorDonggeun Kim <dg77.kim@samsung.com>
Mon, 4 Oct 2010 09:44:39 +0000 (18:44 +0900)
committerDonggeun Kim <dg77.kim@samsung.com>
Mon, 4 Oct 2010 09:44:39 +0000 (18:44 +0900)
It assumes that
only one file (modem.bin) is a source for making ubifs image.
Time information in inode is set by the fixed value.
Gid and uid in inode is set by the value of the original modem binary.

Signed-off-by: Donggeun Kim <dg77.kim@samsung.com>
fs/ubifs/Makefile
fs/ubifs/crc32.c [new file with mode: 0644]
fs/ubifs/crc32.h [new file with mode: 0644]
fs/ubifs/mkfs.ubifs.c [new file with mode: 0644]
fs/ubifs/mkfs.ubifs.h [new file with mode: 0644]
fs/ubifs/ubifs.h
fs/ubifs/ubifs_qsort.c [new file with mode: 0644]
fs/ubifs/ubifs_qsort.h [new file with mode: 0644]
include/mkfs.ubifs.h [new file with mode: 0644]

index 8328843..3be59a7 100644 (file)
@@ -33,6 +33,7 @@ COBJS-$(CONFIG_CMD_UBIFS) := ubifs.o io.o super.o sb.o master.o lpt.o
 COBJS-$(CONFIG_CMD_UBIFS) += lpt_commit.o scan.o lprops.o
 COBJS-$(CONFIG_CMD_UBIFS) += tnc.o tnc_misc.o debug.o crc16.o budget.o
 COBJS-$(CONFIG_CMD_UBIFS) += log.o orphan.o recovery.o replay.o
+COBJS-$(CONFIG_UBIFS_MK)  += ubifs_qsort.o crc32.o crc16.o mkfs.ubifs.o
 
 SRCS   := $(AOBJS:.o=.S) $(COBJS-y:.o=.c)
 OBJS   := $(addprefix $(obj),$(AOBJS) $(COBJS-y))
diff --git a/fs/ubifs/crc32.c b/fs/ubifs/crc32.c
new file mode 100644 (file)
index 0000000..7640507
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be unsigned (bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ */
+#include <linux/types.h>
+
+const u32 crc32_table[256] = {
+       0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+       0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+       0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+       0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+       0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+       0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+       0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+       0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+       0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+       0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+       0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+       0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+       0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+       0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+       0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+       0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+       0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+       0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+       0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+       0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+       0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+       0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+       0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+       0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+       0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+       0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+       0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+       0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+       0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+       0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+       0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+       0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+       0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+       0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+       0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+       0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+       0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+       0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+       0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+       0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+       0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+       0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+       0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+       0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+       0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+       0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+       0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+       0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+       0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+       0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+       0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+       0x2d02ef8dL
+};
diff --git a/fs/ubifs/crc32.h b/fs/ubifs/crc32.h
new file mode 100644 (file)
index 0000000..0a1457c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * This code was taken from the linux kernel. The license is GPL Version 2.
+ */
+
+#ifndef __UBIFS_CRC32_H__
+#define __UBIFS_CRC32_H__
+
+#include <linux/types.h>
+
+extern const u32 crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+static inline u32 ubifs_crc32(u32 val, const void *ss, int len)
+{
+       const unsigned char *s = ss;
+
+       while (--len >= 0)
+               val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+       return val;
+}
+
+#endif /* __CRC32_H__ */
diff --git a/fs/ubifs/mkfs.ubifs.c b/fs/ubifs/mkfs.ubifs.c
new file mode 100644 (file)
index 0000000..62b9961
--- /dev/null
@@ -0,0 +1,1708 @@
+/*
+ * 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
+ */
+
+#include "mkfs.ubifs.h"
+
+#define PROGRAM_VERSION "1.3"
+
+/* The node buffer must allow for worst case compression */
+#define NODE_BUFFER_SIZE (UBIFS_DATA_NODE_SZ + \
+                         UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
+
+/* Default time granularity in nanoseconds */
+#define DEFAULT_TIME_GRAN 1000000000
+
+#define MKFS_UBIFS_COMPR_NONE  0
+#define MKFS_UBIFS_COMPR_LZO   1
+
+#define MODEM_IMAGE_SIZE       0xc00000
+
+/**
+ * struct idx_entry - index entry.
+ * @next: next index entry (NULL at end of list)
+ * @prev: previous index entry (NULL at beginning of list)
+ * @key: key
+ * @name: directory entry name used for sorting colliding keys by name
+ * @lnum: LEB number
+ * @offs: offset
+ * @len: length
+ *
+ * The index is recorded as a linked list which is sorted and used to create
+ * the bottom level of the on-flash index tree. The remaining levels of the
+ * index tree are each built from the level below.
+ */
+struct idx_entry {
+       struct idx_entry *next;
+       struct idx_entry *prev;
+       union ubifs_key key;
+       char *name;
+       int lnum;
+       int offs;
+       int len;
+};
+
+/*
+ * Because we copy functions from the kernel, we use a subset of the UBIFS
+ * file-system description object struct ubifs_info.
+ */
+struct ubifs_info info_;
+static struct ubifs_info *c = &info_;
+
+/* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */
+int debug_level;
+int verbose;
+
+/* The 'head' (position) which nodes are written */
+static int head_lnum;
+static int head_offs;
+static int head_flags;
+
+/* The index list */
+static struct idx_entry *idx_list_first;
+static struct idx_entry *idx_list_last;
+static size_t idx_cnt;
+
+/* Global buffers */
+static void *leb_buf;
+static void *node_buf;
+static void *block_buf;
+static void *lzo_mem;
+
+static void *modem_buf;
+
+/* Inode creation sequence number */
+static unsigned long long creat_sqnum;
+
+/**
+ * calc_min_log_lebs - calculate the minimum number of log LEBs needed.
+ * @max_bud_bytes: journal size (buds only)
+ */
+static int calc_min_log_lebs(unsigned long long max_bud_bytes)
+{
+       int buds, log_lebs;
+       unsigned long long log_size;
+
+       buds = (max_bud_bytes + c->leb_size - 1) / c->leb_size;
+       log_size = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+       log_size *= buds;
+       log_size += ALIGN(UBIFS_CS_NODE_SZ +
+                         UBIFS_REF_NODE_SZ * (c->jhead_cnt + 2),
+                         c->min_io_size);
+       log_lebs = (log_size + c->leb_size - 1) / c->leb_size;
+       log_lebs += 1;
+       return log_lebs;
+}
+
+static int set_options(int min_io_size, int leb_size, int max_leb_cnt)
+{
+       int lebs;
+
+       c->fanout = 8;
+       c->orph_lebs = 1;
+       c->key_hash = key_r5_hash;
+       c->key_len = UBIFS_SK_LEN;
+       c->default_compr = UBIFS_COMPR_LZO;
+       c->lsave_cnt = 256;
+
+       c->min_io_size = min_io_size;
+       c->leb_size = leb_size;
+       c->max_leb_cnt = max_leb_cnt;
+
+       /* calcuate max_bud_bytes */
+       lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+       lebs -= c->orph_lebs;
+       lebs -= UBIFS_MIN_LOG_LEBS;
+       /*
+        * We do not know lprops geometry so far, so assume minimum
+        * count of lprops LEBs.
+        */
+       lebs -= UBIFS_MIN_LPT_LEBS;
+       /* Make the journal about 12.5% of main area lebs */
+       c->max_bud_bytes = (lebs / 8) * (long long)c->leb_size;
+       /* Make the max journal size 8MiB */
+       if (c->max_bud_bytes > 8 * 1024 * 1024)
+               c->max_bud_bytes = 8 * 1024 * 1024;
+       if (c->max_bud_bytes < 4 * c->leb_size)
+               c->max_bud_bytes = 4 * c->leb_size;
+
+       /* calculate log_lebs */
+       c->log_lebs = calc_min_log_lebs(c->max_bud_bytes);
+       c->log_lebs += 2;
+
+       return 0;
+}
+
+/**
+ * prepare_node - fill in the common header.
+ * @node: node
+ * @len: node length
+ */
+static void prepare_node(void *node, int len)
+{
+       uint32_t crc;
+       struct ubifs_ch *ch = node;
+
+       ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
+       ch->len = cpu_to_le32(len);
+       ch->group_type = UBIFS_NO_NODE_GROUP;
+       ch->sqnum = cpu_to_le64(++c->max_sqnum);
+       ch->padding[0] = ch->padding[1] = 0;
+       crc = ubifs_crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
+       ch->crc = cpu_to_le32(crc);
+}
+
+/**
+ * write_leb - copy the image of a LEB to the output target.
+ * @lnum: LEB number
+ * @len: length of data in the buffer
+ * @buf: buffer (must be at least c->leb_size bytes)
+ * @dtype: expected data type
+ */
+int write_leb(int lnum, int len, void *buf, int dtype)
+{
+       unsigned long pos = (unsigned long)lnum * c->leb_size;
+
+       dbg_msg("LEB %d len %d", lnum, len);
+       memset(buf + len, 0xff, c->leb_size - len);
+
+       memcpy(modem_buf + pos, buf, c->leb_size);
+
+       return 0;
+}
+
+/**
+ * write_empty_leb - copy the image of an empty LEB to the output target.
+ * @lnum: LEB number
+ * @dtype: expected data type
+ */
+static int write_empty_leb(int lnum, int dtype)
+{
+       return write_leb(lnum, 0, leb_buf, dtype);
+}
+
+/**
+ * do_pad - pad a buffer to the minimum I/O size.
+ * @buf: buffer
+ * @len: buffer length
+ */
+static int do_pad(void *buf, int len)
+{
+       int pad_len, alen = ALIGN(len, 8), wlen = ALIGN(alen, c->min_io_size);
+       uint32_t crc;
+
+       memset(buf + len, 0xff, alen - len);
+       pad_len = wlen - alen;
+       dbg_msg("len %d pad_len %d", len, pad_len);
+       buf += alen;
+       if (pad_len >= (int)UBIFS_PAD_NODE_SZ) {
+               struct ubifs_ch *ch = buf;
+               struct ubifs_pad_node *pad_node = buf;
+
+               ch->magic      = cpu_to_le32(UBIFS_NODE_MAGIC);
+               ch->node_type  = UBIFS_PAD_NODE;
+               ch->group_type = UBIFS_NO_NODE_GROUP;
+               ch->padding[0] = ch->padding[1] = 0;
+               ch->sqnum      = cpu_to_le64(0);
+               ch->len        = cpu_to_le32(UBIFS_PAD_NODE_SZ);
+
+               pad_len -= UBIFS_PAD_NODE_SZ;
+               pad_node->pad_len = cpu_to_le32(pad_len);
+
+               crc = ubifs_crc32(UBIFS_CRC32_INIT, buf + 8,
+                                 UBIFS_PAD_NODE_SZ - 8);
+               ch->crc = cpu_to_le32(crc);
+
+               memset(buf + UBIFS_PAD_NODE_SZ, 0, pad_len);
+       } else if (pad_len > 0)
+               memset(buf, UBIFS_PADDING_BYTE, pad_len);
+
+       return wlen;
+}
+
+/**
+ * write_node - write a node to a LEB.
+ * @node: node
+ * @len: node length
+ * @lnum: LEB number
+ * @dtype: expected data type
+ */
+static int write_node(void *node, int len, int lnum, int dtype)
+{
+       prepare_node(node, len);
+
+       memcpy(leb_buf, node, len);
+
+       len = do_pad(leb_buf, len);
+
+       return write_leb(lnum, len, leb_buf, dtype);
+}
+
+/**
+ * calc_dark - calculate LEB dark space size.
+ * @c: the UBIFS file-system description object
+ * @spc: amount of free and dirty space in the LEB
+ *
+ * This function calculates amount of dark space in an LEB which has @spc bytes
+ * of free and dirty space. Returns the calculations result.
+ *
+ * Dark space is the space which is not always usable - it depends on which
+ * nodes are written in which order. E.g., if an LEB has only 512 free bytes,
+ * it is dark space, because it cannot fit a large data node. So UBIFS cannot
+ * count on this LEB and treat these 512 bytes as usable because it is not true
+ * if, for example, only big chunks of uncompressible data will be written to
+ * the FS.
+ */
+static int calc_dark(struct ubifs_info *c, int spc)
+{
+       if (spc < c->dark_wm)
+               return spc;
+
+       /*
+        * If we have slightly more space then the dark space watermark, we can
+        * anyway safely assume it we'll be able to write a node of the
+        * smallest size there.
+        */
+       if (spc - c->dark_wm < (int)MIN_WRITE_SZ)
+               return spc - MIN_WRITE_SZ;
+
+       return c->dark_wm;
+}
+
+/**
+ * set_lprops - set the LEB property values for a LEB.
+ * @lnum: LEB number
+ * @offs: end offset of data in the LEB
+ * @flags: LEB property flags
+ */
+static void set_lprops(int lnum, int offs, int flags)
+{
+       int i = lnum - c->main_first, free, dirty;
+       int a = max_t(int, c->min_io_size, 8);
+
+       free = c->leb_size - ALIGN(offs, a);
+       dirty = c->leb_size - free - ALIGN(offs, 8);
+       dbg_msg("LEB %d free %d dirty %d flags %d", lnum, free, dirty,
+               flags);
+       c->lpt[i].free = free;
+       c->lpt[i].dirty = dirty;
+       c->lpt[i].flags = flags;
+       c->lst.total_free += free;
+       c->lst.total_dirty += dirty;
+       if (flags & LPROPS_INDEX)
+               c->lst.idx_lebs += 1;
+       else {
+               int spc;
+
+               spc = free + dirty;
+               if (spc < c->dead_wm)
+                       c->lst.total_dead += spc;
+               else
+                       c->lst.total_dark += calc_dark(c, spc);
+               c->lst.total_used += c->leb_size - spc;
+       }
+}
+
+/**
+ * add_to_index - add a node key and position to the index.
+ * @key: node key
+ * @lnum: node LEB number
+ * @offs: node offset
+ * @len: node length
+ */
+static int add_to_index(union ubifs_key *key, char *name, int lnum, int offs,
+                       int len)
+{
+       struct idx_entry *e;
+
+       dbg_msg("LEB %d offs %d len %d", lnum, offs, len);
+       e = malloc(sizeof(struct idx_entry));
+       if (!e)
+               return err_msg("out of memory");
+
+       e->next = NULL;
+       e->prev = idx_list_last;
+       e->key = *key;
+       e->name = name;
+       e->lnum = lnum;
+       e->offs = offs;
+       e->len = len;
+       if (!idx_list_first)
+               idx_list_first = e;
+       if (idx_list_last)
+               idx_list_last->next = e;
+       idx_list_last = e;
+       idx_cnt += 1;
+       return 0;
+}
+
+/**
+ * flush_nodes - write the current head and move the head to the next LEB.
+ */
+static int flush_nodes(void)
+{
+       int len, err;
+
+       if (!head_offs)
+               return 0;
+       len = do_pad(leb_buf, head_offs);
+       err = write_leb(head_lnum, len, leb_buf, UBI_UNKNOWN);
+       if (err)
+               return err;
+       set_lprops(head_lnum, head_offs, head_flags);
+       head_lnum += 1;
+       head_offs = 0;
+
+       return 0;
+}
+
+/**
+ * reserve_space - reserve space for a node on the head.
+ * @len: node length
+ * @lnum: LEB number is returned here
+ * @offs: offset is returned here
+ */
+static int reserve_space(int len, int *lnum, int *offs)
+{
+       int err;
+
+       if (len > c->leb_size - head_offs) {
+               err = flush_nodes();
+               if (err)
+                       return err;
+       }
+       *lnum = head_lnum;
+       *offs = head_offs;
+       head_offs += ALIGN(len, 8);
+       return 0;
+}
+
+/**
+ * add_node - write a node to the head.
+ * @key: node key
+ * @node: node
+ * @len: node length
+ */
+static int add_node(union ubifs_key *key, char *name, void *node, int len)
+{
+       int err, lnum, offs;
+
+       prepare_node(node, len);
+
+       err = reserve_space(len, &lnum, &offs);
+       if (err)
+               return err;
+
+       memcpy(leb_buf + offs, node, len);
+       memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
+
+       add_to_index(key, name, lnum, offs, len);
+
+       return 0;
+}
+
+/**
+ * add_inode_with_data - write an inode.
+ */
+static int add_inode_with_data(unsigned long file_size, ino_t inum, void *data,
+                              unsigned int data_len)
+{
+       struct ubifs_ino_node *ino = node_buf;
+       union ubifs_key key;
+       int len, use_flags = 0;
+
+       creat_sqnum = c->max_sqnum;
+
+       use_flags |= UBIFS_COMPR_FL;
+
+       memset(ino, 0, UBIFS_INO_NODE_SZ);
+
+       ino_key_init(c, &key, inum);
+       ino->ch.node_type = UBIFS_INO_NODE;
+       key_write(c, &key, &ino->key);
+       ino->size       = cpu_to_le64(file_size);
+
+       if (inum == UBIFS_ROOT_INO) {
+               ino->creat_sqnum        = cpu_to_le64(1);
+               ino->nlink              = cpu_to_le32(2);
+               ino->atime_sec          = cpu_to_le64(0x4ca2dfd9);
+               ino->ctime_sec          = cpu_to_le64(0x4ca2dfd9);
+               ino->mtime_sec          = cpu_to_le64(0x4ca2dfd9);
+               ino->mode               = cpu_to_le32(0x41ed);
+       } else {
+               ino->creat_sqnum        = cpu_to_le64(2);
+               ino->nlink              = cpu_to_le32(1);
+               ino->atime_sec          = cpu_to_le64(0x4ca2dfd9);
+               ino->ctime_sec          = cpu_to_le64(0x4ca2dfd9);
+               ino->mtime_sec          = cpu_to_le64(0x4ca2dfd9);
+               ino->uid                = cpu_to_le32(1000);
+               ino->gid                = cpu_to_le32(513);
+               ino->mode               = cpu_to_le32(0x81c0);
+       }
+
+       ino->flags      = cpu_to_le32(use_flags);
+       ino->data_len   = cpu_to_le32(data_len);
+       ino->compr_type = cpu_to_le16(c->default_compr);
+       if (data_len)
+               memcpy(&ino->data, data, data_len);
+
+       len = UBIFS_INO_NODE_SZ + data_len;
+
+       return add_node(&key, NULL, ino, len);
+}
+
+/**
+ * add_inode - write an inode.
+ */
+static int add_inode(unsigned long file_size, ino_t inum)
+{
+       return add_inode_with_data(file_size, inum, NULL, 0);
+}
+
+/**
+ * add_dent_node - write a directory entry node.
+ * @dir_inum: target inode number of directory
+ * @name: directory entry name
+ * @inum: target inode number of the directory entry
+ * @type: type of the target inode
+ */
+static int add_dent_node(ino_t dir_inum, const char *name, ino_t inum,
+                        unsigned char type)
+{
+       struct ubifs_dent_node *dent = node_buf;
+       union ubifs_key key;
+       struct qstr dname;
+       char *kname;
+       int len;
+
+       dbg_msg("%s ino %lu type %u dir ino %lu", name, inum,
+               (unsigned)type, dir_inum);
+       memset(dent, 0, UBIFS_DENT_NODE_SZ);
+
+       dname.name = (void *)name;
+       dname.len = strlen(name);
+
+       dent->ch.node_type = UBIFS_DENT_NODE;
+
+       dent_key_init(c, &key, dir_inum, &dname);
+       key_write(c, &key, dent->key);
+       dent->inum = cpu_to_le64(inum);
+       dent->padding1 = 0;
+       dent->type = type;
+       dent->nlen = cpu_to_le16(dname.len);
+       memcpy(dent->name, dname.name, dname.len);
+       dent->name[dname.len] = '\0';
+
+       len = UBIFS_DENT_NODE_SZ + dname.len + 1;
+
+       kname = strdup(name);
+       if (!kname)
+               return err_msg("cannot allocate memory");
+
+       return add_node(&key, kname, dent, len);
+}
+
+/**
+ * add_data_node - write the data of a file to the output buffer.
+ */
+static int add_data_node(unsigned long file_size, void *src_addr, ino_t inum)
+{
+       struct ubifs_data_node *dn = node_buf;
+       void *buf = block_buf;
+       ssize_t bytes_read, offset;
+       union ubifs_key key;
+       int dn_len, err;
+       unsigned int block_no = 0;
+       size_t out_len;
+
+       creat_sqnum = c->max_sqnum++;
+
+       bytes_read = 0;
+       offset = 0;
+
+       do {
+               memset(buf, 0, UBIFS_BLOCK_SIZE);
+               if (offset + UBIFS_BLOCK_SIZE > file_size) {
+                       memcpy(buf, src_addr + offset, file_size - offset);
+                       bytes_read = file_size - offset;
+               } else {
+                       memcpy(buf, src_addr + offset, UBIFS_BLOCK_SIZE);
+                       bytes_read = UBIFS_BLOCK_SIZE;
+               }
+
+               /* Make data node */
+               memset(dn, 0, UBIFS_DATA_NODE_SZ);
+               data_key_init(c, &key, inum, block_no++);
+               dn->ch.node_type = UBIFS_DATA_NODE;
+               key_write(c, &key, &dn->key);
+               dn->size = cpu_to_le32(bytes_read);
+               memcpy(&dn->data, buf, bytes_read);
+               out_len = bytes_read;
+
+               err = lzo1x_1_compress(buf, bytes_read, &dn->data,
+                                      &out_len, lzo_mem);
+               if (err != LZO_E_OK)
+                       return err;
+               dn->compr_type = cpu_to_le16(MKFS_UBIFS_COMPR_LZO);
+               dn_len = UBIFS_DATA_NODE_SZ + out_len;
+               /* Add data node to file system */
+
+               err = add_node(&key, NULL, dn, dn_len);
+               if (err)
+                       return err;
+
+               offset += UBIFS_BLOCK_SIZE;
+       } while (offset < file_size);
+
+       return err;
+}
+
+static int namecmp(const char *name1, const char *name2)
+{
+       size_t len1 = strlen(name1), len2 = strlen(name2);
+       size_t clen = (len1 < len2) ? len1 : len2;
+       int cmp;
+
+       cmp = memcmp(name1, name2, clen);
+       if (cmp)
+               return cmp;
+       return (len1 < len2) ? -1 : 1;
+}
+
+static int cmp_idx(const void *a, const void *b)
+{
+       const struct idx_entry *e1 = *(const struct idx_entry **)a;
+       const struct idx_entry *e2 = *(const struct idx_entry **)b;
+       int cmp;
+
+       cmp = keys_cmp(c, &e1->key, &e2->key);
+       if (cmp)
+               return cmp;
+       return namecmp(e1->name, e2->name);
+}
+
+/**
+ * add_idx_node - write an index node to the head.
+ * @node: index node
+ * @child_cnt: number of children of this index node
+ */
+static int add_idx_node(void *node, int child_cnt)
+{
+       int err, lnum, offs, len;
+
+       len = ubifs_idx_node_sz(c, child_cnt);
+
+       prepare_node(node, len);
+
+       err = reserve_space(len, &lnum, &offs);
+       if (err)
+               return err;
+
+       memcpy(leb_buf + offs, node, len);
+       memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len);
+
+       c->old_idx_sz += ALIGN(len, 8);
+
+       dbg_msg("at %d:%d len %d index size %llu", lnum, offs, len,
+               c->old_idx_sz);
+
+       /* The last index node written will be the root */
+       c->zroot.lnum = lnum;
+       c->zroot.offs = offs;
+       c->zroot.len = len;
+
+       return 0;
+}
+
+/**
+ * write_index - write out the index.
+ */
+static int write_index(void)
+{
+       size_t sz, i, cnt, idx_sz, pstep, bcnt;
+       struct idx_entry **idx_ptr, **p;
+       struct ubifs_idx_node *idx;
+       struct ubifs_branch *br;
+       int child_cnt, j, level, blnum, boffs, blen, blast_len, err;
+
+       dbg_msg("leaf node count: %zd", idx_cnt);
+
+       /* Reset the head for the index */
+       head_flags = LPROPS_INDEX;
+       /* Allocate index node */
+       idx_sz = ubifs_idx_node_sz(c, c->fanout);
+       idx = malloc(idx_sz);
+       if (!idx)
+               return err_msg("out of memory");
+
+       /* Make an array of pointers to sort the index list */
+       sz = idx_cnt * sizeof(struct idx_entry *);
+       if (sz / sizeof(struct idx_entry *) != idx_cnt) {
+               free(idx);
+               return err_msg("index is too big (%zu entries)", idx_cnt);
+       }
+       idx_ptr = malloc(sz);
+       if (!idx_ptr) {
+               free(idx);
+               return err_msg("out of memory - needed %zu bytes for index",
+                              sz);
+       }
+       idx_ptr[0] = idx_list_first;
+       for (i = 1; i < idx_cnt; i++)
+               idx_ptr[i] = idx_ptr[i - 1]->next;
+       ubifs_qsort(idx_ptr, idx_cnt, sizeof(struct idx_entry *), cmp_idx);
+       /* Write level 0 index nodes */
+       cnt = idx_cnt / c->fanout;
+       if (idx_cnt % c->fanout)
+               cnt += 1;
+       p = idx_ptr;
+       blnum = head_lnum;
+       boffs = head_offs;
+       for (i = 0; i < cnt; i++) {
+               /*
+                * Calculate the child count. All index nodes are created full
+                * except for the last index node on each row.
+                */
+               if (i == cnt - 1) {
+                       child_cnt = idx_cnt % c->fanout;
+                       if (child_cnt == 0)
+                               child_cnt = c->fanout;
+               } else
+                       child_cnt = c->fanout;
+               memset(idx, 0, idx_sz);
+               idx->ch.node_type = UBIFS_IDX_NODE;
+               idx->child_cnt = cpu_to_le16(child_cnt);
+               idx->level = cpu_to_le16(0);
+               for (j = 0; j < child_cnt; j++, p++) {
+                       br = ubifs_idx_branch(c, idx, j);
+                       key_write_idx(c, &(*p)->key, &br->key);
+                       br->lnum = cpu_to_le32((*p)->lnum);
+                       br->offs = cpu_to_le32((*p)->offs);
+                       br->len = cpu_to_le32((*p)->len);
+               }
+               add_idx_node(idx, child_cnt);
+       }
+       /* Write level 1 index nodes and above */
+       level = 0;
+       pstep = 1;
+       while (cnt > 1) {
+               /*
+                * 'blast_len' is the length of the last index node in the level
+                * below.
+                */
+               blast_len = ubifs_idx_node_sz(c, child_cnt);
+               /* 'bcnt' is the number of index nodes in the level below */
+               bcnt = cnt;
+               /* 'cnt' is the number of index nodes in this level */
+               cnt = (cnt + c->fanout - 1) / c->fanout;
+               if (cnt == 0)
+                       cnt = 1;
+               level += 1;
+               /*
+                * The key of an index node is the same as the key of its first
+                * child. Thus we can get the key by stepping along the bottom
+                * level 'p' with an increasing large step 'pstep'.
+                */
+               p = idx_ptr;
+               pstep *= c->fanout;
+               for (i = 0; i < cnt; i++) {
+                       /*
+                        * Calculate the child count. All index nodes are
+                        * created full except for the last index node on each
+                        * row.
+                        */
+                       if (i == cnt - 1) {
+                               child_cnt = bcnt % c->fanout;
+                               if (child_cnt == 0)
+                                       child_cnt = c->fanout;
+                       } else
+                               child_cnt = c->fanout;
+                       memset(idx, 0, idx_sz);
+                       idx->ch.node_type = UBIFS_IDX_NODE;
+                       idx->child_cnt = cpu_to_le16(child_cnt);
+                       idx->level = cpu_to_le16(level);
+                       for (j = 0; j < child_cnt; j++) {
+                               size_t bn = i * c->fanout + j;
+
+                               /*
+                                * The length of the index node in the level
+                                * below is 'idx_sz' except when it is the last
+                                * node on the row. i.e. all the others on the
+                                * row are full.
+                                */
+                               if (bn == bcnt - 1)
+                                       blen = blast_len;
+                               else
+                                       blen = idx_sz;
+                               /*
+                                * 'blnum' and 'boffs' hold the position of the
+                                * index node on the level below.
+                                */
+                               if (boffs + blen > c->leb_size) {
+                                       blnum += 1;
+                                       boffs = 0;
+                               }
+                               /*
+                                * Fill in the branch with the key and position
+                                * of the index node from the level below.
+                                */
+                               br = ubifs_idx_branch(c, idx, j);
+                               key_write_idx(c, &(*p)->key, &br->key);
+                               br->lnum = cpu_to_le32(blnum);
+                               br->offs = cpu_to_le32(boffs);
+                               br->len = cpu_to_le32(blen);
+                               /*
+                                * Step to the next index node on the level
+                                * below.
+                                */
+                               boffs += ALIGN(blen, 8);
+                               p += pstep;
+                       }
+                       add_idx_node(idx, child_cnt);
+               }
+       }
+
+       /* Free stuff */
+       for (i = 0; i < idx_cnt; i++)
+               free(idx_ptr[i]);
+       free(idx_ptr);
+       free(idx);
+
+       dbg_msg("zroot is at %d:%d len %d", c->zroot.lnum, c->zroot.offs,
+               c->zroot.len);
+
+       /* Set the index head */
+       c->ihead_lnum = head_lnum;
+       c->ihead_offs = ALIGN(head_offs, c->min_io_size);
+       dbg_msg("ihead is at %d:%d", c->ihead_lnum, c->ihead_offs);
+
+       /* Flush the last index LEB */
+       err = flush_nodes();
+       if (err)
+               return err;
+
+       return 0;
+}
+
+/**
+ * set_gc_lnum - set the LEB number reserved for the garbage collector.
+ */
+static int set_gc_lnum(void)
+{
+       int err;
+
+       c->gc_lnum = head_lnum++;
+
+       err = write_empty_leb(c->gc_lnum, UBI_LONGTERM);
+       if (err)
+               return err;
+       set_lprops(c->gc_lnum, 0, 0);
+       c->lst.empty_lebs += 1;
+       return 0;
+}
+
+/**
+ * finalize_leb_cnt - now that we know how many LEBs we used.
+ */
+static int finalize_leb_cnt(void)
+{
+       c->leb_cnt = head_lnum;
+       if (c->leb_cnt > c->max_leb_cnt)
+               /* TODO: in this case it segfaults because buffer overruns - we
+                * somewhere allocate smaller buffers - fix */
+               return err_msg("max_leb_cnt too low (%d needed)", c->leb_cnt);
+       c->main_lebs = c->leb_cnt - c->main_first;
+
+       c->max_bud_bytes = c->leb_size * (c->main_lebs - 1);
+
+       return 0;
+}
+
+/**
+ * write_super - write the super block.
+ */
+static int write_super(void)
+{
+       struct ubifs_sb_node sup;
+       int i;
+
+       memset(&sup, 0, UBIFS_SB_NODE_SZ);
+
+       sup.ch.node_type  = UBIFS_SB_NODE;
+       sup.key_hash      = c->key_hash_type;
+       sup.min_io_size   = cpu_to_le32(c->min_io_size);
+       sup.leb_size      = cpu_to_le32(c->leb_size);
+       sup.leb_cnt       = cpu_to_le32(c->leb_cnt);
+       sup.max_leb_cnt   = cpu_to_le32(c->max_leb_cnt);
+       sup.max_bud_bytes = cpu_to_le64(c->max_bud_bytes);
+       sup.log_lebs      = cpu_to_le32(c->log_lebs);
+       sup.lpt_lebs      = cpu_to_le32(c->lpt_lebs);
+       sup.orph_lebs     = cpu_to_le32(c->orph_lebs);
+       sup.jhead_cnt     = cpu_to_le32(c->jhead_cnt);
+       sup.fanout        = cpu_to_le32(c->fanout);
+       sup.lsave_cnt     = cpu_to_le32(c->lsave_cnt);
+       sup.fmt_version   = cpu_to_le32(UBIFS_FORMAT_VERSION);
+       sup.default_compr = cpu_to_le16(c->default_compr);
+       sup.rp_size       = cpu_to_le64(c->rp_size);
+       sup.time_gran     = cpu_to_le32(DEFAULT_TIME_GRAN);
+
+       for (i = 0; i < 16; i++)
+               sup.uuid[i]     = 1;
+
+       if (c->big_lpt)
+               sup.flags |= cpu_to_le32(UBIFS_FLG_BIGLPT);
+
+       return write_node(&sup, UBIFS_SB_NODE_SZ, UBIFS_SB_LNUM, UBI_LONGTERM);
+}
+
+/**
+ * write_master - write the master node.
+ */
+static int write_master(void)
+{
+       struct ubifs_mst_node mst;
+       int err;
+
+       memset(&mst, 0, UBIFS_MST_NODE_SZ);
+
+       mst.ch.node_type = UBIFS_MST_NODE;
+       mst.log_lnum     = cpu_to_le32(UBIFS_LOG_LNUM);
+       mst.highest_inum = cpu_to_le64(c->highest_inum);
+       mst.cmt_no       = cpu_to_le64(0);
+       mst.flags        = cpu_to_le32(UBIFS_MST_NO_ORPHS);
+       mst.root_lnum    = cpu_to_le32(c->zroot.lnum);
+       mst.root_offs    = cpu_to_le32(c->zroot.offs);
+       mst.root_len     = cpu_to_le32(c->zroot.len);
+       mst.gc_lnum      = cpu_to_le32(c->gc_lnum);
+       mst.ihead_lnum   = cpu_to_le32(c->ihead_lnum);
+       mst.ihead_offs   = cpu_to_le32(c->ihead_offs);
+       mst.index_size   = cpu_to_le64(c->old_idx_sz);
+       mst.lpt_lnum     = cpu_to_le32(c->lpt_lnum);
+       mst.lpt_offs     = cpu_to_le32(c->lpt_offs);
+       mst.nhead_lnum   = cpu_to_le32(c->nhead_lnum);
+       mst.nhead_offs   = cpu_to_le32(c->nhead_offs);
+       mst.ltab_lnum    = cpu_to_le32(c->ltab_lnum);
+       mst.ltab_offs    = cpu_to_le32(c->ltab_offs);
+       mst.lsave_lnum   = cpu_to_le32(c->lsave_lnum);
+       mst.lsave_offs   = cpu_to_le32(c->lsave_offs);
+       mst.lscan_lnum   = cpu_to_le32(c->lscan_lnum);
+       mst.empty_lebs   = cpu_to_le32(c->lst.empty_lebs);
+       mst.idx_lebs     = cpu_to_le32(c->lst.idx_lebs);
+       mst.total_free   = cpu_to_le64(c->lst.total_free);
+       mst.total_dirty  = cpu_to_le64(c->lst.total_dirty);
+       mst.total_used   = cpu_to_le64(c->lst.total_used);
+       mst.total_dead   = cpu_to_le64(c->lst.total_dead);
+       mst.total_dark   = cpu_to_le64(c->lst.total_dark);
+       mst.leb_cnt      = cpu_to_le32(c->leb_cnt);
+
+       err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM,
+                        UBI_SHORTTERM);
+       if (err)
+               return err;
+
+       err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1,
+                        UBI_SHORTTERM);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+/**
+ * write_log - write an empty log.
+ */
+static int write_log(void)
+{
+       struct ubifs_cs_node cs;
+       int err, i, lnum;
+
+       lnum = UBIFS_LOG_LNUM;
+
+       cs.ch.node_type = UBIFS_CS_NODE;
+       cs.cmt_no = cpu_to_le64(0);
+
+       err = write_node(&cs, UBIFS_CS_NODE_SZ, lnum, UBI_UNKNOWN);
+       if (err)
+               return err;
+
+       lnum += 1;
+
+       for (i = 1; i < c->log_lebs; i++, lnum++) {
+               err = write_empty_leb(lnum, UBI_UNKNOWN);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+
+/**
+ * pack_bits - pack bit fields end-to-end.
+ * @addr: address at which to pack (passed and next address returned)
+ * @pos: bit position at which to pack (passed and next position returned)
+ * @val: value to pack
+ * @nrbits: number of bits of value to pack (1-32)
+ */
+static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits)
+{
+       uint8_t *p = *addr;
+       int b = *pos;
+
+       if (b) {
+               *p |= ((uint8_t)val) << b;
+               nrbits += b;
+               if (nrbits > 8) {
+                       *++p = (uint8_t)(val >>= (8 - b));
+                       if (nrbits > 16) {
+                               *++p = (uint8_t)(val >>= 8);
+                               if (nrbits > 24) {
+                                       *++p = (uint8_t)(val >>= 8);
+                                       if (nrbits > 32)
+                                               *++p = (uint8_t)(val >>= 8);
+                               }
+                       }
+               }
+       } else {
+               *p = (uint8_t)val;
+               if (nrbits > 8) {
+                       *++p = (uint8_t)(val >>= 8);
+                       if (nrbits > 16) {
+                               *++p = (uint8_t)(val >>= 8);
+                               if (nrbits > 24)
+                                       *++p = (uint8_t)(val >>= 8);
+                       }
+               }
+       }
+       b = nrbits & 7;
+       if (b == 0)
+               p++;
+       *addr = p;
+       *pos = b;
+}
+
+/**
+ * pack_pnode - pack all the bit fields of a pnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @pnode: pnode to pack
+ */
+static void pack_pnode(struct ubifs_info *c, void *buf,
+                      struct ubifs_pnode *pnode)
+{
+       uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+       int i, pos = 0;
+       uint16_t crc;
+
+       pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
+       if (c->big_lpt)
+               pack_bits(&addr, &pos, pnode->num, c->pcnt_bits);
+       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+               pack_bits(&addr, &pos, pnode->lprops[i].free >> 3,
+                         c->space_bits);
+               pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3,
+                         c->space_bits);
+               if (pnode->lprops[i].flags & LPROPS_INDEX)
+                       pack_bits(&addr, &pos, 1, 1);
+               else
+                       pack_bits(&addr, &pos, 0, 1);
+       }
+       crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+                   c->pnode_sz - UBIFS_LPT_CRC_BYTES);
+       addr = buf;
+       pos = 0;
+       pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * calc_nnode_num - calculate nnode number.
+ * @row: the row in the tree (root is zero)
+ * @col: the column in the row (leftmost is zero)
+ *
+ * The nnode number is a number that uniquely identifies a nnode and can be used
+ * easily to traverse the tree from the root to that nnode.
+ *
+ * This function calculates and returns the nnode number for the nnode at @row
+ * and @col.
+ */
+static int calc_nnode_num(int row, int col)
+{
+       int num, bits;
+
+       num = 1;
+       while (row--) {
+               bits = (col & (UBIFS_LPT_FANOUT - 1));
+               col >>= UBIFS_LPT_FANOUT_SHIFT;
+               num <<= UBIFS_LPT_FANOUT_SHIFT;
+               num |= bits;
+       }
+       return num;
+}
+
+/**
+ * pack_nnode - pack all the bit fields of a nnode.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @nnode: nnode to pack
+ */
+static void pack_nnode(struct ubifs_info *c, void *buf,
+                      struct ubifs_nnode *nnode)
+{
+       uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+       int i, pos = 0;
+       uint16_t crc;
+
+       pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
+       if (c->big_lpt)
+               pack_bits(&addr, &pos, nnode->num, c->pcnt_bits);
+       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+               int lnum = nnode->nbranch[i].lnum;
+
+               if (lnum == 0)
+                       lnum = c->lpt_last + 1;
+               pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
+               pack_bits(&addr, &pos, nnode->nbranch[i].offs,
+                         c->lpt_offs_bits);
+       }
+       crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+                   c->nnode_sz - UBIFS_LPT_CRC_BYTES);
+       addr = buf;
+       pos = 0;
+       pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * pack_lsave - pack the LPT's save table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @lsave: LPT's save table to pack
+ */
+static void pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
+{
+       uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+       int i, pos = 0;
+       uint16_t crc;
+
+       pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
+       for (i = 0; i < c->lsave_cnt; i++)
+               pack_bits(&addr, &pos, lsave[i], c->lnum_bits);
+       crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+                   c->lsave_sz - UBIFS_LPT_CRC_BYTES);
+       addr = buf;
+       pos = 0;
+       pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * set_ltab - set LPT LEB properties.
+ * @c: UBIFS file-system description object
+ * @lnum: LEB number
+ * @free: amount of free space
+ * @dirty: amount of dirty space
+ */
+static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
+{
+       dbg_msg("LEB %d free %d dirty %d to %d %d",
+               lnum, c->ltab[lnum - c->lpt_first].free,
+               c->ltab[lnum - c->lpt_first].dirty, free, dirty);
+       c->ltab[lnum - c->lpt_first].free = free;
+       c->ltab[lnum - c->lpt_first].dirty = dirty;
+}
+
+/**
+ * pack_ltab - pack the LPT's own lprops table.
+ * @c: UBIFS file-system description object
+ * @buf: buffer into which to pack
+ * @ltab: LPT's own lprops table to pack
+ */
+static void pack_ltab(struct ubifs_info *c, void *buf,
+                        struct ubifs_lpt_lprops *ltab)
+{
+       uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
+       int i, pos = 0;
+       uint16_t crc;
+
+       pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
+       for (i = 0; i < c->lpt_lebs; i++) {
+               pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits);
+               pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
+       }
+       crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
+                   c->ltab_sz - UBIFS_LPT_CRC_BYTES);
+       addr = buf;
+       pos = 0;
+       pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
+}
+
+/**
+ * create_lpt - create LPT.
+ * @c: UBIFS file-system description object
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int create_lpt(struct ubifs_info *c)
+{
+       int lnum, err = 0, i, j, cnt, len, alen, row;
+       int blnum, boffs, bsz, bcnt;
+       struct ubifs_pnode *pnode = NULL;
+       struct ubifs_nnode *nnode = NULL;
+       void *buf = NULL, *p;
+       int *lsave = NULL;
+
+       pnode = malloc(sizeof(struct ubifs_pnode));
+       nnode = malloc(sizeof(struct ubifs_nnode));
+       buf = malloc(c->leb_size);
+       lsave = malloc(sizeof(int) * c->lsave_cnt);
+       if (!pnode || !nnode || !buf || !lsave) {
+               err = -ENOMEM;
+               goto out;
+       }
+       memset(pnode, 0 , sizeof(struct ubifs_pnode));
+       memset(nnode, 0 , sizeof(struct ubifs_pnode));
+
+       c->lscan_lnum = c->main_first;
+
+       lnum = c->lpt_first;
+       p = buf;
+       len = 0;
+       /* Number of leaf nodes (pnodes) */
+       cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) >> UBIFS_LPT_FANOUT_SHIFT;
+       //printf("pnode_cnt=%d\n",cnt);
+
+       /*
+        * To calculate the internal node branches, we keep information about
+        * the level below.
+        */
+       blnum = lnum; /* LEB number of level below */
+       boffs = 0; /* Offset of level below */
+       bcnt = cnt; /* Number of nodes in level below */
+       bsz = c->pnode_sz; /* Size of nodes in level below */
+
+       /* Add pnodes */
+       for (i = 0; i < cnt; i++) {
+               if (len + c->pnode_sz > c->leb_size) {
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+                       err = write_leb(lnum++, alen, buf, UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+                       len = 0;
+               }
+               /* Fill in the pnode */
+               for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
+                       int k = (i << UBIFS_LPT_FANOUT_SHIFT) + j;
+
+                       if (k < c->main_lebs)
+                               pnode->lprops[j] = c->lpt[k];
+                       else {
+                               pnode->lprops[j].free = c->leb_size;
+                               pnode->lprops[j].dirty = 0;
+                               pnode->lprops[j].flags = 0;
+                       }
+               }
+               pack_pnode(c, p, pnode);
+               p += c->pnode_sz;
+               len += c->pnode_sz;
+               /*
+                * pnodes are simply numbered left to right starting at zero,
+                * which means the pnode number can be used easily to traverse
+                * down the tree to the corresponding pnode.
+                */
+               pnode->num += 1;
+       }
+
+       row = c->lpt_hght - 1;
+       /* Add all nnodes, one level at a time */
+       while (1) {
+               /* Number of internal nodes (nnodes) at next level */
+               cnt = (cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+               if (cnt == 0)
+                       cnt = 1;
+               for (i = 0; i < cnt; i++) {
+                       if (len + c->nnode_sz > c->leb_size) {
+                               alen = ALIGN(len, c->min_io_size);
+                               set_ltab(c, lnum, c->leb_size - alen,
+                                           alen - len);
+                               memset(p, 0xff, alen - len);
+                               err = write_leb(lnum++, alen, buf, UBI_SHORTTERM);
+                               if (err)
+                                       goto out;
+                               p = buf;
+                               len = 0;
+                       }
+                       /* The root is on row zero */
+                       if (row == 0) {
+                               c->lpt_lnum = lnum;
+                               c->lpt_offs = len;
+                       }
+                       /* Set branches to the level below */
+                       for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
+                               if (bcnt) {
+                                       if (boffs + bsz > c->leb_size) {
+                                               blnum += 1;
+                                               boffs = 0;
+                                       }
+                                       nnode->nbranch[j].lnum = blnum;
+                                       nnode->nbranch[j].offs = boffs;
+                                       boffs += bsz;
+                                       bcnt--;
+                               } else {
+                                       nnode->nbranch[j].lnum = 0;
+                                       nnode->nbranch[j].offs = 0;
+                               }
+                       }
+                       nnode->num = calc_nnode_num(row, i);
+                       pack_nnode(c, p, nnode);
+                       p += c->nnode_sz;
+                       len += c->nnode_sz;
+               }
+               /* Row zero  is the top row */
+               if (row == 0)
+                       break;
+               /* Update the information about the level below */
+               bcnt = cnt;
+               bsz = c->nnode_sz;
+               row -= 1;
+       }
+
+       if (c->big_lpt) {
+               /* Need to add LPT's save table */
+               if (len + c->lsave_sz > c->leb_size) {
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+                       err = write_leb(lnum++, alen, buf, UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+                       len = 0;
+               }
+
+               c->lsave_lnum = lnum;
+               c->lsave_offs = len;
+
+               for (i = 0; i < c->lsave_cnt; i++)
+                       lsave[i] = c->main_first + i;
+
+               pack_lsave(c, p, lsave);
+               p += c->lsave_sz;
+               len += c->lsave_sz;
+       }
+
+       /* Need to add LPT's own LEB properties table */
+       if (len + c->ltab_sz > c->leb_size) {
+               alen = ALIGN(len, c->min_io_size);
+               set_ltab(c, lnum, c->leb_size - alen, alen - len);
+               memset(p, 0xff, alen - len);
+               err = write_leb(lnum++, alen, buf, UBI_SHORTTERM);
+               if (err)
+                       goto out;
+               p = buf;
+               len = 0;
+       }
+
+       c->ltab_lnum = lnum;
+       c->ltab_offs = len;
+
+       /* Update ltab before packing it */
+       len += c->ltab_sz;
+       alen = ALIGN(len, c->min_io_size);
+       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+
+       pack_ltab(c, p, c->ltab);
+       p += c->ltab_sz;
+
+       /* Write remaining buffer */
+       memset(p, 0xff, alen - len);
+       err = write_leb(lnum, alen, buf, UBI_SHORTTERM);
+       if (err)
+               goto out;
+
+       c->nhead_lnum = lnum;
+       c->nhead_offs = ALIGN(len, c->min_io_size);
+
+out:
+       return err;
+}
+
+/**
+ * write_lpt - write the LEB properties tree.
+ */
+static int write_lpt(void)
+{
+       int err, lnum;
+
+       err = create_lpt(c);
+       if (err)
+               return err;
+
+       lnum = c->nhead_lnum + 1;
+       while (lnum <= c->lpt_last) {
+               err = write_empty_leb(lnum++, UBI_SHORTTERM);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+/**
+ * write_orphan_area - write an empty orphan area.
+ */
+static int write_orphan_area(void)
+{
+       int err, i, lnum;
+
+       lnum = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs;
+       for (i = 0; i < c->orph_lebs; i++, lnum++) {
+               err = write_empty_leb(lnum, UBI_SHORTTERM);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+/**
+ * do_calc_lpt_geom - calculate sizes for the LPT area.
+ * @c: the UBIFS file-system description object
+ *
+ * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
+ * properties of the flash and whether LPT is "big" (c->big_lpt).
+ */
+static void do_calc_lpt_geom(struct ubifs_info *c)
+{
+       int n, bits, per_leb_wastage;
+       long long sz, tot_wastage;
+
+       c->pnode_cnt = (c->main_lebs + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+
+       n = (c->pnode_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+       c->nnode_cnt = n;
+       while (n > 1) {
+               n = (n + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+               c->nnode_cnt += n;
+       }
+
+       c->lpt_hght = 1;
+       n = UBIFS_LPT_FANOUT;
+       while (n < c->pnode_cnt) {
+               c->lpt_hght += 1;
+               n <<= UBIFS_LPT_FANOUT_SHIFT;
+       }
+
+       c->space_bits = fls(c->leb_size) - 3;
+       c->lpt_lnum_bits = fls(c->lpt_lebs);
+       c->lpt_offs_bits = fls(c->leb_size - 1);
+       c->lpt_spc_bits = fls(c->leb_size);
+
+       n = (c->max_leb_cnt + UBIFS_LPT_FANOUT - 1) / UBIFS_LPT_FANOUT;
+       c->pcnt_bits = fls(n - 1);
+
+       c->lnum_bits = fls(c->max_leb_cnt - 1);
+
+       bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+              (c->big_lpt ? c->pcnt_bits : 0) +
+              (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
+       c->pnode_sz = (bits + 7) / 8;
+
+       bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+              (c->big_lpt ? c->pcnt_bits : 0) +
+              (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
+       c->nnode_sz = (bits + 7) / 8;
+
+       bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+              c->lpt_lebs * c->lpt_spc_bits * 2;
+       c->ltab_sz = (bits + 7) / 8;
+
+       bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
+              c->lnum_bits * c->lsave_cnt;
+       c->lsave_sz = (bits + 7) / 8;
+
+       /* Calculate the minimum LPT size */
+       c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
+       c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
+       c->lpt_sz += c->ltab_sz;
+       c->lpt_sz += c->lsave_sz;
+
+       /* Add wastage */
+       sz = c->lpt_sz;
+       per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
+       sz += per_leb_wastage;
+       tot_wastage = per_leb_wastage;
+       while (sz > c->leb_size) {
+               sz += per_leb_wastage;
+               sz -= c->leb_size;
+               tot_wastage += per_leb_wastage;
+       }
+       tot_wastage += ALIGN(sz, c->min_io_size) - sz;
+       c->lpt_sz += tot_wastage;
+}
+
+/**
+ * calc_dflt_lpt_geom - calculate default LPT geometry.
+ * @c: the UBIFS file-system description object
+ * @main_lebs: number of main area LEBs is passed and returned here
+ * @big_lpt: whether the LPT area is "big" is returned here
+ *
+ * The size of the LPT area depends on parameters that themselves are dependent
+ * on the size of the LPT area. This function, successively recalculates the LPT
+ * area geometry until the parameters and resultant geometry are consistent.
+ *
+ * This function returns %0 on success and a negative error code on failure.
+ */
+int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt)
+{
+       int i, lebs_needed;
+       uint64_t sz;
+
+       /* Start by assuming the minimum number of LPT LEBs */
+       c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
+       c->main_lebs = *main_lebs - c->lpt_lebs;
+       if (c->main_lebs <= 0)
+               return -EINVAL;
+
+       /* And assume we will use the small LPT model */
+       c->big_lpt = 0;
+
+       /*
+        * Calculate the geometry based on assumptions above and then see if it
+        * makes sense
+        */
+       do_calc_lpt_geom(c);
+
+       /* Small LPT model must have lpt_sz < leb_size */
+       if (c->lpt_sz > c->leb_size) {
+               /* Nope, so try again using big LPT model */
+               c->big_lpt = 1;
+               do_calc_lpt_geom(c);
+       }
+
+       /* Now check there are enough LPT LEBs */
+       for (i = 0; i < 64 ; i++) {
+               sz = c->lpt_sz * 4; /* Allow 4 times the size */
+               sz += c->leb_size - 1;
+               do_div(sz, c->leb_size);
+               lebs_needed = sz;
+               if (lebs_needed > c->lpt_lebs) {
+                       /* Not enough LPT LEBs so try again with more */
+                       c->lpt_lebs = lebs_needed;
+                       c->main_lebs = *main_lebs - c->lpt_lebs;
+                       if (c->main_lebs <= 0)
+                               return -EINVAL;
+                       do_calc_lpt_geom(c);
+                       continue;
+               }
+               if (c->ltab_sz > c->leb_size) {
+                       err_msg("LPT ltab too big");
+                       return -EINVAL;
+               }
+               *main_lebs = c->main_lebs;
+               *big_lpt = c->big_lpt;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+int init_compression(void)
+{
+       lzo_mem = malloc(LZO1X_MEM_COMPRESS);
+       if (!lzo_mem)
+               return -1;
+
+       return 0;
+}
+
+/**
+ * init - initialize things.
+ */
+static int init(void)
+{
+       int err, i, main_lebs, big_lpt = 0;
+
+       c->highest_inum = UBIFS_FIRST_INO;
+
+       c->jhead_cnt = 1;
+
+       main_lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
+       main_lebs -= c->log_lebs + c->orph_lebs;
+
+       err = calc_dflt_lpt_geom(c, &main_lebs, &big_lpt);
+       if (err)
+               return err;
+
+       c->main_first = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs +
+                       c->orph_lebs;
+       head_lnum = c->main_first;
+       head_offs = 0;
+
+       c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs;
+       c->lpt_last = c->lpt_first + c->lpt_lebs - 1;
+
+       c->lpt = malloc(c->main_lebs * sizeof(struct ubifs_lprops));
+       if (!c->lpt)
+               return err_msg("unable to allocate LPT");
+
+       c->ltab = malloc(c->lpt_lebs * sizeof(struct ubifs_lprops));
+       if (!c->ltab)
+               return err_msg("unable to allocate LPT ltab");
+
+       /* Initialize LPT's own lprops */
+       for (i = 0; i < c->lpt_lebs; i++) {
+               c->ltab[i].free = c->leb_size;
+               c->ltab[i].dirty = 0;
+       }
+
+       c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size);
+       c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size);
+       dbg_msg("dead_wm %d  dark_wm %d", c->dead_wm, c->dark_wm);
+
+       leb_buf = malloc(c->leb_size);
+       if (!leb_buf)
+               return err_msg("out of memory");
+
+       node_buf = malloc(NODE_BUFFER_SIZE);
+       if (!node_buf)
+               return err_msg("out of memory");
+
+       block_buf = malloc(UBIFS_BLOCK_SIZE);
+       if (!block_buf)
+               return err_msg("out of memory");
+
+       err = init_compression();
+       if (err)
+               return err;
+
+       modem_buf = malloc(MODEM_IMAGE_SIZE);
+       if (!modem_buf)
+               return err_msg("out of memory");
+
+       return 0;
+}
+
+/**
+ * deinit - deinitialize things.
+ */
+static void deinit(void)
+{
+       free(c->lpt);
+       free(c->ltab);
+       free(leb_buf);
+       free(node_buf);
+       free(block_buf);
+       free(lzo_mem);
+}
+
+/**
+ * mkfs - make the file system.
+ *
+ * Each on-flash area has a corresponding function to create it. The order of
+ * the functions reflects what information must be known to complete each stage.
+ * As a consequence the output file is not written sequentially. No effort has
+ * been made to make efficient use of memory or to allow for the possibility of
+ * incremental updates to the output file.
+ */
+int mkfs(void *src_addr, unsigned long src_size,
+        void **dest_addr, unsigned long *dest_size,
+        int min_io_size, int leb_size, int max_leb_cnt)
+{
+       int err = 0;
+       ino_t inum;
+       ino_t dir_inum = UBIFS_ROOT_INO;
+       unsigned char type = UBIFS_ITYPE_REG;
+       char *name = "modem.bin";
+       unsigned long root_dir_size = UBIFS_INO_NODE_SZ;
+
+       err = set_options(min_io_size, leb_size, max_leb_cnt);
+       if (err)
+               return err;
+
+       err = init();
+       if (err)
+               goto out;
+
+       c->highest_inum++;
+       inum = c->highest_inum;
+       creat_sqnum = c->max_sqnum++;
+
+       err = add_data_node(src_size, src_addr, inum);
+       if (err)
+               goto out;
+
+       err = add_inode(src_size, inum);
+       if (err)
+               goto out;
+
+       err = add_dent_node(dir_inum, name, inum, type);
+       if (err)
+               goto out;
+
+       root_dir_size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(name) + 1, 8);
+
+       err = add_inode(root_dir_size, dir_inum);
+       if (err)
+               goto out;
+
+       err = flush_nodes();
+       if (err)
+               goto out;
+
+       err = set_gc_lnum();
+       if (err)
+               goto out;
+
+       err = write_index();
+       if (err)
+               goto out;
+
+       err = finalize_leb_cnt();
+       if (err)
+               goto out;
+
+       err = write_lpt();
+       if (err)
+               goto out;
+
+       err = write_super();
+       if (err)
+               goto out;
+
+       err = write_master();
+       if (err)
+               goto out;
+
+       err = write_log();
+       if (err)
+               goto out;
+
+       err = write_orphan_area();
+
+       *dest_addr = modem_buf;
+       *dest_size = (unsigned long) c->leb_cnt * c->leb_size;
+
+       printf("ubifs image offset : 0x%x\n", (unsigned int) dest_addr);
+       printf("ubifs image size : 0x%lx\n", *dest_size);
+
+out:
+       deinit();
+       return err;
+}
diff --git a/fs/ubifs/mkfs.ubifs.h b/fs/ubifs/mkfs.ubifs.h
new file mode 100644 (file)
index 0000000..9354050
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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: Artem Bityutskiy
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+#ifndef __MKFS_UBIFS_H__
+#define __MKFS_UBIFS_H__
+
+#define _GNU_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <linux/types.h>
+#include <linux/lzo.h>
+#include <malloc.h>
+#include "crc32.h"
+#include "ubifs_qsort.h"
+#include "crc16.h"
+#include "ubifs.h"
+
+#define err_msg(fmt, ...) ({                                \
+       fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__); \
+       -1;                                                 \
+})
+
+#define sys_err_msg(fmt, ...) ({                                         \
+       int err_ = errno;                                                \
+       fprintf(stderr, "Error: " fmt "\n", ##__VA_ARGS__);              \
+       fprintf(stderr, "       %s (error %d)\n", strerror(err_), err_); \
+       -1;                                                              \
+})
+
+#endif
index 0af471a..bc5356f 100644 (file)
@@ -1784,6 +1784,7 @@ struct ubifs_info {
 
        int ltab_lnum;
        int ltab_offs;
+       struct ubifs_lprops *lpt;
        struct ubifs_lpt_lprops *ltab;
        struct ubifs_lpt_lprops *ltab_cmt;
        int lsave_cnt;
diff --git a/fs/ubifs/ubifs_qsort.c b/fs/ubifs/ubifs_qsort.c
new file mode 100644 (file)
index 0000000..2f76ca3
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* XXX U-BOOT XXX */
+#include <common.h>
+
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) {              \
+       long i = (n) / sizeof (TYPE);                   \
+       register TYPE *pi = (TYPE *) (parmi);           \
+       register TYPE *pj = (TYPE *) (parmj);           \
+       do {                                            \
+               register TYPE   t = *pi;                \
+               *pi++ = *pj;                            \
+               *pj++ = t;                              \
+       } while (--i > 0);                              \
+}
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+       es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
+
+static __inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+       if (swaptype <= 1)
+               swapcode(long, a, b, n)
+       else
+               swapcode(char, a, b, n)
+}
+
+#define swap(a, b)                                     \
+       if (swaptype == 0) {                            \
+               long t = *(long *)(a);                  \
+               *(long *)(a) = *(long *)(b);            \
+               *(long *)(b) = t;                       \
+       } else                                          \
+               swapfunc(a, b, es, swaptype)
+
+#define vecswap(a, b, n)       if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static __inline char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+       return cmp(a, b) < 0 ?
+              (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
+             :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
+}
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+void
+ubifs_qsort(void *aa, size_t n, size_t es,
+       int (*cmp)(const void *, const void *))
+{
+       char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+       int d, r, swaptype, swap_cnt;
+       register char *a = aa;
+
+loop:  SWAPINIT(a, es);
+       swap_cnt = 0;
+       if (n < 7) {
+               for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+                       for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+                            pl -= es)
+                               swap(pl, pl - es);
+               return;
+       }
+       pm = (char *)a + (n / 2) * es;
+       if (n > 7) {
+               pl = (char *)a;
+               pn = (char *)a + (n - 1) * es;
+               if (n > 40) {
+                       d = (n / 8) * es;
+                       pl = med3(pl, pl + d, pl + 2 * d, cmp);
+                       pm = med3(pm - d, pm, pm + d, cmp);
+                       pn = med3(pn - 2 * d, pn - d, pn, cmp);
+               }
+               pm = med3(pl, pm, pn, cmp);
+       }
+       swap(a, pm);
+       pa = pb = (char *)a + es;
+
+       pc = pd = (char *)a + (n - 1) * es;
+       for (;;) {
+               while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+                       if (r == 0) {
+                               swap_cnt = 1;
+                               swap(pa, pb);
+                               pa += es;
+                       }
+                       pb += es;
+               }
+               while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+                       if (r == 0) {
+                               swap_cnt = 1;
+                               swap(pc, pd);
+                               pd -= es;
+                       }
+                       pc -= es;
+               }
+               if (pb > pc)
+                       break;
+               swap(pb, pc);
+               swap_cnt = 1;
+               pb += es;
+               pc -= es;
+       }
+       if (swap_cnt == 0) {  /* Switch to insertion sort */
+               for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+                       for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+                            pl -= es)
+                               swap(pl, pl - es);
+               return;
+       }
+
+       pn = (char *)a + n * es;
+       r = min(pa - (char *)a, pb - pa);
+       vecswap(a, pb - r, r);
+       r = min((long)(pd - pc), (long)(pn - pd - es));
+       vecswap(pb, pn - r, r);
+       if ((r = pb - pa) > es)
+               ubifs_qsort(a, r / es, es, cmp);
+       if ((r = pd - pc) > es) {
+               /* Iterate rather than recurse to save stack space */
+               a = pn - r;
+               n = r / es;
+               goto loop;
+       }
+/*             ubifs_qsort(pn - r, r / es, es, cmp);*/
+}
diff --git a/fs/ubifs/ubifs_qsort.h b/fs/ubifs/ubifs_qsort.h
new file mode 100644 (file)
index 0000000..4c68af1
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __UBIFS_QSORT_H__
+#define __UBIFS_QSORT_H__
+
+extern void ubifs_qsort (void *const base, size_t total_elems, size_t size,
+                  int (*cmp)(const void *, const void *));
+
+#endif
diff --git a/include/mkfs.ubifs.h b/include/mkfs.ubifs.h
new file mode 100644 (file)
index 0000000..a4d10c3
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __MKFS_UBIFS_FUNC_H__
+#define __MKFS_UBIFS_FUNC_H__
+
+extern int mkfs(void *src_addr, unsigned long src_size,
+               void **dest_addr, unsigned long *dest_size,
+               int min_io_size, int leb_size, int max_leb_cnt);
+#endif