1*2654012fSReza Sabdar /*
2*2654012fSReza Sabdar  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3*2654012fSReza Sabdar  * Use is subject to license terms.
4*2654012fSReza Sabdar  */
5*2654012fSReza Sabdar 
6*2654012fSReza Sabdar /*
7*2654012fSReza Sabdar  * BSD 3 Clause License
8*2654012fSReza Sabdar  *
9*2654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
10*2654012fSReza Sabdar  *
11*2654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
12*2654012fSReza Sabdar  * modification, are permitted provided that the following conditions
13*2654012fSReza Sabdar  * are met:
14*2654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
15*2654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
16*2654012fSReza Sabdar  *
17*2654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
18*2654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
19*2654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
20*2654012fSReza Sabdar  *	  distribution.
21*2654012fSReza Sabdar  *
22*2654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23*2654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
24*2654012fSReza Sabdar  *	  products derived from this software without specific prior written
25*2654012fSReza Sabdar  *	  permission.
26*2654012fSReza Sabdar  *
27*2654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28*2654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29*2654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30*2654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31*2654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32*2654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33*2654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34*2654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35*2654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36*2654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37*2654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
38*2654012fSReza Sabdar  */
39*2654012fSReza Sabdar #include <stdlib.h>
40*2654012fSReza Sabdar #include <ctype.h>
41*2654012fSReza Sabdar #include <stdio.h>
42*2654012fSReza Sabdar #include <limits.h>
43*2654012fSReza Sabdar #include <string.h>
44*2654012fSReza Sabdar #include <time.h>
45*2654012fSReza Sabdar #include <sys/types.h>
46*2654012fSReza Sabdar #include <sys/acl.h>
47*2654012fSReza Sabdar #include <utime.h>
48*2654012fSReza Sabdar #include <unistd.h>
49*2654012fSReza Sabdar #include <pthread.h>
50*2654012fSReza Sabdar #include <archives.h>
51*2654012fSReza Sabdar #include <priv.h>
52*2654012fSReza Sabdar #include <tlm.h>
53*2654012fSReza Sabdar #include <libzfs.h>
54*2654012fSReza Sabdar #include <ndmpd_prop.h>
55*2654012fSReza Sabdar #include "tlm_proto.h"
56*2654012fSReza Sabdar 
57*2654012fSReza Sabdar 
58*2654012fSReza Sabdar #define	PM_EXACT_OR_CHILD(m)	((m) == PM_EXACT || (m) == PM_CHILD)
59*2654012fSReza Sabdar 
60*2654012fSReza Sabdar typedef boolean_t name_match_fp_t(char *s, char *t);
61*2654012fSReza Sabdar 
62*2654012fSReza Sabdar static void set_acl(char *name,
63*2654012fSReza Sabdar     tlm_acls_t *acls);
64*2654012fSReza Sabdar static long restore_file(int *fp,
65*2654012fSReza Sabdar     char *real_name,
66*2654012fSReza Sabdar     long size,
67*2654012fSReza Sabdar     longlong_t huge_size,
68*2654012fSReza Sabdar     tlm_acls_t *,
69*2654012fSReza Sabdar     boolean_t want_this_file,
70*2654012fSReza Sabdar     tlm_cmd_t *,
71*2654012fSReza Sabdar     tlm_job_stats_t *);
72*2654012fSReza Sabdar static long restore_xattr_hdr(int *fp,
73*2654012fSReza Sabdar     char *name,
74*2654012fSReza Sabdar     char *fname,
75*2654012fSReza Sabdar     long size,
76*2654012fSReza Sabdar     tlm_acls_t *acls,
77*2654012fSReza Sabdar     tlm_cmd_t *local_commands,
78*2654012fSReza Sabdar     tlm_job_stats_t *job_stats);
79*2654012fSReza Sabdar static int get_long_name(int lib,
80*2654012fSReza Sabdar     int drv,
81*2654012fSReza Sabdar     long recsize,
82*2654012fSReza Sabdar     char *name,
83*2654012fSReza Sabdar     long *buf_spot,
84*2654012fSReza Sabdar     tlm_cmd_t *local_commands);
85*2654012fSReza Sabdar static int get_humongus_file_header(int lib,
86*2654012fSReza Sabdar     int	drv,
87*2654012fSReza Sabdar     long recsize,
88*2654012fSReza Sabdar     longlong_t *size,
89*2654012fSReza Sabdar     char *name,
90*2654012fSReza Sabdar     tlm_cmd_t *);
91*2654012fSReza Sabdar static int create_directory(char *dir,
92*2654012fSReza Sabdar     tlm_job_stats_t *);
93*2654012fSReza Sabdar static int create_hard_link(char *name,
94*2654012fSReza Sabdar     char *link,
95*2654012fSReza Sabdar     tlm_acls_t *,
96*2654012fSReza Sabdar     tlm_job_stats_t *);
97*2654012fSReza Sabdar static int create_sym_link(char *dst,
98*2654012fSReza Sabdar     char *target,
99*2654012fSReza Sabdar     tlm_acls_t *,
100*2654012fSReza Sabdar     tlm_job_stats_t *);
101*2654012fSReza Sabdar static int create_fifo(char *name,
102*2654012fSReza Sabdar     tlm_acls_t *);
103*2654012fSReza Sabdar static long load_acl_info(int lib,
104*2654012fSReza Sabdar     int	drv,
105*2654012fSReza Sabdar     long size,
106*2654012fSReza Sabdar     tlm_acls_t *,
107*2654012fSReza Sabdar     long *acl_spot,
108*2654012fSReza Sabdar     tlm_cmd_t *);
109*2654012fSReza Sabdar static char *get_read_buffer(int want,
110*2654012fSReza Sabdar     int	*error,
111*2654012fSReza Sabdar     int	*actual_size,
112*2654012fSReza Sabdar     tlm_cmd_t *);
113*2654012fSReza Sabdar static boolean_t wildcard_enabled(void);
114*2654012fSReza Sabdar static boolean_t is_file_wanted(char *name,
115*2654012fSReza Sabdar     char **sels,
116*2654012fSReza Sabdar     char **exls,
117*2654012fSReza Sabdar     int	flags,
118*2654012fSReza Sabdar     int	*mchtype,
119*2654012fSReza Sabdar     int	*pos);
120*2654012fSReza Sabdar static char *catnames(struct rs_name_maker *rnp,
121*2654012fSReza Sabdar     char *buf,
122*2654012fSReza Sabdar     int	pos,
123*2654012fSReza Sabdar     char *path);
124*2654012fSReza Sabdar 
125*2654012fSReza Sabdar static char *rs_new_name(struct rs_name_maker *rnp,
126*2654012fSReza Sabdar     char *real_name,
127*2654012fSReza Sabdar     int pos,
128*2654012fSReza Sabdar     char *path);
129*2654012fSReza Sabdar 
130*2654012fSReza Sabdar typedef struct stack_ent {
131*2654012fSReza Sabdar 	char *se_name;
132*2654012fSReza Sabdar 	tlm_acls_t se_acls;
133*2654012fSReza Sabdar } stack_ent_t;
134*2654012fSReza Sabdar 
135*2654012fSReza Sabdar 
136*2654012fSReza Sabdar /*
137*2654012fSReza Sabdar  * dtree_push
138*2654012fSReza Sabdar  */
139*2654012fSReza Sabdar int
140*2654012fSReza Sabdar dtree_push(cstack_t *stp, char *nmp, tlm_acls_t *acls)
141*2654012fSReza Sabdar {
142*2654012fSReza Sabdar 	int len;
143*2654012fSReza Sabdar 	stack_ent_t *sp;
144*2654012fSReza Sabdar 
145*2654012fSReza Sabdar 	sp = ndmp_malloc(sizeof (stack_ent_t));
146*2654012fSReza Sabdar 	if (!sp || !nmp || !acls) {
147*2654012fSReza Sabdar 		free(sp);
148*2654012fSReza Sabdar 		return (-1);
149*2654012fSReza Sabdar 	}
150*2654012fSReza Sabdar 
151*2654012fSReza Sabdar 	len = strlen(nmp) + 1;
152*2654012fSReza Sabdar 	sp->se_name = ndmp_malloc(len);
153*2654012fSReza Sabdar 	if (!sp->se_name) {
154*2654012fSReza Sabdar 		free(sp);
155*2654012fSReza Sabdar 		return (-1);
156*2654012fSReza Sabdar 	}
157*2654012fSReza Sabdar 
158*2654012fSReza Sabdar 	(void) strlcpy(sp->se_name, nmp, len);
159*2654012fSReza Sabdar 	(void) memcpy(&sp->se_acls, acls, sizeof (*acls));
160*2654012fSReza Sabdar 
161*2654012fSReza Sabdar 	return (cstack_push(stp, (void *)sp, sizeof (*sp)));
162*2654012fSReza Sabdar }
163*2654012fSReza Sabdar 
164*2654012fSReza Sabdar /*
165*2654012fSReza Sabdar  * dtree_pop
166*2654012fSReza Sabdar  */
167*2654012fSReza Sabdar int
168*2654012fSReza Sabdar dtree_pop(cstack_t *stp)
169*2654012fSReza Sabdar {
170*2654012fSReza Sabdar 	int err;
171*2654012fSReza Sabdar 	stack_ent_t *sp;
172*2654012fSReza Sabdar 
173*2654012fSReza Sabdar 	err = cstack_pop(stp, (void **)&sp, (void *)NULL);
174*2654012fSReza Sabdar 	if (err)
175*2654012fSReza Sabdar 		return (-1);
176*2654012fSReza Sabdar 
177*2654012fSReza Sabdar 	set_acl(sp->se_name, &sp->se_acls);
178*2654012fSReza Sabdar 
179*2654012fSReza Sabdar 	free(sp->se_name);
180*2654012fSReza Sabdar 	free(sp);
181*2654012fSReza Sabdar 	return (err);
182*2654012fSReza Sabdar }
183*2654012fSReza Sabdar 
184*2654012fSReza Sabdar 
185*2654012fSReza Sabdar /*
186*2654012fSReza Sabdar  * dtree_peek
187*2654012fSReza Sabdar  */
188*2654012fSReza Sabdar char *
189*2654012fSReza Sabdar dtree_peek(cstack_t *stp)
190*2654012fSReza Sabdar {
191*2654012fSReza Sabdar 	int err;
192*2654012fSReza Sabdar 	stack_ent_t *sp;
193*2654012fSReza Sabdar 
194*2654012fSReza Sabdar 	err = cstack_top(stp, (void **)&sp, (void *)NULL);
195*2654012fSReza Sabdar 	if (err)
196*2654012fSReza Sabdar 		return (NULL);
197*2654012fSReza Sabdar 
198*2654012fSReza Sabdar 	return (sp->se_name);
199*2654012fSReza Sabdar }
200*2654012fSReza Sabdar 
201*2654012fSReza Sabdar /*
202*2654012fSReza Sabdar  * NBU and EBS may not send us the correct file list containing hardlinks
203*2654012fSReza Sabdar  * during a DAR restore, e.g. they appear always send the first name
204*2654012fSReza Sabdar  * associated with an inode, even if other link names were
205*2654012fSReza Sabdar  * selected for the restore.  As a workaround, we use the file name entry
206*2654012fSReza Sabdar  * in sels[] (ignore the name in the tar header) as restore target.
207*2654012fSReza Sabdar  */
208*2654012fSReza Sabdar static char *
209*2654012fSReza Sabdar rs_darhl_new_name(struct rs_name_maker *rnp, char *name, char **sels, int *pos,
210*2654012fSReza Sabdar     char *longname)
211*2654012fSReza Sabdar {
212*2654012fSReza Sabdar 	int x;
213*2654012fSReza Sabdar 
214*2654012fSReza Sabdar 	for (x = 0; sels[x] != NULL; x++) {
215*2654012fSReza Sabdar 		if (strcmp(sels[x], " ")) {
216*2654012fSReza Sabdar 			*pos = x;
217*2654012fSReza Sabdar 			(void) strlcpy(longname, sels[x], TLM_MAX_PATH_NAME);
218*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
219*2654012fSReza Sabdar 			    "to replace hardlink name [%s], pos [%d]",
220*2654012fSReza Sabdar 			    longname, *pos);
221*2654012fSReza Sabdar 
222*2654012fSReza Sabdar 			return (rs_new_name(rnp, name, *pos, longname));
223*2654012fSReza Sabdar 		}
224*2654012fSReza Sabdar 	}
225*2654012fSReza Sabdar 
226*2654012fSReza Sabdar 	return (NULL);
227*2654012fSReza Sabdar }
228*2654012fSReza Sabdar 
229*2654012fSReza Sabdar 
230*2654012fSReza Sabdar /*
231*2654012fSReza Sabdar  * Main dir restore funciton for tar
232*2654012fSReza Sabdar  */
233*2654012fSReza Sabdar int
234*2654012fSReza Sabdar tar_getdir(tlm_commands_t *commands,
235*2654012fSReza Sabdar     tlm_cmd_t *local_commands,
236*2654012fSReza Sabdar     tlm_job_stats_t *job_stats,
237*2654012fSReza Sabdar     struct rs_name_maker *rnp,
238*2654012fSReza Sabdar     int	lib,
239*2654012fSReza Sabdar     int	drv,
240*2654012fSReza Sabdar     char **sels, /* what to get off the tape */
241*2654012fSReza Sabdar     char **exls, /* what to leave behind */
242*2654012fSReza Sabdar     int	flags,
243*2654012fSReza Sabdar     int	DAR, struct hardlink_q *hardlink_q)
244*2654012fSReza Sabdar {
245*2654012fSReza Sabdar 	int	fp = 0;		/* file being restored ... */
246*2654012fSReza Sabdar 				/*  ...need to preserve across volume changes */
247*2654012fSReza Sabdar 	tlm_acls_t *acls;	/* file access info */
248*2654012fSReza Sabdar 	char	*longname;
249*2654012fSReza Sabdar 	boolean_t is_long_name = FALSE;
250*2654012fSReza Sabdar 	char	*longlink;
251*2654012fSReza Sabdar 	char	*hugename;
252*2654012fSReza Sabdar 	longlong_t huge_size = 0;	/* size of a HUGE file */
253*2654012fSReza Sabdar 	long	acl_spot;		/* any ACL info on the next volume */
254*2654012fSReza Sabdar 	long	file_size;		/* size of file to restore */
255*2654012fSReza Sabdar 	long	size_left = 0;		/* need this after volume change */
256*2654012fSReza Sabdar 	int	last_action = 0;	/* what we are doing at EOT */
257*2654012fSReza Sabdar 	boolean_t multi_volume = FALSE;	/* is this a multi-volume switch ? */
258*2654012fSReza Sabdar 	int	chk_rv;			/* scratch area */
259*2654012fSReza Sabdar 
260*2654012fSReza Sabdar 	int	mchtype, pos;
261*2654012fSReza Sabdar 					/*
262*2654012fSReza Sabdar 					 * if an exact match is found for
263*2654012fSReza Sabdar 					 * restore and its position in the
264*2654012fSReza Sabdar 					 * selections list
265*2654012fSReza Sabdar 					 */
266*2654012fSReza Sabdar 	int	nzerohdr;		/* the number of empty tar headers */
267*2654012fSReza Sabdar 	boolean_t break_flg;		/* exit the while loop */
268*2654012fSReza Sabdar 	int	rv;
269*2654012fSReza Sabdar 	long nm_end, lnk_end;
270*2654012fSReza Sabdar 	char	*name, *nmp;
271*2654012fSReza Sabdar 	cstack_t *stp;
272*2654012fSReza Sabdar 	char 	*bkpath;
273*2654012fSReza Sabdar 	char 	*parentlnk;
274*2654012fSReza Sabdar 	/*
275*2654012fSReza Sabdar 	 * The directory where temporary files may be created during a partial
276*2654012fSReza Sabdar 	 * non-DAR restore of hardlinks.  It is intended to be initialized by
277*2654012fSReza Sabdar 	 * an environment variable that can be set by user.
278*2654012fSReza Sabdar 	 *
279*2654012fSReza Sabdar 	 * It is not initialized for now.   We keep it here for future use.
280*2654012fSReza Sabdar 	 */
281*2654012fSReza Sabdar 	char *tmplink_dir = NULL;
282*2654012fSReza Sabdar 
283*2654012fSReza Sabdar 	/*
284*2654012fSReza Sabdar 	 * startup
285*2654012fSReza Sabdar 	 */
286*2654012fSReza Sabdar 
287*2654012fSReza Sabdar 	longname = ndmp_malloc(TLM_MAX_PATH_NAME);
288*2654012fSReza Sabdar 	longlink = ndmp_malloc(TLM_MAX_PATH_NAME);
289*2654012fSReza Sabdar 	hugename = ndmp_malloc(TLM_MAX_PATH_NAME);
290*2654012fSReza Sabdar 	parentlnk = ndmp_malloc(TLM_MAX_PATH_NAME);
291*2654012fSReza Sabdar 	name = ndmp_malloc(TLM_MAX_PATH_NAME);
292*2654012fSReza Sabdar 	acls = ndmp_malloc(sizeof (tlm_acls_t));
293*2654012fSReza Sabdar 	stp = cstack_new();
294*2654012fSReza Sabdar 	if (longname == NULL || longlink == NULL || hugename == NULL ||
295*2654012fSReza Sabdar 	    name == NULL || acls == NULL || stp == NULL || parentlnk == NULL) {
296*2654012fSReza Sabdar 		cstack_delete(stp);
297*2654012fSReza Sabdar 		free(longname);
298*2654012fSReza Sabdar 		free(longlink);
299*2654012fSReza Sabdar 		free(hugename);
300*2654012fSReza Sabdar 		free(parentlnk);
301*2654012fSReza Sabdar 		free(name);
302*2654012fSReza Sabdar 		free(acls);
303*2654012fSReza Sabdar 		return (-TLM_NO_SCRATCH_SPACE);
304*2654012fSReza Sabdar 	}
305*2654012fSReza Sabdar 
306*2654012fSReza Sabdar 	acl_spot = 0;
307*2654012fSReza Sabdar 	*hugename = '\0';
308*2654012fSReza Sabdar 	*parentlnk = '\0';
309*2654012fSReza Sabdar 	nm_end = 0;
310*2654012fSReza Sabdar 	*longname = '\0';
311*2654012fSReza Sabdar 	lnk_end = 0;
312*2654012fSReza Sabdar 	*longlink = '\0';
313*2654012fSReza Sabdar 	(void) memset(acls, 0, sizeof (tlm_acls_t));
314*2654012fSReza Sabdar 	if (IS_SET(flags, RSFLG_OVR_ALWAYS)) {
315*2654012fSReza Sabdar 		acls->acl_overwrite = TRUE;
316*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "RSFLG_OVR_ALWAYS");
317*2654012fSReza Sabdar 	} else if (IS_SET(flags, RSFLG_OVR_UPDATE)) {
318*2654012fSReza Sabdar 		acls->acl_update = TRUE;
319*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "RSFLG_OVR_UPDATE");
320*2654012fSReza Sabdar 	}
321*2654012fSReza Sabdar 
322*2654012fSReza Sabdar 	/*
323*2654012fSReza Sabdar 	 * work
324*2654012fSReza Sabdar 	 */
325*2654012fSReza Sabdar 	rv = 0;
326*2654012fSReza Sabdar 	nzerohdr = 0;
327*2654012fSReza Sabdar 	break_flg = FALSE;
328*2654012fSReza Sabdar 	while (commands->tcs_writer != TLM_ABORT &&
329*2654012fSReza Sabdar 	    local_commands->tc_writer != TLM_STOP) {
330*2654012fSReza Sabdar 		tlm_tar_hdr_t fake_tar_hdr;
331*2654012fSReza Sabdar 		char	*file_name;
332*2654012fSReza Sabdar 		char	*link_name;
333*2654012fSReza Sabdar 		int	erc;
334*2654012fSReza Sabdar 		int	actual_size;
335*2654012fSReza Sabdar 		boolean_t want_this_file;
336*2654012fSReza Sabdar 		int	want = sizeof (tlm_tar_hdr_t);
337*2654012fSReza Sabdar 		tlm_tar_hdr_t *tar_hdr;
338*2654012fSReza Sabdar 
339*2654012fSReza Sabdar 		/* The inode of an LF_LINK type. */
340*2654012fSReza Sabdar 		unsigned long hardlink_inode = 0;
341*2654012fSReza Sabdar 
342*2654012fSReza Sabdar 		/*
343*2654012fSReza Sabdar 		 * Indicate whether a file with the same inode has been
344*2654012fSReza Sabdar 		 * restored.
345*2654012fSReza Sabdar 		 */
346*2654012fSReza Sabdar 		int hardlink_done = 0;
347*2654012fSReza Sabdar 
348*2654012fSReza Sabdar 		/* The path of the restored hardlink file */
349*2654012fSReza Sabdar 		char *hardlink_target = NULL;
350*2654012fSReza Sabdar 		int is_hardlink = 0;
351*2654012fSReza Sabdar 
352*2654012fSReza Sabdar 		/*
353*2654012fSReza Sabdar 		 * Whether a temporary file should be created for restoring
354*2654012fSReza Sabdar 		 * hardlink.
355*2654012fSReza Sabdar 		 */
356*2654012fSReza Sabdar 		int hardlink_tmp_file = 0;
357*2654012fSReza Sabdar 		char *hardlink_tmp_name = ".tmphlrsnondar";
358*2654012fSReza Sabdar 
359*2654012fSReza Sabdar 		/* used to make up hardlink_tmp_name */
360*2654012fSReza Sabdar 		static int hardlink_tmp_idx = 0;
361*2654012fSReza Sabdar 
362*2654012fSReza Sabdar 		if (break_flg) {
363*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
364*2654012fSReza Sabdar 			    "Exiting writer thread drive %d", drv);
365*2654012fSReza Sabdar 			break;
366*2654012fSReza Sabdar 		}
367*2654012fSReza Sabdar 
368*2654012fSReza Sabdar 		if (multi_volume) {
369*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "multi_volume %c %d",
370*2654012fSReza Sabdar 			    last_action, size_left);
371*2654012fSReza Sabdar 
372*2654012fSReza Sabdar 			/*
373*2654012fSReza Sabdar 			 * the previous volume is out of data
374*2654012fSReza Sabdar 			 * and is back in the rack, a new tape
375*2654012fSReza Sabdar 			 * is loaded and ready to read.
376*2654012fSReza Sabdar 			 *
377*2654012fSReza Sabdar 			 * We need to pick up where we left off.
378*2654012fSReza Sabdar 			 */
379*2654012fSReza Sabdar 			(void) memset(&fake_tar_hdr, 0, sizeof (fake_tar_hdr));
380*2654012fSReza Sabdar 			file_size = size_left;
381*2654012fSReza Sabdar 			tar_hdr = &fake_tar_hdr;
382*2654012fSReza Sabdar 			tar_hdr->th_linkflag = last_action;
383*2654012fSReza Sabdar 
384*2654012fSReza Sabdar 			multi_volume = FALSE;
385*2654012fSReza Sabdar 			last_action = 0;
386*2654012fSReza Sabdar 		} else {
387*2654012fSReza Sabdar 			tar_hdr = (tlm_tar_hdr_t *)get_read_buffer(want,
388*2654012fSReza Sabdar 			    &erc, &actual_size, local_commands);
389*2654012fSReza Sabdar 			/*
390*2654012fSReza Sabdar 			 * we can ignore read errors here because
391*2654012fSReza Sabdar 			 *   1) they are logged by Restore Reader
392*2654012fSReza Sabdar 			 *   2) we are not doing anything important here
393*2654012fSReza Sabdar 			 *	just looking for the next work record.
394*2654012fSReza Sabdar 			 */
395*2654012fSReza Sabdar 			if (actual_size < want) {
396*2654012fSReza Sabdar 				/*
397*2654012fSReza Sabdar 				 * EOF hits here
398*2654012fSReza Sabdar 				 *
399*2654012fSReza Sabdar 				 * wait for another buffer to come along
400*2654012fSReza Sabdar 				 * or until the Reader thread tells us
401*2654012fSReza Sabdar 				 * that no more tapes will be loaded ...
402*2654012fSReza Sabdar 				 * time to stop.
403*2654012fSReza Sabdar 				 */
404*2654012fSReza Sabdar 				continue;
405*2654012fSReza Sabdar 			}
406*2654012fSReza Sabdar 
407*2654012fSReza Sabdar 			/*
408*2654012fSReza Sabdar 			 * check for "we are lost"
409*2654012fSReza Sabdar 			 */
410*2654012fSReza Sabdar 			chk_rv = tlm_vfy_tar_checksum(tar_hdr);
411*2654012fSReza Sabdar 			if (chk_rv == 0) {
412*2654012fSReza Sabdar 				/* one of the end of tar file marks */
413*2654012fSReza Sabdar 				if (++nzerohdr >= 2) {
414*2654012fSReza Sabdar 					NDMP_LOG(LOG_DEBUG,
415*2654012fSReza Sabdar 					    "nzerohdr %d, breaking",
416*2654012fSReza Sabdar 					    nzerohdr);
417*2654012fSReza Sabdar 					/* end of tar file */
418*2654012fSReza Sabdar 					break;
419*2654012fSReza Sabdar 				}
420*2654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "nzerohdr %d, continuing",
421*2654012fSReza Sabdar 				    nzerohdr);
422*2654012fSReza Sabdar 				continue;
423*2654012fSReza Sabdar 			} else if (chk_rv < 0) {
424*2654012fSReza Sabdar 				nzerohdr = 0;
425*2654012fSReza Sabdar 				/* skip this record */
426*2654012fSReza Sabdar 				continue;
427*2654012fSReza Sabdar 			}
428*2654012fSReza Sabdar 			nzerohdr = 0;
429*2654012fSReza Sabdar 
430*2654012fSReza Sabdar 			/*
431*2654012fSReza Sabdar 			 * When files are spanned to the next tape, the
432*2654012fSReza Sabdar 			 * information of the acls must not be over-written
433*2654012fSReza Sabdar 			 * by the information of the LF_MULTIVOL and LF_VOLHDR
434*2654012fSReza Sabdar 			 * header, whose information is irrelevant to the file.
435*2654012fSReza Sabdar 			 * The information of the original header must be
436*2654012fSReza Sabdar 			 * kept in the 'acl'.
437*2654012fSReza Sabdar 			 */
438*2654012fSReza Sabdar 			if (tar_hdr->th_linkflag != LF_MULTIVOL &&
439*2654012fSReza Sabdar 			    tar_hdr->th_linkflag != LF_VOLHDR) {
440*2654012fSReza Sabdar 				acls->acl_attr.st_mode =
441*2654012fSReza Sabdar 				    oct_atoi(tar_hdr->th_mode);
442*2654012fSReza Sabdar 				acls->acl_attr.st_size =
443*2654012fSReza Sabdar 				    oct_atoi(tar_hdr->th_size);
444*2654012fSReza Sabdar 				acls->acl_attr.st_uid =
445*2654012fSReza Sabdar 				    oct_atoi(tar_hdr->th_uid);
446*2654012fSReza Sabdar 				acls->acl_attr.st_gid =
447*2654012fSReza Sabdar 				    oct_atoi(tar_hdr->th_gid);
448*2654012fSReza Sabdar 				acls->acl_attr.st_mtime =
449*2654012fSReza Sabdar 				    oct_atoi(tar_hdr->th_mtime);
450*2654012fSReza Sabdar 				file_size = oct_atoi(tar_hdr->th_size);
451*2654012fSReza Sabdar 				acl_spot = 0;
452*2654012fSReza Sabdar 				last_action = tar_hdr->th_linkflag;
453*2654012fSReza Sabdar 			}
454*2654012fSReza Sabdar 		}
455*2654012fSReza Sabdar 
456*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "n [%s] f [%c] s %lld m %o u %d g %d t %d",
457*2654012fSReza Sabdar 		    tar_hdr->th_name, tar_hdr->th_linkflag,
458*2654012fSReza Sabdar 		    acls->acl_attr.st_size, acls->acl_attr.st_mode,
459*2654012fSReza Sabdar 		    acls->acl_attr.st_uid, acls->acl_attr.st_gid,
460*2654012fSReza Sabdar 		    acls->acl_attr.st_mtime);
461*2654012fSReza Sabdar 
462*2654012fSReza Sabdar 		switch (tar_hdr->th_linkflag) {
463*2654012fSReza Sabdar 		case LF_MULTIVOL:
464*2654012fSReza Sabdar 			multi_volume = TRUE;
465*2654012fSReza Sabdar 			break;
466*2654012fSReza Sabdar 		case LF_LINK:
467*2654012fSReza Sabdar 			is_hardlink = 1;
468*2654012fSReza Sabdar 			hardlink_inode =
469*2654012fSReza Sabdar 			    oct_atoi(tar_hdr->th_shared.th_hlink_ino);
470*2654012fSReza Sabdar 
471*2654012fSReza Sabdar 			/*
472*2654012fSReza Sabdar 			 * Check if we have restored a link with the same inode
473*2654012fSReza Sabdar 			 * If the inode is 0, we have to restore it as a
474*2654012fSReza Sabdar 			 * regular file.
475*2654012fSReza Sabdar 			 */
476*2654012fSReza Sabdar 			if (hardlink_inode) {
477*2654012fSReza Sabdar 				hardlink_done = !hardlink_q_get(hardlink_q,
478*2654012fSReza Sabdar 				    hardlink_inode, 0, &hardlink_target);
479*2654012fSReza Sabdar 			}
480*2654012fSReza Sabdar 
481*2654012fSReza Sabdar 			if (hardlink_done) {
482*2654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
483*2654012fSReza Sabdar 				    "found hardlink, inode = %u, target = [%s]",
484*2654012fSReza Sabdar 				    hardlink_inode,
485*2654012fSReza Sabdar 				    hardlink_target? hardlink_target : "--");
486*2654012fSReza Sabdar 
487*2654012fSReza Sabdar 				/* create a hardlink to hardlink_target */
488*2654012fSReza Sabdar 				file_name = (*longname == 0) ?
489*2654012fSReza Sabdar 				    tar_hdr->th_name : longname;
490*2654012fSReza Sabdar 				if (!is_file_wanted(file_name, sels, exls,
491*2654012fSReza Sabdar 				    flags, &mchtype, &pos)) {
492*2654012fSReza Sabdar 					nmp = NULL;
493*2654012fSReza Sabdar 					/*
494*2654012fSReza Sabdar 					 * This means that DMA did not send us
495*2654012fSReza Sabdar 					 * the correct fh_info for the file
496*2654012fSReza Sabdar 					 * in restore list.  We use the file
497*2654012fSReza Sabdar 					 * name entry in sels[] (ignore the
498*2654012fSReza Sabdar 					 * name in the tar header) as restore
499*2654012fSReza Sabdar 					 * target.
500*2654012fSReza Sabdar 					 */
501*2654012fSReza Sabdar 					if (DAR) {
502*2654012fSReza Sabdar 						nmp = rs_darhl_new_name(rnp,
503*2654012fSReza Sabdar 						    name, sels, &pos,
504*2654012fSReza Sabdar 						    file_name);
505*2654012fSReza Sabdar 					}
506*2654012fSReza Sabdar 				} else {
507*2654012fSReza Sabdar 					nmp = rs_new_name(rnp, name, pos,
508*2654012fSReza Sabdar 					    file_name);
509*2654012fSReza Sabdar 					if (!nmp) {
510*2654012fSReza Sabdar 						NDMP_LOG(LOG_DEBUG,
511*2654012fSReza Sabdar 						    "can't make name for %s",
512*2654012fSReza Sabdar 						    longname);
513*2654012fSReza Sabdar 					}
514*2654012fSReza Sabdar 				}
515*2654012fSReza Sabdar 
516*2654012fSReza Sabdar 				if (nmp) {
517*2654012fSReza Sabdar 					if (hardlink_target) {
518*2654012fSReza Sabdar 						erc = create_hard_link(
519*2654012fSReza Sabdar 						    hardlink_target, nmp,
520*2654012fSReza Sabdar 						    acls, job_stats);
521*2654012fSReza Sabdar 						if (erc == 0) {
522*2654012fSReza Sabdar 							(void)
523*2654012fSReza Sabdar 							    tlm_entry_restored(
524*2654012fSReza Sabdar 							    job_stats,
525*2654012fSReza Sabdar 							    file_name, pos);
526*2654012fSReza Sabdar 							NDMP_LOG(LOG_DEBUG,
527*2654012fSReza Sabdar 							    "restored %s -> %s",
528*2654012fSReza Sabdar 							    nmp,
529*2654012fSReza Sabdar 							    hardlink_target);
530*2654012fSReza Sabdar 						}
531*2654012fSReza Sabdar 					} else {
532*2654012fSReza Sabdar 						NDMP_LOG(LOG_DEBUG,
533*2654012fSReza Sabdar 						    "no target for hardlink %s",
534*2654012fSReza Sabdar 						    nmp);
535*2654012fSReza Sabdar 					}
536*2654012fSReza Sabdar 
537*2654012fSReza Sabdar 					name[0] = 0;
538*2654012fSReza Sabdar 					is_long_name = FALSE;
539*2654012fSReza Sabdar 				}
540*2654012fSReza Sabdar 
541*2654012fSReza Sabdar 				nm_end = 0;
542*2654012fSReza Sabdar 				longname[0] = 0;
543*2654012fSReza Sabdar 				lnk_end = 0;
544*2654012fSReza Sabdar 				longlink[0] = 0;
545*2654012fSReza Sabdar 
546*2654012fSReza Sabdar 				break;
547*2654012fSReza Sabdar 			}
548*2654012fSReza Sabdar 			/* otherwise fall through, restore like a normal file */
549*2654012fSReza Sabdar 			/*FALLTHROUGH*/
550*2654012fSReza Sabdar 		case LF_OLDNORMAL:
551*2654012fSReza Sabdar 			/*
552*2654012fSReza Sabdar 			 * check for TAR's end-of-tape method
553*2654012fSReza Sabdar 			 * of zero filled records.
554*2654012fSReza Sabdar 			 */
555*2654012fSReza Sabdar 			if (tar_hdr->th_name[0] == 0) {
556*2654012fSReza Sabdar 				break;
557*2654012fSReza Sabdar 			}
558*2654012fSReza Sabdar 			/*
559*2654012fSReza Sabdar 			 * otherwise fall through,
560*2654012fSReza Sabdar 			 * this is an old style normal file header
561*2654012fSReza Sabdar 			 */
562*2654012fSReza Sabdar 			/*FALLTHROUGH*/
563*2654012fSReza Sabdar 		case LF_NORMAL:
564*2654012fSReza Sabdar 		case LF_CONTIG:
565*2654012fSReza Sabdar 			job_stats->js_files_so_far++;
566*2654012fSReza Sabdar 			if (*hugename != 0) {
567*2654012fSReza Sabdar 				(void) strlcpy(longname, hugename,
568*2654012fSReza Sabdar 				    TLM_MAX_PATH_NAME);
569*2654012fSReza Sabdar 			} else if (*longname == 0) {
570*2654012fSReza Sabdar 				if (tar_hdr->th_name[0] != '/') {
571*2654012fSReza Sabdar 					/*
572*2654012fSReza Sabdar 					 * check for old tar format, it
573*2654012fSReza Sabdar 					 * does not have a leading "/"
574*2654012fSReza Sabdar 					 */
575*2654012fSReza Sabdar 					longname[0] = '/';
576*2654012fSReza Sabdar 					longname[1] = 0;
577*2654012fSReza Sabdar 					(void) strlcat(longname,
578*2654012fSReza Sabdar 					    tar_hdr->th_name,
579*2654012fSReza Sabdar 					    TLM_MAX_PATH_NAME);
580*2654012fSReza Sabdar 				} else {
581*2654012fSReza Sabdar 					(void) strlcpy(longname,
582*2654012fSReza Sabdar 					    tar_hdr->th_name,
583*2654012fSReza Sabdar 					    TLM_MAX_PATH_NAME);
584*2654012fSReza Sabdar 				}
585*2654012fSReza Sabdar 			}
586*2654012fSReza Sabdar 
587*2654012fSReza Sabdar 			want_this_file = is_file_wanted(longname, sels, exls,
588*2654012fSReza Sabdar 			    flags, &mchtype, &pos);
589*2654012fSReza Sabdar 			if (!want_this_file) {
590*2654012fSReza Sabdar 				nmp = NULL;
591*2654012fSReza Sabdar 				/*
592*2654012fSReza Sabdar 				 * This means that DMA did not send us valid
593*2654012fSReza Sabdar 				 * fh_info for the file in restore list.  We
594*2654012fSReza Sabdar 				 * use the file name entry in sels[] (ignore
595*2654012fSReza Sabdar 				 * the name in the tar header) as restore
596*2654012fSReza Sabdar 				 * target.
597*2654012fSReza Sabdar 				 */
598*2654012fSReza Sabdar 				if (DAR && (tar_hdr->th_linkflag == LF_LINK)) {
599*2654012fSReza Sabdar 					nmp = rs_darhl_new_name(rnp, name,
600*2654012fSReza Sabdar 					    sels, &pos, longname);
601*2654012fSReza Sabdar 
602*2654012fSReza Sabdar 					if (nmp) {
603*2654012fSReza Sabdar 						want_this_file = TRUE;
604*2654012fSReza Sabdar 						mchtype = PM_EXACT;
605*2654012fSReza Sabdar 					} else {
606*2654012fSReza Sabdar 						break_flg = TRUE;
607*2654012fSReza Sabdar 						break;
608*2654012fSReza Sabdar 					}
609*2654012fSReza Sabdar 				}
610*2654012fSReza Sabdar 			} else {
611*2654012fSReza Sabdar 				nmp = rs_new_name(rnp, name, pos, longname);
612*2654012fSReza Sabdar 				if (!nmp)
613*2654012fSReza Sabdar 					want_this_file = FALSE;
614*2654012fSReza Sabdar 			}
615*2654012fSReza Sabdar 
616*2654012fSReza Sabdar 			if (nmp)
617*2654012fSReza Sabdar 				(void) strlcpy(parentlnk, nmp, strlen(nmp) + 1);
618*2654012fSReza Sabdar 
619*2654012fSReza Sabdar 			/*
620*2654012fSReza Sabdar 			 * For a hardlink, even if it's not asked to be
621*2654012fSReza Sabdar 			 * restored, we restore it to a temporary location,
622*2654012fSReza Sabdar 			 * in case other links to the same file need to be
623*2654012fSReza Sabdar 			 * restored later.
624*2654012fSReza Sabdar 			 *
625*2654012fSReza Sabdar 			 * The temp files are created in tmplink_dir, with
626*2654012fSReza Sabdar 			 * names like ".tmphlrsnondar*".  They are cleaned up
627*2654012fSReza Sabdar 			 * at the completion of a restore.  However, if a
628*2654012fSReza Sabdar 			 * restore were interrupted, e.g. by a system reboot,
629*2654012fSReza Sabdar 			 * they would have to be cleaned up manually in order
630*2654012fSReza Sabdar 			 * for the disk space to be freed.
631*2654012fSReza Sabdar 			 *
632*2654012fSReza Sabdar 			 * If tmplink_dir is NULL, no temperorary files are
633*2654012fSReza Sabdar 			 * created during a restore.  This may result in some
634*2654012fSReza Sabdar 			 * hardlinks not being restored during a partial
635*2654012fSReza Sabdar 			 * restore.
636*2654012fSReza Sabdar 			 */
637*2654012fSReza Sabdar 			if (is_hardlink && !DAR && !want_this_file && !nmp) {
638*2654012fSReza Sabdar 				if (tmplink_dir) {
639*2654012fSReza Sabdar 					(void) snprintf(name, TLM_MAX_PATH_NAME,
640*2654012fSReza Sabdar 					    "%s/%s_%d", tmplink_dir,
641*2654012fSReza Sabdar 					    hardlink_tmp_name,
642*2654012fSReza Sabdar 					    hardlink_tmp_idx);
643*2654012fSReza Sabdar 					nmp = name;
644*2654012fSReza Sabdar 
645*2654012fSReza Sabdar 					hardlink_tmp_idx++;
646*2654012fSReza Sabdar 					hardlink_tmp_file = 1;
647*2654012fSReza Sabdar 					want_this_file = TRUE;
648*2654012fSReza Sabdar 					NDMP_LOG(LOG_DEBUG,
649*2654012fSReza Sabdar 					    "To restore temp hardlink file %s.",
650*2654012fSReza Sabdar 					    nmp);
651*2654012fSReza Sabdar 				} else {
652*2654012fSReza Sabdar 					NDMP_LOG(LOG_DEBUG,
653*2654012fSReza Sabdar 					    "No tmplink_dir specified.");
654*2654012fSReza Sabdar 				}
655*2654012fSReza Sabdar 			}
656*2654012fSReza Sabdar 
657*2654012fSReza Sabdar 			size_left = restore_file(&fp, nmp, file_size,
658*2654012fSReza Sabdar 			    huge_size, acls, want_this_file, local_commands,
659*2654012fSReza Sabdar 			    job_stats);
660*2654012fSReza Sabdar 
661*2654012fSReza Sabdar 			/*
662*2654012fSReza Sabdar 			 * In the case of non-DAR, we have to record the first
663*2654012fSReza Sabdar 			 * link for an inode that has multiple links. That's
664*2654012fSReza Sabdar 			 * the only link with data records actually backed up.
665*2654012fSReza Sabdar 			 * In this way, when we run into the other links, they
666*2654012fSReza Sabdar 			 * will be treated as links, and we won't go to look
667*2654012fSReza Sabdar 			 * for the data records to restore.  This is not a
668*2654012fSReza Sabdar 			 * problem for DAR, where DMA tells the tape where
669*2654012fSReza Sabdar 			 * to locate the data records.
670*2654012fSReza Sabdar 			 */
671*2654012fSReza Sabdar 			if (is_hardlink && !DAR) {
672*2654012fSReza Sabdar 				if (hardlink_q_add(hardlink_q, hardlink_inode,
673*2654012fSReza Sabdar 				    0, nmp, hardlink_tmp_file))
674*2654012fSReza Sabdar 					NDMP_LOG(LOG_DEBUG,
675*2654012fSReza Sabdar 					    "failed to add (%u, %s) to HL q",
676*2654012fSReza Sabdar 					    hardlink_inode, nmp);
677*2654012fSReza Sabdar 			}
678*2654012fSReza Sabdar 
679*2654012fSReza Sabdar 			/* remove / reverse the temporary stuff */
680*2654012fSReza Sabdar 			if (hardlink_tmp_file) {
681*2654012fSReza Sabdar 				nmp = NULL;
682*2654012fSReza Sabdar 				want_this_file = FALSE;
683*2654012fSReza Sabdar 				hardlink_tmp_file = 0;
684*2654012fSReza Sabdar 			}
685*2654012fSReza Sabdar 
686*2654012fSReza Sabdar 			/*
687*2654012fSReza Sabdar 			 * Check if it is time to set the attribute
688*2654012fSReza Sabdar 			 * of the restored directory
689*2654012fSReza Sabdar 			 */
690*2654012fSReza Sabdar 			while (nmp && ((bkpath = dtree_peek(stp)) != NULL)) {
691*2654012fSReza Sabdar 				if (strstr(nmp, bkpath))
692*2654012fSReza Sabdar 					break;
693*2654012fSReza Sabdar 
694*2654012fSReza Sabdar 				(void) dtree_pop(stp);
695*2654012fSReza Sabdar 			}
696*2654012fSReza Sabdar 
697*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "sizeleft %s %d, %lld", longname,
698*2654012fSReza Sabdar 			    size_left, huge_size);
699*2654012fSReza Sabdar 
700*2654012fSReza Sabdar 			if (size_left == -TLM_STOP) {
701*2654012fSReza Sabdar 				break_flg = TRUE;
702*2654012fSReza Sabdar 				rv = -1;
703*2654012fSReza Sabdar 				commands->tcs_reader = TLM_ABORT;
704*2654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG, "restoring [%s] failed",
705*2654012fSReza Sabdar 				    longname);
706*2654012fSReza Sabdar 				break;
707*2654012fSReza Sabdar 			}
708*2654012fSReza Sabdar 
709*2654012fSReza Sabdar 			if (want_this_file) {
710*2654012fSReza Sabdar 				job_stats->js_bytes_total += file_size;
711*2654012fSReza Sabdar 				job_stats->js_files_total++;
712*2654012fSReza Sabdar 			}
713*2654012fSReza Sabdar 
714*2654012fSReza Sabdar 			huge_size -= file_size;
715*2654012fSReza Sabdar 			if (huge_size < 0) {
716*2654012fSReza Sabdar 				huge_size = 0;
717*2654012fSReza Sabdar 			}
718*2654012fSReza Sabdar 			if (size_left == 0 && huge_size == 0) {
719*2654012fSReza Sabdar 				if (PM_EXACT_OR_CHILD(mchtype)) {
720*2654012fSReza Sabdar 					(void) tlm_entry_restored(job_stats,
721*2654012fSReza Sabdar 					    longname, pos);
722*2654012fSReza Sabdar 
723*2654012fSReza Sabdar 					/*
724*2654012fSReza Sabdar 					 * Add an entry to hardlink_q to record
725*2654012fSReza Sabdar 					 * this hardlink.
726*2654012fSReza Sabdar 					 */
727*2654012fSReza Sabdar 					if (is_hardlink) {
728*2654012fSReza Sabdar 						NDMP_LOG(LOG_DEBUG,
729*2654012fSReza Sabdar 						    "Restored hardlink file %s",
730*2654012fSReza Sabdar 						    nmp);
731*2654012fSReza Sabdar 
732*2654012fSReza Sabdar 						if (DAR) {
733*2654012fSReza Sabdar 							(void) hardlink_q_add(
734*2654012fSReza Sabdar 							    hardlink_q,
735*2654012fSReza Sabdar 							    hardlink_inode, 0,
736*2654012fSReza Sabdar 							    nmp, 0);
737*2654012fSReza Sabdar 						}
738*2654012fSReza Sabdar 					}
739*2654012fSReza Sabdar 				}
740*2654012fSReza Sabdar 
741*2654012fSReza Sabdar 				nm_end = 0;
742*2654012fSReza Sabdar 				longname[0] = 0;
743*2654012fSReza Sabdar 				lnk_end = 0;
744*2654012fSReza Sabdar 				longlink[0] = 0;
745*2654012fSReza Sabdar 				hugename[0] = 0;
746*2654012fSReza Sabdar 				name[0] = 0;
747*2654012fSReza Sabdar 				is_long_name = FALSE;
748*2654012fSReza Sabdar 			}
749*2654012fSReza Sabdar 			break;
750*2654012fSReza Sabdar 		case LF_XATTR:
751*2654012fSReza Sabdar 			file_name = (*longname == 0) ? tar_hdr->th_name :
752*2654012fSReza Sabdar 			    longname;
753*2654012fSReza Sabdar 
754*2654012fSReza Sabdar 			size_left = restore_xattr_hdr(&fp, parentlnk,
755*2654012fSReza Sabdar 			    file_name, file_size, acls, local_commands,
756*2654012fSReza Sabdar 			    job_stats);
757*2654012fSReza Sabdar 
758*2654012fSReza Sabdar 			break;
759*2654012fSReza Sabdar 		case LF_SYMLINK:
760*2654012fSReza Sabdar 			file_name = (*longname == 0) ? tar_hdr->th_name :
761*2654012fSReza Sabdar 			    longname;
762*2654012fSReza Sabdar 			link_name = (*longlink == 0) ?
763*2654012fSReza Sabdar 			    tar_hdr->th_linkname : longlink;
764*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "file_name[%s]", file_name);
765*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "link_name[%s]", link_name);
766*2654012fSReza Sabdar 			if (is_file_wanted(file_name, sels, exls, flags,
767*2654012fSReza Sabdar 			    &mchtype, &pos)) {
768*2654012fSReza Sabdar 				nmp = rs_new_name(rnp, name, pos, file_name);
769*2654012fSReza Sabdar 				if (nmp) {
770*2654012fSReza Sabdar 					erc = create_sym_link(nmp, link_name,
771*2654012fSReza Sabdar 					    acls, job_stats);
772*2654012fSReza Sabdar 					if (erc == 0 &&
773*2654012fSReza Sabdar 					    PM_EXACT_OR_CHILD(mchtype))
774*2654012fSReza Sabdar 						(void) tlm_entry_restored(
775*2654012fSReza Sabdar 						    job_stats, file_name, pos);
776*2654012fSReza Sabdar 					name[0] = 0;
777*2654012fSReza Sabdar 				}
778*2654012fSReza Sabdar 			}
779*2654012fSReza Sabdar 			nm_end = 0;
780*2654012fSReza Sabdar 			longname[0] = 0;
781*2654012fSReza Sabdar 			lnk_end = 0;
782*2654012fSReza Sabdar 			longlink[0] = 0;
783*2654012fSReza Sabdar 			break;
784*2654012fSReza Sabdar 		case LF_DIR:
785*2654012fSReza Sabdar 			file_name = *longname == 0 ? tar_hdr->th_name :
786*2654012fSReza Sabdar 			    longname;
787*2654012fSReza Sabdar 			if (is_file_wanted(file_name, sels, exls, flags,
788*2654012fSReza Sabdar 			    &mchtype, &pos)) {
789*2654012fSReza Sabdar 				nmp = rs_new_name(rnp, name, pos, file_name);
790*2654012fSReza Sabdar 				if (nmp && mchtype != PM_PARENT) {
791*2654012fSReza Sabdar 					(void) strlcpy(parentlnk, nmp,
792*2654012fSReza Sabdar 					    strlen(nmp));
793*2654012fSReza Sabdar 					erc = create_directory(nmp, job_stats);
794*2654012fSReza Sabdar 					if (erc == 0 &&
795*2654012fSReza Sabdar 					    PM_EXACT_OR_CHILD(mchtype))
796*2654012fSReza Sabdar 						(void) tlm_entry_restored(
797*2654012fSReza Sabdar 						    job_stats, file_name, pos);
798*2654012fSReza Sabdar 					/*
799*2654012fSReza Sabdar 					 * Check if it is time to set
800*2654012fSReza Sabdar 					 * the attribute of the restored
801*2654012fSReza Sabdar 					 * directory
802*2654012fSReza Sabdar 					 */
803*2654012fSReza Sabdar 					while ((bkpath = dtree_peek(stp))
804*2654012fSReza Sabdar 					    != NULL) {
805*2654012fSReza Sabdar 						if (strstr(nmp, bkpath))
806*2654012fSReza Sabdar 							break;
807*2654012fSReza Sabdar 						(void) dtree_pop(stp);
808*2654012fSReza Sabdar 					}
809*2654012fSReza Sabdar 
810*2654012fSReza Sabdar 					(void) dtree_push(stp, nmp, acls);
811*2654012fSReza Sabdar 					name[0] = 0;
812*2654012fSReza Sabdar 				}
813*2654012fSReza Sabdar 			}
814*2654012fSReza Sabdar 			nm_end = 0;
815*2654012fSReza Sabdar 			longname[0] = 0;
816*2654012fSReza Sabdar 			lnk_end = 0;
817*2654012fSReza Sabdar 			longlink[0] = 0;
818*2654012fSReza Sabdar 			break;
819*2654012fSReza Sabdar 		case LF_FIFO:
820*2654012fSReza Sabdar 			file_name = *longname == 0 ? tar_hdr->th_name :
821*2654012fSReza Sabdar 			    longname;
822*2654012fSReza Sabdar 			if (is_file_wanted(file_name, sels, exls, flags,
823*2654012fSReza Sabdar 			    &mchtype, &pos)) {
824*2654012fSReza Sabdar 				nmp = rs_new_name(rnp, name, pos, file_name);
825*2654012fSReza Sabdar 				if (nmp) {
826*2654012fSReza Sabdar 					erc = create_fifo(nmp, acls);
827*2654012fSReza Sabdar 					if (erc == 0 &&
828*2654012fSReza Sabdar 					    PM_EXACT_OR_CHILD(mchtype))
829*2654012fSReza Sabdar 						(void) tlm_entry_restored(
830*2654012fSReza Sabdar 						    job_stats, file_name, pos);
831*2654012fSReza Sabdar 					name[0] = 0;
832*2654012fSReza Sabdar 				}
833*2654012fSReza Sabdar 			}
834*2654012fSReza Sabdar 			nm_end = 0;
835*2654012fSReza Sabdar 			longname[0] = 0;
836*2654012fSReza Sabdar 			lnk_end = 0;
837*2654012fSReza Sabdar 			longlink[0] = 0;
838*2654012fSReza Sabdar 			break;
839*2654012fSReza Sabdar 		case LF_LONGLINK:
840*2654012fSReza Sabdar 			file_size = min(file_size, TLM_MAX_PATH_NAME - lnk_end);
841*2654012fSReza Sabdar 			file_size = max(0, file_size);
842*2654012fSReza Sabdar 			size_left = get_long_name(lib, drv, file_size, longlink,
843*2654012fSReza Sabdar 			    &lnk_end, local_commands);
844*2654012fSReza Sabdar 
845*2654012fSReza Sabdar 			if (size_left != 0)
846*2654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
847*2654012fSReza Sabdar 				    "fsize %d sleft %d lnkend %d",
848*2654012fSReza Sabdar 				    file_size, size_left, lnk_end);
849*2654012fSReza Sabdar 			break;
850*2654012fSReza Sabdar 		case LF_LONGNAME:
851*2654012fSReza Sabdar 			file_size = min(file_size, TLM_MAX_PATH_NAME - nm_end);
852*2654012fSReza Sabdar 			file_size = max(0, file_size);
853*2654012fSReza Sabdar 			size_left = get_long_name(lib, drv, file_size, longname,
854*2654012fSReza Sabdar 			    &nm_end, local_commands);
855*2654012fSReza Sabdar 
856*2654012fSReza Sabdar 			if (size_left != 0)
857*2654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
858*2654012fSReza Sabdar 				    "fsize %d sleft %d nmend %d",
859*2654012fSReza Sabdar 				    file_size, size_left, nm_end);
860*2654012fSReza Sabdar 			is_long_name = TRUE;
861*2654012fSReza Sabdar 			break;
862*2654012fSReza Sabdar 		case LF_ACL:
863*2654012fSReza Sabdar 			size_left = load_acl_info(lib, drv, file_size, acls,
864*2654012fSReza Sabdar 			    &acl_spot, local_commands);
865*2654012fSReza Sabdar 			break;
866*2654012fSReza Sabdar 		case LF_VOLHDR:
867*2654012fSReza Sabdar 			break;
868*2654012fSReza Sabdar 		case LF_HUMONGUS:
869*2654012fSReza Sabdar 			(void) memset(hugename, 0, TLM_MAX_PATH_NAME);
870*2654012fSReza Sabdar 			(void) get_humongus_file_header(lib, drv, file_size,
871*2654012fSReza Sabdar 			    &huge_size, hugename, local_commands);
872*2654012fSReza Sabdar 			break;
873*2654012fSReza Sabdar 		default:
874*2654012fSReza Sabdar 			break;
875*2654012fSReza Sabdar 
876*2654012fSReza Sabdar 		}
877*2654012fSReza Sabdar 
878*2654012fSReza Sabdar 		/*
879*2654012fSReza Sabdar 		 * If the restore is running using DAR we should check for
880*2654012fSReza Sabdar 		 * long file names and HUGE file sizes.
881*2654012fSReza Sabdar 		 */
882*2654012fSReza Sabdar 		if (DAR && tar_hdr->th_linkflag != LF_ACL &&
883*2654012fSReza Sabdar 		    !huge_size && !is_long_name)
884*2654012fSReza Sabdar 			break;
885*2654012fSReza Sabdar 	}
886*2654012fSReza Sabdar 
887*2654012fSReza Sabdar 	/*
888*2654012fSReza Sabdar 	 * tear down
889*2654012fSReza Sabdar 	 */
890*2654012fSReza Sabdar 	if (fp != 0) {
891*2654012fSReza Sabdar 		(void) close(fp);
892*2654012fSReza Sabdar 	}
893*2654012fSReza Sabdar 	while (dtree_pop(stp) != -1)
894*2654012fSReza Sabdar 		;
895*2654012fSReza Sabdar 	cstack_delete(stp);
896*2654012fSReza Sabdar 	free(acls);
897*2654012fSReza Sabdar 	free(longname);
898*2654012fSReza Sabdar 	free(parentlnk);
899*2654012fSReza Sabdar 	free(longlink);
900*2654012fSReza Sabdar 	free(hugename);
901*2654012fSReza Sabdar 	free(name);
902*2654012fSReza Sabdar 	return (rv);
903*2654012fSReza Sabdar }
904*2654012fSReza Sabdar 
905*2654012fSReza Sabdar /*
906*2654012fSReza Sabdar  * Main file restore function for tar (should run as a thread)
907*2654012fSReza Sabdar  */
908*2654012fSReza Sabdar int
909*2654012fSReza Sabdar tar_getfile(tlm_backup_restore_arg_t *argp)
910*2654012fSReza Sabdar {
911*2654012fSReza Sabdar 	tlm_job_stats_t	*job_stats;
912*2654012fSReza Sabdar 	char	**sels;		/* list of files desired */
913*2654012fSReza Sabdar 	char	**exls;		/* list of files not wanted */
914*2654012fSReza Sabdar 	char	*dir;		/* where to restore the files */
915*2654012fSReza Sabdar 	char	job[TLM_MAX_BACKUP_JOB_NAME+1];
916*2654012fSReza Sabdar 				/* the restore job name */
917*2654012fSReza Sabdar 	int	erc;		/* error return codes */
918*2654012fSReza Sabdar 	int	flags;
919*2654012fSReza Sabdar 	struct	rs_name_maker rn;
920*2654012fSReza Sabdar 	tlm_commands_t *commands;
921*2654012fSReza Sabdar 	tlm_cmd_t *local_commands;
922*2654012fSReza Sabdar 	char *list = NULL;
923*2654012fSReza Sabdar 
924*2654012fSReza Sabdar 	commands = argp->ba_commands;
925*2654012fSReza Sabdar 	local_commands = argp->ba_cmd;
926*2654012fSReza Sabdar 
927*2654012fSReza Sabdar 	flags = 0;
928*2654012fSReza Sabdar 
929*2654012fSReza Sabdar 	dir = ndmp_malloc(TLM_MAX_PATH_NAME);
930*2654012fSReza Sabdar 	if (dir == NULL) {
931*2654012fSReza Sabdar 		local_commands->tc_reader = TLM_STOP;
932*2654012fSReza Sabdar 		(void) pthread_barrier_wait(&argp->ba_barrier);
933*2654012fSReza Sabdar 		return (-1);
934*2654012fSReza Sabdar 	}
935*2654012fSReza Sabdar 
936*2654012fSReza Sabdar 	(void) strlcpy(job, argp->ba_job, TLM_MAX_BACKUP_JOB_NAME+1);
937*2654012fSReza Sabdar 	(void) strlcpy(dir, argp->ba_dir, TLM_MAX_PATH_NAME);
938*2654012fSReza Sabdar 
939*2654012fSReza Sabdar 	flags |= RSFLG_OVR_ALWAYS;
940*2654012fSReza Sabdar 	flags |= RSFLG_IGNORE_CASE;
941*2654012fSReza Sabdar 
942*2654012fSReza Sabdar 	/*
943*2654012fSReza Sabdar 	 * do not test for "dir" having no string, since that
944*2654012fSReza Sabdar 	 * is a legal condition.  Restore to origional location
945*2654012fSReza Sabdar 	 * will not have a restore directory.
946*2654012fSReza Sabdar 	 */
947*2654012fSReza Sabdar 	if (*job == '\0') {
948*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No job defined");
949*2654012fSReza Sabdar 		local_commands->tc_reader = TLM_STOP;
950*2654012fSReza Sabdar 		free(dir);
951*2654012fSReza Sabdar 		(void) pthread_barrier_wait(&argp->ba_barrier);
952*2654012fSReza Sabdar 		return (-1);
953*2654012fSReza Sabdar 	}
954*2654012fSReza Sabdar 
955*2654012fSReza Sabdar 	sels = argp->ba_sels;
956*2654012fSReza Sabdar 	if (sels == NULL) {
957*2654012fSReza Sabdar 		local_commands->tc_reader = TLM_STOP;
958*2654012fSReza Sabdar 		free(dir);
959*2654012fSReza Sabdar 		(void) pthread_barrier_wait(&argp->ba_barrier);
960*2654012fSReza Sabdar 		return (-1);
961*2654012fSReza Sabdar 	}
962*2654012fSReza Sabdar 	exls = &list;
963*2654012fSReza Sabdar 
964*2654012fSReza Sabdar 	tlm_log_list("selections", sels);
965*2654012fSReza Sabdar 	tlm_log_list("exclusions", exls);
966*2654012fSReza Sabdar 
967*2654012fSReza Sabdar 	if (wildcard_enabled())
968*2654012fSReza Sabdar 		flags |= RSFLG_MATCH_WCARD;
969*2654012fSReza Sabdar 
970*2654012fSReza Sabdar 	local_commands->tc_ref++;
971*2654012fSReza Sabdar 	commands->tcs_writer_count++;
972*2654012fSReza Sabdar 
973*2654012fSReza Sabdar 	/*
974*2654012fSReza Sabdar 	 * let the launcher continue
975*2654012fSReza Sabdar 	 */
976*2654012fSReza Sabdar 	(void) pthread_barrier_wait(&argp->ba_barrier);
977*2654012fSReza Sabdar 
978*2654012fSReza Sabdar 	job_stats = tlm_ref_job_stats(job);
979*2654012fSReza Sabdar 
980*2654012fSReza Sabdar 	rn.rn_fp = catnames;
981*2654012fSReza Sabdar 	rn.rn_nlp = dir;
982*2654012fSReza Sabdar 
983*2654012fSReza Sabdar 	/*
984*2654012fSReza Sabdar 	 * work
985*2654012fSReza Sabdar 	 */
986*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "start restore job %s", job);
987*2654012fSReza Sabdar 	erc = tar_getdir(commands, local_commands, job_stats, &rn, 1, 1,
988*2654012fSReza Sabdar 	    sels, exls, flags, 0, NULL);
989*2654012fSReza Sabdar 
990*2654012fSReza Sabdar 	/*
991*2654012fSReza Sabdar 	 * teardown
992*2654012fSReza Sabdar 	 */
993*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "end restore job %s", job);
994*2654012fSReza Sabdar 	tlm_un_ref_job_stats(job);
995*2654012fSReza Sabdar 	tlm_release_list(sels);
996*2654012fSReza Sabdar 	tlm_release_list(exls);
997*2654012fSReza Sabdar 
998*2654012fSReza Sabdar 	commands->tcs_writer_count--;
999*2654012fSReza Sabdar 	local_commands->tc_reader = TLM_STOP;
1000*2654012fSReza Sabdar 	tlm_release_reader_writer_ipc(local_commands);
1001*2654012fSReza Sabdar 	free(dir);
1002*2654012fSReza Sabdar 	return (erc);
1003*2654012fSReza Sabdar }
1004*2654012fSReza Sabdar 
1005*2654012fSReza Sabdar /*
1006*2654012fSReza Sabdar  * Creates the directories all the way down to the
1007*2654012fSReza Sabdar  * end if they dont exist
1008*2654012fSReza Sabdar  */
1009*2654012fSReza Sabdar int
1010*2654012fSReza Sabdar make_dirs(char *dir)
1011*2654012fSReza Sabdar {
1012*2654012fSReza Sabdar 	char c;
1013*2654012fSReza Sabdar 	char *cp, *end;
1014*2654012fSReza Sabdar 	struct stat64 st;
1015*2654012fSReza Sabdar 
1016*2654012fSReza Sabdar 	cp = dir;
1017*2654012fSReza Sabdar 	cp += strspn(cp, "/");
1018*2654012fSReza Sabdar 	end = dir + strlen(dir);
1019*2654012fSReza Sabdar 	do {
1020*2654012fSReza Sabdar 		if (*cp == '\0' || *cp == '/') {
1021*2654012fSReza Sabdar 			c = *cp;
1022*2654012fSReza Sabdar 			*cp = '\0';
1023*2654012fSReza Sabdar 			if (lstat64(dir, &st) < 0)
1024*2654012fSReza Sabdar 				if (mkdir(dir, 0777) < 0) {
1025*2654012fSReza Sabdar 					NDMP_LOG(LOG_DEBUG, "Error %d"
1026*2654012fSReza Sabdar 					    " creating directory %s",
1027*2654012fSReza Sabdar 					    errno, dir);
1028*2654012fSReza Sabdar 					*cp = c;
1029*2654012fSReza Sabdar 					return (-1);
1030*2654012fSReza Sabdar 				}
1031*2654012fSReza Sabdar 
1032*2654012fSReza Sabdar 			*cp = c;
1033*2654012fSReza Sabdar 		}
1034*2654012fSReza Sabdar 	} while (++cp <= end);
1035*2654012fSReza Sabdar 
1036*2654012fSReza Sabdar 	return (0);
1037*2654012fSReza Sabdar }
1038*2654012fSReza Sabdar 
1039*2654012fSReza Sabdar /*
1040*2654012fSReza Sabdar  * Creates the directories leading to the given path
1041*2654012fSReza Sabdar  */
1042*2654012fSReza Sabdar int
1043*2654012fSReza Sabdar mkbasedir(char *path)
1044*2654012fSReza Sabdar {
1045*2654012fSReza Sabdar 	int rv;
1046*2654012fSReza Sabdar 	char *cp;
1047*2654012fSReza Sabdar 	struct stat64 st;
1048*2654012fSReza Sabdar 
1049*2654012fSReza Sabdar 	if (!path || !*path) {
1050*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1051*2654012fSReza Sabdar 		return (-1);
1052*2654012fSReza Sabdar 	}
1053*2654012fSReza Sabdar 
1054*2654012fSReza Sabdar 	cp = strrchr(path, '/');
1055*2654012fSReza Sabdar 	if (cp)
1056*2654012fSReza Sabdar 		*cp = '\0';
1057*2654012fSReza Sabdar 	rv = lstat64(path, &st);
1058*2654012fSReza Sabdar 	if (rv < 0)	/* need new directories */
1059*2654012fSReza Sabdar 		rv = make_dirs(path);
1060*2654012fSReza Sabdar 	if (cp)
1061*2654012fSReza Sabdar 		*cp = '/';
1062*2654012fSReza Sabdar 
1063*2654012fSReza Sabdar 	return (rv);
1064*2654012fSReza Sabdar }
1065*2654012fSReza Sabdar 
1066*2654012fSReza Sabdar 
1067*2654012fSReza Sabdar /*
1068*2654012fSReza Sabdar  * read the file off the tape back onto disk
1069*2654012fSReza Sabdar  */
1070*2654012fSReza Sabdar static long
1071*2654012fSReza Sabdar restore_file(int *fp,
1072*2654012fSReza Sabdar     char *real_name,
1073*2654012fSReza Sabdar     long size,
1074*2654012fSReza Sabdar     longlong_t huge_size,
1075*2654012fSReza Sabdar     tlm_acls_t *acls,
1076*2654012fSReza Sabdar     boolean_t want_this_file,
1077*2654012fSReza Sabdar     tlm_cmd_t *local_commands,
1078*2654012fSReza Sabdar     tlm_job_stats_t *job_stats)
1079*2654012fSReza Sabdar {
1080*2654012fSReza Sabdar 	struct stat64	attr;
1081*2654012fSReza Sabdar 
1082*2654012fSReza Sabdar 	if (!real_name) {
1083*2654012fSReza Sabdar 		if (want_this_file) {
1084*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "No file name but wanted!");
1085*2654012fSReza Sabdar 			want_this_file = FALSE;
1086*2654012fSReza Sabdar 		}
1087*2654012fSReza Sabdar 	} else
1088*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "new file[%s]", real_name);
1089*2654012fSReza Sabdar 
1090*2654012fSReza Sabdar 	/*
1091*2654012fSReza Sabdar 	 * OK, some FM is creeping in here ...
1092*2654012fSReza Sabdar 	 * int *fp is used to keep the
1093*2654012fSReza Sabdar 	 * backup file channel open through
1094*2654012fSReza Sabdar 	 * the interruption of EOT and
1095*2654012fSReza Sabdar 	 * processing the headers of the
1096*2654012fSReza Sabdar 	 * next tape.  So, if *fp is zero
1097*2654012fSReza Sabdar 	 * then no file is open yet and all
1098*2654012fSReza Sabdar 	 * is normal.  If *fp has a number
1099*2654012fSReza Sabdar 	 * then we are returning after an
1100*2654012fSReza Sabdar 	 * EOT break.
1101*2654012fSReza Sabdar 	 *
1102*2654012fSReza Sabdar 	 * *fp is now also open for HUGE files
1103*2654012fSReza Sabdar 	 * that are put back in sections.
1104*2654012fSReza Sabdar 	 */
1105*2654012fSReza Sabdar 
1106*2654012fSReza Sabdar 	if (*fp == 0 && want_this_file) {
1107*2654012fSReza Sabdar 		int	erc_stat;
1108*2654012fSReza Sabdar 
1109*2654012fSReza Sabdar 		if (mkbasedir(real_name) < 0)
1110*2654012fSReza Sabdar 			job_stats->js_errors++;
1111*2654012fSReza Sabdar 
1112*2654012fSReza Sabdar 		erc_stat = stat64(real_name, (struct stat64 *)&attr);
1113*2654012fSReza Sabdar 		if (erc_stat < 0) {
1114*2654012fSReza Sabdar 			/*EMPTY*/
1115*2654012fSReza Sabdar 			/* new file */
1116*2654012fSReza Sabdar 		} else if (acls->acl_overwrite) {
1117*2654012fSReza Sabdar 			/*EMPTY*/
1118*2654012fSReza Sabdar 			/* take this file no matter what */
1119*2654012fSReza Sabdar 		} else if (acls->acl_update) {
1120*2654012fSReza Sabdar 			if (attr.st_mtime < acls->acl_attr.st_mtime) {
1121*2654012fSReza Sabdar 				/*EMPTY*/
1122*2654012fSReza Sabdar 				/* tape is newer */
1123*2654012fSReza Sabdar 			} else {
1124*2654012fSReza Sabdar 				/* disk file is newer */
1125*2654012fSReza Sabdar 				want_this_file = FALSE;
1126*2654012fSReza Sabdar 			}
1127*2654012fSReza Sabdar 		} else {
1128*2654012fSReza Sabdar 			/*
1129*2654012fSReza Sabdar 			 * no overwrite, no update,
1130*2654012fSReza Sabdar 			 * do not ever replace old files.
1131*2654012fSReza Sabdar 			 */
1132*2654012fSReza Sabdar 			want_this_file = TRUE;
1133*2654012fSReza Sabdar 		}
1134*2654012fSReza Sabdar 		if (want_this_file) {
1135*2654012fSReza Sabdar 
1136*2654012fSReza Sabdar 			*fp = open(real_name, O_CREAT | O_WRONLY,
1137*2654012fSReza Sabdar 			    S_IRUSR | S_IWUSR);
1138*2654012fSReza Sabdar 			if (*fp == -1) {
1139*2654012fSReza Sabdar 				NDMP_LOG(LOG_ERR,
1140*2654012fSReza Sabdar 				    "Could not open %s for restore.",
1141*2654012fSReza Sabdar 				    real_name);
1142*2654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
1143*2654012fSReza Sabdar 				    "fp=%d err=%d ", *fp, errno);
1144*2654012fSReza Sabdar 				job_stats->js_errors++;
1145*2654012fSReza Sabdar 				want_this_file = FALSE;
1146*2654012fSReza Sabdar 				/*
1147*2654012fSReza Sabdar 				 * we cannot return here,
1148*2654012fSReza Sabdar 				 * the file is still on
1149*2654012fSReza Sabdar 				 * the tape and must be
1150*2654012fSReza Sabdar 				 * skipped over.
1151*2654012fSReza Sabdar 				 */
1152*2654012fSReza Sabdar 			}
1153*2654012fSReza Sabdar 		}
1154*2654012fSReza Sabdar 		(void) strlcpy(local_commands->tc_file_name, real_name,
1155*2654012fSReza Sabdar 		    TLM_MAX_PATH_NAME);
1156*2654012fSReza Sabdar 	}
1157*2654012fSReza Sabdar 
1158*2654012fSReza Sabdar 	/*
1159*2654012fSReza Sabdar 	 * this is the size left in the next segment
1160*2654012fSReza Sabdar 	 */
1161*2654012fSReza Sabdar 	huge_size -= size;
1162*2654012fSReza Sabdar 
1163*2654012fSReza Sabdar 	/*
1164*2654012fSReza Sabdar 	 * work
1165*2654012fSReza Sabdar 	 */
1166*2654012fSReza Sabdar 	while (size > 0 && local_commands->tc_writer == TLM_RESTORE_RUN) {
1167*2654012fSReza Sabdar 		int	actual_size;
1168*2654012fSReza Sabdar 		int	error;
1169*2654012fSReza Sabdar 		char	*rec;
1170*2654012fSReza Sabdar 		int	write_size;
1171*2654012fSReza Sabdar 
1172*2654012fSReza Sabdar 		/*
1173*2654012fSReza Sabdar 		 * Use bytes_in_file field to tell reader the amount
1174*2654012fSReza Sabdar 		 * of data still need to be read for this file.
1175*2654012fSReza Sabdar 		 */
1176*2654012fSReza Sabdar 		job_stats->js_bytes_in_file = size;
1177*2654012fSReza Sabdar 
1178*2654012fSReza Sabdar 		error = 0;
1179*2654012fSReza Sabdar 		rec = get_read_buffer(size, &error, &actual_size,
1180*2654012fSReza Sabdar 		    local_commands);
1181*2654012fSReza Sabdar 		if (actual_size <= 0) {
1182*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
1183*2654012fSReza Sabdar 			    "RESTORE WRITER> error %d, actual_size %d",
1184*2654012fSReza Sabdar 			    error, actual_size);
1185*2654012fSReza Sabdar 
1186*2654012fSReza Sabdar 			/* no more data for this file for now */
1187*2654012fSReza Sabdar 			job_stats->js_bytes_in_file = 0;
1188*2654012fSReza Sabdar 
1189*2654012fSReza Sabdar 			return (size);
1190*2654012fSReza Sabdar 		} else if (error) {
1191*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "Error %d in file [%s]",
1192*2654012fSReza Sabdar 			    error, local_commands->tc_file_name);
1193*2654012fSReza Sabdar 			break;
1194*2654012fSReza Sabdar 		} else {
1195*2654012fSReza Sabdar 			write_size = min(size, actual_size);
1196*2654012fSReza Sabdar 			if (want_this_file) {
1197*2654012fSReza Sabdar 				write_size = write(*fp, rec, write_size);
1198*2654012fSReza Sabdar 			}
1199*2654012fSReza Sabdar 			NS_ADD(wdisk, write_size);
1200*2654012fSReza Sabdar 			NS_INC(wfile);
1201*2654012fSReza Sabdar 			size -= write_size;
1202*2654012fSReza Sabdar 		}
1203*2654012fSReza Sabdar 	}
1204*2654012fSReza Sabdar 
1205*2654012fSReza Sabdar 	/* no more data for this file for now */
1206*2654012fSReza Sabdar 	job_stats->js_bytes_in_file = 0;
1207*2654012fSReza Sabdar 
1208*2654012fSReza Sabdar 	/*
1209*2654012fSReza Sabdar 	 * teardown
1210*2654012fSReza Sabdar 	 */
1211*2654012fSReza Sabdar 	if (*fp != 0 && huge_size <= 0) {
1212*2654012fSReza Sabdar 		(void) close(*fp);
1213*2654012fSReza Sabdar 		*fp = 0;
1214*2654012fSReza Sabdar 		set_acl(real_name, acls);
1215*2654012fSReza Sabdar 	}
1216*2654012fSReza Sabdar 	return (0);
1217*2654012fSReza Sabdar }
1218*2654012fSReza Sabdar 
1219*2654012fSReza Sabdar /*
1220*2654012fSReza Sabdar  * Set the extended attributes file attribute
1221*2654012fSReza Sabdar  */
1222*2654012fSReza Sabdar static void
1223*2654012fSReza Sabdar set_xattr(int fd, struct stat64 st)
1224*2654012fSReza Sabdar {
1225*2654012fSReza Sabdar 	struct timeval times[2];
1226*2654012fSReza Sabdar 
1227*2654012fSReza Sabdar 	times[0].tv_sec = st.st_atime;
1228*2654012fSReza Sabdar 	times[1].tv_sec = st.st_mtime;
1229*2654012fSReza Sabdar 
1230*2654012fSReza Sabdar 	(void) fchmod(fd, st.st_mode);
1231*2654012fSReza Sabdar 	(void) fchown(fd, st.st_uid, st.st_gid);
1232*2654012fSReza Sabdar 	(void) futimesat(fd, ".", times);
1233*2654012fSReza Sabdar }
1234*2654012fSReza Sabdar 
1235*2654012fSReza Sabdar /*
1236*2654012fSReza Sabdar  * read the extended attribute header and write
1237*2654012fSReza Sabdar  * it to the file
1238*2654012fSReza Sabdar  */
1239*2654012fSReza Sabdar static long
1240*2654012fSReza Sabdar restore_xattr_hdr(int *fp,
1241*2654012fSReza Sabdar     char *name,
1242*2654012fSReza Sabdar     char *fname,
1243*2654012fSReza Sabdar     long size,
1244*2654012fSReza Sabdar     tlm_acls_t *acls,
1245*2654012fSReza Sabdar     tlm_cmd_t *local_commands,
1246*2654012fSReza Sabdar     tlm_job_stats_t *job_stats)
1247*2654012fSReza Sabdar {
1248*2654012fSReza Sabdar 	tlm_tar_hdr_t *tar_hdr;
1249*2654012fSReza Sabdar 	struct xattr_hdr *xhdr;
1250*2654012fSReza Sabdar 	struct xattr_buf *xbuf;
1251*2654012fSReza Sabdar 	int namelen;
1252*2654012fSReza Sabdar 	char *xattrname;
1253*2654012fSReza Sabdar 	int actual_size;
1254*2654012fSReza Sabdar 	int error;
1255*2654012fSReza Sabdar 
1256*2654012fSReza Sabdar 	if (!fname) {
1257*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "No file name but wanted!");
1258*2654012fSReza Sabdar 	} else {
1259*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "new xattr[%s]", fname);
1260*2654012fSReza Sabdar 	}
1261*2654012fSReza Sabdar 
1262*2654012fSReza Sabdar 	error = 0;
1263*2654012fSReza Sabdar 	xhdr = (struct xattr_hdr *)get_read_buffer(size, &error,
1264*2654012fSReza Sabdar 	    &actual_size, local_commands);
1265*2654012fSReza Sabdar 	if (error) {
1266*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
1267*2654012fSReza Sabdar 		    "Could not read xattr [%s:%s] for restore. ",
1268*2654012fSReza Sabdar 		    name, fname);
1269*2654012fSReza Sabdar 		job_stats->js_errors++;
1270*2654012fSReza Sabdar 		return (0);
1271*2654012fSReza Sabdar 	}
1272*2654012fSReza Sabdar 
1273*2654012fSReza Sabdar 	/* Check extended attribute header */
1274*2654012fSReza Sabdar 	if (strcmp(xhdr->h_version, XATTR_ARCH_VERS) != 0) {
1275*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
1276*2654012fSReza Sabdar 		    "Unrecognized header format [%s]", xhdr->h_version);
1277*2654012fSReza Sabdar 		return (0);
1278*2654012fSReza Sabdar 	}
1279*2654012fSReza Sabdar 	xbuf = (struct xattr_buf *)(((char *)xhdr) + sizeof (struct xattr_hdr));
1280*2654012fSReza Sabdar 
1281*2654012fSReza Sabdar 	(void) sscanf(xbuf->h_namesz, "%7d", &namelen);
1282*2654012fSReza Sabdar 	xattrname = xbuf->h_names + strlen(xbuf->h_names) + 1;
1283*2654012fSReza Sabdar 
1284*2654012fSReza Sabdar 	if (*fp == 0) {
1285*2654012fSReza Sabdar 		int fd;
1286*2654012fSReza Sabdar 
1287*2654012fSReza Sabdar 		fd = attropen(name, xattrname, O_CREAT | O_RDWR, 0755);
1288*2654012fSReza Sabdar 		if (fd == -1) {
1289*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
1290*2654012fSReza Sabdar 			    "Could not open xattr [%s:%s] for restore.",
1291*2654012fSReza Sabdar 			    name, xattrname);
1292*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "err=%d ", errno);
1293*2654012fSReza Sabdar 			job_stats->js_errors++;
1294*2654012fSReza Sabdar 		}
1295*2654012fSReza Sabdar 		(void) strlcpy(local_commands->tc_file_name, xattrname,
1296*2654012fSReza Sabdar 		    TLM_MAX_PATH_NAME);
1297*2654012fSReza Sabdar 		*fp = fd;
1298*2654012fSReza Sabdar 	}
1299*2654012fSReza Sabdar 
1300*2654012fSReza Sabdar 	/* Get the actual extended attribute file */
1301*2654012fSReza Sabdar 	tar_hdr = (tlm_tar_hdr_t *)get_read_buffer(sizeof (*tar_hdr),
1302*2654012fSReza Sabdar 	    &error, &actual_size, local_commands);
1303*2654012fSReza Sabdar 	if (error) {
1304*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
1305*2654012fSReza Sabdar 		    "Could not read xattr data [%s:%s] for restore. ",
1306*2654012fSReza Sabdar 		    fname, xattrname);
1307*2654012fSReza Sabdar 		job_stats->js_errors++;
1308*2654012fSReza Sabdar 		return (0);
1309*2654012fSReza Sabdar 	}
1310*2654012fSReza Sabdar 	acls->acl_attr.st_mode = oct_atoi(tar_hdr->th_mode);
1311*2654012fSReza Sabdar 	acls->acl_attr.st_size = oct_atoi(tar_hdr->th_size);
1312*2654012fSReza Sabdar 	acls->acl_attr.st_uid = oct_atoi(tar_hdr->th_uid);
1313*2654012fSReza Sabdar 	acls->acl_attr.st_gid = oct_atoi(tar_hdr->th_gid);
1314*2654012fSReza Sabdar 	acls->acl_attr.st_mtime = oct_atoi(tar_hdr->th_mtime);
1315*2654012fSReza Sabdar 
1316*2654012fSReza Sabdar 	size = acls->acl_attr.st_size;
1317*2654012fSReza Sabdar 	while (size > 0 && local_commands->tc_writer == TLM_RESTORE_RUN) {
1318*2654012fSReza Sabdar 		char	*rec;
1319*2654012fSReza Sabdar 		int	write_size;
1320*2654012fSReza Sabdar 
1321*2654012fSReza Sabdar 		error = 0;
1322*2654012fSReza Sabdar 		rec = get_read_buffer(size, &error, &actual_size,
1323*2654012fSReza Sabdar 		    local_commands);
1324*2654012fSReza Sabdar 		if (actual_size <= 0) {
1325*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
1326*2654012fSReza Sabdar 			    "RESTORE WRITER> error %d, actual_size %d",
1327*2654012fSReza Sabdar 			    error, actual_size);
1328*2654012fSReza Sabdar 
1329*2654012fSReza Sabdar 			return (size);
1330*2654012fSReza Sabdar 		} else if (error) {
1331*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "Error %d in file [%s]",
1332*2654012fSReza Sabdar 			    error, local_commands->tc_file_name);
1333*2654012fSReza Sabdar 			break;
1334*2654012fSReza Sabdar 		} else {
1335*2654012fSReza Sabdar 			write_size = min(size, actual_size);
1336*2654012fSReza Sabdar 			write_size = write(*fp, rec, write_size);
1337*2654012fSReza Sabdar 			NS_ADD(wdisk, write_size);
1338*2654012fSReza Sabdar 			NS_INC(wfile);
1339*2654012fSReza Sabdar 			size -= write_size;
1340*2654012fSReza Sabdar 		}
1341*2654012fSReza Sabdar 	}
1342*2654012fSReza Sabdar 
1343*2654012fSReza Sabdar 	if (*fp != 0) {
1344*2654012fSReza Sabdar 		set_xattr(*fp, acls->acl_attr);
1345*2654012fSReza Sabdar 		(void) close(*fp);
1346*2654012fSReza Sabdar 		*fp = 0;
1347*2654012fSReza Sabdar 	}
1348*2654012fSReza Sabdar 	return (0);
1349*2654012fSReza Sabdar }
1350*2654012fSReza Sabdar 
1351*2654012fSReza Sabdar /*
1352*2654012fSReza Sabdar  * Match the name with the list
1353*2654012fSReza Sabdar  */
1354*2654012fSReza Sabdar static int
1355*2654012fSReza Sabdar exact_find(char *name, char **list)
1356*2654012fSReza Sabdar {
1357*2654012fSReza Sabdar 	boolean_t found;
1358*2654012fSReza Sabdar 	int i;
1359*2654012fSReza Sabdar 	char *cp;
1360*2654012fSReza Sabdar 
1361*2654012fSReza Sabdar 	found = FALSE;
1362*2654012fSReza Sabdar 	for (i = 0; *list != NULL; list++, i++) {
1363*2654012fSReza Sabdar 		cp = *list + strspn(*list, "/");
1364*2654012fSReza Sabdar 		if (match(cp, name)) {
1365*2654012fSReza Sabdar 			found = TRUE;
1366*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "exact_find> found[%s]", cp);
1367*2654012fSReza Sabdar 			break;
1368*2654012fSReza Sabdar 		}
1369*2654012fSReza Sabdar 	}
1370*2654012fSReza Sabdar 
1371*2654012fSReza Sabdar 	return (found);
1372*2654012fSReza Sabdar }
1373*2654012fSReza Sabdar 
1374*2654012fSReza Sabdar /*
1375*2654012fSReza Sabdar  * On error, return FALSE and prevent restoring(probably) unwanted data.
1376*2654012fSReza Sabdar  */
1377*2654012fSReza Sabdar static int
1378*2654012fSReza Sabdar is_parent(char *parent, char *child, int flags)
1379*2654012fSReza Sabdar {
1380*2654012fSReza Sabdar 	char tmp[TLM_MAX_PATH_NAME];
1381*2654012fSReza Sabdar 	boolean_t rv;
1382*2654012fSReza Sabdar 
1383*2654012fSReza Sabdar 	if (IS_SET(flags, RSFLG_MATCH_WCARD)) {
1384*2654012fSReza Sabdar 		if (!tlm_cat_path(tmp, parent, "*")) {
1385*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
1386*2654012fSReza Sabdar 			    "is_parent> path too long [%s]", parent);
1387*2654012fSReza Sabdar 			rv = FALSE;
1388*2654012fSReza Sabdar 		} else
1389*2654012fSReza Sabdar 			rv = (match(tmp, child) != 0) ? TRUE : FALSE;
1390*2654012fSReza Sabdar 	} else {
1391*2654012fSReza Sabdar 		if (!tlm_cat_path(tmp, parent, "/")) {
1392*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
1393*2654012fSReza Sabdar 			    "is_parent> path too long [%s]", parent);
1394*2654012fSReza Sabdar 			rv = FALSE;
1395*2654012fSReza Sabdar 		} else
1396*2654012fSReza Sabdar 			rv = (strncmp(tmp, child, strlen(tmp)) == 0) ?
1397*2654012fSReza Sabdar 			    TRUE : FALSE;
1398*2654012fSReza Sabdar 	}
1399*2654012fSReza Sabdar 
1400*2654012fSReza Sabdar 	return (rv);
1401*2654012fSReza Sabdar }
1402*2654012fSReza Sabdar 
1403*2654012fSReza Sabdar /*
1404*2654012fSReza Sabdar  * Used to match the filename inside the list
1405*2654012fSReza Sabdar  */
1406*2654012fSReza Sabdar static boolean_t
1407*2654012fSReza Sabdar strexactcmp(char *s, char *t)
1408*2654012fSReza Sabdar {
1409*2654012fSReza Sabdar 	return ((strcmp(s, t) == 0) ? TRUE : FALSE);
1410*2654012fSReza Sabdar }
1411*2654012fSReza Sabdar 
1412*2654012fSReza Sabdar /*
1413*2654012fSReza Sabdar  * Check if the file is needed to be restored
1414*2654012fSReza Sabdar  */
1415*2654012fSReza Sabdar static boolean_t
1416*2654012fSReza Sabdar is_file_wanted(char *name,
1417*2654012fSReza Sabdar     char **sels,
1418*2654012fSReza Sabdar     char **exls,
1419*2654012fSReza Sabdar     int flags,
1420*2654012fSReza Sabdar     int *mchtype,
1421*2654012fSReza Sabdar     int *pos)
1422*2654012fSReza Sabdar {
1423*2654012fSReza Sabdar 	char *p_sel;
1424*2654012fSReza Sabdar 	char *uc_name, *retry, *namep;
1425*2654012fSReza Sabdar 	boolean_t found;
1426*2654012fSReza Sabdar 	int i;
1427*2654012fSReza Sabdar 	name_match_fp_t *cmp_fp;
1428*2654012fSReza Sabdar 
1429*2654012fSReza Sabdar 	if (name == NULL || sels == NULL || exls == NULL)
1430*2654012fSReza Sabdar 		return (FALSE);
1431*2654012fSReza Sabdar 
1432*2654012fSReza Sabdar 	found = FALSE;
1433*2654012fSReza Sabdar 	if (mchtype != NULL)
1434*2654012fSReza Sabdar 		*mchtype = PM_NONE;
1435*2654012fSReza Sabdar 	if (pos != NULL)
1436*2654012fSReza Sabdar 		*pos = 0;
1437*2654012fSReza Sabdar 
1438*2654012fSReza Sabdar 	/*
1439*2654012fSReza Sabdar 	 * For empty selection, restore everything
1440*2654012fSReza Sabdar 	 */
1441*2654012fSReza Sabdar 	if (*sels == NULL || **sels == '\0') {
1442*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "is_file_wanted: Restore all");
1443*2654012fSReza Sabdar 		return (TRUE);
1444*2654012fSReza Sabdar 	}
1445*2654012fSReza Sabdar 
1446*2654012fSReza Sabdar 	uc_name = ndmp_malloc(TLM_MAX_PATH_NAME);
1447*2654012fSReza Sabdar 	retry = ndmp_malloc(TLM_MAX_PATH_NAME);
1448*2654012fSReza Sabdar 	if (uc_name == NULL || retry == NULL) {
1449*2654012fSReza Sabdar 		free(uc_name);
1450*2654012fSReza Sabdar 		free(retry);
1451*2654012fSReza Sabdar 		return (FALSE);
1452*2654012fSReza Sabdar 	}
1453*2654012fSReza Sabdar 
1454*2654012fSReza Sabdar 	if (IS_SET(flags, RSFLG_MATCH_WCARD))
1455*2654012fSReza Sabdar 		cmp_fp = match;
1456*2654012fSReza Sabdar 	else
1457*2654012fSReza Sabdar 		cmp_fp = strexactcmp;
1458*2654012fSReza Sabdar 
1459*2654012fSReza Sabdar 	namep = name + strspn(name, "/");
1460*2654012fSReza Sabdar 	if (IS_SET(flags, RSFLG_IGNORE_CASE)) {
1461*2654012fSReza Sabdar 		(void) strlcpy(uc_name, namep, TLM_MAX_PATH_NAME);
1462*2654012fSReza Sabdar 		(void) strupr(uc_name);
1463*2654012fSReza Sabdar 		namep = uc_name;
1464*2654012fSReza Sabdar 	}
1465*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "is_file_wanted> flg: 0x%x name: [%s]",
1466*2654012fSReza Sabdar 	    flags, name);
1467*2654012fSReza Sabdar 
1468*2654012fSReza Sabdar 	for (i = 0; *sels != NULL; sels++, i++) {
1469*2654012fSReza Sabdar 		p_sel = *sels + strspn(*sels, "/");
1470*2654012fSReza Sabdar 
1471*2654012fSReza Sabdar 		/*
1472*2654012fSReza Sabdar 		 * Try exact match.
1473*2654012fSReza Sabdar 		 */
1474*2654012fSReza Sabdar 		if ((*cmp_fp)(p_sel, namep)) {
1475*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "match1> pos: %d [%s][%s]",
1476*2654012fSReza Sabdar 			    i, p_sel, name);
1477*2654012fSReza Sabdar 			found = TRUE;
1478*2654012fSReza Sabdar 			if (mchtype != NULL)
1479*2654012fSReza Sabdar 				*mchtype = PM_EXACT;
1480*2654012fSReza Sabdar 			break;
1481*2654012fSReza Sabdar 		}
1482*2654012fSReza Sabdar 		/*
1483*2654012fSReza Sabdar 		 * Try "entry/" and the current selection.  The
1484*2654012fSReza Sabdar 		 * current selection may be something like "<something>/".
1485*2654012fSReza Sabdar 		 */
1486*2654012fSReza Sabdar 		(void) tlm_cat_path(retry, namep, "/");
1487*2654012fSReza Sabdar 		if ((*cmp_fp)(p_sel, retry)) {
1488*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "match2> pos %d [%s][%s]",
1489*2654012fSReza Sabdar 			    i, p_sel, name);
1490*2654012fSReza Sabdar 			found = TRUE;
1491*2654012fSReza Sabdar 			if (mchtype != NULL)
1492*2654012fSReza Sabdar 				*mchtype = PM_EXACT;
1493*2654012fSReza Sabdar 			break;
1494*2654012fSReza Sabdar 		}
1495*2654012fSReza Sabdar 		/*
1496*2654012fSReza Sabdar 		 * If the following check returns true it means that the
1497*2654012fSReza Sabdar 		 * 'name' is an entry below the 'p_sel' hierarchy.
1498*2654012fSReza Sabdar 		 */
1499*2654012fSReza Sabdar 		if (is_parent(p_sel, namep, flags)) {
1500*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "parent1> pos %d [%s][%s]",
1501*2654012fSReza Sabdar 			    i, p_sel, name);
1502*2654012fSReza Sabdar 			found = TRUE;
1503*2654012fSReza Sabdar 			if (mchtype != NULL)
1504*2654012fSReza Sabdar 				*mchtype = PM_CHILD;
1505*2654012fSReza Sabdar 			break;
1506*2654012fSReza Sabdar 		}
1507*2654012fSReza Sabdar 
1508*2654012fSReza Sabdar 		/*
1509*2654012fSReza Sabdar 		 * There is a special case for parent directories of a
1510*2654012fSReza Sabdar 		 * selection.  If 'p_sel' is something like "*d1", the
1511*2654012fSReza Sabdar 		 * middle directories of the final entry can't be determined
1512*2654012fSReza Sabdar 		 * until the final entry matches with 'p_sel'.  At that
1513*2654012fSReza Sabdar 		 * time the middle directories of the entry have been passed
1514*2654012fSReza Sabdar 		 * and they can't be restored.
1515*2654012fSReza Sabdar 		 */
1516*2654012fSReza Sabdar 		if (is_parent(namep, p_sel, flags)) {
1517*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "parent2> pos %d [%s][%s]",
1518*2654012fSReza Sabdar 			    i, p_sel, name);
1519*2654012fSReza Sabdar 			found = TRUE;
1520*2654012fSReza Sabdar 			if (mchtype != NULL)
1521*2654012fSReza Sabdar 				*mchtype = PM_PARENT;
1522*2654012fSReza Sabdar 			break;
1523*2654012fSReza Sabdar 		}
1524*2654012fSReza Sabdar 	}
1525*2654012fSReza Sabdar 
1526*2654012fSReza Sabdar 	/* Check for exclusions.  */
1527*2654012fSReza Sabdar 	if (found && exact_find(namep, exls)) {
1528*2654012fSReza Sabdar 		if (mchtype != NULL)
1529*2654012fSReza Sabdar 			*mchtype = PM_NONE;
1530*2654012fSReza Sabdar 		found = FALSE;
1531*2654012fSReza Sabdar 	}
1532*2654012fSReza Sabdar 	if (found && pos != NULL)
1533*2654012fSReza Sabdar 		*pos = i;
1534*2654012fSReza Sabdar 
1535*2654012fSReza Sabdar 	free(uc_name);
1536*2654012fSReza Sabdar 	free(retry);
1537*2654012fSReza Sabdar 	return (found);
1538*2654012fSReza Sabdar }
1539*2654012fSReza Sabdar 
1540*2654012fSReza Sabdar /*
1541*2654012fSReza Sabdar  * Read the specified amount data into the buffer.  Detects EOT or EOF
1542*2654012fSReza Sabdar  * during read.
1543*2654012fSReza Sabdar  *
1544*2654012fSReza Sabdar  * Returns the number of bytes actually read.  On error returns -1.
1545*2654012fSReza Sabdar  */
1546*2654012fSReza Sabdar static int
1547*2654012fSReza Sabdar input_mem(int l,
1548*2654012fSReza Sabdar     int d,
1549*2654012fSReza Sabdar     tlm_cmd_t *lcmds,
1550*2654012fSReza Sabdar     char *mem,
1551*2654012fSReza Sabdar     int len)
1552*2654012fSReza Sabdar {
1553*2654012fSReza Sabdar 	int err;
1554*2654012fSReza Sabdar 	int toread, actual_size, rec_size;
1555*2654012fSReza Sabdar 	char *rec;
1556*2654012fSReza Sabdar 
1557*2654012fSReza Sabdar 	if (l <= 0 || d <= 0 || !lcmds || !mem) {
1558*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Invalid argument");
1559*2654012fSReza Sabdar 		return (-1);
1560*2654012fSReza Sabdar 	}
1561*2654012fSReza Sabdar 
1562*2654012fSReza Sabdar 	toread = len;
1563*2654012fSReza Sabdar 	while (toread > 0) {
1564*2654012fSReza Sabdar 		rec = get_read_buffer(toread, &err, &actual_size, lcmds);
1565*2654012fSReza Sabdar 		if (actual_size <= 0) {
1566*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "err %d act_size %d detected",
1567*2654012fSReza Sabdar 			    err, actual_size);
1568*2654012fSReza Sabdar 			break;
1569*2654012fSReza Sabdar 		} else if (err) {
1570*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "error %d reading data", err);
1571*2654012fSReza Sabdar 			return (-1);
1572*2654012fSReza Sabdar 		}
1573*2654012fSReza Sabdar 		rec_size = min(actual_size, toread);
1574*2654012fSReza Sabdar 		(void) memcpy(mem, rec, rec_size);
1575*2654012fSReza Sabdar 		mem += rec_size;
1576*2654012fSReza Sabdar 		toread -= rec_size;
1577*2654012fSReza Sabdar 	}
1578*2654012fSReza Sabdar 
1579*2654012fSReza Sabdar 	return (len - toread);
1580*2654012fSReza Sabdar }
1581*2654012fSReza Sabdar 
1582*2654012fSReza Sabdar /*
1583*2654012fSReza Sabdar  * pick up the name and size of a HUGE file
1584*2654012fSReza Sabdar  */
1585*2654012fSReza Sabdar static	int
1586*2654012fSReza Sabdar get_humongus_file_header(int lib,
1587*2654012fSReza Sabdar     int	drv,
1588*2654012fSReza Sabdar     long recsize,
1589*2654012fSReza Sabdar     longlong_t *size,
1590*2654012fSReza Sabdar     char *name,
1591*2654012fSReza Sabdar     tlm_cmd_t *local_commands)
1592*2654012fSReza Sabdar {
1593*2654012fSReza Sabdar 	char *p_record, *value;
1594*2654012fSReza Sabdar 	int rv;
1595*2654012fSReza Sabdar 
1596*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "HUGE Record found: %d", recsize);
1597*2654012fSReza Sabdar 
1598*2654012fSReza Sabdar 	rv = 0;
1599*2654012fSReza Sabdar 	if (recsize == 0) {
1600*2654012fSReza Sabdar 		/*
1601*2654012fSReza Sabdar 		 * The humongus_file_header was written in a
1602*2654012fSReza Sabdar 		 * RECORDSIZE block and the header.size field of this
1603*2654012fSReza Sabdar 		 * record was 0 before this fix.  For backward compatiblity
1604*2654012fSReza Sabdar 		 * read only one RECORDSIZE-size block if the header.size
1605*2654012fSReza Sabdar 		 * field is 0.  Otherwise the header.size field should show
1606*2654012fSReza Sabdar 		 * the length of the data of this header.
1607*2654012fSReza Sabdar 		 */
1608*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Old HUGE record found");
1609*2654012fSReza Sabdar 		recsize = RECORDSIZE;
1610*2654012fSReza Sabdar 	}
1611*2654012fSReza Sabdar 
1612*2654012fSReza Sabdar 	if (input_mem(lib, drv, local_commands, name, recsize) != recsize) {
1613*2654012fSReza Sabdar 		rv = -1;
1614*2654012fSReza Sabdar 		*size = 0;
1615*2654012fSReza Sabdar 		*name = '\0';
1616*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Error reading a HUGE file name");
1617*2654012fSReza Sabdar 	} else {
1618*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "HUGE [%s]", name);
1619*2654012fSReza Sabdar 
1620*2654012fSReza Sabdar 		p_record = name;
1621*2654012fSReza Sabdar 		value = parse(&p_record, " ");
1622*2654012fSReza Sabdar 		*size = atoll(value);
1623*2654012fSReza Sabdar 		/*
1624*2654012fSReza Sabdar 		 * Note: Since the backed up names are not longer than
1625*2654012fSReza Sabdar 		 * NAME_MAX and the buffer passed to us is
1626*2654012fSReza Sabdar 		 * TLM_MAX_PATH_NAME, it should be safe to use strlcpy
1627*2654012fSReza Sabdar 		 * without check on the buffer size.
1628*2654012fSReza Sabdar 		 */
1629*2654012fSReza Sabdar 		(void) strlcpy(name, p_record, TLM_MAX_PATH_NAME);
1630*2654012fSReza Sabdar 	}
1631*2654012fSReza Sabdar 
1632*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "HUGE Record %lld [%s]", *size, name);
1633*2654012fSReza Sabdar 
1634*2654012fSReza Sabdar 	return (rv);
1635*2654012fSReza Sabdar }
1636*2654012fSReza Sabdar 
1637*2654012fSReza Sabdar /*
1638*2654012fSReza Sabdar  * pick up the long name from the special tape file
1639*2654012fSReza Sabdar  */
1640*2654012fSReza Sabdar static int
1641*2654012fSReza Sabdar get_long_name(int lib,
1642*2654012fSReza Sabdar     int drv,
1643*2654012fSReza Sabdar     long recsize,
1644*2654012fSReza Sabdar     char *name,
1645*2654012fSReza Sabdar     long *buf_spot,
1646*2654012fSReza Sabdar     tlm_cmd_t *local_commands)
1647*2654012fSReza Sabdar {
1648*2654012fSReza Sabdar 	int nread;
1649*2654012fSReza Sabdar 
1650*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "LONGNAME Record found rs %d bs %d", recsize,
1651*2654012fSReza Sabdar 	    *buf_spot);
1652*2654012fSReza Sabdar 
1653*2654012fSReza Sabdar 	if (*buf_spot < 0)
1654*2654012fSReza Sabdar 		*buf_spot = 0;
1655*2654012fSReza Sabdar 
1656*2654012fSReza Sabdar 	nread = input_mem(lib, drv, local_commands, name + *buf_spot,
1657*2654012fSReza Sabdar 	    recsize);
1658*2654012fSReza Sabdar 	if (nread < 0) {
1659*2654012fSReza Sabdar 		nread = recsize; /* return 0 as size left */
1660*2654012fSReza Sabdar 		name[*buf_spot] = '\0';
1661*2654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Error %d reading a long file name %s.",
1662*2654012fSReza Sabdar 		    nread, name);
1663*2654012fSReza Sabdar 	} else {
1664*2654012fSReza Sabdar 		*buf_spot += nread;
1665*2654012fSReza Sabdar 		name[*buf_spot] = '\0';
1666*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "LONGNAME [%s]", name);
1667*2654012fSReza Sabdar 	}
1668*2654012fSReza Sabdar 
1669*2654012fSReza Sabdar 	return (recsize - nread);
1670*2654012fSReza Sabdar }
1671*2654012fSReza Sabdar 
1672*2654012fSReza Sabdar /*
1673*2654012fSReza Sabdar  * create a new directory
1674*2654012fSReza Sabdar  */
1675*2654012fSReza Sabdar static	int
1676*2654012fSReza Sabdar create_directory(char *dir, tlm_job_stats_t *job_stats)
1677*2654012fSReza Sabdar {
1678*2654012fSReza Sabdar 	struct stat64 attr;
1679*2654012fSReza Sabdar 	char	*p;
1680*2654012fSReza Sabdar 	char	temp;
1681*2654012fSReza Sabdar 	int	erc;
1682*2654012fSReza Sabdar 
1683*2654012fSReza Sabdar 	/*
1684*2654012fSReza Sabdar 	 * Make sure all directories in this path exist, create them if
1685*2654012fSReza Sabdar 	 * needed.
1686*2654012fSReza Sabdar 	 */
1687*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "new dir[%s]", dir);
1688*2654012fSReza Sabdar 
1689*2654012fSReza Sabdar 	erc = 0;
1690*2654012fSReza Sabdar 	p = &dir[1];
1691*2654012fSReza Sabdar 	do {
1692*2654012fSReza Sabdar 		temp = *p;
1693*2654012fSReza Sabdar 		if (temp == '/' || temp == 0) {
1694*2654012fSReza Sabdar 			*p = 0;
1695*2654012fSReza Sabdar 			if (stat64(dir, &attr) < 0) {
1696*2654012fSReza Sabdar 				erc = mkdir(dir, 0777);
1697*2654012fSReza Sabdar 				if (erc < 0) {
1698*2654012fSReza Sabdar 					job_stats->js_errors++;
1699*2654012fSReza Sabdar 					NDMP_LOG(LOG_DEBUG,
1700*2654012fSReza Sabdar 					    "Could not create directory %s",
1701*2654012fSReza Sabdar 					    dir);
1702*2654012fSReza Sabdar 					break;
1703*2654012fSReza Sabdar 				}
1704*2654012fSReza Sabdar 			}
1705*2654012fSReza Sabdar 			*p = temp;
1706*2654012fSReza Sabdar 		}
1707*2654012fSReza Sabdar 		p++;
1708*2654012fSReza Sabdar 	} while (temp != 0);
1709*2654012fSReza Sabdar 
1710*2654012fSReza Sabdar 	return (erc);
1711*2654012fSReza Sabdar }
1712*2654012fSReza Sabdar 
1713*2654012fSReza Sabdar /*
1714*2654012fSReza Sabdar  * create a new hardlink
1715*2654012fSReza Sabdar  */
1716*2654012fSReza Sabdar static int
1717*2654012fSReza Sabdar create_hard_link(char *name_old, char *name_new,
1718*2654012fSReza Sabdar     tlm_acls_t *acls, tlm_job_stats_t *job_stats)
1719*2654012fSReza Sabdar {
1720*2654012fSReza Sabdar 	int erc;
1721*2654012fSReza Sabdar 
1722*2654012fSReza Sabdar 	if (mkbasedir(name_new)) {
1723*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "faile to make base dir for [%s]",
1724*2654012fSReza Sabdar 		    name_new);
1725*2654012fSReza Sabdar 
1726*2654012fSReza Sabdar 		return (-1);
1727*2654012fSReza Sabdar 	}
1728*2654012fSReza Sabdar 
1729*2654012fSReza Sabdar 	erc = link(name_old, name_new);
1730*2654012fSReza Sabdar 	if (erc) {
1731*2654012fSReza Sabdar 		job_stats->js_errors++;
1732*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "error %d (errno %d) hardlink [%s] to [%s]",
1733*2654012fSReza Sabdar 		    erc, errno, name_new, name_old);
1734*2654012fSReza Sabdar 	} else {
1735*2654012fSReza Sabdar 		set_acl(name_new, acls);
1736*2654012fSReza Sabdar 	}
1737*2654012fSReza Sabdar 	return (erc);
1738*2654012fSReza Sabdar }
1739*2654012fSReza Sabdar 
1740*2654012fSReza Sabdar /*
1741*2654012fSReza Sabdar  * create a new symlink
1742*2654012fSReza Sabdar  */
1743*2654012fSReza Sabdar /*ARGSUSED*/
1744*2654012fSReza Sabdar static int
1745*2654012fSReza Sabdar create_sym_link(char *dst, char *target, tlm_acls_t *acls,
1746*2654012fSReza Sabdar     tlm_job_stats_t *job_satats)
1747*2654012fSReza Sabdar {
1748*2654012fSReza Sabdar 	int erc;
1749*2654012fSReza Sabdar 
1750*2654012fSReza Sabdar 	if (mkbasedir(dst) < 0)
1751*2654012fSReza Sabdar 		return (-1);
1752*2654012fSReza Sabdar 
1753*2654012fSReza Sabdar 	erc = symlink(target, dst);
1754*2654012fSReza Sabdar 	if (erc) {
1755*2654012fSReza Sabdar 		job_satats->js_errors++;
1756*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "error %d (errno %d) softlink [%s] to [%s]",
1757*2654012fSReza Sabdar 		    erc, errno, dst, target);
1758*2654012fSReza Sabdar 	}
1759*2654012fSReza Sabdar 
1760*2654012fSReza Sabdar 	return (erc);
1761*2654012fSReza Sabdar }
1762*2654012fSReza Sabdar 
1763*2654012fSReza Sabdar /*
1764*2654012fSReza Sabdar  * create a new FIFO
1765*2654012fSReza Sabdar  */
1766*2654012fSReza Sabdar static int
1767*2654012fSReza Sabdar create_fifo(char *name, tlm_acls_t *acls)
1768*2654012fSReza Sabdar {
1769*2654012fSReza Sabdar 	(void) mknod(name, 0777 + S_IFIFO, 0);
1770*2654012fSReza Sabdar 	set_acl(name, acls);
1771*2654012fSReza Sabdar 	return (0);
1772*2654012fSReza Sabdar }
1773*2654012fSReza Sabdar 
1774*2654012fSReza Sabdar /*
1775*2654012fSReza Sabdar  * read in the ACLs for the next file
1776*2654012fSReza Sabdar  */
1777*2654012fSReza Sabdar static long
1778*2654012fSReza Sabdar load_acl_info(int lib,
1779*2654012fSReza Sabdar     int drv,
1780*2654012fSReza Sabdar     long file_size,
1781*2654012fSReza Sabdar     tlm_acls_t *acls,
1782*2654012fSReza Sabdar     long *acl_spot,
1783*2654012fSReza Sabdar     tlm_cmd_t *local_commands)
1784*2654012fSReza Sabdar {
1785*2654012fSReza Sabdar 	char *bp;
1786*2654012fSReza Sabdar 	int nread;
1787*2654012fSReza Sabdar 
1788*2654012fSReza Sabdar 	/*
1789*2654012fSReza Sabdar 	 * If the ACL is spanned on tapes, then the acl_spot should NOT be
1790*2654012fSReza Sabdar 	 * 0 on next calls to this function to read the rest of the ACL
1791*2654012fSReza Sabdar 	 * on next tapes.
1792*2654012fSReza Sabdar 	 */
1793*2654012fSReza Sabdar 	if (*acl_spot == 0) {
1794*2654012fSReza Sabdar 		(void) memset(acls, 0, sizeof (tlm_acls_t));
1795*2654012fSReza Sabdar 	}
1796*2654012fSReza Sabdar 
1797*2654012fSReza Sabdar 	bp = ((char *)&acls->acl_info) + *acl_spot;
1798*2654012fSReza Sabdar 	nread = input_mem(lib, drv, local_commands, (void *)bp, file_size);
1799*2654012fSReza Sabdar 	if (nread < 0) {
1800*2654012fSReza Sabdar 		*acl_spot = 0;
1801*2654012fSReza Sabdar 		(void) memset(acls, 0, sizeof (tlm_acls_t));
1802*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Error reading ACL data");
1803*2654012fSReza Sabdar 		return (0);
1804*2654012fSReza Sabdar 	}
1805*2654012fSReza Sabdar 	*acl_spot += nread;
1806*2654012fSReza Sabdar 	acls->acl_non_trivial = TRUE;
1807*2654012fSReza Sabdar 
1808*2654012fSReza Sabdar 	return (file_size - nread);
1809*2654012fSReza Sabdar }
1810*2654012fSReza Sabdar 
1811*2654012fSReza Sabdar static int
1812*2654012fSReza Sabdar ndmp_set_eprivs_least(void)
1813*2654012fSReza Sabdar {
1814*2654012fSReza Sabdar 	priv_set_t *priv_set;
1815*2654012fSReza Sabdar 
1816*2654012fSReza Sabdar 	if ((priv_set = priv_allocset()) == NULL) {
1817*2654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Out of memory.");
1818*2654012fSReza Sabdar 		return (-1);
1819*2654012fSReza Sabdar 	}
1820*2654012fSReza Sabdar 	priv_emptyset(priv_set);
1821*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "basic");
1822*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "proc_audit");
1823*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "proc_setid");
1824*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "proc_owner");
1825*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "file_chown");
1826*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "file_chown_self");
1827*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "file_dac_read");
1828*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "file_dac_search");
1829*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "file_dac_write");
1830*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "file_owner");
1831*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "file_setid");
1832*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "sys_linkdir");
1833*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "sys_devices");
1834*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "sys_mount");
1835*2654012fSReza Sabdar 	(void) priv_addset(priv_set, "sys_config");
1836*2654012fSReza Sabdar 
1837*2654012fSReza Sabdar 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
1838*2654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Additional privileges required.");
1839*2654012fSReza Sabdar 		priv_freeset(priv_set);
1840*2654012fSReza Sabdar 		return (-1);
1841*2654012fSReza Sabdar 	}
1842*2654012fSReza Sabdar 	priv_freeset(priv_set);
1843*2654012fSReza Sabdar 	return (0);
1844*2654012fSReza Sabdar }
1845*2654012fSReza Sabdar 
1846*2654012fSReza Sabdar static int
1847*2654012fSReza Sabdar ndmp_set_eprivs_all(void)
1848*2654012fSReza Sabdar {
1849*2654012fSReza Sabdar 	priv_set_t *priv_set;
1850*2654012fSReza Sabdar 
1851*2654012fSReza Sabdar 	if ((priv_set = priv_str_to_set("all", ",", NULL)) == NULL) {
1852*2654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Could not set privileges to 'all'.");
1853*2654012fSReza Sabdar 		return (-1);
1854*2654012fSReza Sabdar 	}
1855*2654012fSReza Sabdar 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) != 0) {
1856*2654012fSReza Sabdar 		NDMP_LOG(LOG_ERR, "Additional privileges required.");
1857*2654012fSReza Sabdar 		return (-1);
1858*2654012fSReza Sabdar 	}
1859*2654012fSReza Sabdar 	priv_freeset(priv_set);
1860*2654012fSReza Sabdar 	return (0);
1861*2654012fSReza Sabdar }
1862*2654012fSReza Sabdar 
1863*2654012fSReza Sabdar /*
1864*2654012fSReza Sabdar  * Set the standard attributes of the file
1865*2654012fSReza Sabdar  */
1866*2654012fSReza Sabdar static void
1867*2654012fSReza Sabdar set_attr(char *name, struct stat64 *st)
1868*2654012fSReza Sabdar {
1869*2654012fSReza Sabdar 	struct utimbuf tbuf;
1870*2654012fSReza Sabdar 	boolean_t priv_all = FALSE;
1871*2654012fSReza Sabdar 
1872*2654012fSReza Sabdar 	if (!name || !st)
1873*2654012fSReza Sabdar 		return;
1874*2654012fSReza Sabdar 
1875*2654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "set_attr: %s uid %d gid %d mode %o", name,
1876*2654012fSReza Sabdar 	    st->st_uid, st->st_gid, st->st_mode);
1877*2654012fSReza Sabdar 
1878*2654012fSReza Sabdar 	if (chown(name, st->st_uid, st->st_gid))
1879*2654012fSReza Sabdar 		NDMP_LOG(LOG_ERR,
1880*2654012fSReza Sabdar 		    "Could not set uid or/and gid for file %s.", name);
1881*2654012fSReza Sabdar 
1882*2654012fSReza Sabdar 	if ((st->st_mode & (S_ISUID | S_ISGID)) != 0) {
1883*2654012fSReza Sabdar 		/*
1884*2654012fSReza Sabdar 		 * Change effective privileges to 'all' which is required to
1885*2654012fSReza Sabdar 		 * change setuid bit for 'root' owned files. If fails, just
1886*2654012fSReza Sabdar 		 * send error to log file and proceed.
1887*2654012fSReza Sabdar 		 */
1888*2654012fSReza Sabdar 		if (ndmp_set_eprivs_all()) {
1889*2654012fSReza Sabdar 			NDMP_LOG(LOG_ERR,
1890*2654012fSReza Sabdar 			    "Could not set effective privileges to 'all'.");
1891*2654012fSReza Sabdar 		} else {
1892*2654012fSReza Sabdar 			priv_all = TRUE;
1893*2654012fSReza Sabdar 		}
1894*2654012fSReza Sabdar 	}
1895*2654012fSReza Sabdar 
1896*2654012fSReza Sabdar 	if (chmod(name, st->st_mode))
1897*2654012fSReza Sabdar 		NDMP_LOG(LOG_ERR,
1898*2654012fSReza Sabdar 		    "Could not set correct file permission for file %s.", name);
1899*2654012fSReza Sabdar 
1900*2654012fSReza Sabdar 	if (priv_all == TRUE) {
1901*2654012fSReza Sabdar 		/*
1902*2654012fSReza Sabdar 		 * Give up the 'all' privileges for effective sets and go back
1903*2654012fSReza Sabdar 		 * to least required privileges. If fails, just send error to
1904*2654012fSReza Sabdar 		 * log file and proceed.
1905*2654012fSReza Sabdar 		 */
1906*2654012fSReza Sabdar 		if (ndmp_set_eprivs_least())
1907*2654012fSReza Sabdar 			NDMP_LOG(LOG_ERR,
1908*2654012fSReza Sabdar 			    "Could not set least required privileges.");
1909*2654012fSReza Sabdar 	}
1910*2654012fSReza Sabdar 
1911*2654012fSReza Sabdar 	tbuf.modtime = st->st_mtime;
1912*2654012fSReza Sabdar 	tbuf.actime = st->st_atime;
1913*2654012fSReza Sabdar 	(void) utime(name, &tbuf);
1914*2654012fSReza Sabdar }
1915*2654012fSReza Sabdar 
1916*2654012fSReza Sabdar /*
1917*2654012fSReza Sabdar  * Set the ACL info for the file
1918*2654012fSReza Sabdar  */
1919*2654012fSReza Sabdar static void
1920*2654012fSReza Sabdar set_acl(char *name, tlm_acls_t *acls)
1921*2654012fSReza Sabdar {
1922*2654012fSReza Sabdar 	int erc;
1923*2654012fSReza Sabdar 	acl_t *aclp = NULL;
1924*2654012fSReza Sabdar 
1925*2654012fSReza Sabdar 	if (name)
1926*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "set_acl: %s", name);
1927*2654012fSReza Sabdar 	if (acls != 0) {
1928*2654012fSReza Sabdar 		/* Need a place to save real modification time */
1929*2654012fSReza Sabdar 
1930*2654012fSReza Sabdar 		set_attr(name, &acls->acl_attr);
1931*2654012fSReza Sabdar 
1932*2654012fSReza Sabdar 		if (!acls->acl_non_trivial) {
1933*2654012fSReza Sabdar 			(void) memset(acls, 0, sizeof (tlm_acls_t));
1934*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "set_acl: skipping trivial");
1935*2654012fSReza Sabdar 			return;
1936*2654012fSReza Sabdar 		}
1937*2654012fSReza Sabdar 
1938*2654012fSReza Sabdar 		erc = acl_fromtext(acls->acl_info.attr_info, &aclp);
1939*2654012fSReza Sabdar 		if (erc != 0) {
1940*2654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
1941*2654012fSReza Sabdar 			    "TAPE RESTORE> acl_fromtext errno %d", erc);
1942*2654012fSReza Sabdar 		}
1943*2654012fSReza Sabdar 		if (aclp) {
1944*2654012fSReza Sabdar 			erc = acl_set(name, aclp);
1945*2654012fSReza Sabdar 			if (erc < 0) {
1946*2654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
1947*2654012fSReza Sabdar 				    "TAPE RESTORE> acl_set errno %d", errno);
1948*2654012fSReza Sabdar 			}
1949*2654012fSReza Sabdar 			acl_free(aclp);
1950*2654012fSReza Sabdar 		}
1951*2654012fSReza Sabdar 		(void) memset(acls, 0, sizeof (tlm_acls_t));
1952*2654012fSReza Sabdar 	}
1953*2654012fSReza Sabdar }
1954*2654012fSReza Sabdar 
1955*2654012fSReza Sabdar /*
1956*2654012fSReza Sabdar  * a wrapper to tlm_get_read_buffer so that
1957*2654012fSReza Sabdar  * we can cleanly detect ABORT commands
1958*2654012fSReza Sabdar  * without involving the TLM library with
1959*2654012fSReza Sabdar  * our problems.
1960*2654012fSReza Sabdar  */
1961*2654012fSReza Sabdar static char *
1962*2654012fSReza Sabdar get_read_buffer(int want,
1963*2654012fSReza Sabdar     int	*error,
1964*2654012fSReza Sabdar     int	*actual_size,
1965*2654012fSReza Sabdar     tlm_cmd_t *local_commands)
1966*2654012fSReza Sabdar {
1967*2654012fSReza Sabdar 	while (local_commands->tc_writer == TLM_RESTORE_RUN) {
1968*2654012fSReza Sabdar 		char	*rec;
1969*2654012fSReza Sabdar 		rec = tlm_get_read_buffer(want, error,
1970*2654012fSReza Sabdar 		    local_commands->tc_buffers, actual_size);
1971*2654012fSReza Sabdar 		if (rec != 0) {
1972*2654012fSReza Sabdar 			return (rec);
1973*2654012fSReza Sabdar 		}
1974*2654012fSReza Sabdar 	}
1975*2654012fSReza Sabdar 
1976*2654012fSReza Sabdar 	/*
1977*2654012fSReza Sabdar 	 * the job is ending, give Writer a buffer that will never be read ...
1978*2654012fSReza Sabdar 	 * it does not matter anyhow, we are aborting.
1979*2654012fSReza Sabdar 	 */
1980*2654012fSReza Sabdar 	*actual_size = RECORDSIZE;
1981*2654012fSReza Sabdar 	return (NULL);
1982*2654012fSReza Sabdar }
1983*2654012fSReza Sabdar 
1984*2654012fSReza Sabdar /*
1985*2654012fSReza Sabdar  * Enable wildcard for restore options
1986*2654012fSReza Sabdar  */
1987*2654012fSReza Sabdar static boolean_t
1988*2654012fSReza Sabdar wildcard_enabled(void)
1989*2654012fSReza Sabdar {
1990*2654012fSReza Sabdar 	char *cp;
1991*2654012fSReza Sabdar 
1992*2654012fSReza Sabdar 	cp = ndmpd_get_prop_default(NDMP_RESTORE_WILDCARD_ENABLE, "n");
1993*2654012fSReza Sabdar 	return ((toupper(*cp) == 'Y') ? TRUE : FALSE);
1994*2654012fSReza Sabdar }
1995*2654012fSReza Sabdar 
1996*2654012fSReza Sabdar 
1997*2654012fSReza Sabdar /*
1998*2654012fSReza Sabdar  * Concatenate two names
1999*2654012fSReza Sabdar  */
2000*2654012fSReza Sabdar /*ARGSUSED*/
2001*2654012fSReza Sabdar static char *
2002*2654012fSReza Sabdar catnames(struct rs_name_maker *rnp, char *buf, int pos, char *path)
2003*2654012fSReza Sabdar {
2004*2654012fSReza Sabdar 	char *rv;
2005*2654012fSReza Sabdar 
2006*2654012fSReza Sabdar 	rv = NULL;
2007*2654012fSReza Sabdar 	if (!buf) {
2008*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "buf is NULL");
2009*2654012fSReza Sabdar 	} else if (!path) {
2010*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "path is NULL");
2011*2654012fSReza Sabdar 	} else if (!rnp->rn_nlp) {
2012*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "rn_nlp is NULL [%s]", path);
2013*2654012fSReza Sabdar 	} else if (!tlm_cat_path(buf, rnp->rn_nlp, path)) {
2014*2654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]",
2015*2654012fSReza Sabdar 		    rnp->rn_nlp, path);
2016*2654012fSReza Sabdar 	} else
2017*2654012fSReza Sabdar 		rv = buf;
2018*2654012fSReza Sabdar 
2019*2654012fSReza Sabdar 	return (rv);
2020*2654012fSReza Sabdar }
2021*2654012fSReza Sabdar 
2022*2654012fSReza Sabdar 
2023*2654012fSReza Sabdar /*
2024*2654012fSReza Sabdar  * Create a new name path for restore
2025*2654012fSReza Sabdar  */
2026*2654012fSReza Sabdar static char *
2027*2654012fSReza Sabdar rs_new_name(struct rs_name_maker *rnp, char *buf, int pos, char *path)
2028*2654012fSReza Sabdar {
2029*2654012fSReza Sabdar 	if (!rnp || !rnp->rn_fp)
2030*2654012fSReza Sabdar 		return (NULL);
2031*2654012fSReza Sabdar 
2032*2654012fSReza Sabdar 	return (*rnp->rn_fp)(rnp, buf, pos, path);
2033*2654012fSReza Sabdar }
2034*2654012fSReza Sabdar 
2035*2654012fSReza Sabdar /*
2036*2654012fSReza Sabdar  * Iterate over ZFS metadata stored in the backup stream and use the callback
2037*2654012fSReza Sabdar  * to restore it.
2038*2654012fSReza Sabdar  */
2039*2654012fSReza Sabdar int
2040*2654012fSReza Sabdar ndmp_iter_zfs(ndmp_context_t *nctx, int (*np_restore_property)(nvlist_t *,
2041*2654012fSReza Sabdar     void *), void *ptr)
2042*2654012fSReza Sabdar {
2043*2654012fSReza Sabdar 	tlm_commands_t *cmds;
2044*2654012fSReza Sabdar 	ndmp_metadata_header_t *mhp;
2045*2654012fSReza Sabdar 	ndmp_metadata_property_t *mpp;
2046*2654012fSReza Sabdar 	tlm_cmd_t *lcmd;
2047*2654012fSReza Sabdar 	int actual_size;
2048*2654012fSReza Sabdar 	nvlist_t *nvl;
2049*2654012fSReza Sabdar 	nvlist_t *nvl_head;
2050*2654012fSReza Sabdar 	nvlist_t *valp;
2051*2654012fSReza Sabdar 	nvpair_t *nvp = NULL;
2052*2654012fSReza Sabdar 	nvpair_t *nvph = NULL;
2053*2654012fSReza Sabdar 	char plname[100];
2054*2654012fSReza Sabdar 	char *mhbuf, *pp, *tp;
2055*2654012fSReza Sabdar 	int rv, i;
2056*2654012fSReza Sabdar 	int size, lsize, sz;
2057*2654012fSReza Sabdar 	int align = RECORDSIZE - 1;
2058*2654012fSReza Sabdar 
2059*2654012fSReza Sabdar 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
2060*2654012fSReza Sabdar 		return (-1);
2061*2654012fSReza Sabdar 
2062*2654012fSReza Sabdar 	nctx->nc_plname = plname;
2063*2654012fSReza Sabdar 	if ((lcmd = cmds->tcs_command) == NULL ||
2064*2654012fSReza Sabdar 	    lcmd->tc_buffers == NULL)
2065*2654012fSReza Sabdar 		return (-1);
2066*2654012fSReza Sabdar 
2067*2654012fSReza Sabdar 	size = sizeof (ndmp_metadata_header_t) +
2068*2654012fSReza Sabdar 	    ZFS_MAX_PROPS * sizeof (ndmp_metadata_property_t);
2069*2654012fSReza Sabdar 	size += align;
2070*2654012fSReza Sabdar 	size &= ~align;
2071*2654012fSReza Sabdar 
2072*2654012fSReza Sabdar 	/* For nvlist cleanup */
2073*2654012fSReza Sabdar 	if (nvlist_alloc(&nvl_head, NV_UNIQUE_NAME, 0) != 0)
2074*2654012fSReza Sabdar 		return (-1);
2075*2654012fSReza Sabdar 
2076*2654012fSReza Sabdar 	if ((mhbuf = malloc(size)) == NULL)
2077*2654012fSReza Sabdar 		return (-1);
2078*2654012fSReza Sabdar 
2079*2654012fSReza Sabdar 	/* LINTED improper alignment */
2080*2654012fSReza Sabdar 	while ((mhp = (ndmp_metadata_header_t *)get_read_buffer(size, &rv,
2081*2654012fSReza Sabdar 	    &actual_size, lcmd)) != NULL) {
2082*2654012fSReza Sabdar 		pp = mhbuf;
2083*2654012fSReza Sabdar 
2084*2654012fSReza Sabdar 		if (strncmp(mhp->nh_magic, ZFS_META_MAGIC,
2085*2654012fSReza Sabdar 		    sizeof (mhp->nh_magic)) != 0) {
2086*2654012fSReza Sabdar 			/* No more metadata */
2087*2654012fSReza Sabdar 			tlm_unget_read_buffer(lcmd->tc_buffers, actual_size);
2088*2654012fSReza Sabdar 			nvlist_free(nvl_head);
2089*2654012fSReza Sabdar 			return (0);
2090*2654012fSReza Sabdar 		}
2091*2654012fSReza Sabdar 
2092*2654012fSReza Sabdar 		(void) memcpy(pp, (char *)mhp, (actual_size < size) ?
2093*2654012fSReza Sabdar 		    actual_size : size);
2094*2654012fSReza Sabdar 		pp += (actual_size < size) ? actual_size : size;
2095*2654012fSReza Sabdar 
2096*2654012fSReza Sabdar 		sz = actual_size;
2097*2654012fSReza Sabdar 		while (sz < size &&
2098*2654012fSReza Sabdar 		    ((tp = get_read_buffer(size - sz, &rv, &lsize,
2099*2654012fSReza Sabdar 		    lcmd))) != NULL) {
2100*2654012fSReza Sabdar 			(void) memcpy(pp, tp, size - sz);
2101*2654012fSReza Sabdar 			sz += lsize;
2102*2654012fSReza Sabdar 			pp += lsize;
2103*2654012fSReza Sabdar 		}
2104*2654012fSReza Sabdar 		if (sz > size) {
2105*2654012fSReza Sabdar 			tlm_unget_read_buffer(lcmd->tc_buffers, sz - size);
2106*2654012fSReza Sabdar 		}
2107*2654012fSReza Sabdar 		/* LINTED improper alignment */
2108*2654012fSReza Sabdar 		mhp = (ndmp_metadata_header_t *)mhbuf;
2109*2654012fSReza Sabdar 
2110*2654012fSReza Sabdar 		nctx->nc_plversion = mhp->nh_plversion;
2111*2654012fSReza Sabdar 		(void) strlcpy(plname, mhp->nh_plname, sizeof (plname));
2112*2654012fSReza Sabdar 
2113*2654012fSReza Sabdar 		if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
2114*2654012fSReza Sabdar 			goto nvlist_err;
2115*2654012fSReza Sabdar 
2116*2654012fSReza Sabdar 		mpp = &mhp->nh_property[0];
2117*2654012fSReza Sabdar 		for (i = 0; i < mhp->nh_count && mpp; i++) {
2118*2654012fSReza Sabdar 			if (nvlist_alloc(&valp, NV_UNIQUE_NAME, 0) != 0 ||
2119*2654012fSReza Sabdar 			    nvlist_add_string(valp, "value",
2120*2654012fSReza Sabdar 			    mpp->mp_value) != 0 ||
2121*2654012fSReza Sabdar 			    nvlist_add_string(valp, "source",
2122*2654012fSReza Sabdar 			    mpp->mp_source) != 0 ||
2123*2654012fSReza Sabdar 			    nvlist_add_nvlist(nvl, mpp->mp_name, valp) != 0)
2124*2654012fSReza Sabdar 				goto nvlist_err;
2125*2654012fSReza Sabdar 			mpp++;
2126*2654012fSReza Sabdar 		}
2127*2654012fSReza Sabdar 
2128*2654012fSReza Sabdar 		if (np_restore_property(nvl, ptr) != 0)
2129*2654012fSReza Sabdar 			goto nvlist_err;
2130*2654012fSReza Sabdar 
2131*2654012fSReza Sabdar 		(void) nvlist_add_nvlist(nvl_head, "_", nvl);
2132*2654012fSReza Sabdar 	}
2133*2654012fSReza Sabdar 	free(mhbuf);
2134*2654012fSReza Sabdar 
2135*2654012fSReza Sabdar 	nvlist_free(nvl_head);
2136*2654012fSReza Sabdar 	return (0);
2137*2654012fSReza Sabdar 
2138*2654012fSReza Sabdar nvlist_err:
2139*2654012fSReza Sabdar 	free(mhbuf);
2140*2654012fSReza Sabdar 	while ((nvph = nvlist_next_nvpair(nvl_head, nvph)) != NULL &&
2141*2654012fSReza Sabdar 	    nvpair_value_nvlist(nvph, &nvl) == 0) {
2142*2654012fSReza Sabdar 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL &&
2143*2654012fSReza Sabdar 		    nvpair_value_nvlist(nvp, &valp) == 0) {
2144*2654012fSReza Sabdar 			nvlist_free(valp);
2145*2654012fSReza Sabdar 		}
2146*2654012fSReza Sabdar 		nvlist_free(nvl);
2147*2654012fSReza Sabdar 	}
2148*2654012fSReza Sabdar 	nvlist_free(nvl_head);
2149*2654012fSReza Sabdar 	return (-1);
2150*2654012fSReza Sabdar }
2151*2654012fSReza Sabdar 
2152*2654012fSReza Sabdar /*
2153*2654012fSReza Sabdar  * Returns the version number of the plugin which created the metadata
2154*2654012fSReza Sabdar  */
2155*2654012fSReza Sabdar uint_t
2156*2654012fSReza Sabdar ndmp_context_get_version(ndmp_context_t *nctx)
2157*2654012fSReza Sabdar {
2158*2654012fSReza Sabdar 	tlm_commands_t *cmds;
2159*2654012fSReza Sabdar 	ndmp_metadata_header_t *mhp;
2160*2654012fSReza Sabdar 	tlm_cmd_t *lcmd;
2161*2654012fSReza Sabdar 	int actual_size;
2162*2654012fSReza Sabdar 	int rv;
2163*2654012fSReza Sabdar 	int size;
2164*2654012fSReza Sabdar 	int align = RECORDSIZE - 1;
2165*2654012fSReza Sabdar 
2166*2654012fSReza Sabdar 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
2167*2654012fSReza Sabdar 		return (0);
2168*2654012fSReza Sabdar 
2169*2654012fSReza Sabdar 	if ((lcmd = cmds->tcs_command) == NULL ||
2170*2654012fSReza Sabdar 	    lcmd->tc_buffers == NULL)
2171*2654012fSReza Sabdar 		return (0);
2172*2654012fSReza Sabdar 
2173*2654012fSReza Sabdar 	size = sizeof (ndmp_metadata_header_t);
2174*2654012fSReza Sabdar 	size += align;
2175*2654012fSReza Sabdar 	size &= ~align;
2176*2654012fSReza Sabdar 
2177*2654012fSReza Sabdar 	/* LINTED improper alignment */
2178*2654012fSReza Sabdar 	if ((mhp = (ndmp_metadata_header_t *)get_read_buffer(size, &rv,
2179*2654012fSReza Sabdar 	    &actual_size, lcmd)) != NULL) {
2180*2654012fSReza Sabdar 		if (strncmp(mhp->nh_magic, ZFS_META_MAGIC,
2181*2654012fSReza Sabdar 		    sizeof (mhp->nh_magic)) != 0) {
2182*2654012fSReza Sabdar 			/* No more metadata */
2183*2654012fSReza Sabdar 			tlm_unget_read_buffer(lcmd->tc_buffers, actual_size);
2184*2654012fSReza Sabdar 			return (0);
2185*2654012fSReza Sabdar 		}
2186*2654012fSReza Sabdar 
2187*2654012fSReza Sabdar 		nctx->nc_plversion = mhp->nh_plversion;
2188*2654012fSReza Sabdar 		tlm_unget_read_buffer(lcmd->tc_buffers, actual_size);
2189*2654012fSReza Sabdar 	}
2190*2654012fSReza Sabdar 
2191*2654012fSReza Sabdar 	return (nctx->nc_plversion);
2192*2654012fSReza Sabdar }
2193