1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include "libtnf.h"
29
30 /*
31 * Initiate a reader session
32 */
33
34 tnf_errcode_t
tnf_reader_begin(caddr_t base,size_t size,TNF ** tnfret)35 tnf_reader_begin(caddr_t base, size_t size, TNF **tnfret)
36 {
37 tnf_uint32_t magic;
38 int native;
39 TNF *tnf;
40 tnf_ref32_t *fhdr, *bhdr;
41 size_t tmpsz;
42 caddr_t p, genp, bvp;
43 tnf_errcode_t err;
44
45 /*
46 * Check magic number
47 */
48
49 /* LINTED pointer cast may result in improper alignment */
50 if ((magic = *(tnf_uint32_t *)base) == TNF_MAGIC)
51 native = 1; /* same endian */
52 else if (magic == TNF_MAGIC_1)
53 native = 0; /* other endian */
54 else
55 return (TNF_ERR_NOTTNF);
56
57 /*
58 * Allocate TNF struct, initialize members
59 */
60
61 if ((tnf = (TNF*)calloc(1, sizeof (*tnf))) == (TNF*)NULL)
62 return (TNF_ERR_ALLOCFAIL);
63
64 tnf->file_magic = magic;
65 tnf->file_native = native;
66 tnf->file_start = base;
67 tnf->file_size = size;
68 tnf->file_end = base + size;
69
70 /*
71 * Examine file header
72 */
73
74 /* LINTED pointer cast may result in improper alignment */
75 fhdr = (tnf_ref32_t *)(base + sizeof (magic)); /* second word */
76 tnf->file_header = fhdr;
77
78 /* Block size */
79 p = _tnf_get_slot_named(tnf, fhdr, TNF_N_BLOCK_SIZE);
80 /* LINTED pointer cast may result in improper alignment */
81 tnf->block_size = _GET_UINT32(tnf, (tnf_uint32_t *)p);
82
83 /* Directory size */
84 p = _tnf_get_slot_named(tnf, fhdr, TNF_N_DIRECTORY_SIZE);
85 /* LINTED pointer cast may result in improper alignment */
86 tnf->directory_size = _GET_UINT32(tnf, (tnf_uint32_t *)p);
87
88 /* Block count */
89 p = _tnf_get_slot_named(tnf, fhdr, TNF_N_BLOCK_COUNT);
90 /* LINTED pointer cast may result in improper alignment */
91 tnf->block_count = _GET_UINT32(tnf, (tnf_uint32_t *)p);
92 /*
93 * This member tracks data block count, not total block count
94 * (unlike the TNF file header). Discount directory blocks.
95 */
96 tnf->block_count -= tnf->directory_size / tnf->block_size;
97
98 /*
99 * 1196886: Clients may supply file_size information obtained
100 * by fstat() which is incorrect. Check it now and revise
101 * downwards if we have to.
102 */
103 tmpsz = tnf->directory_size + tnf->block_count * tnf->block_size;
104 if (tmpsz != size) {
105 if (tmpsz > size)
106 /* missing data? */
107 return (TNF_ERR_BADTNF);
108 else {
109 tnf->file_size = tmpsz;
110 tnf->file_end = base + tmpsz;
111 }
112 }
113
114 /* Calculate block shift */
115 tmpsz = 1;
116 while (tmpsz != tnf->block_size) {
117 tmpsz <<= 1;
118 tnf->block_shift++;
119 }
120
121 /* Calculate block mask */
122 tnf->block_mask = ~(tnf->block_size - 1);
123
124 /* Generation shift */
125 p = _tnf_get_slot_named(tnf, fhdr, TNF_N_FILE_LOGICAL_SIZE);
126 /* LINTED pointer cast may result in improper alignment */
127 tnf->generation_shift = _GET_UINT32(tnf, (tnf_uint32_t *)p);
128
129 /* Calculate the address mask */
130 /*
131 * Following lint complaint is unwarranted, probably an
132 * uninitialized variable in lint or something ...
133 */
134 /* LINTED constant truncated by assignment */
135 tnf->address_mask = 0xffffffff;
136 tnf->address_mask <<= tnf->generation_shift;
137 tnf->address_mask = ~(tnf->address_mask);
138
139
140 /*
141 * Examine first block header in data area
142 */
143
144 tnf->data_start = tnf->file_start + tnf->directory_size;
145 /* LINTED pointer cast may result in improper alignment */
146 bhdr = (tnf_ref32_t *)tnf->data_start;
147
148 /* Block generation offset */
149 genp = _tnf_get_slot_named(tnf, bhdr, TNF_N_GENERATION);
150 tnf->block_generation_offset = genp - (caddr_t)bhdr;
151
152 /* Block bytes valid offset */
153 bvp = _tnf_get_slot_named(tnf, bhdr, TNF_N_BYTES_VALID);
154 tnf->block_bytes_valid_offset = bvp - (caddr_t)bhdr;
155
156 /*
157 * Bootstrap taginfo system and cache important taginfo
158 */
159
160 if ((err = _tnf_init_tags(tnf)) != TNF_ERR_NONE)
161 return (err);
162
163 tnf->file_header_info = _tnf_get_info(tnf, _tnf_get_tag(tnf, fhdr));
164 tnf->block_header_info = _tnf_get_info(tnf, _tnf_get_tag(tnf, bhdr));
165
166 /*
167 * Return TNF handle and error status
168 */
169
170 *tnfret = tnf;
171 return (TNF_ERR_NONE);
172 }
173
174 /*
175 * Terminate a reader session
176 */
177
178 tnf_errcode_t
tnf_reader_end(TNF * tnf)179 tnf_reader_end(TNF *tnf)
180 {
181 tnf_errcode_t err;
182
183 /* Deallocate all taginfo */
184 if ((err = _tnf_fini_tags(tnf)) != TNF_ERR_NONE)
185 return (err);
186
187 /* Deallocate TNF */
188 free(tnf);
189
190 return (TNF_ERR_NONE);
191 }
192