xref: /onnv-gate/usr/src/cmd/ndmpd/tlm/tlm_backup_reader.c (revision 8193:9b3c96bc17e3)
17917SReza.Sabdar@Sun.COM /*
27917SReza.Sabdar@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37917SReza.Sabdar@Sun.COM  * Use is subject to license terms.
47917SReza.Sabdar@Sun.COM  */
57917SReza.Sabdar@Sun.COM 
67917SReza.Sabdar@Sun.COM /*
77917SReza.Sabdar@Sun.COM  * BSD 3 Clause License
87917SReza.Sabdar@Sun.COM  *
97917SReza.Sabdar@Sun.COM  * Copyright (c) 2007, The Storage Networking Industry Association.
107917SReza.Sabdar@Sun.COM  *
117917SReza.Sabdar@Sun.COM  * Redistribution and use in source and binary forms, with or without
127917SReza.Sabdar@Sun.COM  * modification, are permitted provided that the following conditions
137917SReza.Sabdar@Sun.COM  * are met:
147917SReza.Sabdar@Sun.COM  * 	- Redistributions of source code must retain the above copyright
157917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer.
167917SReza.Sabdar@Sun.COM  *
177917SReza.Sabdar@Sun.COM  * 	- Redistributions in binary form must reproduce the above copyright
187917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer in
197917SReza.Sabdar@Sun.COM  *	  the documentation and/or other materials provided with the
207917SReza.Sabdar@Sun.COM  *	  distribution.
217917SReza.Sabdar@Sun.COM  *
227917SReza.Sabdar@Sun.COM  *	- Neither the name of The Storage Networking Industry Association (SNIA)
237917SReza.Sabdar@Sun.COM  *	  nor the names of its contributors may be used to endorse or promote
247917SReza.Sabdar@Sun.COM  *	  products derived from this software without specific prior written
257917SReza.Sabdar@Sun.COM  *	  permission.
267917SReza.Sabdar@Sun.COM  *
277917SReza.Sabdar@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
287917SReza.Sabdar@Sun.COM  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
297917SReza.Sabdar@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
307917SReza.Sabdar@Sun.COM  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
317917SReza.Sabdar@Sun.COM  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
327917SReza.Sabdar@Sun.COM  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
337917SReza.Sabdar@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
347917SReza.Sabdar@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
357917SReza.Sabdar@Sun.COM  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
367917SReza.Sabdar@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
377917SReza.Sabdar@Sun.COM  * POSSIBILITY OF SUCH DAMAGE.
387917SReza.Sabdar@Sun.COM  */
397917SReza.Sabdar@Sun.COM #include <stdio.h>
407917SReza.Sabdar@Sun.COM #include <limits.h>
417917SReza.Sabdar@Sun.COM #include <time.h>
427917SReza.Sabdar@Sun.COM #include <sys/stat.h>
437917SReza.Sabdar@Sun.COM #include <unistd.h>
447917SReza.Sabdar@Sun.COM #include <dirent.h>
457917SReza.Sabdar@Sun.COM #include <pthread.h>
467917SReza.Sabdar@Sun.COM #include <archives.h>
477917SReza.Sabdar@Sun.COM #include <tlm.h>
487917SReza.Sabdar@Sun.COM #include <sys/fs/zfs.h>
497917SReza.Sabdar@Sun.COM #include <libzfs.h>
507917SReza.Sabdar@Sun.COM #include "tlm_proto.h"
517917SReza.Sabdar@Sun.COM 
527917SReza.Sabdar@Sun.COM 
537917SReza.Sabdar@Sun.COM static char *get_write_buffer(long size,
547917SReza.Sabdar@Sun.COM     long *actual_size,
557917SReza.Sabdar@Sun.COM     boolean_t zero,
567917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
577917SReza.Sabdar@Sun.COM static int output_acl_header(sec_attr_t *,
587917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
597917SReza.Sabdar@Sun.COM static int output_file_header(char *name,
607917SReza.Sabdar@Sun.COM     char *link,
617917SReza.Sabdar@Sun.COM     tlm_acls_t *,
627917SReza.Sabdar@Sun.COM     int section,
637917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
647917SReza.Sabdar@Sun.COM static int output_xattr_header(char *fname,
657917SReza.Sabdar@Sun.COM     char *aname,
667917SReza.Sabdar@Sun.COM     int fd,
677917SReza.Sabdar@Sun.COM     tlm_acls_t *,
687917SReza.Sabdar@Sun.COM     int section,
697917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
707917SReza.Sabdar@Sun.COM 
717917SReza.Sabdar@Sun.COM extern  libzfs_handle_t *zlibh;
727917SReza.Sabdar@Sun.COM 
737917SReza.Sabdar@Sun.COM 
747917SReza.Sabdar@Sun.COM /*
757917SReza.Sabdar@Sun.COM  * output_mem
767917SReza.Sabdar@Sun.COM  *
777917SReza.Sabdar@Sun.COM  * Gets a IO write buffer and copies memory to the that.
787917SReza.Sabdar@Sun.COM  */
797917SReza.Sabdar@Sun.COM static void
807917SReza.Sabdar@Sun.COM output_mem(tlm_cmd_t *local_commands, char *mem,
817917SReza.Sabdar@Sun.COM     int len)
827917SReza.Sabdar@Sun.COM {
837917SReza.Sabdar@Sun.COM 	long actual_size, rec_size;
847917SReza.Sabdar@Sun.COM 	char *rec;
857917SReza.Sabdar@Sun.COM 
867917SReza.Sabdar@Sun.COM 	while (len > 0) {
877917SReza.Sabdar@Sun.COM 		rec = get_write_buffer(len, &actual_size,
887917SReza.Sabdar@Sun.COM 		    FALSE, local_commands);
897917SReza.Sabdar@Sun.COM 		rec_size = min(actual_size, len);
907917SReza.Sabdar@Sun.COM 		(void) memcpy(rec, mem, rec_size);
917917SReza.Sabdar@Sun.COM 		mem += rec_size;
927917SReza.Sabdar@Sun.COM 		len -= rec_size;
937917SReza.Sabdar@Sun.COM 	}
947917SReza.Sabdar@Sun.COM }
957917SReza.Sabdar@Sun.COM 
967917SReza.Sabdar@Sun.COM /*
977917SReza.Sabdar@Sun.COM  * tlm_output_dir
987917SReza.Sabdar@Sun.COM  *
997917SReza.Sabdar@Sun.COM  * Put the directory information into the output buffers.
1007917SReza.Sabdar@Sun.COM  */
1017917SReza.Sabdar@Sun.COM int
1027917SReza.Sabdar@Sun.COM tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
1037917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1047917SReza.Sabdar@Sun.COM {
1057917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
1067917SReza.Sabdar@Sun.COM 
1077917SReza.Sabdar@Sun.COM 	/*
1087917SReza.Sabdar@Sun.COM 	 * Send the node or path history of the directory itself.
1097917SReza.Sabdar@Sun.COM 	 */
1107917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
1117917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
1127917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
1137917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
1147917SReza.Sabdar@Sun.COM 	/* fhdir_cb is handled in ndmpd_tar3.c */
1157917SReza.Sabdar@Sun.COM 
1167917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
1177917SReza.Sabdar@Sun.COM 	    local_commands);
1187917SReza.Sabdar@Sun.COM 	(void) output_file_header(name, "", tlm_acls, 0,
1197917SReza.Sabdar@Sun.COM 	    local_commands);
1207917SReza.Sabdar@Sun.COM 
1217917SReza.Sabdar@Sun.COM 	return (0);
1227917SReza.Sabdar@Sun.COM }
1237917SReza.Sabdar@Sun.COM 
1247917SReza.Sabdar@Sun.COM /*
1257917SReza.Sabdar@Sun.COM  * tar_putdir
1267917SReza.Sabdar@Sun.COM  *
1277917SReza.Sabdar@Sun.COM  * Main dir backup function for tar
1287917SReza.Sabdar@Sun.COM  */
1297917SReza.Sabdar@Sun.COM int
1307917SReza.Sabdar@Sun.COM tar_putdir(char *name, tlm_acls_t *tlm_acls,
1317917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1327917SReza.Sabdar@Sun.COM {
1337917SReza.Sabdar@Sun.COM 	int rv;
1347917SReza.Sabdar@Sun.COM 
1357917SReza.Sabdar@Sun.COM 	rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats);
1367917SReza.Sabdar@Sun.COM 	return (rv < 0 ? rv : 0);
1377917SReza.Sabdar@Sun.COM }
1387917SReza.Sabdar@Sun.COM 
1397917SReza.Sabdar@Sun.COM /*
1407917SReza.Sabdar@Sun.COM  * output_acl_header
1417917SReza.Sabdar@Sun.COM  *
1427917SReza.Sabdar@Sun.COM  * output the ACL header record and data
1437917SReza.Sabdar@Sun.COM  */
1447917SReza.Sabdar@Sun.COM static int
1457917SReza.Sabdar@Sun.COM output_acl_header(sec_attr_t *acl_info,
1467917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands)
1477917SReza.Sabdar@Sun.COM {
1487917SReza.Sabdar@Sun.COM 	long	actual_size;
1497917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
1507917SReza.Sabdar@Sun.COM 	long	acl_size;
1517917SReza.Sabdar@Sun.COM 
1527917SReza.Sabdar@Sun.COM 	if ((acl_info == NULL) || (*acl_info->attr_info == '\0'))
1537917SReza.Sabdar@Sun.COM 		return (0);
1547917SReza.Sabdar@Sun.COM 
1557917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
1567917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
1577917SReza.Sabdar@Sun.COM 	if (!tar_hdr)
1587917SReza.Sabdar@Sun.COM 		return (0);
1597917SReza.Sabdar@Sun.COM 
1607917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_ACL;
1617917SReza.Sabdar@Sun.COM 	acl_info->attr_type = UFSD_ACL;
1627917SReza.Sabdar@Sun.COM 	(void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len),
1637917SReza.Sabdar@Sun.COM 	    "%06o", strlen(acl_info->attr_info));
1647917SReza.Sabdar@Sun.COM 
1657917SReza.Sabdar@Sun.COM 	acl_size = sizeof (*acl_info);
1667917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE);
1677917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
1687917SReza.Sabdar@Sun.COM 	    acl_size);
1697917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
1707917SReza.Sabdar@Sun.COM 	    0444);
1717917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0);
1727917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0);
1737917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
1747917SReza.Sabdar@Sun.COM 	    "%011o ", 0);
1757917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
1767917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
1777917SReza.Sabdar@Sun.COM 
1787917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
1797917SReza.Sabdar@Sun.COM 
1807917SReza.Sabdar@Sun.COM 	(void) output_mem(local_commands, (void *)acl_info, acl_size);
1817917SReza.Sabdar@Sun.COM 	return (0);
1827917SReza.Sabdar@Sun.COM }
1837917SReza.Sabdar@Sun.COM 
1847917SReza.Sabdar@Sun.COM /*
1857917SReza.Sabdar@Sun.COM  * output_humongus_header
1867917SReza.Sabdar@Sun.COM  *
1877917SReza.Sabdar@Sun.COM  * output a special header record for HUGE files
1887917SReza.Sabdar@Sun.COM  * output is:	1) a TAR "HUGE" header redord
1897917SReza.Sabdar@Sun.COM  * 		2) a "file" of size, name
1907917SReza.Sabdar@Sun.COM  */
1917917SReza.Sabdar@Sun.COM static int
1927917SReza.Sabdar@Sun.COM output_humongus_header(char *fullname, longlong_t file_size,
1937917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands)
1947917SReza.Sabdar@Sun.COM {
1957917SReza.Sabdar@Sun.COM 	char	*buf;
1967917SReza.Sabdar@Sun.COM 	int	len;
1977917SReza.Sabdar@Sun.COM 	long	actual_size;
1987917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
1997917SReza.Sabdar@Sun.COM 
2007917SReza.Sabdar@Sun.COM 	/*
2017917SReza.Sabdar@Sun.COM 	 * buf will contain: "%llu %s":
2027917SReza.Sabdar@Sun.COM 	 * - 20 is the maximum length of 'ulong_tlong' decimal notation.
2037917SReza.Sabdar@Sun.COM 	 * - The first '1' is for the ' ' between the "%llu" and the fullname.
2047917SReza.Sabdar@Sun.COM 	 * - The last '1' is for the null-terminator of fullname.
2057917SReza.Sabdar@Sun.COM 	 */
2067917SReza.Sabdar@Sun.COM 	len = 20 + 1 + strlen(fullname) + 1;
2077917SReza.Sabdar@Sun.COM 
2087917SReza.Sabdar@Sun.COM 	if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
2097917SReza.Sabdar@Sun.COM 		return (-1);
2107917SReza.Sabdar@Sun.COM 
2117917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2127917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
2137917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
2147917SReza.Sabdar@Sun.COM 		free(buf);
2157917SReza.Sabdar@Sun.COM 		return (0);
2167917SReza.Sabdar@Sun.COM 	}
2177917SReza.Sabdar@Sun.COM 
2187917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_HUMONGUS;
2197917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2207917SReza.Sabdar@Sun.COM 	    len);
2217917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
2227917SReza.Sabdar@Sun.COM 	(void) snprintf(buf, len, "%lld %s", file_size, fullname);
2237917SReza.Sabdar@Sun.COM 	(void) output_mem(local_commands, buf, len);
2247917SReza.Sabdar@Sun.COM 
2257917SReza.Sabdar@Sun.COM 	free(buf);
2267917SReza.Sabdar@Sun.COM 	return (0);
2277917SReza.Sabdar@Sun.COM }
2287917SReza.Sabdar@Sun.COM 
2297917SReza.Sabdar@Sun.COM 
2307917SReza.Sabdar@Sun.COM /*
2317917SReza.Sabdar@Sun.COM  * output_xattr_header
2327917SReza.Sabdar@Sun.COM  *
2337917SReza.Sabdar@Sun.COM  * output the TAR header record for extended attributes
2347917SReza.Sabdar@Sun.COM  */
2357917SReza.Sabdar@Sun.COM static int
2367917SReza.Sabdar@Sun.COM output_xattr_header(char *fname, char *aname, int fd,
2377917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
2387917SReza.Sabdar@Sun.COM {
2397917SReza.Sabdar@Sun.COM 	struct stat64 *attr = &tlm_acls->acl_attr;
2407917SReza.Sabdar@Sun.COM 	struct xattr_hdr *xhdr;
2417917SReza.Sabdar@Sun.COM 	struct xattr_buf *xbuf;
2427917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
2437917SReza.Sabdar@Sun.COM 	long	actual_size;
2447917SReza.Sabdar@Sun.COM 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
2457917SReza.Sabdar@Sun.COM 	int	hsize;
2467917SReza.Sabdar@Sun.COM 	int	comlen;
2477917SReza.Sabdar@Sun.COM 	int	namesz;
2487917SReza.Sabdar@Sun.COM 
2497917SReza.Sabdar@Sun.COM 	if (section_name == NULL)
2507917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
2517917SReza.Sabdar@Sun.COM 
2527917SReza.Sabdar@Sun.COM 	if (fstat64(fd, attr) == -1) {
2537917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "output_file_header stat failed.");
2547917SReza.Sabdar@Sun.COM 		free(section_name);
2557917SReza.Sabdar@Sun.COM 		return (-TLM_OPEN_ERR);
2567917SReza.Sabdar@Sun.COM 	}
2577917SReza.Sabdar@Sun.COM 
2587917SReza.Sabdar@Sun.COM 	/*
2597917SReza.Sabdar@Sun.COM 	 * if the file has to go out in sections,
2607917SReza.Sabdar@Sun.COM 	 * we must mung the name.
2617917SReza.Sabdar@Sun.COM 	 */
2627917SReza.Sabdar@Sun.COM 	if (section == 0) {
2637917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name, TLM_MAX_PATH_NAME,
2647917SReza.Sabdar@Sun.COM 		    "/dev/null/%s.hdr", aname);
2657917SReza.Sabdar@Sun.COM 	} else {
2667917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name,
2677917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
2687917SReza.Sabdar@Sun.COM 	}
2697917SReza.Sabdar@Sun.COM 	namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
2707917SReza.Sabdar@Sun.COM 	hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
2717917SReza.Sabdar@Sun.COM 	comlen = namesz + sizeof (struct xattr_buf);
2727917SReza.Sabdar@Sun.COM 
2737917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2747917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
2757917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
2767917SReza.Sabdar@Sun.COM 		free(section_name);
2777917SReza.Sabdar@Sun.COM 		return (0);
2787917SReza.Sabdar@Sun.COM 	}
2797917SReza.Sabdar@Sun.COM 
2807917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
2817917SReza.Sabdar@Sun.COM 
2827917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_XATTR;
2837917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2847917SReza.Sabdar@Sun.COM 	    hsize);
2857917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
2867917SReza.Sabdar@Sun.COM 	    attr->st_mode & 07777);
2877917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
2887917SReza.Sabdar@Sun.COM 	    attr->st_uid);
2897917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
2907917SReza.Sabdar@Sun.COM 	    attr->st_gid);
2917917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
2927917SReza.Sabdar@Sun.COM 	    attr->st_mtime);
2937917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
2947917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
2957917SReza.Sabdar@Sun.COM 
2967917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
2977917SReza.Sabdar@Sun.COM 
2987917SReza.Sabdar@Sun.COM 	xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE,
2997917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
3007917SReza.Sabdar@Sun.COM 	if (!xhdr) {
3017917SReza.Sabdar@Sun.COM 		free(section_name);
3027917SReza.Sabdar@Sun.COM 		return (0);
3037917SReza.Sabdar@Sun.COM 	}
3047917SReza.Sabdar@Sun.COM 
3057917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s",
3067917SReza.Sabdar@Sun.COM 	    XATTR_ARCH_VERS);
3077917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d",
3087917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_size) - 1, hsize);
3097917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len),
3107917SReza.Sabdar@Sun.COM 	    "%0*d", sizeof (xhdr->h_component_len) - 1, comlen);
3117917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_link_component_len,
3127917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_link_component_len), "%0*d",
3137917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_link_component_len) - 1, 0);
3147917SReza.Sabdar@Sun.COM 
3157917SReza.Sabdar@Sun.COM 	xbuf = (struct xattr_buf *)(((caddr_t)xhdr) +
3167917SReza.Sabdar@Sun.COM 	    sizeof (struct xattr_hdr));
3177917SReza.Sabdar@Sun.COM 	(void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d",
3187917SReza.Sabdar@Sun.COM 	    sizeof (xbuf->h_namesz) - 1, namesz);
3197917SReza.Sabdar@Sun.COM 
3207917SReza.Sabdar@Sun.COM 	/* No support for links in extended attributes */
3217917SReza.Sabdar@Sun.COM 	xbuf->h_typeflag = LF_NORMAL;
3227917SReza.Sabdar@Sun.COM 
3237917SReza.Sabdar@Sun.COM 	(void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE);
3247917SReza.Sabdar@Sun.COM 	(void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname,
3257917SReza.Sabdar@Sun.COM 	    TLM_NAME_SIZE);
3267917SReza.Sabdar@Sun.COM 
3277917SReza.Sabdar@Sun.COM 	free(section_name);
3287917SReza.Sabdar@Sun.COM 	return (0);
3297917SReza.Sabdar@Sun.COM }
3307917SReza.Sabdar@Sun.COM 
3317917SReza.Sabdar@Sun.COM 
3327917SReza.Sabdar@Sun.COM /*
3337917SReza.Sabdar@Sun.COM  * output_file_header
3347917SReza.Sabdar@Sun.COM  *
3357917SReza.Sabdar@Sun.COM  * output the TAR header record
3367917SReza.Sabdar@Sun.COM  */
3377917SReza.Sabdar@Sun.COM static int
3387917SReza.Sabdar@Sun.COM output_file_header(char *name, char *link,
3397917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
3407917SReza.Sabdar@Sun.COM {
3417917SReza.Sabdar@Sun.COM 	static	longlong_t file_count = 0;
3427917SReza.Sabdar@Sun.COM 	struct stat64 *attr = &tlm_acls->acl_attr;
3437917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
3447917SReza.Sabdar@Sun.COM 	long	actual_size;
3457917SReza.Sabdar@Sun.COM 	boolean_t long_name = FALSE;
3467917SReza.Sabdar@Sun.COM 	boolean_t long_link = FALSE;
3477917SReza.Sabdar@Sun.COM 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
3487917SReza.Sabdar@Sun.COM 	int	nmlen, lnklen;
3497917SReza.Sabdar@Sun.COM 
3507917SReza.Sabdar@Sun.COM 	if (section_name == NULL)
3517917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
3527917SReza.Sabdar@Sun.COM 
3537917SReza.Sabdar@Sun.COM 	/*
3547917SReza.Sabdar@Sun.COM 	 * if the file has to go out in sections,
3557917SReza.Sabdar@Sun.COM 	 * we must mung the name.
3567917SReza.Sabdar@Sun.COM 	 */
3577917SReza.Sabdar@Sun.COM 	if (section == 0) {
3587917SReza.Sabdar@Sun.COM 		(void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
3597917SReza.Sabdar@Sun.COM 	} else {
3607917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name,
3617917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME, "%s.%03d", name, section);
3627917SReza.Sabdar@Sun.COM 	}
3637917SReza.Sabdar@Sun.COM 
3647917SReza.Sabdar@Sun.COM 	nmlen = strlen(section_name);
3657917SReza.Sabdar@Sun.COM 	if (nmlen >= NAMSIZ) {
3667917SReza.Sabdar@Sun.COM 		/*
3677917SReza.Sabdar@Sun.COM 		 * file name is too big, it must go out
3687917SReza.Sabdar@Sun.COM 		 * in its own data file
3697917SReza.Sabdar@Sun.COM 		 */
3707917SReza.Sabdar@Sun.COM 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
3717917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
3727917SReza.Sabdar@Sun.COM 		if (!tar_hdr) {
3737917SReza.Sabdar@Sun.COM 			free(section_name);
3747917SReza.Sabdar@Sun.COM 			return (0);
3757917SReza.Sabdar@Sun.COM 		}
3767917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_name,
3777917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
3787917SReza.Sabdar@Sun.COM 		    "%s%08qd.fil",
3797917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
3807917SReza.Sabdar@Sun.COM 		    file_count++);
3817917SReza.Sabdar@Sun.COM 
3827917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LONGNAME;
3837917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
3847917SReza.Sabdar@Sun.COM 		    "%011o ", nmlen);
3857917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
3867917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_mode & 07777);
3877917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
3887917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_uid);
3897917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
3907917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_gid);
3917917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
3927917SReza.Sabdar@Sun.COM 		    "%011o ", attr->st_mtime);
3937917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
3947917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_magic));
3957917SReza.Sabdar@Sun.COM 
3967917SReza.Sabdar@Sun.COM 		tlm_build_header_checksum(tar_hdr);
3977917SReza.Sabdar@Sun.COM 
3987917SReza.Sabdar@Sun.COM 		(void) output_mem(local_commands,
3997917SReza.Sabdar@Sun.COM 		    (void *)section_name, nmlen);
4007917SReza.Sabdar@Sun.COM 		long_name = TRUE;
4017917SReza.Sabdar@Sun.COM 	}
4027917SReza.Sabdar@Sun.COM 
4037917SReza.Sabdar@Sun.COM 	lnklen = strlen(link);
4047917SReza.Sabdar@Sun.COM 	if (lnklen >= NAMSIZ) {
4057917SReza.Sabdar@Sun.COM 		/*
4067917SReza.Sabdar@Sun.COM 		 * link name is too big, it must go out
4077917SReza.Sabdar@Sun.COM 		 * in its own data file
4087917SReza.Sabdar@Sun.COM 		 */
4097917SReza.Sabdar@Sun.COM 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4107917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
4117917SReza.Sabdar@Sun.COM 		if (!tar_hdr) {
4127917SReza.Sabdar@Sun.COM 			free(section_name);
4137917SReza.Sabdar@Sun.COM 			return (0);
4147917SReza.Sabdar@Sun.COM 		}
4157917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_linkname,
4167917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4177917SReza.Sabdar@Sun.COM 		    "%s%08qd.slk",
4187917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4197917SReza.Sabdar@Sun.COM 		    file_count++);
4207917SReza.Sabdar@Sun.COM 
4217917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LONGLINK;
4227917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
4237917SReza.Sabdar@Sun.COM 		    "%011o ", lnklen);
4247917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
4257917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_mode & 07777);
4267917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
4277917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_uid);
4287917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
4297917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_gid);
4307917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
4317917SReza.Sabdar@Sun.COM 		    "%011o ", attr->st_mtime);
4327917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4337917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_magic));
4347917SReza.Sabdar@Sun.COM 
4357917SReza.Sabdar@Sun.COM 		tlm_build_header_checksum(tar_hdr);
4367917SReza.Sabdar@Sun.COM 
4377917SReza.Sabdar@Sun.COM 		(void) output_mem(local_commands, (void *)link,
4387917SReza.Sabdar@Sun.COM 		    lnklen);
4397917SReza.Sabdar@Sun.COM 		long_link = TRUE;
4407917SReza.Sabdar@Sun.COM 	}
4417917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4427917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
4437917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
4447917SReza.Sabdar@Sun.COM 		free(section_name);
4457917SReza.Sabdar@Sun.COM 		return (0);
4467917SReza.Sabdar@Sun.COM 	}
4477917SReza.Sabdar@Sun.COM 	if (long_name) {
4487917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_name,
4497917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4507917SReza.Sabdar@Sun.COM 		    "%s%08qd.fil",
4517917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4527917SReza.Sabdar@Sun.COM 		    file_count++);
4537917SReza.Sabdar@Sun.COM 	} else {
4547917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
4557917SReza.Sabdar@Sun.COM 	}
4567917SReza.Sabdar@Sun.COM 
4577917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "long_link: %s [%s]", long_link ? "TRUE" : "FALSE",
4587917SReza.Sabdar@Sun.COM 	    link);
4597917SReza.Sabdar@Sun.COM 
4607917SReza.Sabdar@Sun.COM 	if (long_link) {
4617917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_linkname,
4627917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4637917SReza.Sabdar@Sun.COM 		    "%s%08qd.slk",
4647917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4657917SReza.Sabdar@Sun.COM 		    file_count++);
4667917SReza.Sabdar@Sun.COM 	} else {
4677917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
4687917SReza.Sabdar@Sun.COM 	}
4697917SReza.Sabdar@Sun.COM 	if (S_ISDIR(attr->st_mode)) {
4707917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_DIR;
4717917SReza.Sabdar@Sun.COM 	} else if (S_ISFIFO(attr->st_mode)) {
4727917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_FIFO;
4737917SReza.Sabdar@Sun.COM 	} else if (attr->st_nlink > 1) {
4747917SReza.Sabdar@Sun.COM 		/* mark file with hardlink LF_LINK */
4757917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LINK;
4767917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_shared.th_hlink_ino,
4777917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_shared.th_hlink_ino),
478*8193SReza.Sabdar@Sun.COM 		    "%011llo ", attr->st_ino);
4797917SReza.Sabdar@Sun.COM 	} else {
4807917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL : LF_SYMLINK;
4817917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "linkflag: '%c'", tar_hdr->th_linkflag);
4827917SReza.Sabdar@Sun.COM 	}
4837917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
4847917SReza.Sabdar@Sun.COM 	    (long)attr->st_size);
4857917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
4867917SReza.Sabdar@Sun.COM 	    attr->st_mode & 07777);
4877917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
4887917SReza.Sabdar@Sun.COM 	    attr->st_uid);
4897917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
4907917SReza.Sabdar@Sun.COM 	    attr->st_gid);
4917917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
4927917SReza.Sabdar@Sun.COM 	    attr->st_mtime);
4937917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4947917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
4957917SReza.Sabdar@Sun.COM 
4967917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
4977917SReza.Sabdar@Sun.COM 	if (long_name || long_link) {
4987917SReza.Sabdar@Sun.COM 		if (file_count > 99999990) {
4997917SReza.Sabdar@Sun.COM 			file_count = 0;
5007917SReza.Sabdar@Sun.COM 		}
5017917SReza.Sabdar@Sun.COM 	}
5027917SReza.Sabdar@Sun.COM 	free(section_name);
5037917SReza.Sabdar@Sun.COM 	return (0);
5047917SReza.Sabdar@Sun.COM }
5057917SReza.Sabdar@Sun.COM 
5067917SReza.Sabdar@Sun.COM 
5077917SReza.Sabdar@Sun.COM /*
5087917SReza.Sabdar@Sun.COM  * tlm_readlink
5097917SReza.Sabdar@Sun.COM  *
5107917SReza.Sabdar@Sun.COM  * Read where the softlink points to.  Read the link in the checkpointed
5117917SReza.Sabdar@Sun.COM  * path if the backup is being done on a checkpointed file system.
5127917SReza.Sabdar@Sun.COM  */
5137917SReza.Sabdar@Sun.COM static int
5147917SReza.Sabdar@Sun.COM tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
5157917SReza.Sabdar@Sun.COM {
5167917SReza.Sabdar@Sun.COM 	int len;
5177917SReza.Sabdar@Sun.COM 
5187917SReza.Sabdar@Sun.COM 	if ((len = readlink(snap, buf, bufsize)) >= 0) {
5197917SReza.Sabdar@Sun.COM 		/*
5207917SReza.Sabdar@Sun.COM 		 * realink(2) doesn't null terminate the link name.  We must
5217917SReza.Sabdar@Sun.COM 		 * do it here.
5227917SReza.Sabdar@Sun.COM 		 */
5237917SReza.Sabdar@Sun.COM 		buf[len] = '\0';
5247917SReza.Sabdar@Sun.COM 	} else {
5257917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Error %d reading softlink of [%s]",
5267917SReza.Sabdar@Sun.COM 		    errno, nm);
5277917SReza.Sabdar@Sun.COM 		buf[0] = '\0';
5287917SReza.Sabdar@Sun.COM 
5297917SReza.Sabdar@Sun.COM 		/* Backup the link if the destination missing */
5307917SReza.Sabdar@Sun.COM 		if (errno == ENOENT)
5317917SReza.Sabdar@Sun.COM 			return (0);
5327917SReza.Sabdar@Sun.COM 
5337917SReza.Sabdar@Sun.COM 	}
5347917SReza.Sabdar@Sun.COM 
5357917SReza.Sabdar@Sun.COM 	return (len);
5367917SReza.Sabdar@Sun.COM }
5377917SReza.Sabdar@Sun.COM 
5387917SReza.Sabdar@Sun.COM 
5397917SReza.Sabdar@Sun.COM /*
5407917SReza.Sabdar@Sun.COM  * tlm_output_xattr
5417917SReza.Sabdar@Sun.COM  *
5427917SReza.Sabdar@Sun.COM  * Put this file into the output buffers.
5437917SReza.Sabdar@Sun.COM  */
5447917SReza.Sabdar@Sun.COM /*ARGSUSED*/
5457917SReza.Sabdar@Sun.COM longlong_t
5467917SReza.Sabdar@Sun.COM tlm_output_xattr(char  *dir, char *name, char *chkdir,
5477917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
5487917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
5497917SReza.Sabdar@Sun.COM {
5507917SReza.Sabdar@Sun.COM 	char	*fullname;		/* directory + name */
5517917SReza.Sabdar@Sun.COM 	char	*snapname;		/* snapshot name */
5527917SReza.Sabdar@Sun.COM 	int	section;		/* section of a huge file */
5537917SReza.Sabdar@Sun.COM 	int	fd;
5547917SReza.Sabdar@Sun.COM 	longlong_t seek_spot = 0;	/* location in the file */
5557917SReza.Sabdar@Sun.COM 					/* for Multi Volume record */
5567917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
5577917SReza.Sabdar@Sun.COM 	DIR *dp;
5587917SReza.Sabdar@Sun.COM 	struct dirent *dtp;
5597917SReza.Sabdar@Sun.COM 	char *attrname;
5607917SReza.Sabdar@Sun.COM 	char *fnamep;
5617917SReza.Sabdar@Sun.COM 	int rv = 0;
5627917SReza.Sabdar@Sun.COM 
5637917SReza.Sabdar@Sun.COM 	if (S_ISLNK(tlm_acls->acl_attr.st_mode))
5647917SReza.Sabdar@Sun.COM 		return (TLM_NO_SOURCE_FILE);
5657917SReza.Sabdar@Sun.COM 
5667917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
5677917SReza.Sabdar@Sun.COM 	if (fullname == NULL) {
5687917SReza.Sabdar@Sun.COM 		free(fullname);
5697917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
5707917SReza.Sabdar@Sun.COM 	}
5717917SReza.Sabdar@Sun.COM 
5727917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name)) {
5737917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
5747917SReza.Sabdar@Sun.COM 		free(fullname);
5757917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
5767917SReza.Sabdar@Sun.COM 	}
5777917SReza.Sabdar@Sun.COM 
5787917SReza.Sabdar@Sun.COM 	if (pathconf(fullname, _PC_XATTR_EXISTS) != 1) {
5797917SReza.Sabdar@Sun.COM 		free(fullname);
5807917SReza.Sabdar@Sun.COM 		return (0);
5817917SReza.Sabdar@Sun.COM 	}
5827917SReza.Sabdar@Sun.COM 
5837917SReza.Sabdar@Sun.COM 	attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
5847917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
5857917SReza.Sabdar@Sun.COM 	if (attrname == NULL || snapname == NULL) {
5867917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
5877917SReza.Sabdar@Sun.COM 		goto err_out;
5887917SReza.Sabdar@Sun.COM 	}
5897917SReza.Sabdar@Sun.COM 
5907917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(snapname, chkdir, name)) {
5917917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
5927917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
5937917SReza.Sabdar@Sun.COM 		goto err_out;
5947917SReza.Sabdar@Sun.COM 	}
5957917SReza.Sabdar@Sun.COM 
5967917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
5977917SReza.Sabdar@Sun.COM 
5987917SReza.Sabdar@Sun.COM 	/*
5997917SReza.Sabdar@Sun.COM 	 * Open the file for reading.
6007917SReza.Sabdar@Sun.COM 	 */
6017917SReza.Sabdar@Sun.COM 	fd = open(fnamep, O_RDONLY | O_XATTR);
6027917SReza.Sabdar@Sun.COM 	if (fd == -1) {
6037917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
6047917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
6057917SReza.Sabdar@Sun.COM 		goto err_out;
6067917SReza.Sabdar@Sun.COM 	}
6077917SReza.Sabdar@Sun.COM 
6087917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
6097917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
6107917SReza.Sabdar@Sun.COM 
6117917SReza.Sabdar@Sun.COM 	section = 0;
6127917SReza.Sabdar@Sun.COM 
6137917SReza.Sabdar@Sun.COM 	dp = (DIR *)fdopendir(fd);
6147917SReza.Sabdar@Sun.COM 	if (dp == NULL) {
6157917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
6167917SReza.Sabdar@Sun.COM 		(void) close(fd);
6177917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
6187917SReza.Sabdar@Sun.COM 		goto err_out;
6197917SReza.Sabdar@Sun.COM 	}
6207917SReza.Sabdar@Sun.COM 
6217917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
6227917SReza.Sabdar@Sun.COM 	    local_commands);
6237917SReza.Sabdar@Sun.COM 
6247917SReza.Sabdar@Sun.COM 	while ((dtp = readdir(dp)) != NULL) {
6257917SReza.Sabdar@Sun.COM 		int section_size;
6267917SReza.Sabdar@Sun.COM 
6277917SReza.Sabdar@Sun.COM 		if (*dtp->d_name == '.')
6287917SReza.Sabdar@Sun.COM 			continue;
6297917SReza.Sabdar@Sun.COM 
6307917SReza.Sabdar@Sun.COM 		(void) close(fd);
6317917SReza.Sabdar@Sun.COM 		fd = attropen(fnamep, dtp->d_name, O_RDONLY);
6327917SReza.Sabdar@Sun.COM 		if (fd == -1) {
6337917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
6347917SReza.Sabdar@Sun.COM 			    "problem(%d) opening xattr file [%s]", errno,
6357917SReza.Sabdar@Sun.COM 			    fullname);
6367917SReza.Sabdar@Sun.COM 			goto tear_down;
6377917SReza.Sabdar@Sun.COM 		}
6387917SReza.Sabdar@Sun.COM 
6397917SReza.Sabdar@Sun.COM 		(void) output_xattr_header(fullname, dtp->d_name, fd,
6407917SReza.Sabdar@Sun.COM 		    tlm_acls, section, local_commands);
6417917SReza.Sabdar@Sun.COM 		(void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
6427917SReza.Sabdar@Sun.COM 		    dtp->d_name);
6437917SReza.Sabdar@Sun.COM 		(void) output_file_header(attrname, "", tlm_acls, 0,
6447917SReza.Sabdar@Sun.COM 		    local_commands);
6457917SReza.Sabdar@Sun.COM 
6467917SReza.Sabdar@Sun.COM 		section_size = (long)llmin(tlm_acls->acl_attr.st_size,
6477917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
6487917SReza.Sabdar@Sun.COM 
6497917SReza.Sabdar@Sun.COM 		/* We only can read upto one section extended attribute */
6507917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
6517917SReza.Sabdar@Sun.COM 			char	*buf;
6527917SReza.Sabdar@Sun.COM 			long	actual_size;
6537917SReza.Sabdar@Sun.COM 			int	read_size;
6547917SReza.Sabdar@Sun.COM 
6557917SReza.Sabdar@Sun.COM 			/*
6567917SReza.Sabdar@Sun.COM 			 * check for Abort commands
6577917SReza.Sabdar@Sun.COM 			 */
6587917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
6597917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
6607917SReza.Sabdar@Sun.COM 				goto tear_down;
6617917SReza.Sabdar@Sun.COM 			}
6627917SReza.Sabdar@Sun.COM 
6637917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
6647917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
6657917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
6667917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
6677917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
6687917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
6697917SReza.Sabdar@Sun.COM 
6707917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
6717917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
6727917SReza.Sabdar@Sun.COM 			if (!buf)
6737917SReza.Sabdar@Sun.COM 				goto tear_down;
6747917SReza.Sabdar@Sun.COM 
6757917SReza.Sabdar@Sun.COM 			/*
6767917SReza.Sabdar@Sun.COM 			 * check for Abort commands
6777917SReza.Sabdar@Sun.COM 			 */
6787917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
6797917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
6807917SReza.Sabdar@Sun.COM 				goto tear_down;
6817917SReza.Sabdar@Sun.COM 			}
6827917SReza.Sabdar@Sun.COM 
6837917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
6847917SReza.Sabdar@Sun.COM 			actual_size = read(fd, buf, read_size);
6857917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
6867917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
6877917SReza.Sabdar@Sun.COM 
6887917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
6897917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
6907917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
6917917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
6927917SReza.Sabdar@Sun.COM 				goto tear_down;
6937917SReza.Sabdar@Sun.COM 			}
6947917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
6957917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
6967917SReza.Sabdar@Sun.COM 		}
6977917SReza.Sabdar@Sun.COM 	}
6987917SReza.Sabdar@Sun.COM 
6997917SReza.Sabdar@Sun.COM tear_down:
7007917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
7017917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
7027917SReza.Sabdar@Sun.COM 
7037917SReza.Sabdar@Sun.COM 	(void) closedir(dp);
7047917SReza.Sabdar@Sun.COM 	(void) close(fd);
7057917SReza.Sabdar@Sun.COM 
7067917SReza.Sabdar@Sun.COM err_out:
7077917SReza.Sabdar@Sun.COM 	free(fullname);
7087917SReza.Sabdar@Sun.COM 	free(attrname);
7097917SReza.Sabdar@Sun.COM 	free(snapname);
7107917SReza.Sabdar@Sun.COM 	return (rv);
7117917SReza.Sabdar@Sun.COM }
7127917SReza.Sabdar@Sun.COM 
7137917SReza.Sabdar@Sun.COM 
7147917SReza.Sabdar@Sun.COM /*
7157917SReza.Sabdar@Sun.COM  * tlm_output_file
7167917SReza.Sabdar@Sun.COM  *
7177917SReza.Sabdar@Sun.COM  * Put this file into the output buffers.
7187917SReza.Sabdar@Sun.COM  */
7197917SReza.Sabdar@Sun.COM longlong_t
7207917SReza.Sabdar@Sun.COM tlm_output_file(char *dir, char *name, char *chkdir,
7217917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
7227917SReza.Sabdar@Sun.COM     tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
7237917SReza.Sabdar@Sun.COM {
7247917SReza.Sabdar@Sun.COM 	char	*fullname;		/* directory + name */
7257917SReza.Sabdar@Sun.COM 	char	*snapname;		/* snapshot name */
7267917SReza.Sabdar@Sun.COM 	char	*linkname;		/* where this file points */
7277917SReza.Sabdar@Sun.COM 	int	section = 0;		/* section of a huge file */
7287917SReza.Sabdar@Sun.COM 	int	fd;
7297917SReza.Sabdar@Sun.COM 	longlong_t real_size;		/* the origional file size */
7307917SReza.Sabdar@Sun.COM 	longlong_t file_size;		/* real size of this file */
7317917SReza.Sabdar@Sun.COM 	longlong_t seek_spot = 0;	/* location in the file */
7327917SReza.Sabdar@Sun.COM 					/* for Multi Volume record */
7337917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
7347917SReza.Sabdar@Sun.COM 	char *fnamep;
7357917SReza.Sabdar@Sun.COM 
7367917SReza.Sabdar@Sun.COM 	/* Indicate whether a file with the same inode has been backed up. */
7377917SReza.Sabdar@Sun.COM 	int hardlink_done = 0;
7387917SReza.Sabdar@Sun.COM 
7397917SReza.Sabdar@Sun.COM 	/*
7407917SReza.Sabdar@Sun.COM 	 * If a file with the same inode has been backed up, hardlink_pos holds
7417917SReza.Sabdar@Sun.COM 	 * the tape offset of the data record.
7427917SReza.Sabdar@Sun.COM 	 */
7437917SReza.Sabdar@Sun.COM 	u_longlong_t hardlink_pos = 0;
7447917SReza.Sabdar@Sun.COM 
7457917SReza.Sabdar@Sun.COM 	if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
7467917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name);
7477917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
7487917SReza.Sabdar@Sun.COM 	}
7497917SReza.Sabdar@Sun.COM 
7507917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
7517917SReza.Sabdar@Sun.COM 	linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
7527917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
7537917SReza.Sabdar@Sun.COM 	if (fullname == NULL || linkname == NULL || snapname == NULL) {
7547917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
7557917SReza.Sabdar@Sun.COM 		goto err_out;
7567917SReza.Sabdar@Sun.COM 	}
7577917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name) ||
7587917SReza.Sabdar@Sun.COM 	    !tlm_cat_path(snapname, chkdir, name)) {
7597917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
7607917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
7617917SReza.Sabdar@Sun.COM 		goto err_out;
7627917SReza.Sabdar@Sun.COM 	}
7637917SReza.Sabdar@Sun.COM 
7647917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
7657917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
7667917SReza.Sabdar@Sun.COM 
7677917SReza.Sabdar@Sun.COM 	if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
7687917SReza.Sabdar@Sun.COM 		file_size = tlm_readlink(fullname, snapname, linkname,
7697917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME-1);
7707917SReza.Sabdar@Sun.COM 		if (file_size < 0) {
7717917SReza.Sabdar@Sun.COM 			real_size = -ENOENT;
7727917SReza.Sabdar@Sun.COM 			goto err_out;
7737917SReza.Sabdar@Sun.COM 		}
7747917SReza.Sabdar@Sun.COM 
7757917SReza.Sabdar@Sun.COM 		/*
7767917SReza.Sabdar@Sun.COM 		 * Since soft links can not be read(2), we should only
7777917SReza.Sabdar@Sun.COM 		 * backup the file header.
7787917SReza.Sabdar@Sun.COM 		 */
7797917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
7807917SReza.Sabdar@Sun.COM 		    linkname,
7817917SReza.Sabdar@Sun.COM 		    tlm_acls,
7827917SReza.Sabdar@Sun.COM 		    section,
7837917SReza.Sabdar@Sun.COM 		    local_commands);
7847917SReza.Sabdar@Sun.COM 
7857917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
7867917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
7877917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhpath_name(job_stats, fullname,
7887917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
7897917SReza.Sabdar@Sun.COM 
7907917SReza.Sabdar@Sun.COM 		free(fullname);
7917917SReza.Sabdar@Sun.COM 		free(linkname);
7927917SReza.Sabdar@Sun.COM 		free(snapname);
7937917SReza.Sabdar@Sun.COM 		return (0);
7947917SReza.Sabdar@Sun.COM 	}
7957917SReza.Sabdar@Sun.COM 
7967917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
7977917SReza.Sabdar@Sun.COM 
7987917SReza.Sabdar@Sun.COM 	/*
7997917SReza.Sabdar@Sun.COM 	 * For hardlink, only read the data if no other link
8007917SReza.Sabdar@Sun.COM 	 * belonging to the same inode has been backed up.
8017917SReza.Sabdar@Sun.COM 	 */
8027917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1) {
8037917SReza.Sabdar@Sun.COM 		hardlink_done = !hardlink_q_get(hardlink_q,
8047917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
8057917SReza.Sabdar@Sun.COM 	}
8067917SReza.Sabdar@Sun.COM 
8077917SReza.Sabdar@Sun.COM 	if (!hardlink_done) {
8087917SReza.Sabdar@Sun.COM 		/*
8097917SReza.Sabdar@Sun.COM 		 * Open the file for reading.
8107917SReza.Sabdar@Sun.COM 		 */
8117917SReza.Sabdar@Sun.COM 		fd = open(fnamep, O_RDONLY);
8127917SReza.Sabdar@Sun.COM 		if (fd == -1) {
8137917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
8147917SReza.Sabdar@Sun.COM 			    "BACKUP> Can't open file [%s] err(%d)",
8157917SReza.Sabdar@Sun.COM 			    fullname, errno);
8167917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SOURCE_FILE;
8177917SReza.Sabdar@Sun.COM 			goto err_out;
8187917SReza.Sabdar@Sun.COM 		}
8197917SReza.Sabdar@Sun.COM 	} else {
820*8193SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
8217917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, hardlink_pos);
8227917SReza.Sabdar@Sun.COM 
8237917SReza.Sabdar@Sun.COM 		fd = -1;
8247917SReza.Sabdar@Sun.COM 	}
8257917SReza.Sabdar@Sun.COM 
8267917SReza.Sabdar@Sun.COM 	linkname[0] = 0;
8277917SReza.Sabdar@Sun.COM 
8287917SReza.Sabdar@Sun.COM 	real_size = tlm_acls->acl_attr.st_size;
8297917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
8307917SReza.Sabdar@Sun.COM 	    local_commands);
8317917SReza.Sabdar@Sun.COM 
8327917SReza.Sabdar@Sun.COM 	/*
8337917SReza.Sabdar@Sun.COM 	 * section = 0: file is small enough for TAR
8347917SReza.Sabdar@Sun.COM 	 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
8357917SReza.Sabdar@Sun.COM 	 * 		and the file name gets munged
8367917SReza.Sabdar@Sun.COM 	 */
8377917SReza.Sabdar@Sun.COM 	file_size = real_size;
8387917SReza.Sabdar@Sun.COM 	if (file_size > TLM_MAX_TAR_IMAGE) {
8397917SReza.Sabdar@Sun.COM 		if (output_humongus_header(fullname, file_size,
8407917SReza.Sabdar@Sun.COM 		    local_commands) < 0) {
8417917SReza.Sabdar@Sun.COM 			(void) close(fd);
8427917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SCRATCH_SPACE;
8437917SReza.Sabdar@Sun.COM 			goto err_out;
8447917SReza.Sabdar@Sun.COM 		}
8457917SReza.Sabdar@Sun.COM 		section = 1;
8467917SReza.Sabdar@Sun.COM 	} else {
8477917SReza.Sabdar@Sun.COM 		section = 0;
8487917SReza.Sabdar@Sun.COM 	}
8497917SReza.Sabdar@Sun.COM 
8507917SReza.Sabdar@Sun.COM 	/*
8517917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode
8527917SReza.Sabdar@Sun.COM 	 * has been backed up, only backup an empty record.
8537917SReza.Sabdar@Sun.COM 	 */
8547917SReza.Sabdar@Sun.COM 	if (hardlink_done)
8557917SReza.Sabdar@Sun.COM 		file_size = 0;
8567917SReza.Sabdar@Sun.COM 
8577917SReza.Sabdar@Sun.COM 	/*
8587917SReza.Sabdar@Sun.COM 	 * work
8597917SReza.Sabdar@Sun.COM 	 */
8607917SReza.Sabdar@Sun.COM 	if (file_size == 0) {
8617917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
8627917SReza.Sabdar@Sun.COM 		    linkname,
8637917SReza.Sabdar@Sun.COM 		    tlm_acls,
8647917SReza.Sabdar@Sun.COM 		    section,
8657917SReza.Sabdar@Sun.COM 		    local_commands);
8667917SReza.Sabdar@Sun.COM 		/*
8677917SReza.Sabdar@Sun.COM 		 * this can fall right through since zero size files
8687917SReza.Sabdar@Sun.COM 		 * will be skipped by the WHILE loop anyway
8697917SReza.Sabdar@Sun.COM 		 */
8707917SReza.Sabdar@Sun.COM 	}
8717917SReza.Sabdar@Sun.COM 
8727917SReza.Sabdar@Sun.COM 	while (file_size > 0) {
8737917SReza.Sabdar@Sun.COM 		int section_size = llmin(file_size,
8747917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
8757917SReza.Sabdar@Sun.COM 
8767917SReza.Sabdar@Sun.COM 		tlm_acls->acl_attr.st_size = (longlong_t)section_size;
8777917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
8787917SReza.Sabdar@Sun.COM 		    linkname,
8797917SReza.Sabdar@Sun.COM 		    tlm_acls,
8807917SReza.Sabdar@Sun.COM 		    section,
8817917SReza.Sabdar@Sun.COM 		    local_commands);
8827917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
8837917SReza.Sabdar@Sun.COM 			char	*buf;
8847917SReza.Sabdar@Sun.COM 			long	actual_size;
8857917SReza.Sabdar@Sun.COM 			int	read_size;
8867917SReza.Sabdar@Sun.COM 
8877917SReza.Sabdar@Sun.COM 			/*
8887917SReza.Sabdar@Sun.COM 			 * check for Abort commands
8897917SReza.Sabdar@Sun.COM 			 */
8907917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
8917917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
8927917SReza.Sabdar@Sun.COM 				goto tear_down;
8937917SReza.Sabdar@Sun.COM 			}
8947917SReza.Sabdar@Sun.COM 
8957917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
8967917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
8977917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
8987917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
8997917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
9007917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
9017917SReza.Sabdar@Sun.COM 
9027917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
9037917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
9047917SReza.Sabdar@Sun.COM 			if (!buf)
9057917SReza.Sabdar@Sun.COM 				goto tear_down;
9067917SReza.Sabdar@Sun.COM 
9077917SReza.Sabdar@Sun.COM 			/*
9087917SReza.Sabdar@Sun.COM 			 * check for Abort commands
9097917SReza.Sabdar@Sun.COM 			 */
9107917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
9117917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
9127917SReza.Sabdar@Sun.COM 				goto tear_down;
9137917SReza.Sabdar@Sun.COM 			}
9147917SReza.Sabdar@Sun.COM 
9157917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
9167917SReza.Sabdar@Sun.COM 			actual_size = read(fd, buf, read_size);
9177917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
9187917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
9197917SReza.Sabdar@Sun.COM 
9207917SReza.Sabdar@Sun.COM 			if (actual_size == 0)
9217917SReza.Sabdar@Sun.COM 				break;
9227917SReza.Sabdar@Sun.COM 
9237917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
9247917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
9257917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
9267917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
9277917SReza.Sabdar@Sun.COM 				goto tear_down;
9287917SReza.Sabdar@Sun.COM 			}
9297917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
9307917SReza.Sabdar@Sun.COM 			file_size -= actual_size;
9317917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
9327917SReza.Sabdar@Sun.COM 		}
9337917SReza.Sabdar@Sun.COM 		section++;
9347917SReza.Sabdar@Sun.COM 	}
9357917SReza.Sabdar@Sun.COM 
9367917SReza.Sabdar@Sun.COM 	/*
9377917SReza.Sabdar@Sun.COM 	 * If data belonging to this hardlink has been backed up, add the link
9387917SReza.Sabdar@Sun.COM 	 * to hardlink queue.
9397917SReza.Sabdar@Sun.COM 	 */
9407917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
9417917SReza.Sabdar@Sun.COM 		(void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
9427917SReza.Sabdar@Sun.COM 		    pos, NULL, 0);
9437917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
944*8193SReza.Sabdar@Sun.COM 		    "backed up hardlink file %s, inode = %llu, pos = %llu ",
9457917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, pos);
9467917SReza.Sabdar@Sun.COM 	}
9477917SReza.Sabdar@Sun.COM 
9487917SReza.Sabdar@Sun.COM 	/*
9497917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode has been
950*8193SReza.Sabdar@Sun.COM 	 * backed up, no add_node entry should be sent for this link.
9517917SReza.Sabdar@Sun.COM 	 */
9527917SReza.Sabdar@Sun.COM 	if (hardlink_done) {
9537917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
954*8193SReza.Sabdar@Sun.COM 		    "backed up hardlink link %s, inode = %llu, pos = %llu ",
9557917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
9567917SReza.Sabdar@Sun.COM 	} else {
9577917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
9587917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
9597917SReza.Sabdar@Sun.COM 	}
9607917SReza.Sabdar@Sun.COM 
9617917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
9627917SReza.Sabdar@Sun.COM 	    pos);
9637917SReza.Sabdar@Sun.COM 
9647917SReza.Sabdar@Sun.COM tear_down:
9657917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
9667917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
9677917SReza.Sabdar@Sun.COM 
9687917SReza.Sabdar@Sun.COM 	(void) close(fd);
9697917SReza.Sabdar@Sun.COM 
9707917SReza.Sabdar@Sun.COM err_out:
9717917SReza.Sabdar@Sun.COM 	free(fullname);
9727917SReza.Sabdar@Sun.COM 	free(linkname);
9737917SReza.Sabdar@Sun.COM 	free(snapname);
9747917SReza.Sabdar@Sun.COM 	return (real_size);
9757917SReza.Sabdar@Sun.COM }
9767917SReza.Sabdar@Sun.COM 
9777917SReza.Sabdar@Sun.COM /*
9787917SReza.Sabdar@Sun.COM  * tar_putfile
9797917SReza.Sabdar@Sun.COM  *
9807917SReza.Sabdar@Sun.COM  * Main file backup function for tar
9817917SReza.Sabdar@Sun.COM  */
9827917SReza.Sabdar@Sun.COM int
9837917SReza.Sabdar@Sun.COM tar_putfile(char *dir, char *name, char *chkdir,
9847917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
9857917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
9867917SReza.Sabdar@Sun.COM     struct hardlink_q *hardlink_q)
9877917SReza.Sabdar@Sun.COM {
9887917SReza.Sabdar@Sun.COM 	int rv;
9897917SReza.Sabdar@Sun.COM 
9907917SReza.Sabdar@Sun.COM 	rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
9917917SReza.Sabdar@Sun.COM 	    local_commands, job_stats, hardlink_q);
9927917SReza.Sabdar@Sun.COM 	if (rv < 0)
9937917SReza.Sabdar@Sun.COM 		return (rv);
9947917SReza.Sabdar@Sun.COM 
9957917SReza.Sabdar@Sun.COM 	rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
9967917SReza.Sabdar@Sun.COM 	    local_commands, job_stats);
9977917SReza.Sabdar@Sun.COM 
9987917SReza.Sabdar@Sun.COM 	return (rv < 0 ? rv : 0);
9997917SReza.Sabdar@Sun.COM }
10007917SReza.Sabdar@Sun.COM 
10017917SReza.Sabdar@Sun.COM /*
10027917SReza.Sabdar@Sun.COM  * get_write_buffer
10037917SReza.Sabdar@Sun.COM  *
10047917SReza.Sabdar@Sun.COM  * a wrapper to tlm_get_write_buffer so that
10057917SReza.Sabdar@Sun.COM  * we can cleanly detect ABORT commands
10067917SReza.Sabdar@Sun.COM  * without involving the TLM library with
10077917SReza.Sabdar@Sun.COM  * our problems.
10087917SReza.Sabdar@Sun.COM  */
10097917SReza.Sabdar@Sun.COM static char *
10107917SReza.Sabdar@Sun.COM get_write_buffer(long size, long *actual_size,
10117917SReza.Sabdar@Sun.COM     boolean_t zero, tlm_cmd_t *local_commands)
10127917SReza.Sabdar@Sun.COM {
10137917SReza.Sabdar@Sun.COM 	while (local_commands->tc_reader == TLM_BACKUP_RUN) {
10147917SReza.Sabdar@Sun.COM 		char *rec = tlm_get_write_buffer(size, actual_size,
10157917SReza.Sabdar@Sun.COM 		    local_commands->tc_buffers, zero);
10167917SReza.Sabdar@Sun.COM 		if (rec != 0) {
10177917SReza.Sabdar@Sun.COM 			return (rec);
10187917SReza.Sabdar@Sun.COM 		}
10197917SReza.Sabdar@Sun.COM 	}
10207917SReza.Sabdar@Sun.COM 	return (NULL);
10217917SReza.Sabdar@Sun.COM }
10227917SReza.Sabdar@Sun.COM 
10237917SReza.Sabdar@Sun.COM #define	NDMP_MORE_RECORDS	2
10247917SReza.Sabdar@Sun.COM 
10257917SReza.Sabdar@Sun.COM /*
10267917SReza.Sabdar@Sun.COM  * write_tar_eof
10277917SReza.Sabdar@Sun.COM  *
10287917SReza.Sabdar@Sun.COM  * This function is initially written for NDMP support.  It appends
10297917SReza.Sabdar@Sun.COM  * two tar headers to the tar file, and also N more empty buffers
10307917SReza.Sabdar@Sun.COM  * to make sure that the two tar headers will be read as a part of
10317917SReza.Sabdar@Sun.COM  * a mover record and don't get locked because of EOM on the mover
10327917SReza.Sabdar@Sun.COM  * side.
10337917SReza.Sabdar@Sun.COM  */
10347917SReza.Sabdar@Sun.COM void
10357917SReza.Sabdar@Sun.COM write_tar_eof(tlm_cmd_t *local_commands)
10367917SReza.Sabdar@Sun.COM {
10377917SReza.Sabdar@Sun.COM 	int i;
10387917SReza.Sabdar@Sun.COM 	long actual_size;
10397917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
10407917SReza.Sabdar@Sun.COM 
10417917SReza.Sabdar@Sun.COM 	/*
10427917SReza.Sabdar@Sun.COM 	 * output 2 zero filled records,
10437917SReza.Sabdar@Sun.COM 	 * TAR wants this.
10447917SReza.Sabdar@Sun.COM 	 */
10457917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
10467917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
10477917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
10487917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
10497917SReza.Sabdar@Sun.COM 
10507917SReza.Sabdar@Sun.COM 	/*
10517917SReza.Sabdar@Sun.COM 	 * NDMP: Clear the rest of the buffer and write two more buffers
10527917SReza.Sabdar@Sun.COM 	 * to the tape.
10537917SReza.Sabdar@Sun.COM 	 */
10547917SReza.Sabdar@Sun.COM 	bufs = local_commands->tc_buffers;
10557917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(bufs->tbs_data_transfer_size,
10567917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
10577917SReza.Sabdar@Sun.COM 
10587917SReza.Sabdar@Sun.COM 	for (i = 0; i < NDMP_MORE_RECORDS &&
10597917SReza.Sabdar@Sun.COM 	    local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
10607917SReza.Sabdar@Sun.COM 		/*
10617917SReza.Sabdar@Sun.COM 		 * We don't need the return value of get_write_buffer(),
10627917SReza.Sabdar@Sun.COM 		 * since it's already zeroed out if the buffer is returned.
10637917SReza.Sabdar@Sun.COM 		 */
10647917SReza.Sabdar@Sun.COM 		(void) get_write_buffer(bufs->tbs_data_transfer_size,
10657917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
10667917SReza.Sabdar@Sun.COM 	}
10677917SReza.Sabdar@Sun.COM 
10687917SReza.Sabdar@Sun.COM 	bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
10697917SReza.Sabdar@Sun.COM 	tlm_buffer_release_in_buf(bufs);
10707917SReza.Sabdar@Sun.COM }
10717917SReza.Sabdar@Sun.COM 
10727917SReza.Sabdar@Sun.COM /*
10737917SReza.Sabdar@Sun.COM  * Callback to backup each ZFS property
10747917SReza.Sabdar@Sun.COM  */
10757917SReza.Sabdar@Sun.COM static int
10767917SReza.Sabdar@Sun.COM zfs_put_prop_cb(int prop, void *pp)
10777917SReza.Sabdar@Sun.COM {
10787917SReza.Sabdar@Sun.COM 	ndmp_metadata_header_t *mhp;
10797917SReza.Sabdar@Sun.COM 	ndmp_metadata_property_t *mpp;
10807917SReza.Sabdar@Sun.COM 	char buf[ZFS_MAXNAMELEN];
10817917SReza.Sabdar@Sun.COM 	char sbuf[ZFS_MAXNAMELEN];
10827917SReza.Sabdar@Sun.COM 	zprop_source_t stype;
10837917SReza.Sabdar@Sun.COM 
10847917SReza.Sabdar@Sun.COM 	if (pp == NULL)
10857917SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
10867917SReza.Sabdar@Sun.COM 
10877917SReza.Sabdar@Sun.COM 	mhp = (ndmp_metadata_header_t *)pp;
10887917SReza.Sabdar@Sun.COM 	mpp = &mhp->nh_property[mhp->nh_count++];
10897917SReza.Sabdar@Sun.COM 
10907917SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), NAME_MAX);
10917917SReza.Sabdar@Sun.COM 	(void) zfs_prop_get(mhp->nh_handle,
10927917SReza.Sabdar@Sun.COM 	    prop, buf, sizeof (buf), &stype, sbuf, sizeof (sbuf), FALSE);
10937917SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_value, buf, NAME_MAX);
10947917SReza.Sabdar@Sun.COM 	if (stype == ZPROP_SRC_LOCAL)
10957917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_source, mhp->nh_dataset, NAME_MAX);
10967917SReza.Sabdar@Sun.COM 	else
10977917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_source, sbuf, NAME_MAX);
10987917SReza.Sabdar@Sun.COM 
10997917SReza.Sabdar@Sun.COM 	return (ZPROP_CONT);
11007917SReza.Sabdar@Sun.COM }
11017917SReza.Sabdar@Sun.COM 
11027917SReza.Sabdar@Sun.COM 
11037917SReza.Sabdar@Sun.COM /*
11047917SReza.Sabdar@Sun.COM  * Notifies ndmpd that the metadata associated with the given ZFS dataset
11057917SReza.Sabdar@Sun.COM  * should be backed up.
11067917SReza.Sabdar@Sun.COM  */
11077917SReza.Sabdar@Sun.COM int
11087917SReza.Sabdar@Sun.COM ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
11097917SReza.Sabdar@Sun.COM {
11107917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;
11117917SReza.Sabdar@Sun.COM 	ndmp_metadata_header_t *mhp;
11127917SReza.Sabdar@Sun.COM 	ndmp_metadata_property_t *mpp;
11137917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;
11147917SReza.Sabdar@Sun.COM 	long actual_size;
11157917SReza.Sabdar@Sun.COM 	nvlist_t *uprops, *ulist;
11167917SReza.Sabdar@Sun.COM 	const char *pname;
11177917SReza.Sabdar@Sun.COM 	nvpair_t *elp;
11187917SReza.Sabdar@Sun.COM 	char *sval, *ssrc;
11197917SReza.Sabdar@Sun.COM 	char *wbuf, *pp, *tp;
11207917SReza.Sabdar@Sun.COM 	long size, lsize, sz;
11217917SReza.Sabdar@Sun.COM 	int align = RECORDSIZE - 1;
11227917SReza.Sabdar@Sun.COM 
11237917SReza.Sabdar@Sun.COM 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
11247917SReza.Sabdar@Sun.COM 		return (-1);
11257917SReza.Sabdar@Sun.COM 
11267917SReza.Sabdar@Sun.COM 	if ((lcmd = cmds->tcs_command) == NULL ||
11277917SReza.Sabdar@Sun.COM 	    lcmd->tc_buffers == NULL)
11287917SReza.Sabdar@Sun.COM 		return (-1);
11297917SReza.Sabdar@Sun.COM 
11307917SReza.Sabdar@Sun.COM 	size = sizeof (ndmp_metadata_header_t) +
11317917SReza.Sabdar@Sun.COM 	    ZFS_MAX_PROPS * sizeof (ndmp_metadata_property_t);
11327917SReza.Sabdar@Sun.COM 	size += align;
11337917SReza.Sabdar@Sun.COM 	size &= ~align;
11347917SReza.Sabdar@Sun.COM 
11357917SReza.Sabdar@Sun.COM 	if ((mhp = malloc(size)) == NULL)
11367917SReza.Sabdar@Sun.COM 		return (-1);
11377917SReza.Sabdar@Sun.COM 	(void) memset(mhp, 0, size);
11387917SReza.Sabdar@Sun.COM 
11397917SReza.Sabdar@Sun.COM 	mhp->nh_plversion = nctx->nc_plversion;
11407917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_plname, nctx->nc_plname,
11417917SReza.Sabdar@Sun.COM 	    sizeof (mhp->nh_plname));
11427917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC, sizeof (mhp->nh_magic));
11437917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
11447917SReza.Sabdar@Sun.COM 
11457917SReza.Sabdar@Sun.COM 	if ((mhp->nh_handle = zfs_open(zlibh, dataset,
11467917SReza.Sabdar@Sun.COM 	    ZFS_TYPE_DATASET)) == NULL) {
11477917SReza.Sabdar@Sun.COM 		free(mhp);
11487917SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
11497917SReza.Sabdar@Sun.COM 	}
11507917SReza.Sabdar@Sun.COM 
11517917SReza.Sabdar@Sun.COM 	/* Get all the ZFS properties */
11527917SReza.Sabdar@Sun.COM 	(void) zprop_iter(zfs_put_prop_cb, mhp, TRUE, TRUE,
11537917SReza.Sabdar@Sun.COM 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
11547917SReza.Sabdar@Sun.COM 
11557917SReza.Sabdar@Sun.COM 	/* Get user properties */
11567917SReza.Sabdar@Sun.COM 	uprops = zfs_get_user_props(mhp->nh_handle);
11577917SReza.Sabdar@Sun.COM 
11587917SReza.Sabdar@Sun.COM 	elp = nvlist_next_nvpair(uprops, NULL);
11597917SReza.Sabdar@Sun.COM 
11607917SReza.Sabdar@Sun.COM 	while (elp != NULL) {
11617917SReza.Sabdar@Sun.COM 		mpp = &mhp->nh_property[mhp->nh_count];
11627917SReza.Sabdar@Sun.COM 		if (nvpair_value_nvlist(elp, &ulist) != 0 ||
11637917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
11647917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
11657917SReza.Sabdar@Sun.COM 			zfs_close(mhp->nh_handle);
11667917SReza.Sabdar@Sun.COM 			free(mhp);
11677917SReza.Sabdar@Sun.COM 			return (-1);
11687917SReza.Sabdar@Sun.COM 		}
11697917SReza.Sabdar@Sun.COM 		if ((pname = nvpair_name(elp)) != NULL)
11707917SReza.Sabdar@Sun.COM 			(void) strlcpy(mpp->mp_name, pname, NAME_MAX);
11717917SReza.Sabdar@Sun.COM 
11727917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_value, sval, NAME_MAX);
11737917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_source, ssrc, NAME_MAX);
11747917SReza.Sabdar@Sun.COM 		mhp->nh_count++;
11757917SReza.Sabdar@Sun.COM 		elp = nvlist_next_nvpair(uprops, elp);
11767917SReza.Sabdar@Sun.COM 	}
11777917SReza.Sabdar@Sun.COM 
11787917SReza.Sabdar@Sun.COM 	zfs_close(mhp->nh_handle);
11797917SReza.Sabdar@Sun.COM 
11807917SReza.Sabdar@Sun.COM 	if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
11817917SReza.Sabdar@Sun.COM 	    lcmd)) != NULL) {
11827917SReza.Sabdar@Sun.COM 		pp = (char *)mhp;
11837917SReza.Sabdar@Sun.COM 
11847917SReza.Sabdar@Sun.COM 		(void) memcpy(wbuf, pp, (actual_size < size) ?
11857917SReza.Sabdar@Sun.COM 		    actual_size : size);
11867917SReza.Sabdar@Sun.COM 		pp += (actual_size < size) ? actual_size : size;
11877917SReza.Sabdar@Sun.COM 
11887917SReza.Sabdar@Sun.COM 		sz = actual_size;
11897917SReza.Sabdar@Sun.COM 		while (sz < size &&
11907917SReza.Sabdar@Sun.COM 		    ((tp = get_write_buffer(size - sz, &lsize,
11917917SReza.Sabdar@Sun.COM 		    TRUE, lcmd))) != NULL) {
11927917SReza.Sabdar@Sun.COM 			(void) memcpy(tp, pp, size - sz);
11937917SReza.Sabdar@Sun.COM 			sz += lsize;
11947917SReza.Sabdar@Sun.COM 			pp += lsize;
11957917SReza.Sabdar@Sun.COM 		}
11967917SReza.Sabdar@Sun.COM 		if (sz > size) {
11977917SReza.Sabdar@Sun.COM 			tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
11987917SReza.Sabdar@Sun.COM 		}
11997917SReza.Sabdar@Sun.COM 	}
12007917SReza.Sabdar@Sun.COM 
12017917SReza.Sabdar@Sun.COM 	free(mhp);
12027917SReza.Sabdar@Sun.COM 	return (0);
12037917SReza.Sabdar@Sun.COM }
1204