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
= 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
);