1 1.31 andvar /* $NetBSD: symtab.c,v 1.31 2024/02/10 08:24:50 andvar Exp $ */ 2 1.8 cgd 3 1.1 cgd /* 4 1.4 mycroft * Copyright (c) 1983, 1993 5 1.4 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.19 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.11 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.8 cgd #if 0 35 1.13 lukem static char sccsid[] = "@(#)symtab.c 8.3 (Berkeley) 4/28/95"; 36 1.8 cgd #else 37 1.31 andvar __RCSID("$NetBSD: symtab.c,v 1.31 2024/02/10 08:24:50 andvar Exp $"); 38 1.8 cgd #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.1 cgd /* 42 1.1 cgd * These routines maintain the symbol table which tracks the state 43 1.1 cgd * of the file system being restored. They provide lookup by either 44 1.1 cgd * name or inode number. They also provide for creation, deletion, 45 1.1 cgd * and renaming of entries. Because of the dynamic nature of pathnames, 46 1.1 cgd * names should not be saved, but always constructed just before they 47 1.1 cgd * are needed, by calling "myname". 48 1.1 cgd */ 49 1.1 cgd 50 1.3 cgd #include <sys/param.h> 51 1.3 cgd #include <sys/stat.h> 52 1.3 cgd 53 1.4 mycroft #include <ufs/ufs/dinode.h> 54 1.3 cgd 55 1.3 cgd #include <errno.h> 56 1.3 cgd #include <fcntl.h> 57 1.3 cgd #include <stdio.h> 58 1.3 cgd #include <stdlib.h> 59 1.3 cgd #include <string.h> 60 1.3 cgd #include <unistd.h> 61 1.3 cgd 62 1.1 cgd #include "restore.h" 63 1.3 cgd #include "extern.h" 64 1.1 cgd 65 1.1 cgd /* 66 1.1 cgd * The following variables define the inode symbol table. 67 1.1 cgd * The primary hash table is dynamically allocated based on 68 1.1 cgd * the number of inodes in the file system (maxino), scaled by 69 1.1 cgd * HASHFACTOR. The variable "entry" points to the hash table; 70 1.1 cgd * the variable "entrytblsize" indicates its size (in entries). 71 1.1 cgd */ 72 1.1 cgd #define HASHFACTOR 5 73 1.1 cgd static struct entry **entry; 74 1.1 cgd static long entrytblsize; 75 1.1 cgd 76 1.20 xtraeme static void addino(ino_t, struct entry *); 77 1.21 christos static struct entry *lookupparent(const char *); 78 1.20 xtraeme static void removeentry(struct entry *); 79 1.3 cgd 80 1.1 cgd /* 81 1.1 cgd * Look up an entry by inode number 82 1.1 cgd */ 83 1.1 cgd struct entry * 84 1.20 xtraeme lookupino(ino_t inum) 85 1.1 cgd { 86 1.10 lukem struct entry *ep; 87 1.1 cgd 88 1.29 dholland if (inum < UFS_WINO || inum >= maxino) 89 1.3 cgd return (NULL); 90 1.3 cgd for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next) 91 1.1 cgd if (ep->e_ino == inum) 92 1.1 cgd return (ep); 93 1.3 cgd return (NULL); 94 1.1 cgd } 95 1.1 cgd 96 1.1 cgd /* 97 1.1 cgd * Add an entry into the entry table 98 1.1 cgd */ 99 1.3 cgd static void 100 1.20 xtraeme addino(ino_t inum, struct entry *np) 101 1.1 cgd { 102 1.1 cgd struct entry **epp; 103 1.1 cgd 104 1.29 dholland if (inum < UFS_WINO || inum >= maxino) 105 1.30 christos panic("addino: out of range %ju\n", (uintmax_t)inum); 106 1.1 cgd epp = &entry[inum % entrytblsize]; 107 1.1 cgd np->e_ino = inum; 108 1.1 cgd np->e_next = *epp; 109 1.1 cgd *epp = np; 110 1.1 cgd if (dflag) 111 1.3 cgd for (np = np->e_next; np != NULL; np = np->e_next) 112 1.1 cgd if (np->e_ino == inum) 113 1.1 cgd badentry(np, "duplicate inum"); 114 1.1 cgd } 115 1.1 cgd 116 1.1 cgd /* 117 1.1 cgd * Delete an entry from the entry table 118 1.1 cgd */ 119 1.3 cgd void 120 1.20 xtraeme deleteino(ino_t inum) 121 1.1 cgd { 122 1.10 lukem struct entry *next; 123 1.1 cgd struct entry **prev; 124 1.1 cgd 125 1.29 dholland if (inum < UFS_WINO || inum >= maxino) 126 1.30 christos panic("deleteino: out of range %ju\n", 127 1.30 christos (uintmax_t)inum); 128 1.1 cgd prev = &entry[inum % entrytblsize]; 129 1.3 cgd for (next = *prev; next != NULL; next = next->e_next) { 130 1.1 cgd if (next->e_ino == inum) { 131 1.1 cgd next->e_ino = 0; 132 1.1 cgd *prev = next->e_next; 133 1.1 cgd return; 134 1.1 cgd } 135 1.1 cgd prev = &next->e_next; 136 1.1 cgd } 137 1.30 christos panic("deleteino: %ju not found\n", (uintmax_t)inum); 138 1.1 cgd } 139 1.1 cgd 140 1.1 cgd /* 141 1.1 cgd * Look up an entry by name 142 1.1 cgd */ 143 1.1 cgd struct entry * 144 1.21 christos lookupname(const char *name) 145 1.1 cgd { 146 1.10 lukem struct entry *ep; 147 1.21 christos char *np; 148 1.21 christos const char *cp; 149 1.1 cgd char buf[MAXPATHLEN]; 150 1.1 cgd 151 1.1 cgd cp = name; 152 1.29 dholland for (ep = lookupino(UFS_ROOTINO); ep != NULL; ep = ep->e_entries) { 153 1.1 cgd for (np = buf; *cp != '/' && *cp != '\0'; ) 154 1.1 cgd *np++ = *cp++; 155 1.1 cgd *np = '\0'; 156 1.3 cgd for ( ; ep != NULL; ep = ep->e_sibling) 157 1.1 cgd if (strcmp(ep->e_name, buf) == 0) 158 1.1 cgd break; 159 1.3 cgd if (ep == NULL) 160 1.1 cgd break; 161 1.1 cgd if (*cp++ == '\0') 162 1.1 cgd return (ep); 163 1.1 cgd } 164 1.3 cgd return (NULL); 165 1.1 cgd } 166 1.1 cgd 167 1.1 cgd /* 168 1.1 cgd * Look up the parent of a pathname 169 1.1 cgd */ 170 1.3 cgd static struct entry * 171 1.21 christos lookupparent(const char *name) 172 1.1 cgd { 173 1.1 cgd struct entry *ep; 174 1.1 cgd char *tailindex; 175 1.1 cgd 176 1.5 mycroft tailindex = strrchr(name, '/'); 177 1.4 mycroft if (tailindex == NULL) 178 1.3 cgd return (NULL); 179 1.1 cgd *tailindex = '\0'; 180 1.1 cgd ep = lookupname(name); 181 1.1 cgd *tailindex = '/'; 182 1.3 cgd if (ep == NULL) 183 1.3 cgd return (NULL); 184 1.1 cgd if (ep->e_type != NODE) 185 1.1 cgd panic("%s is not a directory\n", name); 186 1.1 cgd return (ep); 187 1.1 cgd } 188 1.1 cgd 189 1.1 cgd /* 190 1.1 cgd * Determine the current pathname of a node or leaf 191 1.1 cgd */ 192 1.1 cgd char * 193 1.20 xtraeme myname(struct entry *ep) 194 1.1 cgd { 195 1.10 lukem char *cp; 196 1.1 cgd static char namebuf[MAXPATHLEN]; 197 1.1 cgd 198 1.1 cgd for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) { 199 1.1 cgd cp -= ep->e_namlen; 200 1.13 lukem memmove(cp, ep->e_name, (long)ep->e_namlen); 201 1.29 dholland if (ep == lookupino(UFS_ROOTINO)) 202 1.1 cgd return (cp); 203 1.1 cgd *(--cp) = '/'; 204 1.1 cgd ep = ep->e_parent; 205 1.1 cgd } 206 1.1 cgd panic("%s: pathname too long\n", cp); 207 1.1 cgd return(cp); 208 1.1 cgd } 209 1.1 cgd 210 1.1 cgd /* 211 1.1 cgd * Unused symbol table entries are linked together on a freelist 212 1.1 cgd * headed by the following pointer. 213 1.1 cgd */ 214 1.3 cgd static struct entry *freelist = NULL; 215 1.1 cgd 216 1.1 cgd /* 217 1.1 cgd * add an entry to the symbol table 218 1.1 cgd */ 219 1.1 cgd struct entry * 220 1.21 christos addentry(const char *name, ino_t inum, int type) 221 1.1 cgd { 222 1.10 lukem struct entry *np, *ep; 223 1.1 cgd 224 1.16 enami if (freelist == NULL) { 225 1.16 enami np = malloc(pagesize); 226 1.3 cgd if (np == NULL) 227 1.1 cgd panic("no memory to extend symbol table\n"); 228 1.16 enami for (ep = (struct entry *)((char *)np + pagesize) - 1; 229 1.16 enami np <= ep; np++) { 230 1.16 enami np->e_next = freelist; 231 1.16 enami freelist = np; 232 1.16 enami } 233 1.1 cgd } 234 1.16 enami np = freelist; 235 1.16 enami freelist = np->e_next; 236 1.24 yamt memset(np, 0, sizeof(struct entry)); 237 1.16 enami 238 1.1 cgd np->e_type = type & ~LINK; 239 1.1 cgd ep = lookupparent(name); 240 1.3 cgd if (ep == NULL) { 241 1.29 dholland if (inum != UFS_ROOTINO || lookupino(UFS_ROOTINO) != NULL) 242 1.1 cgd panic("bad name to addentry %s\n", name); 243 1.1 cgd np->e_name = savename(name); 244 1.1 cgd np->e_namlen = strlen(name); 245 1.1 cgd np->e_parent = np; 246 1.29 dholland addino(UFS_ROOTINO, np); 247 1.1 cgd return (np); 248 1.1 cgd } 249 1.5 mycroft np->e_name = savename(strrchr(name, '/') + 1); 250 1.1 cgd np->e_namlen = strlen(np->e_name); 251 1.1 cgd np->e_parent = ep; 252 1.1 cgd np->e_sibling = ep->e_entries; 253 1.1 cgd ep->e_entries = np; 254 1.1 cgd if (type & LINK) { 255 1.1 cgd ep = lookupino(inum); 256 1.3 cgd if (ep == NULL) 257 1.14 wiz panic("link to non-existent name\n"); 258 1.1 cgd np->e_ino = inum; 259 1.1 cgd np->e_links = ep->e_links; 260 1.1 cgd ep->e_links = np; 261 1.1 cgd } else if (inum != 0) { 262 1.3 cgd if (lookupino(inum) != NULL) 263 1.1 cgd panic("duplicate entry\n"); 264 1.1 cgd addino(inum, np); 265 1.1 cgd } 266 1.1 cgd return (np); 267 1.1 cgd } 268 1.1 cgd 269 1.1 cgd /* 270 1.1 cgd * delete an entry from the symbol table 271 1.1 cgd */ 272 1.3 cgd void 273 1.20 xtraeme freeentry(struct entry *ep) 274 1.1 cgd { 275 1.10 lukem struct entry *np; 276 1.1 cgd ino_t inum; 277 1.1 cgd 278 1.1 cgd if (ep->e_flags != REMOVED) 279 1.1 cgd badentry(ep, "not marked REMOVED"); 280 1.1 cgd if (ep->e_type == NODE) { 281 1.3 cgd if (ep->e_links != NULL) 282 1.1 cgd badentry(ep, "freeing referenced directory"); 283 1.3 cgd if (ep->e_entries != NULL) 284 1.1 cgd badentry(ep, "freeing non-empty directory"); 285 1.1 cgd } 286 1.1 cgd if (ep->e_ino != 0) { 287 1.1 cgd np = lookupino(ep->e_ino); 288 1.3 cgd if (np == NULL) 289 1.1 cgd badentry(ep, "lookupino failed"); 290 1.1 cgd if (np == ep) { 291 1.1 cgd inum = ep->e_ino; 292 1.1 cgd deleteino(inum); 293 1.3 cgd if (ep->e_links != NULL) 294 1.1 cgd addino(inum, ep->e_links); 295 1.1 cgd } else { 296 1.3 cgd for (; np != NULL; np = np->e_links) { 297 1.1 cgd if (np->e_links == ep) { 298 1.1 cgd np->e_links = ep->e_links; 299 1.1 cgd break; 300 1.1 cgd } 301 1.1 cgd } 302 1.3 cgd if (np == NULL) 303 1.1 cgd badentry(ep, "link not found"); 304 1.1 cgd } 305 1.1 cgd } 306 1.1 cgd removeentry(ep); 307 1.1 cgd freename(ep->e_name); 308 1.1 cgd ep->e_next = freelist; 309 1.1 cgd freelist = ep; 310 1.1 cgd } 311 1.1 cgd 312 1.1 cgd /* 313 1.1 cgd * Relocate an entry in the tree structure 314 1.1 cgd */ 315 1.3 cgd void 316 1.22 christos moveentry(struct entry *ep, const char *newname) 317 1.1 cgd { 318 1.1 cgd struct entry *np; 319 1.1 cgd char *cp; 320 1.1 cgd 321 1.1 cgd np = lookupparent(newname); 322 1.3 cgd if (np == NULL) 323 1.1 cgd badentry(ep, "cannot move ROOT"); 324 1.1 cgd if (np != ep->e_parent) { 325 1.1 cgd removeentry(ep); 326 1.1 cgd ep->e_parent = np; 327 1.1 cgd ep->e_sibling = np->e_entries; 328 1.1 cgd np->e_entries = ep; 329 1.1 cgd } 330 1.5 mycroft cp = strrchr(newname, '/') + 1; 331 1.1 cgd freename(ep->e_name); 332 1.1 cgd ep->e_name = savename(cp); 333 1.1 cgd ep->e_namlen = strlen(cp); 334 1.1 cgd if (strcmp(gentempname(ep), ep->e_name) == 0) 335 1.1 cgd ep->e_flags |= TMPNAME; 336 1.1 cgd else 337 1.1 cgd ep->e_flags &= ~TMPNAME; 338 1.1 cgd } 339 1.1 cgd 340 1.1 cgd /* 341 1.1 cgd * Remove an entry in the tree structure 342 1.1 cgd */ 343 1.3 cgd static void 344 1.20 xtraeme removeentry(struct entry *ep) 345 1.1 cgd { 346 1.10 lukem struct entry *np; 347 1.1 cgd 348 1.1 cgd np = ep->e_parent; 349 1.1 cgd if (np->e_entries == ep) { 350 1.1 cgd np->e_entries = ep->e_sibling; 351 1.1 cgd } else { 352 1.3 cgd for (np = np->e_entries; np != NULL; np = np->e_sibling) { 353 1.1 cgd if (np->e_sibling == ep) { 354 1.1 cgd np->e_sibling = ep->e_sibling; 355 1.1 cgd break; 356 1.1 cgd } 357 1.1 cgd } 358 1.3 cgd if (np == NULL) 359 1.1 cgd badentry(ep, "cannot find entry in parent list"); 360 1.1 cgd } 361 1.1 cgd } 362 1.1 cgd 363 1.1 cgd /* 364 1.1 cgd * Table of unused string entries, sorted by length. 365 1.1 cgd * 366 1.1 cgd * Entries are allocated in STRTBLINCR sized pieces so that names 367 1.1 cgd * of similar lengths can use the same entry. The value of STRTBLINCR 368 1.1 cgd * is chosen so that every entry has at least enough space to hold 369 1.1 cgd * a "struct strtbl" header. Thus every entry can be linked onto an 370 1.17 enami * appropriate free list. 371 1.1 cgd * 372 1.1 cgd * NB. The macro "allocsize" below assumes that "struct strhdr" 373 1.1 cgd * has a size that is a power of two. 374 1.1 cgd */ 375 1.1 cgd struct strhdr { 376 1.1 cgd struct strhdr *next; 377 1.1 cgd }; 378 1.1 cgd 379 1.1 cgd #define STRTBLINCR (sizeof(struct strhdr)) 380 1.1 cgd #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1)) 381 1.1 cgd 382 1.3 cgd static struct strhdr strtblhdr[allocsize(NAME_MAX) / STRTBLINCR]; 383 1.1 cgd 384 1.1 cgd /* 385 1.1 cgd * Allocate space for a name. It first looks to see if it already 386 1.1 cgd * has an appropriate sized entry, and if not allocates a new one. 387 1.1 cgd */ 388 1.1 cgd char * 389 1.21 christos savename(const char *name) 390 1.1 cgd { 391 1.18 enami struct strhdr *np, *tp; 392 1.18 enami long len, siz; 393 1.18 enami char *cp, *ep; 394 1.1 cgd 395 1.1 cgd if (name == NULL) 396 1.1 cgd panic("bad name\n"); 397 1.1 cgd len = strlen(name); 398 1.18 enami tp = &strtblhdr[len / STRTBLINCR]; 399 1.18 enami if (tp->next == NULL) { 400 1.18 enami cp = malloc(pagesize); 401 1.1 cgd if (cp == NULL) 402 1.1 cgd panic("no space for string table\n"); 403 1.18 enami for (siz = allocsize(len), ep = (cp + pagesize) - siz; 404 1.18 enami cp <= ep; cp += siz) { 405 1.18 enami np = (struct strhdr *)cp; 406 1.18 enami np->next = tp->next; 407 1.18 enami tp->next = np; 408 1.18 enami } 409 1.1 cgd } 410 1.18 enami np = tp->next; 411 1.18 enami tp->next = np->next; 412 1.18 enami cp = (char *)np; 413 1.1 cgd (void) strcpy(cp, name); 414 1.1 cgd return (cp); 415 1.1 cgd } 416 1.1 cgd 417 1.1 cgd /* 418 1.1 cgd * Free space for a name. The resulting entry is linked onto the 419 1.1 cgd * appropriate free list. 420 1.1 cgd */ 421 1.3 cgd void 422 1.20 xtraeme freename(char *name) 423 1.1 cgd { 424 1.1 cgd struct strhdr *tp, *np; 425 1.1 cgd 426 1.1 cgd tp = &strtblhdr[strlen(name) / STRTBLINCR]; 427 1.1 cgd np = (struct strhdr *)name; 428 1.1 cgd np->next = tp->next; 429 1.1 cgd tp->next = np; 430 1.1 cgd } 431 1.1 cgd 432 1.1 cgd /* 433 1.1 cgd * Useful quantities placed at the end of a dumped symbol table. 434 1.1 cgd */ 435 1.1 cgd struct symtableheader { 436 1.9 cgd int32_t volno; 437 1.9 cgd int32_t stringsize; 438 1.9 cgd int32_t entrytblsize; 439 1.1 cgd time_t dumptime; 440 1.1 cgd time_t dumpdate; 441 1.1 cgd ino_t maxino; 442 1.9 cgd int32_t ntrec; 443 1.1 cgd }; 444 1.1 cgd 445 1.1 cgd /* 446 1.1 cgd * dump a snapshot of the symbol table 447 1.1 cgd */ 448 1.3 cgd void 449 1.21 christos dumpsymtable(const char *filename, int32_t checkpt) 450 1.1 cgd { 451 1.10 lukem struct entry *ep, *tep; 452 1.10 lukem ino_t i; 453 1.25 lukem long l; 454 1.1 cgd struct entry temp, *tentry; 455 1.1 cgd long mynum = 1, stroff = 0; 456 1.1 cgd FILE *fd; 457 1.1 cgd struct symtableheader hdr; 458 1.1 cgd 459 1.26 mbalmer vprintf(stdout, "Checkpointing the restore\n"); 460 1.1 cgd if (Nflag) 461 1.1 cgd return; 462 1.1 cgd if ((fd = fopen(filename, "w")) == NULL) { 463 1.3 cgd fprintf(stderr, "fopen: %s\n", strerror(errno)); 464 1.1 cgd panic("cannot create save file %s for symbol table\n", 465 1.1 cgd filename); 466 1.1 cgd } 467 1.1 cgd clearerr(fd); 468 1.1 cgd /* 469 1.31 andvar * Assign indices to each entry 470 1.1 cgd * Write out the string entries 471 1.1 cgd */ 472 1.29 dholland for (i = UFS_WINO; i <= maxino; i++) { 473 1.3 cgd for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { 474 1.1 cgd ep->e_index = mynum++; 475 1.1 cgd (void) fwrite(ep->e_name, sizeof(char), 476 1.1 cgd (int)allocsize(ep->e_namlen), fd); 477 1.1 cgd } 478 1.1 cgd } 479 1.1 cgd /* 480 1.1 cgd * Convert pointers to indexes, and output 481 1.1 cgd */ 482 1.1 cgd tep = &temp; 483 1.1 cgd stroff = 0; 484 1.29 dholland for (i = UFS_WINO; i <= maxino; i++) { 485 1.3 cgd for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { 486 1.13 lukem memmove(tep, ep, (long)sizeof(struct entry)); 487 1.1 cgd tep->e_name = (char *)stroff; 488 1.1 cgd stroff += allocsize(ep->e_namlen); 489 1.12 mrg tep->e_parent = (struct entry *)(long) 490 1.12 mrg ep->e_parent->e_index; 491 1.3 cgd if (ep->e_links != NULL) 492 1.12 mrg tep->e_links = (struct entry *)(long) 493 1.12 mrg ep->e_links->e_index; 494 1.3 cgd if (ep->e_sibling != NULL) 495 1.12 mrg tep->e_sibling = (struct entry *)(long) 496 1.12 mrg ep->e_sibling->e_index; 497 1.3 cgd if (ep->e_entries != NULL) 498 1.12 mrg tep->e_entries = (struct entry *)(long) 499 1.12 mrg ep->e_entries->e_index; 500 1.3 cgd if (ep->e_next != NULL) 501 1.12 mrg tep->e_next = (struct entry *)(long) 502 1.12 mrg ep->e_next->e_index; 503 1.1 cgd (void) fwrite((char *)tep, sizeof(struct entry), 1, fd); 504 1.1 cgd } 505 1.1 cgd } 506 1.1 cgd /* 507 1.1 cgd * Convert entry pointers to indexes, and output 508 1.1 cgd */ 509 1.25 lukem for (l = 0; l < entrytblsize; l++) { 510 1.25 lukem if (entry[l] == NULL) 511 1.3 cgd tentry = NULL; 512 1.1 cgd else 513 1.25 lukem tentry = (struct entry *)(long)entry[l]->e_index; 514 1.1 cgd (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd); 515 1.1 cgd } 516 1.1 cgd hdr.volno = checkpt; 517 1.1 cgd hdr.maxino = maxino; 518 1.1 cgd hdr.entrytblsize = entrytblsize; 519 1.1 cgd hdr.stringsize = stroff; 520 1.1 cgd hdr.dumptime = dumptime; 521 1.1 cgd hdr.dumpdate = dumpdate; 522 1.1 cgd hdr.ntrec = ntrec; 523 1.1 cgd (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd); 524 1.1 cgd if (ferror(fd)) { 525 1.3 cgd fprintf(stderr, "fwrite: %s\n", strerror(errno)); 526 1.1 cgd panic("output error to file %s writing symbol table\n", 527 1.1 cgd filename); 528 1.1 cgd } 529 1.1 cgd (void) fclose(fd); 530 1.1 cgd } 531 1.1 cgd 532 1.1 cgd /* 533 1.1 cgd * Initialize a symbol table from a file 534 1.1 cgd */ 535 1.3 cgd void 536 1.21 christos initsymtable(const char *filename) 537 1.1 cgd { 538 1.1 cgd char *base; 539 1.1 cgd long tblsize; 540 1.10 lukem struct entry *ep; 541 1.1 cgd struct entry *baseep, *lep; 542 1.1 cgd struct symtableheader hdr; 543 1.1 cgd struct stat stbuf; 544 1.10 lukem long i; 545 1.1 cgd int fd; 546 1.1 cgd 547 1.1 cgd vprintf(stdout, "Initialize symbol table.\n"); 548 1.1 cgd if (filename == NULL) { 549 1.1 cgd entrytblsize = maxino / HASHFACTOR; 550 1.1 cgd entry = (struct entry **) 551 1.1 cgd calloc((unsigned)entrytblsize, sizeof(struct entry *)); 552 1.28 plunky if (entry == NULL) 553 1.1 cgd panic("no memory for entry table\n"); 554 1.29 dholland ep = addentry(".", UFS_ROOTINO, NODE); 555 1.1 cgd ep->e_flags |= NEW; 556 1.1 cgd return; 557 1.1 cgd } 558 1.3 cgd if ((fd = open(filename, O_RDONLY, 0)) < 0) { 559 1.3 cgd fprintf(stderr, "open: %s\n", strerror(errno)); 560 1.1 cgd panic("cannot open symbol table file %s\n", filename); 561 1.1 cgd } 562 1.1 cgd if (fstat(fd, &stbuf) < 0) { 563 1.3 cgd fprintf(stderr, "stat: %s\n", strerror(errno)); 564 1.1 cgd panic("cannot stat symbol table file %s\n", filename); 565 1.1 cgd } 566 1.1 cgd tblsize = stbuf.st_size - sizeof(struct symtableheader); 567 1.15 itojun base = calloc((unsigned)tblsize, sizeof(char)); 568 1.1 cgd if (base == NULL) 569 1.1 cgd panic("cannot allocate space for symbol table\n"); 570 1.1 cgd if (read(fd, base, (int)tblsize) < 0 || 571 1.1 cgd read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) { 572 1.3 cgd fprintf(stderr, "read: %s\n", strerror(errno)); 573 1.1 cgd panic("cannot read symbol table file %s\n", filename); 574 1.1 cgd } 575 1.27 wiz (void)close(fd); 576 1.1 cgd switch (command) { 577 1.1 cgd case 'r': 578 1.1 cgd /* 579 1.1 cgd * For normal continuation, insure that we are using 580 1.1 cgd * the next incremental tape 581 1.1 cgd */ 582 1.1 cgd if (hdr.dumpdate != dumptime) { 583 1.1 cgd if (hdr.dumpdate < dumptime) 584 1.1 cgd fprintf(stderr, "Incremental tape too low\n"); 585 1.1 cgd else 586 1.1 cgd fprintf(stderr, "Incremental tape too high\n"); 587 1.7 mycroft exit(1); 588 1.1 cgd } 589 1.1 cgd break; 590 1.1 cgd case 'R': 591 1.1 cgd /* 592 1.1 cgd * For restart, insure that we are using the same tape 593 1.1 cgd */ 594 1.1 cgd curfile.action = SKIP; 595 1.1 cgd dumptime = hdr.dumptime; 596 1.1 cgd dumpdate = hdr.dumpdate; 597 1.1 cgd if (!bflag) 598 1.1 cgd newtapebuf(hdr.ntrec); 599 1.1 cgd getvol(hdr.volno); 600 1.1 cgd break; 601 1.1 cgd default: 602 1.1 cgd panic("initsymtable called from command %c\n", command); 603 1.1 cgd break; 604 1.1 cgd } 605 1.1 cgd maxino = hdr.maxino; 606 1.1 cgd entrytblsize = hdr.entrytblsize; 607 1.1 cgd entry = (struct entry **) 608 1.1 cgd (base + tblsize - (entrytblsize * sizeof(struct entry *))); 609 1.1 cgd baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); 610 1.1 cgd lep = (struct entry *)entry; 611 1.1 cgd for (i = 0; i < entrytblsize; i++) { 612 1.3 cgd if (entry[i] == NULL) 613 1.1 cgd continue; 614 1.1 cgd entry[i] = &baseep[(long)entry[i]]; 615 1.1 cgd } 616 1.1 cgd for (ep = &baseep[1]; ep < lep; ep++) { 617 1.1 cgd ep->e_name = base + (long)ep->e_name; 618 1.1 cgd ep->e_parent = &baseep[(long)ep->e_parent]; 619 1.3 cgd if (ep->e_sibling != NULL) 620 1.1 cgd ep->e_sibling = &baseep[(long)ep->e_sibling]; 621 1.3 cgd if (ep->e_links != NULL) 622 1.1 cgd ep->e_links = &baseep[(long)ep->e_links]; 623 1.3 cgd if (ep->e_entries != NULL) 624 1.1 cgd ep->e_entries = &baseep[(long)ep->e_entries]; 625 1.3 cgd if (ep->e_next != NULL) 626 1.1 cgd ep->e_next = &baseep[(long)ep->e_next]; 627 1.1 cgd } 628 1.1 cgd } 629