3 * dumpscan - routines for scanning and manipulating AFS volume dumps
5 * Copyright (c) 1998 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
29 /* parsevnode.c - Parse a VNode */
31 #include <sys/types.h>
32 #include <netinet/in.h>
36 #include "dumpscan_errs.h"
41 #include <afs/prs_fs.h>
43 static afs_uint32 LastGoodVNode = 0;
44 static afs_uint32 store_vnode(XFILE *, unsigned char *, tagged_field *,
45 afs_uint32, tag_parse_info *, void *, void *);
46 static afs_uint32 parse_acl(XFILE *, unsigned char *, tagged_field *,
47 afs_uint32, tag_parse_info *, void *, void *);
48 static afs_uint32 parse_vdata(XFILE *, unsigned char *, tagged_field *,
49 afs_uint32, tag_parse_info *, void *, void *);
51 /** Field list for vnodes **/
52 static tagged_field vnode_fields[] = {
53 {VTAG_TYPE, DKIND_BYTE, " VNode type: ", store_vnode, 0, 0},
54 {VTAG_NLINKS, DKIND_INT16, " Link count: ", store_vnode, 0, 0},
55 {VTAG_DVERS, DKIND_INT32, " Version: ", store_vnode, 0, 0},
56 {VTAG_CLIENT_DATE, DKIND_TIME, " Server Date: ", store_vnode, 0, 0},
57 {VTAG_AUTHOR, DKIND_INT32, " Author: ", store_vnode, 0, 0},
58 {VTAG_OWNER, DKIND_INT32, " Owner: ", store_vnode, 0, 0},
59 {VTAG_GROUP, DKIND_INT32, " Group: ", store_vnode, 0, 0},
60 {VTAG_MODE, DKIND_INT16, " UNIX mode: ", store_vnode, 0, 0},
61 {VTAG_PARENT, DKIND_INT32, " Parent: ", store_vnode, 0, 0},
62 {VTAG_SERVER_DATE, DKIND_TIME, " Client Date: ", store_vnode, 0, 0},
63 {VTAG_ACL, DKIND_SPECIAL, " xxxxxxxx ACL: ", parse_acl, 0, 0},
64 {VTAG_DATA, DKIND_SPECIAL, " Contents: ", parse_vdata, 0, 0},
70 resync_vnode(XFILE * X, dump_parser * p, afs_vnode * v, int start, int limit)
72 dt_uint64 where, expected_where;
76 if ((r = xftell(X, &expected_where)))
78 cp64(where, expected_where);
80 r = match_next_vnode(X, p, &where, v->vnode);
81 if (r && r != DSERR_FMT)
84 for (i = -start; i < limit; i++) {
85 add64_32(where, expected_where, i);
86 r = match_next_vnode(X, p, &where, v->vnode);
94 (p->cb_error) (r, 1, p->err_refcon,
95 "Unable to resync after vnode %d [%s = 0x%s]",
96 v->vnode, decimate_int64(&expected_where, 0),
97 hexify_int64(&expected_where, 0));
100 if (ne64(where, expected_where) && p->cb_error) {
101 (p->cb_error) (DSERR_FMT, 0, p->err_refcon,
102 "Vnode after %d not in expected location", v->vnode);
103 (p->cb_error) (DSERR_FMT, 0, p->err_refcon,
104 "Expected location: %s = 0x%s",
105 decimate_int64(&expected_where, 0),
106 hexify_int64(&expected_where, 0));
107 (p->cb_error) (DSERR_FMT, 0, p->err_refcon,
108 "Actual location: %s = 0x%s", decimate_int64(&where,
110 hexify_int64(&where, 0));
112 return xfseek(X, &where);
116 /* Parse a VNode, including any tagged attributes and data, and call the
117 * appropriate callback, if one is defined.
120 parse_vnode(XFILE * X, unsigned char *tag, tagged_field * field,
121 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
124 dump_parser *p = (dump_parser *) g_refcon;
125 afs_uint32(*cb) (afs_vnode *, XFILE *, void *);
126 dt_uint64 where, offset2k;
131 if ((r = xftell(X, &where)))
133 memset(&v, 0, sizeof(v));
134 sub64_32(v.offset, where, 1);
135 if ((r = ReadInt32(X, &v.vnode)))
137 if ((r = ReadInt32(X, &v.vuniq)))
140 mk64(offset2k, 0, 2048);
142 || ((p->flags & DSFLAG_SEEK) && v.vnode == 1
143 && lt64(v.offset, offset2k)))
146 if (p->print_flags & DSPRINT_ITEM) {
147 printf("%s %d/%d [%s = 0x%s]\n", field->label, v.vnode, v.vuniq,
148 decimate_int64(&where, 0), hexify_int64(&where, 0));
151 r = ParseTaggedData(X, vnode_fields, tag, pi, g_refcon, (void *)&v);
153 /* Try to resync, if requested */
154 if (!r && (p->repair_flags & DSFIX_VFSYNC)) {
158 if ((r = xftell(X, &where)))
160 sub64_32(xwhere, where, 1);
162 /* Are we at the start of a valid vnode (or dump end)? */
163 r = match_next_vnode(X, p, &xwhere, v.vnode);
164 if (r && r != DSERR_FMT)
167 /* Was _this_ a valid vnode? If so, we can keep it and search for
168 * the next one. Otherwise, we throw it out, and start the search
169 * at the starting point of this vnode.
171 drop = r = match_next_vnode(X, p, &v.offset, LastGoodVNode);
172 if (r && r != DSERR_FMT)
175 add64_32(where, v.offset, 1);
176 if ((r = xfseek(X, &v.offset)))
179 if ((r = xfseek(X, &xwhere)))
182 if ((r = resync_vnode(X, p, &v, 0, 1024)))
184 if ((r = ReadByte(X, tag)))
188 (p->cb_error) (DSERR_FMT, 0, p->err_refcon,
189 "Dropping vnode %d", v.vnode);
193 if ((r = xfseek(X, &where)))
197 LastGoodVNode = v.vnode;
200 if (v.field_mask & F_VNODE_TYPE)
203 cb = p->cb_vnode_file;
206 cb = p->cb_vnode_dir;
209 cb = p->cb_vnode_link;
212 cb = p->cb_vnode_wierd;
215 cb = p->cb_vnode_empty;
219 if ((r = xftell(X, &where)))
221 r = (cb) (&v, X, p->refcon);
222 if (p->flags & DSFLAG_SEEK) {
224 r = xfseek(X, &where);
234 /* Store data in a vnode */
236 store_vnode(XFILE * X, unsigned char *tag, tagged_field * field,
237 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
240 dump_parser *p = (dump_parser *) g_refcon;
241 afs_vnode *v = (afs_vnode *) l_refcon;
245 switch (field->tag) {
247 v->field_mask |= F_VNODE_TYPE;
249 if (p->print_flags & DSPRINT_VNODE) {
252 printf("%sFile (%d)\n", field->label, value);
255 printf("%sDirectory (%d)\n", field->label, value);
258 printf("%sSymbolic Link (%d)\n", field->label, value);
261 printf("%s??? (%d)\n", field->label, value);
268 v->field_mask |= F_VNODE_NLINKS;
273 v->field_mask |= F_VNODE_DVERS;
277 case VTAG_CLIENT_DATE:
278 v->field_mask |= F_VNODE_CDATE;
279 v->client_date = value;
282 case VTAG_SERVER_DATE:
283 v->field_mask |= F_VNODE_SDATE;
284 v->server_date = value;
288 v->field_mask |= F_VNODE_AUTHOR;
293 v->field_mask |= F_VNODE_OWNER;
298 v->field_mask |= F_VNODE_GROUP;
303 v->field_mask |= F_VNODE_MODE;
308 v->field_mask |= F_VNODE_PARENT;
313 if (p->print_flags & DSPRINT_VNODE)
314 switch (field->kind) {
318 printf("%s%d\n", field->label, value);
321 printf("%s0x%02x\n", field->label, value);
324 printf("%s0x%04x\n", field->label, value);
327 printf("%s0x%08x\n", field->label, value);
330 printf("%s%c\n", field->label, value);
333 printf("%s%s\n", field->label, tag);
336 printf("%s%s\n", field->label, value ? "true" : "false");
340 printf("%s%s", field->label, ctime(&when));
348 rights2str(afs_uint32 rights)
353 if (rights & PRSFS_READ)
355 if (rights & PRSFS_LOOKUP)
357 if (rights & PRSFS_INSERT)
359 if (rights & PRSFS_DELETE)
361 if (rights & PRSFS_WRITE)
363 if (rights & PRSFS_LOCK)
365 if (rights & PRSFS_ADMINISTER)
367 if (rights & PRSFS_USR0)
369 if (rights & PRSFS_USR1)
371 if (rights & PRSFS_USR2)
373 if (rights & PRSFS_USR3)
375 if (rights & PRSFS_USR4)
377 if (rights & PRSFS_USR5)
379 if (rights & PRSFS_USR6)
381 if (rights & PRSFS_USR7)
391 /* Parse and store the ACL data from a directory vnode */
393 parse_acl(XFILE * X, unsigned char *tag, tagged_field * field,
394 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
397 struct acl_accessList *acl;
398 dump_parser *p = (dump_parser *) g_refcon;
399 afs_vnode *v = (afs_vnode *) l_refcon;
402 if ((r = xfread(X, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE)))
405 v->field_mask |= F_VNODE_ACL;
406 if (p->print_flags & DSPRINT_ACL) {
407 acl = (struct acl_accessList *)(v->acl);
408 n = ntohl(acl->positive);
410 printf(" Positive ACL: %d entries\n", n);
411 for (i = 0; i < n; i++)
412 printf(" %9d %s\n", ntohl(acl->entries[i].id),
413 rights2str(ntohl(acl->entries[i].rights)));
415 n = ntohl(acl->negative);
417 printf(" Negative ACL: %d entries\n", n);
418 for (i = ntohl(acl->positive); i < ntohl(acl->total); i++)
419 printf(" %9d %s\n", ntohl(acl->entries[i].id),
420 rights2str(ntohl(acl->entries[i].rights)));
423 return ReadByte(X, tag);
427 /* Parse or skip over the vnode data */
429 parse_vdata(XFILE * X, unsigned char *tag, tagged_field * field,
430 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
433 dump_parser *p = (dump_parser *) g_refcon;
434 afs_vnode *v = (afs_vnode *) l_refcon;
435 static char *symlink_buf = 0;
436 static int symlink_size = 0;
439 if ((r = ReadInt32(X, &v->size)))
441 v->field_mask |= F_VNODE_SIZE;
444 v->field_mask |= F_VNODE_DATA;
445 if ((r = xftell(X, &v->d_offset)))
447 if (p->print_flags & DSPRINT_VNODE)
448 printf("%s%d (0x%08x) bytes at %s (0x%s)\n", field->label,
449 v->size, v->size, decimate_int64(&v->d_offset, 0),
450 hexify_int64(&v->d_offset, 0));
454 if (v->size > symlink_size) {
456 symlink_buf = (char *)realloc(symlink_buf, v->size + 1);
458 symlink_buf = (char *)malloc(v->size + 1);
459 symlink_size = symlink_buf ? v->size : 0;
462 if ((r = xfread(X, symlink_buf, v->size)))
464 symlink_buf[v->size] = 0;
465 if (p->print_flags & DSPRINT_VNODE)
466 printf(" Target: %s\n", symlink_buf);
468 /* Call the callback here, because it's non-fatal */
470 (p->cb_error) (ENOMEM, 0, p->err_refcon,
471 "Out of memory reading symlink");
472 if ((r = xfskip(X, v->size)))
478 if (p->cb_dirent || (p->print_flags & DSPRINT_DIR)) {
479 if ((r = parse_directory(X, p, v, v->size, 0)))
485 if ((r = xfskip(X, v->size)))
488 } else if (p->print_flags & DSPRINT_VNODE) {
489 printf("%sEmpty\n", field->label);
491 if (p->repair_flags & DSFIX_VDSYNC) {
492 r = resync_vnode(X, p, v, 10, 15);
496 return ReadByte(X, tag);