1 /* @(#)restore.c 1.81 20/02/05 Copyright 2003-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)restore.c 1.81 20/02/05 Copyright 2003-2020 J. Schilling";
6 #endif
7 /*
8 * Data base management for incremental restores
9 * needed to detect and execute rename() and unlink()
10 * operations between two incremental dumps.
11 *
12 * File renames and file deletions are handled here as well.
13 * Since we cannot immediately know whether a file is deleted
14 * or just renamed, files that disappear from their old location
15 * are first moved to "star-tmpdir" and finally removed from there
16 * when we decide to exit star.
17 *
18 * Copyright (c) 2003-2020 J. Schilling
19 */
20 /*
21 * The contents of this file are subject to the terms of the
22 * Common Development and Distribution License, Version 1.0 only
23 * (the "License"). You may not use this file except in compliance
24 * with the License.
25 *
26 * See the file CDDL.Schily.txt in this distribution for details.
27 * A copy of the CDDL is also available via the Internet at
28 * http://www.opensource.org/licenses/cddl1.txt
29 *
30 * When distributing Covered Code, include this CDDL HEADER in each
31 * file and include the License file CDDL.Schily.txt from this distribution.
32 */
33
34 /*
35 * Problems:
36 *
37 * - lost+found will usually not be extracted and thus
38 * get no new inode number.
39 * **** Solution: Use -U ****
40 *
41 * - chmod(1) only changes st_ctime but star will
42 * extract neither data nor permissions if only
43 * a chmod(1), chown(1) or smilar change did ocur.
44 * **** Solution: Use -U ****
45 *
46 * - unlink(dev) .... create(dev) and get same inode #
47 * **** Solution: sym_typecheck() ****
48 * The Solution creates a new problem that the new
49 * node created after sym_typecheck() may have a
50 * different inode number and we need to change the node.
51 */
52
53 #include <schily/stdio.h>
54 #include <schily/stdlib.h>
55 #include <schily/fcntl.h> /* For AT_REMOVEDIR */
56 #include <schily/unistd.h>
57 #include <schily/standard.h>
58 #include "star.h"
59 #include "props.h"
60 #include "table.h"
61 #include "diff.h"
62 #include <schily/string.h>
63 #define GT_COMERR /* #define comerr gtcomerr */
64 #define GT_ERROR /* #define error gterror */
65 #include <schily/schily.h>
66 #include <schily/dirent.h> /* XXX Wegen S_IFLNK */
67 #include <schily/stat.h> /* XXX Wegen S_IRWXU */
68 #include <schily/errno.h> /* XXX Wegen ENOENT */
69 #include "restore.h"
70 #include "dumpdate.h"
71 #include "starsubs.h"
72 #include <schily/fetchdir.h>
73
74 #define PADD_NODE_DEBUG
75
76 #define PRINT_L_SYM /* Include symbols for star_sym.c */
77
78 extern BOOL debug;
79 extern int xdebug;
80 extern int verbose;
81 extern dev_t curfs;
82 extern BOOL dopartial;
83 extern BOOL forcerestore;
84 extern char *vers;
85 extern GINFO *grip; /* Global read info pointer */
86
87 LOCAL char *overs; /* Star version used with last restore */
88 LOCAL int odtype; /* Old Dump type */
89 LOCAL GINFO *ogp; /* Global information from last restore */
90 EXPORT BOOL restore_valid; /* TRUE when after we did read a valid header */
91 /* Also needed by star_sym.c */
92 EXPORT BOOL is_star = TRUE; /* TRUE with star and we check the version */
93 /* We do not abort if this is for star_sym.c */
94
95 #define HASH_ENTS 1024
96
97 LOCAL imap_t *iroot = NULL; /* The root directory */
98 LOCAL imap_t *itmp = NULL; /* The temp directory star-tmpdir */
99 LOCAL imap_t *isym = NULL; /* The temp directory star-symtable */
100 LOCAL imap_t *imaps = NULL;
101 LOCAL imap_t **himaps = NULL;
102 LOCAL imap_t **hoimaps = NULL;
103 LOCAL imap_t **hnimaps = NULL;
104 #ifdef DEBUG
105 LOCAL int nimp;
106 #endif
107
108 #ifdef PADD_NODE_DEBUG
109 char *padd_node_caller = NULL;
110 #endif
111
112 LOCAL char sym_tmpdir[] = "star-tmpdir";
113 LOCAL char sym_symtable[] = "star-symtable";
114 LOCAL char sym_oldsymtable[] = "star-symtable.old";
115 LOCAL char sym_symdump[] = "star-symdump";
116 LOCAL char sym_lock[] = "star-lock";
117
118 LOCAL ino_t lock_ino;
119
120 LOCAL int hashval __PR((Uchar *str));
121 LOCAL imap_t *nfind_node __PR((char *name, imap_t *idir));
122 LOCAL imap_t *pfind_node __PR((char *name));
123 EXPORT imap_t *padd_node __PR((char *name, ino_t oino, ino_t nino, Int32_t flags));
124 LOCAL imap_t *oifind_node __PR((imap_t *idir, ino_t nino));
125 LOCAL imap_t *nifind_node __PR((imap_t *idir, ino_t nino));
126 LOCAL imap_t *add_node __PR((imap_t *cwd, char *name, ino_t oino, ino_t nino, Int32_t flags));
127 EXPORT imap_t *sym_addrec __PR((FINFO *info));
128 EXPORT void sym_addstat __PR((FINFO *info, imap_t *imp));
129 EXPORT imap_t *sym_dirprerpare __PR((FINFO *info, imap_t *idir));
130 LOCAL void move2tmp __PR((char *dir, char *name, ino_t oino, ino_t nino));
131 LOCAL void move2dir __PR((char *dir, char *name, ino_t oino));
132 EXPORT imap_t *sym_typecheck __PR((FINFO *info, FINFO *cinfo, imap_t *imp));
133 LOCAL BOOL removefile __PR((char *name));
134 LOCAL BOOL removetree __PR((char *name));
135 EXPORT void sym_initmaps __PR((void));
136 EXPORT void sym_open __PR((char *name));
137 LOCAL int xgetline __PR((FILE *f, char **bufp, size_t *lenp, char *name));
138 LOCAL void checknl __PR((FILE *f));
139 LOCAL void sym_initsym __PR((void));
140 LOCAL void tmpnotempty __PR((void));
141 LOCAL void purgeent __PR((imap_t *imp));
142 LOCAL void purgetree __PR((imap_t *imp));
143 EXPORT void sym_init __PR((GINFO *gp));
144 EXPORT void sym_close __PR((void));
145 LOCAL void sym_dump __PR((void));
146 LOCAL void writeheader __PR((FILE *f));
147 LOCAL void readheader __PR((FILE *f));
148 LOCAL void checkheader __PR((void));
149 LOCAL void useforce __PR((void));
150 LOCAL void usepartial __PR((void));
151 LOCAL size_t fullnlen __PR((imap_t *imp, BOOL top));
152 LOCAL char *fullname __PR((imap_t *imp, char *cp, char *ep, BOOL top));
153 LOCAL void printfullname __PR((FILE *f, imap_t *imp));
154 LOCAL void printonesym __PR((FILE *f, imap_t *imp));
155 LOCAL void printsyms __PR((FILE *f, imap_t *imp));
156 #ifdef PRINT_L_SYM
157 LOCAL void printoneLsym __PR((FILE *f, imap_t *imp));
158 LOCAL void printLsyms __PR((FILE *f, imap_t *imp));
159 EXPORT void printLsym __PR((FILE *f));
160 #endif
161 #ifdef __needed__
162 LOCAL BOOL dirdiskonly __PR((FINFO *info, size_t *odep, char ***odp));
163 #endif
164
165 LOCAL int
hashval(str)166 hashval(str)
167 register Uchar *str;
168 {
169 register int sum = 0;
170 register int i;
171 register int c;
172
173 for (i = 0; (c = *str++) != '\0'; i++)
174 sum ^= (c << (i&7));
175 return (sum);
176 }
177
178 /*
179 * Find a node by path name component and directory node pointer
180 */
181 LOCAL imap_t *
nfind_node(name,idir)182 nfind_node(name, idir)
183 char *name;
184 register imap_t *idir;
185 {
186 register imap_t *imp;
187 register char *np;
188 register char *inp;
189 register int nhash;
190
191 np = name;
192 if (np[0] == '\0')
193 return (idir);
194 if (np[0] == '.') {
195 if (np[1] == '\0')
196 return (idir);
197 if (np[1] == '.' && np[2] == '\0')
198 return (idir->i_dparent);
199 }
200 nhash = hashval((Uchar *)name);
201 imp = himaps[nhash%HASH_ENTS];
202
203 for (; imp; imp = imp->i_hnext) {
204
205 if (nhash != imp->i_hash)
206 continue;
207 if (imp->i_dparent != idir)
208 continue;
209 if (imp->i_flags & I_DELETE)
210 continue;
211
212 np = name;
213 inp = imp->i_name;
214 while (*inp) {
215 if (*np++ != *inp++)
216 goto nextmatch;
217 }
218 if (np[0] == '\0')
219 break;
220 nextmatch:
221 ;
222 }
223 return (imp);
224 }
225
226 /*
227 * Find a node by full path name
228 */
229 LOCAL imap_t *
pfind_node(name)230 pfind_node(name)
231 char *name;
232 {
233 register imap_t *imp = iroot;
234 register char *np = name;
235 register char *sp;
236
237 if (imp == NULL)
238 return (imp);
239
240 while (*np) {
241 if ((sp = strchr(np, '/')) != NULL)
242 *sp = '\0';
243 if ((imp->i_flags & I_DIR) == 0) {
244 errmsgno(EX_BAD,
245 "pfind_node(): Not a directory '%s' for '%s' flags %X i_dir %p.\n",
246 imp->i_name, name,
247 imp->i_flags, imp->i_dir);
248 return (NULL);
249 }
250 imp = nfind_node(np, imp);
251 if (sp)
252 *sp = '/';
253 else
254 break;
255 np = &sp[1];
256 if (imp == NULL)
257 break;
258 }
259 return (imp);
260 }
261
262 /*
263 * Add a new full path name and return a node pointer
264 * Also used by star_sym.c
265 */
266 EXPORT imap_t *
padd_node(name,oino,nino,flags)267 padd_node(name, oino, nino, flags)
268 char *name;
269 ino_t oino;
270 ino_t nino;
271 Int32_t flags;
272 {
273 register imap_t *imp = iroot;
274 register imap_t *idir;
275 register char *np = name;
276 register char *sp;
277
278 if (imp == NULL) {
279 if ((np[0] == '.' && np[1] == '\0') ||
280 (np[0] == '.' && np[1] == '/' && np[2] == '\0')) {
281 imp = add_node(NULL, ".", oino, nino, flags);
282 imp->i_dparent = imp;
283 iroot = imp;
284 return (imp);
285 }
286 comerrno(EX_BAD, "Panic no root to add '%s'.\n", name);
287 /* NOTREACHED */
288 }
289
290 while (*np) {
291 if ((sp = strchr(np, '/')) != NULL)
292 *sp = '\0';
293
294 if ((imp->i_flags & I_DIR) == 0) {
295 #ifdef PADD_NODE_DEBUG
296 errmsgno(EX_BAD, "padd_node(): caller '%s'.\n", padd_node_caller);
297 #endif
298 errmsgno(EX_BAD,
299 "padd_node(): Not a directory '%s' for '%s' flags %X i_dir %p.\n",
300 imp->i_name, name,
301 imp->i_flags, imp->i_dir);
302 return (NULL);
303 }
304 idir = imp;
305 imp = nfind_node(np, idir);
306 if (imp == NULL) {
307 if (sp != NULL && strchr(&sp[1], '/') != NULL)
308 imp = add_node(idir, np, 0, 0, I_DIR);
309 else
310 imp = add_node(idir, np, oino, nino, flags);
311 }
312 if (sp)
313 *sp = '/';
314 else
315 break;
316 np = &sp[1];
317 }
318 if (imp->i_oino == 0 && oino != 0) {
319 int hv;
320
321 imp->i_oino = oino;
322 hv = oino % HASH_ENTS;
323 imp->i_honext = hoimaps[hv];
324 hoimaps[hv] = imp;
325 }
326 if (imp->i_nino == 0 && nino != 0) {
327 int hv;
328
329 /*
330 * This is (most likely) a temporary node.
331 * We need to set up the flags acording to the right file.
332 */
333 if (imp->i_flags != 0) {
334 /*
335 * Not a temporarary node found?
336 */
337 #ifdef PADD_NODE_DEBUG
338 errmsgno(EX_BAD, "padd_node(): caller '%s'.\n", padd_node_caller);
339 #endif
340 errmsgno(EX_BAD,
341 "padd_node(): Panic: Flags 0x%X on temp node '%s' for '%s'.\n",
342 imp->i_flags, imp->i_name, name);
343 }
344 imp->i_flags = flags;
345 imp->i_nino = nino;
346 hv = nino % HASH_ENTS;
347 imp->i_hnnext = hnimaps[hv];
348 hnimaps[hv] = imp;
349 }
350 return (imp);
351 }
352
353 /*
354 * Find a node by old inode number
355 */
356 LOCAL imap_t *
oifind_node(idir,oino)357 oifind_node(idir, oino)
358 imap_t *idir;
359 ino_t oino;
360 {
361 register imap_t *imp;
362
363 imp = hoimaps[oino%HASH_ENTS];
364
365 for (; imp; imp = imp->i_honext) {
366
367 if (imp->i_flags & I_DELETE)
368 continue;
369 if (idir && idir != imp->i_dparent)
370 continue;
371
372 /*
373 * XXX Dies ist eine halbfertige Directory.
374 * XXX Hoffentlich brauchen wir diesen Knoten nie.
375 */
376 if (imp->i_nino == 0)
377 continue;
378 if (oino == imp->i_oino)
379 break;
380 }
381 return (imp);
382 }
383
384 /*
385 * Find a node by new inode number
386 */
387 LOCAL imap_t *
nifind_node(idir,nino)388 nifind_node(idir, nino)
389 imap_t *idir;
390 ino_t nino;
391 {
392 register imap_t *imp;
393
394 imp = hnimaps[nino%HASH_ENTS];
395
396 for (; imp; imp = imp->i_hnnext) {
397
398 if (imp->i_flags & I_DELETE)
399 continue;
400 if (idir && idir != imp->i_dparent)
401 continue;
402 if (nino == imp->i_nino)
403 break;
404 }
405 return (imp);
406 }
407
408 /*
409 * Add a new node by path name component and directory node pointer
410 * return a node pointer
411 */
412 LOCAL imap_t *
add_node(cwd,name,oino,nino,flags)413 add_node(cwd, name, oino, nino, flags)
414 imap_t *cwd;
415 char *name;
416 ino_t oino;
417 ino_t nino;
418 Int32_t flags;
419 {
420 register imap_t *imp;
421 register int hv;
422
423 imp = ___malloc(sizeof (imap_t), "new imap");
424 imp->i_name = ___savestr(name);
425 imp->i_hash = hashval((Uchar *)imp->i_name);
426 imp->i_oino = oino;
427 imp->i_nino = nino;
428 imp->i_flags = flags;
429 imp->i_next = imaps;
430 imaps = imp;
431
432 imp->i_dir = NULL;
433 imp->i_dnext = NULL;
434 imp->i_dxnext = NULL;
435 imp->i_dparent = cwd;
436 if (cwd) {
437 imp->i_dxnext = cwd->i_dir;
438 cwd->i_dir = imp;
439 }
440
441 hv = imp->i_hash % HASH_ENTS;
442 imp->i_hnext = himaps[hv];
443 himaps[hv] = imp;
444
445 if (oino) {
446 hv = oino % HASH_ENTS;
447 imp->i_honext = hoimaps[hv];
448 hoimaps[hv] = imp;
449 } else {
450 imp->i_honext = NULL;
451 }
452 if (nino) {
453 hv = nino % HASH_ENTS;
454 imp->i_hnnext = hnimaps[hv];
455 hnimaps[hv] = imp;
456 } else {
457 imp->i_hnnext = NULL;
458 }
459 #ifdef DEBUG
460 nimp++;
461 #endif
462
463 return (imp);
464 }
465
466 /*
467 * Add a record for a file. If this is a directory, add entries for the
468 * directory content.
469 */
470 EXPORT imap_t *
sym_addrec(info)471 sym_addrec(info)
472 FINFO *info;
473 {
474 imap_t *imp;
475 BOOL isold = TRUE;
476
477 #ifdef XXX_DEBUG
478 if (grip->dumplevel > 0) {
479 error("sym_addrec(%s) Type %s\n",
480 info->f_name, XTTONAME(info->f_rxftype));
481 }
482 #endif
483 if ((imp = pfind_node(info->f_name)) == NULL) {
484 isold = FALSE;
485 #ifdef PADD_NODE_DEBUG
486 padd_node_caller = "sym_addrec";
487 #endif
488 imp = padd_node(info->f_name, info->f_ino, (ino_t)0, 0);
489 #ifdef PADD_NODE_DEBUG
490 if (imp == NULL)
491 errmsgno(EX_BAD, "padd_node(%s, %lld, 0, 0) = NULL\n",
492 info->f_name, (Llong)info->f_ino);
493 #endif
494 } else {
495 #ifdef XXX_DEBUG
496 if (grip->dumplevel > 0) {
497 error("sym_addrec(%s) found dir: %d TYPECHANGE: %d\n",
498 info->f_name,
499 imp->i_flags & I_DIR,
500 is_dir(info) != ((imp->i_flags & I_DIR) != 0));
501 }
502 #endif
503 }
504 if (imp == NULL) {
505 sym_dump();
506 comerrno(EX_BAD,
507 "Panic: cannot add node '%s' in sym_addrec().\n",
508 info->f_name);
509 /* NOTREACHED */
510 }
511
512 if (is_dir(info)) {
513 /*
514 * If the node for the name of this dir is an old node and
515 * does not have the DIR flag set, we may not set up the dir
516 * content as we later will move this node away and create a
517 * new one for the new dir that is going to be created.
518 */
519 if (isold && (imp->i_flags & I_DIR) == 0)
520 return (imp);
521
522 imp->i_flags |= I_DIR;
523 }
524
525 if (is_dir(info)) {
526 imap_t *idir;
527 char *dp;
528 ino_t *ip;
529 size_t len;
530 size_t i;
531
532 idir = imp;
533 dp = info->f_dir;
534 ip = info->f_dirinos;
535 if (dp == NULL || ip == NULL)
536 return (idir);
537
538 i = 0;
539 while (*dp) {
540 dp++;
541 len = strlen(dp);
542
543 if ((imp = nfind_node(dp, idir)) == NULL) {
544 imp = add_node(idir, dp, (ino_t)0, (ino_t)0, 0);
545 }
546 if (imp->i_oino == (ino_t)0) {
547 int hv;
548
549 imp->i_oino = ip[i];
550 hv = imp->i_oino % HASH_ENTS;
551 imp->i_honext = hoimaps[hv];
552 hoimaps[hv] = imp;
553 }
554 i++;
555 dp += len+1;
556 }
557 return (idir);
558 }
559 return (imp);
560 }
561
562 /*
563 * Add status information for a node.
564 */
565 EXPORT void
sym_addstat(info,imp)566 sym_addstat(info, imp)
567 FINFO *info;
568 imap_t *imp;
569 {
570 FINFO finfo;
571 BOOL isold = TRUE;
572 int hv;
573
574 if (imp == NULL && (imp = pfind_node(info->f_name)) == NULL) {
575 isold = FALSE;
576 #ifdef PADD_NODE_DEBUG
577 padd_node_caller = "sym_addstat";
578 #endif
579 imp = padd_node(info->f_name, info->f_ino, (ino_t)0, 0);
580 #ifdef PADD_NODE_DEBUG
581 if (imp == NULL)
582 errmsgno(EX_BAD, "padd_node(%s, %lld, 0, 0) = NULL\n",
583 info->f_name, (Llong)info->f_ino);
584 #endif
585 }
586 if (imp == NULL) {
587 sym_dump();
588 comerrno(EX_BAD,
589 "Panic: cannot add node '%s' in sym_addstat().\n",
590 info->f_name);
591 /* NOTREACHED */
592 }
593 if (imp->i_oino == 0) {
594 if (imp != iroot) {
595 errmsgno(EX_BAD,
596 "WARNING: late old inode add for '%s'\n", info->f_name);
597 }
598 imp->i_oino = info->f_ino;
599 hv = imp->i_oino % HASH_ENTS;
600 imp->i_honext = hoimaps[hv];
601 hoimaps[hv] = imp;
602 }
603
604 fillbytes((char *)&finfo, sizeof (finfo), '\0');
605 _getinfo(info->f_name, &finfo);
606 if (imp->i_nino != 0 && imp->i_nino != finfo.f_ino) {
607 errmsgno(EX_BAD, "sym_addstat(): %s nino change from %lld to %lld flags %X\n",
608 info->f_name,
609 (Llong)imp->i_nino, (Llong)finfo.f_ino,
610 imp->i_flags);
611 }
612
613 /*
614 * An nino change implies a hash change. We need to remove the node
615 * from the old hash list and put it into the new list.
616 */
617 if (imp->i_nino != finfo.f_ino) {
618 BOOL newhash = FALSE;
619
620 if ((imp->i_nino != 0) &&
621 ((imp->i_nino % HASH_ENTS) != (finfo.f_ino % HASH_ENTS))) {
622 imap_t *tnp;
623
624 tnp = hnimaps[imp->i_nino % HASH_ENTS];
625 for (; tnp; tnp = tnp->i_hnnext) {
626 if (imp == tnp->i_hnnext) {
627 tnp->i_hnnext = imp->i_hnnext;
628 break;
629 }
630 }
631 newhash = TRUE;
632 }
633
634 if (imp->i_nino == 0 || newhash) {
635 hv = finfo.f_ino % HASH_ENTS;
636 imp->i_hnnext = hnimaps[hv];
637 hnimaps[hv] = imp;
638 }
639 imp->i_nino = finfo.f_ino;
640 }
641
642 if (is_dir(info)) {
643 size_t len = strlen(imp->i_name);
644
645 if (len > 0 && imp->i_name[len-1] == '/')
646 imp->i_name[len-1] = '\0';
647 imp->i_flags |= I_DIR;
648 }
649 }
650
651 /*
652 * Prepare the directory for the following extraction.
653 * This is done by first removing all files that are no longer present on the
654 * current incremental and then trying to move/link missing files that are
655 * a result of a rename or link operation.
656 */
657 EXPORT imap_t *
sym_dirprepare(info,idir)658 sym_dirprepare(info, idir)
659 FINFO *info;
660 imap_t *idir;
661 {
662 size_t dlen;
663 ino_t *oino;
664 char **dname;
665 char *p;
666 size_t i;
667 size_t j;
668 FINFO finfo;
669 char *dp2;
670 size_t ents2;
671 char **dname2;
672 ino_t *ino2;
673 ino_t *oino2;
674 char *slashp = NULL;
675 DIR *dirp;
676
677 if (info->f_dir == NULL) {
678 /*
679 * Most likely a mount point
680 */
681 if (info->f_dev == curfs) {
682 lunlinkat(sym_lock, 0);
683 comerrno(EX_BAD, "Archive contains directory '%s' without name list\n", info->f_name);
684 /* NOTREACHED */
685 }
686 return (idir);
687 }
688
689 #ifdef DIRP_DEBUG
690 if (!_getinfo(info->f_name, &finfo) && geterrno() != ENOENT)
691 errmsg("DEBUG1: stat for '%s' failed.\n",
692 info->f_name);
693 #endif
694 /*
695 * Try to work around a moving POSIX target.
696 * POSIX.1-1988 requires that stat("/etc/passwd/", ) works.
697 * While POSIX.1-2001 requires to return ENOTDIR.
698 */
699 info->f_namelen = strlen(info->f_name);
700 if (info->f_name[info->f_namelen-1] == '/') {
701 slashp = &info->f_name[info->f_namelen-1];
702 *slashp = '\0';
703 }
704 /*
705 * Check if the node on disk is really a directory.
706 * As we did already check the directory content of the higher direcory
707 * it should never happen that the on disk node is not a directory.
708 */
709 fillbytes((char *)&finfo, sizeof (finfo), '\0');
710 seterrno(0);
711 (void) _getinfo(info->f_name, &finfo);
712
713 if (!is_dir(&finfo)) { /* Also catches the ENOENT case */
714 /*
715 * There is either no file on disk, we cannot stat() it, or
716 * the file on the disk has the same name and inode number
717 * as the directory in the archive.
718 * XXX Should we rather use move2tmp()?
719 */
720 imap_t *imp;
721
722 imp = idir;
723 if (geterrno() != ENOENT) {
724 if (lunlinkat(info->f_name, 0) < 0)
725 comerr("Cannot unlink '%s'.\n", info->f_name);
726 }
727 #ifdef MKD_DEBUG
728 { extern char *mkdwhy; mkdwhy = "restore"; }
729 #endif
730 if (!make_adir(info)) {
731 if (slashp)
732 *slashp = '/';
733 return (imp);
734 }
735 if ((imp->i_flags & I_DIR) == 0) {
736 purgeent(imp);
737 imp = sym_addrec(info);
738 }
739 if (!_getinfo(info->f_name, &finfo)) {
740 if (slashp)
741 *slashp = '/';
742 return (imp);
743 }
744 sym_addstat(&finfo, imp);
745 idir = imp;
746 }
747 if (slashp)
748 *slashp = '/';
749
750 if ((dname = ___malloc(info->f_dirents * sizeof (char *), "sym_dirprepare name")) == NULL) {
751 return (idir);
752 }
753 /*
754 * Put directory names from archive into array.
755 */
756 p = info->f_dir;
757 oino = info->f_dirinos;
758 dlen = info->f_dirents;
759 for (i = 0; i < dlen; i++) {
760 dname[i] = &p[1];
761 p += strlen(&p[1]) + 2;
762 }
763
764 #ifdef RES_DEBUG
765 for (i = 0; i < dlen; i++) {
766 error("INO %lld NAME %s\n",
767 (Llong)info->f_dirinos[i],
768 dname[i]);
769 }
770 #endif
771
772 ents2 = 0;
773 dirp = lopendir(info->f_name);
774 if (dirp == NULL) {
775 return (idir);
776 } else {
777 dp2 = dfetchdir(dirp, info->f_name, &ents2, 0, &ino2);
778 closedir(dirp);
779 }
780 if ((oino2 = ___malloc(ents2 * sizeof (ino_t), "sym_dirprepare oino2")) == NULL) {
781 return (idir);
782 }
783 if ((dname2 = ___malloc(ents2 * sizeof (char *), "sym_dirprepare name2")) == NULL) {
784 return (idir);
785 }
786 /*
787 * Put directory names from disk into array.
788 */
789 p = dp2;
790 for (i = 0; i < ents2; i++) {
791 dname2[i] = &p[1];
792 p += strlen(&p[1]) + 2;
793 }
794 for (i = 0; i < ents2; i++) {
795 imap_t *imp;
796 imp = nifind_node((imap_t *)0, ino2[i]);
797 if (imp == NULL) {
798 if (ino2[i] != lock_ino) {
799 errmsgno(EX_BAD,
800 "Panic: No symbol entry for inode %lld (%s).\n",
801 (Llong)ino2[i], dname2[i]);
802 }
803 oino2[i] = 0;
804 continue;
805 }
806 if (imp->i_oino == (ino_t)0) {
807 if (imp != itmp && imp != isym) {
808 errmsgno(EX_BAD,
809 "Panic: No old inode for inode %lld (%s).\n",
810 (Llong)ino2[i], dname2[i]);
811 }
812 }
813 oino2[i] = imp->i_oino;
814 }
815
816 if (xdebug)
817 error("sym_dirprepare(%s)\n", info->f_name);
818 /*
819 * Check for all files that are in the current on disk directory
820 * but no longer exist on the current incremental with the same
821 * name and inode number as before.
822 */
823 for (i = 0; i < ents2; i++) {
824 ino_t in;
825 if (oino2[i] == 0)
826 continue;
827 in = oino2[i];
828
829 if (xdebug)
830 error("Checking ino %lld (%s)...", (Llong)oino2[i], dname2[i]);
831 for (j = 0; j < dlen; j++) {
832 if (xdebug > 1)
833 error("in %lld oino %lld\n", (Llong)in, (Llong)oino[j]);
834 if (in == oino[j] && streql(dname2[i], dname[j]))
835 break;
836 }
837 if (j >= dlen) {
838 if (xdebug)
839 error("RM\n");
840 /* dir name, file name, old inode#, new inode # */
841 move2tmp(info->f_name, dname2[i], in, ino2[i]);
842 } else {
843 if (xdebug)
844 error("found\n");
845 }
846 }
847
848 if (xdebug)
849 error("sym_dirprepare(%s) <<<<\n", info->f_name);
850 /*
851 * Check for all files that are on the current incremental but
852 * are not in the current on disk directory with the same
853 * and inode number.
854 */
855 for (i = 0; i < dlen; i++) {
856 ino_t in;
857 in = oino[i];
858
859 if (xdebug)
860 error("Checking ino %lld (%s)...", (Llong)oino[i], dname[i]);
861 for (j = 0; j < ents2; j++) {
862 if (in == oino2[j] && streql(dname2[j], dname[i]))
863 break;
864 }
865 if (j >= ents2) {
866 if (xdebug)
867 error("LINK\n");
868 /* dir name, file name, old inode# */
869 move2dir(info->f_name, dname[i], in);
870 } else {
871 if (xdebug)
872 error("found\n");
873 }
874 }
875
876 if (dname != NULL)
877 free(dname);
878 if (oino2 != NULL)
879 free(oino2);
880 if (dname2 != NULL)
881 free(dname2);
882 if (dp2 != NULL)
883 free(dp2);
884 if (ino2 != NULL)
885 free(ino2);
886 return (idir);
887 }
888
889 /*
890 * Move a file to the temp directory. This file has been identified
891 * to be no longer in the current directory pointed to by 'dir'.
892 */
893 LOCAL void
move2tmp(dir,name,oino,nino)894 move2tmp(dir, name, oino, nino)
895 char *dir;
896 char *name;
897 ino_t oino;
898 ino_t nino;
899 {
900 char path[2*PATH_MAX+1];
901 char tpath[2*PATH_MAX+1]; /* "star-tmpdir/#%lld" */
902 char *pathp = path;
903 size_t pathlen = sizeof (path);
904 size_t plen;
905 imap_t *onp;
906 imap_t *nnp;
907
908 plen = strlen(dir) + strlen(name) + 2; /* "%s/%s" + Nul */
909 if (plen > pathlen) {
910 pathp = ___malloc(plen, "name buffer");
911 pathlen = plen;
912 }
913 js_snprintf(pathp, pathlen, "%s/%s", dir, name);
914
915 onp = pfind_node(pathp);
916 if (onp == NULL) {
917 sym_dump();
918 comerrno(EX_BAD,
919 "Panic: amnesia in inode data base for '%s'.\n",
920 pathp);
921 /* NOTREACHED */
922 }
923 nnp = nifind_node(itmp, nino);
924 if (nnp) { /* inode is already in star-tmpdir */
925 if (xdebug)
926 error("unlink(%s)\n", pathp);
927 if (lunlinkat(pathp, 0) < 0)
928 comerr("Cannot unlink '%s'.\n", pathp);
929 purgeent(onp);
930 goto out;
931 }
932
933 js_snprintf(tpath, sizeof (tpath), "%s/#%lld", sym_tmpdir, (Llong)nino);
934 if (xdebug)
935 error("rename(%s, %s)\n", pathp, tpath);
936 if (lrename(pathp, tpath) < 0)
937 comerr("Cannot rename '%s' to '%s'.\n", pathp, tpath);
938
939 #ifdef PADD_NODE_DEBUG
940 padd_node_caller = "move2tmp";
941 #endif
942 nnp = padd_node(tpath, onp->i_oino, onp->i_nino, onp->i_flags);
943 #ifdef PADD_NODE_DEBUG
944 if (nnp == NULL)
945 errmsgno(EX_BAD, "padd_node(%s, %lld, %lld, %X) = NULL\n",
946 tpath, (Llong)onp->i_oino,
947 (Llong)onp->i_nino, onp->i_flags);
948 #endif
949 if (xdebug)
950 error("move2tmp() itmp %p onp %p nnp %p\n", itmp, onp, nnp);
951
952 purgeent(onp);
953 nnp->i_dir = onp->i_dir;
954 for (onp = nnp->i_dir; onp; onp = onp->i_dxnext) {
955 onp->i_dparent = nnp;
956 }
957 out:
958 if (pathp != path)
959 free(pathp);
960 }
961
962 /*
963 * Try to move a file from the temp directory to the current directory
964 * pointed to by 'dir'.
965 */
966 LOCAL void
move2dir(dir,name,oino)967 move2dir(dir, name, oino)
968 char *dir;
969 char *name;
970 ino_t oino;
971 {
972 char path[2*PATH_MAX+1];
973 char *pathp = path;
974 size_t pathlen = sizeof (path);
975 char tpath[2*PATH_MAX+1];
976 char *tpathp = tpath;
977 size_t tpathlen = sizeof (tpath);
978 imap_t *onp;
979 imap_t *nnp;
980 char *p;
981 size_t plen;
982
983 plen = strlen(dir) + strlen(name) + 2;
984 if (plen > pathlen) {
985 pathp = ___malloc(plen, "name buffer");
986 pathlen = plen;
987 }
988 js_snprintf(pathp, pathlen, "%s/%s", dir, name);
989 onp = oifind_node(itmp, oino);
990
991 #ifdef RES_DEBUG
992 if (onp)
993 error("move2dir(%s, %s, %lld) = %s\n",
994 dir, name, (Llong)oino, onp->i_name);
995 else
996 error("move2dir(%s, %s, %lld) = NOT FOUND\n",
997 dir, name, (Llong)oino);
998 #endif
999
1000 if (onp) {
1001 /*
1002 * Since our static buffer is 2*PATH_MAX, we cannot get more
1003 * here because "star-tmpdir" + one path name component cannot
1004 * result in more than 2*256 chars and PATH_MAX is at least 256.
1005 */
1006 js_snprintf(tpath, sizeof (tpath), "%s/%s",
1007 sym_tmpdir, onp->i_name);
1008 if (xdebug)
1009 error("rename(%s, %s)\n", tpath, pathp);
1010 if (lrename(tpath, pathp) < 0) {
1011 errmsg("Cannot rename '%s' to '%s'.\n", tpath, pathp);
1012 /* XXX set error code */
1013 goto out;
1014 }
1015 #ifdef PADD_NODE_DEBUG
1016 padd_node_caller = "move2dir";
1017 #endif
1018 nnp = padd_node(pathp, onp->i_oino, onp->i_nino, onp->i_flags);
1019 #ifdef PADD_NODE_DEBUG
1020 if (nnp == NULL)
1021 errmsgno(EX_BAD, "padd_node(%s, %lld, %lld, %X) = NULL\n",
1022 pathp, (Llong)onp->i_oino,
1023 (Llong)onp->i_nino, onp->i_flags);
1024 #endif
1025 if (xdebug) {
1026 error("move2dir() itmp %p onp %p nnp %p\n",
1027 itmp, onp, nnp);
1028 }
1029 purgeent(onp);
1030 nnp->i_dir = onp->i_dir;
1031 for (onp = nnp->i_dir; onp; onp = onp->i_dxnext) {
1032 onp->i_dparent = nnp;
1033 }
1034 goto out;
1035 }
1036
1037 /*
1038 * XXX Wenn nicht in star-tmpdir, dann
1039 *
1040 * - hard link zu File versuchen
1041 *
1042 * - rename einer Directory versuchen und Flag setzen
1043 *
1044 * - Ist Flag gesetzt, dann Hard Link auf Dir setzen.
1045 */
1046 if (xdebug)
1047 error("Cannot rename '%s' from '%s'.\n", pathp, sym_tmpdir);
1048
1049 onp = oifind_node((imap_t *)0, oino);
1050 if (onp == NULL) {
1051 if (xdebug)
1052 error("Cannot link/move any file to '%s'.\n",
1053 pathp);
1054 goto out;
1055 }
1056 plen = fullnlen(onp, TRUE);
1057 if (plen == 0) {
1058 /* XXX error code */
1059 errmsgno(EX_BAD, "Path name '");
1060 printfullname(stderr, onp);
1061 error("' cannot rename\n");
1062 goto out;
1063 }
1064 if (plen > tpathlen) {
1065 tpathp = ___malloc(plen, "name buffer");
1066 tpathlen = plen;
1067 }
1068 p = fullname(onp, tpathp, &tpathp[tpathlen], TRUE);
1069 if (p == NULL) {
1070 /* XXX error code */
1071 errmsgno(EX_BAD, "Path name '");
1072 printfullname(stderr, onp);
1073 error("' too long, cannot rename\n");
1074 goto out;
1075 }
1076 if (xdebug)
1077 error("move2dir(%s, %s, %lld) found path => '%s'\n",
1078 dir, name, (Llong)oino, tpathp);
1079
1080 if ((onp->i_flags & (I_DIR|I_DID_RENAME)) == I_DIR) {
1081 if (xdebug)
1082 error("rename(%s, %s)\n", tpathp, pathp);
1083 if (lrename(tpathp, pathp) < 0) {
1084 /* XXX error code */
1085 errmsg("Cannot rename(%s, %s)\n", tpathp, pathp);
1086 } else {
1087 #ifdef PADD_NODE_DEBUG
1088 padd_node_caller = "move2dir 2";
1089 #endif
1090 nnp = padd_node(pathp, onp->i_oino, onp->i_nino, onp->i_flags);
1091 #ifdef PADD_NODE_DEBUG
1092 if (nnp == NULL)
1093 errmsgno(EX_BAD, "padd_node(%s, %lld, %lld, %X) = NULL\n",
1094 pathp, (Llong)onp->i_oino,
1095 (Llong)onp->i_nino, onp->i_flags);
1096 #endif
1097 purgeent(onp);
1098 nnp->i_flags |= I_DID_RENAME;
1099 if ((onp->i_flags & I_DIR) == 0)
1100 comerrno(EX_BAD, "Panic: Not a dir '%s'.\n", pathp);
1101 nnp->i_dir = onp->i_dir;
1102 for (onp = nnp->i_dir; onp; onp = onp->i_dxnext) {
1103 onp->i_dparent = nnp;
1104 }
1105 }
1106 goto out;
1107 }
1108 if (xdebug)
1109 error("link(%s, %s)\n", tpathp, pathp);
1110 #ifdef HAVE_LINK
1111 if (llink(tpathp, pathp) < 0) {
1112 #else
1113 if (1) {
1114 #ifdef ENOSYS
1115 seterrno(ENOSYS);
1116 #else
1117 seterrno(EINVAL);
1118 #endif
1119 #endif
1120 /* XXX error code */
1121 errmsg("Cannot link(%s, %s)\n", tpathp, pathp);
1122 } else {
1123 #ifdef PADD_NODE_DEBUG
1124 padd_node_caller = "move2dir 3";
1125 #endif
1126 nnp = padd_node(pathp, onp->i_oino, onp->i_nino, onp->i_flags);
1127 #ifdef PADD_NODE_DEBUG
1128 if (nnp == NULL)
1129 errmsgno(EX_BAD, "padd_node(%s, %lld, %lld, %X) = NULL\n",
1130 pathp, (Llong)onp->i_oino,
1131 (Llong)onp->i_nino, onp->i_flags);
1132 #endif
1133 #ifdef __never__
1134 /*
1135 * XXX It is not clear how to handle new hard links
1136 * XXX to directories correctly.
1137 */
1138 nnp->i_dir = onp->i_dir;
1139 for (onp = nnp->i_dir; onp; onp = onp->i_dxnext) {
1140 onp->i_dparent = nnp;
1141 }
1142 #endif
1143 }
1144 out:
1145 if (pathp != path)
1146 free(pathp);
1147 if (tpathp != tpath)
1148 free(tpathp);
1149 }
1150
1151 /*
1152 * Check whether the target file exists and has a
1153 * different type or is a dev node with different
1154 * major/minor numbers. In this case, we need to
1155 * remove the file. This happend when the original
1156 * file has been removed and a new (different) file
1157 * with the same name did get the same inode number.
1158 */
1159 EXPORT imap_t *
sym_typecheck(info,cinfo,imp)1160 sym_typecheck(info, cinfo, imp)
1161 FINFO *info;
1162 FINFO *cinfo;
1163 imap_t *imp;
1164 {
1165 char *slashp = NULL;
1166 extern BOOL uncond;
1167 extern BOOL nowarn;
1168 BOOL ouncond = uncond;
1169 BOOL onowarn = nowarn;
1170
1171 #ifdef RES2_DEBUG
1172 error("sym_typecheck(%s) NEW type: %s\n",
1173 info->f_name,
1174 XTTONAME(info->f_rxftype));
1175 #endif
1176 #ifdef RES2_DEBUG
1177 seterrno(0);
1178 #endif
1179 /*
1180 * Try to work around a moving POSIX target.
1181 * POSIX.1-1988 requires that stat("/etc/passwd/", ) works.
1182 * While POSIX.1-2001 requires to return ENOTDIR.
1183 */
1184 info->f_namelen = strlen(info->f_name);
1185 if (info->f_name[info->f_namelen-1] == '/') {
1186 slashp = &info->f_name[info->f_namelen-1];
1187 *slashp = '\0';
1188 }
1189 fillbytes((char *)cinfo, sizeof (*cinfo), '\0');
1190 if (!_getinfo(info->f_name, cinfo)) {
1191 cinfo->f_rxftype = XT_NONE;
1192 #ifdef RES2_DEBUG
1193 errmsg("sym_typecheck(%s) ---> OLD FILE NOT found\n",
1194 info->f_name);
1195 #endif
1196 if (slashp)
1197 *slashp = '/';
1198 return (imp);
1199 }
1200
1201 #ifdef RES2_DEBUG
1202 error("sym_typecheck(%s) OLD FILE found, type: %s\n",
1203 info->f_name,
1204 XTTONAME(cinfo->f_rxftype));
1205 #endif
1206
1207 if (info->f_filetype == cinfo->f_filetype &&
1208 !is_special(cinfo) && !is_symlink(cinfo)) {
1209 if (slashp)
1210 *slashp = '/';
1211 if (!(cinfo->f_mode & TUWRITE)) {
1212 #ifdef RES2_DEBUG
1213 error("sym_typecheck(%s) OLD FILE mode: %o\n",
1214 info->f_name, cinfo->f_mode);
1215 #endif
1216 /*
1217 * Need to give write permissions to allow to run
1218 * "star -restore" as non-root user.
1219 *
1220 * info->f_mode | TUWRITE may be closer to the
1221 * final modes than cinfo->f_mode | TUWRITE.
1222 */
1223 if (lchmodat(info->f_name,
1224 osmode(info->f_mode | TUWRITE),
1225 0 /* chmod */) < 0) {
1226 errmsg("Cannot chmod +w '%s'\n",
1227 info->f_name);
1228 }
1229 }
1230 return (imp);
1231 }
1232
1233 uncond = FALSE;
1234 nowarn = TRUE;
1235 if (is_symlink(cinfo) && same_symlink(cinfo))
1236 cinfo->f_flags |= F_SAME;
1237 if (is_special(cinfo) && same_special(cinfo))
1238 cinfo->f_flags |= F_SAME;
1239 uncond = ouncond;
1240 onowarn = nowarn;
1241
1242 if ((is_symlink(cinfo) || is_special(cinfo)) &&
1243 (cinfo->f_flags & F_SAME) == 0) {
1244 #ifdef RES2_DEBUG
1245 error("sym_typecheck(%s) REMOVE OLD\n",
1246 info->f_name);
1247 #endif
1248 removefile(info->f_name);
1249 purgeent(imp);
1250 if (slashp)
1251 *slashp = '/';
1252 return (NULL);
1253 }
1254
1255 if (info->f_type == cinfo->f_type) {
1256 if (slashp)
1257 *slashp = '/';
1258 return (imp);
1259 }
1260
1261 if (imp == NULL) {
1262 if (slashp)
1263 *slashp = '/';
1264 return (imp);
1265 }
1266
1267 if (is_dir(cinfo)) {
1268 imap_t *cmp;
1269
1270 #ifdef RES2_DEBUG
1271 error("sym_typecheck(%s) MOVE DIRCONT\n",
1272 info->f_name);
1273 #endif
1274 for (cmp = imp->i_dir; cmp; cmp = cmp->i_dxnext) {
1275 if (cmp->i_flags & I_DELETE)
1276 continue;
1277
1278 move2tmp(info->f_name, cmp->i_name, cmp->i_oino, cmp->i_nino);
1279 }
1280 }
1281
1282 #ifdef RES2_DEBUG
1283 error("sym_typecheck(%s) REMOVE OLD\n",
1284 info->f_name);
1285 #endif
1286 removefile(info->f_name);
1287 purgeent(imp);
1288 if (slashp)
1289 *slashp = '/';
1290 return (NULL);
1291 }
1292
1293 LOCAL BOOL
removefile(name)1294 removefile(name)
1295 char *name;
1296 {
1297 extern BOOL force_remove;
1298 BOOL of = force_remove;
1299 BOOL ret;
1300
1301 if (xdebug)
1302 error("REMOVE %s\n", name);
1303
1304 force_remove = TRUE;
1305 ret = remove_file(name, TRUE);
1306 force_remove = of;
1307 return (ret);
1308 }
1309
1310 LOCAL BOOL
removetree(name)1311 removetree(name)
1312 char *name;
1313 {
1314 extern BOOL force_remove;
1315 extern BOOL remove_recursive;
1316 BOOL of = force_remove;
1317 BOOL or = remove_recursive;
1318 BOOL ret;
1319
1320 if (xdebug)
1321 error("REMOVE tree %s\n", name);
1322
1323 force_remove = TRUE;
1324 remove_recursive = TRUE;
1325 ret = remove_file(name, TRUE);
1326 force_remove = of;
1327 remove_recursive = or;
1328 return (ret);
1329 }
1330
1331 /*
1332 * Needed separately by star_sym
1333 */
1334 EXPORT void
sym_initmaps()1335 sym_initmaps()
1336 {
1337 if (himaps == NULL) {
1338 register int hv;
1339
1340 himaps = ___malloc(HASH_ENTS * sizeof (imap_t *), "imap hash");
1341 hoimaps = ___malloc(HASH_ENTS * sizeof (imap_t *), "oimap hash");
1342 hnimaps = ___malloc(HASH_ENTS * sizeof (imap_t *), "nimap hash");
1343 for (hv = 0; hv < HASH_ENTS; hv++) {
1344 himaps[hv] = 0;
1345 hoimaps[hv] = 0;
1346 hnimaps[hv] = 0;
1347 }
1348 }
1349 }
1350
1351 /*
1352 * Read in the old inode symbol table
1353 */
1354 EXPORT void
sym_open(name)1355 sym_open(name)
1356 char *name;
1357 {
1358 char *buf;
1359 size_t buflen = PATH_MAX;
1360 FILE *f;
1361 ssize_t amt;
1362 char *p;
1363 Llong ll;
1364 ino_t oino;
1365 ino_t nino;
1366 mode_t old_umask;
1367 static char td[] = "star-tmpdir/.";
1368 imap_t *ilast = NULL;
1369 imap_t *icwd = NULL;
1370 FINFO finfo;
1371
1372 #define PERM_BITS (S_IRWXU|S_IRWXG|S_IRWXO) /* u/g/o basic perm */
1373
1374 if (name)
1375 f = lfilemopen(name, "r", S_IRUSR|S_IWUSR);
1376 else
1377 f = lfilemopen(sym_symtable, "r", S_IRUSR|S_IWUSR);
1378
1379 fillbytes((char *)&finfo, sizeof (finfo), '\0');
1380 if (_getinfo(sym_symtable, &finfo) && !is_file(&finfo)) {
1381 errmsgno(EX_BAD, "'%s' is not a file.\n", sym_symtable);
1382 comerrno(EX_BAD, "Remove '%s' and try again.\n", sym_symtable);
1383 }
1384 sym_initmaps();
1385
1386 old_umask = umask((mode_t)0);
1387 umask(PERM_BITS & ~S_IRWXU);
1388 if (!create_dirs(td)) {
1389 /*
1390 * This also fails if star-tmpdir is not a directory.
1391 */
1392 comerrno(EX_BAD, "Cannot create '%s'.\n", sym_tmpdir);
1393 }
1394 umask(old_umask);
1395
1396 if (f == NULL)
1397 return;
1398
1399 buf = ___malloc(buflen, "line buffer");
1400 (void) xgetline(f, &buf, &buflen, sym_symtable);
1401 if (!streql(buf, vers)) {
1402 errmsgno(EX_BAD, "Restore version mismatch '%s' '%s'.\n",
1403 buf, vers);
1404 if (is_star) {
1405 comerrno(EX_BAD,
1406 "All restores need to be done with the same star version.\n");
1407 }
1408 }
1409 overs = ___savestr(buf); /* Restore SCHILY.release */
1410
1411 readheader(f);
1412
1413 while ((amt = getdelim(&buf, &buflen, '\0', f)) > 0) {
1414 Int32_t flags;
1415
1416 checknl(f);
1417
1418 if (buf[0] == '>' && buf[1] == '\0') {
1419 if (iroot == NULL) {
1420 iroot = icwd = ilast;
1421 icwd->i_dparent = icwd;
1422 if (icwd->i_name[0] != '.' || icwd->i_name[1] != '\0')
1423 comerrno(EX_BAD, "Bad root dir '%s' in '%s'.\n",
1424 icwd->i_name,
1425 sym_symtable);
1426 } else {
1427 icwd->i_dnext = ilast;
1428 if (ilast->i_dparent != icwd)
1429 comerrno(EX_BAD, "Bad parent dir.\n");
1430 ilast->i_dparent = icwd;
1431 icwd = ilast;
1432 }
1433 continue;
1434 }
1435 if (buf[0] == '<' && buf[1] == '\0') {
1436 icwd = icwd->i_dparent;
1437 icwd->i_dnext = NULL;
1438 continue;
1439 }
1440
1441 p = buf;
1442 flags = 0;
1443 if (*p == 'D')
1444 flags |= I_DIR;
1445
1446 p++; /* Skip Flag */
1447 p = astollb(p, &ll, 10);
1448 if (*p != '\t') {
1449 comerrno(EX_BAD,
1450 "Missing TAB after old ino in '%s'.\n",
1451 sym_symtable);
1452 }
1453 oino = ll;
1454 p = astollb(p, &ll, 10);
1455 if (*p != '\t') {
1456 comerrno(EX_BAD,
1457 "Missing TAB after NEW ino '%s'.\n",
1458 sym_symtable);
1459 }
1460 nino = ll;
1461 ilast = add_node(icwd, ++p, oino, nino, flags);
1462 #ifdef __needed__
1463 if (0) {
1464 imap_t *ip = iroot;
1465
1466 for (; ip; ip = ip->i_dnext) {
1467 printf("%s/", ip->i_name);
1468 if (ip == icwd)
1469 break;
1470 }
1471 printf("%s\n", p);
1472 }
1473 #endif
1474 }
1475 fclose(f);
1476 free(buf);
1477
1478 #ifdef OLDSYM_DEBUG
1479 printsyms(stderr, iroot);
1480 printLsyms(stderr, iroot);
1481 #endif
1482 }
1483
1484 LOCAL int
xgetline(f,bufp,lenp,name)1485 xgetline(f, bufp, lenp, name)
1486 FILE *f;
1487 char **bufp;
1488 size_t *lenp;
1489 char *name;
1490 {
1491 ssize_t amt;
1492
1493 clearerr(f);
1494 if ((amt = getdelim(bufp, lenp, '\0', f)) < 0) {
1495 if (feof(f)) {
1496 amt = 0;
1497 } else {
1498 comerr("Cannot read '%s'.\n", name);
1499 }
1500 }
1501 if (amt == 0)
1502 comerrno(EX_BAD, "File '%s' too short.\n", name);
1503 checknl(f);
1504 return (amt);
1505 }
1506
1507 LOCAL void
checknl(f)1508 checknl(f)
1509 FILE *f;
1510 {
1511 if (getc(f) != '\n') {
1512 comerrno(EX_BAD,
1513 "Missing newline at end of record in '%s'.\n",
1514 sym_symtable);
1515 }
1516 }
1517
1518 /*
1519 * Make sure "star-tmpdir" exists and is part of the inode symbol cache.
1520 * Make sure that "star-symtable" is part of the inode symbol cache if
1521 * it exists.
1522 */
1523 LOCAL void
sym_initsym()1524 sym_initsym()
1525 {
1526 char tpath[2*PATH_MAX+1];
1527 FINFO finfo;
1528 imap_t *imp;
1529 char *dp;
1530 size_t ents;
1531 DIR *dirp;
1532
1533 fillbytes((char *)&finfo, sizeof (finfo), '\0');
1534 if (!_getinfo(sym_tmpdir, &finfo)) {
1535 lunlinkat(sym_lock, 0);
1536 comerr("Cannot stat '%s'\n", sym_tmpdir);
1537 }
1538
1539 if (iroot == NULL) {
1540 #ifdef PADD_NODE_DEBUG
1541 padd_node_caller = "sym_initsym";
1542 #endif
1543 imp = padd_node(".", (ino_t)0, (ino_t)0, I_DIR);
1544 }
1545 if ((imp = pfind_node(sym_tmpdir)) == NULL) {
1546 #ifdef PADD_NODE_DEBUG
1547 padd_node_caller = "sym_initsym 2";
1548 #endif
1549 imp = padd_node(sym_tmpdir, (ino_t)0, finfo.f_ino, I_DIR);
1550 }
1551 if (imp->i_nino != finfo.f_ino)
1552 errmsgno(EX_BAD, "sym_initsym(): %s nino change from %lld to %lld flags %X\n",
1553 sym_tmpdir,
1554 (Llong)imp->i_nino, (Llong)finfo.f_ino,
1555 imp->i_flags);
1556
1557 imp->i_nino = finfo.f_ino;
1558 itmp = imp;
1559
1560 for (imp = imp->i_dir; imp; imp = imp->i_dxnext) {
1561 if (imp->i_flags & I_DELETE)
1562 continue;
1563
1564 js_snprintf(tpath, sizeof (tpath), "%s/%s",
1565 sym_tmpdir, imp->i_name);
1566 if (!_getinfo(tpath, &finfo))
1567 purgetree(imp);
1568 else
1569 tmpnotempty();
1570 }
1571 ents = 0;
1572 dirp = lopendir(sym_tmpdir);
1573 if (dirp) {
1574 dp = dfetchdir(dirp, sym_tmpdir, &ents, 0, (ino_t **)0);
1575 closedir(dirp);
1576 } else {
1577 dp = NULL;
1578 }
1579 if (dp)
1580 free(dp);
1581 if (ents > 0)
1582 tmpnotempty();
1583
1584 fillbytes((char *)&finfo, sizeof (finfo), '\0');
1585 if (_getinfo(sym_symtable, &finfo)) {
1586 if ((imp = pfind_node(sym_symtable)) == NULL) {
1587 #ifdef PADD_NODE_DEBUG
1588 padd_node_caller = "sym_initsym 3";
1589 #endif
1590 imp = padd_node(sym_symtable, (ino_t)0, finfo.f_ino, 0);
1591 }
1592 isym = imp;
1593 }
1594 }
1595
1596 LOCAL void
tmpnotempty()1597 tmpnotempty()
1598 {
1599 errmsgno(EX_BAD, "The directory '%s' is not empty.\n", sym_tmpdir);
1600 comerrno(EX_BAD, "Remove all files in '%s' and try again.\n", sym_tmpdir);
1601 }
1602
1603 LOCAL void
purgeent(imp)1604 purgeent(imp)
1605 imap_t *imp;
1606 {
1607 if (imp == NULL)
1608 return;
1609 imp->i_flags |= I_DELETE;
1610 free(imp->i_name);
1611 imp->i_name = NULL;
1612 }
1613
1614 LOCAL void
purgetree(imp)1615 purgetree(imp)
1616 imap_t *imp;
1617 {
1618 if (imp == NULL)
1619 return;
1620
1621 for (; imp; imp = imp->i_dxnext) {
1622
1623 if (imp->i_flags & I_DELETE)
1624 continue;
1625
1626 purgetree(imp->i_dir);
1627 purgeent(imp);
1628 }
1629 }
1630
1631 /*
1632 * Do some checks and initialisations before the symbols are going to be used
1633 */
1634 EXPORT void
sym_init(gp)1635 sym_init(gp)
1636 GINFO *gp;
1637 {
1638 FILE *f;
1639 FINFO finfo;
1640 #ifdef VERS_DEBUG
1641 extern char *vers;
1642
1643 error("Star version '%s'\n", vers);
1644 error("imaps: %p level %d\n", imaps, gp->dumplevel);
1645 #endif
1646
1647 f = lfilemopen(sym_lock, "wce", S_IRUSR|S_IWUSR);
1648 if (f == NULL) {
1649 comerr("Cannot create '%s', restore is already running.\n",
1650 sym_lock);
1651 /* NOTREACHED */
1652 }
1653 fclose(f);
1654 fillbytes((char *)&finfo, sizeof (finfo), '\0');
1655 _getinfo(sym_lock, &finfo);
1656 lock_ino = finfo.f_ino;
1657
1658 if (ogp == NULL) /* If star-symtable not read */
1659 odtype = gp->dumptype; /* Use this dump type */
1660
1661 /*
1662 * XXX imaps -> iroot ???
1663 */
1664 if (gp->dumplevel == 0 && imaps != NULL) {
1665 errmsgno(EX_BAD, "Trying to extract a level 0 dump but '%s' exists.\n", sym_symtable);
1666 lunlinkat(sym_lock, 0);
1667 comerrno(EX_BAD, "Remove '%s' and try again.\n", sym_symtable);
1668 }
1669 if (gp->dumplevel > 0 && imaps == NULL) {
1670 errmsgno(EX_BAD, "Trying to extract a level %d dump but '%s' does not exist.\n",
1671 gp->dumplevel, sym_symtable);
1672 lunlinkat(sym_lock, 0);
1673 comerrno(EX_BAD, "Restore the level 0 dump first and try again.\n");
1674 }
1675 if (gp->dumptype != DT_FULL || odtype != DT_FULL) {
1676 if (gp->dumptype != DT_FULL) {
1677 errmsgno(EX_BAD,
1678 "WARNING: This dump is a '%s' dump and not a 'full' dump.\n",
1679 dt_name(gp->dumptype));
1680 } else {
1681 errmsgno(EX_BAD,
1682 "WARNING: Restore status is '%s' and not from a 'full' dump.\n",
1683 dt_name(odtype));
1684 }
1685 errmsgno(EX_BAD, "WARNING: An incremental restore may not work correctly.\n");
1686 if (!dopartial && !forcerestore) {
1687 usepartial();
1688 /* NOTREACHED */
1689 }
1690 if (gp->dumptype < odtype)
1691 odtype = gp->dumptype;
1692 }
1693
1694 checkheader(); /* Check Dump level & Dump date */
1695 sym_initsym();
1696 }
1697
1698 /*
1699 * Write back the inode symbol table
1700 */
1701 EXPORT void
sym_close()1702 sym_close()
1703 {
1704 char tpath[2*PATH_MAX+1];
1705 FINFO finfo;
1706 FILE *f;
1707 imap_t *imp;
1708 BOOL warned = FALSE;
1709 BOOL tmpremove = TRUE;
1710 BOOL ok = TRUE;
1711 int err;
1712 #ifdef HAVE_FSYNC
1713 int cnt;
1714 #endif
1715
1716 if (!restore_valid) {
1717 errmsgno(EX_BAD,
1718 "Invalid or empty dump, will not overwrite '%s'\n",
1719 sym_symtable);
1720 return;
1721 }
1722 if (_getinfo(sym_symtable, &finfo) &&
1723 lrename(sym_symtable, sym_oldsymtable) < 0) {
1724 errmsg("Cannot rename %s to %s.\n",
1725 sym_symtable, sym_oldsymtable);
1726 }
1727 f = lfilemopen(sym_symtable, "wct", S_IRUSR|S_IWUSR);
1728 if (f == NULL) {
1729 errmsg("Cannot create '%s'.\n", sym_symtable);
1730 return;
1731 }
1732 fillbytes((char *)&finfo, sizeof (finfo), '\0');
1733 if (!_getinfo(sym_symtable, &finfo))
1734 comerr("Cannot stat '%s'\n", sym_symtable);
1735 if ((imp = pfind_node(sym_symtable)) == NULL) {
1736
1737 #ifdef PADD_NODE_DEBUG
1738 padd_node_caller = "sym_close";
1739 #endif
1740 imp = padd_node(sym_symtable, (ino_t)0, finfo.f_ino, 0);
1741 }
1742 imp->i_nino = finfo.f_ino;
1743
1744 if (isym == NULL)
1745 isym = imp;
1746
1747 if (getenv("STAR_DEBUG"))
1748 tmpremove = FALSE;
1749 else if (itmp != NULL)
1750 error("Removing all in '%s'.\n", sym_tmpdir);
1751 if (itmp != NULL)
1752 for (imp = itmp->i_dir; imp; imp = imp->i_dxnext) {
1753 if (imp->i_flags & I_DELETE)
1754 continue;
1755
1756 js_snprintf(tpath, sizeof (tpath), "%s/%s",
1757 sym_tmpdir, imp->i_name);
1758 fillbytes((char *)&finfo, sizeof (finfo), '\0');
1759 if (_getinfo(tpath, &finfo)) {
1760 if (is_dir(&finfo)) {
1761 /* rmdir */
1762 if (lunlinkat(tpath, AT_REMOVEDIR) >= 0) {
1763 purgeent(imp);
1764 } else if (tmpremove) {
1765 /*
1766 * This is a shortcut. We do not walk
1767 * through the imap tree but rather
1768 * remove anything we find via readdir.
1769 */
1770 if (removetree(tpath))
1771 purgeent(imp);
1772 }
1773 } else {
1774 if (tmpremove || finfo.f_nlink > 1) {
1775 if (lunlinkat(tpath, 0) >= 0)
1776 purgeent(imp);
1777 }
1778 }
1779 if ((imp->i_flags & I_DELETE) == 0 && !warned) {
1780 if (tmpremove) {
1781 errmsgno(EX_BAD,
1782 "A problem occured, not all files in '%s' could be removed.\n",
1783 sym_tmpdir);
1784 }
1785 errmsgno(EX_BAD,
1786 "Don't forget to remove the files in '%s'.\n",
1787 sym_tmpdir);
1788 warned = TRUE;
1789 }
1790 }
1791 }
1792
1793 writeheader(f);
1794 printsyms(f, iroot);
1795
1796 if (fflush(f) != 0)
1797 ok = FALSE;
1798 #ifdef HAVE_FSYNC
1799 err = 0;
1800 cnt = 0;
1801 do {
1802 if (fsync(fdown(f)) != 0)
1803 err = geterrno();
1804
1805 if (err == EINVAL)
1806 err = 0;
1807 } while (err == EINTR && ++cnt < 10);
1808 if (err != 0)
1809 ok = FALSE;
1810 #endif
1811 if (fclose(f) != 0)
1812 ok = FALSE;
1813 if (ok) {
1814 lunlinkat(sym_oldsymtable, 0);
1815 } else {
1816 xstats.s_restore++;
1817 if (lrename(sym_oldsymtable, sym_symtable) < 0)
1818 errmsg("Cannot rename %s to %s.\n",
1819 sym_oldsymtable, sym_symtable);
1820 }
1821
1822 lunlinkat(sym_lock, 0);
1823 }
1824
1825 LOCAL void
sym_dump()1826 sym_dump()
1827 {
1828 FILE *f;
1829
1830 f = lfilemopen(sym_symdump, "wct", S_IRUSR|S_IWUSR);
1831 if (f == NULL) {
1832 errmsg("Panic: cannot open '%s'\n", sym_symdump);
1833 return;
1834 }
1835 writeheader(f);
1836 printsyms(f, iroot);
1837 fclose(f);
1838 }
1839
1840 /*
1841 * star 1.5 (i386-pc-solaris2.9) last star
1842 * partial last Dump
1843 * star 1.5 (i386-pc-solaris2.9) last Dump star
1844 * exustar last Dump archive type
1845 * hugo last Dump host name
1846 * /tmp last Dump filesys
1847 * partial last Dump dumptype
1848 * 1 last Dump dumplevel
1849 * 0 last Dump reflevel
1850 * 1097092599.544044 last Dump dumpdate
1851 * 1096935113.887915 last Dump refdate
1852 */
1853 LOCAL void
writeheader(f)1854 writeheader(f)
1855 FILE *f;
1856 {
1857 fprintf(f, "%s%c\n", vers, 0);
1858 fprintf(f, "%s%c\n", dt_name(odtype), 0);
1859 fprintf(f, "%s%c\n", grip->release, 0);
1860 fprintf(f, "%s%c\n", hdr_name(grip->archtype), 0);
1861 fprintf(f, "%s%c\n", grip->hostname, 0);
1862 fprintf(f, "%s%c\n", grip->filesys, 0);
1863 fprintf(f, "%s%c\n", dt_name(grip->dumptype), 0);
1864 fprintf(f, "%d%c\n", grip->dumplevel, 0);
1865 fprintf(f, "%d%c\n", grip->reflevel, 0);
1866 fprintf(f, "%10lld.%9.9lld%c\n",
1867 (Llong)grip->dumpdate.tv_sec,
1868 (Llong)grip->dumpdate.tv_nsec,
1869 0);
1870 fprintf(f, "%10lld.%9.9lld%c\n",
1871 (Llong)grip->refdate.tv_sec,
1872 (Llong)grip->refdate.tv_nsec,
1873 0);
1874 }
1875
1876 LOCAL void
readheader(f)1877 readheader(f)
1878 FILE *f;
1879 {
1880 char *buf;
1881 size_t buflen = PATH_MAX;
1882 char *p;
1883 Llong ll;
1884
1885 buf = ___malloc(buflen, "line buffer");
1886 (void) xgetline(f, &buf, &buflen, sym_symtable);
1887 odtype = dt_type(buf); /* Old Dump type */
1888
1889 ogp = ___malloc(sizeof (*ogp), "ogp");
1890 fillbytes(ogp, sizeof (*ogp), '\0');
1891 (void) xgetline(f, &buf, &buflen, sym_symtable);
1892 ogp->release = ___savestr(buf); /* Last dump SCHILY.release */
1893 (void) xgetline(f, &buf, &buflen, sym_symtable);
1894 ogp->archtype = hdr_type(buf); /* Last dump SCHILY.archtype */
1895 (void) xgetline(f, &buf, &buflen, sym_symtable);
1896 ogp->hostname = ___savestr(buf); /* " SCHILY.volhdr.hostname */
1897 (void) xgetline(f, &buf, &buflen, sym_symtable);
1898 ogp->filesys = ___savestr(buf); /* " SCHILY.volhdr.filesys */
1899 (void) xgetline(f, &buf, &buflen, sym_symtable);
1900 ogp->dumptype = dt_type(buf); /* " SCHILY.volhdr.dumptype */
1901 (void) xgetline(f, &buf, &buflen, sym_symtable);
1902 p = astollb(buf, &ll, 10);
1903 if (*p != '\0')
1904 comerrno(EX_BAD, "Bad dumplevel '%s' in '%s'.\n",
1905 buf, sym_symtable);
1906 ogp->dumplevel = ll; /* " SCHILY.volhdr.dumplevel */
1907 (void) xgetline(f, &buf, &buflen, sym_symtable);
1908 p = astollb(buf, &ll, 10);
1909 if (*p != '\0')
1910 comerrno(EX_BAD, "Bad reflevel '%s' in '%s'.\n",
1911 buf, sym_symtable);
1912 ogp->reflevel = ll; /* " SCHILY.volhdr.reflevel */
1913 (void) xgetline(f, &buf, &buflen, sym_symtable);
1914 if (!getdumptime(buf, &ogp->dumpdate)) /* " SCHILY.volhdr.dumpdate */
1915 exit(EX_BAD);
1916 (void) xgetline(f, &buf, &buflen, sym_symtable);
1917 if (!getdumptime(buf, &ogp->refdate)) /* " SCHILY.volhdr.refdate */
1918 exit(EX_BAD);
1919 ogp->gflags = GF_RELEASE | GF_ARCHTYPE | GF_HOSTNAME | GF_FILESYS |
1920 GF_DUMPTYPE | GF_DUMPLEVEL | GF_REFLEVEL |
1921 GF_DUMPDATE | GF_REFDATE;
1922
1923 free(buf);
1924 }
1925
1926 LOCAL void
checkheader()1927 checkheader()
1928 {
1929 #ifdef DEBUG
1930 extern FILE *vpr;
1931
1932 fprintf(vpr, "Last restored dump:\n");
1933 verbose++;
1934 if (ogp)
1935 griprint(ogp);
1936 fprintf(vpr, "This dump:\n");
1937 griprint(grip);
1938 verbose--;
1939 #endif
1940
1941 error("Validating this dump against restored filesystem...\n");
1942 if (ogp == NULL) { /* star-symtable not read */
1943 if (grip->dumplevel == 0) {
1944 restore_valid = TRUE;
1945 error("Dump level 0 on empty filesystem, starting restore.\n");
1946 return;
1947 }
1948 }
1949 if (!streql(grip->hostname, ogp->hostname))
1950 comerrno(EX_BAD, "Wrong dumphost '%s', last restored dump is from '%s'.\n",
1951 grip->hostname, ogp->hostname);
1952 if (!streql(grip->filesys, ogp->filesys))
1953 comerrno(EX_BAD, "Wrong filesys '%s', last restored dump is from '%s'.\n",
1954 grip->filesys, ogp->filesys);
1955 if ((grip->dumplevel == ogp->dumplevel) &&
1956 (grip->reflevel == ogp->reflevel) &&
1957 (grip->refdate.tv_sec == ogp->refdate.tv_sec) &&
1958 (grip->dumpdate.tv_sec == ogp->dumpdate.tv_sec)) {
1959 comerrno(EX_BAD, "This dump has already been restored.\n");
1960 }
1961 if ((grip->dumplevel == ogp->dumplevel) &&
1962 (grip->reflevel == ogp->reflevel) &&
1963 (grip->refdate.tv_sec == ogp->refdate.tv_sec) &&
1964 (grip->dumpdate.tv_sec > ogp->dumpdate.tv_sec)) {
1965 errmsgno(EX_BAD, "A level %d dump has already been restored.\n",
1966 grip->dumplevel);
1967 errmsgno(EX_BAD, "Is is sufficient to restore the most recent dump of each level.\n");
1968 } else {
1969 if (grip->reflevel != ogp->dumplevel) {
1970 errmsgno(EX_BAD,
1971 "Wrong reflevel %d, last restored dump level was %d.\n",
1972 grip->reflevel, ogp->dumplevel);
1973 if (!forcerestore) {
1974 errmsgno(EX_BAD,
1975 "Restore a level %d (or higher) dump with reflevel %d.\n",
1976 ogp->dumplevel+1, ogp->dumplevel);
1977 useforce();
1978 /* NOTREACHED */
1979 }
1980 }
1981 if (grip->refdate.tv_sec != ogp->dumpdate.tv_sec) {
1982 if (ogp->dumpdate.tv_sec > grip->refdate.tv_sec) {
1983 errmsgno(EX_BAD, "WARNING: refdate %s is older than last restored dump ",
1984 dumpdate(&grip->refdate));
1985 error("%s.\n", dumpdate(&ogp->dumpdate));
1986 } else {
1987 errmsgno(EX_BAD, "Wrong refdate %s, last restored dump was from ",
1988 dumpdate(&grip->refdate));
1989 error("%s.\n", dumpdate(&ogp->dumpdate));
1990 if (forcerestore)
1991 goto force;
1992 useforce();
1993 /* NOTREACHED */
1994 }
1995 }
1996 }
1997 restore_valid = TRUE;
1998 error("Dump is valid, starting restore.\n");
1999 return;
2000 force:
2001 restore_valid = TRUE;
2002 error("Dump is not valid, starting restore because of -force-restore.\n");
2003 }
2004
2005 LOCAL void
useforce()2006 useforce()
2007 {
2008 lunlinkat(sym_lock, 0);
2009 comerrno(EX_BAD, "Use -force-restore if you want to restore anyway.\n");
2010 /* NOTREACHED */
2011 }
2012
2013 LOCAL void
usepartial()2014 usepartial()
2015 {
2016 lunlinkat(sym_lock, 0);
2017 comerrno(EX_BAD, "Use -partial if you want to restore anyway.\n");
2018 /* NOTREACHED */
2019 }
2020
2021 /*
2022 * Compute the name length for full path name for imp
2023 */
2024 LOCAL size_t
fullnlen(imp,top)2025 fullnlen(imp, top)
2026 imap_t *imp;
2027 BOOL top;
2028 {
2029 ssize_t len = 1; /* Final Null Byte */
2030
2031 if (imp == iroot)
2032 return (len);
2033
2034 if (imp == NULL) {
2035 errmsgno(EX_BAD, "Panic: fullnlen(NULL)\n");
2036 return (0);
2037 }
2038 len = fullnlen(imp->i_dparent, FALSE);
2039 if (len == 0)
2040 return (len);
2041
2042 if (imp->i_name == NULL) {
2043 errmsgno(EX_BAD, "Panic: fullnlen NULL i_name\n");
2044 return (0);
2045 }
2046 len += strlen(imp->i_name) + (top ? 0:1); /* Add '/' if not top */
2047 return (len);
2048 }
2049
2050 /*
2051 * Create a full path name for imp in cp
2052 */
2053 LOCAL char *
fullname(imp,cp,ep,top)2054 fullname(imp, cp, ep, top)
2055 imap_t *imp;
2056 char *cp;
2057 char *ep;
2058 BOOL top;
2059 {
2060 size_t len;
2061
2062 if (imp == iroot)
2063 return (cp);
2064
2065 if (imp == NULL) {
2066 errmsgno(EX_BAD, "Panic: fullname(NULL)\n");
2067 return (NULL);
2068 }
2069 cp = fullname(imp->i_dparent, cp, ep, FALSE);
2070 if (cp == NULL)
2071 return (NULL);
2072
2073 if (imp->i_name == NULL) {
2074 errmsgno(EX_BAD, "Panic: fullname NULL i_name\n");
2075 return (NULL);
2076 }
2077 len = strlen(imp->i_name) + (top ? 0:1);
2078 if (cp + len >= ep)
2079 return (NULL);
2080
2081 strcpy(cp, imp->i_name);
2082 if (!top) {
2083 cp += len-1;
2084 *cp++ = '/';
2085 *cp = '\0';
2086 } else {
2087 cp += len;
2088 }
2089 return (cp);
2090 }
2091
2092 /*
2093 * Print a full path name by parsing the tree of parent directories
2094 */
2095 LOCAL void
printfullname(f,imp)2096 printfullname(f, imp)
2097 FILE *f;
2098 imap_t *imp;
2099 {
2100 if (imp == iroot)
2101 return;
2102 printfullname(f, imp->i_dparent);
2103 fprintf(f, "/%s", imp->i_name);
2104 }
2105
2106 /*
2107 * Print a single symbol to a file
2108 */
2109 LOCAL void
printonesym(f,imp)2110 printonesym(f, imp)
2111 FILE *f;
2112 imap_t *imp;
2113 {
2114 /* Flags Old ino New Ino Name */
2115 fprintf(f, "%c %lld %lld %s%c\n",
2116 imp->i_flags & I_DIR ? 'D':' ',
2117 (Llong)imp->i_oino, (Llong)imp->i_nino,
2118 imp->i_name,
2119 0);
2120
2121 if (imp->i_oino == 0) {
2122 if (imp != itmp && imp != isym) {
2123 errmsgno(EX_BAD, "WARNING: No old inode number for ");
2124 printfullname(stderr, imp);
2125 fprintf(stderr, "\n");
2126 }
2127 }
2128 if (imp->i_nino == 0) {
2129 errmsgno(EX_BAD, "WARNING: No new inode number for ");
2130 printfullname(stderr, imp);
2131 fprintf(stderr, "\n");
2132 }
2133 }
2134
2135 /*
2136 * Print all symbols to a file
2137 */
2138 LOCAL void
printsyms(f,imp)2139 printsyms(f, imp)
2140 FILE *f;
2141 imap_t *imp;
2142 {
2143 #ifdef DEBUG
2144 error("nimp %d\n", nimp);
2145 #endif
2146 for (; imp; imp = imp->i_dxnext) {
2147
2148 if (imp->i_flags & I_DELETE)
2149 continue;
2150
2151 printonesym(f, imp);
2152
2153 if (imp->i_flags & I_DIR && imp->i_dir) {
2154 fprintf(f, ">%c\n", 0);
2155 printsyms(f, imp->i_dir);
2156 fprintf(f, "<%c\n", 0);
2157 }
2158 }
2159 }
2160
2161
2162 #ifdef PRINT_L_SYM
2163 /*
2164 * Print a single symbol with long filenames to a file
2165 */
2166 LOCAL void
printoneLsym(f,imp)2167 printoneLsym(f, imp)
2168 FILE *f;
2169 imap_t *imp;
2170 {
2171 /* Flags Old ino New Ino Name */
2172 fprintf(f, "%c %lld %lld ",
2173 imp->i_flags & I_DIR ? 'D':' ',
2174 (Llong)imp->i_oino, (Llong)imp->i_nino);
2175 printfullname(f, imp);
2176 fprintf(f, "\n");
2177
2178 if (imp->i_oino == 0) {
2179 if (imp != itmp && imp != isym) {
2180 errmsgno(EX_BAD, "WARNING: No old inode number for ");
2181 printfullname(stderr, imp);
2182 fprintf(stderr, "\n");
2183 }
2184 }
2185 }
2186
2187 /*
2188 * Print all symbols with long filenames to a file
2189 */
2190 LOCAL void
printLsyms(f,imp)2191 printLsyms(f, imp)
2192 FILE *f;
2193 imap_t *imp;
2194 {
2195 #ifdef DEBUG
2196 error("nimp %d\n", nimp);
2197 #endif
2198 for (; imp; imp = imp->i_dxnext) {
2199
2200 if (imp->i_flags & I_DELETE)
2201 continue;
2202
2203 printoneLsym(f, imp);
2204
2205 if (imp->i_flags & I_DIR && imp->i_dir)
2206 printLsyms(f, imp->i_dir);
2207 }
2208 }
2209
2210 EXPORT void
printLsym(f)2211 printLsym(f)
2212 FILE *f;
2213 {
2214 printLsyms(f, iroot);
2215 }
2216 #endif /* PRINT_L_SYM */
2217
2218 #ifdef __needed__
2219 /* EXPORT BOOL */
2220 LOCAL BOOL
dirdiskonly(info,odep,odp)2221 dirdiskonly(info, odep, odp)
2222 FINFO *info;
2223 size_t *odep;
2224 char ***odp;
2225 {
2226 register char **ep1; /* Directory entry pointer array (arch) */
2227 register char **ep2 = 0; /* Directory entry pointer array (disk) */
2228 register char *dp2; /* Directory names string from disk */
2229 register char **oa = 0; /* Only in arch pointer array */
2230 register char **od = 0; /* Only on disk pointer array */
2231 register size_t i;
2232 size_t ents1 = (size_t)-1;
2233 size_t ents2;
2234 size_t dlen = 0; /* # of entries only on disk */
2235 size_t alen = 0; /* # of entries only in arch */
2236 BOOL diffs = FALSE;
2237 DIR *dirp;
2238
2239 /*
2240 * Old archives had only one nul at the end
2241 * xheader.c already increments info->f_dirlen in this case
2242 * but a newline may appear to be the last char.
2243 * Note that we receicve the space from the xheader
2244 * extract buffer.
2245 */
2246 i = info->f_dirlen;
2247 if (info->f_dir[i-1] != '\0')
2248 info->f_dir[i-1] = '\0'; /* Kill '\n' */
2249
2250 ep1 = sortdir(info->f_dir, &ents1); /* from archive */
2251 dirp = lopendir(info->f_name);
2252 if (dirp) {
2253 dp2 = dfetchdir(dirp, info->f_name, &ents2, 0, (ino_t **)0);
2254 closedir(dirp);
2255 } else {
2256 dp2 = NULL;
2257 }
2258 if (dp2 == NULL) {
2259 diffs = TRUE;
2260 errmsg("Cannot read dir '%s'.\n", info->f_name);
2261 goto no_dircmp;
2262 }
2263 ep2 = sortdir(dp2, &ents2); /* from disk */
2264
2265 if (ents1 != ents2) {
2266 if (debug || verbose > 2) {
2267 error("Archive ents: %d Disk ents: %d '%s'\n",
2268 ents1, ents2, info->f_name);
2269 }
2270 diffs = TRUE;
2271 }
2272
2273 if (cmpdir(ents1, ents2, ep1, ep2, NULL, NULL, &alen, &dlen) > 0)
2274 diffs = TRUE;
2275
2276 oa = ___malloc(alen * sizeof (char *), "dir diff array");
2277 od = ___malloc(dlen * sizeof (char *), "dir diff array");
2278 cmpdir(ents1, ents2, ep1, ep2, oa, od, &alen, &dlen);
2279
2280 #ifdef DEBUG
2281 for (i = 0; i < dlen; i++) {
2282 error("Only on disk '%s': '%s'\n",
2283 info->f_name, od[i] + 1);
2284 }
2285 for (i = 0; i < alen; i++) {
2286 error("Only in archive '%s': '%s'\n",
2287 info->f_name, oa[i] + 1);
2288 }
2289 #endif
2290
2291 no_dircmp:
2292 if (odep)
2293 *odep = dlen;
2294
2295 if (dp2)
2296 free(dp2);
2297 if (ep1)
2298 free(ep1);
2299 if (ep2)
2300 free(ep2);
2301 if (odp)
2302 *odp = od;
2303 else if (od)
2304 free(od);
2305 if (oa)
2306 free(oa);
2307
2308 return (diffs);
2309 }
2310 #endif /* __needed__ */
2311