make machine-independent by generatibg syswrite.s on the fly;
[unix-history] / usr / src / sbin / restore / symtab.c
CommitLineData
8c5eec2f
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
e0519353 6
8c5eec2f
DF
7#ifndef lint
8static char sccsid[] = "@(#)symtab.c 5.1 (Berkeley) %G%";
9#endif not lint
ebd1f727 10
d27b99b5
KM
11/*
12 * These routines maintain the symbol table which tracks the state
13 * of the file system being restored. They provide lookup by either
14 * name or inode number. They also provide for creation, deletion,
15 * and renaming of entries. Because of the dynamic nature of pathnames,
16 * names should not be saved, but always constructed just before they
17 * are needed, by calling "myname".
18 */
19
e0519353
KM
20#include "restore.h"
21#include <sys/stat.h>
22
d27b99b5
KM
23/*
24 * The following variables define the inode symbol table.
25 * The primary hash table is dynamically allocated based on
26 * the number of inodes in the file system (maxino), scaled by
27 * HASHFACTOR. The variable "entry" points to the hash table;
28 * the variable "entrytblsize" indicates its size (in entries).
29 */
30#define HASHFACTOR 5
a08c9679
KM
31static struct entry **entry;
32static long entrytblsize;
e0519353
KM
33
34/*
35 * Look up an entry by inode number
36 */
37struct entry *
38lookupino(inum)
39 ino_t inum;
40{
a08c9679 41 register struct entry *ep;
e0519353 42
a08c9679
KM
43 if (inum < ROOTINO || inum >= maxino)
44 return (NIL);
45 for (ep = entry[inum % entrytblsize]; ep != NIL; ep = ep->e_next)
46 if (ep->e_ino == inum)
47 return (ep);
48 return (NIL);
e0519353
KM
49}
50
51/*
52 * Add an entry into the entry table
53 */
54addino(inum, np)
a08c9679 55 ino_t inum;
e0519353
KM
56 struct entry *np;
57{
a08c9679 58 struct entry **epp;
6e466853 59
a08c9679
KM
60 if (inum < ROOTINO || inum >= maxino)
61 panic("addino: out of range %d\n", inum);
62 epp = &entry[inum % entrytblsize];
63 np->e_ino = inum;
64 np->e_next = *epp;
65 *epp = np;
66 if (dflag)
67 for (np = np->e_next; np != NIL; np = np->e_next)
68 if (np->e_ino == inum)
69 badentry(np, "duplicate inum");
e0519353
KM
70}
71
72/*
73 * Delete an entry from the entry table
74 */
75deleteino(inum)
a08c9679 76 ino_t inum;
e0519353 77{
a08c9679
KM
78 register struct entry *next;
79 struct entry **prev;
80
81 if (inum < ROOTINO || inum >= maxino)
82 panic("deleteino: out of range %d\n", inum);
83 prev = &entry[inum % entrytblsize];
84 for (next = *prev; next != NIL; next = next->e_next) {
85 if (next->e_ino == inum) {
86 next->e_ino = 0;
87 *prev = next->e_next;
88 return;
89 }
90 prev = &next->e_next;
91 }
92 panic("deleteino: %d not found\n", inum);
e0519353
KM
93}
94
95/*
96 * Look up an entry by name
97 */
98struct entry *
99lookupname(name)
100 char *name;
101{
102 register struct entry *ep;
103 register char *np, *cp;
d27b99b5 104 char buf[MAXPATHLEN];
e0519353
KM
105
106 cp = name;
107 for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
108 for (np = buf; *cp != '/' && *cp != '\0'; )
109 *np++ = *cp++;
110 *np = '\0';
111 for ( ; ep != NIL; ep = ep->e_sibling)
112 if (strcmp(ep->e_name, buf) == 0)
113 break;
114 if (ep == NIL)
115 break;
9f13f26d 116 if (*cp++ == '\0')
e0519353
KM
117 return (ep);
118 }
9f13f26d 119 return (NIL);
e0519353
KM
120}
121
122/*
123 * Look up the parent of a pathname
124 */
125struct entry *
126lookupparent(name)
127 char *name;
128{
129 struct entry *ep;
130 char *tailindex;
131
132 tailindex = rindex(name, '/');
133 if (tailindex == 0)
134 return (NIL);
135 *tailindex = '\0';
136 ep = lookupname(name);
9f13f26d 137 *tailindex = '/';
e0519353
KM
138 if (ep == NIL)
139 return (NIL);
140 if (ep->e_type != NODE)
141 panic("%s is not a directory\n", name);
142 return (ep);
143}
144
145/*
146 * Determine the current pathname of a node or leaf
147 */
148char *
149myname(ep)
150 register struct entry *ep;
151{
152 register char *cp;
d27b99b5 153 static char namebuf[MAXPATHLEN];
e0519353 154
d27b99b5 155 for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
e0519353
KM
156 cp -= ep->e_namlen;
157 bcopy(ep->e_name, cp, (long)ep->e_namlen);
158 if (ep == lookupino(ROOTINO))
159 return (cp);
160 *(--cp) = '/';
161 ep = ep->e_parent;
162 }
163 panic("%s: pathname too long\n", cp);
164 return(cp);
165}
166
d27b99b5
KM
167/*
168 * Unused symbol table entries are linked together on a freelist
169 * headed by the following pointer.
170 */
171static struct entry *freelist = NIL;
172
e0519353
KM
173/*
174 * add an entry to the symbol table
175 */
176struct entry *
177addentry(name, inum, type)
178 char *name;
179 ino_t inum;
180 int type;
181{
182 register struct entry *np, *ep;
183
184 if (freelist != NIL) {
185 np = freelist;
a08c9679 186 freelist = np->e_next;
e0519353
KM
187 bzero((char *)np, (long)sizeof(struct entry));
188 } else {
189 np = (struct entry *)calloc(1, sizeof(struct entry));
ad4fabdf
KM
190 if (np == NIL)
191 panic("no memory to extend symbol table\n");
e0519353 192 }
e0519353
KM
193 np->e_type = type & ~LINK;
194 ep = lookupparent(name);
195 if (ep == NIL) {
196 if (inum != ROOTINO || lookupino(ROOTINO) != NIL)
197 panic("bad name to addentry %s\n", name);
198 np->e_name = savename(name);
199 np->e_namlen = strlen(name);
200 np->e_parent = np;
201 addino(ROOTINO, np);
202 return (np);
203 }
204 np->e_name = savename(rindex(name, '/') + 1);
205 np->e_namlen = strlen(np->e_name);
206 np->e_parent = ep;
207 np->e_sibling = ep->e_entries;
208 ep->e_entries = np;
209 if (type & LINK) {
210 ep = lookupino(inum);
211 if (ep == NIL)
212 panic("link to non-existant name\n");
b99fe9a4 213 np->e_ino = inum;
e0519353
KM
214 np->e_links = ep->e_links;
215 ep->e_links = np;
216 } else if (inum != 0) {
217 if (lookupino(inum) != NIL)
218 panic("duplicate entry\n");
219 addino(inum, np);
220 }
221 return (np);
222}
223
224/*
225 * delete an entry from the symbol table
226 */
227freeentry(ep)
228 register struct entry *ep;
229{
230 register struct entry *np;
40204072 231 ino_t inum;
e0519353 232
e0519353
KM
233 if (ep->e_flags != REMOVED)
234 badentry(ep, "not marked REMOVED");
a08c9679
KM
235 if (ep->e_type == NODE) {
236 if (ep->e_links != NIL)
e0519353
KM
237 badentry(ep, "freeing referenced directory");
238 if (ep->e_entries != NIL)
239 badentry(ep, "freeing non-empty directory");
240 }
a08c9679
KM
241 if (ep->e_ino != 0) {
242 np = lookupino(ep->e_ino);
243 if (np == NIL)
244 badentry(ep, "lookupino failed");
245 if (np == ep) {
40204072
KM
246 inum = ep->e_ino;
247 deleteino(inum);
a08c9679 248 if (ep->e_links != NIL)
40204072 249 addino(inum, ep->e_links);
a08c9679
KM
250 } else {
251 for (; np != NIL; np = np->e_links) {
252 if (np->e_links == ep) {
253 np->e_links = ep->e_links;
254 break;
255 }
e0519353 256 }
a08c9679
KM
257 if (np == NIL)
258 badentry(ep, "link not found");
e0519353 259 }
e0519353
KM
260 }
261 removeentry(ep);
d27b99b5 262 freename(ep->e_name);
a08c9679 263 ep->e_next = freelist;
e0519353
KM
264 freelist = ep;
265}
266
267/*
268 * Relocate an entry in the tree structure
269 */
270moveentry(ep, newname)
271 register struct entry *ep;
272 char *newname;
273{
274 struct entry *np;
275 char *cp;
e0519353
KM
276
277 np = lookupparent(newname);
278 if (np == NIL)
279 badentry(ep, "cannot move ROOT");
280 if (np != ep->e_parent) {
281 removeentry(ep);
282 ep->e_parent = np;
283 ep->e_sibling = np->e_entries;
284 np->e_entries = ep;
285 }
286 cp = rindex(newname, '/') + 1;
d27b99b5
KM
287 freename(ep->e_name);
288 ep->e_name = savename(cp);
289 ep->e_namlen = strlen(cp);
290 if (strcmp(gentempname(ep), ep->e_name) == 0)
e0519353
KM
291 ep->e_flags |= TMPNAME;
292 else
293 ep->e_flags &= ~TMPNAME;
294}
295
296/*
297 * Remove an entry in the tree structure
298 */
299removeentry(ep)
300 register struct entry *ep;
301{
302 register struct entry *np;
303
304 np = ep->e_parent;
305 if (np->e_entries == ep) {
306 np->e_entries = ep->e_sibling;
307 } else {
308 for (np = np->e_entries; np != NIL; np = np->e_sibling) {
309 if (np->e_sibling == ep) {
310 np->e_sibling = ep->e_sibling;
311 break;
312 }
313 }
314 if (np == NIL)
315 badentry(ep, "cannot find entry in parent list");
316 }
317}
318
319/*
d27b99b5
KM
320 * Table of unused string entries, sorted by length.
321 *
322 * Entries are allocated in STRTBLINCR sized pieces so that names
323 * of similar lengths can use the same entry. The value of STRTBLINCR
324 * is chosen so that every entry has at least enough space to hold
325 * a "struct strtbl" header. Thus every entry can be linked onto an
326 * apprpriate free list.
327 *
328 * NB. The macro "allocsize" below assumes that "struct strhdr"
329 * has a size that is a power of two.
330 */
331struct strhdr {
332 struct strhdr *next;
333};
334
335#define STRTBLINCR (sizeof(struct strhdr))
336#define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
337
338static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR];
339
340/*
341 * Allocate space for a name. It first looks to see if it already
342 * has an appropriate sized entry, and if not allocates a new one.
e0519353
KM
343 */
344char *
345savename(name)
346 char *name;
347{
d27b99b5 348 struct strhdr *np;
e0519353 349 long len;
9f13f26d 350 char *cp;
e0519353
KM
351
352 if (name == NULL)
353 panic("bad name\n");
d27b99b5
KM
354 len = strlen(name);
355 np = strtblhdr[len / STRTBLINCR].next;
356 if (np != NULL) {
357 strtblhdr[len / STRTBLINCR].next = np->next;
358 cp = (char *)np;
359 } else {
360 cp = malloc((unsigned)allocsize(len));
361 if (cp == NULL)
362 panic("no space for string table\n");
363 }
a08c9679 364 (void) strcpy(cp, name);
9f13f26d 365 return (cp);
e0519353
KM
366}
367
d27b99b5
KM
368/*
369 * Free space for a name. The resulting entry is linked onto the
370 * appropriate free list.
371 */
372freename(name)
373 char *name;
374{
375 struct strhdr *tp, *np;
376
377 tp = &strtblhdr[strlen(name) / STRTBLINCR];
378 np = (struct strhdr *)name;
379 np->next = tp->next;
380 tp->next = np;
381}
382
383/*
384 * Useful quantities placed at the end of a dumped symbol table.
385 */
386struct symtableheader {
387 long volno;
388 long stringsize;
389 long entrytblsize;
390 time_t dumptime;
391 time_t dumpdate;
392 ino_t maxino;
b97e998a 393 long ntrec;
d27b99b5
KM
394};
395
e0519353
KM
396/*
397 * dump a snapshot of the symbol table
398 */
399dumpsymtable(filename, checkpt)
400 char *filename;
401 long checkpt;
402{
a08c9679
KM
403 register struct entry *ep, *tep;
404 register ino_t i;
405 struct entry temp, *tentry;
406 long mynum = 1, stroff = 0;
e0519353
KM
407 FILE *fd;
408 struct symtableheader hdr;
409
410 vprintf(stdout, "Check pointing the restore\n");
411 if ((fd = fopen(filename, "w")) == NULL) {
412 perror("fopen");
413 panic("cannot create save file %s for symbol table\n",
414 filename);
415 }
416 clearerr(fd);
417 /*
418 * Assign indicies to each entry
419 * Write out the string entries
420 */
421 for (i = ROOTINO; i < maxino; i++) {
422 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
a08c9679 423 ep->e_index = mynum++;
e9a184e3
KM
424 (void) fwrite(ep->e_name, sizeof(char),
425 (int)allocsize(ep->e_namlen), fd);
e0519353
KM
426 }
427 }
e0519353
KM
428 /*
429 * Convert pointers to indexes, and output
430 */
a08c9679
KM
431 tep = &temp;
432 stroff = 0;
e0519353 433 for (i = ROOTINO; i < maxino; i++) {
a08c9679 434 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
e9a184e3
KM
435 bcopy((char *)ep, (char *)tep,
436 (long)sizeof(struct entry));
a08c9679 437 tep->e_name = (char *)stroff;
d27b99b5 438 stroff += allocsize(ep->e_namlen);
a08c9679
KM
439 tep->e_parent = (struct entry *)ep->e_parent->e_index;
440 if (ep->e_links != NIL)
441 tep->e_links =
442 (struct entry *)ep->e_links->e_index;
443 if (ep->e_sibling != NIL)
444 tep->e_sibling =
445 (struct entry *)ep->e_sibling->e_index;
446 if (ep->e_entries != NIL)
447 tep->e_entries =
448 (struct entry *)ep->e_entries->e_index;
449 if (ep->e_next != NIL)
450 tep->e_next =
451 (struct entry *)ep->e_next->e_index;
e9a184e3 452 (void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
e0519353
KM
453 }
454 }
a08c9679
KM
455 /*
456 * Convert entry pointers to indexes, and output
457 */
458 for (i = 0; i < entrytblsize; i++) {
459 if (entry[i] == NIL)
460 tentry = NIL;
461 else
462 tentry = (struct entry *)entry[i]->e_index;
e9a184e3 463 (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
a08c9679 464 }
e0519353
KM
465 hdr.volno = checkpt;
466 hdr.maxino = maxino;
a08c9679 467 hdr.entrytblsize = entrytblsize;
d27b99b5 468 hdr.stringsize = stroff;
2cb5dabb
KM
469 hdr.dumptime = dumptime;
470 hdr.dumpdate = dumpdate;
b97e998a 471 hdr.ntrec = ntrec;
e9a184e3 472 (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
e0519353
KM
473 if (ferror(fd)) {
474 perror("fwrite");
475 panic("output error to file %s writing symbol table\n",
476 filename);
477 }
e9a184e3 478 (void) fclose(fd);
e0519353
KM
479}
480
481/*
482 * Initialize a symbol table from a file
483 */
484initsymtable(filename)
485 char *filename;
486{
487 char *base;
488 long tblsize;
489 register struct entry *ep;
490 struct entry *baseep, *lep;
491 struct symtableheader hdr;
492 struct stat stbuf;
493 register long i;
494 int fd;
495
496 vprintf(stdout, "Initialize symbol table.\n");
a08c9679
KM
497 if (filename == NULL) {
498 entrytblsize = maxino / HASHFACTOR;
499 entry = (struct entry **)
500 calloc((unsigned)entrytblsize, sizeof(struct entry *));
501 if (entry == (struct entry **)NIL)
502 panic("no memory for entry table\n");
021e989e
KM
503 ep = addentry(".", ROOTINO, NODE);
504 ep->e_flags |= NEW;
a08c9679
KM
505 return;
506 }
e0519353
KM
507 if ((fd = open(filename, 0)) < 0) {
508 perror("open");
509 panic("cannot open symbol table file %s\n", filename);
510 }
511 if (fstat(fd, &stbuf) < 0) {
512 perror("stat");
513 panic("cannot stat symbol table file %s\n", filename);
514 }
515 tblsize = stbuf.st_size - sizeof(struct symtableheader);
4b05a065 516 base = calloc(sizeof(char), (unsigned)tblsize);
e0519353
KM
517 if (base == NULL)
518 panic("cannot allocate space for symbol table\n");
519 if (read(fd, base, (int)tblsize) < 0 ||
520 read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
521 perror("read");
522 panic("cannot read symbol table file %s\n", filename);
523 }
2cb5dabb
KM
524 switch (command) {
525 case 'r':
526 /*
527 * For normal continuation, insure that we are using
528 * the next incremental tape
529 */
a08c9679
KM
530 if (hdr.dumpdate != dumptime) {
531 if (hdr.dumpdate < dumptime)
2cb5dabb
KM
532 fprintf(stderr, "Incremental tape too low\n");
533 else
534 fprintf(stderr, "Incremental tape too high\n");
535 done(1);
536 }
537 break;
538 case 'R':
539 /*
540 * For restart, insure that we are using the same tape
541 */
e108d3a2
KM
542 curfile.action = SKIP;
543 dumptime = hdr.dumptime;
544 dumpdate = hdr.dumpdate;
b97e998a
KM
545 if (!bflag)
546 newtapebuf(hdr.ntrec);
e108d3a2 547 getvol(hdr.volno);
2cb5dabb
KM
548 break;
549 default:
550 panic("initsymtable called from command %c\n", command);
551 break;
552 }
e0519353 553 maxino = hdr.maxino;
a08c9679
KM
554 entrytblsize = hdr.entrytblsize;
555 entry = (struct entry **)
556 (base + tblsize - (entrytblsize * sizeof(struct entry *)));
557 baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
558 lep = (struct entry *)entry;
559 for (i = 0; i < entrytblsize; i++) {
e0519353
KM
560 if (entry[i] == NIL)
561 continue;
562 entry[i] = &baseep[(long)entry[i]];
563 }
a08c9679 564 for (ep = &baseep[1]; ep < lep; ep++) {
e0519353
KM
565 ep->e_name = base + (long)ep->e_name;
566 ep->e_parent = &baseep[(long)ep->e_parent];
a08c9679
KM
567 if (ep->e_sibling != NIL)
568 ep->e_sibling = &baseep[(long)ep->e_sibling];
569 if (ep->e_links != NIL)
570 ep->e_links = &baseep[(long)ep->e_links];
571 if (ep->e_entries != NIL)
572 ep->e_entries = &baseep[(long)ep->e_entries];
573 if (ep->e_next != NIL)
574 ep->e_next = &baseep[(long)ep->e_next];
e0519353
KM
575 }
576}