/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/ int handle_return(int r, XFILE * X, unsigned char tag, dump_parser * p) { u_int64 where, xwhere; switch (r) { case 0: if (p->cb_error) { xftell(X, &where); sub64_32(xwhere, where, 1); (p->cb_error) (DSERR_TAG, 1, p->err_refcon, (tag > 0x20 && tag < 0x7f) ? "Unexpected tag '%c' at %s = 0x%s" : "Unexpected tag 0x%02x at %s = 0x%s", tag, decimate_int64(&xwhere, 0), hexify_int64(&xwhere, 0)); } return DSERR_TAG; case ERROR_XFILE_EOF: if (p->cb_error) { xftell(X, &where); (p->cb_error) (ERROR_XFILE_EOF, 1, p->err_refcon, "Unexpected EOF at %s = 0x%s", decimate_int64(&where, 0), hexify_int64(&where, 0)); } return ERROR_XFILE_EOF; case ENOMEM: if (p->cb_error) { xftell(X, &where); (p->cb_error) (ENOMEM, 1, p->err_refcon, "Out of memory at %s = 0x%s", decimate_int64(&where, 0), hexify_int64(&where, 0)); } return ENOMEM; case DSERR_DONE: return 0; default: /* For other negative valuees, the callback was already done */ if (r > 0 && p->cb_error) (p->cb_error) (r, 1, p->err_refcon, "System error %d reading dump file", r); return r; } }
/* Parse a dump header, including its tagged attributes, and call the * dump-header callback, if one is defined. */ static afs_uint32 parse_dumphdr(XFILE * X, unsigned char *tag, tagged_field * field, afs_uint32 value, tag_parse_info * pi, void *g_refcon, void *l_refcon) { dump_parser *p = (dump_parser *) g_refcon; afs_dump_header hdr; dt_uint64 where; afs_uint32 r; memset(&hdr, 0, sizeof(hdr)); if ((r = xftell(X, &where))) return r; sub64_32(hdr.offset, where, 1); if ((r = ReadInt32(X, &hdr.magic))) return r; if ((r = ReadInt32(X, &hdr.version))) return r; if (hdr.magic != DUMPBEGINMAGIC) { if (p->cb_error) (p->cb_error) (DSERR_MAGIC, 1, p->err_refcon, "Invalid magic number (0x%08x) in dump header", hdr.magic); return DSERR_MAGIC; } if (hdr.version != DUMPVERSION) { if (p->cb_error) (p->cb_error) (DSERR_MAGIC, 1, p->err_refcon, "Unknown dump format version (%d) in dump header", hdr.version); return DSERR_MAGIC; } if (p->print_flags & DSPRINT_DUMPHDR) printf("%s [%s = 0x%s]\n", field->label, decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0)); if (p->print_flags & DSPRINT_DUMPHDR) { printf(" Magic number: 0x%08x\n", hdr.magic); printf(" Version: %d\n", hdr.version); } r = ParseTaggedData(X, dumphdr_fields, tag, pi, g_refcon, (void *)&hdr); if (!r && p->cb_dumphdr) { r = xftell(X, &where); if (!r) r = (p->cb_dumphdr) (&hdr, X, p->refcon); if (p->flags & DSFLAG_SEEK) { if (!r) r = xfseek(X, &where); else xfseek(X, &where); } } if (hdr.field_mask & F_DUMPHDR_VOLNAME) free(hdr.volname); return r; }
static afs_uint32 resync_vnode(XFILE * X, dump_parser * p, afs_vnode * v, int start, int limit) { dt_uint64 where, expected_where; afs_uint32 r; int i; if ((r = xftell(X, &expected_where))) return r; cp64(where, expected_where); r = match_next_vnode(X, p, &where, v->vnode); if (r && r != DSERR_FMT) return r; if (r) for (i = -start; i < limit; i++) { add64_32(where, expected_where, i); r = match_next_vnode(X, p, &where, v->vnode); if (!r) break; if (r != DSERR_FMT) return r; } if (r) { if (p->cb_error) (p->cb_error) (r, 1, p->err_refcon, "Unable to resync after vnode %d [%s = 0x%s]", v->vnode, decimate_int64(&expected_where, 0), hexify_int64(&expected_where, 0)); return r; } if (ne64(where, expected_where) && p->cb_error) { (p->cb_error) (DSERR_FMT, 0, p->err_refcon, "Vnode after %d not in expected location", v->vnode); (p->cb_error) (DSERR_FMT, 0, p->err_refcon, "Expected location: %s = 0x%s", decimate_int64(&expected_where, 0), hexify_int64(&expected_where, 0)); (p->cb_error) (DSERR_FMT, 0, p->err_refcon, "Actual location: %s = 0x%s", decimate_int64(&where, 0), hexify_int64(&where, 0)); } return xfseek(X, &where); }
/* Parse a volume header, including any tagged attributes, and call the * volume-header callback, if one is defined. */ afs_uint32 parse_volhdr(XFILE * X, unsigned char *tag, tagged_field * field, afs_uint32 value, tag_parse_info * pi, void *g_refcon, void *l_refcon) { dump_parser *p = (dump_parser *) g_refcon; afs_vol_header hdr; u_int64 where; afs_uint32 r; memset(&hdr, 0, sizeof(hdr)); if (r = xftell(X, &where)) return r; sub64_32(hdr.offset, where, 1); if (p->print_flags & DSPRINT_VOLHDR) printf("%s [%s = 0x%s]\n", field->label, decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0)); r = ParseTaggedData(X, volhdr_fields, tag, pi, g_refcon, (void *)&hdr); if (!r && p->cb_volhdr) { if (r = xftell(X, &where)) return r; r = (p->cb_volhdr) (&hdr, X, p->refcon); if (p->flags & DSFLAG_SEEK) { if (!r) r = xfseek(X, &where); else xfseek(X, &where); } } if (hdr.field_mask & F_VOLHDR_VOLUNIQ) p->vol_uniquifier = hdr.voluniq; if (hdr.field_mask & F_VOLHDR_VOLNAME) free(hdr.volname); if (hdr.field_mask & F_VOLHDR_OFFLINE_MSG) free(hdr.offline_msg); if (hdr.field_mask & F_VOLHDR_MOTD) free(hdr.motd_msg); return r; }
/* Parse or skip over the vnode data */ static afs_uint32 parse_vdata(XFILE * X, unsigned char *tag, tagged_field * field, afs_uint32 value, tag_parse_info * pi, void *g_refcon, void *l_refcon) { dump_parser *p = (dump_parser *) g_refcon; afs_vnode *v = (afs_vnode *) l_refcon; static char *symlink_buf = 0; static int symlink_size = 0; afs_uint32 r; if ((r = ReadInt32(X, &v->size))) return r; v->field_mask |= F_VNODE_SIZE; if (v->size) { v->field_mask |= F_VNODE_DATA; if ((r = xftell(X, &v->d_offset))) return r; if (p->print_flags & DSPRINT_VNODE) printf("%s%d (0x%08x) bytes at %s (0x%s)\n", field->label, v->size, v->size, decimate_int64(&v->d_offset, 0), hexify_int64(&v->d_offset, 0)); switch (v->type) { case vSymlink: if (v->size > symlink_size) { if (symlink_buf) symlink_buf = realloc(symlink_buf, v->size + 1); else symlink_buf = (char *)malloc(v->size + 1); symlink_size = symlink_buf ? v->size : 0; } if (symlink_buf) { if ((r = xfread(X, symlink_buf, v->size))) return r; symlink_buf[v->size] = 0; if (p->print_flags & DSPRINT_VNODE) printf(" Target: %s\n", symlink_buf); } else { /* Call the callback here, because it's non-fatal */ if (p->cb_error) (p->cb_error) (ENOMEM, 0, p->err_refcon, "Out of memory reading symlink"); if ((r = xfskip(X, v->size))) return r; } break; case vDirectory: if (p->cb_dirent || (p->print_flags & DSPRINT_DIR)) { if ((r = parse_directory(X, p, v, v->size, 0))) return r; break; } default: if ((r = xfskip(X, v->size))) return r; } } else if (p->print_flags & DSPRINT_VNODE) { printf("%sEmpty\n", field->label); } if (p->repair_flags & DSFIX_VDSYNC) { r = resync_vnode(X, p, v, 10, 15); if (r) return r; } return ReadByte(X, tag); }
/* Parse a VNode, including any tagged attributes and data, and call the * appropriate callback, if one is defined. */ afs_uint32 parse_vnode(XFILE * X, unsigned char *tag, tagged_field * field, afs_uint32 value, tag_parse_info * pi, void *g_refcon, void *l_refcon) { dump_parser *p = (dump_parser *) g_refcon; afs_uint32(*cb) (afs_vnode *, XFILE *, void *); dt_uint64 where, offset2k; afs_vnode v; afs_uint32 r; if ((r = xftell(X, &where))) return r; memset(&v, 0, sizeof(v)); sub64_32(v.offset, where, 1); if ((r = ReadInt32(X, &v.vnode))) return r; if ((r = ReadInt32(X, &v.vuniq))) return r; mk64(offset2k, 0, 2048); if (!LastGoodVNode || ((p->flags & DSFLAG_SEEK) && v.vnode == 1 && lt64(v.offset, offset2k))) LastGoodVNode = -1; if (p->print_flags & DSPRINT_ITEM) { printf("%s %d/%d [%s = 0x%s]\n", field->label, v.vnode, v.vuniq, decimate_int64(&where, 0), hexify_int64(&where, 0)); } r = ParseTaggedData(X, vnode_fields, tag, pi, g_refcon, (void *)&v); /* Try to resync, if requested */ if (!r && (p->repair_flags & DSFIX_VFSYNC)) { afs_uint32 drop; dt_uint64 xwhere; if ((r = xftell(X, &where))) return r; sub64_32(xwhere, where, 1); /* Are we at the start of a valid vnode (or dump end)? */ r = match_next_vnode(X, p, &xwhere, v.vnode); if (r && r != DSERR_FMT) return r; if (r) { /* Nope. */ /* Was _this_ a valid vnode? If so, we can keep it and search for * the next one. Otherwise, we throw it out, and start the search * at the starting point of this vnode. */ drop = r = match_next_vnode(X, p, &v.offset, LastGoodVNode); if (r && r != DSERR_FMT) return r; if (!r) { add64_32(where, v.offset, 1); if ((r = xfseek(X, &v.offset))) return r; } else { if ((r = xfseek(X, &xwhere))) return r; } if ((r = resync_vnode(X, p, &v, 0, 1024))) return r; if ((r = ReadByte(X, tag))) return r; if (drop) { if (p->cb_error) (p->cb_error) (DSERR_FMT, 0, p->err_refcon, "Dropping vnode %d", v.vnode); return 0; } } else { if ((r = xfseek(X, &where))) return r; } } LastGoodVNode = v.vnode; if (!r) { if (v.field_mask & F_VNODE_TYPE) switch (v.type) { case vFile: cb = p->cb_vnode_file; break; case vDirectory: cb = p->cb_vnode_dir; break; case vSymlink: cb = p->cb_vnode_link; break; default: cb = p->cb_vnode_wierd; break; } else cb = p->cb_vnode_empty; if (cb) { dt_uint64 where; if ((r = xftell(X, &where))) return r; r = (cb) (&v, X, p->refcon); if (p->flags & DSFLAG_SEEK) { if (!r) r = xfseek(X, &where); else xfseek(X, &where); } } } return r; }
/* 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)) { u_int64 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; u_int64 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; } } }