579 lines
15 KiB
C
579 lines
15 KiB
C
/*
|
|
* This file is part of UBIFS.
|
|
*
|
|
* Copyright (C) 2006, 2007 Nokia Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
* the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc., 51
|
|
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Authors: Adrian Hunter
|
|
* Artem Bityutskiy
|
|
*/
|
|
|
|
#include "mkfs.ubifs.h"
|
|
|
|
/**
|
|
* 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;
|
|
long long 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;
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* 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_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);
|
|
}
|
|
|
|
/**
|
|
* 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(3, "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;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
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);
|
|
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);
|
|
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);
|
|
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);
|
|
if (err)
|
|
goto out;
|
|
|
|
c->nhead_lnum = lnum;
|
|
c->nhead_offs = ALIGN(len, c->min_io_size);
|
|
|
|
dbg_msg(1, "lpt_sz: %lld", c->lpt_sz);
|
|
dbg_msg(1, "space_bits: %d", c->space_bits);
|
|
dbg_msg(1, "lpt_lnum_bits: %d", c->lpt_lnum_bits);
|
|
dbg_msg(1, "lpt_offs_bits: %d", c->lpt_offs_bits);
|
|
dbg_msg(1, "lpt_spc_bits: %d", c->lpt_spc_bits);
|
|
dbg_msg(1, "pcnt_bits: %d", c->pcnt_bits);
|
|
dbg_msg(1, "lnum_bits: %d", c->lnum_bits);
|
|
dbg_msg(1, "pnode_sz: %d", c->pnode_sz);
|
|
dbg_msg(1, "nnode_sz: %d", c->nnode_sz);
|
|
dbg_msg(1, "ltab_sz: %d", c->ltab_sz);
|
|
dbg_msg(1, "lsave_sz: %d", c->lsave_sz);
|
|
dbg_msg(1, "lsave_cnt: %d", c->lsave_cnt);
|
|
dbg_msg(1, "lpt_hght: %d", c->lpt_hght);
|
|
dbg_msg(1, "big_lpt: %d", c->big_lpt);
|
|
dbg_msg(1, "LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
|
|
dbg_msg(1, "LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
|
|
dbg_msg(1, "LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
|
|
if (c->big_lpt)
|
|
dbg_msg(1, "LPT lsave is at %d:%d",
|
|
c->lsave_lnum, c->lsave_offs);
|
|
out:
|
|
free(lsave);
|
|
free(buf);
|
|
free(nnode);
|
|
free(pnode);
|
|
return err;
|
|
}
|