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 * Unoptimized versions, always dereference a cell through _GET_INT32() 32 * 33 */ 34 35 #define LONG_SIGN_BIT 0x80000000 36 37 static tnf_ref32_t *vaddr_to_phys(TNF *, tnf_ref32_t *, tnf_ref32_t); 38 39 /* 40 * Return target cell referred to via src_val from src_cell, after 41 * checking that target is valid (block was not reused). Return NULL 42 * otherwise. 43 * 44 * NOTE: We must check if the destination is within the valid_bytes 45 * range of its block, so as to correctly handle tnfxtract'ed files: 46 * the block containing the target cell may have been copied out 47 * before the block containing the source cell. 48 */ 49 50 static tnf_ref32_t * 51 vaddr_to_phys(TNF *tnf, tnf_ref32_t *src_cell, tnf_ref32_t src_val) 52 { 53 char *base; 54 unsigned shft, mask; 55 tnf_uint32_t src_gen, dst_gen, exp_gen; 56 tnf_int32_t gen_delta; 57 tnf_ref32_t src_off, exp_off, dst_off, *dst_blk, *dst_cell; 58 tnf_uint32_t bytes_valid; 59 60 base = tnf->file_start; 61 shft = tnf->generation_shift; 62 mask = tnf->address_mask; 63 64 /* Generation of source cell */ 65 /* LINTED pointer cast */ 66 src_gen = _GET_BLOCK_GENERATION(tnf, _GET_BLOCK(tnf, src_cell)); 67 /* Physical file offset of source cell */ 68 src_off = (tnf_ref32_t)((char *)src_cell - base); 69 /* Expected (unadjusted) file offset of destination cell */ 70 exp_off = src_off + src_val; 71 /* Generation delta */ 72 gen_delta = (tnf_int32_t)((unsigned)exp_off >> shft); 73 if ((exp_off & LONG_SIGN_BIT) == LONG_SIGN_BIT) { 74 /* sign bit was a 1 - so restore sign */ 75 gen_delta |= ((unsigned)mask << (32 - shft)); 76 } 77 /* Expected destination generation */ 78 exp_gen = src_gen + gen_delta; 79 /* Physical file offset of destination cell */ 80 dst_off = (tnf_ref32_t)((unsigned)exp_off & mask); 81 82 /* Destination cell */ 83 /* LINTED pointer cast */ 84 dst_cell = (tnf_ref32_t *)(base + dst_off); 85 /* Destination block */ 86 /* LINTED pointer cast */ 87 dst_blk = _GET_BLOCK(tnf, dst_cell); 88 /* Generation of destination cell */ 89 /* LINTED pointer cast */ 90 dst_gen = _GET_BLOCK_GENERATION(tnf, dst_blk); 91 /* Bytes valid in destination block */ 92 /* LINTED pointer cast */ 93 bytes_valid = _GET_BLOCK_BYTES_VALID(tnf, dst_blk); 94 95 if ((src_gen == (tnf_uint32_t)TNF_TAG_GENERATION_NUM) || 96 (dst_gen == (tnf_uint32_t)TNF_TAG_GENERATION_NUM) || 97 ((dst_gen == exp_gen) && 98 ((char *)dst_cell - (char *)dst_blk) < bytes_valid)) 99 return (dst_cell); 100 101 return ((tnf_ref32_t *)NULL); 102 } 103 104 /* 105 * Return the target referent of a cell, chasing forwarding references. 106 * Return TNF_NULL if cell is a TNF_NULL forwarding reference. 107 */ 108 109 tnf_ref32_t * 110 _tnf_get_ref32(TNF *tnf, tnf_ref32_t *cell) 111 { 112 tnf_ref32_t ref32, reftemp; 113 114 ref32 = _GET_INT32(tnf, cell); 115 116 if (TNF_REF32_IS_NULL(ref32)) 117 return (TNF_NULL); 118 119 if (TNF_REF32_IS_RSVD(ref32)) { 120 _tnf_error(tnf, TNF_ERR_BADREFTYPE); 121 return (TNF_NULL); 122 } 123 124 if (TNF_REF32_IS_PAIR(ref32)) { 125 /* We chase the high (tag) half */ 126 tnf_ref16_t tag16; 127 128 tag16 = TNF_REF32_TAG16(ref32); 129 130 if (TNF_TAG16_IS_ABS(tag16)) { 131 cell = (tnf_ref32_t *) 132 ((char *)tnf->file_start 133 /* LINTED pointer cast may result in improper alignment */ 134 + TNF_TAG16_ABS16(tag16)); 135 ref32 = _GET_INT32(tnf, cell); 136 137 } else if (TNF_TAG16_IS_REL(tag16)) { 138 cell = vaddr_to_phys(tnf, cell, 139 (tnf_ref32_t) TNF_TAG16_REF16(tag16)); 140 if (cell == TNF_NULL) 141 return (TNF_NULL); 142 ref32 = _GET_INT32(tnf, cell); 143 144 } else { 145 _tnf_error(tnf, TNF_ERR_BADREFTYPE); 146 return (TNF_NULL); 147 } 148 149 } else if (TNF_REF32_IS_PERMANENT(ref32)) { 150 /* permanent space pointer */ 151 reftemp = TNF_REF32_VALUE(ref32); 152 reftemp = TNF_REF32_SIGN_EXTEND(reftemp); 153 /* LINTED pointer cast may result in improper alignment */ 154 cell = (tnf_ref32_t *) ((char *)tnf->file_start + reftemp); 155 ref32 = _GET_INT32(tnf, cell); 156 157 } else { /* full/tag reclaimable space reference */ 158 cell = vaddr_to_phys(tnf, cell, TNF_REF32_VALUE(ref32)); 159 if (cell == TNF_NULL) 160 return (TNF_NULL); 161 ref32 = _GET_INT32(tnf, cell); 162 } 163 164 /* chase intermediate forwarding references */ 165 while (ref32 && TNF_REF32_IS_FWD(ref32)) { 166 if (TNF_REF32_IS_PERMANENT(ref32)) { 167 reftemp = TNF_REF32_VALUE(ref32); 168 reftemp = TNF_REF32_SIGN_EXTEND(reftemp); 169 cell = (tnf_ref32_t *) ((char *)tnf->file_start + 170 /* LINTED pointer cast may result in improper alignment */ 171 reftemp); 172 173 } else { 174 cell = vaddr_to_phys(tnf, cell, TNF_REF32_VALUE(ref32)); 175 if (cell == TNF_NULL) 176 return (TNF_NULL); 177 } 178 ref32 = _GET_INT32(tnf, cell); 179 } 180 181 return (cell); 182 } 183 184 /* 185 * Return the target referent of ref16 contained in cell. 186 * Return TNF_NULL if cell doesn't have a ref16. 187 */ 188 189 tnf_ref32_t * 190 _tnf_get_ref16(TNF *tnf, tnf_ref32_t *cell) 191 { 192 tnf_ref32_t ref32, reftemp; 193 194 ref32 = _GET_INT32(tnf, cell); 195 196 if (TNF_REF32_IS_PAIR(ref32)) { 197 tnf_ref16_t ref16; 198 199 ref16 = TNF_REF32_REF16(ref32); 200 201 if (TNF_REF16_VALUE(ref16) == TNF_NULL) 202 /* No ref16 was stored */ 203 return (TNF_NULL); 204 else { 205 cell = vaddr_to_phys(tnf, cell, 206 (tnf_ref32_t) TNF_REF16_VALUE(ref16)); 207 if (cell == TNF_NULL) 208 return (TNF_NULL); 209 ref32 = _GET_INT32(tnf, cell); 210 } 211 } else /* not a pair pointer */ 212 return (TNF_NULL); 213 214 /* chase intermediate forwarding references */ 215 while (ref32 && TNF_REF32_IS_FWD(ref32)) { 216 if (TNF_REF32_IS_PERMANENT(ref32)) { 217 reftemp = TNF_REF32_VALUE(ref32); 218 reftemp = TNF_REF32_SIGN_EXTEND(reftemp); 219 cell = (tnf_ref32_t *) ((char *)tnf->file_start + 220 /* LINTED pointer cast may result in improper alignment */ 221 reftemp); 222 223 } else { 224 cell = vaddr_to_phys(tnf, cell, TNF_REF32_VALUE(ref32)); 225 if (cell == TNF_NULL) 226 return (TNF_NULL); 227 } 228 ref32 = _GET_INT32(tnf, cell); 229 } 230 231 return (cell); 232 } 233