Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / tools / dumpscan / parsevnode.c
1 /*
2 * CMUCS AFStools
3 * dumpscan - routines for scanning and manipulating AFS volume dumps
4 *
5 * Copyright (c) 1998 Carnegie Mellon University
6 * All Rights Reserved.
7 *
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.
13 *
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.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
27 */
28
29 /* parsevnode.c - Parse a VNode */
30
31 #include <sys/types.h>
32 #include <netinet/in.h>
33 #include <errno.h>
34
35 #include "dumpscan.h"
36 #include "dumpscan_errs.h"
37 #include "dumpfmt.h"
38 #include "internal.h"
39
40 #include <afs/acl.h>
41 #include <afs/prs_fs.h>
42
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 *);
50
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},
65 {0, 0, 0, 0, 0, 0}
66 };
67
68
69 static afs_uint32
70 resync_vnode(XFILE * X, dump_parser * p, afs_vnode * v, int start, int limit)
71 {
72 dt_uint64 where, expected_where;
73 afs_uint32 r;
74 int i;
75
76 if ((r = xftell(X, &expected_where)))
77 return r;
78 cp64(where, expected_where);
79
80 r = match_next_vnode(X, p, &where, v->vnode);
81 if (r && r != DSERR_FMT)
82 return r;
83 if (r)
84 for (i = -start; i < limit; i++) {
85 add64_32(where, expected_where, i);
86 r = match_next_vnode(X, p, &where, v->vnode);
87 if (!r)
88 break;
89 if (r != DSERR_FMT)
90 return r;
91 }
92 if (r) {
93 if (p->cb_error)
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));
98 return r;
99 }
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,
109 0),
110 hexify_int64(&where, 0));
111 }
112 return xfseek(X, &where);
113 }
114
115
116 /* Parse a VNode, including any tagged attributes and data, and call the
117 * appropriate callback, if one is defined.
118 */
119 afs_uint32
120 parse_vnode(XFILE * X, unsigned char *tag, tagged_field * field,
121 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
122 void *l_refcon)
123 {
124 dump_parser *p = (dump_parser *) g_refcon;
125 afs_uint32(*cb) (afs_vnode *, XFILE *, void *);
126 dt_uint64 where, offset2k;
127 afs_vnode v;
128 afs_uint32 r;
129
130
131 if ((r = xftell(X, &where)))
132 return r;
133 memset(&v, 0, sizeof(v));
134 sub64_32(v.offset, where, 1);
135 if ((r = ReadInt32(X, &v.vnode)))
136 return r;
137 if ((r = ReadInt32(X, &v.vuniq)))
138 return r;
139
140 mk64(offset2k, 0, 2048);
141 if (!LastGoodVNode
142 || ((p->flags & DSFLAG_SEEK) && v.vnode == 1
143 && lt64(v.offset, offset2k)))
144 LastGoodVNode = -1;
145
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));
149 }
150
151 r = ParseTaggedData(X, vnode_fields, tag, pi, g_refcon, (void *)&v);
152
153 /* Try to resync, if requested */
154 if (!r && (p->repair_flags & DSFIX_VFSYNC)) {
155 afs_uint32 drop;
156 dt_uint64 xwhere;
157
158 if ((r = xftell(X, &where)))
159 return r;
160 sub64_32(xwhere, where, 1);
161
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)
165 return r;
166 if (r) { /* Nope. */
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.
170 */
171 drop = r = match_next_vnode(X, p, &v.offset, LastGoodVNode);
172 if (r && r != DSERR_FMT)
173 return r;
174 if (!r) {
175 add64_32(where, v.offset, 1);
176 if ((r = xfseek(X, &v.offset)))
177 return r;
178 } else {
179 if ((r = xfseek(X, &xwhere)))
180 return r;
181 }
182 if ((r = resync_vnode(X, p, &v, 0, 1024)))
183 return r;
184 if ((r = ReadByte(X, tag)))
185 return r;
186 if (drop) {
187 if (p->cb_error)
188 (p->cb_error) (DSERR_FMT, 0, p->err_refcon,
189 "Dropping vnode %d", v.vnode);
190 return 0;
191 }
192 } else {
193 if ((r = xfseek(X, &where)))
194 return r;
195 }
196 }
197 LastGoodVNode = v.vnode;
198
199 if (!r) {
200 if (v.field_mask & F_VNODE_TYPE)
201 switch (v.type) {
202 case vFile:
203 cb = p->cb_vnode_file;
204 break;
205 case vDirectory:
206 cb = p->cb_vnode_dir;
207 break;
208 case vSymlink:
209 cb = p->cb_vnode_link;
210 break;
211 default:
212 cb = p->cb_vnode_wierd;
213 break;
214 } else
215 cb = p->cb_vnode_empty;
216 if (cb) {
217 dt_uint64 where;
218
219 if ((r = xftell(X, &where)))
220 return r;
221 r = (cb) (&v, X, p->refcon);
222 if (p->flags & DSFLAG_SEEK) {
223 if (!r)
224 r = xfseek(X, &where);
225 else
226 xfseek(X, &where);
227 }
228 }
229 }
230 return r;
231 }
232
233
234 /* Store data in a vnode */
235 static afs_uint32
236 store_vnode(XFILE * X, unsigned char *tag, tagged_field * field,
237 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
238 void *l_refcon)
239 {
240 dump_parser *p = (dump_parser *) g_refcon;
241 afs_vnode *v = (afs_vnode *) l_refcon;
242 time_t when;
243 afs_uint32 r = 0;
244
245 switch (field->tag) {
246 case VTAG_TYPE:
247 v->field_mask |= F_VNODE_TYPE;
248 v->type = value;
249 if (p->print_flags & DSPRINT_VNODE) {
250 switch (value) {
251 case vFile:
252 printf("%sFile (%d)\n", field->label, value);
253 break;
254 case vDirectory:
255 printf("%sDirectory (%d)\n", field->label, value);
256 break;
257 case vSymlink:
258 printf("%sSymbolic Link (%d)\n", field->label, value);
259 break;
260 default:
261 printf("%s??? (%d)\n", field->label, value);
262 }
263 return r;
264 }
265 break;
266
267 case VTAG_NLINKS:
268 v->field_mask |= F_VNODE_NLINKS;
269 v->nlinks = value;
270 break;
271
272 case VTAG_DVERS:
273 v->field_mask |= F_VNODE_DVERS;
274 v->datavers = value;
275 break;
276
277 case VTAG_CLIENT_DATE:
278 v->field_mask |= F_VNODE_CDATE;
279 v->client_date = value;
280 break;
281
282 case VTAG_SERVER_DATE:
283 v->field_mask |= F_VNODE_SDATE;
284 v->server_date = value;
285 break;
286
287 case VTAG_AUTHOR:
288 v->field_mask |= F_VNODE_AUTHOR;
289 v->author = value;
290 break;
291
292 case VTAG_OWNER:
293 v->field_mask |= F_VNODE_OWNER;
294 v->owner = value;
295 break;
296
297 case VTAG_GROUP:
298 v->field_mask |= F_VNODE_GROUP;
299 v->group = value;
300 break;
301
302 case VTAG_MODE:
303 v->field_mask |= F_VNODE_MODE;
304 v->mode = value;
305 break;
306
307 case VTAG_PARENT:
308 v->field_mask |= F_VNODE_PARENT;
309 v->parent = value;
310 break;
311 }
312
313 if (p->print_flags & DSPRINT_VNODE)
314 switch (field->kind) {
315 case DKIND_BYTE:
316 case DKIND_INT16:
317 case DKIND_INT32:
318 printf("%s%d\n", field->label, value);
319 break;
320 case DKIND_HEX8:
321 printf("%s0x%02x\n", field->label, value);
322 break;
323 case DKIND_HEX16:
324 printf("%s0x%04x\n", field->label, value);
325 break;
326 case DKIND_HEX32:
327 printf("%s0x%08x\n", field->label, value);
328 break;
329 case DKIND_CHAR:
330 printf("%s%c\n", field->label, value);
331 break;
332 case DKIND_STRING:
333 printf("%s%s\n", field->label, tag);
334 break;
335 case DKIND_FLAG:
336 printf("%s%s\n", field->label, value ? "true" : "false");
337 break;
338 case DKIND_TIME:
339 when = value;
340 printf("%s%s", field->label, ctime(&when));
341 break;
342 }
343 return r;
344 }
345
346
347 static char *
348 rights2str(afs_uint32 rights)
349 {
350 static char str[16];
351 char *p = str;
352
353 if (rights & PRSFS_READ)
354 *p++ = 'r';
355 if (rights & PRSFS_LOOKUP)
356 *p++ = 'l';
357 if (rights & PRSFS_INSERT)
358 *p++ = 'i';
359 if (rights & PRSFS_DELETE)
360 *p++ = 'd';
361 if (rights & PRSFS_WRITE)
362 *p++ = 'w';
363 if (rights & PRSFS_LOCK)
364 *p++ = 'k';
365 if (rights & PRSFS_ADMINISTER)
366 *p++ = 'a';
367 if (rights & PRSFS_USR0)
368 *p++ = 'A';
369 if (rights & PRSFS_USR1)
370 *p++ = 'B';
371 if (rights & PRSFS_USR2)
372 *p++ = 'C';
373 if (rights & PRSFS_USR3)
374 *p++ = 'D';
375 if (rights & PRSFS_USR4)
376 *p++ = 'E';
377 if (rights & PRSFS_USR5)
378 *p++ = 'F';
379 if (rights & PRSFS_USR6)
380 *p++ = 'G';
381 if (rights & PRSFS_USR7)
382 *p++ = 'H';
383
384 *p = 0;
385 if (!str[0])
386 strcpy(str, "none");
387 return str;
388 }
389
390
391 /* Parse and store the ACL data from a directory vnode */
392 static afs_uint32
393 parse_acl(XFILE * X, unsigned char *tag, tagged_field * field,
394 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
395 void *l_refcon)
396 {
397 struct acl_accessList *acl;
398 dump_parser *p = (dump_parser *) g_refcon;
399 afs_vnode *v = (afs_vnode *) l_refcon;
400 afs_uint32 r, i, n;
401
402 if ((r = xfread(X, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE)))
403 return r;
404
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);
409 if (n) {
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)));
414 }
415 n = ntohl(acl->negative);
416 if (n) {
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)));
421 }
422 }
423 return ReadByte(X, tag);
424 }
425
426
427 /* Parse or skip over the vnode data */
428 static afs_uint32
429 parse_vdata(XFILE * X, unsigned char *tag, tagged_field * field,
430 afs_uint32 value, tag_parse_info * pi, void *g_refcon,
431 void *l_refcon)
432 {
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;
437 afs_uint32 r;
438
439 if ((r = ReadInt32(X, &v->size)))
440 return r;
441 v->field_mask |= F_VNODE_SIZE;
442
443 if (v->size) {
444 v->field_mask |= F_VNODE_DATA;
445 if ((r = xftell(X, &v->d_offset)))
446 return r;
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));
451
452 switch (v->type) {
453 case vSymlink:
454 if (v->size > symlink_size) {
455 if (symlink_buf)
456 symlink_buf = realloc(symlink_buf, v->size + 1);
457 else
458 symlink_buf = (char *)malloc(v->size + 1);
459 symlink_size = symlink_buf ? v->size : 0;
460 }
461 if (symlink_buf) {
462 if ((r = xfread(X, symlink_buf, v->size)))
463 return r;
464 symlink_buf[v->size] = 0;
465 if (p->print_flags & DSPRINT_VNODE)
466 printf(" Target: %s\n", symlink_buf);
467 } else {
468 /* Call the callback here, because it's non-fatal */
469 if (p->cb_error)
470 (p->cb_error) (ENOMEM, 0, p->err_refcon,
471 "Out of memory reading symlink");
472 if ((r = xfskip(X, v->size)))
473 return r;
474 }
475 break;
476
477 case vDirectory:
478 if (p->cb_dirent || (p->print_flags & DSPRINT_DIR)) {
479 if ((r = parse_directory(X, p, v, v->size, 0)))
480 return r;
481 break;
482 }
483
484 default:
485 if ((r = xfskip(X, v->size)))
486 return r;
487 }
488 } else if (p->print_flags & DSPRINT_VNODE) {
489 printf("%sEmpty\n", field->label);
490 }
491 if (p->repair_flags & DSFIX_VDSYNC) {
492 r = resync_vnode(X, p, v, 10, 15);
493 if (r)
494 return r;
495 }
496 return ReadByte(X, tag);
497 }