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