xref: /onnv-gate/usr/src/cmd/ndmpd/tlm/tlm_backup_reader.c (revision 9323:b14e6a74639f)
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;
620*9323SReza.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 
6307917SReza.Sabdar@Sun.COM 	if (S_ISLNK(tlm_acls->acl_attr.st_mode))
6317917SReza.Sabdar@Sun.COM 		return (TLM_NO_SOURCE_FILE);
6327917SReza.Sabdar@Sun.COM 
6337917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
6347917SReza.Sabdar@Sun.COM 	if (fullname == NULL) {
6357917SReza.Sabdar@Sun.COM 		free(fullname);
6367917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
6377917SReza.Sabdar@Sun.COM 	}
6387917SReza.Sabdar@Sun.COM 
6397917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name)) {
6407917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6417917SReza.Sabdar@Sun.COM 		free(fullname);
6427917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
6437917SReza.Sabdar@Sun.COM 	}
6447917SReza.Sabdar@Sun.COM 
6458540SReza.Sabdar@Sun.COM 	if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
6468540SReza.Sabdar@Sun.COM 	    sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
6477917SReza.Sabdar@Sun.COM 		free(fullname);
6487917SReza.Sabdar@Sun.COM 		return (0);
6497917SReza.Sabdar@Sun.COM 	}
6507917SReza.Sabdar@Sun.COM 
6517917SReza.Sabdar@Sun.COM 	attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
6527917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
6537917SReza.Sabdar@Sun.COM 	if (attrname == NULL || snapname == NULL) {
6547917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
6557917SReza.Sabdar@Sun.COM 		goto err_out;
6567917SReza.Sabdar@Sun.COM 	}
6577917SReza.Sabdar@Sun.COM 
6587917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(snapname, chkdir, name)) {
6597917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6607917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
6617917SReza.Sabdar@Sun.COM 		goto err_out;
6627917SReza.Sabdar@Sun.COM 	}
6637917SReza.Sabdar@Sun.COM 
6647917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
6657917SReza.Sabdar@Sun.COM 
6667917SReza.Sabdar@Sun.COM 	/*
6677917SReza.Sabdar@Sun.COM 	 * Open the file for reading.
6687917SReza.Sabdar@Sun.COM 	 */
6698540SReza.Sabdar@Sun.COM 	fd = attropen(fnamep, ".", O_RDONLY);
6707917SReza.Sabdar@Sun.COM 	if (fd == -1) {
6718540SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s][%s]",
6728540SReza.Sabdar@Sun.COM 		    fullname, fnamep);
6737917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
6747917SReza.Sabdar@Sun.COM 		goto err_out;
6757917SReza.Sabdar@Sun.COM 	}
6767917SReza.Sabdar@Sun.COM 
6777917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
6787917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
6797917SReza.Sabdar@Sun.COM 
6807917SReza.Sabdar@Sun.COM 	section = 0;
6817917SReza.Sabdar@Sun.COM 
6827917SReza.Sabdar@Sun.COM 	dp = (DIR *)fdopendir(fd);
6837917SReza.Sabdar@Sun.COM 	if (dp == NULL) {
6847917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
6857917SReza.Sabdar@Sun.COM 		(void) close(fd);
6867917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
6877917SReza.Sabdar@Sun.COM 		goto err_out;
6887917SReza.Sabdar@Sun.COM 	}
6897917SReza.Sabdar@Sun.COM 
6907917SReza.Sabdar@Sun.COM 	while ((dtp = readdir(dp)) != NULL) {
6917917SReza.Sabdar@Sun.COM 		int section_size;
6927917SReza.Sabdar@Sun.COM 
6937917SReza.Sabdar@Sun.COM 		if (*dtp->d_name == '.')
6947917SReza.Sabdar@Sun.COM 			continue;
6957917SReza.Sabdar@Sun.COM 
6968540SReza.Sabdar@Sun.COM 		if (sysattr_rdonly(dtp->d_name))
6978540SReza.Sabdar@Sun.COM 			continue;
6988540SReza.Sabdar@Sun.COM 
699*9323SReza.Sabdar@Sun.COM 		afd = attropen(fnamep, dtp->d_name, O_RDONLY);
700*9323SReza.Sabdar@Sun.COM 		if (afd == -1) {
7017917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
7028540SReza.Sabdar@Sun.COM 			    "problem(%d) opening xattr file [%s][%s]", errno,
7038540SReza.Sabdar@Sun.COM 			    fullname, fnamep);
7047917SReza.Sabdar@Sun.COM 			goto tear_down;
7057917SReza.Sabdar@Sun.COM 		}
7067917SReza.Sabdar@Sun.COM 
707*9323SReza.Sabdar@Sun.COM 		(void) output_xattr_header(fullname, dtp->d_name, afd,
7087917SReza.Sabdar@Sun.COM 		    tlm_acls, section, local_commands);
7097917SReza.Sabdar@Sun.COM 		(void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
7107917SReza.Sabdar@Sun.COM 		    dtp->d_name);
7117917SReza.Sabdar@Sun.COM 		(void) output_file_header(attrname, "", tlm_acls, 0,
7127917SReza.Sabdar@Sun.COM 		    local_commands);
7137917SReza.Sabdar@Sun.COM 
7147917SReza.Sabdar@Sun.COM 		section_size = (long)llmin(tlm_acls->acl_attr.st_size,
7157917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
7167917SReza.Sabdar@Sun.COM 
7177917SReza.Sabdar@Sun.COM 		/* We only can read upto one section extended attribute */
7187917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
7197917SReza.Sabdar@Sun.COM 			char	*buf;
7207917SReza.Sabdar@Sun.COM 			long	actual_size;
7217917SReza.Sabdar@Sun.COM 			int	read_size;
7228540SReza.Sabdar@Sun.COM 			int sysattr_read = 0;
7238540SReza.Sabdar@Sun.COM 			char *rec;
7248540SReza.Sabdar@Sun.COM 			int size;
7257917SReza.Sabdar@Sun.COM 
7267917SReza.Sabdar@Sun.COM 			/*
7277917SReza.Sabdar@Sun.COM 			 * check for Abort commands
7287917SReza.Sabdar@Sun.COM 			 */
7297917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7307917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
7317917SReza.Sabdar@Sun.COM 				goto tear_down;
7327917SReza.Sabdar@Sun.COM 			}
7337917SReza.Sabdar@Sun.COM 
7347917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
7357917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
7367917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
7377917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
7387917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
7397917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
7407917SReza.Sabdar@Sun.COM 
7417917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
7427917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
7437917SReza.Sabdar@Sun.COM 			if (!buf)
7447917SReza.Sabdar@Sun.COM 				goto tear_down;
7457917SReza.Sabdar@Sun.COM 
7468540SReza.Sabdar@Sun.COM 			if ((actual_size < section_size) &&
7478540SReza.Sabdar@Sun.COM 			    sysattr_rw(dtp->d_name)) {
7488540SReza.Sabdar@Sun.COM 				rec = buf;
7498540SReza.Sabdar@Sun.COM 				buf = ndmp_malloc(section_size);
7508540SReza.Sabdar@Sun.COM 				if (!buf)
7518540SReza.Sabdar@Sun.COM 					goto tear_down;
7528540SReza.Sabdar@Sun.COM 				size = actual_size;
7538540SReza.Sabdar@Sun.COM 				actual_size = section_size;
7548540SReza.Sabdar@Sun.COM 				sysattr_read = 1;
7558540SReza.Sabdar@Sun.COM 			}
7568540SReza.Sabdar@Sun.COM 
7577917SReza.Sabdar@Sun.COM 			/*
7587917SReza.Sabdar@Sun.COM 			 * check for Abort commands
7597917SReza.Sabdar@Sun.COM 			 */
7607917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7617917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
7627917SReza.Sabdar@Sun.COM 				goto tear_down;
7637917SReza.Sabdar@Sun.COM 			}
7647917SReza.Sabdar@Sun.COM 
7657917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
766*9323SReza.Sabdar@Sun.COM 			if ((actual_size = read(afd, buf, read_size)) < 0)
7678540SReza.Sabdar@Sun.COM 				break;
7688540SReza.Sabdar@Sun.COM 
7698540SReza.Sabdar@Sun.COM 			if (sysattr_read) {
7708540SReza.Sabdar@Sun.COM 				if (get_write_one_buf(buf, rec, read_size,
7718540SReza.Sabdar@Sun.COM 				    size, local_commands) == 0) {
7728540SReza.Sabdar@Sun.COM 					free(buf);
7738540SReza.Sabdar@Sun.COM 					goto tear_down;
7748540SReza.Sabdar@Sun.COM 				}
7758540SReza.Sabdar@Sun.COM 				free(buf);
7768540SReza.Sabdar@Sun.COM 			}
7778540SReza.Sabdar@Sun.COM 
7788540SReza.Sabdar@Sun.COM 
7797917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
7807917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
7817917SReza.Sabdar@Sun.COM 
7827917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
7837917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
7847917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
7857917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
7867917SReza.Sabdar@Sun.COM 				goto tear_down;
7877917SReza.Sabdar@Sun.COM 			}
7887917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
7897917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
7907917SReza.Sabdar@Sun.COM 		}
791*9323SReza.Sabdar@Sun.COM 		(void) close(afd);
792*9323SReza.Sabdar@Sun.COM 		afd = -1;
7937917SReza.Sabdar@Sun.COM 	}
7947917SReza.Sabdar@Sun.COM 
7957917SReza.Sabdar@Sun.COM tear_down:
7967917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
7977917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
7987917SReza.Sabdar@Sun.COM 
799*9323SReza.Sabdar@Sun.COM 	if (afd > 0)
800*9323SReza.Sabdar@Sun.COM 		(void) close(afd);
801*9323SReza.Sabdar@Sun.COM 
802*9323SReza.Sabdar@Sun.COM 	/* closedir closes fd too */
8037917SReza.Sabdar@Sun.COM 	(void) closedir(dp);
8047917SReza.Sabdar@Sun.COM 
8057917SReza.Sabdar@Sun.COM err_out:
8067917SReza.Sabdar@Sun.COM 	free(fullname);
8077917SReza.Sabdar@Sun.COM 	free(attrname);
8087917SReza.Sabdar@Sun.COM 	free(snapname);
8097917SReza.Sabdar@Sun.COM 	return (rv);
8107917SReza.Sabdar@Sun.COM }
8117917SReza.Sabdar@Sun.COM 
8127917SReza.Sabdar@Sun.COM 
8137917SReza.Sabdar@Sun.COM /*
8147917SReza.Sabdar@Sun.COM  * tlm_output_file
8157917SReza.Sabdar@Sun.COM  *
8167917SReza.Sabdar@Sun.COM  * Put this file into the output buffers.
8177917SReza.Sabdar@Sun.COM  */
8187917SReza.Sabdar@Sun.COM longlong_t
8197917SReza.Sabdar@Sun.COM tlm_output_file(char *dir, char *name, char *chkdir,
8207917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
8217917SReza.Sabdar@Sun.COM     tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
8227917SReza.Sabdar@Sun.COM {
8237917SReza.Sabdar@Sun.COM 	char	*fullname;		/* directory + name */
8247917SReza.Sabdar@Sun.COM 	char	*snapname;		/* snapshot name */
8257917SReza.Sabdar@Sun.COM 	char	*linkname;		/* where this file points */
8267917SReza.Sabdar@Sun.COM 	int	section = 0;		/* section of a huge file */
8277917SReza.Sabdar@Sun.COM 	int	fd;
8287917SReza.Sabdar@Sun.COM 	longlong_t real_size;		/* the origional file size */
8297917SReza.Sabdar@Sun.COM 	longlong_t file_size;		/* real size of this file */
8307917SReza.Sabdar@Sun.COM 	longlong_t seek_spot = 0;	/* location in the file */
8317917SReza.Sabdar@Sun.COM 					/* for Multi Volume record */
8327917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
8337917SReza.Sabdar@Sun.COM 	char *fnamep;
8347917SReza.Sabdar@Sun.COM 
8357917SReza.Sabdar@Sun.COM 	/* Indicate whether a file with the same inode has been backed up. */
8367917SReza.Sabdar@Sun.COM 	int hardlink_done = 0;
8377917SReza.Sabdar@Sun.COM 
8387917SReza.Sabdar@Sun.COM 	/*
8397917SReza.Sabdar@Sun.COM 	 * If a file with the same inode has been backed up, hardlink_pos holds
8407917SReza.Sabdar@Sun.COM 	 * the tape offset of the data record.
8417917SReza.Sabdar@Sun.COM 	 */
8427917SReza.Sabdar@Sun.COM 	u_longlong_t hardlink_pos = 0;
8437917SReza.Sabdar@Sun.COM 
8447917SReza.Sabdar@Sun.COM 	if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
8457917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name);
8467917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
8477917SReza.Sabdar@Sun.COM 	}
8487917SReza.Sabdar@Sun.COM 
8497917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
8507917SReza.Sabdar@Sun.COM 	linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
8517917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
8527917SReza.Sabdar@Sun.COM 	if (fullname == NULL || linkname == NULL || snapname == NULL) {
8537917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
8547917SReza.Sabdar@Sun.COM 		goto err_out;
8557917SReza.Sabdar@Sun.COM 	}
8567917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name) ||
8577917SReza.Sabdar@Sun.COM 	    !tlm_cat_path(snapname, chkdir, name)) {
8587917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
8597917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
8607917SReza.Sabdar@Sun.COM 		goto err_out;
8617917SReza.Sabdar@Sun.COM 	}
8627917SReza.Sabdar@Sun.COM 
8637917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
8647917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
8657917SReza.Sabdar@Sun.COM 
8667917SReza.Sabdar@Sun.COM 	if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
8677917SReza.Sabdar@Sun.COM 		file_size = tlm_readlink(fullname, snapname, linkname,
8687917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME-1);
8697917SReza.Sabdar@Sun.COM 		if (file_size < 0) {
8707917SReza.Sabdar@Sun.COM 			real_size = -ENOENT;
8717917SReza.Sabdar@Sun.COM 			goto err_out;
8727917SReza.Sabdar@Sun.COM 		}
8737917SReza.Sabdar@Sun.COM 
8747917SReza.Sabdar@Sun.COM 		/*
8757917SReza.Sabdar@Sun.COM 		 * Since soft links can not be read(2), we should only
8767917SReza.Sabdar@Sun.COM 		 * backup the file header.
8777917SReza.Sabdar@Sun.COM 		 */
8787917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
8797917SReza.Sabdar@Sun.COM 		    linkname,
8807917SReza.Sabdar@Sun.COM 		    tlm_acls,
8817917SReza.Sabdar@Sun.COM 		    section,
8827917SReza.Sabdar@Sun.COM 		    local_commands);
8837917SReza.Sabdar@Sun.COM 
8847917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
8857917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
8867917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhpath_name(job_stats, fullname,
8877917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
8887917SReza.Sabdar@Sun.COM 
8897917SReza.Sabdar@Sun.COM 		free(fullname);
8907917SReza.Sabdar@Sun.COM 		free(linkname);
8917917SReza.Sabdar@Sun.COM 		free(snapname);
8927917SReza.Sabdar@Sun.COM 		return (0);
8937917SReza.Sabdar@Sun.COM 	}
8947917SReza.Sabdar@Sun.COM 
8957917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
8967917SReza.Sabdar@Sun.COM 
8977917SReza.Sabdar@Sun.COM 	/*
8987917SReza.Sabdar@Sun.COM 	 * For hardlink, only read the data if no other link
8997917SReza.Sabdar@Sun.COM 	 * belonging to the same inode has been backed up.
9007917SReza.Sabdar@Sun.COM 	 */
9017917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1) {
9027917SReza.Sabdar@Sun.COM 		hardlink_done = !hardlink_q_get(hardlink_q,
9037917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
9047917SReza.Sabdar@Sun.COM 	}
9057917SReza.Sabdar@Sun.COM 
9067917SReza.Sabdar@Sun.COM 	if (!hardlink_done) {
9077917SReza.Sabdar@Sun.COM 		/*
9087917SReza.Sabdar@Sun.COM 		 * Open the file for reading.
9097917SReza.Sabdar@Sun.COM 		 */
9107917SReza.Sabdar@Sun.COM 		fd = open(fnamep, O_RDONLY);
9117917SReza.Sabdar@Sun.COM 		if (fd == -1) {
9127917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
9138540SReza.Sabdar@Sun.COM 			    "BACKUP> Can't open file [%s][%s] err(%d)",
9148540SReza.Sabdar@Sun.COM 			    fullname, fnamep, errno);
9157917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SOURCE_FILE;
9167917SReza.Sabdar@Sun.COM 			goto err_out;
9177917SReza.Sabdar@Sun.COM 		}
9187917SReza.Sabdar@Sun.COM 	} else {
9198193SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
9207917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, hardlink_pos);
9217917SReza.Sabdar@Sun.COM 
9227917SReza.Sabdar@Sun.COM 		fd = -1;
9237917SReza.Sabdar@Sun.COM 	}
9247917SReza.Sabdar@Sun.COM 
9257917SReza.Sabdar@Sun.COM 	linkname[0] = 0;
9267917SReza.Sabdar@Sun.COM 
9277917SReza.Sabdar@Sun.COM 	real_size = tlm_acls->acl_attr.st_size;
9287917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
9297917SReza.Sabdar@Sun.COM 	    local_commands);
9307917SReza.Sabdar@Sun.COM 
9317917SReza.Sabdar@Sun.COM 	/*
9327917SReza.Sabdar@Sun.COM 	 * section = 0: file is small enough for TAR
9337917SReza.Sabdar@Sun.COM 	 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
9347917SReza.Sabdar@Sun.COM 	 * 		and the file name gets munged
9357917SReza.Sabdar@Sun.COM 	 */
9367917SReza.Sabdar@Sun.COM 	file_size = real_size;
9377917SReza.Sabdar@Sun.COM 	if (file_size > TLM_MAX_TAR_IMAGE) {
9387917SReza.Sabdar@Sun.COM 		if (output_humongus_header(fullname, file_size,
9397917SReza.Sabdar@Sun.COM 		    local_commands) < 0) {
9407917SReza.Sabdar@Sun.COM 			(void) close(fd);
9417917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SCRATCH_SPACE;
9427917SReza.Sabdar@Sun.COM 			goto err_out;
9437917SReza.Sabdar@Sun.COM 		}
9447917SReza.Sabdar@Sun.COM 		section = 1;
9457917SReza.Sabdar@Sun.COM 	} else {
9467917SReza.Sabdar@Sun.COM 		section = 0;
9477917SReza.Sabdar@Sun.COM 	}
9487917SReza.Sabdar@Sun.COM 
9497917SReza.Sabdar@Sun.COM 	/*
9507917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode
9517917SReza.Sabdar@Sun.COM 	 * has been backed up, only backup an empty record.
9527917SReza.Sabdar@Sun.COM 	 */
9537917SReza.Sabdar@Sun.COM 	if (hardlink_done)
9547917SReza.Sabdar@Sun.COM 		file_size = 0;
9557917SReza.Sabdar@Sun.COM 
9567917SReza.Sabdar@Sun.COM 	/*
9577917SReza.Sabdar@Sun.COM 	 * work
9587917SReza.Sabdar@Sun.COM 	 */
9597917SReza.Sabdar@Sun.COM 	if (file_size == 0) {
9607917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
9617917SReza.Sabdar@Sun.COM 		    linkname,
9627917SReza.Sabdar@Sun.COM 		    tlm_acls,
9637917SReza.Sabdar@Sun.COM 		    section,
9647917SReza.Sabdar@Sun.COM 		    local_commands);
9657917SReza.Sabdar@Sun.COM 		/*
9667917SReza.Sabdar@Sun.COM 		 * this can fall right through since zero size files
9677917SReza.Sabdar@Sun.COM 		 * will be skipped by the WHILE loop anyway
9687917SReza.Sabdar@Sun.COM 		 */
9697917SReza.Sabdar@Sun.COM 	}
9707917SReza.Sabdar@Sun.COM 
9717917SReza.Sabdar@Sun.COM 	while (file_size > 0) {
9727917SReza.Sabdar@Sun.COM 		int section_size = llmin(file_size,
9737917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
9747917SReza.Sabdar@Sun.COM 
9757917SReza.Sabdar@Sun.COM 		tlm_acls->acl_attr.st_size = (longlong_t)section_size;
9767917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
9777917SReza.Sabdar@Sun.COM 		    linkname,
9787917SReza.Sabdar@Sun.COM 		    tlm_acls,
9797917SReza.Sabdar@Sun.COM 		    section,
9807917SReza.Sabdar@Sun.COM 		    local_commands);
9817917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
9827917SReza.Sabdar@Sun.COM 			char	*buf;
9837917SReza.Sabdar@Sun.COM 			long	actual_size;
9847917SReza.Sabdar@Sun.COM 			int	read_size;
9857917SReza.Sabdar@Sun.COM 
9867917SReza.Sabdar@Sun.COM 			/*
9877917SReza.Sabdar@Sun.COM 			 * check for Abort commands
9887917SReza.Sabdar@Sun.COM 			 */
9897917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
9907917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
9917917SReza.Sabdar@Sun.COM 				goto tear_down;
9927917SReza.Sabdar@Sun.COM 			}
9937917SReza.Sabdar@Sun.COM 
9947917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
9957917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
9967917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
9977917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
9987917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
9997917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
10007917SReza.Sabdar@Sun.COM 
10017917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
10027917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
10037917SReza.Sabdar@Sun.COM 			if (!buf)
10047917SReza.Sabdar@Sun.COM 				goto tear_down;
10057917SReza.Sabdar@Sun.COM 
10067917SReza.Sabdar@Sun.COM 			/*
10077917SReza.Sabdar@Sun.COM 			 * check for Abort commands
10087917SReza.Sabdar@Sun.COM 			 */
10097917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
10107917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
10117917SReza.Sabdar@Sun.COM 				goto tear_down;
10127917SReza.Sabdar@Sun.COM 			}
10137917SReza.Sabdar@Sun.COM 
10147917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
10157917SReza.Sabdar@Sun.COM 			actual_size = read(fd, buf, read_size);
10167917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
10177917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
10187917SReza.Sabdar@Sun.COM 
10197917SReza.Sabdar@Sun.COM 			if (actual_size == 0)
10207917SReza.Sabdar@Sun.COM 				break;
10217917SReza.Sabdar@Sun.COM 
10227917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
10237917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
10247917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
10257917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
10267917SReza.Sabdar@Sun.COM 				goto tear_down;
10277917SReza.Sabdar@Sun.COM 			}
10287917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
10297917SReza.Sabdar@Sun.COM 			file_size -= actual_size;
10307917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
10317917SReza.Sabdar@Sun.COM 		}
10327917SReza.Sabdar@Sun.COM 		section++;
10337917SReza.Sabdar@Sun.COM 	}
10347917SReza.Sabdar@Sun.COM 
10357917SReza.Sabdar@Sun.COM 	/*
10367917SReza.Sabdar@Sun.COM 	 * If data belonging to this hardlink has been backed up, add the link
10377917SReza.Sabdar@Sun.COM 	 * to hardlink queue.
10387917SReza.Sabdar@Sun.COM 	 */
10397917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
10407917SReza.Sabdar@Sun.COM 		(void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
10417917SReza.Sabdar@Sun.COM 		    pos, NULL, 0);
10427917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10438193SReza.Sabdar@Sun.COM 		    "backed up hardlink file %s, inode = %llu, pos = %llu ",
10447917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, pos);
10457917SReza.Sabdar@Sun.COM 	}
10467917SReza.Sabdar@Sun.COM 
10477917SReza.Sabdar@Sun.COM 	/*
10487917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode has been
10498193SReza.Sabdar@Sun.COM 	 * backed up, no add_node entry should be sent for this link.
10507917SReza.Sabdar@Sun.COM 	 */
10517917SReza.Sabdar@Sun.COM 	if (hardlink_done) {
10527917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10538193SReza.Sabdar@Sun.COM 		    "backed up hardlink link %s, inode = %llu, pos = %llu ",
10547917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
10557917SReza.Sabdar@Sun.COM 	} else {
10567917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
10577917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
10587917SReza.Sabdar@Sun.COM 	}
10597917SReza.Sabdar@Sun.COM 
10607917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
10617917SReza.Sabdar@Sun.COM 	    pos);
10627917SReza.Sabdar@Sun.COM 
10637917SReza.Sabdar@Sun.COM tear_down:
10647917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
10657917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
10667917SReza.Sabdar@Sun.COM 
10677917SReza.Sabdar@Sun.COM 	(void) close(fd);
10687917SReza.Sabdar@Sun.COM 
10697917SReza.Sabdar@Sun.COM err_out:
10707917SReza.Sabdar@Sun.COM 	free(fullname);
10717917SReza.Sabdar@Sun.COM 	free(linkname);
10727917SReza.Sabdar@Sun.COM 	free(snapname);
10737917SReza.Sabdar@Sun.COM 	return (real_size);
10747917SReza.Sabdar@Sun.COM }
10757917SReza.Sabdar@Sun.COM 
10767917SReza.Sabdar@Sun.COM /*
10777917SReza.Sabdar@Sun.COM  * tar_putfile
10787917SReza.Sabdar@Sun.COM  *
10797917SReza.Sabdar@Sun.COM  * Main file backup function for tar
10807917SReza.Sabdar@Sun.COM  */
10817917SReza.Sabdar@Sun.COM int
10827917SReza.Sabdar@Sun.COM tar_putfile(char *dir, char *name, char *chkdir,
10837917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
10847917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
10857917SReza.Sabdar@Sun.COM     struct hardlink_q *hardlink_q)
10867917SReza.Sabdar@Sun.COM {
10877917SReza.Sabdar@Sun.COM 	int rv;
10887917SReza.Sabdar@Sun.COM 
10897917SReza.Sabdar@Sun.COM 	rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
10907917SReza.Sabdar@Sun.COM 	    local_commands, job_stats, hardlink_q);
10917917SReza.Sabdar@Sun.COM 	if (rv < 0)
10927917SReza.Sabdar@Sun.COM 		return (rv);
10937917SReza.Sabdar@Sun.COM 
10947917SReza.Sabdar@Sun.COM 	rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
10957917SReza.Sabdar@Sun.COM 	    local_commands, job_stats);
10967917SReza.Sabdar@Sun.COM 
10977917SReza.Sabdar@Sun.COM 	return (rv < 0 ? rv : 0);
10987917SReza.Sabdar@Sun.COM }
10997917SReza.Sabdar@Sun.COM 
11007917SReza.Sabdar@Sun.COM /*
11017917SReza.Sabdar@Sun.COM  * get_write_buffer
11027917SReza.Sabdar@Sun.COM  *
11037917SReza.Sabdar@Sun.COM  * a wrapper to tlm_get_write_buffer so that
11047917SReza.Sabdar@Sun.COM  * we can cleanly detect ABORT commands
11057917SReza.Sabdar@Sun.COM  * without involving the TLM library with
11067917SReza.Sabdar@Sun.COM  * our problems.
11077917SReza.Sabdar@Sun.COM  */
11087917SReza.Sabdar@Sun.COM static char *
11097917SReza.Sabdar@Sun.COM get_write_buffer(long size, long *actual_size,
11107917SReza.Sabdar@Sun.COM     boolean_t zero, tlm_cmd_t *local_commands)
11117917SReza.Sabdar@Sun.COM {
11127917SReza.Sabdar@Sun.COM 	while (local_commands->tc_reader == TLM_BACKUP_RUN) {
11137917SReza.Sabdar@Sun.COM 		char *rec = tlm_get_write_buffer(size, actual_size,
11147917SReza.Sabdar@Sun.COM 		    local_commands->tc_buffers, zero);
11157917SReza.Sabdar@Sun.COM 		if (rec != 0) {
11167917SReza.Sabdar@Sun.COM 			return (rec);
11177917SReza.Sabdar@Sun.COM 		}
11187917SReza.Sabdar@Sun.COM 	}
11197917SReza.Sabdar@Sun.COM 	return (NULL);
11207917SReza.Sabdar@Sun.COM }
11217917SReza.Sabdar@Sun.COM 
11227917SReza.Sabdar@Sun.COM #define	NDMP_MORE_RECORDS	2
11237917SReza.Sabdar@Sun.COM 
11247917SReza.Sabdar@Sun.COM /*
11257917SReza.Sabdar@Sun.COM  * write_tar_eof
11267917SReza.Sabdar@Sun.COM  *
11277917SReza.Sabdar@Sun.COM  * This function is initially written for NDMP support.  It appends
11287917SReza.Sabdar@Sun.COM  * two tar headers to the tar file, and also N more empty buffers
11297917SReza.Sabdar@Sun.COM  * to make sure that the two tar headers will be read as a part of
11307917SReza.Sabdar@Sun.COM  * a mover record and don't get locked because of EOM on the mover
11317917SReza.Sabdar@Sun.COM  * side.
11327917SReza.Sabdar@Sun.COM  */
11337917SReza.Sabdar@Sun.COM void
11347917SReza.Sabdar@Sun.COM write_tar_eof(tlm_cmd_t *local_commands)
11357917SReza.Sabdar@Sun.COM {
11367917SReza.Sabdar@Sun.COM 	int i;
11377917SReza.Sabdar@Sun.COM 	long actual_size;
11387917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
11397917SReza.Sabdar@Sun.COM 
11407917SReza.Sabdar@Sun.COM 	/*
11417917SReza.Sabdar@Sun.COM 	 * output 2 zero filled records,
11427917SReza.Sabdar@Sun.COM 	 * TAR wants this.
11437917SReza.Sabdar@Sun.COM 	 */
11447917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11457917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11467917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11477917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11487917SReza.Sabdar@Sun.COM 
11497917SReza.Sabdar@Sun.COM 	/*
11507917SReza.Sabdar@Sun.COM 	 * NDMP: Clear the rest of the buffer and write two more buffers
11517917SReza.Sabdar@Sun.COM 	 * to the tape.
11527917SReza.Sabdar@Sun.COM 	 */
11537917SReza.Sabdar@Sun.COM 	bufs = local_commands->tc_buffers;
11547917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(bufs->tbs_data_transfer_size,
11557917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11567917SReza.Sabdar@Sun.COM 
11577917SReza.Sabdar@Sun.COM 	for (i = 0; i < NDMP_MORE_RECORDS &&
11587917SReza.Sabdar@Sun.COM 	    local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
11597917SReza.Sabdar@Sun.COM 		/*
11607917SReza.Sabdar@Sun.COM 		 * We don't need the return value of get_write_buffer(),
11617917SReza.Sabdar@Sun.COM 		 * since it's already zeroed out if the buffer is returned.
11627917SReza.Sabdar@Sun.COM 		 */
11637917SReza.Sabdar@Sun.COM 		(void) get_write_buffer(bufs->tbs_data_transfer_size,
11647917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
11657917SReza.Sabdar@Sun.COM 	}
11667917SReza.Sabdar@Sun.COM 
11677917SReza.Sabdar@Sun.COM 	bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
11687917SReza.Sabdar@Sun.COM 	tlm_buffer_release_in_buf(bufs);
11697917SReza.Sabdar@Sun.COM }
11707917SReza.Sabdar@Sun.COM 
11717917SReza.Sabdar@Sun.COM /*
11727917SReza.Sabdar@Sun.COM  * Callback to backup each ZFS property
11737917SReza.Sabdar@Sun.COM  */
11747917SReza.Sabdar@Sun.COM static int
11757917SReza.Sabdar@Sun.COM zfs_put_prop_cb(int prop, void *pp)
11767917SReza.Sabdar@Sun.COM {
11777917SReza.Sabdar@Sun.COM 	ndmp_metadata_header_t *mhp;
11787917SReza.Sabdar@Sun.COM 	ndmp_metadata_property_t *mpp;
11797917SReza.Sabdar@Sun.COM 	char buf[ZFS_MAXNAMELEN];
11807917SReza.Sabdar@Sun.COM 	char sbuf[ZFS_MAXNAMELEN];
11817917SReza.Sabdar@Sun.COM 	zprop_source_t stype;
11828800SReza.Sabdar@Sun.COM 	char *sourcestr;
11837917SReza.Sabdar@Sun.COM 
11847917SReza.Sabdar@Sun.COM 	if (pp == NULL)
11857917SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
11867917SReza.Sabdar@Sun.COM 
11877917SReza.Sabdar@Sun.COM 	mhp = (ndmp_metadata_header_t *)pp;
11887917SReza.Sabdar@Sun.COM 	mpp = &mhp->nh_property[mhp->nh_count++];
11897917SReza.Sabdar@Sun.COM 
11907917SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), NAME_MAX);
11917917SReza.Sabdar@Sun.COM 	(void) zfs_prop_get(mhp->nh_handle,
11929169SReza.Sabdar@Sun.COM 	    prop, buf, sizeof (buf), &stype, sbuf, sizeof (sbuf), B_TRUE);
11937917SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_value, buf, NAME_MAX);
11948800SReza.Sabdar@Sun.COM 
11958800SReza.Sabdar@Sun.COM 	switch (stype) {
11968800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_NONE:
11978800SReza.Sabdar@Sun.COM 		sourcestr = "none";
11988800SReza.Sabdar@Sun.COM 		break;
11998800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_LOCAL:
12008800SReza.Sabdar@Sun.COM 		sourcestr = mhp->nh_dataset;
12018800SReza.Sabdar@Sun.COM 		break;
12028800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_TEMPORARY:
12038800SReza.Sabdar@Sun.COM 		sourcestr = "temporary";
12048800SReza.Sabdar@Sun.COM 		break;
12058800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_DEFAULT:
12068800SReza.Sabdar@Sun.COM 		sourcestr = "default";
12078800SReza.Sabdar@Sun.COM 		break;
12088800SReza.Sabdar@Sun.COM 	default:
12098800SReza.Sabdar@Sun.COM 		sourcestr = sbuf;
12108800SReza.Sabdar@Sun.COM 		break;
12118800SReza.Sabdar@Sun.COM 	}
12128800SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_source, sourcestr, NAME_MAX);
12137917SReza.Sabdar@Sun.COM 
12147917SReza.Sabdar@Sun.COM 	return (ZPROP_CONT);
12157917SReza.Sabdar@Sun.COM }
12167917SReza.Sabdar@Sun.COM 
12177917SReza.Sabdar@Sun.COM 
12187917SReza.Sabdar@Sun.COM /*
12197917SReza.Sabdar@Sun.COM  * Notifies ndmpd that the metadata associated with the given ZFS dataset
12207917SReza.Sabdar@Sun.COM  * should be backed up.
12217917SReza.Sabdar@Sun.COM  */
12227917SReza.Sabdar@Sun.COM int
12237917SReza.Sabdar@Sun.COM ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
12247917SReza.Sabdar@Sun.COM {
12257917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;
12267917SReza.Sabdar@Sun.COM 	ndmp_metadata_header_t *mhp;
12277917SReza.Sabdar@Sun.COM 	ndmp_metadata_property_t *mpp;
12287917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;
12297917SReza.Sabdar@Sun.COM 	long actual_size;
12307917SReza.Sabdar@Sun.COM 	nvlist_t *uprops, *ulist;
12317917SReza.Sabdar@Sun.COM 	const char *pname;
12327917SReza.Sabdar@Sun.COM 	nvpair_t *elp;
12337917SReza.Sabdar@Sun.COM 	char *sval, *ssrc;
12347917SReza.Sabdar@Sun.COM 	char *wbuf, *pp, *tp;
12357917SReza.Sabdar@Sun.COM 	long size, lsize, sz;
12367917SReza.Sabdar@Sun.COM 	int align = RECORDSIZE - 1;
12377917SReza.Sabdar@Sun.COM 
12387917SReza.Sabdar@Sun.COM 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
12397917SReza.Sabdar@Sun.COM 		return (-1);
12407917SReza.Sabdar@Sun.COM 
12417917SReza.Sabdar@Sun.COM 	if ((lcmd = cmds->tcs_command) == NULL ||
12427917SReza.Sabdar@Sun.COM 	    lcmd->tc_buffers == NULL)
12437917SReza.Sabdar@Sun.COM 		return (-1);
12447917SReza.Sabdar@Sun.COM 
12457917SReza.Sabdar@Sun.COM 	size = sizeof (ndmp_metadata_header_t) +
12467917SReza.Sabdar@Sun.COM 	    ZFS_MAX_PROPS * sizeof (ndmp_metadata_property_t);
12477917SReza.Sabdar@Sun.COM 	size += align;
12487917SReza.Sabdar@Sun.COM 	size &= ~align;
12497917SReza.Sabdar@Sun.COM 
12507917SReza.Sabdar@Sun.COM 	if ((mhp = malloc(size)) == NULL)
12517917SReza.Sabdar@Sun.COM 		return (-1);
12527917SReza.Sabdar@Sun.COM 	(void) memset(mhp, 0, size);
12537917SReza.Sabdar@Sun.COM 
12547917SReza.Sabdar@Sun.COM 	mhp->nh_plversion = nctx->nc_plversion;
12557917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_plname, nctx->nc_plname,
12567917SReza.Sabdar@Sun.COM 	    sizeof (mhp->nh_plname));
12577917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC, sizeof (mhp->nh_magic));
12587917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
12597917SReza.Sabdar@Sun.COM 
12607917SReza.Sabdar@Sun.COM 	if ((mhp->nh_handle = zfs_open(zlibh, dataset,
12617917SReza.Sabdar@Sun.COM 	    ZFS_TYPE_DATASET)) == NULL) {
12627917SReza.Sabdar@Sun.COM 		free(mhp);
12637917SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
12647917SReza.Sabdar@Sun.COM 	}
12657917SReza.Sabdar@Sun.COM 
12667917SReza.Sabdar@Sun.COM 	/* Get all the ZFS properties */
12677917SReza.Sabdar@Sun.COM 	(void) zprop_iter(zfs_put_prop_cb, mhp, TRUE, TRUE,
12687917SReza.Sabdar@Sun.COM 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
12697917SReza.Sabdar@Sun.COM 
12707917SReza.Sabdar@Sun.COM 	/* Get user properties */
12717917SReza.Sabdar@Sun.COM 	uprops = zfs_get_user_props(mhp->nh_handle);
12727917SReza.Sabdar@Sun.COM 
12737917SReza.Sabdar@Sun.COM 	elp = nvlist_next_nvpair(uprops, NULL);
12747917SReza.Sabdar@Sun.COM 
12757917SReza.Sabdar@Sun.COM 	while (elp != NULL) {
12767917SReza.Sabdar@Sun.COM 		mpp = &mhp->nh_property[mhp->nh_count];
12777917SReza.Sabdar@Sun.COM 		if (nvpair_value_nvlist(elp, &ulist) != 0 ||
12787917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
12797917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
12807917SReza.Sabdar@Sun.COM 			zfs_close(mhp->nh_handle);
12817917SReza.Sabdar@Sun.COM 			free(mhp);
12827917SReza.Sabdar@Sun.COM 			return (-1);
12837917SReza.Sabdar@Sun.COM 		}
12847917SReza.Sabdar@Sun.COM 		if ((pname = nvpair_name(elp)) != NULL)
12857917SReza.Sabdar@Sun.COM 			(void) strlcpy(mpp->mp_name, pname, NAME_MAX);
12867917SReza.Sabdar@Sun.COM 
12877917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_value, sval, NAME_MAX);
12887917SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_source, ssrc, NAME_MAX);
12897917SReza.Sabdar@Sun.COM 		mhp->nh_count++;
12907917SReza.Sabdar@Sun.COM 		elp = nvlist_next_nvpair(uprops, elp);
12917917SReza.Sabdar@Sun.COM 	}
12927917SReza.Sabdar@Sun.COM 
12937917SReza.Sabdar@Sun.COM 	zfs_close(mhp->nh_handle);
12947917SReza.Sabdar@Sun.COM 
12957917SReza.Sabdar@Sun.COM 	if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
12967917SReza.Sabdar@Sun.COM 	    lcmd)) != NULL) {
12977917SReza.Sabdar@Sun.COM 		pp = (char *)mhp;
12987917SReza.Sabdar@Sun.COM 
12997917SReza.Sabdar@Sun.COM 		(void) memcpy(wbuf, pp, (actual_size < size) ?
13007917SReza.Sabdar@Sun.COM 		    actual_size : size);
13017917SReza.Sabdar@Sun.COM 		pp += (actual_size < size) ? actual_size : size;
13027917SReza.Sabdar@Sun.COM 
13037917SReza.Sabdar@Sun.COM 		sz = actual_size;
13047917SReza.Sabdar@Sun.COM 		while (sz < size &&
13057917SReza.Sabdar@Sun.COM 		    ((tp = get_write_buffer(size - sz, &lsize,
13067917SReza.Sabdar@Sun.COM 		    TRUE, lcmd))) != NULL) {
13077917SReza.Sabdar@Sun.COM 			(void) memcpy(tp, pp, size - sz);
13087917SReza.Sabdar@Sun.COM 			sz += lsize;
13097917SReza.Sabdar@Sun.COM 			pp += lsize;
13107917SReza.Sabdar@Sun.COM 		}
13117917SReza.Sabdar@Sun.COM 		if (sz > size) {
13127917SReza.Sabdar@Sun.COM 			tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
13137917SReza.Sabdar@Sun.COM 		}
13147917SReza.Sabdar@Sun.COM 	}
13157917SReza.Sabdar@Sun.COM 
13167917SReza.Sabdar@Sun.COM 	free(mhp);
13177917SReza.Sabdar@Sun.COM 	return (0);
13187917SReza.Sabdar@Sun.COM }
1319