/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1994, by Sun Microsytems, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "libtnf.h"
/*
* Initiate a reader session
*/
tnf_errcode_t
tnf_reader_begin(caddr_t base, size_t size, TNF **tnfret)
{
tnf_uint32_t magic;
int native;
TNF *tnf;
tnf_ref32_t *fhdr, *bhdr;
size_t tmpsz;
caddr_t p, genp, bvp;
tnf_errcode_t err;
/*
* Check magic number
*/
/* LINTED pointer cast may result in improper alignment */
if ((magic = *(tnf_uint32_t *)base) == TNF_MAGIC)
native = 1; /* same endian */
else if (magic == TNF_MAGIC_1)
native = 0; /* other endian */
else
return (TNF_ERR_NOTTNF);
/*
* Allocate TNF struct, initialize members
*/
if ((tnf = (TNF*)calloc(1, sizeof (*tnf))) == (TNF*)NULL)
return (TNF_ERR_ALLOCFAIL);
tnf->file_magic = magic;
tnf->file_native = native;
tnf->file_start = base;
tnf->file_size = size;
tnf->file_end = base + size;
/*
* Examine file header
*/
/* LINTED pointer cast may result in improper alignment */
fhdr = (tnf_ref32_t *)(base + sizeof (magic)); /* second word */
tnf->file_header = fhdr;
/* Block size */
p = _tnf_get_slot_named(tnf, fhdr, TNF_N_BLOCK_SIZE);
/* LINTED pointer cast may result in improper alignment */
tnf->block_size = _GET_UINT32(tnf, (tnf_uint32_t *)p);
/* Directory size */
p = _tnf_get_slot_named(tnf, fhdr, TNF_N_DIRECTORY_SIZE);
/* LINTED pointer cast may result in improper alignment */
tnf->directory_size = _GET_UINT32(tnf, (tnf_uint32_t *)p);
/* Block count */
p = _tnf_get_slot_named(tnf, fhdr, TNF_N_BLOCK_COUNT);
/* LINTED pointer cast may result in improper alignment */
tnf->block_count = _GET_UINT32(tnf, (tnf_uint32_t *)p);
/*
* This member tracks data block count, not total block count
* (unlike the TNF file header). Discount directory blocks.
*/
tnf->block_count -= tnf->directory_size / tnf->block_size;
/*
* 1196886: Clients may supply file_size information obtained
* by fstat() which is incorrect. Check it now and revise
* downwards if we have to.
*/
tmpsz = tnf->directory_size + tnf->block_count * tnf->block_size;
if (tmpsz != size) {
if (tmpsz > size)
/* missing data? */
return (TNF_ERR_BADTNF);
else {
tnf->file_size = tmpsz;
tnf->file_end = base + tmpsz;
}
}
/* Calculate block shift */
tmpsz = 1;
while (tmpsz != tnf->block_size) {
tmpsz <<= 1;
tnf->block_shift++;
}
/* Calculate block mask */
tnf->block_mask = ~(tnf->block_size - 1);
/* Generation shift */
p = _tnf_get_slot_named(tnf, fhdr, TNF_N_FILE_LOGICAL_SIZE);
/* LINTED pointer cast may result in improper alignment */
tnf->generation_shift = _GET_UINT32(tnf, (tnf_uint32_t *)p);
/* Calculate the address mask */
/*
* Following lint complaint is unwarranted, probably an
* uninitialized variable in lint or something ...
*/
/* LINTED constant truncated by assignment */
tnf->address_mask = 0xffffffff;
tnf->address_mask <<= tnf->generation_shift;
tnf->address_mask = ~(tnf->address_mask);
/*
* Examine first block header in data area
*/
tnf->data_start = tnf->file_start + tnf->directory_size;
/* LINTED pointer cast may result in improper alignment */
bhdr = (tnf_ref32_t *)tnf->data_start;
/* Block generation offset */
genp = _tnf_get_slot_named(tnf, bhdr, TNF_N_GENERATION);
tnf->block_generation_offset = genp - (caddr_t)bhdr;
/* Block bytes valid offset */
bvp = _tnf_get_slot_named(tnf, bhdr, TNF_N_BYTES_VALID);
tnf->block_bytes_valid_offset = bvp - (caddr_t)bhdr;
/*
* Bootstrap taginfo system and cache important taginfo
*/
if ((err = _tnf_init_tags(tnf)) != TNF_ERR_NONE)
return (err);
tnf->file_header_info = _tnf_get_info(tnf, _tnf_get_tag(tnf, fhdr));
tnf->block_header_info = _tnf_get_info(tnf, _tnf_get_tag(tnf, bhdr));
/*
* Return TNF handle and error status
*/
*tnfret = tnf;
return (TNF_ERR_NONE);
}
/*
* Terminate a reader session
*/
tnf_errcode_t
tnf_reader_end(TNF *tnf)
{
tnf_errcode_t err;
/* Deallocate all taginfo */
if ((err = _tnf_fini_tags(tnf)) != TNF_ERR_NONE)
return (err);
/* Deallocate TNF */
free(tnf);
return (TNF_ERR_NONE);
}