linux: update spec requirements
[openafs.git] / src / tests / repair.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 /* repair.c - Routines to generate a repaired dump */
30
31 #include <sys/types.h>
32 #include <netinet/in.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36
37 #include "dumpscan.h"
38 #include "dumpscan_errs.h"
39 #include "dumpfmt.h"
40
41 #include <afs/acl.h>
42 #include <afs/dir.h>
43 #include <afs/prs_fs.h>
44
45 XFILE repair_output;
46 int repair_verbose;
47 #define RV repair_verbose
48
49 extern afs_uint32 CopyVNodeData(XFILE * OX, XFILE * X, afs_uint32 size);
50 extern afs_uint32 DumpVNodeData(XFILE * OX, char *buf, afs_uint32 size);
51
52 /* Try to dump a dump header.  Generate missing fields, if neccessary */
53 afs_uint32
54 repair_dumphdr_cb(afs_dump_header * hdr, XFILE * X, void *refcon)
55 {
56     afs_uint32 field_mask = hdr->field_mask;
57     char volname[22];
58
59     if (!(field_mask & F_DUMPHDR_VOLID)) {
60         if (RV)
61             fprintf(stderr, ">>> DUMP HEADER missing volume ID\n");
62         return DSERR_FMT;
63     }
64     if (!(field_mask & F_DUMPHDR_VOLNAME)) {
65         if (RV) {
66             fprintf(stderr, ">>> DUMP HEADER missing volume name\n");
67             fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
68         }
69         sprintf(volname, "RESTORED.%d", hdr->volid);
70         hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
71         if (!hdr->volname)
72             return ENOMEM;
73         strcpy((char *)hdr->volname, volname);
74         hdr->field_mask |= F_DUMPHDR_VOLNAME;
75     }
76     if (!(field_mask & F_DUMPHDR_FROM)) {
77         if (RV)
78             fprintf(stderr, ">>> DUMP HEADER missing from time (using 0)\n");
79         hdr->from_date = 0;
80         hdr->field_mask |= F_DUMPHDR_FROM;
81     }
82     if (!(field_mask & F_DUMPHDR_TO)) {
83         hdr->to_date = time(0);
84         if (RV)
85             fprintf(stderr, ">>> DUMP HEADER missing from time (using %d)\n",
86                     hdr->to_date);
87         hdr->field_mask |= F_DUMPHDR_TO;
88     }
89
90     return DumpDumpHeader(&repair_output, hdr);
91 }
92
93
94 /* Try to dump a volume header.  Generate missing fields, if necessary */
95 afs_uint32
96 repair_volhdr_cb(afs_vol_header * hdr, XFILE * X, void *refcon)
97 {
98     afs_uint32 field_mask = hdr->field_mask;
99     char volname[22];
100
101     if (!(field_mask & F_VOLHDR_VOLID)) {
102         if (RV)
103             fprintf(stderr, ">>> VOL HEADER missing volume ID\n");
104         return DSERR_FMT;
105     }
106     if (!(field_mask & F_VOLHDR_VOLVERS)) {
107         if (RV)
108             fprintf(stderr, ">>> VOL HEADER missing version (using 1)\n");
109         hdr->volvers = 1;
110         hdr->field_mask |= F_VOLHDR_VOLVERS;
111     } else if (hdr->volvers != 1) {
112         if (RV)
113             fprintf(stderr, ">>> VOL HEADER bogus version %d (using 1)\n",
114                     hdr->volvers);
115         hdr->volvers = 1;
116     }
117     if (!(field_mask & F_VOLHDR_VOLNAME)) {
118         if (RV) {
119             fprintf(stderr, ">>> VOL HEADER missing volume name\n");
120             fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
121         }
122         sprintf(volname, "RESTORED.%d", hdr->volid);
123         hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
124         if (!hdr->volname)
125             return ENOMEM;
126         strcpy((char *)hdr->volname, volname);
127         hdr->field_mask |= F_VOLHDR_VOLNAME;
128     }
129     if (!(field_mask & F_VOLHDR_INSERV)) {
130         if (RV)
131             fprintf(stderr,
132                     ">>> VOL HEADER missing in-service flag (using 1)\n");
133         hdr->flag_inservice = 1;
134         hdr->field_mask |= F_VOLHDR_INSERV;
135     }
136     if (!(field_mask & F_VOLHDR_BLESSED)) {
137         if (RV)
138             fprintf(stderr,
139                     ">>> VOL HEADER missing blessed flag (using 1)\n");
140         hdr->flag_blessed = 1;
141         hdr->field_mask |= F_VOLHDR_BLESSED;
142     }
143     if (!(field_mask & F_VOLHDR_VOLUNIQ)) {
144         if (RV)
145             fprintf(stderr, ">>> VOL HEADER missing uniquifier (using 1)\n");
146         hdr->voluniq = 1;
147         hdr->field_mask |= F_VOLHDR_VOLUNIQ;
148     }
149     if (!(field_mask & F_VOLHDR_VOLTYPE)) {
150         if (RV)
151             fprintf(stderr, ">>> VOL HEADER missing type (using 0: RW)\n");
152         hdr->voltype = 0;
153         hdr->field_mask |= F_VOLHDR_VOLTYPE;
154     } else if (hdr->voltype < 0 || hdr->voltype > 2) {
155         if (RV)
156             fprintf(stderr, ">>> VOL HEADER bogus type %d (using 0: RW)\n",
157                     hdr->voltype);
158         hdr->voltype = 0;
159     }
160     if (!(field_mask & F_VOLHDR_PARENT)) {
161         if (RV)
162             fprintf(stderr, ">>> VOL HEADER parent (using %d)\n", hdr->volid);
163         hdr->parent_volid = hdr->volid;
164         hdr->field_mask |= F_VOLHDR_PARENT;
165     }
166     if (!(field_mask & F_VOLHDR_MAXQ)) {
167         if (field_mask & F_VOLHDR_DISKUSED)
168             hdr->maxquota = hdr->diskused;
169         else
170             hdr->maxquota = 1;
171         if (RV)
172             fprintf(stderr, ">>> VOL HEADER missing max quota (using %d)\n",
173                     hdr->maxquota);
174         hdr->field_mask |= F_VOLHDR_MAXQ;
175     }
176     if (!(field_mask & F_VOLHDR_DISKUSED)) {
177         if (RV)
178             fprintf(stderr,
179                     ">>> VOL HEADER missing disk used (using 2048)\n");
180         hdr->diskused = 2048;
181         hdr->field_mask |= F_VOLHDR_DISKUSED;
182     }
183     if (!(field_mask & F_VOLHDR_NFILES)) {
184         if (RV)
185             fprintf(stderr, ">>> VOL HEADER missing file count (using 1)\n");
186         hdr->nfiles = 1;
187         hdr->field_mask |= F_VOLHDR_NFILES;
188     }
189     if (!(field_mask & F_VOLHDR_CREATE_DATE)) {
190         hdr->create_date = 0;
191         if ((field_mask & F_VOLHDR_ACCESS_DATE)
192             && (!hdr->create_date || hdr->access_date < hdr->create_date))
193             hdr->create_date = hdr->access_date;
194         if ((field_mask & F_VOLHDR_UPDATE_DATE)
195             && (!hdr->create_date || hdr->update_date < hdr->create_date))
196             hdr->create_date = hdr->update_date;
197         if ((field_mask & F_VOLHDR_BACKUP_DATE)
198             && (!hdr->create_date || hdr->backup_date < hdr->create_date))
199             hdr->create_date = hdr->backup_date;
200
201         if (RV)
202             fprintf(stderr, ">>> VOL HEADER missing create date (using %d)\n",
203                     hdr->create_date);
204         hdr->field_mask |= F_VOLHDR_CREATE_DATE;
205     }
206     if (!(field_mask & F_VOLHDR_ACCESS_DATE)) {
207         hdr->access_date = 0;
208         if ((field_mask & F_VOLHDR_CREATE_DATE)
209             && (!hdr->access_date || hdr->create_date > hdr->access_date))
210             hdr->access_date = hdr->create_date;
211         if ((field_mask & F_VOLHDR_UPDATE_DATE)
212             && (!hdr->access_date || hdr->update_date > hdr->access_date))
213             hdr->access_date = hdr->update_date;
214         if ((field_mask & F_VOLHDR_BACKUP_DATE)
215             && (!hdr->access_date || hdr->backup_date > hdr->access_date))
216             hdr->access_date = hdr->backup_date;
217
218         if (RV)
219             fprintf(stderr, ">>> VOL HEADER missing access date (using %d)\n",
220                     hdr->access_date);
221         hdr->field_mask |= F_VOLHDR_ACCESS_DATE;
222     }
223     if (!(field_mask & F_VOLHDR_UPDATE_DATE)) {
224         hdr->update_date = 0;
225         if ((field_mask & F_VOLHDR_CREATE_DATE)
226             && (!hdr->update_date || hdr->create_date > hdr->update_date))
227             hdr->update_date = hdr->create_date;
228         if ((field_mask & F_VOLHDR_ACCESS_DATE) && !hdr->update_date)
229             hdr->update_date = hdr->access_date;
230         if ((field_mask & F_VOLHDR_BACKUP_DATE) && !hdr->update_date)
231             hdr->update_date = hdr->backup_date;
232
233         if (RV)
234             fprintf(stderr, ">>> VOL HEADER missing update date (using %d)\n",
235                     hdr->update_date);
236         hdr->field_mask |= F_VOLHDR_UPDATE_DATE;
237     }
238
239     return DumpVolumeHeader(&repair_output, hdr);
240 }
241
242
243 /* Try to dump a vnode.  Generate missing fields, if necessary */
244 afs_uint32
245 repair_vnode_cb(afs_vnode * v, XFILE * X, void *refcon)
246 {
247     afs_uint32 r, field_mask = v->field_mask;
248
249     if ((v->vnode & 1) && !field_mask) {
250         if (RV)
251             fprintf(stderr, ">>> VNODE %d is directory but has no fields?\n", v->vnode);
252         v->type = vDirectory;
253         v->field_mask |= F_VNODE_TYPE;
254         field_mask = F_VNODE_TYPE;      /* Messy! */
255     }
256     if (field_mask && !(field_mask & F_VNODE_TYPE)) {
257         v->type = (v->vnode & 1) ? vDirectory : vFile;
258         if (RV)
259             fprintf(stderr, ">>> VNODE %d missing type (using %d)\n",
260                     v->vnode, v->type);
261         v->field_mask |= F_VNODE_TYPE;
262     }
263     if (field_mask && !(field_mask & F_VNODE_NLINKS)) {
264         if (RV)
265             fprintf(stderr, ">>> VNODE %d missing link count (using 1)\n",
266                     v->vnode);
267         v->nlinks = 1;
268         v->field_mask |= F_VNODE_NLINKS;
269     }
270     if (field_mask && !(field_mask & F_VNODE_PARENT)) {
271         if (RV)
272             fprintf(stderr, ">>> VNODE %d missing parent (using 1)\n",
273                     v->vnode);
274         v->parent = 1;
275         v->field_mask |= F_VNODE_PARENT;
276     }
277     if (field_mask && !(field_mask & F_VNODE_DVERS)) {
278         if (RV)
279             fprintf(stderr, ">>> VNODE %d missing data version (using 1)\n",
280                     v->vnode);
281         v->datavers = 1;
282         v->field_mask |= F_VNODE_DVERS;
283     }
284     if (field_mask && !(field_mask & F_VNODE_AUTHOR)) {
285         if (field_mask & F_VNODE_OWNER)
286             v->author = v->owner;
287         else
288             v->author = 0;
289         if (RV)
290             fprintf(stderr, ">>> VNODE %d missing author (using %d)\n",
291                     v->vnode, v->author);
292         v->field_mask |= F_VNODE_AUTHOR;
293     }
294     if (field_mask && !(field_mask & F_VNODE_OWNER)) {
295         if (field_mask & F_VNODE_AUTHOR)
296             v->owner = v->author;
297         else
298             v->owner = 0;
299         if (RV)
300             fprintf(stderr, ">>> VNODE %d missing owner (using %d)\n",
301                     v->vnode, v->owner);
302         v->field_mask |= F_VNODE_OWNER;
303     }
304     if (field_mask && !(field_mask & F_VNODE_MODE)) {
305         v->mode = (v->vnode & 1) ? 0755 : 0644;
306         if (RV)
307             fprintf(stderr, ">>> VNODE missing mode (using %d)\n", v->mode);
308         v->field_mask |= F_VNODE_MODE;
309     }
310     if (field_mask && !(field_mask & F_VNODE_CDATE)) {
311         if (field_mask & F_VNODE_SDATE)
312             v->client_date = v->server_date;
313         else
314             v->client_date = 0;
315
316         if (RV)
317             fprintf(stderr, ">>> VNODE %d missing client date (using %d)\n",
318                     v->vnode, v->client_date);
319         v->field_mask |= F_VNODE_CDATE;
320     }
321     if (field_mask && !(field_mask & F_VNODE_SDATE)) {
322         if (field_mask & F_VNODE_CDATE)
323             v->server_date = v->client_date;
324         else
325             v->server_date = 0;
326
327         if (RV)
328             fprintf(stderr, ">>> VNODE %d missing server date (using %d)\n",
329                     v->vnode, v->server_date);
330         v->field_mask |= F_VNODE_SDATE;
331     }
332     if (field_mask && !(field_mask & F_VNODE_SIZE)) {
333         if (RV)
334             fprintf(stderr, ">>> VNODE %d has no data size (using 0)\n", v->vnode);
335         v->size = 0;
336         v->field_mask |= F_VNODE_SIZE;
337     }
338     if ((field_mask & F_VNODE_DATA) && !v->size) {
339         if (RV)
340             fprintf(stderr,
341                     ">>> VNODE %d has data, but size == 0 (ignoring)\n",
342                     v->vnode);
343         v->field_mask &= ~F_VNODE_DATA;
344     }
345     if (field_mask && v->type == vDirectory && !(field_mask & F_VNODE_ACL)) {
346         struct acl_accessList *acl = (struct acl_accessList *)v->acl;
347         if (RV) {
348             fprintf(stderr, ">>> VNODE %d is directory but has no ACL\n", v->vnode);
349             fprintf(stderr, ">>> Will generate default ACL\n");
350         }
351         memset(v->acl, 0, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
352         acl->size = htonl(SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
353         acl->version = htonl(ACL_ACLVERSION);
354         acl->total = htonl(v->owner ? 0 : 1);
355         acl->positive = acl->total;
356         acl->negative = 0;
357         if (v->owner) {
358             acl->entries[0].id = htonl(v->owner);
359             acl->entries[0].rights =
360                 htonl((PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP
361                        | PRSFS_DELETE | PRSFS_LOCK | PRSFS_ADMINISTER));
362         }
363         v->field_mask |= F_VNODE_ACL;
364     }
365
366     r = DumpVNode(&repair_output, v);
367     if (r)
368         return r;
369
370     if (v->size) {
371         if ((r = xfseek(X, &v->d_offset)))
372             return r;
373         r = CopyVNodeData(&repair_output, X, v->size);
374     } else if (v->type == vDirectory) {
375         afs_dir_page page;
376         struct DirHeader *dhp = (struct DirHeader *)&page;
377         int i;
378
379         if (RV) {
380             fprintf(stderr,
381                     ">>> VNODE %d is directory but has no contents\n", v->vnode);
382             fprintf(stderr, ">>> Will generate deafult directory entries\n");
383         }
384         memset(&page, 0, sizeof(page));
385
386         /* Page and Directory Headers */
387         page.header.tag = htons(1234);
388         page.header.freecount = (EPP - DHE - 3);
389         page.header.freebitmap[0] = 0xff;
390         page.header.freebitmap[1] = 0x7f;
391         dhp->alloMap[0] = EPP - DHE - 3;
392         for (i = 1; i < MAXPAGES; i++)
393             dhp->alloMap[i] = EPP;
394
395         /* Entry for . */
396         page.entry[DHE + 1].flag = FFIRST;
397         page.entry[DHE + 1].length = 1;
398         page.entry[DHE + 1].vnode = v->vnode;
399         page.entry[DHE + 1].vunique = v->vuniq;
400         strcpy(page.entry[DHE + 1].name, ".");
401         dhp->hashTable[0x2e] = DHE + 1;
402
403         /* Entry for .. */
404         page.entry[DHE + 2].flag = FFIRST;
405         page.entry[DHE + 2].length = 1;
406         page.entry[DHE + 2].vnode = v->parent;
407         page.entry[DHE + 2].vunique = 1;        /* Can't have everything! */
408         strcpy(page.entry[DHE + 2].name, "..");
409         dhp->hashTable[0x44] = DHE + 2;
410
411         r = DumpVNodeData(&repair_output, (char *)&page, 2048);
412     } else if (field_mask) {
413         /* We wrote out attributes, so we should also write the 0-length data */
414         r = DumpVNodeData(&repair_output, "", 0);
415     }
416
417     return r;
418 }