test-suite-pull-tools-directly-in-20020114
[openafs.git] / src / tests / 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 *, afs_uint32,
45                            tag_parse_info *, void *, void *);
46 static afs_uint32 parse_acl  (XFILE *, unsigned char *, tagged_field *, afs_uint32,
47                            tag_parse_info *, void *, void *);
48 static afs_uint32 parse_vdata(XFILE *, unsigned char *, tagged_field *, afs_uint32,
49                            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 static afs_uint32 resync_vnode(XFILE *X, dump_parser *p, afs_vnode *v,
69                             int start, int limit)
70 {
71   u_int64 where, expected_where;
72   afs_uint32 r;
73   int i;
74
75   if (r = xftell(X, &expected_where)) return r;
76   cp64(where, expected_where);
77
78   r = match_next_vnode(X, p, &where, v->vnode);
79   if (r && r != DSERR_FMT) return r;
80   if (r) for (i = -start; i < limit; i++) {
81     add64_32(where, expected_where, i);
82     r = match_next_vnode(X, p, &where, v->vnode);
83     if (!r) break;
84     if (r != DSERR_FMT) return r;
85   }
86   if (r) {
87     if (p->cb_error)
88       (p->cb_error)(r, 1, p->err_refcon,
89                     "Unable to resync after vnode %d [%s = 0x%s]",
90                     v->vnode, decimate_int64(&expected_where, 0),
91                     hexify_int64(&expected_where, 0));
92     return r;
93   }
94   if (ne64(where, expected_where) && p->cb_error) {
95     (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
96                   "Vnode after %d not in expected location",
97                   v->vnode);
98     (p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Expected location: %s = 0x%s",
99                   decimate_int64(&expected_where, 0),
100                   hexify_int64(&expected_where, 0));
101     (p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Actual location: %s = 0x%s",
102                   decimate_int64(&where, 0), hexify_int64(&where, 0));
103   }
104   return xfseek(X, &where);
105 }
106
107
108 /* Parse a VNode, including any tagged attributes and data, and call the
109  * appropriate callback, if one is defined.
110  */
111 afs_uint32 parse_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
112                     afs_uint32 value, tag_parse_info *pi,
113                     void *g_refcon, void *l_refcon)
114 {
115   dump_parser *p = (dump_parser *)g_refcon;
116   afs_uint32 (*cb)(afs_vnode *, XFILE *, void *);
117   u_int64 where, offset2k;
118   afs_vnode v;
119   afs_uint32 r;
120
121
122   if (r = xftell(X, &where)) return r;
123   memset(&v, 0, sizeof(v));
124   sub64_32(v.offset, where, 1);
125   if (r = ReadInt32(X, &v.vnode)) return r;
126   if (r = ReadInt32(X, &v.vuniq)) return r;
127
128   mk64(offset2k, 0, 2048);
129   if (!LastGoodVNode
130   || ((p->flags & DSFLAG_SEEK) && v.vnode == 1
131        && lt64(v.offset, offset2k)))
132     LastGoodVNode = -1;
133
134   if (p->print_flags & DSPRINT_ITEM) {
135     printf("%s %d/%d [%s = 0x%s]\n", field->label, v.vnode, v.vuniq,
136            decimate_int64(&where, 0), hexify_int64(&where, 0));
137   }
138
139   r = ParseTaggedData(X, vnode_fields, tag, pi, g_refcon, (void *)&v);
140
141   /* Try to resync, if requested */
142   if (!r && (p->repair_flags & DSFIX_VFSYNC)) {
143     afs_uint32 drop;
144     u_int64 xwhere;
145
146     if (r = xftell(X, &where)) return r;
147     sub64_32(xwhere, where, 1);
148
149     /* Are we at the start of a valid vnode (or dump end)? */
150     r = match_next_vnode(X, p, &xwhere, v.vnode);
151     if (r && r != DSERR_FMT) return r;
152     if (r) { /* Nope. */
153       /* Was _this_ a valid vnode?  If so, we can keep it and search for
154        * the next one.  Otherwise, we throw it out, and start the search
155        * at the starting point of this vnode.
156        */
157       drop = r = match_next_vnode(X, p, &v.offset, LastGoodVNode);
158       if (r && r != DSERR_FMT) return r;
159       if (!r) {
160         add64_32(where, v.offset, 1);
161         if (r = xfseek(X, &v.offset)) return r;
162       } else {
163         if (r = xfseek(X, &xwhere)) return r;
164       }
165       if (r = resync_vnode(X, p, &v, 0, 1024)) return r;
166       if (r = ReadByte(X, tag)) return r;
167       if (drop) {
168         if (p->cb_error)
169           (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
170                         "Dropping vnode %d", v.vnode);
171         return 0;
172       }
173     } else {
174       if (r = xfseek(X, &where)) return r;
175     }
176   }
177   LastGoodVNode = v.vnode;
178
179   if (!r) {
180     if (v.field_mask & F_VNODE_TYPE)
181       switch (v.type) {
182       case vFile:      cb = p->cb_vnode_file;  break;
183       case vDirectory: cb = p->cb_vnode_dir;   break;
184       case vSymlink:   cb = p->cb_vnode_link;  break;
185       default:         cb = p->cb_vnode_wierd; break;
186       }
187     else               cb = p->cb_vnode_empty;
188     if (cb) {
189       u_int64 where;
190
191       if (r = xftell(X, &where)) return r;
192       r = (cb)(&v, X, p->refcon);
193       if (p->flags & DSFLAG_SEEK) {
194         if (!r) r = xfseek(X, &where);
195         else xfseek(X, &where);
196       }
197     }
198   }
199   return r;
200 }
201
202
203 /* Store data in a vnode */
204 static afs_uint32 store_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
205                            afs_uint32 value, tag_parse_info *pi,
206                            void *g_refcon, void *l_refcon)
207 {
208   dump_parser *p = (dump_parser *)g_refcon;
209   afs_vnode *v = (afs_vnode *)l_refcon;
210   time_t when;
211   afs_uint32 r = 0;
212
213   switch (field->tag) {
214   case VTAG_TYPE:
215     v->field_mask |= F_VNODE_TYPE;
216     v->type = value;
217     if (p->print_flags & DSPRINT_VNODE) {
218       switch (value) {
219       case vFile:
220         printf("%sFile (%d)\n", field->label, value);
221         break;
222       case vDirectory:
223         printf("%sDirectory (%d)\n", field->label, value);
224         break;
225       case vSymlink:
226         printf("%sSymbolic Link (%d)\n", field->label, value);
227         break;
228       default:
229         printf("%s??? (%d)\n", field->label, value);
230       }
231       return r;
232     }
233     break;
234
235   case VTAG_NLINKS:
236     v->field_mask |= F_VNODE_NLINKS;
237     v->nlinks = value;
238     break;
239
240   case VTAG_DVERS:
241     v->field_mask |= F_VNODE_DVERS;
242     v->datavers = value;
243     break;
244
245   case VTAG_CLIENT_DATE:
246     v->field_mask |= F_VNODE_CDATE;
247     v->client_date = value;
248     break;
249
250   case VTAG_SERVER_DATE:
251     v->field_mask |= F_VNODE_SDATE;
252     v->server_date = value;
253     break;
254
255   case VTAG_AUTHOR:
256     v->field_mask |= F_VNODE_AUTHOR;
257     v->author = value;
258     break;
259
260   case VTAG_OWNER:
261     v->field_mask |= F_VNODE_OWNER;
262     v->owner = value;
263     break;
264
265   case VTAG_GROUP:
266     v->field_mask |= F_VNODE_GROUP;
267     v->group = value;
268     break;
269
270   case VTAG_MODE:
271     v->field_mask |= F_VNODE_MODE;
272     v->mode = value;
273     break;
274
275   case VTAG_PARENT:
276     v->field_mask |= F_VNODE_PARENT;
277     v->parent = value;
278     break;
279   }
280
281   if (p->print_flags & DSPRINT_VNODE)
282     switch (field->kind) {
283     case DKIND_BYTE:
284     case DKIND_INT16:
285     case DKIND_INT32:  printf("%s%d\n",     field->label, value); break;
286     case DKIND_HEX8:   printf("%s0x%02x\n", field->label, value); break;
287     case DKIND_HEX16:  printf("%s0x%04x\n", field->label, value); break;
288     case DKIND_HEX32:  printf("%s0x%08x\n", field->label, value); break;
289     case DKIND_CHAR:   printf("%s%c\n",     field->label, value); break;
290     case DKIND_STRING: printf("%s%s\n",     field->label, tag);   break;
291     case DKIND_FLAG:
292       printf("%s%s\n", field->label, value ? "true" : "false");
293       break;
294     case DKIND_TIME:
295       when = value;
296       printf("%s%s", field->label, ctime(&when));
297       break;
298   }
299   return r;
300 }
301
302
303 static char *rights2str(afs_uint32 rights)
304 {
305   static char str[16];
306   char *p = str;
307
308   if (rights & PRSFS_READ)       *p++ = 'r';
309   if (rights & PRSFS_LOOKUP)     *p++ = 'l';
310   if (rights & PRSFS_INSERT)     *p++ = 'i';
311   if (rights & PRSFS_DELETE)     *p++ = 'd';
312   if (rights & PRSFS_WRITE)      *p++ = 'w';
313   if (rights & PRSFS_LOCK)       *p++ = 'k';
314   if (rights & PRSFS_ADMINISTER) *p++ = 'a';
315   if (rights & PRSFS_USR0)       *p++ = 'A';
316   if (rights & PRSFS_USR1)       *p++ = 'B';
317   if (rights & PRSFS_USR2)       *p++ = 'C';
318   if (rights & PRSFS_USR3)       *p++ = 'D';
319   if (rights & PRSFS_USR4)       *p++ = 'E';
320   if (rights & PRSFS_USR5)       *p++ = 'F';
321   if (rights & PRSFS_USR6)       *p++ = 'G';
322   if (rights & PRSFS_USR7)       *p++ = 'H';
323
324   *p = 0;
325   if (!str[0]) strcpy(str, "none");
326   return str;
327 }
328
329
330 /* Parse and store the ACL data from a directory vnode */
331 static afs_uint32 parse_acl(XFILE *X, unsigned char *tag, tagged_field *field,
332                          afs_uint32 value, tag_parse_info *pi,
333                          void *g_refcon, void *l_refcon)
334 {
335   struct acl_accessList *acl;
336   dump_parser *p = (dump_parser *)g_refcon;
337   afs_vnode *v = (afs_vnode *)l_refcon;
338   afs_uint32 r, i, n;
339
340   if (r = xfread(X, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE))
341     return r;
342
343   v->field_mask |= F_VNODE_ACL;
344   if (p->print_flags & DSPRINT_ACL) {
345     acl = (struct acl_accessList *)(v->acl);
346     n = ntohl(acl->positive);
347     if (n) {
348       printf("Positive ACL: %d entries\n", n);
349       for (i = 0; i < n; i++)
350         printf("              %9d  %s\n",
351                ntohl(acl->entries[i].id),
352                rights2str(acl->entries[i].rights));
353     }
354     n = ntohl(acl->negative);
355     if (n) {
356       printf("Positive ACL: %d entries\n", n);
357       for (i = ntohl(acl->positive); i < ntohl(acl->total); i++)
358         printf("              %9d  %s\n",
359                ntohl(acl->entries[i].id),
360                rights2str(acl->entries[i].rights));
361     }
362   }
363   return ReadByte(X, tag);
364 }
365
366
367 /* Parse or skip over the vnode data */
368 static afs_uint32 parse_vdata(XFILE *X, unsigned char *tag, tagged_field *field,
369                            afs_uint32 value, tag_parse_info *pi,
370                            void *g_refcon, void *l_refcon)
371 {
372   dump_parser *p = (dump_parser *)g_refcon;
373   afs_vnode *v = (afs_vnode *)l_refcon;
374   static char *symlink_buf = 0;
375   static int symlink_size = 0;
376   afs_uint32 r;
377
378   if (r = ReadInt32(X, &v->size)) return r;
379   v->field_mask |= F_VNODE_SIZE;
380
381   if (v->size) {
382     v->field_mask |= F_VNODE_DATA;
383     if (r = xftell(X, &v->d_offset)) return r;
384     if (p->print_flags & DSPRINT_VNODE)
385       printf("%s%d (0x%08x) bytes at %s (0x%s)\n", field->label,
386              v->size, v->size, decimate_int64(&v->d_offset, 0),
387              hexify_int64(&v->d_offset, 0));
388     
389     switch (v->type) {
390     case vSymlink:
391       if (v->size > symlink_size) {
392         if (symlink_buf) symlink_buf = (char *)realloc(symlink_buf, v->size + 1);
393         else symlink_buf = (char *)malloc(v->size + 1);
394         symlink_size = symlink_buf ? v->size : 0;
395       }
396       if (symlink_buf) {
397         if (r = xfread(X, symlink_buf, v->size)) return r;
398         symlink_buf[v->size] = 0;
399         if (p->print_flags & DSPRINT_VNODE)
400           printf("Target:       %s\n", symlink_buf);
401       } else {
402         /* Call the callback here, because it's non-fatal */
403         if (p->cb_error)
404           (p->cb_error)(ENOMEM, 0, p->err_refcon,
405                         "Out of memory reading symlink");
406         if (r = xfskip(X, v->size)) return r;
407       }
408       break;
409
410     case vDirectory:
411       if (p->cb_dirent || (p->print_flags & DSPRINT_DIR)) {
412         if (r = parse_directory(X, p, v, v->size, 0)) return r;
413         break;
414       }
415
416     default:
417       if (r = xfskip(X, v->size)) return r;
418     }
419   } else if (p->print_flags & DSPRINT_VNODE) {
420     printf("%sEmpty\n", field->label);
421   }
422   if (p->repair_flags & DSFIX_VDSYNC) {
423     r = resync_vnode(X, p, v, 10, 15);
424     if (r) return r;
425   }
426   return ReadByte(X, tag);
427 }