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