12654012fSReza Sabdar /*
25181c2afSReza Sabdar  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3*9adfa60dSMatthew Ahrens  * Copyright (c) 2015 by Delphix. All rights reserved.
42654012fSReza Sabdar  */
52654012fSReza Sabdar 
62654012fSReza Sabdar /*
72654012fSReza Sabdar  * BSD 3 Clause License
82654012fSReza Sabdar  *
92654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
102654012fSReza Sabdar  *
112654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
122654012fSReza Sabdar  * modification, are permitted provided that the following conditions
132654012fSReza Sabdar  * are met:
142654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
152654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
162654012fSReza Sabdar  *
172654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
182654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
192654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
202654012fSReza Sabdar  *	  distribution.
212654012fSReza Sabdar  *
222654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
232654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
242654012fSReza Sabdar  *	  products derived from this software without specific prior written
252654012fSReza Sabdar  *	  permission.
262654012fSReza Sabdar  *
272654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
282654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
292654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
302654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
312654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
322654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
332654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
342654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
352654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
362654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
372654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
382654012fSReza Sabdar  */
392654012fSReza Sabdar #include <stdio.h>
402654012fSReza Sabdar #include <limits.h>
412654012fSReza Sabdar #include <time.h>
422654012fSReza Sabdar #include <sys/stat.h>
432654012fSReza Sabdar #include <unistd.h>
442654012fSReza Sabdar #include <dirent.h>
452654012fSReza Sabdar #include <pthread.h>
462654012fSReza Sabdar #include <archives.h>
472654012fSReza Sabdar #include <tlm.h>
482654012fSReza Sabdar #include <sys/fs/zfs.h>
495181c2afSReza Sabdar #include <sys/mkdev.h>
502654012fSReza Sabdar #include <libzfs.h>
51b6b15642SReza Sabdar #include <libcmdutils.h>
52b6b15642SReza Sabdar #include <pwd.h>
53b6b15642SReza Sabdar #include <grp.h>
542654012fSReza Sabdar #include "tlm_proto.h"
552654012fSReza Sabdar 
562654012fSReza Sabdar 
572654012fSReza Sabdar static char *get_write_buffer(long size,
582654012fSReza Sabdar     long *actual_size,
592654012fSReza Sabdar     boolean_t zero,
602654012fSReza Sabdar     tlm_cmd_t *);
612654012fSReza Sabdar static int output_acl_header(sec_attr_t *,
622654012fSReza Sabdar     tlm_cmd_t *);
632654012fSReza Sabdar static int output_file_header(char *name,
642654012fSReza Sabdar     char *link,
652654012fSReza Sabdar     tlm_acls_t *,
662654012fSReza Sabdar     int section,
672654012fSReza Sabdar     tlm_cmd_t *);
682654012fSReza Sabdar static int output_xattr_header(char *fname,
692654012fSReza Sabdar     char *aname,
702654012fSReza Sabdar     int fd,
712654012fSReza Sabdar     tlm_acls_t *,
722654012fSReza Sabdar     int section,
732654012fSReza Sabdar     tlm_cmd_t *);
742654012fSReza Sabdar 
752654012fSReza Sabdar extern  libzfs_handle_t *zlibh;
7642ed7838SReza Sabdar extern	mutex_t zlib_mtx;
772654012fSReza Sabdar 
785181c2afSReza Sabdar #define	S_ISPECIAL(a)	(S_ISLNK(a) || S_ISFIFO(a) || S_ISBLK(a) || \
795181c2afSReza Sabdar 	S_ISCHR(a))
802654012fSReza Sabdar 
812654012fSReza Sabdar /*
822654012fSReza Sabdar  * output_mem
832654012fSReza Sabdar  *
842654012fSReza Sabdar  * Gets a IO write buffer and copies memory to the that.
852654012fSReza Sabdar  */
862654012fSReza Sabdar static void
output_mem(tlm_cmd_t * local_commands,char * mem,int len)872654012fSReza Sabdar output_mem(tlm_cmd_t *local_commands, char *mem,
882654012fSReza Sabdar     int len)
892654012fSReza Sabdar {
902654012fSReza Sabdar 	long actual_size, rec_size;
912654012fSReza Sabdar 	char *rec;
922654012fSReza Sabdar 
932654012fSReza Sabdar 	while (len > 0) {
942654012fSReza Sabdar 		rec = get_write_buffer(len, &actual_size,
952654012fSReza Sabdar 		    FALSE, local_commands);
962654012fSReza Sabdar 		rec_size = min(actual_size, len);
972654012fSReza Sabdar 		(void) memcpy(rec, mem, rec_size);
982654012fSReza Sabdar 		mem += rec_size;
992654012fSReza Sabdar 		len -= rec_size;
1002654012fSReza Sabdar 	}
1012654012fSReza Sabdar }
1022654012fSReza Sabdar 
1032654012fSReza Sabdar /*
1042654012fSReza Sabdar  * tlm_output_dir
1052654012fSReza Sabdar  *
1062654012fSReza Sabdar  * Put the directory information into the output buffers.
1072654012fSReza Sabdar  */
1082654012fSReza Sabdar int
tlm_output_dir(char * name,tlm_acls_t * tlm_acls,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)1092654012fSReza Sabdar tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
1102654012fSReza Sabdar     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1112654012fSReza Sabdar {
1122654012fSReza Sabdar 	u_longlong_t pos;
1132654012fSReza Sabdar 
1142654012fSReza Sabdar 	/*
1152654012fSReza Sabdar 	 * Send the node or path history of the directory itself.
1162654012fSReza Sabdar 	 */
1172654012fSReza Sabdar 	pos = tlm_get_data_offset(local_commands);
1182654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
1192654012fSReza Sabdar 	(void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
1202654012fSReza Sabdar 	(void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
1212654012fSReza Sabdar 	/* fhdir_cb is handled in ndmpd_tar3.c */
1222654012fSReza Sabdar 
1232654012fSReza Sabdar 	(void) output_acl_header(&tlm_acls->acl_info,
1242654012fSReza Sabdar 	    local_commands);
1252654012fSReza Sabdar 	(void) output_file_header(name, "", tlm_acls, 0,
1262654012fSReza Sabdar 	    local_commands);
1272654012fSReza Sabdar 
1282654012fSReza Sabdar 	return (0);
1292654012fSReza Sabdar }
1302654012fSReza Sabdar 
1312654012fSReza Sabdar /*
1322654012fSReza Sabdar  * tar_putdir
1332654012fSReza Sabdar  *
1342654012fSReza Sabdar  * Main dir backup function for tar
1352654012fSReza Sabdar  */
1362654012fSReza Sabdar int
tar_putdir(char * name,tlm_acls_t * tlm_acls,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)1372654012fSReza Sabdar tar_putdir(char *name, tlm_acls_t *tlm_acls,
1382654012fSReza Sabdar     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1392654012fSReza Sabdar {
1402654012fSReza Sabdar 	int rv;
1412654012fSReza Sabdar 
1422654012fSReza Sabdar 	rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats);
1432654012fSReza Sabdar 	return (rv < 0 ? rv : 0);
1442654012fSReza Sabdar }
1452654012fSReza Sabdar 
1462654012fSReza Sabdar /*
1472654012fSReza Sabdar  * output_acl_header
1482654012fSReza Sabdar  *
1492654012fSReza Sabdar  * output the ACL header record and data
1502654012fSReza Sabdar  */
1512654012fSReza Sabdar static int
output_acl_header(sec_attr_t * acl_info,tlm_cmd_t * local_commands)1522654012fSReza Sabdar output_acl_header(sec_attr_t *acl_info,
1532654012fSReza Sabdar     tlm_cmd_t *local_commands)
1542654012fSReza Sabdar {
1552654012fSReza Sabdar 	long	actual_size;
1562654012fSReza Sabdar 	tlm_tar_hdr_t *tar_hdr;
1572654012fSReza Sabdar 	long	acl_size;
1582654012fSReza Sabdar 
1592654012fSReza Sabdar 	if ((acl_info == NULL) || (*acl_info->attr_info == '\0'))
1602654012fSReza Sabdar 		return (0);
1612654012fSReza Sabdar 
1622654012fSReza Sabdar 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
1632654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
1642654012fSReza Sabdar 	if (!tar_hdr)
1652654012fSReza Sabdar 		return (0);
1662654012fSReza Sabdar 
1672654012fSReza Sabdar 	tar_hdr->th_linkflag = LF_ACL;
1682654012fSReza Sabdar 	acl_info->attr_type = UFSD_ACL;
1692654012fSReza Sabdar 	(void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len),
1702654012fSReza Sabdar 	    "%06o", strlen(acl_info->attr_info));
1712654012fSReza Sabdar 
1722654012fSReza Sabdar 	acl_size = sizeof (*acl_info);
1732654012fSReza Sabdar 	(void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE);
1742654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
1752654012fSReza Sabdar 	    acl_size);
1762654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
1772654012fSReza Sabdar 	    0444);
1782654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0);
1792654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0);
1802654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
1812654012fSReza Sabdar 	    "%011o ", 0);
1822654012fSReza Sabdar 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
1832654012fSReza Sabdar 	    sizeof (tar_hdr->th_magic));
1842654012fSReza Sabdar 
1852654012fSReza Sabdar 	tlm_build_header_checksum(tar_hdr);
1862654012fSReza Sabdar 
1872654012fSReza Sabdar 	(void) output_mem(local_commands, (void *)acl_info, acl_size);
1882654012fSReza Sabdar 	return (0);
1892654012fSReza Sabdar }
1902654012fSReza Sabdar 
1912654012fSReza Sabdar /*
1922654012fSReza Sabdar  * output_humongus_header
1932654012fSReza Sabdar  *
1942654012fSReza Sabdar  * output a special header record for HUGE files
1952654012fSReza Sabdar  * output is:	1) a TAR "HUGE" header redord
1962654012fSReza Sabdar  * 		2) a "file" of size, name
1972654012fSReza Sabdar  */
1982654012fSReza Sabdar static int
output_humongus_header(char * fullname,longlong_t file_size,tlm_cmd_t * local_commands)1992654012fSReza Sabdar output_humongus_header(char *fullname, longlong_t file_size,
2002654012fSReza Sabdar     tlm_cmd_t *local_commands)
2012654012fSReza Sabdar {
2022654012fSReza Sabdar 	char	*buf;
2032654012fSReza Sabdar 	int	len;
2042654012fSReza Sabdar 	long	actual_size;
2052654012fSReza Sabdar 	tlm_tar_hdr_t *tar_hdr;
2062654012fSReza Sabdar 
2072654012fSReza Sabdar 	/*
2082654012fSReza Sabdar 	 * buf will contain: "%llu %s":
2092654012fSReza Sabdar 	 * - 20 is the maximum length of 'ulong_tlong' decimal notation.
2102654012fSReza Sabdar 	 * - The first '1' is for the ' ' between the "%llu" and the fullname.
2112654012fSReza Sabdar 	 * - The last '1' is for the null-terminator of fullname.
2122654012fSReza Sabdar 	 */
2132654012fSReza Sabdar 	len = 20 + 1 + strlen(fullname) + 1;
2142654012fSReza Sabdar 
2152654012fSReza Sabdar 	if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
2162654012fSReza Sabdar 		return (-1);
2172654012fSReza Sabdar 
2182654012fSReza Sabdar 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2192654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
2202654012fSReza Sabdar 	if (!tar_hdr) {
2212654012fSReza Sabdar 		free(buf);
2222654012fSReza Sabdar 		return (0);
2232654012fSReza Sabdar 	}
2242654012fSReza Sabdar 
2252654012fSReza Sabdar 	tar_hdr->th_linkflag = LF_HUMONGUS;
2262654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2272654012fSReza Sabdar 	    len);
2282654012fSReza Sabdar 	tlm_build_header_checksum(tar_hdr);
2292654012fSReza Sabdar 	(void) snprintf(buf, len, "%lld %s", file_size, fullname);
2302654012fSReza Sabdar 	(void) output_mem(local_commands, buf, len);
2312654012fSReza Sabdar 
2322654012fSReza Sabdar 	free(buf);
2332654012fSReza Sabdar 	return (0);
2342654012fSReza Sabdar }
2352654012fSReza Sabdar 
2362654012fSReza Sabdar 
2372654012fSReza Sabdar /*
2382654012fSReza Sabdar  * output_xattr_header
2392654012fSReza Sabdar  *
2402654012fSReza Sabdar  * output the TAR header record for extended attributes
2412654012fSReza Sabdar  */
2422654012fSReza Sabdar static int
output_xattr_header(char * fname,char * aname,int fd,tlm_acls_t * tlm_acls,int section,tlm_cmd_t * local_commands)2432654012fSReza Sabdar output_xattr_header(char *fname, char *aname, int fd,
2442654012fSReza Sabdar     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
2452654012fSReza Sabdar {
2462654012fSReza Sabdar 	struct stat64 *attr = &tlm_acls->acl_attr;
2472654012fSReza Sabdar 	struct xattr_hdr *xhdr;
2482654012fSReza Sabdar 	struct xattr_buf *xbuf;
2492654012fSReza Sabdar 	tlm_tar_hdr_t *tar_hdr;
2502654012fSReza Sabdar 	long	actual_size;
2512654012fSReza Sabdar 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
2522654012fSReza Sabdar 	int	hsize;
2532654012fSReza Sabdar 	int	comlen;
2542654012fSReza Sabdar 	int	namesz;
2552654012fSReza Sabdar 
2562654012fSReza Sabdar 	if (section_name == NULL)
2572654012fSReza Sabdar 		return (-TLM_NO_SCRATCH_SPACE);
2582654012fSReza Sabdar 
2592654012fSReza Sabdar 	if (fstat64(fd, attr) == -1) {
2602654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "output_file_header stat failed.");
2612654012fSReza Sabdar 		free(section_name);
2622654012fSReza Sabdar 		return (-TLM_OPEN_ERR);
2632654012fSReza Sabdar 	}
2642654012fSReza Sabdar 
2652654012fSReza Sabdar 	/*
2662654012fSReza Sabdar 	 * if the file has to go out in sections,
2672654012fSReza Sabdar 	 * we must mung the name.
2682654012fSReza Sabdar 	 */
2692654012fSReza Sabdar 	if (section == 0) {
2702654012fSReza Sabdar 		(void) snprintf(section_name, TLM_MAX_PATH_NAME,
2712654012fSReza Sabdar 		    "/dev/null/%s.hdr", aname);
2722654012fSReza Sabdar 	} else {
2732654012fSReza Sabdar 		(void) snprintf(section_name,
2742654012fSReza Sabdar 		    TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
2752654012fSReza Sabdar 	}
2762654012fSReza Sabdar 	namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
2772654012fSReza Sabdar 	hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
2782654012fSReza Sabdar 	comlen = namesz + sizeof (struct xattr_buf);
2792654012fSReza Sabdar 
2802654012fSReza Sabdar 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2812654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
2822654012fSReza Sabdar 	if (!tar_hdr) {
2832654012fSReza Sabdar 		free(section_name);
2842654012fSReza Sabdar 		return (0);
2852654012fSReza Sabdar 	}
2862654012fSReza Sabdar 
2872654012fSReza Sabdar 	(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
2882654012fSReza Sabdar 
2892654012fSReza Sabdar 	tar_hdr->th_linkflag = LF_XATTR;
2902654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2912654012fSReza Sabdar 	    hsize);
2922654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
2932654012fSReza Sabdar 	    attr->st_mode & 07777);
2942654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
2952654012fSReza Sabdar 	    attr->st_uid);
2962654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
2972654012fSReza Sabdar 	    attr->st_gid);
2982654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
2992654012fSReza Sabdar 	    attr->st_mtime);
3002654012fSReza Sabdar 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
3012654012fSReza Sabdar 	    sizeof (tar_hdr->th_magic));
3022654012fSReza Sabdar 
303b6b15642SReza Sabdar 	NDMP_LOG(LOG_DEBUG, "xattr_hdr: %s size %d mode %06o uid %d gid %d",
304b6b15642SReza Sabdar 	    aname, hsize, attr->st_mode & 07777, attr->st_uid, attr->st_gid);
305b6b15642SReza Sabdar 
3062654012fSReza Sabdar 	tlm_build_header_checksum(tar_hdr);
3072654012fSReza Sabdar 
3082654012fSReza Sabdar 	xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE,
3092654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
3102654012fSReza Sabdar 	if (!xhdr) {
3112654012fSReza Sabdar 		free(section_name);
3122654012fSReza Sabdar 		return (0);
3132654012fSReza Sabdar 	}
3142654012fSReza Sabdar 
3152654012fSReza Sabdar 	(void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s",
3162654012fSReza Sabdar 	    XATTR_ARCH_VERS);
3172654012fSReza Sabdar 	(void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d",
3182654012fSReza Sabdar 	    sizeof (xhdr->h_size) - 1, hsize);
3192654012fSReza Sabdar 	(void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len),
3202654012fSReza Sabdar 	    "%0*d", sizeof (xhdr->h_component_len) - 1, comlen);
3212654012fSReza Sabdar 	(void) snprintf(xhdr->h_link_component_len,
3222654012fSReza Sabdar 	    sizeof (xhdr->h_link_component_len), "%0*d",
3232654012fSReza Sabdar 	    sizeof (xhdr->h_link_component_len) - 1, 0);
3242654012fSReza Sabdar 
3252654012fSReza Sabdar 	xbuf = (struct xattr_buf *)(((caddr_t)xhdr) +
3262654012fSReza Sabdar 	    sizeof (struct xattr_hdr));
3272654012fSReza Sabdar 	(void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d",
3282654012fSReza Sabdar 	    sizeof (xbuf->h_namesz) - 1, namesz);
3292654012fSReza Sabdar 
3302654012fSReza Sabdar 	/* No support for links in extended attributes */
3312654012fSReza Sabdar 	xbuf->h_typeflag = LF_NORMAL;
3322654012fSReza Sabdar 
3332654012fSReza Sabdar 	(void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE);
3342654012fSReza Sabdar 	(void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname,
3352654012fSReza Sabdar 	    TLM_NAME_SIZE);
3362654012fSReza Sabdar 
3372654012fSReza Sabdar 	free(section_name);
3382654012fSReza Sabdar 	return (0);
3392654012fSReza Sabdar }
3402654012fSReza Sabdar 
3412654012fSReza Sabdar 
3422654012fSReza Sabdar /*
3432654012fSReza Sabdar  * output_file_header
3442654012fSReza Sabdar  *
3452654012fSReza Sabdar  * output the TAR header record
3462654012fSReza Sabdar  */
3472654012fSReza Sabdar static int
output_file_header(char * name,char * link,tlm_acls_t * tlm_acls,int section,tlm_cmd_t * local_commands)3482654012fSReza Sabdar output_file_header(char *name, char *link,
3492654012fSReza Sabdar     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
3502654012fSReza Sabdar {
3512654012fSReza Sabdar 	static	longlong_t file_count = 0;
3522654012fSReza Sabdar 	struct stat64 *attr = &tlm_acls->acl_attr;
3532654012fSReza Sabdar 	tlm_tar_hdr_t *tar_hdr;
3542654012fSReza Sabdar 	long	actual_size;
3552654012fSReza Sabdar 	boolean_t long_name = FALSE;
3562654012fSReza Sabdar 	boolean_t long_link = FALSE;
3572654012fSReza Sabdar 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
3582654012fSReza Sabdar 	int	nmlen, lnklen;
359b6b15642SReza Sabdar 	uid_t uid;
360b6b15642SReza Sabdar 	gid_t gid;
361b6b15642SReza Sabdar 	char *uname = "";
362b6b15642SReza Sabdar 	char *gname = "";
363b6b15642SReza Sabdar 	struct passwd *pwd;
364b6b15642SReza Sabdar 	struct group *grp;
3652654012fSReza Sabdar 
3662654012fSReza Sabdar 	if (section_name == NULL)
3672654012fSReza Sabdar 		return (-TLM_NO_SCRATCH_SPACE);
3682654012fSReza Sabdar 
3692654012fSReza Sabdar 	/*
3702654012fSReza Sabdar 	 * if the file has to go out in sections,
3712654012fSReza Sabdar 	 * we must mung the name.
3722654012fSReza Sabdar 	 */
3732654012fSReza Sabdar 	if (section == 0) {
3742654012fSReza Sabdar 		(void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
3752654012fSReza Sabdar 	} else {
3762654012fSReza Sabdar 		(void) snprintf(section_name,
3772654012fSReza Sabdar 		    TLM_MAX_PATH_NAME, "%s.%03d", name, section);
3782654012fSReza Sabdar 	}
3792654012fSReza Sabdar 
380b6b15642SReza Sabdar 	if ((pwd = getpwuid(attr->st_uid)) != NULL)
381b6b15642SReza Sabdar 		uname = pwd->pw_name;
382b6b15642SReza Sabdar 	if ((grp = getgrgid(attr->st_gid)) != NULL)
383b6b15642SReza Sabdar 		gname = grp->gr_name;
384b6b15642SReza Sabdar 
385b6b15642SReza Sabdar 	if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR)
386b6b15642SReza Sabdar 		uid = UID_NOBODY;
387b6b15642SReza Sabdar 	if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR)
388b6b15642SReza Sabdar 		gid = GID_NOBODY;
389b6b15642SReza Sabdar 
3902654012fSReza Sabdar 	nmlen = strlen(section_name);
3912654012fSReza Sabdar 	if (nmlen >= NAMSIZ) {
3922654012fSReza Sabdar 		/*
3932654012fSReza Sabdar 		 * file name is too big, it must go out
3942654012fSReza Sabdar 		 * in its own data file
3952654012fSReza Sabdar 		 */
3962654012fSReza Sabdar 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
3972654012fSReza Sabdar 		    &actual_size, TRUE, local_commands);
3982654012fSReza Sabdar 		if (!tar_hdr) {
3992654012fSReza Sabdar 			free(section_name);
4002654012fSReza Sabdar 			return (0);
4012654012fSReza Sabdar 		}
4022654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_name,
4032654012fSReza Sabdar 		    sizeof (tar_hdr->th_name),
4042654012fSReza Sabdar 		    "%s%08qd.fil",
4052654012fSReza Sabdar 		    LONGNAME_PREFIX,
4062654012fSReza Sabdar 		    file_count++);
4072654012fSReza Sabdar 
4082654012fSReza Sabdar 		tar_hdr->th_linkflag = LF_LONGNAME;
4092654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
4102654012fSReza Sabdar 		    "%011o ", nmlen);
4112654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
4122654012fSReza Sabdar 		    "%06o ", attr->st_mode & 07777);
4132654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
414b6b15642SReza Sabdar 		    "%06o ", uid);
4152654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
416b6b15642SReza Sabdar 		    "%06o ", gid);
417b6b15642SReza Sabdar 		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
418b6b15642SReza Sabdar 		    "%.31s", uname);
419b6b15642SReza Sabdar 		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
420b6b15642SReza Sabdar 		    "%.31s", gname);
4212654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
4222654012fSReza Sabdar 		    "%011o ", attr->st_mtime);
4232654012fSReza Sabdar 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4242654012fSReza Sabdar 		    sizeof (tar_hdr->th_magic));
4252654012fSReza Sabdar 
4262654012fSReza Sabdar 		tlm_build_header_checksum(tar_hdr);
4272654012fSReza Sabdar 
4282654012fSReza Sabdar 		(void) output_mem(local_commands,
4292654012fSReza Sabdar 		    (void *)section_name, nmlen);
4302654012fSReza Sabdar 		long_name = TRUE;
4312654012fSReza Sabdar 	}
4322654012fSReza Sabdar 
4332654012fSReza Sabdar 	lnklen = strlen(link);
4342654012fSReza Sabdar 	if (lnklen >= NAMSIZ) {
4352654012fSReza Sabdar 		/*
4362654012fSReza Sabdar 		 * link name is too big, it must go out
4372654012fSReza Sabdar 		 * in its own data file
4382654012fSReza Sabdar 		 */
4392654012fSReza Sabdar 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4402654012fSReza Sabdar 		    &actual_size, TRUE, local_commands);
4412654012fSReza Sabdar 		if (!tar_hdr) {
4422654012fSReza Sabdar 			free(section_name);
4432654012fSReza Sabdar 			return (0);
4442654012fSReza Sabdar 		}
4452654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_linkname,
4462654012fSReza Sabdar 		    sizeof (tar_hdr->th_name),
4472654012fSReza Sabdar 		    "%s%08qd.slk",
4482654012fSReza Sabdar 		    LONGNAME_PREFIX,
4492654012fSReza Sabdar 		    file_count++);
4502654012fSReza Sabdar 
4512654012fSReza Sabdar 		tar_hdr->th_linkflag = LF_LONGLINK;
4522654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
4532654012fSReza Sabdar 		    "%011o ", lnklen);
4542654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
4552654012fSReza Sabdar 		    "%06o ", attr->st_mode & 07777);
4562654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
457b6b15642SReza Sabdar 		    "%06o ", uid);
4582654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
459b6b15642SReza Sabdar 		    "%06o ", gid);
460b6b15642SReza Sabdar 		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
461b6b15642SReza Sabdar 		    "%.31s", uname);
462b6b15642SReza Sabdar 		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
463b6b15642SReza Sabdar 		    "%.31s", gname);
4642654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
4652654012fSReza Sabdar 		    "%011o ", attr->st_mtime);
4662654012fSReza Sabdar 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4672654012fSReza Sabdar 		    sizeof (tar_hdr->th_magic));
4682654012fSReza Sabdar 
4692654012fSReza Sabdar 		tlm_build_header_checksum(tar_hdr);
4702654012fSReza Sabdar 
4712654012fSReza Sabdar 		(void) output_mem(local_commands, (void *)link,
4722654012fSReza Sabdar 		    lnklen);
4732654012fSReza Sabdar 		long_link = TRUE;
4742654012fSReza Sabdar 	}
4752654012fSReza Sabdar 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4762654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
4772654012fSReza Sabdar 	if (!tar_hdr) {
4782654012fSReza Sabdar 		free(section_name);
4792654012fSReza Sabdar 		return (0);
4802654012fSReza Sabdar 	}
4812654012fSReza Sabdar 	if (long_name) {
4822654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_name,
4832654012fSReza Sabdar 		    sizeof (tar_hdr->th_name),
4842654012fSReza Sabdar 		    "%s%08qd.fil",
4852654012fSReza Sabdar 		    LONGNAME_PREFIX,
4862654012fSReza Sabdar 		    file_count++);
4872654012fSReza Sabdar 	} else {
4882654012fSReza Sabdar 		(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
4892654012fSReza Sabdar 	}
4902654012fSReza Sabdar 
4912654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "long_link: %s [%s]", long_link ? "TRUE" : "FALSE",
4922654012fSReza Sabdar 	    link);
4932654012fSReza Sabdar 
4942654012fSReza Sabdar 	if (long_link) {
4952654012fSReza Sabdar 		(void) snprintf(tar_hdr->th_linkname,
4962654012fSReza Sabdar 		    sizeof (tar_hdr->th_name),
4972654012fSReza Sabdar 		    "%s%08qd.slk",
4982654012fSReza Sabdar 		    LONGNAME_PREFIX,
4992654012fSReza Sabdar 		    file_count++);
5002654012fSReza Sabdar 	} else {
5012654012fSReza Sabdar 		(void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
5022654012fSReza Sabdar 	}
5035181c2afSReza Sabdar 	switch (attr->st_mode & S_IFMT) {
5045181c2afSReza Sabdar 	case S_IFDIR:
5052654012fSReza Sabdar 		tar_hdr->th_linkflag = LF_DIR;
5065181c2afSReza Sabdar 		break;
5075181c2afSReza Sabdar 	case S_IFIFO:
5082654012fSReza Sabdar 		tar_hdr->th_linkflag = LF_FIFO;
5095181c2afSReza Sabdar 		break;
5105181c2afSReza Sabdar 	case S_IFBLK:
5115181c2afSReza Sabdar 	case S_IFCHR:
5125181c2afSReza Sabdar 		if (S_ISBLK(attr->st_mode))
5135181c2afSReza Sabdar 			tar_hdr->th_linkflag = LF_BLK;
5145181c2afSReza Sabdar 		else
5155181c2afSReza Sabdar 			tar_hdr->th_linkflag = LF_CHR;
5165181c2afSReza Sabdar 		(void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor,
5175181c2afSReza Sabdar 		    sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ",
5185181c2afSReza Sabdar 		    major(attr->st_rdev));
5195181c2afSReza Sabdar 		(void) snprintf(tar_hdr->th_shared.th_dev.th_devminor,
5205181c2afSReza Sabdar 		    sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ",
5215181c2afSReza Sabdar 		    minor(attr->st_rdev));
5225181c2afSReza Sabdar 		break;
5235181c2afSReza Sabdar 	default:
5245181c2afSReza Sabdar 		if (attr->st_nlink > 1) {
5255181c2afSReza Sabdar 			/* mark file with hardlink LF_LINK */
5265181c2afSReza Sabdar 			tar_hdr->th_linkflag = LF_LINK;
5275181c2afSReza Sabdar 			(void) snprintf(tar_hdr->th_shared.th_hlink_ino,
5285181c2afSReza Sabdar 			    sizeof (tar_hdr->th_shared.th_hlink_ino),
5295181c2afSReza Sabdar 			    "%011llo ", attr->st_ino);
5305181c2afSReza Sabdar 		} else {
5315181c2afSReza Sabdar 			tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL :
5325181c2afSReza Sabdar 			    LF_SYMLINK;
5335181c2afSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "linkflag: '%c'",
5345181c2afSReza Sabdar 			    tar_hdr->th_linkflag);
5355181c2afSReza Sabdar 		}
5362654012fSReza Sabdar 	}
5372654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
5382654012fSReza Sabdar 	    (long)attr->st_size);
5392654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
5402654012fSReza Sabdar 	    attr->st_mode & 07777);
5412654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
542b6b15642SReza Sabdar 	    uid);
5432654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
544b6b15642SReza Sabdar 	    gid);
545b6b15642SReza Sabdar 	(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
546b6b15642SReza Sabdar 	    uname);
547b6b15642SReza Sabdar 	(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
548b6b15642SReza Sabdar 	    gname);
5492654012fSReza Sabdar 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
5502654012fSReza Sabdar 	    attr->st_mtime);
5512654012fSReza Sabdar 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
5522654012fSReza Sabdar 	    sizeof (tar_hdr->th_magic));
5532654012fSReza Sabdar 
5542654012fSReza Sabdar 	tlm_build_header_checksum(tar_hdr);
5552654012fSReza Sabdar 	if (long_name || long_link) {
5562654012fSReza Sabdar 		if (file_count > 99999990) {
5572654012fSReza Sabdar 			file_count = 0;
5582654012fSReza Sabdar 		}
5592654012fSReza Sabdar 	}
5602654012fSReza Sabdar 	free(section_name);
5612654012fSReza Sabdar 	return (0);
5622654012fSReza Sabdar }
5632654012fSReza Sabdar 
5642654012fSReza Sabdar 
5652654012fSReza Sabdar /*
5662654012fSReza Sabdar  * tlm_readlink
5672654012fSReza Sabdar  *
5682654012fSReza Sabdar  * Read where the softlink points to.  Read the link in the checkpointed
5692654012fSReza Sabdar  * path if the backup is being done on a checkpointed file system.
5702654012fSReza Sabdar  */
5712654012fSReza Sabdar static int
tlm_readlink(char * nm,char * snap,char * buf,int bufsize)5722654012fSReza Sabdar tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
5732654012fSReza Sabdar {
5742654012fSReza Sabdar 	int len;
5752654012fSReza Sabdar 
5762654012fSReza Sabdar 	if ((len = readlink(snap, buf, bufsize)) >= 0) {
5772654012fSReza Sabdar 		/*
5782654012fSReza Sabdar 		 * realink(2) doesn't null terminate the link name.  We must
5792654012fSReza Sabdar 		 * do it here.
5802654012fSReza Sabdar 		 */
5812654012fSReza Sabdar 		buf[len] = '\0';
5822654012fSReza Sabdar 	} else {
5832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Error %d reading softlink of [%s]",
5842654012fSReza Sabdar 		    errno, nm);
5852654012fSReza Sabdar 		buf[0] = '\0';
5862654012fSReza Sabdar 
5872654012fSReza Sabdar 		/* Backup the link if the destination missing */
5882654012fSReza Sabdar 		if (errno == ENOENT)
5892654012fSReza Sabdar 			return (0);
5902654012fSReza Sabdar 
5912654012fSReza Sabdar 	}
5922654012fSReza Sabdar 
5932654012fSReza Sabdar 	return (len);
5942654012fSReza Sabdar }
5952654012fSReza Sabdar 
596b6b15642SReza Sabdar /*
597b6b15642SReza Sabdar  * Read the system attribute file in a single buffer to write
598b6b15642SReza Sabdar  * it as a single write. A partial write to system attribute would
599b6b15642SReza Sabdar  * cause an EINVAL on write.
600b6b15642SReza Sabdar  */
601b6b15642SReza Sabdar static char *
get_write_one_buf(char * buf,char * rec,int buf_size,int rec_size,tlm_cmd_t * lc)602b6b15642SReza Sabdar get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
603b6b15642SReza Sabdar     tlm_cmd_t *lc)
604b6b15642SReza Sabdar {
605b6b15642SReza Sabdar 	int len;
606b6b15642SReza Sabdar 	long write_size;
607b6b15642SReza Sabdar 
608b6b15642SReza Sabdar 	if (rec_size > buf_size)
609b6b15642SReza Sabdar 		return (rec);
610b6b15642SReza Sabdar 
611b6b15642SReza Sabdar 	len = rec_size;
612b6b15642SReza Sabdar 	(void) memcpy(rec, buf, len);
613b6b15642SReza Sabdar 	buf += len;
614b6b15642SReza Sabdar 	while (rec_size < buf_size) {
615b6b15642SReza Sabdar 		rec = get_write_buffer(buf_size - rec_size,
616b6b15642SReza Sabdar 		    &write_size, FALSE, lc);
617b6b15642SReza Sabdar 		if (!rec)
618b6b15642SReza Sabdar 			return (0);
619b6b15642SReza Sabdar 
620b6b15642SReza Sabdar 		len = min(buf_size - rec_size, write_size);
621b6b15642SReza Sabdar 		(void) memcpy(rec, buf, len);
622b6b15642SReza Sabdar 		rec_size += len;
623b6b15642SReza Sabdar 		buf += len;
624b6b15642SReza Sabdar 	}
625b6b15642SReza Sabdar 	return (rec);
626b6b15642SReza Sabdar }
627b6b15642SReza Sabdar 
6282654012fSReza Sabdar 
6292654012fSReza Sabdar /*
6302654012fSReza Sabdar  * tlm_output_xattr
6312654012fSReza Sabdar  *
6322654012fSReza Sabdar  * Put this file into the output buffers.
6332654012fSReza Sabdar  */
6342654012fSReza Sabdar /*ARGSUSED*/
6352654012fSReza Sabdar longlong_t
tlm_output_xattr(char * dir,char * name,char * chkdir,tlm_acls_t * tlm_acls,tlm_commands_t * commands,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)6362654012fSReza Sabdar tlm_output_xattr(char  *dir, char *name, char *chkdir,
6372654012fSReza Sabdar     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
6382654012fSReza Sabdar     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
6392654012fSReza Sabdar {
6402654012fSReza Sabdar 	char	*fullname;		/* directory + name */
6412654012fSReza Sabdar 	char	*snapname;		/* snapshot name */
6422654012fSReza Sabdar 	int	section;		/* section of a huge file */
6432654012fSReza Sabdar 	int	fd;
6440fd80060SReza Sabdar 	int	afd = 0;
6452654012fSReza Sabdar 	longlong_t seek_spot = 0;	/* location in the file */
6462654012fSReza Sabdar 					/* for Multi Volume record */
6472654012fSReza Sabdar 	u_longlong_t pos;
6482654012fSReza Sabdar 	DIR *dp;
6492654012fSReza Sabdar 	struct dirent *dtp;
6502654012fSReza Sabdar 	char *attrname;
6512654012fSReza Sabdar 	char *fnamep;
6522654012fSReza Sabdar 	int rv = 0;
6532654012fSReza Sabdar 
6545181c2afSReza Sabdar 	if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
6552654012fSReza Sabdar 		return (TLM_NO_SOURCE_FILE);
656295e611fSReza Sabdar 	}
6572654012fSReza Sabdar 
6582654012fSReza Sabdar 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
6592654012fSReza Sabdar 	if (fullname == NULL) {
6602654012fSReza Sabdar 		free(fullname);
6612654012fSReza Sabdar 		return (-TLM_NO_SCRATCH_SPACE);
6622654012fSReza Sabdar 	}
6632654012fSReza Sabdar 
6642654012fSReza Sabdar 	if (!tlm_cat_path(fullname, dir, name)) {
6652654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6662654012fSReza Sabdar 		free(fullname);
6672654012fSReza Sabdar 		return (-TLM_NO_SCRATCH_SPACE);
6682654012fSReza Sabdar 	}
6692654012fSReza Sabdar 
670b6b15642SReza Sabdar 	if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
671b6b15642SReza Sabdar 	    sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
6722654012fSReza Sabdar 		free(fullname);
6732654012fSReza Sabdar 		return (0);
6742654012fSReza Sabdar 	}
6752654012fSReza Sabdar 
6762654012fSReza Sabdar 	attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
6772654012fSReza Sabdar 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
6782654012fSReza Sabdar 	if (attrname == NULL || snapname == NULL) {
6792654012fSReza Sabdar 		rv = -TLM_NO_SCRATCH_SPACE;
6802654012fSReza Sabdar 		goto err_out;
6812654012fSReza Sabdar 	}
6822654012fSReza Sabdar 
6832654012fSReza Sabdar 	if (!tlm_cat_path(snapname, chkdir, name)) {
6842654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6852654012fSReza Sabdar 		rv = -TLM_NO_SCRATCH_SPACE;
6862654012fSReza Sabdar 		goto err_out;
6872654012fSReza Sabdar 	}
6882654012fSReza Sabdar 
6892654012fSReza Sabdar 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
6902654012fSReza Sabdar 
6912654012fSReza Sabdar 	/*
6922654012fSReza Sabdar 	 * Open the file for reading.
6932654012fSReza Sabdar 	 */
694b6b15642SReza Sabdar 	fd = attropen(fnamep, ".", O_RDONLY);
6952654012fSReza Sabdar 	if (fd == -1) {
696b6b15642SReza Sabdar 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s][%s]",
697b6b15642SReza Sabdar 		    fullname, fnamep);
6982654012fSReza Sabdar 		rv = TLM_NO_SOURCE_FILE;
6992654012fSReza Sabdar 		goto err_out;
7002654012fSReza Sabdar 	}
7012654012fSReza Sabdar 
7022654012fSReza Sabdar 	pos = tlm_get_data_offset(local_commands);
7032654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
7042654012fSReza Sabdar 
7052654012fSReza Sabdar 	section = 0;
7062654012fSReza Sabdar 
7072654012fSReza Sabdar 	dp = (DIR *)fdopendir(fd);
7082654012fSReza Sabdar 	if (dp == NULL) {
7092654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
7102654012fSReza Sabdar 		(void) close(fd);
7112654012fSReza Sabdar 		rv = TLM_NO_SOURCE_FILE;
7122654012fSReza Sabdar 		goto err_out;
7132654012fSReza Sabdar 	}
7142654012fSReza Sabdar 
7152654012fSReza Sabdar 	while ((dtp = readdir(dp)) != NULL) {
7162654012fSReza Sabdar 		int section_size;
7172654012fSReza Sabdar 
7182654012fSReza Sabdar 		if (*dtp->d_name == '.')
7192654012fSReza Sabdar 			continue;
7202654012fSReza Sabdar 
721b6b15642SReza Sabdar 		if (sysattr_rdonly(dtp->d_name))
722b6b15642SReza Sabdar 			continue;
723b6b15642SReza Sabdar 
7240fd80060SReza Sabdar 		afd = attropen(fnamep, dtp->d_name, O_RDONLY);
7250fd80060SReza Sabdar 		if (afd == -1) {
7262654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
727b6b15642SReza Sabdar 			    "problem(%d) opening xattr file [%s][%s]", errno,
728b6b15642SReza Sabdar 			    fullname, fnamep);
7292654012fSReza Sabdar 			goto tear_down;
7302654012fSReza Sabdar 		}
7312654012fSReza Sabdar 
7320fd80060SReza Sabdar 		(void) output_xattr_header(fullname, dtp->d_name, afd,
7332654012fSReza Sabdar 		    tlm_acls, section, local_commands);
7342654012fSReza Sabdar 		(void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
7352654012fSReza Sabdar 		    dtp->d_name);
7362654012fSReza Sabdar 		(void) output_file_header(attrname, "", tlm_acls, 0,
7372654012fSReza Sabdar 		    local_commands);
7382654012fSReza Sabdar 
7392654012fSReza Sabdar 		section_size = (long)llmin(tlm_acls->acl_attr.st_size,
7402654012fSReza Sabdar 		    (longlong_t)TLM_MAX_TAR_IMAGE);
7412654012fSReza Sabdar 
7422654012fSReza Sabdar 		/* We only can read upto one section extended attribute */
7432654012fSReza Sabdar 		while (section_size > 0) {
7442654012fSReza Sabdar 			char	*buf;
7452654012fSReza Sabdar 			long	actual_size;
7462654012fSReza Sabdar 			int	read_size;
747b6b15642SReza Sabdar 			int sysattr_read = 0;
748b6b15642SReza Sabdar 			char *rec;
749b6b15642SReza Sabdar 			int size;
7502654012fSReza Sabdar 
7512654012fSReza Sabdar 			/*
7522654012fSReza Sabdar 			 * check for Abort commands
7532654012fSReza Sabdar 			 */
7542654012fSReza Sabdar 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7552654012fSReza Sabdar 				local_commands->tc_writer = TLM_ABORT;
7562654012fSReza Sabdar 				goto tear_down;
7572654012fSReza Sabdar 			}
7582654012fSReza Sabdar 
7592654012fSReza Sabdar 			local_commands->tc_buffers->tbs_buffer[
7602654012fSReza Sabdar 			    local_commands->tc_buffers->tbs_buffer_in].
7612654012fSReza Sabdar 			    tb_file_size = section_size;
7622654012fSReza Sabdar 			local_commands->tc_buffers->tbs_buffer[
7632654012fSReza Sabdar 			    local_commands->tc_buffers->tbs_buffer_in].
7642654012fSReza Sabdar 			    tb_seek_spot = seek_spot;
7652654012fSReza Sabdar 
7662654012fSReza Sabdar 			buf = get_write_buffer(section_size,
7672654012fSReza Sabdar 			    &actual_size, FALSE, local_commands);
7682654012fSReza Sabdar 			if (!buf)
7692654012fSReza Sabdar 				goto tear_down;
7702654012fSReza Sabdar 
771b6b15642SReza Sabdar 			if ((actual_size < section_size) &&
772b6b15642SReza Sabdar 			    sysattr_rw(dtp->d_name)) {
773b6b15642SReza Sabdar 				rec = buf;
774b6b15642SReza Sabdar 				buf = ndmp_malloc(section_size);
775b6b15642SReza Sabdar 				if (!buf)
776b6b15642SReza Sabdar 					goto tear_down;
777b6b15642SReza Sabdar 				size = actual_size;
778b6b15642SReza Sabdar 				actual_size = section_size;
779b6b15642SReza Sabdar 				sysattr_read = 1;
780b6b15642SReza Sabdar 			}
781b6b15642SReza Sabdar 
7822654012fSReza Sabdar 			/*
7832654012fSReza Sabdar 			 * check for Abort commands
7842654012fSReza Sabdar 			 */
7852654012fSReza Sabdar 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7862654012fSReza Sabdar 				local_commands->tc_writer = TLM_ABORT;
7872654012fSReza Sabdar 				goto tear_down;
7882654012fSReza Sabdar 			}
7892654012fSReza Sabdar 
7902654012fSReza Sabdar 			read_size = min(section_size, actual_size);
7910fd80060SReza Sabdar 			if ((actual_size = read(afd, buf, read_size)) < 0)
792b6b15642SReza Sabdar 				break;
793b6b15642SReza Sabdar 
794b6b15642SReza Sabdar 			if (sysattr_read) {
795b6b15642SReza Sabdar 				if (get_write_one_buf(buf, rec, read_size,
796b6b15642SReza Sabdar 				    size, local_commands) == 0) {
797b6b15642SReza Sabdar 					free(buf);
798b6b15642SReza Sabdar 					goto tear_down;
799b6b15642SReza Sabdar 				}
800b6b15642SReza Sabdar 				free(buf);
801b6b15642SReza Sabdar 			}
802b6b15642SReza Sabdar 
803b6b15642SReza Sabdar 
8042654012fSReza Sabdar 			NS_ADD(rdisk, actual_size);
8052654012fSReza Sabdar 			NS_INC(rfile);
8062654012fSReza Sabdar 
8072654012fSReza Sabdar 			if (actual_size == -1) {
8082654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
8092654012fSReza Sabdar 				    "problem(%d) reading file [%s][%s]",
8102654012fSReza Sabdar 				    errno, fullname, snapname);
8112654012fSReza Sabdar 				goto tear_down;
8122654012fSReza Sabdar 			}
8132654012fSReza Sabdar 			seek_spot += actual_size;
8142654012fSReza Sabdar 			section_size -= actual_size;
8152654012fSReza Sabdar 		}
8160fd80060SReza Sabdar 		(void) close(afd);
8170fd80060SReza Sabdar 		afd = -1;
8182654012fSReza Sabdar 	}
8192654012fSReza Sabdar 
8202654012fSReza Sabdar tear_down:
8212654012fSReza Sabdar 	local_commands->tc_buffers->tbs_buffer[
8222654012fSReza Sabdar 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
8232654012fSReza Sabdar 
8240fd80060SReza Sabdar 	if (afd > 0)
8250fd80060SReza Sabdar 		(void) close(afd);
8260fd80060SReza Sabdar 
8270fd80060SReza Sabdar 	/* closedir closes fd too */
8282654012fSReza Sabdar 	(void) closedir(dp);
8292654012fSReza Sabdar 
8302654012fSReza Sabdar err_out:
8312654012fSReza Sabdar 	free(fullname);
8322654012fSReza Sabdar 	free(attrname);
8332654012fSReza Sabdar 	free(snapname);
8342654012fSReza Sabdar 	return (rv);
8352654012fSReza Sabdar }
8362654012fSReza Sabdar 
8372654012fSReza Sabdar 
8382654012fSReza Sabdar /*
8392654012fSReza Sabdar  * tlm_output_file
8402654012fSReza Sabdar  *
8412654012fSReza Sabdar  * Put this file into the output buffers.
8422654012fSReza Sabdar  */
8432654012fSReza Sabdar longlong_t
tlm_output_file(char * dir,char * name,char * chkdir,tlm_acls_t * tlm_acls,tlm_commands_t * commands,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats,struct hardlink_q * hardlink_q)8442654012fSReza Sabdar tlm_output_file(char *dir, char *name, char *chkdir,
8452654012fSReza Sabdar     tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
8462654012fSReza Sabdar     tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
8472654012fSReza Sabdar {
8482654012fSReza Sabdar 	char	*fullname;		/* directory + name */
8492654012fSReza Sabdar 	char	*snapname;		/* snapshot name */
8502654012fSReza Sabdar 	char	*linkname;		/* where this file points */
8512654012fSReza Sabdar 	int	section = 0;		/* section of a huge file */
8522654012fSReza Sabdar 	int	fd;
8532654012fSReza Sabdar 	longlong_t real_size;		/* the origional file size */
8542654012fSReza Sabdar 	longlong_t file_size;		/* real size of this file */
8552654012fSReza Sabdar 	longlong_t seek_spot = 0;	/* location in the file */
8562654012fSReza Sabdar 					/* for Multi Volume record */
8572654012fSReza Sabdar 	u_longlong_t pos;
8582654012fSReza Sabdar 	char *fnamep;
8592654012fSReza Sabdar 
8602654012fSReza Sabdar 	/* Indicate whether a file with the same inode has been backed up. */
8612654012fSReza Sabdar 	int hardlink_done = 0;
8622654012fSReza Sabdar 
8632654012fSReza Sabdar 	/*
8642654012fSReza Sabdar 	 * If a file with the same inode has been backed up, hardlink_pos holds
8652654012fSReza Sabdar 	 * the tape offset of the data record.
8662654012fSReza Sabdar 	 */
8672654012fSReza Sabdar 	u_longlong_t hardlink_pos = 0;
8682654012fSReza Sabdar 
8692654012fSReza Sabdar 	if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
8702654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name);
8712654012fSReza Sabdar 		return (-TLM_NO_SCRATCH_SPACE);
8722654012fSReza Sabdar 	}
8732654012fSReza Sabdar 
8742654012fSReza Sabdar 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
8752654012fSReza Sabdar 	linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
8762654012fSReza Sabdar 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
8772654012fSReza Sabdar 	if (fullname == NULL || linkname == NULL || snapname == NULL) {
8782654012fSReza Sabdar 		real_size = -TLM_NO_SCRATCH_SPACE;
8792654012fSReza Sabdar 		goto err_out;
8802654012fSReza Sabdar 	}
8812654012fSReza Sabdar 	if (!tlm_cat_path(fullname, dir, name) ||
8822654012fSReza Sabdar 	    !tlm_cat_path(snapname, chkdir, name)) {
8832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Path too long.");
8842654012fSReza Sabdar 		real_size = -TLM_NO_SCRATCH_SPACE;
8852654012fSReza Sabdar 		goto err_out;
8862654012fSReza Sabdar 	}
8872654012fSReza Sabdar 
8882654012fSReza Sabdar 	pos = tlm_get_data_offset(local_commands);
8892654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
8902654012fSReza Sabdar 
8915181c2afSReza Sabdar 	if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
892295e611fSReza Sabdar 		if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
893295e611fSReza Sabdar 			file_size = tlm_readlink(fullname, snapname, linkname,
894295e611fSReza Sabdar 			    TLM_MAX_PATH_NAME-1);
895295e611fSReza Sabdar 			if (file_size < 0) {
896295e611fSReza Sabdar 				real_size = -ENOENT;
897295e611fSReza Sabdar 				goto err_out;
898295e611fSReza Sabdar 			}
8992654012fSReza Sabdar 		}
9002654012fSReza Sabdar 
9012654012fSReza Sabdar 		/*
9022654012fSReza Sabdar 		 * Since soft links can not be read(2), we should only
9032654012fSReza Sabdar 		 * backup the file header.
9042654012fSReza Sabdar 		 */
9052654012fSReza Sabdar 		(void) output_file_header(fullname,
9062654012fSReza Sabdar 		    linkname,
9072654012fSReza Sabdar 		    tlm_acls,
9082654012fSReza Sabdar 		    section,
9092654012fSReza Sabdar 		    local_commands);
9102654012fSReza Sabdar 
9112654012fSReza Sabdar 		(void) tlm_log_fhnode(job_stats, dir, name,
9122654012fSReza Sabdar 		    &tlm_acls->acl_attr, pos);
9132654012fSReza Sabdar 		(void) tlm_log_fhpath_name(job_stats, fullname,
9142654012fSReza Sabdar 		    &tlm_acls->acl_attr, pos);
9152654012fSReza Sabdar 
9162654012fSReza Sabdar 		free(fullname);
9172654012fSReza Sabdar 		free(linkname);
9182654012fSReza Sabdar 		free(snapname);
9192654012fSReza Sabdar 		return (0);
9202654012fSReza Sabdar 	}
9212654012fSReza Sabdar 
9222654012fSReza Sabdar 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
9232654012fSReza Sabdar 
9242654012fSReza Sabdar 	/*
9252654012fSReza Sabdar 	 * For hardlink, only read the data if no other link
9262654012fSReza Sabdar 	 * belonging to the same inode has been backed up.
9272654012fSReza Sabdar 	 */
9282654012fSReza Sabdar 	if (tlm_acls->acl_attr.st_nlink > 1) {
9292654012fSReza Sabdar 		hardlink_done = !hardlink_q_get(hardlink_q,
9302654012fSReza Sabdar 		    tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
9312654012fSReza Sabdar 	}
9322654012fSReza Sabdar 
9332654012fSReza Sabdar 	if (!hardlink_done) {
9342654012fSReza Sabdar 		/*
9352654012fSReza Sabdar 		 * Open the file for reading.
9362654012fSReza Sabdar 		 */
9372654012fSReza Sabdar 		fd = open(fnamep, O_RDONLY);
9382654012fSReza Sabdar 		if (fd == -1) {
9392654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG,
940b6b15642SReza Sabdar 			    "BACKUP> Can't open file [%s][%s] err(%d)",
941b6b15642SReza Sabdar 			    fullname, fnamep, errno);
9422654012fSReza Sabdar 			real_size = -TLM_NO_SOURCE_FILE;
9432654012fSReza Sabdar 			goto err_out;
9442654012fSReza Sabdar 		}
9452654012fSReza Sabdar 	} else {
9467bc22e45SReza Sabdar 		NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
9472654012fSReza Sabdar 		    tlm_acls->acl_attr.st_ino, hardlink_pos);
9482654012fSReza Sabdar 
9492654012fSReza Sabdar 		fd = -1;
9502654012fSReza Sabdar 	}
9512654012fSReza Sabdar 
9522654012fSReza Sabdar 	linkname[0] = 0;
9532654012fSReza Sabdar 
9542654012fSReza Sabdar 	real_size = tlm_acls->acl_attr.st_size;
9552654012fSReza Sabdar 	(void) output_acl_header(&tlm_acls->acl_info,
9562654012fSReza Sabdar 	    local_commands);
9572654012fSReza Sabdar 
9582654012fSReza Sabdar 	/*
9592654012fSReza Sabdar 	 * section = 0: file is small enough for TAR
9602654012fSReza Sabdar 	 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
9612654012fSReza Sabdar 	 * 		and the file name gets munged
9622654012fSReza Sabdar 	 */
9632654012fSReza Sabdar 	file_size = real_size;
9642654012fSReza Sabdar 	if (file_size > TLM_MAX_TAR_IMAGE) {
9652654012fSReza Sabdar 		if (output_humongus_header(fullname, file_size,
9662654012fSReza Sabdar 		    local_commands) < 0) {
9672654012fSReza Sabdar 			(void) close(fd);
9682654012fSReza Sabdar 			real_size = -TLM_NO_SCRATCH_SPACE;
9692654012fSReza Sabdar 			goto err_out;
9702654012fSReza Sabdar 		}
9712654012fSReza Sabdar 		section = 1;
9722654012fSReza Sabdar 	} else {
9732654012fSReza Sabdar 		section = 0;
9742654012fSReza Sabdar 	}
9752654012fSReza Sabdar 
9762654012fSReza Sabdar 	/*
9772654012fSReza Sabdar 	 * For hardlink, if other link belonging to the same inode
9782654012fSReza Sabdar 	 * has been backed up, only backup an empty record.
9792654012fSReza Sabdar 	 */
9802654012fSReza Sabdar 	if (hardlink_done)
9812654012fSReza Sabdar 		file_size = 0;
9822654012fSReza Sabdar 
9832654012fSReza Sabdar 	/*
9842654012fSReza Sabdar 	 * work
9852654012fSReza Sabdar 	 */
9862654012fSReza Sabdar 	if (file_size == 0) {
9872654012fSReza Sabdar 		(void) output_file_header(fullname,
9882654012fSReza Sabdar 		    linkname,
9892654012fSReza Sabdar 		    tlm_acls,
9902654012fSReza Sabdar 		    section,
9912654012fSReza Sabdar 		    local_commands);
9922654012fSReza Sabdar 		/*
9932654012fSReza Sabdar 		 * this can fall right through since zero size files
9942654012fSReza Sabdar 		 * will be skipped by the WHILE loop anyway
9952654012fSReza Sabdar 		 */
9962654012fSReza Sabdar 	}
9972654012fSReza Sabdar 
9982654012fSReza Sabdar 	while (file_size > 0) {
9992654012fSReza Sabdar 		int section_size = llmin(file_size,
10002654012fSReza Sabdar 		    (longlong_t)TLM_MAX_TAR_IMAGE);
10012654012fSReza Sabdar 
10022654012fSReza Sabdar 		tlm_acls->acl_attr.st_size = (longlong_t)section_size;
10032654012fSReza Sabdar 		(void) output_file_header(fullname,
10042654012fSReza Sabdar 		    linkname,
10052654012fSReza Sabdar 		    tlm_acls,
10062654012fSReza Sabdar 		    section,
10072654012fSReza Sabdar 		    local_commands);
10082654012fSReza Sabdar 		while (section_size > 0) {
10092654012fSReza Sabdar 			char	*buf;
10102654012fSReza Sabdar 			long	actual_size;
10112654012fSReza Sabdar 			int	read_size;
10122654012fSReza Sabdar 
10132654012fSReza Sabdar 			/*
10142654012fSReza Sabdar 			 * check for Abort commands
10152654012fSReza Sabdar 			 */
10162654012fSReza Sabdar 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
10172654012fSReza Sabdar 				local_commands->tc_writer = TLM_ABORT;
10182654012fSReza Sabdar 				goto tear_down;
10192654012fSReza Sabdar 			}
10202654012fSReza Sabdar 
10212654012fSReza Sabdar 			local_commands->tc_buffers->tbs_buffer[
10222654012fSReza Sabdar 			    local_commands->tc_buffers->tbs_buffer_in].
10232654012fSReza Sabdar 			    tb_file_size = section_size;
10242654012fSReza Sabdar 			local_commands->tc_buffers->tbs_buffer[
10252654012fSReza Sabdar 			    local_commands->tc_buffers->tbs_buffer_in].
10262654012fSReza Sabdar 			    tb_seek_spot = seek_spot;
10272654012fSReza Sabdar 
10282654012fSReza Sabdar 			buf = get_write_buffer(section_size,
10292654012fSReza Sabdar 			    &actual_size, FALSE, local_commands);
10302654012fSReza Sabdar 			if (!buf)
10312654012fSReza Sabdar 				goto tear_down;
10322654012fSReza Sabdar 
10332654012fSReza Sabdar 			/*
10342654012fSReza Sabdar 			 * check for Abort commands
10352654012fSReza Sabdar 			 */
10362654012fSReza Sabdar 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
10372654012fSReza Sabdar 				local_commands->tc_writer = TLM_ABORT;
10382654012fSReza Sabdar 				goto tear_down;
10392654012fSReza Sabdar 			}
10402654012fSReza Sabdar 
10412654012fSReza Sabdar 			read_size = min(section_size, actual_size);
10422654012fSReza Sabdar 			actual_size = read(fd, buf, read_size);
10432654012fSReza Sabdar 			NS_ADD(rdisk, actual_size);
10442654012fSReza Sabdar 			NS_INC(rfile);
10452654012fSReza Sabdar 
10462654012fSReza Sabdar 			if (actual_size == 0)
10472654012fSReza Sabdar 				break;
10482654012fSReza Sabdar 
10492654012fSReza Sabdar 			if (actual_size == -1) {
10502654012fSReza Sabdar 				NDMP_LOG(LOG_DEBUG,
10512654012fSReza Sabdar 				    "problem(%d) reading file [%s][%s]",
10522654012fSReza Sabdar 				    errno, fullname, snapname);
10532654012fSReza Sabdar 				goto tear_down;
10542654012fSReza Sabdar 			}
10552654012fSReza Sabdar 			seek_spot += actual_size;
10562654012fSReza Sabdar 			file_size -= actual_size;
10572654012fSReza Sabdar 			section_size -= actual_size;
10582654012fSReza Sabdar 		}
10592654012fSReza Sabdar 		section++;
10602654012fSReza Sabdar 	}
10612654012fSReza Sabdar 
10622654012fSReza Sabdar 	/*
10632654012fSReza Sabdar 	 * If data belonging to this hardlink has been backed up, add the link
10642654012fSReza Sabdar 	 * to hardlink queue.
10652654012fSReza Sabdar 	 */
10662654012fSReza Sabdar 	if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
10672654012fSReza Sabdar 		(void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
10682654012fSReza Sabdar 		    pos, NULL, 0);
10692654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
10707bc22e45SReza Sabdar 		    "backed up hardlink file %s, inode = %llu, pos = %llu ",
10712654012fSReza Sabdar 		    fullname, tlm_acls->acl_attr.st_ino, pos);
10722654012fSReza Sabdar 	}
10732654012fSReza Sabdar 
10742654012fSReza Sabdar 	/*
10752654012fSReza Sabdar 	 * For hardlink, if other link belonging to the same inode has been
10767bc22e45SReza Sabdar 	 * backed up, no add_node entry should be sent for this link.
10772654012fSReza Sabdar 	 */
10782654012fSReza Sabdar 	if (hardlink_done) {
10792654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
10807bc22e45SReza Sabdar 		    "backed up hardlink link %s, inode = %llu, pos = %llu ",
10812654012fSReza Sabdar 		    fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
10822654012fSReza Sabdar 	} else {
10832654012fSReza Sabdar 		(void) tlm_log_fhnode(job_stats, dir, name,
10842654012fSReza Sabdar 		    &tlm_acls->acl_attr, pos);
10852654012fSReza Sabdar 	}
10862654012fSReza Sabdar 
10872654012fSReza Sabdar 	(void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
10882654012fSReza Sabdar 	    pos);
10892654012fSReza Sabdar 
10902654012fSReza Sabdar tear_down:
10912654012fSReza Sabdar 	local_commands->tc_buffers->tbs_buffer[
10922654012fSReza Sabdar 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
10932654012fSReza Sabdar 
10942654012fSReza Sabdar 	(void) close(fd);
10952654012fSReza Sabdar 
10962654012fSReza Sabdar err_out:
10972654012fSReza Sabdar 	free(fullname);
10982654012fSReza Sabdar 	free(linkname);
10992654012fSReza Sabdar 	free(snapname);
11002654012fSReza Sabdar 	return (real_size);
11012654012fSReza Sabdar }
11022654012fSReza Sabdar 
11032654012fSReza Sabdar /*
11042654012fSReza Sabdar  * tar_putfile
11052654012fSReza Sabdar  *
11062654012fSReza Sabdar  * Main file backup function for tar
11072654012fSReza Sabdar  */
11082654012fSReza Sabdar int
tar_putfile(char * dir,char * name,char * chkdir,tlm_acls_t * tlm_acls,tlm_commands_t * commands,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats,struct hardlink_q * hardlink_q)11092654012fSReza Sabdar tar_putfile(char *dir, char *name, char *chkdir,
11102654012fSReza Sabdar     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
11112654012fSReza Sabdar     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
11122654012fSReza Sabdar     struct hardlink_q *hardlink_q)
11132654012fSReza Sabdar {
11142654012fSReza Sabdar 	int rv;
11152654012fSReza Sabdar 
11162654012fSReza Sabdar 	rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
11172654012fSReza Sabdar 	    local_commands, job_stats, hardlink_q);
11182654012fSReza Sabdar 	if (rv < 0)
11192654012fSReza Sabdar 		return (rv);
11202654012fSReza Sabdar 
11212654012fSReza Sabdar 	rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
11222654012fSReza Sabdar 	    local_commands, job_stats);
11232654012fSReza Sabdar 
11242654012fSReza Sabdar 	return (rv < 0 ? rv : 0);
11252654012fSReza Sabdar }
11262654012fSReza Sabdar 
11272654012fSReza Sabdar /*
11282654012fSReza Sabdar  * get_write_buffer
11292654012fSReza Sabdar  *
11302654012fSReza Sabdar  * a wrapper to tlm_get_write_buffer so that
11312654012fSReza Sabdar  * we can cleanly detect ABORT commands
11322654012fSReza Sabdar  * without involving the TLM library with
11332654012fSReza Sabdar  * our problems.
11342654012fSReza Sabdar  */
11352654012fSReza Sabdar static char *
get_write_buffer(long size,long * actual_size,boolean_t zero,tlm_cmd_t * local_commands)11362654012fSReza Sabdar get_write_buffer(long size, long *actual_size,
11372654012fSReza Sabdar     boolean_t zero, tlm_cmd_t *local_commands)
11382654012fSReza Sabdar {
11392654012fSReza Sabdar 	while (local_commands->tc_reader == TLM_BACKUP_RUN) {
11402654012fSReza Sabdar 		char *rec = tlm_get_write_buffer(size, actual_size,
11412654012fSReza Sabdar 		    local_commands->tc_buffers, zero);
11422654012fSReza Sabdar 		if (rec != 0) {
11432654012fSReza Sabdar 			return (rec);
11442654012fSReza Sabdar 		}
11452654012fSReza Sabdar 	}
11462654012fSReza Sabdar 	return (NULL);
11472654012fSReza Sabdar }
11482654012fSReza Sabdar 
11492654012fSReza Sabdar #define	NDMP_MORE_RECORDS	2
11502654012fSReza Sabdar 
11512654012fSReza Sabdar /*
11522654012fSReza Sabdar  * write_tar_eof
11532654012fSReza Sabdar  *
11542654012fSReza Sabdar  * This function is initially written for NDMP support.  It appends
11552654012fSReza Sabdar  * two tar headers to the tar file, and also N more empty buffers
11562654012fSReza Sabdar  * to make sure that the two tar headers will be read as a part of
11572654012fSReza Sabdar  * a mover record and don't get locked because of EOM on the mover
11582654012fSReza Sabdar  * side.
11592654012fSReza Sabdar  */
11602654012fSReza Sabdar void
write_tar_eof(tlm_cmd_t * local_commands)11612654012fSReza Sabdar write_tar_eof(tlm_cmd_t *local_commands)
11622654012fSReza Sabdar {
11632654012fSReza Sabdar 	int i;
11642654012fSReza Sabdar 	long actual_size;
11652654012fSReza Sabdar 	tlm_buffers_t *bufs;
11662654012fSReza Sabdar 
11672654012fSReza Sabdar 	/*
11682654012fSReza Sabdar 	 * output 2 zero filled records,
11692654012fSReza Sabdar 	 * TAR wants this.
11702654012fSReza Sabdar 	 */
11712654012fSReza Sabdar 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11722654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
11732654012fSReza Sabdar 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11742654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
11752654012fSReza Sabdar 
11762654012fSReza Sabdar 	/*
11772654012fSReza Sabdar 	 * NDMP: Clear the rest of the buffer and write two more buffers
11782654012fSReza Sabdar 	 * to the tape.
11792654012fSReza Sabdar 	 */
11802654012fSReza Sabdar 	bufs = local_commands->tc_buffers;
11812654012fSReza Sabdar 	(void) get_write_buffer(bufs->tbs_data_transfer_size,
11822654012fSReza Sabdar 	    &actual_size, TRUE, local_commands);
11832654012fSReza Sabdar 
11842654012fSReza Sabdar 	for (i = 0; i < NDMP_MORE_RECORDS &&
11852654012fSReza Sabdar 	    local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
11862654012fSReza Sabdar 		/*
11872654012fSReza Sabdar 		 * We don't need the return value of get_write_buffer(),
11882654012fSReza Sabdar 		 * since it's already zeroed out if the buffer is returned.
11892654012fSReza Sabdar 		 */
11902654012fSReza Sabdar 		(void) get_write_buffer(bufs->tbs_data_transfer_size,
11912654012fSReza Sabdar 		    &actual_size, TRUE, local_commands);
11922654012fSReza Sabdar 	}
11932654012fSReza Sabdar 
11942654012fSReza Sabdar 	bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
11952654012fSReza Sabdar 	tlm_buffer_release_in_buf(bufs);
11962654012fSReza Sabdar }
11972654012fSReza Sabdar 
11982654012fSReza Sabdar /*
11992654012fSReza Sabdar  * Callback to backup each ZFS property
12002654012fSReza Sabdar  */
12012654012fSReza Sabdar static int
zfs_put_prop_cb(int prop,void * pp)12022654012fSReza Sabdar zfs_put_prop_cb(int prop, void *pp)
12032654012fSReza Sabdar {
120442ed7838SReza Sabdar 	ndmp_metadata_handle_t *mhd;
120542ed7838SReza Sabdar 	ndmp_metadata_header_ext_t *mhp;
120642ed7838SReza Sabdar 	ndmp_metadata_property_ext_t *mpp;
120742ed7838SReza Sabdar 	char vbuf[ZFS_MAXPROPLEN];
120842ed7838SReza Sabdar 	char sbuf[ZFS_MAXPROPLEN];
12092654012fSReza Sabdar 	zprop_source_t stype;
121086c48bbfSReza Sabdar 	char *sourcestr;
12112654012fSReza Sabdar 
12122654012fSReza Sabdar 	if (pp == NULL)
12132654012fSReza Sabdar 		return (ZPROP_INVAL);
12142654012fSReza Sabdar 
121542ed7838SReza Sabdar 	mhd = (ndmp_metadata_handle_t *)pp;
121642ed7838SReza Sabdar 	mhp = mhd->ml_xhdr;
121742ed7838SReza Sabdar 	mpp = &mhp->nh_property[mhp->nh_count];
12182654012fSReza Sabdar 
121942ed7838SReza Sabdar 	if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
122042ed7838SReza Sabdar 	    sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
122142ed7838SReza Sabdar 		return (ZPROP_INVAL);
122242ed7838SReza Sabdar 
122342ed7838SReza Sabdar 	if (zfs_prop_get(mhd->ml_handle, prop, vbuf, sizeof (vbuf),
122442ed7838SReza Sabdar 	    &stype, sbuf, sizeof (sbuf), B_TRUE) != 0) {
122542ed7838SReza Sabdar 		mhp->nh_count++;
1226674cb4b0SReza Sabdar 		return (ZPROP_CONT);
122742ed7838SReza Sabdar 	}
1228674cb4b0SReza Sabdar 
1229*9adfa60dSMatthew Ahrens 	(void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop),
1230*9adfa60dSMatthew Ahrens 	    ZFS_MAX_DATASET_NAME_LEN);
123142ed7838SReza Sabdar 	(void) strlcpy(mpp->mp_value, vbuf, ZFS_MAXPROPLEN);
123286c48bbfSReza Sabdar 
123386c48bbfSReza Sabdar 	switch (stype) {
123486c48bbfSReza Sabdar 	case ZPROP_SRC_NONE:
123586c48bbfSReza Sabdar 		sourcestr = "none";
123686c48bbfSReza Sabdar 		break;
123742ed7838SReza Sabdar 	case ZPROP_SRC_RECEIVED:
123842ed7838SReza Sabdar 		sourcestr = "received";
123942ed7838SReza Sabdar 		break;
124086c48bbfSReza Sabdar 	case ZPROP_SRC_LOCAL:
124186c48bbfSReza Sabdar 		sourcestr = mhp->nh_dataset;
124286c48bbfSReza Sabdar 		break;
124386c48bbfSReza Sabdar 	case ZPROP_SRC_TEMPORARY:
124486c48bbfSReza Sabdar 		sourcestr = "temporary";
124586c48bbfSReza Sabdar 		break;
124686c48bbfSReza Sabdar 	case ZPROP_SRC_DEFAULT:
124786c48bbfSReza Sabdar 		sourcestr = "default";
124886c48bbfSReza Sabdar 		break;
124986c48bbfSReza Sabdar 	default:
125086c48bbfSReza Sabdar 		sourcestr = sbuf;
125186c48bbfSReza Sabdar 		break;
125286c48bbfSReza Sabdar 	}
125342ed7838SReza Sabdar 	(void) strlcpy(mpp->mp_source, sourcestr, ZFS_MAXPROPLEN);
12542654012fSReza Sabdar 
125542ed7838SReza Sabdar 	mhp->nh_count++;
12562654012fSReza Sabdar 	return (ZPROP_CONT);
12572654012fSReza Sabdar }
12582654012fSReza Sabdar 
125942ed7838SReza Sabdar /*
126042ed7838SReza Sabdar  * Callback to backup each ZFS user/group quota
126142ed7838SReza Sabdar  */
126242ed7838SReza Sabdar static int
zfs_put_quota_cb(void * pp,const char * domain,uid_t rid,uint64_t space)126342ed7838SReza Sabdar zfs_put_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
126442ed7838SReza Sabdar {
126542ed7838SReza Sabdar 	ndmp_metadata_handle_t *mhd;
126642ed7838SReza Sabdar 	ndmp_metadata_header_ext_t *mhp;
126742ed7838SReza Sabdar 	ndmp_metadata_property_ext_t *mpp;
126842ed7838SReza Sabdar 	char *typestr;
126942ed7838SReza Sabdar 
127042ed7838SReza Sabdar 	if (pp == NULL)
127142ed7838SReza Sabdar 		return (ZPROP_INVAL);
127242ed7838SReza Sabdar 
127342ed7838SReza Sabdar 	mhd = (ndmp_metadata_handle_t *)pp;
127442ed7838SReza Sabdar 	mhp = mhd->ml_xhdr;
127542ed7838SReza Sabdar 	mpp = &mhp->nh_property[mhp->nh_count];
127642ed7838SReza Sabdar 
127742ed7838SReza Sabdar 	if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
127842ed7838SReza Sabdar 	    sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
127942ed7838SReza Sabdar 		return (ZPROP_INVAL);
128042ed7838SReza Sabdar 
128142ed7838SReza Sabdar 	if (mhd->ml_quota_prop == ZFS_PROP_USERQUOTA)
128242ed7838SReza Sabdar 		typestr = "userquota";
128342ed7838SReza Sabdar 	else
128442ed7838SReza Sabdar 		typestr = "groupquota";
128542ed7838SReza Sabdar 
1286*9adfa60dSMatthew Ahrens 	if (domain == NULL || *domain == '\0') {
1287*9adfa60dSMatthew Ahrens 		(void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN,
1288*9adfa60dSMatthew Ahrens 		    "%s@%llu", typestr, (longlong_t)rid);
1289*9adfa60dSMatthew Ahrens 	} else {
1290*9adfa60dSMatthew Ahrens 		(void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN,
1291*9adfa60dSMatthew Ahrens 		    "%s@%s-%llu", typestr, domain, (longlong_t)rid);
1292*9adfa60dSMatthew Ahrens 	}
129342ed7838SReza Sabdar 	(void) snprintf(mpp->mp_value, ZFS_MAXPROPLEN, "%llu", space);
129442ed7838SReza Sabdar 	(void) strlcpy(mpp->mp_source, mhp->nh_dataset, ZFS_MAXPROPLEN);
129542ed7838SReza Sabdar 
129642ed7838SReza Sabdar 	mhp->nh_count++;
129742ed7838SReza Sabdar 	return (0);
129842ed7838SReza Sabdar }
129942ed7838SReza Sabdar 
130042ed7838SReza Sabdar /*
130142ed7838SReza Sabdar  * Callback to count each ZFS property
130242ed7838SReza Sabdar  */
130342ed7838SReza Sabdar /*ARGSUSED*/
130442ed7838SReza Sabdar static int
zfs_count_prop_cb(int prop,void * pp)130542ed7838SReza Sabdar zfs_count_prop_cb(int prop, void *pp)
130642ed7838SReza Sabdar {
130742ed7838SReza Sabdar 	(*(int *)pp)++;
130842ed7838SReza Sabdar 	return (ZPROP_CONT);
130942ed7838SReza Sabdar }
131042ed7838SReza Sabdar 
131142ed7838SReza Sabdar /*
131242ed7838SReza Sabdar  * Callback to count each ZFS user/group quota
131342ed7838SReza Sabdar  */
131442ed7838SReza Sabdar /*ARGSUSED*/
131542ed7838SReza Sabdar static int
zfs_count_quota_cb(void * pp,const char * domain,uid_t rid,uint64_t space)131642ed7838SReza Sabdar zfs_count_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
131742ed7838SReza Sabdar {
131842ed7838SReza Sabdar 	(*(int *)pp)++;
131942ed7838SReza Sabdar 	return (0);
132042ed7838SReza Sabdar }
132142ed7838SReza Sabdar 
132242ed7838SReza Sabdar /*
132342ed7838SReza Sabdar  * Count the number of ZFS properties and user/group quotas
132442ed7838SReza Sabdar  */
132542ed7838SReza Sabdar int
zfs_get_prop_counts(zfs_handle_t * zhp)132642ed7838SReza Sabdar zfs_get_prop_counts(zfs_handle_t *zhp)
132742ed7838SReza Sabdar {
132842ed7838SReza Sabdar 	int count = 0;
132942ed7838SReza Sabdar 	nvlist_t *uprops;
133042ed7838SReza Sabdar 	nvpair_t *elp;
133142ed7838SReza Sabdar 
133242ed7838SReza Sabdar 	if (zhp == NULL)
133342ed7838SReza Sabdar 		return (0);
133442ed7838SReza Sabdar 
133542ed7838SReza Sabdar 	(void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE,
133642ed7838SReza Sabdar 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
133742ed7838SReza Sabdar 
133842ed7838SReza Sabdar 	(void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb,
133942ed7838SReza Sabdar 	    &count);
134042ed7838SReza Sabdar 	(void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb,
134142ed7838SReza Sabdar 	    &count);
134242ed7838SReza Sabdar 
134342ed7838SReza Sabdar 	uprops = zfs_get_user_props(zhp);
134442ed7838SReza Sabdar 
134542ed7838SReza Sabdar 	elp = nvlist_next_nvpair(uprops, NULL);
134642ed7838SReza Sabdar 	for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp))
134742ed7838SReza Sabdar 		count++;
134842ed7838SReza Sabdar 
134942ed7838SReza Sabdar 	return (count);
135042ed7838SReza Sabdar }
13512654012fSReza Sabdar 
13522654012fSReza Sabdar /*
13532654012fSReza Sabdar  * Notifies ndmpd that the metadata associated with the given ZFS dataset
13542654012fSReza Sabdar  * should be backed up.
13552654012fSReza Sabdar  */
13562654012fSReza Sabdar int
ndmp_include_zfs(ndmp_context_t * nctx,const char * dataset)13572654012fSReza Sabdar ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
13582654012fSReza Sabdar {
13592654012fSReza Sabdar 	tlm_commands_t *cmds;
136042ed7838SReza Sabdar 	ndmp_metadata_handle_t mhd;
136142ed7838SReza Sabdar 	ndmp_metadata_header_ext_t *mhp;
136242ed7838SReza Sabdar 	ndmp_metadata_property_ext_t *mpp;
136342ed7838SReza Sabdar 	zfs_handle_t *zhp;
13642654012fSReza Sabdar 	tlm_cmd_t *lcmd;
13652654012fSReza Sabdar 	long actual_size;
13662654012fSReza Sabdar 	nvlist_t *uprops, *ulist;
13672654012fSReza Sabdar 	const char *pname;
13682654012fSReza Sabdar 	nvpair_t *elp;
13692654012fSReza Sabdar 	char *sval, *ssrc;
13702654012fSReza Sabdar 	char *wbuf, *pp, *tp;
13712654012fSReza Sabdar 	long size, lsize, sz;
13722654012fSReza Sabdar 	int align = RECORDSIZE - 1;
137342ed7838SReza Sabdar 	int pcount;
13742654012fSReza Sabdar 
13752654012fSReza Sabdar 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
13762654012fSReza Sabdar 		return (-1);
13772654012fSReza Sabdar 
13782654012fSReza Sabdar 	if ((lcmd = cmds->tcs_command) == NULL ||
13792654012fSReza Sabdar 	    lcmd->tc_buffers == NULL)
13802654012fSReza Sabdar 		return (-1);
13812654012fSReza Sabdar 
138242ed7838SReza Sabdar 	(void) mutex_lock(&zlib_mtx);
138342ed7838SReza Sabdar 	if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) {
138442ed7838SReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
138542ed7838SReza Sabdar 		return (-1);
138642ed7838SReza Sabdar 	}
138742ed7838SReza Sabdar 
138842ed7838SReza Sabdar 	pcount = zfs_get_prop_counts(zhp);
138942ed7838SReza Sabdar 	size = sizeof (ndmp_metadata_header_ext_t) +
139042ed7838SReza Sabdar 	    pcount * sizeof (ndmp_metadata_property_ext_t);
139142ed7838SReza Sabdar 
13922654012fSReza Sabdar 	size += align;
13932654012fSReza Sabdar 	size &= ~align;
13942654012fSReza Sabdar 
139542ed7838SReza Sabdar 	if ((mhp = malloc(size)) == NULL) {
139642ed7838SReza Sabdar 		zfs_close(zhp);
139742ed7838SReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
13982654012fSReza Sabdar 		return (-1);
139942ed7838SReza Sabdar 	}
140042ed7838SReza Sabdar 
14012654012fSReza Sabdar 	(void) memset(mhp, 0, size);
14022654012fSReza Sabdar 
140342ed7838SReza Sabdar 	mhd.ml_handle = zhp;
140442ed7838SReza Sabdar 	mhd.ml_xhdr = mhp;
140542ed7838SReza Sabdar 	mhp->nh_total_bytes = size;
140642ed7838SReza Sabdar 	mhp->nh_major = META_HDR_MAJOR_VERSION;
140742ed7838SReza Sabdar 	mhp->nh_minor = META_HDR_MINOR_VERSION;
14082654012fSReza Sabdar 	mhp->nh_plversion = nctx->nc_plversion;
140942ed7838SReza Sabdar 
14102654012fSReza Sabdar 	(void) strlcpy(mhp->nh_plname, nctx->nc_plname,
14112654012fSReza Sabdar 	    sizeof (mhp->nh_plname));
141242ed7838SReza Sabdar 	(void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT,
141342ed7838SReza Sabdar 	    sizeof (mhp->nh_magic));
14142654012fSReza Sabdar 	(void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
14152654012fSReza Sabdar 
14162654012fSReza Sabdar 	/* Get all the ZFS properties */
141742ed7838SReza Sabdar 	(void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE,
14182654012fSReza Sabdar 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
14192654012fSReza Sabdar 
14202654012fSReza Sabdar 	/* Get user properties */
142142ed7838SReza Sabdar 	uprops = zfs_get_user_props(mhd.ml_handle);
14222654012fSReza Sabdar 
14232654012fSReza Sabdar 	elp = nvlist_next_nvpair(uprops, NULL);
14242654012fSReza Sabdar 
14252654012fSReza Sabdar 	while (elp != NULL) {
14262654012fSReza Sabdar 		mpp = &mhp->nh_property[mhp->nh_count];
14272654012fSReza Sabdar 		if (nvpair_value_nvlist(elp, &ulist) != 0 ||
14282654012fSReza Sabdar 		    nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
14292654012fSReza Sabdar 		    nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
143042ed7838SReza Sabdar 			zfs_close(mhd.ml_handle);
143189f9eb87SReza Sabdar 			(void) mutex_unlock(&zlib_mtx);
14322654012fSReza Sabdar 			free(mhp);
14332654012fSReza Sabdar 			return (-1);
14342654012fSReza Sabdar 		}
1435*9adfa60dSMatthew Ahrens 		if ((pname = nvpair_name(elp)) != NULL) {
1436*9adfa60dSMatthew Ahrens 			(void) strlcpy(mpp->mp_name, pname,
1437*9adfa60dSMatthew Ahrens 			    ZFS_MAX_DATASET_NAME_LEN);
1438*9adfa60dSMatthew Ahrens 		}
14392654012fSReza Sabdar 
144042ed7838SReza Sabdar 		(void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN);
144142ed7838SReza Sabdar 		(void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN);
14422654012fSReza Sabdar 		mhp->nh_count++;
14432654012fSReza Sabdar 		elp = nvlist_next_nvpair(uprops, elp);
14442654012fSReza Sabdar 	}
14452654012fSReza Sabdar 
144642ed7838SReza Sabdar 	mhd.ml_quota_prop = ZFS_PROP_USERQUOTA;
144742ed7838SReza Sabdar 	(void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA,
144842ed7838SReza Sabdar 	    zfs_put_quota_cb, &mhd);
144942ed7838SReza Sabdar 	mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA;
145042ed7838SReza Sabdar 	(void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA,
145142ed7838SReza Sabdar 	    zfs_put_quota_cb, &mhd);
145242ed7838SReza Sabdar 	mhp->nh_count = pcount;
145342ed7838SReza Sabdar 
145442ed7838SReza Sabdar 	zfs_close(mhd.ml_handle);
145589f9eb87SReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
14562654012fSReza Sabdar 
14572654012fSReza Sabdar 	if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
14582654012fSReza Sabdar 	    lcmd)) != NULL) {
14592654012fSReza Sabdar 		pp = (char *)mhp;
14602654012fSReza Sabdar 
14612654012fSReza Sabdar 		(void) memcpy(wbuf, pp, (actual_size < size) ?
14622654012fSReza Sabdar 		    actual_size : size);
14632654012fSReza Sabdar 		pp += (actual_size < size) ? actual_size : size;
14642654012fSReza Sabdar 
14652654012fSReza Sabdar 		sz = actual_size;
14662654012fSReza Sabdar 		while (sz < size &&
14672654012fSReza Sabdar 		    ((tp = get_write_buffer(size - sz, &lsize,
14682654012fSReza Sabdar 		    TRUE, lcmd))) != NULL) {
146942ed7838SReza Sabdar 			(void) memcpy(tp, pp, lsize);
14702654012fSReza Sabdar 			sz += lsize;
14712654012fSReza Sabdar 			pp += lsize;
14722654012fSReza Sabdar 		}
14732654012fSReza Sabdar 		if (sz > size) {
14742654012fSReza Sabdar 			tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
14752654012fSReza Sabdar 		}
14762654012fSReza Sabdar 	}
14772654012fSReza Sabdar 
14782654012fSReza Sabdar 	free(mhp);
14792654012fSReza Sabdar 	return (0);
14802654012fSReza Sabdar }
1481