/* * CMUCS AFStools * dumpscan - routines for scanning and manipulating AFS volume dumps * * Copyright (c) 1998 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* parsetag.c - Parse a tagged data stream */ #include "dumpscan.h" #include "dumpscan_errs.h" /* If a parser function is defined, it will be called after the data value * (if any) is read. The parser is called as follows: * * parser(input_file, &tag, &field_rec, value, g_refcon, l_refcon); * * - input_file is the FILE * for the input stream * - field_rec is a pointer to the field record for the field just read * - g_refcon and l_refcon are as passed in to ParseTaggedData * - For integer types, value is the integer value * - For DKIND_STRING, tag is a pointer to the string just read * - For DKIND_SPEACH, tag is a pointer to the place to put the next tag. * * If the field type is DKIND_SPECIAL, the parser is expected to read its * own data from the input stream, and return when ParseTaggedData is supposed * to take over, with the next tag to process in *tag. At no other time * should the parser read, write, or reposition the input stream. * * The parser routine should return 0 on success, non-0 on failure. If the * data type is DKIND_STRING, the parser may return DSERR_KEEP to indicate * that the memory allocated for the value should not be freed. */ /* Parse a file containing tagged data and attributes **/ afs_uint32 ParseTaggedData(XFILE * X, tagged_field * fields, unsigned char *tag, tag_parse_info * pi, void *g_refcon, void *l_refcon) { int i = -1; afs_uint32 r, val; afs_uint16 val16; unsigned char val8; unsigned char *strval; for (;;) { if (i < 0 || (fields[i].kind & DKIND_MASK) != DKIND_SPECIAL) { /* Need to read in a tag */ if ((r = ReadByte(X, tag))) return r; } /* Simple error recovery - if we encounter a 0, it can never be * a valid tag. If TPFLAG_SKIP is set, we can skip over any * such null bytes, and process whatever tag we find beyond. * In addition, if TPFLAG_RSKIP is set, then the next time * we encounter a 0, try skipping backwards. That seems to * work much of the time. */ if (!*tag && pi->shift_offset && (pi->flags & TPFLAG_RSKIP)) { dt_uint64 where, tmp64a, tmp64b; char buf1[21], buf2[21], buf3[21]; char *p1, *p2, *p3; if ((r = xftell(X, &tmp64a))) return r; sub64_32(where, tmp64a, pi->shift_offset + 1); if ((r = xfseek(X, &where))) return r; if (pi->cb_error) { (pi->cb_error) (DSERR_FMT, 0, pi->err_refcon, "Inserted %d bytes before offset %d", pi->shift_offset, decimate_int64(&where, 0)); add64_32(tmp64a, pi->shift_start, pi->shift_offset); p1 = decimate_int64(&tmp64a, buf1); sub64_64(tmp64b, where, tmp64a); p2 = decimate_int64(&tmp64b, buf2); p3 = decimate_int64(&pi->shift_start, buf3); (pi->cb_error) (DSERR_FMT, 0, pi->err_refcon, ">>> SHIFT start=%s length=%s target=%s", p1, p2, p3); } pi->shift_offset = 0; if ((r = ReadByte(X, tag))) return r; } if (!*tag && (pi->flags & TPFLAG_SKIP)) { int count = 0; dt_uint64 where, tmp64a; if ((r = xftell(X, &where))) return r; while (!*tag) { if ((r = ReadByte(X, tag))) return r; count++; } pi->shift_offset += count; cp64(pi->shift_start, where); if (pi->cb_error) { sub64_32(tmp64a, where, 1); (pi->cb_error) (DSERR_FMT, 0, pi->err_refcon, "Skipped %d bytes at offset %s", count, decimate_int64(&tmp64a, 0)); } } for (i = 0; fields[i].tag && fields[i].tag != *tag; i++); if (!fields[i].tag) return 0; switch (fields[i].kind & DKIND_MASK) { case DKIND_NOOP: if (fields[i].func) { r = (fields[i].func) (X, 0, fields + i, 0, pi, g_refcon, l_refcon); if (r) return r; } break; case DKIND_BYTE: if ((r = ReadByte(X, &val8))) return r; if (fields[i].func) { r = (fields[i].func) (X, 0, fields + i, val8, pi, g_refcon, l_refcon); if (r) return r; } break; case DKIND_INT16: if ((r = ReadInt16(X, &val16))) return r; if (fields[i].func) { r = (fields[i].func) (X, 0, fields + i, val16, pi, g_refcon, l_refcon); if (r) return r; } break; case DKIND_INT32: if ((r = ReadInt32(X, &val))) return r; if (fields[i].func) { r = (fields[i].func) (X, 0, fields + i, val, pi, g_refcon, l_refcon); if (r) return r; } break; case DKIND_STRING: if ((r = ReadString(X, &strval))) return r; if (fields[i].func) { r = (fields[i].func) (X, strval, fields + i, 0, pi, g_refcon, l_refcon); if (r != DSERR_KEEP) free(strval); if (r && r != DSERR_KEEP) return r; } else free(strval); break; case DKIND_SPECIAL: if (fields[i].func) { r = (fields[i].func) (X, tag, fields + i, 0, pi, g_refcon, l_refcon); if (r) return r; } else i = -1; } } }