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