Import Upstream version 1.8.5
[hcoop/debian/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 }