xref: /onnv-gate/usr/src/cmd/ndmpd/tlm/tlm_backup_reader.c (revision 9659:525bdf24b1f5)
17917SReza.Sabdar@Sun.COM /*
28540SReza.Sabdar@Sun.COM  * Copyright 2009 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>
508540SReza.Sabdar@Sun.COM #include <libcmdutils.h>
518540SReza.Sabdar@Sun.COM #include <pwd.h>
528540SReza.Sabdar@Sun.COM #include <grp.h>
537917SReza.Sabdar@Sun.COM #include "tlm_proto.h"
547917SReza.Sabdar@Sun.COM 
557917SReza.Sabdar@Sun.COM 
567917SReza.Sabdar@Sun.COM static char *get_write_buffer(long size,
577917SReza.Sabdar@Sun.COM     long *actual_size,
587917SReza.Sabdar@Sun.COM     boolean_t zero,
597917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
607917SReza.Sabdar@Sun.COM static int output_acl_header(sec_attr_t *,
617917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
627917SReza.Sabdar@Sun.COM static int output_file_header(char *name,
637917SReza.Sabdar@Sun.COM     char *link,
647917SReza.Sabdar@Sun.COM     tlm_acls_t *,
657917SReza.Sabdar@Sun.COM     int section,
667917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
677917SReza.Sabdar@Sun.COM static int output_xattr_header(char *fname,
687917SReza.Sabdar@Sun.COM     char *aname,
697917SReza.Sabdar@Sun.COM     int fd,
707917SReza.Sabdar@Sun.COM     tlm_acls_t *,
717917SReza.Sabdar@Sun.COM     int section,
727917SReza.Sabdar@Sun.COM     tlm_cmd_t *);
737917SReza.Sabdar@Sun.COM 
747917SReza.Sabdar@Sun.COM extern  libzfs_handle_t *zlibh;
757917SReza.Sabdar@Sun.COM 
767917SReza.Sabdar@Sun.COM 
777917SReza.Sabdar@Sun.COM /*
787917SReza.Sabdar@Sun.COM  * output_mem
797917SReza.Sabdar@Sun.COM  *
807917SReza.Sabdar@Sun.COM  * Gets a IO write buffer and copies memory to the that.
817917SReza.Sabdar@Sun.COM  */
827917SReza.Sabdar@Sun.COM static void
837917SReza.Sabdar@Sun.COM output_mem(tlm_cmd_t *local_commands, char *mem,
847917SReza.Sabdar@Sun.COM     int len)
857917SReza.Sabdar@Sun.COM {
867917SReza.Sabdar@Sun.COM 	long actual_size, rec_size;
877917SReza.Sabdar@Sun.COM 	char *rec;
887917SReza.Sabdar@Sun.COM 
897917SReza.Sabdar@Sun.COM 	while (len > 0) {
907917SReza.Sabdar@Sun.COM 		rec = get_write_buffer(len, &actual_size,
917917SReza.Sabdar@Sun.COM 		    FALSE, local_commands);
927917SReza.Sabdar@Sun.COM 		rec_size = min(actual_size, len);
937917SReza.Sabdar@Sun.COM 		(void) memcpy(rec, mem, rec_size);
947917SReza.Sabdar@Sun.COM 		mem += rec_size;
957917SReza.Sabdar@Sun.COM 		len -= rec_size;
967917SReza.Sabdar@Sun.COM 	}
977917SReza.Sabdar@Sun.COM }
987917SReza.Sabdar@Sun.COM 
997917SReza.Sabdar@Sun.COM /*
1007917SReza.Sabdar@Sun.COM  * tlm_output_dir
1017917SReza.Sabdar@Sun.COM  *
1027917SReza.Sabdar@Sun.COM  * Put the directory information into the output buffers.
1037917SReza.Sabdar@Sun.COM  */
1047917SReza.Sabdar@Sun.COM int
1057917SReza.Sabdar@Sun.COM tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
1067917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1077917SReza.Sabdar@Sun.COM {
1087917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
1097917SReza.Sabdar@Sun.COM 
1107917SReza.Sabdar@Sun.COM 	/*
1117917SReza.Sabdar@Sun.COM 	 * Send the node or path history of the directory itself.
1127917SReza.Sabdar@Sun.COM 	 */
1137917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
1147917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
1157917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
1167917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
1177917SReza.Sabdar@Sun.COM 	/* fhdir_cb is handled in ndmpd_tar3.c */
1187917SReza.Sabdar@Sun.COM 
1197917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
1207917SReza.Sabdar@Sun.COM 	    local_commands);
1217917SReza.Sabdar@Sun.COM 	(void) output_file_header(name, "", tlm_acls, 0,
1227917SReza.Sabdar@Sun.COM 	    local_commands);
1237917SReza.Sabdar@Sun.COM 
1247917SReza.Sabdar@Sun.COM 	return (0);
1257917SReza.Sabdar@Sun.COM }
1267917SReza.Sabdar@Sun.COM 
1277917SReza.Sabdar@Sun.COM /*
1287917SReza.Sabdar@Sun.COM  * tar_putdir
1297917SReza.Sabdar@Sun.COM  *
1307917SReza.Sabdar@Sun.COM  * Main dir backup function for tar
1317917SReza.Sabdar@Sun.COM  */
1327917SReza.Sabdar@Sun.COM int
1337917SReza.Sabdar@Sun.COM tar_putdir(char *name, tlm_acls_t *tlm_acls,
1347917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1357917SReza.Sabdar@Sun.COM {
1367917SReza.Sabdar@Sun.COM 	int rv;
1377917SReza.Sabdar@Sun.COM 
1387917SReza.Sabdar@Sun.COM 	rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats);
1397917SReza.Sabdar@Sun.COM 	return (rv < 0 ? rv : 0);
1407917SReza.Sabdar@Sun.COM }
1417917SReza.Sabdar@Sun.COM 
1427917SReza.Sabdar@Sun.COM /*
1437917SReza.Sabdar@Sun.COM  * output_acl_header
1447917SReza.Sabdar@Sun.COM  *
1457917SReza.Sabdar@Sun.COM  * output the ACL header record and data
1467917SReza.Sabdar@Sun.COM  */
1477917SReza.Sabdar@Sun.COM static int
1487917SReza.Sabdar@Sun.COM output_acl_header(sec_attr_t *acl_info,
1497917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands)
1507917SReza.Sabdar@Sun.COM {
1517917SReza.Sabdar@Sun.COM 	long	actual_size;
1527917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
1537917SReza.Sabdar@Sun.COM 	long	acl_size;
1547917SReza.Sabdar@Sun.COM 
1557917SReza.Sabdar@Sun.COM 	if ((acl_info == NULL) || (*acl_info->attr_info == '\0'))
1567917SReza.Sabdar@Sun.COM 		return (0);
1577917SReza.Sabdar@Sun.COM 
1587917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
1597917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
1607917SReza.Sabdar@Sun.COM 	if (!tar_hdr)
1617917SReza.Sabdar@Sun.COM 		return (0);
1627917SReza.Sabdar@Sun.COM 
1637917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_ACL;
1647917SReza.Sabdar@Sun.COM 	acl_info->attr_type = UFSD_ACL;
1657917SReza.Sabdar@Sun.COM 	(void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len),
1667917SReza.Sabdar@Sun.COM 	    "%06o", strlen(acl_info->attr_info));
1677917SReza.Sabdar@Sun.COM 
1687917SReza.Sabdar@Sun.COM 	acl_size = sizeof (*acl_info);
1697917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE);
1707917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
1717917SReza.Sabdar@Sun.COM 	    acl_size);
1727917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
1737917SReza.Sabdar@Sun.COM 	    0444);
1747917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0);
1757917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0);
1767917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
1777917SReza.Sabdar@Sun.COM 	    "%011o ", 0);
1787917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
1797917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
1807917SReza.Sabdar@Sun.COM 
1817917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
1827917SReza.Sabdar@Sun.COM 
1837917SReza.Sabdar@Sun.COM 	(void) output_mem(local_commands, (void *)acl_info, acl_size);
1847917SReza.Sabdar@Sun.COM 	return (0);
1857917SReza.Sabdar@Sun.COM }
1867917SReza.Sabdar@Sun.COM 
1877917SReza.Sabdar@Sun.COM /*
1887917SReza.Sabdar@Sun.COM  * output_humongus_header
1897917SReza.Sabdar@Sun.COM  *
1907917SReza.Sabdar@Sun.COM  * output a special header record for HUGE files
1917917SReza.Sabdar@Sun.COM  * output is:	1) a TAR "HUGE" header redord
1927917SReza.Sabdar@Sun.COM  * 		2) a "file" of size, name
1937917SReza.Sabdar@Sun.COM  */
1947917SReza.Sabdar@Sun.COM static int
1957917SReza.Sabdar@Sun.COM output_humongus_header(char *fullname, longlong_t file_size,
1967917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands)
1977917SReza.Sabdar@Sun.COM {
1987917SReza.Sabdar@Sun.COM 	char	*buf;
1997917SReza.Sabdar@Sun.COM 	int	len;
2007917SReza.Sabdar@Sun.COM 	long	actual_size;
2017917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
2027917SReza.Sabdar@Sun.COM 
2037917SReza.Sabdar@Sun.COM 	/*
2047917SReza.Sabdar@Sun.COM 	 * buf will contain: "%llu %s":
2057917SReza.Sabdar@Sun.COM 	 * - 20 is the maximum length of 'ulong_tlong' decimal notation.
2067917SReza.Sabdar@Sun.COM 	 * - The first '1' is for the ' ' between the "%llu" and the fullname.
2077917SReza.Sabdar@Sun.COM 	 * - The last '1' is for the null-terminator of fullname.
2087917SReza.Sabdar@Sun.COM 	 */
2097917SReza.Sabdar@Sun.COM 	len = 20 + 1 + strlen(fullname) + 1;
2107917SReza.Sabdar@Sun.COM 
2117917SReza.Sabdar@Sun.COM 	if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
2127917SReza.Sabdar@Sun.COM 		return (-1);
2137917SReza.Sabdar@Sun.COM 
2147917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2157917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
2167917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
2177917SReza.Sabdar@Sun.COM 		free(buf);
2187917SReza.Sabdar@Sun.COM 		return (0);
2197917SReza.Sabdar@Sun.COM 	}
2207917SReza.Sabdar@Sun.COM 
2217917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_HUMONGUS;
2227917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2237917SReza.Sabdar@Sun.COM 	    len);
2247917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
2257917SReza.Sabdar@Sun.COM 	(void) snprintf(buf, len, "%lld %s", file_size, fullname);
2267917SReza.Sabdar@Sun.COM 	(void) output_mem(local_commands, buf, len);
2277917SReza.Sabdar@Sun.COM 
2287917SReza.Sabdar@Sun.COM 	free(buf);
2297917SReza.Sabdar@Sun.COM 	return (0);
2307917SReza.Sabdar@Sun.COM }
2317917SReza.Sabdar@Sun.COM 
2327917SReza.Sabdar@Sun.COM 
2337917SReza.Sabdar@Sun.COM /*
2347917SReza.Sabdar@Sun.COM  * output_xattr_header
2357917SReza.Sabdar@Sun.COM  *
2367917SReza.Sabdar@Sun.COM  * output the TAR header record for extended attributes
2377917SReza.Sabdar@Sun.COM  */
2387917SReza.Sabdar@Sun.COM static int
2397917SReza.Sabdar@Sun.COM output_xattr_header(char *fname, char *aname, int fd,
2407917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
2417917SReza.Sabdar@Sun.COM {
2427917SReza.Sabdar@Sun.COM 	struct stat64 *attr = &tlm_acls->acl_attr;
2437917SReza.Sabdar@Sun.COM 	struct xattr_hdr *xhdr;
2447917SReza.Sabdar@Sun.COM 	struct xattr_buf *xbuf;
2457917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
2467917SReza.Sabdar@Sun.COM 	long	actual_size;
2477917SReza.Sabdar@Sun.COM 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
2487917SReza.Sabdar@Sun.COM 	int	hsize;
2497917SReza.Sabdar@Sun.COM 	int	comlen;
2507917SReza.Sabdar@Sun.COM 	int	namesz;
2517917SReza.Sabdar@Sun.COM 
2527917SReza.Sabdar@Sun.COM 	if (section_name == NULL)
2537917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
2547917SReza.Sabdar@Sun.COM 
2557917SReza.Sabdar@Sun.COM 	if (fstat64(fd, attr) == -1) {
2567917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "output_file_header stat failed.");
2577917SReza.Sabdar@Sun.COM 		free(section_name);
2587917SReza.Sabdar@Sun.COM 		return (-TLM_OPEN_ERR);
2597917SReza.Sabdar@Sun.COM 	}
2607917SReza.Sabdar@Sun.COM 
2617917SReza.Sabdar@Sun.COM 	/*
2627917SReza.Sabdar@Sun.COM 	 * if the file has to go out in sections,
2637917SReza.Sabdar@Sun.COM 	 * we must mung the name.
2647917SReza.Sabdar@Sun.COM 	 */
2657917SReza.Sabdar@Sun.COM 	if (section == 0) {
2667917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name, TLM_MAX_PATH_NAME,
2677917SReza.Sabdar@Sun.COM 		    "/dev/null/%s.hdr", aname);
2687917SReza.Sabdar@Sun.COM 	} else {
2697917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name,
2707917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
2717917SReza.Sabdar@Sun.COM 	}
2727917SReza.Sabdar@Sun.COM 	namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
2737917SReza.Sabdar@Sun.COM 	hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
2747917SReza.Sabdar@Sun.COM 	comlen = namesz + sizeof (struct xattr_buf);
2757917SReza.Sabdar@Sun.COM 
2767917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2777917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
2787917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
2797917SReza.Sabdar@Sun.COM 		free(section_name);
2807917SReza.Sabdar@Sun.COM 		return (0);
2817917SReza.Sabdar@Sun.COM 	}
2827917SReza.Sabdar@Sun.COM 
2837917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
2847917SReza.Sabdar@Sun.COM 
2857917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_XATTR;
2867917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2877917SReza.Sabdar@Sun.COM 	    hsize);
2887917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
2897917SReza.Sabdar@Sun.COM 	    attr->st_mode & 07777);
2907917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
2917917SReza.Sabdar@Sun.COM 	    attr->st_uid);
2927917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
2937917SReza.Sabdar@Sun.COM 	    attr->st_gid);
2947917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
2957917SReza.Sabdar@Sun.COM 	    attr->st_mtime);
2967917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
2977917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
2987917SReza.Sabdar@Sun.COM 
2998540SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "xattr_hdr: %s size %d mode %06o uid %d gid %d",
3008540SReza.Sabdar@Sun.COM 	    aname, hsize, attr->st_mode & 07777, attr->st_uid, attr->st_gid);
3018540SReza.Sabdar@Sun.COM 
3027917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
3037917SReza.Sabdar@Sun.COM 
3047917SReza.Sabdar@Sun.COM 	xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE,
3057917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
3067917SReza.Sabdar@Sun.COM 	if (!xhdr) {
3077917SReza.Sabdar@Sun.COM 		free(section_name);
3087917SReza.Sabdar@Sun.COM 		return (0);
3097917SReza.Sabdar@Sun.COM 	}
3107917SReza.Sabdar@Sun.COM 
3117917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s",
3127917SReza.Sabdar@Sun.COM 	    XATTR_ARCH_VERS);
3137917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d",
3147917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_size) - 1, hsize);
3157917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len),
3167917SReza.Sabdar@Sun.COM 	    "%0*d", sizeof (xhdr->h_component_len) - 1, comlen);
3177917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_link_component_len,
3187917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_link_component_len), "%0*d",
3197917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_link_component_len) - 1, 0);
3207917SReza.Sabdar@Sun.COM 
3217917SReza.Sabdar@Sun.COM 	xbuf = (struct xattr_buf *)(((caddr_t)xhdr) +
3227917SReza.Sabdar@Sun.COM 	    sizeof (struct xattr_hdr));
3237917SReza.Sabdar@Sun.COM 	(void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d",
3247917SReza.Sabdar@Sun.COM 	    sizeof (xbuf->h_namesz) - 1, namesz);
3257917SReza.Sabdar@Sun.COM 
3267917SReza.Sabdar@Sun.COM 	/* No support for links in extended attributes */
3277917SReza.Sabdar@Sun.COM 	xbuf->h_typeflag = LF_NORMAL;
3287917SReza.Sabdar@Sun.COM 
3297917SReza.Sabdar@Sun.COM 	(void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE);
3307917SReza.Sabdar@Sun.COM 	(void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname,
3317917SReza.Sabdar@Sun.COM 	    TLM_NAME_SIZE);
3327917SReza.Sabdar@Sun.COM 
3337917SReza.Sabdar@Sun.COM 	free(section_name);
3347917SReza.Sabdar@Sun.COM 	return (0);
3357917SReza.Sabdar@Sun.COM }
3367917SReza.Sabdar@Sun.COM 
3377917SReza.Sabdar@Sun.COM 
3387917SReza.Sabdar@Sun.COM /*
3397917SReza.Sabdar@Sun.COM  * output_file_header
3407917SReza.Sabdar@Sun.COM  *
3417917SReza.Sabdar@Sun.COM  * output the TAR header record
3427917SReza.Sabdar@Sun.COM  */
3437917SReza.Sabdar@Sun.COM static int
3447917SReza.Sabdar@Sun.COM output_file_header(char *name, char *link,
3457917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
3467917SReza.Sabdar@Sun.COM {
3477917SReza.Sabdar@Sun.COM 	static	longlong_t file_count = 0;
3487917SReza.Sabdar@Sun.COM 	struct stat64 *attr = &tlm_acls->acl_attr;
3497917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
3507917SReza.Sabdar@Sun.COM 	long	actual_size;
3517917SReza.Sabdar@Sun.COM 	boolean_t long_name = FALSE;
3527917SReza.Sabdar@Sun.COM 	boolean_t long_link = FALSE;
3537917SReza.Sabdar@Sun.COM 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
3547917SReza.Sabdar@Sun.COM 	int	nmlen, lnklen;
3558540SReza.Sabdar@Sun.COM 	uid_t uid;
3568540SReza.Sabdar@Sun.COM 	gid_t gid;
3578540SReza.Sabdar@Sun.COM 	char *uname = "";
3588540SReza.Sabdar@Sun.COM 	char *gname = "";
3598540SReza.Sabdar@Sun.COM 	struct passwd *pwd;
3608540SReza.Sabdar@Sun.COM 	struct group *grp;
3617917SReza.Sabdar@Sun.COM 
3627917SReza.Sabdar@Sun.COM 	if (section_name == NULL)
3637917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
3647917SReza.Sabdar@Sun.COM 
3657917SReza.Sabdar@Sun.COM 	/*
3667917SReza.Sabdar@Sun.COM 	 * if the file has to go out in sections,
3677917SReza.Sabdar@Sun.COM 	 * we must mung the name.
3687917SReza.Sabdar@Sun.COM 	 */
3697917SReza.Sabdar@Sun.COM 	if (section == 0) {
3707917SReza.Sabdar@Sun.COM 		(void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
3717917SReza.Sabdar@Sun.COM 	} else {
3727917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name,
3737917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME, "%s.%03d", name, section);
3747917SReza.Sabdar@Sun.COM 	}
3757917SReza.Sabdar@Sun.COM 
3768540SReza.Sabdar@Sun.COM 	if ((pwd = getpwuid(attr->st_uid)) != NULL)
3778540SReza.Sabdar@Sun.COM 		uname = pwd->pw_name;
3788540SReza.Sabdar@Sun.COM 	if ((grp = getgrgid(attr->st_gid)) != NULL)
3798540SReza.Sabdar@Sun.COM 		gname = grp->gr_name;
3808540SReza.Sabdar@Sun.COM 
3818540SReza.Sabdar@Sun.COM 	if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR)
3828540SReza.Sabdar@Sun.COM 		uid = UID_NOBODY;
3838540SReza.Sabdar@Sun.COM 	if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR)
3848540SReza.Sabdar@Sun.COM 		gid = GID_NOBODY;
3858540SReza.Sabdar@Sun.COM 
3867917SReza.Sabdar@Sun.COM 	nmlen = strlen(section_name);
3877917SReza.Sabdar@Sun.COM 	if (nmlen >= NAMSIZ) {
3887917SReza.Sabdar@Sun.COM 		/*
3897917SReza.Sabdar@Sun.COM 		 * file name is too big, it must go out
3907917SReza.Sabdar@Sun.COM 		 * in its own data file
3917917SReza.Sabdar@Sun.COM 		 */
3927917SReza.Sabdar@Sun.COM 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
3937917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
3947917SReza.Sabdar@Sun.COM 		if (!tar_hdr) {
3957917SReza.Sabdar@Sun.COM 			free(section_name);
3967917SReza.Sabdar@Sun.COM 			return (0);
3977917SReza.Sabdar@Sun.COM 		}
3987917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_name,
3997917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4007917SReza.Sabdar@Sun.COM 		    "%s%08qd.fil",
4017917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4027917SReza.Sabdar@Sun.COM 		    file_count++);
4037917SReza.Sabdar@Sun.COM 
4047917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LONGNAME;
4057917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
4067917SReza.Sabdar@Sun.COM 		    "%011o ", nmlen);
4077917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
4087917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_mode & 07777);
4097917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
4108540SReza.Sabdar@Sun.COM 		    "%06o ", uid);
4117917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
4128540SReza.Sabdar@Sun.COM 		    "%06o ", gid);
4138540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
4148540SReza.Sabdar@Sun.COM 		    "%.31s", uname);
4158540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
4168540SReza.Sabdar@Sun.COM 		    "%.31s", gname);
4177917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
4187917SReza.Sabdar@Sun.COM 		    "%011o ", attr->st_mtime);
4197917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4207917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_magic));
4217917SReza.Sabdar@Sun.COM 
4227917SReza.Sabdar@Sun.COM 		tlm_build_header_checksum(tar_hdr);
4237917SReza.Sabdar@Sun.COM 
4247917SReza.Sabdar@Sun.COM 		(void) output_mem(local_commands,
4257917SReza.Sabdar@Sun.COM 		    (void *)section_name, nmlen);
4267917SReza.Sabdar@Sun.COM 		long_name = TRUE;
4277917SReza.Sabdar@Sun.COM 	}
4287917SReza.Sabdar@Sun.COM 
4297917SReza.Sabdar@Sun.COM 	lnklen = strlen(link);
4307917SReza.Sabdar@Sun.COM 	if (lnklen >= NAMSIZ) {
4317917SReza.Sabdar@Sun.COM 		/*
4327917SReza.Sabdar@Sun.COM 		 * link name is too big, it must go out
4337917SReza.Sabdar@Sun.COM 		 * in its own data file
4347917SReza.Sabdar@Sun.COM 		 */
4357917SReza.Sabdar@Sun.COM 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4367917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
4377917SReza.Sabdar@Sun.COM 		if (!tar_hdr) {
4387917SReza.Sabdar@Sun.COM 			free(section_name);
4397917SReza.Sabdar@Sun.COM 			return (0);
4407917SReza.Sabdar@Sun.COM 		}
4417917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_linkname,
4427917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4437917SReza.Sabdar@Sun.COM 		    "%s%08qd.slk",
4447917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4457917SReza.Sabdar@Sun.COM 		    file_count++);
4467917SReza.Sabdar@Sun.COM 
4477917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LONGLINK;
4487917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
4497917SReza.Sabdar@Sun.COM 		    "%011o ", lnklen);
4507917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
4517917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_mode & 07777);
4527917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
4538540SReza.Sabdar@Sun.COM 		    "%06o ", uid);
4547917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
4558540SReza.Sabdar@Sun.COM 		    "%06o ", gid);
4568540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
4578540SReza.Sabdar@Sun.COM 		    "%.31s", uname);
4588540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
4598540SReza.Sabdar@Sun.COM 		    "%.31s", gname);
4607917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
4617917SReza.Sabdar@Sun.COM 		    "%011o ", attr->st_mtime);
4627917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4637917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_magic));
4647917SReza.Sabdar@Sun.COM 
4657917SReza.Sabdar@Sun.COM 		tlm_build_header_checksum(tar_hdr);
4667917SReza.Sabdar@Sun.COM 
4677917SReza.Sabdar@Sun.COM 		(void) output_mem(local_commands, (void *)link,
4687917SReza.Sabdar@Sun.COM 		    lnklen);
4697917SReza.Sabdar@Sun.COM 		long_link = TRUE;
4707917SReza.Sabdar@Sun.COM 	}
4717917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4727917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
4737917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
4747917SReza.Sabdar@Sun.COM 		free(section_name);
4757917SReza.Sabdar@Sun.COM 		return (0);
4767917SReza.Sabdar@Sun.COM 	}
4777917SReza.Sabdar@Sun.COM 	if (long_name) {
4787917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_name,
4797917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4807917SReza.Sabdar@Sun.COM 		    "%s%08qd.fil",
4817917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4827917SReza.Sabdar@Sun.COM 		    file_count++);
4837917SReza.Sabdar@Sun.COM 	} else {
4847917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
4857917SReza.Sabdar@Sun.COM 	}
4867917SReza.Sabdar@Sun.COM 
4877917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "long_link: %s [%s]", long_link ? "TRUE" : "FALSE",
4887917SReza.Sabdar@Sun.COM 	    link);
4897917SReza.Sabdar@Sun.COM 
4907917SReza.Sabdar@Sun.COM 	if (long_link) {
4917917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_linkname,
4927917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4937917SReza.Sabdar@Sun.COM 		    "%s%08qd.slk",
4947917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4957917SReza.Sabdar@Sun.COM 		    file_count++);
4967917SReza.Sabdar@Sun.COM 	} else {
4977917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
4987917SReza.Sabdar@Sun.COM 	}
4997917SReza.Sabdar@Sun.COM 	if (S_ISDIR(attr->st_mode)) {
5007917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_DIR;
5017917SReza.Sabdar@Sun.COM 	} else if (S_ISFIFO(attr->st_mode)) {
5027917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_FIFO;
5037917SReza.Sabdar@Sun.COM 	} else if (attr->st_nlink > 1) {
5047917SReza.Sabdar@Sun.COM 		/* mark file with hardlink LF_LINK */
5057917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LINK;
5067917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_shared.th_hlink_ino,
5077917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_shared.th_hlink_ino),
5088193SReza.Sabdar@Sun.COM 		    "%011llo ", attr->st_ino);
5097917SReza.Sabdar@Sun.COM 	} else {
5107917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL : LF_SYMLINK;
5117917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "linkflag: '%c'", tar_hdr->th_linkflag);
5127917SReza.Sabdar@Sun.COM 	}
5137917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
5147917SReza.Sabdar@Sun.COM 	    (long)attr->st_size);
5157917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
5167917SReza.Sabdar@Sun.COM 	    attr->st_mode & 07777);
5177917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
5188540SReza.Sabdar@Sun.COM 	    uid);
5197917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
5208540SReza.Sabdar@Sun.COM 	    gid);
5218540SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
5228540SReza.Sabdar@Sun.COM 	    uname);
5238540SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
5248540SReza.Sabdar@Sun.COM 	    gname);
5257917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
5267917SReza.Sabdar@Sun.COM 	    attr->st_mtime);
5277917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
5287917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
5297917SReza.Sabdar@Sun.COM 
5307917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
5317917SReza.Sabdar@Sun.COM 	if (long_name || long_link) {
5327917SReza.Sabdar@Sun.COM 		if (file_count > 99999990) {
5337917SReza.Sabdar@Sun.COM 			file_count = 0;
5347917SReza.Sabdar@Sun.COM 		}
5357917SReza.Sabdar@Sun.COM 	}
5367917SReza.Sabdar@Sun.COM 	free(section_name);
5377917SReza.Sabdar@Sun.COM 	return (0);
5387917SReza.Sabdar@Sun.COM }
5397917SReza.Sabdar@Sun.COM 
5407917SReza.Sabdar@Sun.COM 
5417917SReza.Sabdar@Sun.COM /*
5427917SReza.Sabdar@Sun.COM  * tlm_readlink
5437917SReza.Sabdar@Sun.COM  *
5447917SReza.Sabdar@Sun.COM  * Read where the softlink points to.  Read the link in the checkpointed
5457917SReza.Sabdar@Sun.COM  * path if the backup is being done on a checkpointed file system.
5467917SReza.Sabdar@Sun.COM  */
5477917SReza.Sabdar@Sun.COM static int
5487917SReza.Sabdar@Sun.COM tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
5497917SReza.Sabdar@Sun.COM {
5507917SReza.Sabdar@Sun.COM 	int len;
5517917SReza.Sabdar@Sun.COM 
5527917SReza.Sabdar@Sun.COM 	if ((len = readlink(snap, buf, bufsize)) >= 0) {
5537917SReza.Sabdar@Sun.COM 		/*
5547917SReza.Sabdar@Sun.COM 		 * realink(2) doesn't null terminate the link name.  We must
5557917SReza.Sabdar@Sun.COM 		 * do it here.
5567917SReza.Sabdar@Sun.COM 		 */
5577917SReza.Sabdar@Sun.COM 		buf[len] = '\0';
5587917SReza.Sabdar@Sun.COM 	} else {
5597917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Error %d reading softlink of [%s]",
5607917SReza.Sabdar@Sun.COM 		    errno, nm);
5617917SReza.Sabdar@Sun.COM 		buf[0] = '\0';
5627917SReza.Sabdar@Sun.COM 
5637917SReza.Sabdar@Sun.COM 		/* Backup the link if the destination missing */
5647917SReza.Sabdar@Sun.COM 		if (errno == ENOENT)
5657917SReza.Sabdar@Sun.COM 			return (0);
5667917SReza.Sabdar@Sun.COM 
5677917SReza.Sabdar@Sun.COM 	}
5687917SReza.Sabdar@Sun.COM 
5697917SReza.Sabdar@Sun.COM 	return (len);
5707917SReza.Sabdar@Sun.COM }
5717917SReza.Sabdar@Sun.COM 
5728540SReza.Sabdar@Sun.COM /*
5738540SReza.Sabdar@Sun.COM  * Read the system attribute file in a single buffer to write
5748540SReza.Sabdar@Sun.COM  * it as a single write. A partial write to system attribute would
5758540SReza.Sabdar@Sun.COM  * cause an EINVAL on write.
5768540SReza.Sabdar@Sun.COM  */
5778540SReza.Sabdar@Sun.COM static char *
5788540SReza.Sabdar@Sun.COM get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
5798540SReza.Sabdar@Sun.COM     tlm_cmd_t *lc)
5808540SReza.Sabdar@Sun.COM {
5818540SReza.Sabdar@Sun.COM 	int len;
5828540SReza.Sabdar@Sun.COM 	long write_size;
5838540SReza.Sabdar@Sun.COM 
5848540SReza.Sabdar@Sun.COM 	if (rec_size > buf_size)
5858540SReza.Sabdar@Sun.COM 		return (rec);
5868540SReza.Sabdar@Sun.COM 
5878540SReza.Sabdar@Sun.COM 	len = rec_size;
5888540SReza.Sabdar@Sun.COM 	(void) memcpy(rec, buf, len);
5898540SReza.Sabdar@Sun.COM 	buf += len;
5908540SReza.Sabdar@Sun.COM 	while (rec_size < buf_size) {
5918540SReza.Sabdar@Sun.COM 		rec = get_write_buffer(buf_size - rec_size,
5928540SReza.Sabdar@Sun.COM 		    &write_size, FALSE, lc);
5938540SReza.Sabdar@Sun.COM 		if (!rec)
5948540SReza.Sabdar@Sun.COM 			return (0);
5958540SReza.Sabdar@Sun.COM 
5968540SReza.Sabdar@Sun.COM 		len = min(buf_size - rec_size, write_size);
5978540SReza.Sabdar@Sun.COM 		(void) memcpy(rec, buf, len);
5988540SReza.Sabdar@Sun.COM 		rec_size += len;
5998540SReza.Sabdar@Sun.COM 		buf += len;
6008540SReza.Sabdar@Sun.COM 	}
6018540SReza.Sabdar@Sun.COM 	return (rec);
6028540SReza.Sabdar@Sun.COM }
6038540SReza.Sabdar@Sun.COM 
6047917SReza.Sabdar@Sun.COM 
6057917SReza.Sabdar@Sun.COM /*
6067917SReza.Sabdar@Sun.COM  * tlm_output_xattr
6077917SReza.Sabdar@Sun.COM  *
6087917SReza.Sabdar@Sun.COM  * Put this file into the output buffers.
6097917SReza.Sabdar@Sun.COM  */
6107917SReza.Sabdar@Sun.COM /*ARGSUSED*/
6117917SReza.Sabdar@Sun.COM longlong_t
6127917SReza.Sabdar@Sun.COM tlm_output_xattr(char  *dir, char *name, char *chkdir,
6137917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
6147917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
6157917SReza.Sabdar@Sun.COM {
6167917SReza.Sabdar@Sun.COM 	char	*fullname;		/* directory + name */
6177917SReza.Sabdar@Sun.COM 	char	*snapname;		/* snapshot name */
6187917SReza.Sabdar@Sun.COM 	int	section;		/* section of a huge file */
6197917SReza.Sabdar@Sun.COM 	int	fd;
6209323SReza.Sabdar@Sun.COM 	int	afd = 0;
6217917SReza.Sabdar@Sun.COM 	longlong_t seek_spot = 0;	/* location in the file */
6227917SReza.Sabdar@Sun.COM 					/* for Multi Volume record */
6237917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
6247917SReza.Sabdar@Sun.COM 	DIR *dp;
6257917SReza.Sabdar@Sun.COM 	struct dirent *dtp;
6267917SReza.Sabdar@Sun.COM 	char *attrname;
6277917SReza.Sabdar@Sun.COM 	char *fnamep;
6287917SReza.Sabdar@Sun.COM 	int rv = 0;
6297917SReza.Sabdar@Sun.COM 
630*9659SReza.Sabdar@Sun.COM 	if (S_ISLNK(tlm_acls->acl_attr.st_mode) ||
631*9659SReza.Sabdar@Sun.COM 	    S_ISFIFO(tlm_acls->acl_attr.st_mode)) {
6327917SReza.Sabdar@Sun.COM 		return (TLM_NO_SOURCE_FILE);
633*9659SReza.Sabdar@Sun.COM 	}
6347917SReza.Sabdar@Sun.COM 
6357917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
6367917SReza.Sabdar@Sun.COM 	if (fullname == NULL) {
6377917SReza.Sabdar@Sun.COM 		free(fullname);
6387917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
6397917SReza.Sabdar@Sun.COM 	}
6407917SReza.Sabdar@Sun.COM 
6417917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name)) {
6427917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6437917SReza.Sabdar@Sun.COM 		free(fullname);
6447917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
6457917SReza.Sabdar@Sun.COM 	}
6467917SReza.Sabdar@Sun.COM 
6478540SReza.Sabdar@Sun.COM 	if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
6488540SReza.Sabdar@Sun.COM 	    sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
6497917SReza.Sabdar@Sun.COM 		free(fullname);
6507917SReza.Sabdar@Sun.COM 		return (0);
6517917SReza.Sabdar@Sun.COM 	}
6527917SReza.Sabdar@Sun.COM 
6537917SReza.Sabdar@Sun.COM 	attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
6547917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
6557917SReza.Sabdar@Sun.COM 	if (attrname == NULL || snapname == NULL) {
6567917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
6577917SReza.Sabdar@Sun.COM 		goto err_out;
6587917SReza.Sabdar@Sun.COM 	}
6597917SReza.Sabdar@Sun.COM 
6607917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(snapname, chkdir, name)) {
6617917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6627917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
6637917SReza.Sabdar@Sun.COM 		goto err_out;
6647917SReza.Sabdar@Sun.COM 	}
6657917SReza.Sabdar@Sun.COM 
6667917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
6677917SReza.Sabdar@Sun.COM 
6687917SReza.Sabdar@Sun.COM 	/*
6697917SReza.Sabdar@Sun.COM 	 * Open the file for reading.
6707917SReza.Sabdar@Sun.COM 	 */
6718540SReza.Sabdar@Sun.COM 	fd = attropen(fnamep, ".", O_RDONLY);
6727917SReza.Sabdar@Sun.COM 	if (fd == -1) {
6738540SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s][%s]",
6748540SReza.Sabdar@Sun.COM 		    fullname, fnamep);
6757917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
6767917SReza.Sabdar@Sun.COM 		goto err_out;
6777917SReza.Sabdar@Sun.COM 	}
6787917SReza.Sabdar@Sun.COM 
6797917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
6807917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
6817917SReza.Sabdar@Sun.COM 
6827917SReza.Sabdar@Sun.COM 	section = 0;
6837917SReza.Sabdar@Sun.COM 
6847917SReza.Sabdar@Sun.COM 	dp = (DIR *)fdopendir(fd);
6857917SReza.Sabdar@Sun.COM 	if (dp == NULL) {
6867917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
6877917SReza.Sabdar@Sun.COM 		(void) close(fd);
6887917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
6897917SReza.Sabdar@Sun.COM 		goto err_out;
6907917SReza.Sabdar@Sun.COM 	}
6917917SReza.Sabdar@Sun.COM 
6927917SReza.Sabdar@Sun.COM 	while ((dtp = readdir(dp)) != NULL) {
6937917SReza.Sabdar@Sun.COM 		int section_size;
6947917SReza.Sabdar@Sun.COM 
6957917SReza.Sabdar@Sun.COM 		if (*dtp->d_name == '.')
6967917SReza.Sabdar@Sun.COM 			continue;
6977917SReza.Sabdar@Sun.COM 
6988540SReza.Sabdar@Sun.COM 		if (sysattr_rdonly(dtp->d_name))
6998540SReza.Sabdar@Sun.COM 			continue;
7008540SReza.Sabdar@Sun.COM 
7019323SReza.Sabdar@Sun.COM 		afd = attropen(fnamep, dtp->d_name, O_RDONLY);
7029323SReza.Sabdar@Sun.COM 		if (afd == -1) {
7037917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
7048540SReza.Sabdar@Sun.COM 			    "problem(%d) opening xattr file [%s][%s]", errno,
7058540SReza.Sabdar@Sun.COM 			    fullname, fnamep);
7067917SReza.Sabdar@Sun.COM 			goto tear_down;
7077917SReza.Sabdar@Sun.COM 		}
7087917SReza.Sabdar@Sun.COM 
7099323SReza.Sabdar@Sun.COM 		(void) output_xattr_header(fullname, dtp->d_name, afd,
7107917SReza.Sabdar@Sun.COM 		    tlm_acls, section, local_commands);
7117917SReza.Sabdar@Sun.COM 		(void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
7127917SReza.Sabdar@Sun.COM 		    dtp->d_name);
7137917SReza.Sabdar@Sun.COM 		(void) output_file_header(attrname, "", tlm_acls, 0,
7147917SReza.Sabdar@Sun.COM 		    local_commands);
7157917SReza.Sabdar@Sun.COM 
7167917SReza.Sabdar@Sun.COM 		section_size = (long)llmin(tlm_acls->acl_attr.st_size,
7177917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
7187917SReza.Sabdar@Sun.COM 
7197917SReza.Sabdar@Sun.COM 		/* We only can read upto one section extended attribute */
7207917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
7217917SReza.Sabdar@Sun.COM 			char	*buf;
7227917SReza.Sabdar@Sun.COM 			long	actual_size;
7237917SReza.Sabdar@Sun.COM 			int	read_size;
7248540SReza.Sabdar@Sun.COM 			int sysattr_read = 0;
7258540SReza.Sabdar@Sun.COM 			char *rec;
7268540SReza.Sabdar@Sun.COM 			int size;
7277917SReza.Sabdar@Sun.COM 
7287917SReza.Sabdar@Sun.COM 			/*
7297917SReza.Sabdar@Sun.COM 			 * check for Abort commands
7307917SReza.Sabdar@Sun.COM 			 */
7317917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7327917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
7337917SReza.Sabdar@Sun.COM 				goto tear_down;
7347917SReza.Sabdar@Sun.COM 			}
7357917SReza.Sabdar@Sun.COM 
7367917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
7377917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
7387917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
7397917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
7407917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
7417917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
7427917SReza.Sabdar@Sun.COM 
7437917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
7447917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
7457917SReza.Sabdar@Sun.COM 			if (!buf)
7467917SReza.Sabdar@Sun.COM 				goto tear_down;
7477917SReza.Sabdar@Sun.COM 
7488540SReza.Sabdar@Sun.COM 			if ((actual_size < section_size) &&
7498540SReza.Sabdar@Sun.COM 			    sysattr_rw(dtp->d_name)) {
7508540SReza.Sabdar@Sun.COM 				rec = buf;
7518540SReza.Sabdar@Sun.COM 				buf = ndmp_malloc(section_size);
7528540SReza.Sabdar@Sun.COM 				if (!buf)
7538540SReza.Sabdar@Sun.COM 					goto tear_down;
7548540SReza.Sabdar@Sun.COM 				size = actual_size;
7558540SReza.Sabdar@Sun.COM 				actual_size = section_size;
7568540SReza.Sabdar@Sun.COM 				sysattr_read = 1;
7578540SReza.Sabdar@Sun.COM 			}
7588540SReza.Sabdar@Sun.COM 
7597917SReza.Sabdar@Sun.COM 			/*
7607917SReza.Sabdar@Sun.COM 			 * check for Abort commands
7617917SReza.Sabdar@Sun.COM 			 */
7627917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7637917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
7647917SReza.Sabdar@Sun.COM 				goto tear_down;
7657917SReza.Sabdar@Sun.COM 			}
7667917SReza.Sabdar@Sun.COM 
7677917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
7689323SReza.Sabdar@Sun.COM 			if ((actual_size = read(afd, buf, read_size)) < 0)
7698540SReza.Sabdar@Sun.COM 				break;
7708540SReza.Sabdar@Sun.COM 
7718540SReza.Sabdar@Sun.COM 			if (sysattr_read) {
7728540SReza.Sabdar@Sun.COM 				if (get_write_one_buf(buf, rec, read_size,
7738540SReza.Sabdar@Sun.COM 				    size, local_commands) == 0) {
7748540SReza.Sabdar@Sun.COM 					free(buf);
7758540SReza.Sabdar@Sun.COM 					goto tear_down;
7768540SReza.Sabdar@Sun.COM 				}
7778540SReza.Sabdar@Sun.COM 				free(buf);
7788540SReza.Sabdar@Sun.COM 			}
7798540SReza.Sabdar@Sun.COM 
7808540SReza.Sabdar@Sun.COM 
7817917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
7827917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
7837917SReza.Sabdar@Sun.COM 
7847917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
7857917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
7867917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
7877917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
7887917SReza.Sabdar@Sun.COM 				goto tear_down;
7897917SReza.Sabdar@Sun.COM 			}
7907917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
7917917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
7927917SReza.Sabdar@Sun.COM 		}
7939323SReza.Sabdar@Sun.COM 		(void) close(afd);
7949323SReza.Sabdar@Sun.COM 		afd = -1;
7957917SReza.Sabdar@Sun.COM 	}
7967917SReza.Sabdar@Sun.COM 
7977917SReza.Sabdar@Sun.COM tear_down:
7987917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
7997917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
8007917SReza.Sabdar@Sun.COM 
8019323SReza.Sabdar@Sun.COM 	if (afd > 0)
8029323SReza.Sabdar@Sun.COM 		(void) close(afd);
8039323SReza.Sabdar@Sun.COM 
8049323SReza.Sabdar@Sun.COM 	/* closedir closes fd too */
8057917SReza.Sabdar@Sun.COM 	(void) closedir(dp);
8067917SReza.Sabdar@Sun.COM 
8077917SReza.Sabdar@Sun.COM err_out:
8087917SReza.Sabdar@Sun.COM 	free(fullname);
8097917SReza.Sabdar@Sun.COM 	free(attrname);
8107917SReza.Sabdar@Sun.COM 	free(snapname);
8117917SReza.Sabdar@Sun.COM 	return (rv);
8127917SReza.Sabdar@Sun.COM }
8137917SReza.Sabdar@Sun.COM 
8147917SReza.Sabdar@Sun.COM 
8157917SReza.Sabdar@Sun.COM /*
8167917SReza.Sabdar@Sun.COM  * tlm_output_file
8177917SReza.Sabdar@Sun.COM  *
8187917SReza.Sabdar@Sun.COM  * Put this file into the output buffers.
8197917SReza.Sabdar@Sun.COM  */
8207917SReza.Sabdar@Sun.COM longlong_t
8217917SReza.Sabdar@Sun.COM tlm_output_file(char *dir, char *name, char *chkdir,
8227917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
8237917SReza.Sabdar@Sun.COM     tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
8247917SReza.Sabdar@Sun.COM {
8257917SReza.Sabdar@Sun.COM 	char	*fullname;		/* directory + name */
8267917SReza.Sabdar@Sun.COM 	char	*snapname;		/* snapshot name */
8277917SReza.Sabdar@Sun.COM 	char	*linkname;		/* where this file points */
8287917SReza.Sabdar@Sun.COM 	int	section = 0;		/* section of a huge file */
8297917SReza.Sabdar@Sun.COM 	int	fd;
8307917SReza.Sabdar@Sun.COM 	longlong_t real_size;		/* the origional file size */
8317917SReza.Sabdar@Sun.COM 	longlong_t file_size;		/* real size of this file */
8327917SReza.Sabdar@Sun.COM 	longlong_t seek_spot = 0;	/* location in the file */
8337917SReza.Sabdar@Sun.COM 					/* for Multi Volume record */
8347917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
8357917SReza.Sabdar@Sun.COM 	char *fnamep;
8367917SReza.Sabdar@Sun.COM 
8377917SReza.Sabdar@Sun.COM 	/* Indicate whether a file with the same inode has been backed up. */
8387917SReza.Sabdar@Sun.COM 	int hardlink_done = 0;
8397917SReza.Sabdar@Sun.COM 
8407917SReza.Sabdar@Sun.COM 	/*
8417917SReza.Sabdar@Sun.COM 	 * If a file with the same inode has been backed up, hardlink_pos holds
8427917SReza.Sabdar@Sun.COM 	 * the tape offset of the data record.
8437917SReza.Sabdar@Sun.COM 	 */
8447917SReza.Sabdar@Sun.COM 	u_longlong_t hardlink_pos = 0;
8457917SReza.Sabdar@Sun.COM 
8467917SReza.Sabdar@Sun.COM 	if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
8477917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name);
8487917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
8497917SReza.Sabdar@Sun.COM 	}
8507917SReza.Sabdar@Sun.COM 
8517917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
8527917SReza.Sabdar@Sun.COM 	linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
8537917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
8547917SReza.Sabdar@Sun.COM 	if (fullname == NULL || linkname == NULL || snapname == NULL) {
8557917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
8567917SReza.Sabdar@Sun.COM 		goto err_out;
8577917SReza.Sabdar@Sun.COM 	}
8587917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name) ||
8597917SReza.Sabdar@Sun.COM 	    !tlm_cat_path(snapname, chkdir, name)) {
8607917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
8617917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
8627917SReza.Sabdar@Sun.COM 		goto err_out;
8637917SReza.Sabdar@Sun.COM 	}
8647917SReza.Sabdar@Sun.COM 
8657917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
8667917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
8677917SReza.Sabdar@Sun.COM 
868*9659SReza.Sabdar@Sun.COM 	if (S_ISLNK(tlm_acls->acl_attr.st_mode) ||
869*9659SReza.Sabdar@Sun.COM 	    S_ISFIFO(tlm_acls->acl_attr.st_mode)) {
870*9659SReza.Sabdar@Sun.COM 		if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
871*9659SReza.Sabdar@Sun.COM 			file_size = tlm_readlink(fullname, snapname, linkname,
872*9659SReza.Sabdar@Sun.COM 			    TLM_MAX_PATH_NAME-1);
873*9659SReza.Sabdar@Sun.COM 			if (file_size < 0) {
874*9659SReza.Sabdar@Sun.COM 				real_size = -ENOENT;
875*9659SReza.Sabdar@Sun.COM 				goto err_out;
876*9659SReza.Sabdar@Sun.COM 			}
8777917SReza.Sabdar@Sun.COM 		}
8787917SReza.Sabdar@Sun.COM 
8797917SReza.Sabdar@Sun.COM 		/*
8807917SReza.Sabdar@Sun.COM 		 * Since soft links can not be read(2), we should only
8817917SReza.Sabdar@Sun.COM 		 * backup the file header.
8827917SReza.Sabdar@Sun.COM 		 */
8837917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
8847917SReza.Sabdar@Sun.COM 		    linkname,
8857917SReza.Sabdar@Sun.COM 		    tlm_acls,
8867917SReza.Sabdar@Sun.COM 		    section,
8877917SReza.Sabdar@Sun.COM 		    local_commands);
8887917SReza.Sabdar@Sun.COM 
8897917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
8907917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
8917917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhpath_name(job_stats, fullname,
8927917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
8937917SReza.Sabdar@Sun.COM 
8947917SReza.Sabdar@Sun.COM 		free(fullname);
8957917SReza.Sabdar@Sun.COM 		free(linkname);
8967917SReza.Sabdar@Sun.COM 		free(snapname);
8977917SReza.Sabdar@Sun.COM 		return (0);
8987917SReza.Sabdar@Sun.COM 	}
8997917SReza.Sabdar@Sun.COM 
9007917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
9017917SReza.Sabdar@Sun.COM 
9027917SReza.Sabdar@Sun.COM 	/*
9037917SReza.Sabdar@Sun.COM 	 * For hardlink, only read the data if no other link
9047917SReza.Sabdar@Sun.COM 	 * belonging to the same inode has been backed up.
9057917SReza.Sabdar@Sun.COM 	 */
9067917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1) {
9077917SReza.Sabdar@Sun.COM 		hardlink_done = !hardlink_q_get(hardlink_q,
9087917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
9097917SReza.Sabdar@Sun.COM 	}
9107917SReza.Sabdar@Sun.COM 
9117917SReza.Sabdar@Sun.COM 	if (!hardlink_done) {
9127917SReza.Sabdar@Sun.COM 		/*
9137917SReza.Sabdar@Sun.COM 		 * Open the file for reading.
9147917SReza.Sabdar@Sun.COM 		 */
9157917SReza.Sabdar@Sun.COM 		fd = open(fnamep, O_RDONLY);
9167917SReza.Sabdar@Sun.COM 		if (fd == -1) {
9177917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
9188540SReza.Sabdar@Sun.COM 			    "BACKUP> Can't open file [%s][%s] err(%d)",
9198540SReza.Sabdar@Sun.COM 			    fullname, fnamep, errno);
9207917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SOURCE_FILE;
9217917SReza.Sabdar@Sun.COM 			goto err_out;
9227917SReza.Sabdar@Sun.COM 		}
9237917SReza.Sabdar@Sun.COM 	} else {
9248193SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
9257917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, hardlink_pos);
9267917SReza.Sabdar@Sun.COM 
9277917SReza.Sabdar@Sun.COM 		fd = -1;
9287917SReza.Sabdar@Sun.COM 	}
9297917SReza.Sabdar@Sun.COM 
9307917SReza.Sabdar@Sun.COM 	linkname[0] = 0;
9317917SReza.Sabdar@Sun.COM 
9327917SReza.Sabdar@Sun.COM 	real_size = tlm_acls->acl_attr.st_size;
9337917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
9347917SReza.Sabdar@Sun.COM 	    local_commands);
9357917SReza.Sabdar@Sun.COM 
9367917SReza.Sabdar@Sun.COM 	/*
9377917SReza.Sabdar@Sun.COM 	 * section = 0: file is small enough for TAR
9387917SReza.Sabdar@Sun.COM 	 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
9397917SReza.Sabdar@Sun.COM 	 * 		and the file name gets munged
9407917SReza.Sabdar@Sun.COM 	 */
9417917SReza.Sabdar@Sun.COM 	file_size = real_size;
9427917SReza.Sabdar@Sun.COM 	if (file_size > TLM_MAX_TAR_IMAGE) {
9437917SReza.Sabdar@Sun.COM 		if (output_humongus_header(fullname, file_size,
9447917SReza.Sabdar@Sun.COM 		    local_commands) < 0) {
9457917SReza.Sabdar@Sun.COM 			(void) close(fd);
9467917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SCRATCH_SPACE;
9477917SReza.Sabdar@Sun.COM 			goto err_out;
9487917SReza.Sabdar@Sun.COM 		}
9497917SReza.Sabdar@Sun.COM 		section = 1;
9507917SReza.Sabdar@Sun.COM 	} else {
9517917SReza.Sabdar@Sun.COM 		section = 0;
9527917SReza.Sabdar@Sun.COM 	}
9537917SReza.Sabdar@Sun.COM 
9547917SReza.Sabdar@Sun.COM 	/*
9557917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode
9567917SReza.Sabdar@Sun.COM 	 * has been backed up, only backup an empty record.
9577917SReza.Sabdar@Sun.COM 	 */
9587917SReza.Sabdar@Sun.COM 	if (hardlink_done)
9597917SReza.Sabdar@Sun.COM 		file_size = 0;
9607917SReza.Sabdar@Sun.COM 
9617917SReza.Sabdar@Sun.COM 	/*
9627917SReza.Sabdar@Sun.COM 	 * work
9637917SReza.Sabdar@Sun.COM 	 */
9647917SReza.Sabdar@Sun.COM 	if (file_size == 0) {
9657917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
9667917SReza.Sabdar@Sun.COM 		    linkname,
9677917SReza.Sabdar@Sun.COM 		    tlm_acls,
9687917SReza.Sabdar@Sun.COM 		    section,
9697917SReza.Sabdar@Sun.COM 		    local_commands);
9707917SReza.Sabdar@Sun.COM 		/*
9717917SReza.Sabdar@Sun.COM 		 * this can fall right through since zero size files
9727917SReza.Sabdar@Sun.COM 		 * will be skipped by the WHILE loop anyway
9737917SReza.Sabdar@Sun.COM 		 */
9747917SReza.Sabdar@Sun.COM 	}
9757917SReza.Sabdar@Sun.COM 
9767917SReza.Sabdar@Sun.COM 	while (file_size > 0) {
9777917SReza.Sabdar@Sun.COM 		int section_size = llmin(file_size,
9787917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
9797917SReza.Sabdar@Sun.COM 
9807917SReza.Sabdar@Sun.COM 		tlm_acls->acl_attr.st_size = (longlong_t)section_size;
9817917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
9827917SReza.Sabdar@Sun.COM 		    linkname,
9837917SReza.Sabdar@Sun.COM 		    tlm_acls,
9847917SReza.Sabdar@Sun.COM 		    section,
9857917SReza.Sabdar@Sun.COM 		    local_commands);
9867917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
9877917SReza.Sabdar@Sun.COM 			char	*buf;
9887917SReza.Sabdar@Sun.COM 			long	actual_size;
9897917SReza.Sabdar@Sun.COM 			int	read_size;
9907917SReza.Sabdar@Sun.COM 
9917917SReza.Sabdar@Sun.COM 			/*
9927917SReza.Sabdar@Sun.COM 			 * check for Abort commands
9937917SReza.Sabdar@Sun.COM 			 */
9947917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
9957917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
9967917SReza.Sabdar@Sun.COM 				goto tear_down;
9977917SReza.Sabdar@Sun.COM 			}
9987917SReza.Sabdar@Sun.COM 
9997917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
10007917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
10017917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
10027917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
10037917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
10047917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
10057917SReza.Sabdar@Sun.COM 
10067917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
10077917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
10087917SReza.Sabdar@Sun.COM 			if (!buf)
10097917SReza.Sabdar@Sun.COM 				goto tear_down;
10107917SReza.Sabdar@Sun.COM 
10117917SReza.Sabdar@Sun.COM 			/*
10127917SReza.Sabdar@Sun.COM 			 * check for Abort commands
10137917SReza.Sabdar@Sun.COM 			 */
10147917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
10157917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
10167917SReza.Sabdar@Sun.COM 				goto tear_down;
10177917SReza.Sabdar@Sun.COM 			}
10187917SReza.Sabdar@Sun.COM 
10197917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
10207917SReza.Sabdar@Sun.COM 			actual_size = read(fd, buf, read_size);
10217917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
10227917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
10237917SReza.Sabdar@Sun.COM 
10247917SReza.Sabdar@Sun.COM 			if (actual_size == 0)
10257917SReza.Sabdar@Sun.COM 				break;
10267917SReza.Sabdar@Sun.COM 
10277917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
10287917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
10297917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
10307917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
10317917SReza.Sabdar@Sun.COM 				goto tear_down;
10327917SReza.Sabdar@Sun.COM 			}
10337917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
10347917SReza.Sabdar@Sun.COM 			file_size -= actual_size;
10357917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
10367917SReza.Sabdar@Sun.COM 		}
10377917SReza.Sabdar@Sun.COM 		section++;
10387917SReza.Sabdar@Sun.COM 	}
10397917SReza.Sabdar@Sun.COM 
10407917SReza.Sabdar@Sun.COM 	/*
10417917SReza.Sabdar@Sun.COM 	 * If data belonging to this hardlink has been backed up, add the link
10427917SReza.Sabdar@Sun.COM 	 * to hardlink queue.
10437917SReza.Sabdar@Sun.COM 	 */
10447917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
10457917SReza.Sabdar@Sun.COM 		(void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
10467917SReza.Sabdar@Sun.COM 		    pos, NULL, 0);
10477917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10488193SReza.Sabdar@Sun.COM 		    "backed up hardlink file %s, inode = %llu, pos = %llu ",
10497917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, pos);
10507917SReza.Sabdar@Sun.COM 	}
10517917SReza.Sabdar@Sun.COM 
10527917SReza.Sabdar@Sun.COM 	/*
10537917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode has been
10548193SReza.Sabdar@Sun.COM 	 * backed up, no add_node entry should be sent for this link.
10557917SReza.Sabdar@Sun.COM 	 */
10567917SReza.Sabdar@Sun.COM 	if (hardlink_done) {
10577917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10588193SReza.Sabdar@Sun.COM 		    "backed up hardlink link %s, inode = %llu, pos = %llu ",
10597917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
10607917SReza.Sabdar@Sun.COM 	} else {
10617917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
10627917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
10637917SReza.Sabdar@Sun.COM 	}
10647917SReza.Sabdar@Sun.COM 
10657917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
10667917SReza.Sabdar@Sun.COM 	    pos);
10677917SReza.Sabdar@Sun.COM 
10687917SReza.Sabdar@Sun.COM tear_down:
10697917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
10707917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
10717917SReza.Sabdar@Sun.COM 
10727917SReza.Sabdar@Sun.COM 	(void) close(fd);
10737917SReza.Sabdar@Sun.COM 
10747917SReza.Sabdar@Sun.COM err_out:
10757917SReza.Sabdar@Sun.COM 	free(fullname);
10767917SReza.Sabdar@Sun.COM 	free(linkname);
10777917SReza.Sabdar@Sun.COM 	free(snapname);
10787917SReza.Sabdar@Sun.COM 	return (real_size);
10797917SReza.Sabdar@Sun.COM }
10807917SReza.Sabdar@Sun.COM 
10817917SReza.Sabdar@Sun.COM /*
10827917SReza.Sabdar@Sun.COM  * tar_putfile
10837917SReza.Sabdar@Sun.COM  *
10847917SReza.Sabdar@Sun.COM  * Main file backup function for tar
10857917SReza.Sabdar@Sun.COM  */
10867917SReza.Sabdar@Sun.COM int
10877917SReza.Sabdar@Sun.COM tar_putfile(char *dir, char *name, char *chkdir,
10887917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
10897917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
10907917SReza.Sabdar@Sun.COM     struct hardlink_q *hardlink_q)
10917917SReza.Sabdar@Sun.COM {
10927917SReza.Sabdar@Sun.COM 	int rv;
10937917SReza.Sabdar@Sun.COM 
10947917SReza.Sabdar@Sun.COM 	rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
10957917SReza.Sabdar@Sun.COM 	    local_commands, job_stats, hardlink_q);
10967917SReza.Sabdar@Sun.COM 	if (rv < 0)
10977917SReza.Sabdar@Sun.COM 		return (rv);
10987917SReza.Sabdar@Sun.COM 
10997917SReza.Sabdar@Sun.COM 	rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
11007917SReza.Sabdar@Sun.COM 	    local_commands, job_stats);
11017917SReza.Sabdar@Sun.COM 
11027917SReza.Sabdar@Sun.COM 	return (rv < 0 ? rv : 0);
11037917SReza.Sabdar@Sun.COM }
11047917SReza.Sabdar@Sun.COM 
11057917SReza.Sabdar@Sun.COM /*
11067917SReza.Sabdar@Sun.COM  * get_write_buffer
11077917SReza.Sabdar@Sun.COM  *
11087917SReza.Sabdar@Sun.COM  * a wrapper to tlm_get_write_buffer so that
11097917SReza.Sabdar@Sun.COM  * we can cleanly detect ABORT commands
11107917SReza.Sabdar@Sun.COM  * without involving the TLM library with
11117917SReza.Sabdar@Sun.COM  * our problems.
11127917SReza.Sabdar@Sun.COM  */
11137917SReza.Sabdar@Sun.COM static char *
11147917SReza.Sabdar@Sun.COM get_write_buffer(long size, long *actual_size,
11157917SReza.Sabdar@Sun.COM     boolean_t zero, tlm_cmd_t *local_commands)
11167917SReza.Sabdar@Sun.COM {
11177917SReza.Sabdar@Sun.COM 	while (local_commands->tc_reader == TLM_BACKUP_RUN) {
11187917SReza.Sabdar@Sun.COM 		char *rec = tlm_get_write_buffer(size, actual_size,
11197917SReza.Sabdar@Sun.COM 		    local_commands->tc_buffers, zero);
11207917SReza.Sabdar@Sun.COM 		if (rec != 0) {
11217917SReza.Sabdar@Sun.COM 			return (rec);
11227917SReza.Sabdar@Sun.COM 		}
11237917SReza.Sabdar@Sun.COM 	}
11247917SReza.Sabdar@Sun.COM 	return (NULL);
11257917SReza.Sabdar@Sun.COM }
11267917SReza.Sabdar@Sun.COM 
11277917SReza.Sabdar@Sun.COM #define	NDMP_MORE_RECORDS	2
11287917SReza.Sabdar@Sun.COM 
11297917SReza.Sabdar@Sun.COM /*
11307917SReza.Sabdar@Sun.COM  * write_tar_eof
11317917SReza.Sabdar@Sun.COM  *
11327917SReza.Sabdar@Sun.COM  * This function is initially written for NDMP support.  It appends
11337917SReza.Sabdar@Sun.COM  * two tar headers to the tar file, and also N more empty buffers
11347917SReza.Sabdar@Sun.COM  * to make sure that the two tar headers will be read as a part of
11357917SReza.Sabdar@Sun.COM  * a mover record and don't get locked because of EOM on the mover
11367917SReza.Sabdar@Sun.COM  * side.
11377917SReza.Sabdar@Sun.COM  */
11387917SReza.Sabdar@Sun.COM void
11397917SReza.Sabdar@Sun.COM write_tar_eof(tlm_cmd_t *local_commands)
11407917SReza.Sabdar@Sun.COM {
11417917SReza.Sabdar@Sun.COM 	int i;
11427917SReza.Sabdar@Sun.COM 	long actual_size;
11437917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
11447917SReza.Sabdar@Sun.COM 
11457917SReza.Sabdar@Sun.COM 	/*
11467917SReza.Sabdar@Sun.COM 	 * output 2 zero filled records,
11477917SReza.Sabdar@Sun.COM 	 * TAR wants this.
11487917SReza.Sabdar@Sun.COM 	 */
11497917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11507917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11517917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11527917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11537917SReza.Sabdar@Sun.COM 
11547917SReza.Sabdar@Sun.COM 	/*
11557917SReza.Sabdar@Sun.COM 	 * NDMP: Clear the rest of the buffer and write two more buffers
11567917SReza.Sabdar@Sun.COM 	 * to the tape.
11577917SReza.Sabdar@Sun.COM 	 */
11587917SReza.Sabdar@Sun.COM 	bufs = local_commands->tc_buffers;
11597917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(bufs->tbs_data_transfer_size,
11607917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11617917SReza.Sabdar@Sun.COM 
11627917SReza.Sabdar@Sun.COM 	for (i = 0; i < NDMP_MORE_RECORDS &&
11637917SReza.Sabdar@Sun.COM 	    local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
11647917SReza.Sabdar@Sun.COM 		/*
11657917SReza.Sabdar@Sun.COM 		 * We don't need the return value of get_write_buffer(),
11667917SReza.Sabdar@Sun.COM 		 * since it's already zeroed out if the buffer is returned.
11677917SReza.Sabdar@Sun.COM 		 */
11687917SReza.Sabdar@Sun.COM 		(void) get_write_buffer(bufs->tbs_data_transfer_size,
11697917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
11707917SReza.Sabdar@Sun.COM 	}
11717917SReza.Sabdar@Sun.COM 
11727917SReza.Sabdar@Sun.COM 	bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
11737917SReza.Sabdar@Sun.COM 	tlm_buffer_release_in_buf(bufs);
11747917SReza.Sabdar@Sun.COM }
11757917SReza.Sabdar@Sun.COM 
11767917SReza.Sabdar@Sun.COM /*
11777917SReza.Sabdar@Sun.COM  * Callback to backup each ZFS property
11787917SReza.Sabdar@Sun.COM  */
11797917SReza.Sabdar@Sun.COM static int
11807917SReza.Sabdar@Sun.COM zfs_put_prop_cb(int prop, void *pp)
11817917SReza.Sabdar@Sun.COM {
11827917SReza.Sabdar@Sun.COM 	ndmp_metadata_header_t *mhp;
11837917SReza.Sabdar@Sun.COM 	ndmp_metadata_property_t *mpp;
11847917SReza.Sabdar@Sun.COM 	char buf[ZFS_MAXNAMELEN];
11857917SReza.Sabdar@Sun.COM 	char sbuf[ZFS_MAXNAMELEN];
11867917SReza.Sabdar@Sun.COM 	zprop_source_t stype;
11878800SReza.Sabdar@Sun.COM 	char *sourcestr;
11887917SReza.Sabdar@Sun.COM 
11897917SReza.Sabdar@Sun.COM 	if (pp == NULL)
11907917SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
11917917SReza.Sabdar@Sun.COM 
11927917SReza.Sabdar@Sun.COM 	mhp = (ndmp_metadata_header_t *)pp;
11937917SReza.Sabdar@Sun.COM 	mpp = &mhp->nh_property[mhp->nh_count++];
11947917SReza.Sabdar@Sun.COM 
11957917SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), NAME_MAX);
11967917SReza.Sabdar@Sun.COM 	(void) zfs_prop_get(mhp->nh_handle,
11979169SReza.Sabdar@Sun.COM 	    prop, buf, sizeof (buf), &stype, sbuf, sizeof (sbuf), B_TRUE);
11987917SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_value, buf, NAME_MAX);
11998800SReza.Sabdar@Sun.COM 
12008800SReza.Sabdar@Sun.COM 	switch (stype) {
12018800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_NONE:
12028800SReza.Sabdar@Sun.COM 		sourcestr = "none";
12038800SReza.Sabdar@Sun.COM 		break;
12048800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_LOCAL:
12058800SReza.Sabdar@Sun.COM 		sourcestr = mhp->nh_dataset;
12068800SReza.Sabdar@Sun.COM 		break;
12078800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_TEMPORARY:
12088800SReza.Sabdar@Sun.COM 		sourcestr = "temporary";
12098800SReza.Sabdar@Sun.COM 		break;
12108800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_DEFAULT:
12118800SReza.Sabdar@Sun.COM 		sourcestr = "default";
12128800SReza.Sabdar@Sun.COM 		break;
12138800SReza.Sabdar@Sun.COM 	default:
12148800SReza.Sabdar@Sun.COM 		sourcestr = sbuf;
12158800SReza.Sabdar@Sun.COM 		break;
12168800SReza.Sabdar@Sun.COM 	}
12178800SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_source, sourcestr, NAME_MAX);
12187917SReza.Sabdar@Sun.COM 
12197917SReza.Sabdar@Sun.COM 	return (ZPROP_CONT);
12207917SReza.Sabdar@Sun.COM }
12217917SReza.Sabdar@Sun.COM 
12227917SReza.Sabdar@Sun.COM 
12237917SReza.Sabdar@Sun.COM /*
12247917SReza.Sabdar@Sun.COM  * Notifies ndmpd that the metadata associated with the given ZFS dataset
12257917SReza.Sabdar@Sun.COM  * should be backed up.
12267917SReza.Sabdar@Sun.COM  */
12277917SReza.Sabdar@Sun.COM int
12287917SReza.Sabdar@Sun.COM ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
12297917SReza.Sabdar@Sun.COM {
12307917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;
12317917SReza.Sabdar@Sun.COM 	ndmp_metadata_header_t *mhp;
12327917SReza.Sabdar@Sun.COM 	ndmp_metadata_property_t *mpp;
12337917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;
12347917SReza.Sabdar@Sun.COM 	long actual_size;
12357917SReza.Sabdar@Sun.COM 	nvlist_t *uprops, *ulist;
12367917SReza.Sabdar@Sun.COM 	const char *pname;
12377917SReza.Sabdar@Sun.COM 	nvpair_t *elp;
12387917SReza.Sabdar@Sun.COM 	char *sval, *ssrc;
12397917SReza.Sabdar@Sun.COM 	char *wbuf, *pp, *tp;
12407917SReza.Sabdar@Sun.COM 	long size, lsize, sz;
12417917SReza.Sabdar@Sun.COM 	int align = RECORDSIZE - 1;
12427917SReza.Sabdar@Sun.COM 
12437917SReza.Sabdar@Sun.COM 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
12447917SReza.Sabdar@Sun.COM 		return (-1);
12457917SReza.Sabdar@Sun.COM 
12467917SReza.Sabdar@Sun.COM 	if ((lcmd = cmds->tcs_command) == NULL ||
12477917SReza.Sabdar@Sun.COM 	    lcmd->tc_buffers == NULL)
12487917SReza.Sabdar@Sun.COM 		return (-1);
12497917SReza.Sabdar@Sun.COM 
12507917SReza.Sabdar@Sun.COM 	size = sizeof (ndmp_metadata_header_t) +
12517917SReza.Sabdar@Sun.COM 	    ZFS_MAX_PROPS * sizeof (ndmp_metadata_property_t);
12527917SReza.Sabdar@Sun.COM 	size += align;
12537917SReza.Sabdar@Sun.COM 	size &= ~align;
12547917SReza.Sabdar@Sun.COM 
12557917SReza.Sabdar@Sun.COM 	if ((mhp = malloc(size)) == NULL)
12567917SReza.Sabdar@Sun.COM 		return (-1);
12577917SReza.Sabdar@Sun.COM 	(void) memset(mhp, 0, size);
12587917SReza.Sabdar@Sun.COM 
12597917SReza.Sabdar@Sun.COM 	mhp->nh_plversion = nctx->nc_plversion;
12607917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_plname, nctx->nc_plname,
12617917SReza.Sabdar@Sun.COM 	    sizeof (mhp->nh_plname));
12627917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC, sizeof (mhp->nh_magic));
12637917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
12647917SReza.Sabdar@Sun.COM 
12657917SReza.Sabdar@Sun.COM 	if ((mhp->nh_handle = zfs_open(zlibh, dataset,
12667917SReza.Sabdar@Sun.COM 	    ZFS_TYPE_DATASET)) == NULL) {
12677917SReza.Sabdar@Sun.COM 		free(mhp);
12687917SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
12697917SReza.Sabdar@Sun.COM 	}
12707917SReza.Sabdar@Sun.COM 
12717917SReza.Sabdar@Sun.COM 	/* Get all the ZFS properties */
12727917SReza.Sabdar@Sun.COM 	(void) zprop_iter(zfs_put_prop_cb, mhp, TRUE, TRUE,
12737917SReza.Sabdar@Sun.COM 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
12747917SReza.Sabdar@Sun.COM 
12757917SReza.Sabdar@Sun.COM 	/* Get user properties */
12767917SReza.Sabdar@Sun.COM 	uprops = zfs_get_user_props(mhp->nh_handle);
12777917SReza.Sabdar@Sun.COM 
12787917SReza.Sabdar@Sun.COM 	elp = nvlist_next_nvpair(uprops, NULL);
12797917SReza.Sabdar@Sun.COM 
12807917SReza.Sabdar@Sun.COM 	while (elp != NULL) {
12817917SReza.Sabdar@Sun.COM 		mpp = &mhp->nh_property[mhp->nh_count];
12827917SReza.Sabdar@Sun.COM 		if (nvpair_value_nvlist(elp, &ulist) != 0 ||
12837917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
12847917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
12857917SReza.Sabdar@Sun.COM 			zfs_close(mhp->nh_handle);
12867917SReza.Sabdar@Sun.COM 			free(mhp);
12877917SReza.Sabdar@Sun.COM 			return (-1);
12887917SReza.Sabdar@Sun.COM 		}
12897917SReza.Sabdar@Sun.COM 		if ((pname = nvpair_name(elp)) != NULL)
12907917SReza.Sabdar@Sun.COM 			(void) strlcpy(mpp->mp_name, pname, NAME_MAX);
12917917SReza.Sabdar@Sun.COM 
12927917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_value, sval, NAME_MAX);
12937917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_source, ssrc, NAME_MAX);
12947917SReza.Sabdar@Sun.COM 		mhp->nh_count++;
12957917SReza.Sabdar@Sun.COM 		elp = nvlist_next_nvpair(uprops, elp);
12967917SReza.Sabdar@Sun.COM 	}
12977917SReza.Sabdar@Sun.COM 
12987917SReza.Sabdar@Sun.COM 	zfs_close(mhp->nh_handle);
12997917SReza.Sabdar@Sun.COM 
13007917SReza.Sabdar@Sun.COM 	if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
13017917SReza.Sabdar@Sun.COM 	    lcmd)) != NULL) {
13027917SReza.Sabdar@Sun.COM 		pp = (char *)mhp;
13037917SReza.Sabdar@Sun.COM 
13047917SReza.Sabdar@Sun.COM 		(void) memcpy(wbuf, pp, (actual_size < size) ?
13057917SReza.Sabdar@Sun.COM 		    actual_size : size);
13067917SReza.Sabdar@Sun.COM 		pp += (actual_size < size) ? actual_size : size;
13077917SReza.Sabdar@Sun.COM 
13087917SReza.Sabdar@Sun.COM 		sz = actual_size;
13097917SReza.Sabdar@Sun.COM 		while (sz < size &&
13107917SReza.Sabdar@Sun.COM 		    ((tp = get_write_buffer(size - sz, &lsize,
13117917SReza.Sabdar@Sun.COM 		    TRUE, lcmd))) != NULL) {
13127917SReza.Sabdar@Sun.COM 			(void) memcpy(tp, pp, size - sz);
13137917SReza.Sabdar@Sun.COM 			sz += lsize;
13147917SReza.Sabdar@Sun.COM 			pp += lsize;
13157917SReza.Sabdar@Sun.COM 		}
13167917SReza.Sabdar@Sun.COM 		if (sz > size) {
13177917SReza.Sabdar@Sun.COM 			tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
13187917SReza.Sabdar@Sun.COM 		}
13197917SReza.Sabdar@Sun.COM 	}
13207917SReza.Sabdar@Sun.COM 
13217917SReza.Sabdar@Sun.COM 	free(mhp);
13227917SReza.Sabdar@Sun.COM 	return (0);
13237917SReza.Sabdar@Sun.COM }
1324