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