summaryrefslogtreecommitdiff
path: root/ubi-utils/src/libubigen.c
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils/src/libubigen.c')
-rw-r--r--ubi-utils/src/libubigen.c660
1 files changed, 413 insertions, 247 deletions
diff --git a/ubi-utils/src/libubigen.c b/ubi-utils/src/libubigen.c
index 8d71fde..1fce3f9 100644
--- a/ubi-utils/src/libubigen.c
+++ b/ubi-utils/src/libubigen.c
@@ -1,6 +1,5 @@
/*
* Copyright (c) International Business Machines Corp., 2006
- * Copyright (C) 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 as published by
@@ -15,307 +14,474 @@
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * Generating UBI images.
*
- * Authors: Oliver Lohmann
- * Artem Bityutskiy
+ * Author: Oliver Lohmann
+ *
+ * Add UBI headers to binary data.
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
-#include <unistd.h>
+#include <errno.h>
#include <string.h>
-
#include <mtd/ubi-header.h>
-#include <libubigen.h>
+#include <mtd_swab.h>
+
+#include "config.h"
+#include "ubigen.h"
#include "crc32.h"
-#include "common.h"
-
-#define PROGRAM_NAME "libubigen"
-
-/**
- * ubigen_info_init - initialize libubigen.
- * @ui: libubigen information
- * @peb_size: flash physical eraseblock size
- * @min_io_size: flash minimum input/output unit size
- * @subpage_size: flash sub-page, if present (has to be equivalent to
- * @min_io_size if does not exist)
- * @vid_hdr_offs: offset of the VID header
- * @ubi_ver: UBI version
- * @ec: initial erase counter
- */
-void ubigen_info_init(struct ubigen_info *ui, int peb_size, int min_io_size,
- int subpage_size, int vid_hdr_offs, int ubi_ver,
- long long ec)
+
+#define UBI_NAME_SIZE 256
+#define DEFAULT_VID_OFFSET ((DEFAULT_PAGESIZE) - (UBI_VID_HDR_SIZE))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+static uint32_t crc32_table[256];
+
+struct ubi_info {
+ struct ubi_vid_hdr* v; /* Volume ID header */
+ struct ubi_ec_hdr* ec; /* Erase count header */
+
+ FILE* fp_in; /* Input Stream */
+ FILE* fp_out; /* Output stream */
+
+ size_t eb_size; /* Physical EB size in bytes */
+ size_t leb_size; /* Size of a logical EB in a physical EB */
+ size_t leb_total; /* Total input size in logical EB */
+ size_t alignment; /* Block alignment */
+ size_t data_pad; /* Size of padding in each physical EB */
+
+ size_t bytes_total; /* Total input size in bytes */
+ size_t bytes_read; /* Nymber of read bytes (total) */
+
+ uint32_t blks_written; /* Number of written logical EB */
+
+ uint8_t* buf; /* Allocated buffer */
+ uint8_t* ptr_ec_hdr; /* Pointer to EC hdr in buf */
+ uint8_t* ptr_vid_hdr; /* Pointer to VID hdr in buf */
+ uint8_t* ptr_data; /* Pointer to data region in buf */
+};
+
+
+static uint32_t
+byte_to_blk(uint64_t byte, uint32_t eb_size)
{
- if (!vid_hdr_offs)
- vid_hdr_offs = subpage_size;
-
- ui->peb_size = peb_size;
- ui->min_io_size = min_io_size;
- ui->vid_hdr_offs = vid_hdr_offs;
- ui->data_offs = vid_hdr_offs + UBI_VID_HDR_SIZE + min_io_size - 1;
- ui->data_offs /= min_io_size;
- ui->data_offs *= min_io_size;
- ui->leb_size = peb_size - ui->data_offs;
- ui->ubi_ver = ubi_ver;
- ui->ec = ec;
-
- ui->vtbl_size = ui->leb_size;
- if (ui->vtbl_size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE)
- ui->vtbl_size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
- ui->max_volumes = ui->vtbl_size / UBI_VTBL_RECORD_SIZE;
+ return (byte % eb_size) == 0
+ ? (byte / eb_size)
+ : (byte / eb_size) + 1;
}
-/**
- * ubigen_create_empty_vtbl - creates empty volume table.
- *
- * This function creates an empty volume table and returns a pointer to it in
- * case of success and %NULL in case of failure. The returned object has to be
- * freed with 'free()' call.
- */
-struct ubi_vtbl_record *ubigen_create_empty_vtbl(const struct ubigen_info *ui)
+static int
+validate_ubi_info(ubi_info_t u)
{
- struct ubi_vtbl_record *vtbl;
- int i;
-
- vtbl = calloc(1, ui->vtbl_size);
- if (!vtbl) {
- errmsg("cannot allocate %d bytes of memory", ui->vtbl_size);
- return NULL;
+ if ((u->v->vol_type != UBI_VID_DYNAMIC) &&
+ (u->v->vol_type != UBI_VID_STATIC)) {
+ return EUBIGEN_INVALID_TYPE;
}
- for (i = 0; i < UBI_MAX_VOLUMES; i++) {
- uint32_t crc = crc32(UBI_CRC32_INIT, &vtbl[i],
- UBI_VTBL_RECORD_SIZE_CRC);
- vtbl[i].crc = cpu_to_be32(crc);
+ if (be32_to_cpu(u->ec->vid_hdr_offset) < UBI_VID_HDR_SIZE) {
+ return EUBIGEN_INVALID_HDR_OFFSET;
}
- return vtbl;
+ return 0;
}
-/**
- * ubigen_add_volume - add a volume to the volume table.
- * @ui: libubigen information
- * @vi: volume information
- * @vtbl: volume table to add to
- *
- * This function adds volume described by input parameters to the volume table
- * @vtbl.
- */
-int ubigen_add_volume(const struct ubigen_info *ui,
- const struct ubigen_vol_info *vi,
- struct ubi_vtbl_record *vtbl)
+static int
+skip_blks(ubi_info_t u, uint32_t blks)
{
- struct ubi_vtbl_record *vtbl_rec = &vtbl[vi->id];
- uint32_t tmp;
-
- if (vi->id >= ui->max_volumes)
- return errmsg("too high volume id %d, max. volumes is %d",
- vi->id, ui->max_volumes);
-
- if (vi->alignment >= ui->leb_size)
- return errmsg("too large alignment %d, max is %d (LEB size)",
- vi->alignment, ui->leb_size);
-
- memset(vtbl_rec, '\0', sizeof(struct ubi_vtbl_record));
- tmp = (vi->bytes + ui->leb_size - 1) / ui->leb_size;
- vtbl_rec->reserved_pebs = cpu_to_be32(tmp);
- vtbl_rec->alignment = cpu_to_be32(vi->alignment);
- vtbl_rec->vol_type = vi->type;
- tmp = ui->leb_size % vi->alignment;
- vtbl_rec->data_pad = cpu_to_be32(tmp);
- vtbl_rec->flags = vi->flags;
-
- memcpy(vtbl_rec->name, vi->name, vi->name_len);
- vtbl_rec->name[vi->name_len] = '\0';
- vtbl_rec->name_len = cpu_to_be16(vi->name_len);
-
- tmp = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
- vtbl_rec->crc = cpu_to_be32(tmp);
+ uint32_t i;
+ size_t read = 0, to_read = 0;
+
+ /* Step to a maximum of leb_total - 1 to keep the
+ restrictions. */
+ for (i = 0; i < MIN(blks, u->leb_total-1); i++) {
+ /* Read in data */
+ to_read = MIN(u->leb_size,
+ (u->bytes_total - u->bytes_read));
+ read = fread(u->ptr_data, 1, to_read, u->fp_in);
+ if (read != to_read) {
+ return -EIO;
+ }
+ u->bytes_read += read;
+ u->blks_written++;
+ }
+
return 0;
}
-/**
- * init_ec_hdr - initialize EC header.
- * @ui: libubigen information
- * @hdr: the EC header to initialize
- */
-static void init_ec_hdr(const struct ubigen_info *ui,
- struct ubi_ec_hdr *hdr)
+static void
+clear_buf(ubi_info_t u)
{
- uint32_t crc;
+ memset(u->buf, 0xff, u->eb_size);
+}
- memset(hdr, '\0', sizeof(struct ubi_ec_hdr));
+static void
+write_ec_hdr(ubi_info_t u)
+{
+ memcpy(u->ptr_ec_hdr, u->ec, UBI_EC_HDR_SIZE);
+}
- hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
- hdr->version = ui->ubi_ver;
- hdr->ec = cpu_to_be64(ui->ec);
- hdr->vid_hdr_offset = cpu_to_be32(ui->vid_hdr_offs);
+static int
+fill_data_buffer_from_file(ubi_info_t u, size_t* read)
+{
+ size_t to_read = 0;
- hdr->data_offset = cpu_to_be32(ui->data_offs);
+ if (u-> fp_in == NULL)
+ return -EIO;
- crc = crc32(UBI_CRC32_INIT, hdr, UBI_EC_HDR_SIZE_CRC);
- hdr->hdr_crc = cpu_to_be32(crc);
+ to_read = MIN(u->leb_size, (u->bytes_total - u->bytes_read));
+ *read = fread(u->ptr_data, 1, to_read, u->fp_in);
+ if (*read != to_read) {
+ return -EIO;
+ }
+ return 0;
}
-/**
- * init_vid_hdr - initialize VID header.
- * @ui: libubigen information
- * @vi: volume information
- * @hdr: the VID header to initialize
- * @lnum: logical eraseblock number
- * @data: the contents of the LEB (static volumes only)
- * @data_size: amount of data in this LEB (static volumes only)
- *
- * Note, @used_ebs, @data and @data_size are ignored in case of dynamic
- * volumes.
- */
-static void init_vid_hdr(const struct ubigen_info *ui,
- const struct ubigen_vol_info *vi,
- struct ubi_vid_hdr *hdr, int lnum,
- const void *data, int data_size)
+static void
+add_static_info(ubi_info_t u, size_t data_size, ubigen_action_t action)
{
- uint32_t crc;
+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+ u->ptr_data, data_size);
- memset(hdr, '\0', sizeof(struct ubi_vid_hdr));
-
- hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
- hdr->version = ui->ubi_ver;
- hdr->vol_type = vi->type;
- hdr->vol_id = cpu_to_be32(vi->id);
- hdr->lnum = cpu_to_be32(lnum);
- hdr->data_pad = cpu_to_be32(vi->data_pad);
- hdr->compat = vi->compat;
-
- if (vi->type == UBI_VID_STATIC) {
- hdr->data_size = cpu_to_be32(data_size);
- hdr->used_ebs = cpu_to_be32(vi->used_ebs);
- crc = crc32(UBI_CRC32_INIT, data, data_size);
- hdr->data_crc = cpu_to_be32(crc);
+ u->v->data_size = cpu_to_be32(data_size);
+ u->v->data_crc = cpu_to_be32(crc);
+
+ if (action & BROKEN_DATA_CRC) {
+ u->v->data_crc =
+ cpu_to_be32(be32_to_cpu(u->v->data_crc) + 1);
+ }
+ if (action & BROKEN_DATA_SIZE) {
+ u->v->data_size =
+ cpu_to_be32(be32_to_cpu(u->v->data_size) + 1);
}
+}
- crc = crc32(UBI_CRC32_INIT, hdr, UBI_VID_HDR_SIZE_CRC);
- hdr->hdr_crc = cpu_to_be32(crc);
+static void
+write_vid_hdr(ubi_info_t u, ubigen_action_t action)
+{
+ uint32_t crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+ u->v, UBI_VID_HDR_SIZE_CRC);
+ /* Write VID header */
+ u->v->hdr_crc = cpu_to_be32(crc);
+ if (action & BROKEN_HDR_CRC) {
+ u->v->hdr_crc = cpu_to_be32(be32_to_cpu(u->v->hdr_crc) + 1);
+ }
+ memcpy(u->ptr_vid_hdr, u->v, UBI_VID_HDR_SIZE);
}
-/**
- * ubigen_write_volume - write UBI volume.
- * @ui: libubigen information
- * @vi: volume information
- * @bytes: volume size in bytes
- * @in: input file descriptor (has to be properly seeked)
- * @out: output file descriptor
- *
- * This function reads the contents of the volume from the input file @in and
- * writes the UBI volume to the output file @out. Returns zero on success and
- * %-1 on failure.
- */
-int ubigen_write_volume(const struct ubigen_info *ui,
- const struct ubigen_vol_info *vi,
- long long bytes, FILE *in, FILE *out)
+static int
+write_to_output_stream(ubi_info_t u)
{
- int len = vi->usable_leb_size, rd, lnum = 0;
- char inbuf[ui->leb_size], outbuf[ui->peb_size];
+ size_t written;
- if (vi->id >= ui->max_volumes)
- return errmsg("too high volume id %d, max. volumes is %d",
- vi->id, ui->max_volumes);
+ written = fwrite(u->buf, 1, u->eb_size, u->fp_out);
+ if (written != u->eb_size) {
+ return -EIO;
+ }
+ return 0;
+}
- if (vi->alignment >= ui->leb_size)
- return errmsg("too large alignment %d, max is %d (LEB size)",
- vi->alignment, ui->leb_size);
+int
+ubigen_write_leb(ubi_info_t u, ubigen_action_t action)
+{
+ int rc = 0;
+ size_t read = 0;
- memset(outbuf, 0xFF, ui->data_offs);
- init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf);
+ clear_buf(u);
+ write_ec_hdr(u);
- while (bytes) {
- int l;
- struct ubi_vid_hdr *vid_hdr;
+ rc = fill_data_buffer_from_file(u, &read);
+ if (rc != 0)
+ return rc;
- if (bytes < len)
- len = bytes;
- bytes -= len;
+ if (u->v->vol_type == UBI_VID_STATIC) {
+ add_static_info(u, read, action);
+ }
- l = len;
- do {
- rd = fread(inbuf + len - l, 1, l, in);
- if (rd == 0) {
- if (ferror(in))
- return errmsg("cannot read %d bytes from the input file", l);
- else
- return errmsg("not enough data in the input file");
- }
+ u->v->lnum = cpu_to_be32(u->blks_written);
- l -= rd;
- } while (l);
+ if (action & MARK_AS_UPDATE) {
+ u->v->copy_flag = (u->v->copy_flag)++;
+ }
- vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
- init_vid_hdr(ui, vi, vid_hdr, lnum, inbuf, len);
+ write_vid_hdr(u, action);
+ rc = write_to_output_stream(u);
+ if (rc != 0)
+ return rc;
- memcpy(outbuf + ui->data_offs, inbuf, len);
- memset(outbuf + ui->data_offs + len, 0xFF,
- ui->peb_size - ui->data_offs - len);
+ /* Update current handle */
+ u->bytes_read += read;
+ u->blks_written++;
+ return 0;
+}
- if (fwrite(outbuf, 1, ui->peb_size, out) != ui->peb_size)
- return errmsg("cannot write %d bytes from the output file", l);
+int
+ubigen_write_complete(ubi_info_t u)
+{
+ size_t i;
+ int rc = 0;
- lnum += 1;
+ for (i = 0; i < u->leb_total; i++) {
+ rc = ubigen_write_leb(u, NO_ERROR);
+ if (rc != 0)
+ return rc;
}
return 0;
}
-/**
- * ubigen_write_layout_vol - write UBI layout volume
- * @ui: libubigen information
- * @vtbl: volume table
- * @out: output file stream
- *
- * This function creates the UBI layout volume which contains 2 copies of the
- * volume table. Returns zero in case of success and %-1 in case of failure.
- */
-int ubigen_write_layout_vol(const struct ubigen_info *ui,
- struct ubi_vtbl_record *vtbl, FILE *out)
+int
+ubigen_write_broken_update(ubi_info_t u, uint32_t blk)
{
- int size = ui->leb_size;
- struct ubigen_vol_info vi;
- char outbuf[ui->peb_size];
- struct ubi_vid_hdr *vid_hdr;
-
- if (size > UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE)
- size = UBI_MAX_VOLUMES * UBI_VTBL_RECORD_SIZE;
-
- vi.bytes = ui->leb_size * UBI_LAYOUT_VOLUME_EBS;
- vi.id = UBI_LAYOUT_VOLUME_ID;
- vi.alignment = UBI_LAYOUT_VOLUME_ALIGN;
- vi.data_pad = ui->leb_size % UBI_LAYOUT_VOLUME_ALIGN;
- vi.usable_leb_size = ui->leb_size - vi.data_pad;
- vi.data_pad = ui->leb_size - vi.usable_leb_size;
- vi.type = UBI_LAYOUT_VOLUME_TYPE;
- vi.name = UBI_LAYOUT_VOLUME_NAME;
- vi.name_len = strlen(UBI_LAYOUT_VOLUME_NAME);
- vi.compat = UBI_LAYOUT_VOLUME_COMPAT;
-
- memset(outbuf, 0xFF, ui->data_offs);
- vid_hdr = (struct ubi_vid_hdr *)(&outbuf[ui->vid_hdr_offs]);
- init_ec_hdr(ui, (struct ubi_ec_hdr *)outbuf);
- memcpy(outbuf + ui->data_offs, vtbl, size);
- memset(outbuf + ui->data_offs + size, 0xFF,
- ui->peb_size - ui->data_offs - size);
-
- init_vid_hdr(ui, &vi, vid_hdr, 0, NULL, 0);
- size = fwrite(outbuf, 1, ui->peb_size, out);
- if (size == ui->peb_size) {
- init_vid_hdr(ui, &vi, vid_hdr, 1, NULL, 0);
- size = fwrite(outbuf, 1, ui->peb_size, out);
- if (size != ui->peb_size)
- return sys_errmsg("cannot write %d bytes", ui->peb_size);
+ int rc = 0;
+
+ rc = skip_blks(u, blk);
+ if (rc != 0)
+ return rc;
+
+ rc = ubigen_write_leb(u, MARK_AS_UPDATE | BROKEN_DATA_CRC);
+ if (rc != 0)
+ return rc;
+
+
+ return 0;
+}
+
+void
+dump_info(ubi_info_t u ubi_unused)
+{
+#ifdef DEBUG
+ int err = 0;
+ if (!u) {
+ fprintf(stderr, "<empty>");
+ return;
+ }
+ if (!u->ec) {
+ fprintf(stderr, "<ec-empty>");
+ err = 1;
+ }
+ if (!u->v) {
+ fprintf(stderr, "<v-empty>");
+ err = 1;
+ }
+ if (err) return;
+
+ fprintf(stderr, "ubi volume\n");
+ fprintf(stderr, "version : %8d\n", u->v->version);
+ fprintf(stderr, "vol_id : %8d\n", be32_to_cpu(u->v->vol_id));
+ fprintf(stderr, "vol_type : %8s\n",
+ u->v->vol_type == UBI_VID_STATIC ?
+ "static" : "dynamic");
+ fprintf(stderr, "used_ebs : %8d\n",
+ be32_to_cpu(u->v->used_ebs));
+ fprintf(stderr, "eb_size : 0x%08x\n", u->eb_size);
+ fprintf(stderr, "leb_size : 0x%08x\n", u->leb_size);
+ fprintf(stderr, "data_pad : 0x%08x\n",
+ be32_to_cpu(u->v->data_pad));
+ fprintf(stderr, "leb_total : %8d\n", u->leb_total);
+ fprintf(stderr, "header offs : 0x%08x\n",
+ be32_to_cpu(u->ec->vid_hdr_offset));
+ fprintf(stderr, "bytes_total : %8d\n", u->bytes_total);
+ fprintf(stderr, " + in MiB : %8.2f M\n",
+ ((float)(u->bytes_total)) / 1024 / 1024);
+ fprintf(stderr, "-------------------------------\n\n");
+#else
+ return;
+#endif
+}
+
+int
+ubigen_destroy(ubi_info_t *u)
+{
+ if (u == NULL)
+ return -EINVAL;
+
+ ubi_info_t tmp = *u;
+
+ if (tmp) {
+ if (tmp->v)
+ free(tmp->v);
+ if (tmp->ec)
+ free(tmp->ec);
+ if (tmp->buf)
+ free(tmp->buf);
+ free(tmp);
+ }
+ *u = NULL;
+ return 0;
+}
+
+void
+ubigen_init(void)
+{
+ init_crc32_table(crc32_table);
+}
+
+int
+ubigen_create(ubi_info_t* u, uint32_t vol_id, uint8_t vol_type,
+ uint32_t eb_size, uint64_t ec, uint32_t alignment,
+ uint8_t version, uint32_t vid_hdr_offset, uint8_t compat_flag,
+ size_t data_size, FILE* fp_in, FILE* fp_out)
+{
+ int rc = 0;
+ ubi_info_t res = NULL;
+ uint32_t crc;
+ uint32_t data_offset;
+
+ if (alignment == 0) {
+ rc = EUBIGEN_INVALID_ALIGNMENT;
+ goto ubigen_create_err;
+ }
+ if ((fp_in == NULL) || (fp_out == NULL)) {
+ rc = -EINVAL;
+ goto ubigen_create_err;
+ }
+
+ res = (ubi_info_t) calloc(1, sizeof(struct ubi_info));
+ if (res == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
+ }
+
+ res->v = (struct ubi_vid_hdr*) calloc(1, sizeof(struct ubi_vid_hdr));
+ if (res->v == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
}
+ res->ec = (struct ubi_ec_hdr*) calloc(1, sizeof(struct ubi_ec_hdr));
+ if (res->ec == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
+ }
+
+ /* data which is needed in the general process */
+ vid_hdr_offset = vid_hdr_offset ? vid_hdr_offset : DEFAULT_VID_OFFSET;
+ data_offset = vid_hdr_offset + UBI_VID_HDR_SIZE;
+ res->bytes_total = data_size;
+ res->eb_size = eb_size ? eb_size : DEFAULT_BLOCKSIZE;
+ res->data_pad = (res->eb_size - data_offset) % alignment;
+ res->leb_size = res->eb_size - data_offset - res->data_pad;
+ res->leb_total = byte_to_blk(data_size, res->leb_size);
+ res->alignment = alignment;
+
+ if ((res->eb_size < (vid_hdr_offset + UBI_VID_HDR_SIZE))) {
+ rc = EUBIGEN_TOO_SMALL_EB;
+ goto ubigen_create_err;
+ }
+ res->fp_in = fp_in;
+ res->fp_out = fp_out;
+
+ /* vid hdr data which doesn't change */
+ res->v->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
+ res->v->version = version ? version : UBI_VERSION;
+ res->v->vol_type = vol_type;
+ res->v->vol_id = cpu_to_be32(vol_id);
+ res->v->compat = compat_flag;
+ res->v->data_pad = cpu_to_be32(res->data_pad);
+
+ /* static only: used_ebs */
+ if (res->v->vol_type == UBI_VID_STATIC) {
+ res->v->used_ebs = cpu_to_be32(byte_to_blk
+ (res->bytes_total,
+ res->leb_size));
+ }
+
+ /* ec hdr (fixed, doesn't change) */
+ res->ec->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
+ res->ec->version = version ? version : UBI_VERSION;
+ res->ec->ec = cpu_to_be64(ec);
+ res->ec->vid_hdr_offset = cpu_to_be32(vid_hdr_offset);
+
+ res->ec->data_offset = cpu_to_be32(data_offset);
+
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT, res->ec,
+ UBI_EC_HDR_SIZE_CRC);
+ res->ec->hdr_crc = cpu_to_be32(crc);
+
+ /* prepare a read buffer */
+ res->buf = (uint8_t*) malloc (res->eb_size * sizeof(uint8_t));
+ if (res->buf == NULL) {
+ rc = -ENOMEM;
+ goto ubigen_create_err;
+ }
+
+ /* point to distinct regions within the buffer */
+ res->ptr_ec_hdr = res->buf;
+ res->ptr_vid_hdr = res->buf + be32_to_cpu(res->ec->vid_hdr_offset);
+ res->ptr_data = res->buf + be32_to_cpu(res->ec->vid_hdr_offset)
+ + UBI_VID_HDR_SIZE;
+
+ rc = validate_ubi_info(res);
+ if (rc != 0) {
+ fprintf(stderr, "Volume validation failed: %d\n", rc);
+ goto ubigen_create_err;
+ }
+
+ dump_info(res);
+ *u = res;
+ return rc;
+
+ ubigen_create_err:
+ if (res) {
+ if (res->v)
+ free(res->v);
+ if (res->ec)
+ free(res->ec);
+ if (res->buf)
+ free(res->buf);
+ free(res);
+ }
+ *u = NULL;
+ return rc;
+}
+
+int
+ubigen_get_leb_size(ubi_info_t u, size_t* size)
+{
+ if (u == NULL)
+ return -EINVAL;
+
+ *size = u->leb_size;
+ return 0;
+}
+
+
+int
+ubigen_get_leb_total(ubi_info_t u, size_t* total)
+{
+ if (u == NULL)
+ return -EINVAL;
+
+ *total = u->leb_total;
+ return 0;
+}
+
+int
+ubigen_set_lvol_rec(ubi_info_t u, size_t reserved_bytes,
+ const char* vol_name, struct ubi_vtbl_record *lvol_rec)
+{
+ uint32_t crc;
+
+ if ((u == NULL) || (vol_name == NULL))
+ return -EINVAL;
+
+ memset(lvol_rec, 0x0, UBI_VTBL_RECORD_SIZE);
+
+ lvol_rec->reserved_pebs =
+ cpu_to_be32(byte_to_blk(reserved_bytes, u->leb_size));
+ lvol_rec->alignment = cpu_to_be32(u->alignment);
+ lvol_rec->data_pad = u->v->data_pad;
+ lvol_rec->vol_type = u->v->vol_type;
+
+ lvol_rec->name_len =
+ cpu_to_be16((uint16_t)strlen((const char*)vol_name));
+
+ memcpy(lvol_rec->name, vol_name, UBI_VOL_NAME_MAX + 1);
+
+ crc = clc_crc32(crc32_table, UBI_CRC32_INIT,
+ lvol_rec, UBI_VTBL_RECORD_SIZE_CRC);
+ lvol_rec->crc = cpu_to_be32(crc);
+
return 0;
}