xref: /onnv-gate/usr/src/cmd/ndmpd/tlm/tlm_backup_reader.c (revision 12353:9b7835aa98d4)
17917SReza.Sabdar@Sun.COM /*
2*12353SReza.Sabdar@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
37917SReza.Sabdar@Sun.COM  */
47917SReza.Sabdar@Sun.COM 
57917SReza.Sabdar@Sun.COM /*
67917SReza.Sabdar@Sun.COM  * BSD 3 Clause License
77917SReza.Sabdar@Sun.COM  *
87917SReza.Sabdar@Sun.COM  * Copyright (c) 2007, The Storage Networking Industry Association.
97917SReza.Sabdar@Sun.COM  *
107917SReza.Sabdar@Sun.COM  * Redistribution and use in source and binary forms, with or without
117917SReza.Sabdar@Sun.COM  * modification, are permitted provided that the following conditions
127917SReza.Sabdar@Sun.COM  * are met:
137917SReza.Sabdar@Sun.COM  * 	- Redistributions of source code must retain the above copyright
147917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer.
157917SReza.Sabdar@Sun.COM  *
167917SReza.Sabdar@Sun.COM  * 	- Redistributions in binary form must reproduce the above copyright
177917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer in
187917SReza.Sabdar@Sun.COM  *	  the documentation and/or other materials provided with the
197917SReza.Sabdar@Sun.COM  *	  distribution.
207917SReza.Sabdar@Sun.COM  *
217917SReza.Sabdar@Sun.COM  *	- Neither the name of The Storage Networking Industry Association (SNIA)
227917SReza.Sabdar@Sun.COM  *	  nor the names of its contributors may be used to endorse or promote
237917SReza.Sabdar@Sun.COM  *	  products derived from this software without specific prior written
247917SReza.Sabdar@Sun.COM  *	  permission.
257917SReza.Sabdar@Sun.COM  *
267917SReza.Sabdar@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
277917SReza.Sabdar@Sun.COM  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287917SReza.Sabdar@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
297917SReza.Sabdar@Sun.COM  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
307917SReza.Sabdar@Sun.COM  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
317917SReza.Sabdar@Sun.COM  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
327917SReza.Sabdar@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
337917SReza.Sabdar@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
347917SReza.Sabdar@Sun.COM  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
357917SReza.Sabdar@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
367917SReza.Sabdar@Sun.COM  * POSSIBILITY OF SUCH DAMAGE.
377917SReza.Sabdar@Sun.COM  */
387917SReza.Sabdar@Sun.COM #include <stdio.h>
397917SReza.Sabdar@Sun.COM #include <limits.h>
407917SReza.Sabdar@Sun.COM #include <time.h>
417917SReza.Sabdar@Sun.COM #include <sys/stat.h>
427917SReza.Sabdar@Sun.COM #include <unistd.h>
437917SReza.Sabdar@Sun.COM #include <dirent.h>
447917SReza.Sabdar@Sun.COM #include <pthread.h>
457917SReza.Sabdar@Sun.COM #include <archives.h>
467917SReza.Sabdar@Sun.COM #include <tlm.h>
477917SReza.Sabdar@Sun.COM #include <sys/fs/zfs.h>
48*12353SReza.Sabdar@Sun.COM #include <sys/mkdev.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;
7511170SReza.Sabdar@Sun.COM extern	mutex_t zlib_mtx;
767917SReza.Sabdar@Sun.COM 
77*12353SReza.Sabdar@Sun.COM #define	S_ISPECIAL(a)	(S_ISLNK(a) || S_ISFIFO(a) || S_ISBLK(a) || \
78*12353SReza.Sabdar@Sun.COM 	S_ISCHR(a))
797917SReza.Sabdar@Sun.COM 
807917SReza.Sabdar@Sun.COM /*
817917SReza.Sabdar@Sun.COM  * output_mem
827917SReza.Sabdar@Sun.COM  *
837917SReza.Sabdar@Sun.COM  * Gets a IO write buffer and copies memory to the that.
847917SReza.Sabdar@Sun.COM  */
857917SReza.Sabdar@Sun.COM static void
output_mem(tlm_cmd_t * local_commands,char * mem,int len)867917SReza.Sabdar@Sun.COM output_mem(tlm_cmd_t *local_commands, char *mem,
877917SReza.Sabdar@Sun.COM     int len)
887917SReza.Sabdar@Sun.COM {
897917SReza.Sabdar@Sun.COM 	long actual_size, rec_size;
907917SReza.Sabdar@Sun.COM 	char *rec;
917917SReza.Sabdar@Sun.COM 
927917SReza.Sabdar@Sun.COM 	while (len > 0) {
937917SReza.Sabdar@Sun.COM 		rec = get_write_buffer(len, &actual_size,
947917SReza.Sabdar@Sun.COM 		    FALSE, local_commands);
957917SReza.Sabdar@Sun.COM 		rec_size = min(actual_size, len);
967917SReza.Sabdar@Sun.COM 		(void) memcpy(rec, mem, rec_size);
977917SReza.Sabdar@Sun.COM 		mem += rec_size;
987917SReza.Sabdar@Sun.COM 		len -= rec_size;
997917SReza.Sabdar@Sun.COM 	}
1007917SReza.Sabdar@Sun.COM }
1017917SReza.Sabdar@Sun.COM 
1027917SReza.Sabdar@Sun.COM /*
1037917SReza.Sabdar@Sun.COM  * tlm_output_dir
1047917SReza.Sabdar@Sun.COM  *
1057917SReza.Sabdar@Sun.COM  * Put the directory information into the output buffers.
1067917SReza.Sabdar@Sun.COM  */
1077917SReza.Sabdar@Sun.COM int
tlm_output_dir(char * name,tlm_acls_t * tlm_acls,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)1087917SReza.Sabdar@Sun.COM tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
1097917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1107917SReza.Sabdar@Sun.COM {
1117917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
1127917SReza.Sabdar@Sun.COM 
1137917SReza.Sabdar@Sun.COM 	/*
1147917SReza.Sabdar@Sun.COM 	 * Send the node or path history of the directory itself.
1157917SReza.Sabdar@Sun.COM 	 */
1167917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
1177917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
1187917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
1197917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
1207917SReza.Sabdar@Sun.COM 	/* fhdir_cb is handled in ndmpd_tar3.c */
1217917SReza.Sabdar@Sun.COM 
1227917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
1237917SReza.Sabdar@Sun.COM 	    local_commands);
1247917SReza.Sabdar@Sun.COM 	(void) output_file_header(name, "", tlm_acls, 0,
1257917SReza.Sabdar@Sun.COM 	    local_commands);
1267917SReza.Sabdar@Sun.COM 
1277917SReza.Sabdar@Sun.COM 	return (0);
1287917SReza.Sabdar@Sun.COM }
1297917SReza.Sabdar@Sun.COM 
1307917SReza.Sabdar@Sun.COM /*
1317917SReza.Sabdar@Sun.COM  * tar_putdir
1327917SReza.Sabdar@Sun.COM  *
1337917SReza.Sabdar@Sun.COM  * Main dir backup function for tar
1347917SReza.Sabdar@Sun.COM  */
1357917SReza.Sabdar@Sun.COM int
tar_putdir(char * name,tlm_acls_t * tlm_acls,tlm_cmd_t * local_commands,tlm_job_stats_t * job_stats)1367917SReza.Sabdar@Sun.COM tar_putdir(char *name, tlm_acls_t *tlm_acls,
1377917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
1387917SReza.Sabdar@Sun.COM {
1397917SReza.Sabdar@Sun.COM 	int rv;
1407917SReza.Sabdar@Sun.COM 
1417917SReza.Sabdar@Sun.COM 	rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats);
1427917SReza.Sabdar@Sun.COM 	return (rv < 0 ? rv : 0);
1437917SReza.Sabdar@Sun.COM }
1447917SReza.Sabdar@Sun.COM 
1457917SReza.Sabdar@Sun.COM /*
1467917SReza.Sabdar@Sun.COM  * output_acl_header
1477917SReza.Sabdar@Sun.COM  *
1487917SReza.Sabdar@Sun.COM  * output the ACL header record and data
1497917SReza.Sabdar@Sun.COM  */
1507917SReza.Sabdar@Sun.COM static int
output_acl_header(sec_attr_t * acl_info,tlm_cmd_t * local_commands)1517917SReza.Sabdar@Sun.COM output_acl_header(sec_attr_t *acl_info,
1527917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands)
1537917SReza.Sabdar@Sun.COM {
1547917SReza.Sabdar@Sun.COM 	long	actual_size;
1557917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
1567917SReza.Sabdar@Sun.COM 	long	acl_size;
1577917SReza.Sabdar@Sun.COM 
1587917SReza.Sabdar@Sun.COM 	if ((acl_info == NULL) || (*acl_info->attr_info == '\0'))
1597917SReza.Sabdar@Sun.COM 		return (0);
1607917SReza.Sabdar@Sun.COM 
1617917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
1627917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
1637917SReza.Sabdar@Sun.COM 	if (!tar_hdr)
1647917SReza.Sabdar@Sun.COM 		return (0);
1657917SReza.Sabdar@Sun.COM 
1667917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_ACL;
1677917SReza.Sabdar@Sun.COM 	acl_info->attr_type = UFSD_ACL;
1687917SReza.Sabdar@Sun.COM 	(void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len),
1697917SReza.Sabdar@Sun.COM 	    "%06o", strlen(acl_info->attr_info));
1707917SReza.Sabdar@Sun.COM 
1717917SReza.Sabdar@Sun.COM 	acl_size = sizeof (*acl_info);
1727917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE);
1737917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
1747917SReza.Sabdar@Sun.COM 	    acl_size);
1757917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
1767917SReza.Sabdar@Sun.COM 	    0444);
1777917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0);
1787917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0);
1797917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
1807917SReza.Sabdar@Sun.COM 	    "%011o ", 0);
1817917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
1827917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
1837917SReza.Sabdar@Sun.COM 
1847917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
1857917SReza.Sabdar@Sun.COM 
1867917SReza.Sabdar@Sun.COM 	(void) output_mem(local_commands, (void *)acl_info, acl_size);
1877917SReza.Sabdar@Sun.COM 	return (0);
1887917SReza.Sabdar@Sun.COM }
1897917SReza.Sabdar@Sun.COM 
1907917SReza.Sabdar@Sun.COM /*
1917917SReza.Sabdar@Sun.COM  * output_humongus_header
1927917SReza.Sabdar@Sun.COM  *
1937917SReza.Sabdar@Sun.COM  * output a special header record for HUGE files
1947917SReza.Sabdar@Sun.COM  * output is:	1) a TAR "HUGE" header redord
1957917SReza.Sabdar@Sun.COM  * 		2) a "file" of size, name
1967917SReza.Sabdar@Sun.COM  */
1977917SReza.Sabdar@Sun.COM static int
output_humongus_header(char * fullname,longlong_t file_size,tlm_cmd_t * local_commands)1987917SReza.Sabdar@Sun.COM output_humongus_header(char *fullname, longlong_t file_size,
1997917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands)
2007917SReza.Sabdar@Sun.COM {
2017917SReza.Sabdar@Sun.COM 	char	*buf;
2027917SReza.Sabdar@Sun.COM 	int	len;
2037917SReza.Sabdar@Sun.COM 	long	actual_size;
2047917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
2057917SReza.Sabdar@Sun.COM 
2067917SReza.Sabdar@Sun.COM 	/*
2077917SReza.Sabdar@Sun.COM 	 * buf will contain: "%llu %s":
2087917SReza.Sabdar@Sun.COM 	 * - 20 is the maximum length of 'ulong_tlong' decimal notation.
2097917SReza.Sabdar@Sun.COM 	 * - The first '1' is for the ' ' between the "%llu" and the fullname.
2107917SReza.Sabdar@Sun.COM 	 * - The last '1' is for the null-terminator of fullname.
2117917SReza.Sabdar@Sun.COM 	 */
2127917SReza.Sabdar@Sun.COM 	len = 20 + 1 + strlen(fullname) + 1;
2137917SReza.Sabdar@Sun.COM 
2147917SReza.Sabdar@Sun.COM 	if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
2157917SReza.Sabdar@Sun.COM 		return (-1);
2167917SReza.Sabdar@Sun.COM 
2177917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2187917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
2197917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
2207917SReza.Sabdar@Sun.COM 		free(buf);
2217917SReza.Sabdar@Sun.COM 		return (0);
2227917SReza.Sabdar@Sun.COM 	}
2237917SReza.Sabdar@Sun.COM 
2247917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_HUMONGUS;
2257917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2267917SReza.Sabdar@Sun.COM 	    len);
2277917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
2287917SReza.Sabdar@Sun.COM 	(void) snprintf(buf, len, "%lld %s", file_size, fullname);
2297917SReza.Sabdar@Sun.COM 	(void) output_mem(local_commands, buf, len);
2307917SReza.Sabdar@Sun.COM 
2317917SReza.Sabdar@Sun.COM 	free(buf);
2327917SReza.Sabdar@Sun.COM 	return (0);
2337917SReza.Sabdar@Sun.COM }
2347917SReza.Sabdar@Sun.COM 
2357917SReza.Sabdar@Sun.COM 
2367917SReza.Sabdar@Sun.COM /*
2377917SReza.Sabdar@Sun.COM  * output_xattr_header
2387917SReza.Sabdar@Sun.COM  *
2397917SReza.Sabdar@Sun.COM  * output the TAR header record for extended attributes
2407917SReza.Sabdar@Sun.COM  */
2417917SReza.Sabdar@Sun.COM static int
output_xattr_header(char * fname,char * aname,int fd,tlm_acls_t * tlm_acls,int section,tlm_cmd_t * local_commands)2427917SReza.Sabdar@Sun.COM output_xattr_header(char *fname, char *aname, int fd,
2437917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
2447917SReza.Sabdar@Sun.COM {
2457917SReza.Sabdar@Sun.COM 	struct stat64 *attr = &tlm_acls->acl_attr;
2467917SReza.Sabdar@Sun.COM 	struct xattr_hdr *xhdr;
2477917SReza.Sabdar@Sun.COM 	struct xattr_buf *xbuf;
2487917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
2497917SReza.Sabdar@Sun.COM 	long	actual_size;
2507917SReza.Sabdar@Sun.COM 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
2517917SReza.Sabdar@Sun.COM 	int	hsize;
2527917SReza.Sabdar@Sun.COM 	int	comlen;
2537917SReza.Sabdar@Sun.COM 	int	namesz;
2547917SReza.Sabdar@Sun.COM 
2557917SReza.Sabdar@Sun.COM 	if (section_name == NULL)
2567917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
2577917SReza.Sabdar@Sun.COM 
2587917SReza.Sabdar@Sun.COM 	if (fstat64(fd, attr) == -1) {
2597917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "output_file_header stat failed.");
2607917SReza.Sabdar@Sun.COM 		free(section_name);
2617917SReza.Sabdar@Sun.COM 		return (-TLM_OPEN_ERR);
2627917SReza.Sabdar@Sun.COM 	}
2637917SReza.Sabdar@Sun.COM 
2647917SReza.Sabdar@Sun.COM 	/*
2657917SReza.Sabdar@Sun.COM 	 * if the file has to go out in sections,
2667917SReza.Sabdar@Sun.COM 	 * we must mung the name.
2677917SReza.Sabdar@Sun.COM 	 */
2687917SReza.Sabdar@Sun.COM 	if (section == 0) {
2697917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name, TLM_MAX_PATH_NAME,
2707917SReza.Sabdar@Sun.COM 		    "/dev/null/%s.hdr", aname);
2717917SReza.Sabdar@Sun.COM 	} else {
2727917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name,
2737917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
2747917SReza.Sabdar@Sun.COM 	}
2757917SReza.Sabdar@Sun.COM 	namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
2767917SReza.Sabdar@Sun.COM 	hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
2777917SReza.Sabdar@Sun.COM 	comlen = namesz + sizeof (struct xattr_buf);
2787917SReza.Sabdar@Sun.COM 
2797917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
2807917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
2817917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
2827917SReza.Sabdar@Sun.COM 		free(section_name);
2837917SReza.Sabdar@Sun.COM 		return (0);
2847917SReza.Sabdar@Sun.COM 	}
2857917SReza.Sabdar@Sun.COM 
2867917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
2877917SReza.Sabdar@Sun.COM 
2887917SReza.Sabdar@Sun.COM 	tar_hdr->th_linkflag = LF_XATTR;
2897917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
2907917SReza.Sabdar@Sun.COM 	    hsize);
2917917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
2927917SReza.Sabdar@Sun.COM 	    attr->st_mode & 07777);
2937917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
2947917SReza.Sabdar@Sun.COM 	    attr->st_uid);
2957917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
2967917SReza.Sabdar@Sun.COM 	    attr->st_gid);
2977917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
2987917SReza.Sabdar@Sun.COM 	    attr->st_mtime);
2997917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
3007917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
3017917SReza.Sabdar@Sun.COM 
3028540SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "xattr_hdr: %s size %d mode %06o uid %d gid %d",
3038540SReza.Sabdar@Sun.COM 	    aname, hsize, attr->st_mode & 07777, attr->st_uid, attr->st_gid);
3048540SReza.Sabdar@Sun.COM 
3057917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
3067917SReza.Sabdar@Sun.COM 
3077917SReza.Sabdar@Sun.COM 	xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE,
3087917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
3097917SReza.Sabdar@Sun.COM 	if (!xhdr) {
3107917SReza.Sabdar@Sun.COM 		free(section_name);
3117917SReza.Sabdar@Sun.COM 		return (0);
3127917SReza.Sabdar@Sun.COM 	}
3137917SReza.Sabdar@Sun.COM 
3147917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s",
3157917SReza.Sabdar@Sun.COM 	    XATTR_ARCH_VERS);
3167917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d",
3177917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_size) - 1, hsize);
3187917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len),
3197917SReza.Sabdar@Sun.COM 	    "%0*d", sizeof (xhdr->h_component_len) - 1, comlen);
3207917SReza.Sabdar@Sun.COM 	(void) snprintf(xhdr->h_link_component_len,
3217917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_link_component_len), "%0*d",
3227917SReza.Sabdar@Sun.COM 	    sizeof (xhdr->h_link_component_len) - 1, 0);
3237917SReza.Sabdar@Sun.COM 
3247917SReza.Sabdar@Sun.COM 	xbuf = (struct xattr_buf *)(((caddr_t)xhdr) +
3257917SReza.Sabdar@Sun.COM 	    sizeof (struct xattr_hdr));
3267917SReza.Sabdar@Sun.COM 	(void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d",
3277917SReza.Sabdar@Sun.COM 	    sizeof (xbuf->h_namesz) - 1, namesz);
3287917SReza.Sabdar@Sun.COM 
3297917SReza.Sabdar@Sun.COM 	/* No support for links in extended attributes */
3307917SReza.Sabdar@Sun.COM 	xbuf->h_typeflag = LF_NORMAL;
3317917SReza.Sabdar@Sun.COM 
3327917SReza.Sabdar@Sun.COM 	(void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE);
3337917SReza.Sabdar@Sun.COM 	(void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname,
3347917SReza.Sabdar@Sun.COM 	    TLM_NAME_SIZE);
3357917SReza.Sabdar@Sun.COM 
3367917SReza.Sabdar@Sun.COM 	free(section_name);
3377917SReza.Sabdar@Sun.COM 	return (0);
3387917SReza.Sabdar@Sun.COM }
3397917SReza.Sabdar@Sun.COM 
3407917SReza.Sabdar@Sun.COM 
3417917SReza.Sabdar@Sun.COM /*
3427917SReza.Sabdar@Sun.COM  * output_file_header
3437917SReza.Sabdar@Sun.COM  *
3447917SReza.Sabdar@Sun.COM  * output the TAR header record
3457917SReza.Sabdar@Sun.COM  */
3467917SReza.Sabdar@Sun.COM static int
output_file_header(char * name,char * link,tlm_acls_t * tlm_acls,int section,tlm_cmd_t * local_commands)3477917SReza.Sabdar@Sun.COM output_file_header(char *name, char *link,
3487917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
3497917SReza.Sabdar@Sun.COM {
3507917SReza.Sabdar@Sun.COM 	static	longlong_t file_count = 0;
3517917SReza.Sabdar@Sun.COM 	struct stat64 *attr = &tlm_acls->acl_attr;
3527917SReza.Sabdar@Sun.COM 	tlm_tar_hdr_t *tar_hdr;
3537917SReza.Sabdar@Sun.COM 	long	actual_size;
3547917SReza.Sabdar@Sun.COM 	boolean_t long_name = FALSE;
3557917SReza.Sabdar@Sun.COM 	boolean_t long_link = FALSE;
3567917SReza.Sabdar@Sun.COM 	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
3577917SReza.Sabdar@Sun.COM 	int	nmlen, lnklen;
3588540SReza.Sabdar@Sun.COM 	uid_t uid;
3598540SReza.Sabdar@Sun.COM 	gid_t gid;
3608540SReza.Sabdar@Sun.COM 	char *uname = "";
3618540SReza.Sabdar@Sun.COM 	char *gname = "";
3628540SReza.Sabdar@Sun.COM 	struct passwd *pwd;
3638540SReza.Sabdar@Sun.COM 	struct group *grp;
3647917SReza.Sabdar@Sun.COM 
3657917SReza.Sabdar@Sun.COM 	if (section_name == NULL)
3667917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
3677917SReza.Sabdar@Sun.COM 
3687917SReza.Sabdar@Sun.COM 	/*
3697917SReza.Sabdar@Sun.COM 	 * if the file has to go out in sections,
3707917SReza.Sabdar@Sun.COM 	 * we must mung the name.
3717917SReza.Sabdar@Sun.COM 	 */
3727917SReza.Sabdar@Sun.COM 	if (section == 0) {
3737917SReza.Sabdar@Sun.COM 		(void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
3747917SReza.Sabdar@Sun.COM 	} else {
3757917SReza.Sabdar@Sun.COM 		(void) snprintf(section_name,
3767917SReza.Sabdar@Sun.COM 		    TLM_MAX_PATH_NAME, "%s.%03d", name, section);
3777917SReza.Sabdar@Sun.COM 	}
3787917SReza.Sabdar@Sun.COM 
3798540SReza.Sabdar@Sun.COM 	if ((pwd = getpwuid(attr->st_uid)) != NULL)
3808540SReza.Sabdar@Sun.COM 		uname = pwd->pw_name;
3818540SReza.Sabdar@Sun.COM 	if ((grp = getgrgid(attr->st_gid)) != NULL)
3828540SReza.Sabdar@Sun.COM 		gname = grp->gr_name;
3838540SReza.Sabdar@Sun.COM 
3848540SReza.Sabdar@Sun.COM 	if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR)
3858540SReza.Sabdar@Sun.COM 		uid = UID_NOBODY;
3868540SReza.Sabdar@Sun.COM 	if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR)
3878540SReza.Sabdar@Sun.COM 		gid = GID_NOBODY;
3888540SReza.Sabdar@Sun.COM 
3897917SReza.Sabdar@Sun.COM 	nmlen = strlen(section_name);
3907917SReza.Sabdar@Sun.COM 	if (nmlen >= NAMSIZ) {
3917917SReza.Sabdar@Sun.COM 		/*
3927917SReza.Sabdar@Sun.COM 		 * file name is too big, it must go out
3937917SReza.Sabdar@Sun.COM 		 * in its own data file
3947917SReza.Sabdar@Sun.COM 		 */
3957917SReza.Sabdar@Sun.COM 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
3967917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
3977917SReza.Sabdar@Sun.COM 		if (!tar_hdr) {
3987917SReza.Sabdar@Sun.COM 			free(section_name);
3997917SReza.Sabdar@Sun.COM 			return (0);
4007917SReza.Sabdar@Sun.COM 		}
4017917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_name,
4027917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4037917SReza.Sabdar@Sun.COM 		    "%s%08qd.fil",
4047917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4057917SReza.Sabdar@Sun.COM 		    file_count++);
4067917SReza.Sabdar@Sun.COM 
4077917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LONGNAME;
4087917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
4097917SReza.Sabdar@Sun.COM 		    "%011o ", nmlen);
4107917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
4117917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_mode & 07777);
4127917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
4138540SReza.Sabdar@Sun.COM 		    "%06o ", uid);
4147917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
4158540SReza.Sabdar@Sun.COM 		    "%06o ", gid);
4168540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
4178540SReza.Sabdar@Sun.COM 		    "%.31s", uname);
4188540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
4198540SReza.Sabdar@Sun.COM 		    "%.31s", gname);
4207917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
4217917SReza.Sabdar@Sun.COM 		    "%011o ", attr->st_mtime);
4227917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4237917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_magic));
4247917SReza.Sabdar@Sun.COM 
4257917SReza.Sabdar@Sun.COM 		tlm_build_header_checksum(tar_hdr);
4267917SReza.Sabdar@Sun.COM 
4277917SReza.Sabdar@Sun.COM 		(void) output_mem(local_commands,
4287917SReza.Sabdar@Sun.COM 		    (void *)section_name, nmlen);
4297917SReza.Sabdar@Sun.COM 		long_name = TRUE;
4307917SReza.Sabdar@Sun.COM 	}
4317917SReza.Sabdar@Sun.COM 
4327917SReza.Sabdar@Sun.COM 	lnklen = strlen(link);
4337917SReza.Sabdar@Sun.COM 	if (lnklen >= NAMSIZ) {
4347917SReza.Sabdar@Sun.COM 		/*
4357917SReza.Sabdar@Sun.COM 		 * link name is too big, it must go out
4367917SReza.Sabdar@Sun.COM 		 * in its own data file
4377917SReza.Sabdar@Sun.COM 		 */
4387917SReza.Sabdar@Sun.COM 		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4397917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
4407917SReza.Sabdar@Sun.COM 		if (!tar_hdr) {
4417917SReza.Sabdar@Sun.COM 			free(section_name);
4427917SReza.Sabdar@Sun.COM 			return (0);
4437917SReza.Sabdar@Sun.COM 		}
4447917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_linkname,
4457917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4467917SReza.Sabdar@Sun.COM 		    "%s%08qd.slk",
4477917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4487917SReza.Sabdar@Sun.COM 		    file_count++);
4497917SReza.Sabdar@Sun.COM 
4507917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_LONGLINK;
4517917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
4527917SReza.Sabdar@Sun.COM 		    "%011o ", lnklen);
4537917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
4547917SReza.Sabdar@Sun.COM 		    "%06o ", attr->st_mode & 07777);
4557917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
4568540SReza.Sabdar@Sun.COM 		    "%06o ", uid);
4577917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
4588540SReza.Sabdar@Sun.COM 		    "%06o ", gid);
4598540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
4608540SReza.Sabdar@Sun.COM 		    "%.31s", uname);
4618540SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
4628540SReza.Sabdar@Sun.COM 		    "%.31s", gname);
4637917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
4647917SReza.Sabdar@Sun.COM 		    "%011o ", attr->st_mtime);
4657917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
4667917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_magic));
4677917SReza.Sabdar@Sun.COM 
4687917SReza.Sabdar@Sun.COM 		tlm_build_header_checksum(tar_hdr);
4697917SReza.Sabdar@Sun.COM 
4707917SReza.Sabdar@Sun.COM 		(void) output_mem(local_commands, (void *)link,
4717917SReza.Sabdar@Sun.COM 		    lnklen);
4727917SReza.Sabdar@Sun.COM 		long_link = TRUE;
4737917SReza.Sabdar@Sun.COM 	}
4747917SReza.Sabdar@Sun.COM 	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
4757917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
4767917SReza.Sabdar@Sun.COM 	if (!tar_hdr) {
4777917SReza.Sabdar@Sun.COM 		free(section_name);
4787917SReza.Sabdar@Sun.COM 		return (0);
4797917SReza.Sabdar@Sun.COM 	}
4807917SReza.Sabdar@Sun.COM 	if (long_name) {
4817917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_name,
4827917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4837917SReza.Sabdar@Sun.COM 		    "%s%08qd.fil",
4847917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4857917SReza.Sabdar@Sun.COM 		    file_count++);
4867917SReza.Sabdar@Sun.COM 	} else {
4877917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
4887917SReza.Sabdar@Sun.COM 	}
4897917SReza.Sabdar@Sun.COM 
4907917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "long_link: %s [%s]", long_link ? "TRUE" : "FALSE",
4917917SReza.Sabdar@Sun.COM 	    link);
4927917SReza.Sabdar@Sun.COM 
4937917SReza.Sabdar@Sun.COM 	if (long_link) {
4947917SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_linkname,
4957917SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_name),
4967917SReza.Sabdar@Sun.COM 		    "%s%08qd.slk",
4977917SReza.Sabdar@Sun.COM 		    LONGNAME_PREFIX,
4987917SReza.Sabdar@Sun.COM 		    file_count++);
4997917SReza.Sabdar@Sun.COM 	} else {
5007917SReza.Sabdar@Sun.COM 		(void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
5017917SReza.Sabdar@Sun.COM 	}
502*12353SReza.Sabdar@Sun.COM 	switch (attr->st_mode & S_IFMT) {
503*12353SReza.Sabdar@Sun.COM 	case S_IFDIR:
5047917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_DIR;
505*12353SReza.Sabdar@Sun.COM 		break;
506*12353SReza.Sabdar@Sun.COM 	case S_IFIFO:
5077917SReza.Sabdar@Sun.COM 		tar_hdr->th_linkflag = LF_FIFO;
508*12353SReza.Sabdar@Sun.COM 		break;
509*12353SReza.Sabdar@Sun.COM 	case S_IFBLK:
510*12353SReza.Sabdar@Sun.COM 	case S_IFCHR:
511*12353SReza.Sabdar@Sun.COM 		if (S_ISBLK(attr->st_mode))
512*12353SReza.Sabdar@Sun.COM 			tar_hdr->th_linkflag = LF_BLK;
513*12353SReza.Sabdar@Sun.COM 		else
514*12353SReza.Sabdar@Sun.COM 			tar_hdr->th_linkflag = LF_CHR;
515*12353SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor,
516*12353SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ",
517*12353SReza.Sabdar@Sun.COM 		    major(attr->st_rdev));
518*12353SReza.Sabdar@Sun.COM 		(void) snprintf(tar_hdr->th_shared.th_dev.th_devminor,
519*12353SReza.Sabdar@Sun.COM 		    sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ",
520*12353SReza.Sabdar@Sun.COM 		    minor(attr->st_rdev));
521*12353SReza.Sabdar@Sun.COM 		break;
522*12353SReza.Sabdar@Sun.COM 	default:
523*12353SReza.Sabdar@Sun.COM 		if (attr->st_nlink > 1) {
524*12353SReza.Sabdar@Sun.COM 			/* mark file with hardlink LF_LINK */
525*12353SReza.Sabdar@Sun.COM 			tar_hdr->th_linkflag = LF_LINK;
526*12353SReza.Sabdar@Sun.COM 			(void) snprintf(tar_hdr->th_shared.th_hlink_ino,
527*12353SReza.Sabdar@Sun.COM 			    sizeof (tar_hdr->th_shared.th_hlink_ino),
528*12353SReza.Sabdar@Sun.COM 			    "%011llo ", attr->st_ino);
529*12353SReza.Sabdar@Sun.COM 		} else {
530*12353SReza.Sabdar@Sun.COM 			tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL :
531*12353SReza.Sabdar@Sun.COM 			    LF_SYMLINK;
532*12353SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "linkflag: '%c'",
533*12353SReza.Sabdar@Sun.COM 			    tar_hdr->th_linkflag);
534*12353SReza.Sabdar@Sun.COM 		}
5357917SReza.Sabdar@Sun.COM 	}
5367917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
5377917SReza.Sabdar@Sun.COM 	    (long)attr->st_size);
5387917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
5397917SReza.Sabdar@Sun.COM 	    attr->st_mode & 07777);
5407917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
5418540SReza.Sabdar@Sun.COM 	    uid);
5427917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
5438540SReza.Sabdar@Sun.COM 	    gid);
5448540SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
5458540SReza.Sabdar@Sun.COM 	    uname);
5468540SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
5478540SReza.Sabdar@Sun.COM 	    gname);
5487917SReza.Sabdar@Sun.COM 	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
5497917SReza.Sabdar@Sun.COM 	    attr->st_mtime);
5507917SReza.Sabdar@Sun.COM 	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
5517917SReza.Sabdar@Sun.COM 	    sizeof (tar_hdr->th_magic));
5527917SReza.Sabdar@Sun.COM 
5537917SReza.Sabdar@Sun.COM 	tlm_build_header_checksum(tar_hdr);
5547917SReza.Sabdar@Sun.COM 	if (long_name || long_link) {
5557917SReza.Sabdar@Sun.COM 		if (file_count > 99999990) {
5567917SReza.Sabdar@Sun.COM 			file_count = 0;
5577917SReza.Sabdar@Sun.COM 		}
5587917SReza.Sabdar@Sun.COM 	}
5597917SReza.Sabdar@Sun.COM 	free(section_name);
5607917SReza.Sabdar@Sun.COM 	return (0);
5617917SReza.Sabdar@Sun.COM }
5627917SReza.Sabdar@Sun.COM 
5637917SReza.Sabdar@Sun.COM 
5647917SReza.Sabdar@Sun.COM /*
5657917SReza.Sabdar@Sun.COM  * tlm_readlink
5667917SReza.Sabdar@Sun.COM  *
5677917SReza.Sabdar@Sun.COM  * Read where the softlink points to.  Read the link in the checkpointed
5687917SReza.Sabdar@Sun.COM  * path if the backup is being done on a checkpointed file system.
5697917SReza.Sabdar@Sun.COM  */
5707917SReza.Sabdar@Sun.COM static int
tlm_readlink(char * nm,char * snap,char * buf,int bufsize)5717917SReza.Sabdar@Sun.COM tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
5727917SReza.Sabdar@Sun.COM {
5737917SReza.Sabdar@Sun.COM 	int len;
5747917SReza.Sabdar@Sun.COM 
5757917SReza.Sabdar@Sun.COM 	if ((len = readlink(snap, buf, bufsize)) >= 0) {
5767917SReza.Sabdar@Sun.COM 		/*
5777917SReza.Sabdar@Sun.COM 		 * realink(2) doesn't null terminate the link name.  We must
5787917SReza.Sabdar@Sun.COM 		 * do it here.
5797917SReza.Sabdar@Sun.COM 		 */
5807917SReza.Sabdar@Sun.COM 		buf[len] = '\0';
5817917SReza.Sabdar@Sun.COM 	} else {
5827917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Error %d reading softlink of [%s]",
5837917SReza.Sabdar@Sun.COM 		    errno, nm);
5847917SReza.Sabdar@Sun.COM 		buf[0] = '\0';
5857917SReza.Sabdar@Sun.COM 
5867917SReza.Sabdar@Sun.COM 		/* Backup the link if the destination missing */
5877917SReza.Sabdar@Sun.COM 		if (errno == ENOENT)
5887917SReza.Sabdar@Sun.COM 			return (0);
5897917SReza.Sabdar@Sun.COM 
5907917SReza.Sabdar@Sun.COM 	}
5917917SReza.Sabdar@Sun.COM 
5927917SReza.Sabdar@Sun.COM 	return (len);
5937917SReza.Sabdar@Sun.COM }
5947917SReza.Sabdar@Sun.COM 
5958540SReza.Sabdar@Sun.COM /*
5968540SReza.Sabdar@Sun.COM  * Read the system attribute file in a single buffer to write
5978540SReza.Sabdar@Sun.COM  * it as a single write. A partial write to system attribute would
5988540SReza.Sabdar@Sun.COM  * cause an EINVAL on write.
5998540SReza.Sabdar@Sun.COM  */
6008540SReza.Sabdar@Sun.COM static char *
get_write_one_buf(char * buf,char * rec,int buf_size,int rec_size,tlm_cmd_t * lc)6018540SReza.Sabdar@Sun.COM get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
6028540SReza.Sabdar@Sun.COM     tlm_cmd_t *lc)
6038540SReza.Sabdar@Sun.COM {
6048540SReza.Sabdar@Sun.COM 	int len;
6058540SReza.Sabdar@Sun.COM 	long write_size;
6068540SReza.Sabdar@Sun.COM 
6078540SReza.Sabdar@Sun.COM 	if (rec_size > buf_size)
6088540SReza.Sabdar@Sun.COM 		return (rec);
6098540SReza.Sabdar@Sun.COM 
6108540SReza.Sabdar@Sun.COM 	len = rec_size;
6118540SReza.Sabdar@Sun.COM 	(void) memcpy(rec, buf, len);
6128540SReza.Sabdar@Sun.COM 	buf += len;
6138540SReza.Sabdar@Sun.COM 	while (rec_size < buf_size) {
6148540SReza.Sabdar@Sun.COM 		rec = get_write_buffer(buf_size - rec_size,
6158540SReza.Sabdar@Sun.COM 		    &write_size, FALSE, lc);
6168540SReza.Sabdar@Sun.COM 		if (!rec)
6178540SReza.Sabdar@Sun.COM 			return (0);
6188540SReza.Sabdar@Sun.COM 
6198540SReza.Sabdar@Sun.COM 		len = min(buf_size - rec_size, write_size);
6208540SReza.Sabdar@Sun.COM 		(void) memcpy(rec, buf, len);
6218540SReza.Sabdar@Sun.COM 		rec_size += len;
6228540SReza.Sabdar@Sun.COM 		buf += len;
6238540SReza.Sabdar@Sun.COM 	}
6248540SReza.Sabdar@Sun.COM 	return (rec);
6258540SReza.Sabdar@Sun.COM }
6268540SReza.Sabdar@Sun.COM 
6277917SReza.Sabdar@Sun.COM 
6287917SReza.Sabdar@Sun.COM /*
6297917SReza.Sabdar@Sun.COM  * tlm_output_xattr
6307917SReza.Sabdar@Sun.COM  *
6317917SReza.Sabdar@Sun.COM  * Put this file into the output buffers.
6327917SReza.Sabdar@Sun.COM  */
6337917SReza.Sabdar@Sun.COM /*ARGSUSED*/
6347917SReza.Sabdar@Sun.COM 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)6357917SReza.Sabdar@Sun.COM tlm_output_xattr(char  *dir, char *name, char *chkdir,
6367917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
6377917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
6387917SReza.Sabdar@Sun.COM {
6397917SReza.Sabdar@Sun.COM 	char	*fullname;		/* directory + name */
6407917SReza.Sabdar@Sun.COM 	char	*snapname;		/* snapshot name */
6417917SReza.Sabdar@Sun.COM 	int	section;		/* section of a huge file */
6427917SReza.Sabdar@Sun.COM 	int	fd;
6439323SReza.Sabdar@Sun.COM 	int	afd = 0;
6447917SReza.Sabdar@Sun.COM 	longlong_t seek_spot = 0;	/* location in the file */
6457917SReza.Sabdar@Sun.COM 					/* for Multi Volume record */
6467917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
6477917SReza.Sabdar@Sun.COM 	DIR *dp;
6487917SReza.Sabdar@Sun.COM 	struct dirent *dtp;
6497917SReza.Sabdar@Sun.COM 	char *attrname;
6507917SReza.Sabdar@Sun.COM 	char *fnamep;
6517917SReza.Sabdar@Sun.COM 	int rv = 0;
6527917SReza.Sabdar@Sun.COM 
653*12353SReza.Sabdar@Sun.COM 	if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
6547917SReza.Sabdar@Sun.COM 		return (TLM_NO_SOURCE_FILE);
6559659SReza.Sabdar@Sun.COM 	}
6567917SReza.Sabdar@Sun.COM 
6577917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
6587917SReza.Sabdar@Sun.COM 	if (fullname == NULL) {
6597917SReza.Sabdar@Sun.COM 		free(fullname);
6607917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
6617917SReza.Sabdar@Sun.COM 	}
6627917SReza.Sabdar@Sun.COM 
6637917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name)) {
6647917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6657917SReza.Sabdar@Sun.COM 		free(fullname);
6667917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
6677917SReza.Sabdar@Sun.COM 	}
6687917SReza.Sabdar@Sun.COM 
6698540SReza.Sabdar@Sun.COM 	if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
6708540SReza.Sabdar@Sun.COM 	    sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
6717917SReza.Sabdar@Sun.COM 		free(fullname);
6727917SReza.Sabdar@Sun.COM 		return (0);
6737917SReza.Sabdar@Sun.COM 	}
6747917SReza.Sabdar@Sun.COM 
6757917SReza.Sabdar@Sun.COM 	attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
6767917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
6777917SReza.Sabdar@Sun.COM 	if (attrname == NULL || snapname == NULL) {
6787917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
6797917SReza.Sabdar@Sun.COM 		goto err_out;
6807917SReza.Sabdar@Sun.COM 	}
6817917SReza.Sabdar@Sun.COM 
6827917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(snapname, chkdir, name)) {
6837917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
6847917SReza.Sabdar@Sun.COM 		rv = -TLM_NO_SCRATCH_SPACE;
6857917SReza.Sabdar@Sun.COM 		goto err_out;
6867917SReza.Sabdar@Sun.COM 	}
6877917SReza.Sabdar@Sun.COM 
6887917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
6897917SReza.Sabdar@Sun.COM 
6907917SReza.Sabdar@Sun.COM 	/*
6917917SReza.Sabdar@Sun.COM 	 * Open the file for reading.
6927917SReza.Sabdar@Sun.COM 	 */
6938540SReza.Sabdar@Sun.COM 	fd = attropen(fnamep, ".", O_RDONLY);
6947917SReza.Sabdar@Sun.COM 	if (fd == -1) {
6958540SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s][%s]",
6968540SReza.Sabdar@Sun.COM 		    fullname, fnamep);
6977917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
6987917SReza.Sabdar@Sun.COM 		goto err_out;
6997917SReza.Sabdar@Sun.COM 	}
7007917SReza.Sabdar@Sun.COM 
7017917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
7027917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
7037917SReza.Sabdar@Sun.COM 
7047917SReza.Sabdar@Sun.COM 	section = 0;
7057917SReza.Sabdar@Sun.COM 
7067917SReza.Sabdar@Sun.COM 	dp = (DIR *)fdopendir(fd);
7077917SReza.Sabdar@Sun.COM 	if (dp == NULL) {
7087917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
7097917SReza.Sabdar@Sun.COM 		(void) close(fd);
7107917SReza.Sabdar@Sun.COM 		rv = TLM_NO_SOURCE_FILE;
7117917SReza.Sabdar@Sun.COM 		goto err_out;
7127917SReza.Sabdar@Sun.COM 	}
7137917SReza.Sabdar@Sun.COM 
7147917SReza.Sabdar@Sun.COM 	while ((dtp = readdir(dp)) != NULL) {
7157917SReza.Sabdar@Sun.COM 		int section_size;
7167917SReza.Sabdar@Sun.COM 
7177917SReza.Sabdar@Sun.COM 		if (*dtp->d_name == '.')
7187917SReza.Sabdar@Sun.COM 			continue;
7197917SReza.Sabdar@Sun.COM 
7208540SReza.Sabdar@Sun.COM 		if (sysattr_rdonly(dtp->d_name))
7218540SReza.Sabdar@Sun.COM 			continue;
7228540SReza.Sabdar@Sun.COM 
7239323SReza.Sabdar@Sun.COM 		afd = attropen(fnamep, dtp->d_name, O_RDONLY);
7249323SReza.Sabdar@Sun.COM 		if (afd == -1) {
7257917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
7268540SReza.Sabdar@Sun.COM 			    "problem(%d) opening xattr file [%s][%s]", errno,
7278540SReza.Sabdar@Sun.COM 			    fullname, fnamep);
7287917SReza.Sabdar@Sun.COM 			goto tear_down;
7297917SReza.Sabdar@Sun.COM 		}
7307917SReza.Sabdar@Sun.COM 
7319323SReza.Sabdar@Sun.COM 		(void) output_xattr_header(fullname, dtp->d_name, afd,
7327917SReza.Sabdar@Sun.COM 		    tlm_acls, section, local_commands);
7337917SReza.Sabdar@Sun.COM 		(void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
7347917SReza.Sabdar@Sun.COM 		    dtp->d_name);
7357917SReza.Sabdar@Sun.COM 		(void) output_file_header(attrname, "", tlm_acls, 0,
7367917SReza.Sabdar@Sun.COM 		    local_commands);
7377917SReza.Sabdar@Sun.COM 
7387917SReza.Sabdar@Sun.COM 		section_size = (long)llmin(tlm_acls->acl_attr.st_size,
7397917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
7407917SReza.Sabdar@Sun.COM 
7417917SReza.Sabdar@Sun.COM 		/* We only can read upto one section extended attribute */
7427917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
7437917SReza.Sabdar@Sun.COM 			char	*buf;
7447917SReza.Sabdar@Sun.COM 			long	actual_size;
7457917SReza.Sabdar@Sun.COM 			int	read_size;
7468540SReza.Sabdar@Sun.COM 			int sysattr_read = 0;
7478540SReza.Sabdar@Sun.COM 			char *rec;
7488540SReza.Sabdar@Sun.COM 			int size;
7497917SReza.Sabdar@Sun.COM 
7507917SReza.Sabdar@Sun.COM 			/*
7517917SReza.Sabdar@Sun.COM 			 * check for Abort commands
7527917SReza.Sabdar@Sun.COM 			 */
7537917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7547917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
7557917SReza.Sabdar@Sun.COM 				goto tear_down;
7567917SReza.Sabdar@Sun.COM 			}
7577917SReza.Sabdar@Sun.COM 
7587917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
7597917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
7607917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
7617917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
7627917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
7637917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
7647917SReza.Sabdar@Sun.COM 
7657917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
7667917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
7677917SReza.Sabdar@Sun.COM 			if (!buf)
7687917SReza.Sabdar@Sun.COM 				goto tear_down;
7697917SReza.Sabdar@Sun.COM 
7708540SReza.Sabdar@Sun.COM 			if ((actual_size < section_size) &&
7718540SReza.Sabdar@Sun.COM 			    sysattr_rw(dtp->d_name)) {
7728540SReza.Sabdar@Sun.COM 				rec = buf;
7738540SReza.Sabdar@Sun.COM 				buf = ndmp_malloc(section_size);
7748540SReza.Sabdar@Sun.COM 				if (!buf)
7758540SReza.Sabdar@Sun.COM 					goto tear_down;
7768540SReza.Sabdar@Sun.COM 				size = actual_size;
7778540SReza.Sabdar@Sun.COM 				actual_size = section_size;
7788540SReza.Sabdar@Sun.COM 				sysattr_read = 1;
7798540SReza.Sabdar@Sun.COM 			}
7808540SReza.Sabdar@Sun.COM 
7817917SReza.Sabdar@Sun.COM 			/*
7827917SReza.Sabdar@Sun.COM 			 * check for Abort commands
7837917SReza.Sabdar@Sun.COM 			 */
7847917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
7857917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
7867917SReza.Sabdar@Sun.COM 				goto tear_down;
7877917SReza.Sabdar@Sun.COM 			}
7887917SReza.Sabdar@Sun.COM 
7897917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
7909323SReza.Sabdar@Sun.COM 			if ((actual_size = read(afd, buf, read_size)) < 0)
7918540SReza.Sabdar@Sun.COM 				break;
7928540SReza.Sabdar@Sun.COM 
7938540SReza.Sabdar@Sun.COM 			if (sysattr_read) {
7948540SReza.Sabdar@Sun.COM 				if (get_write_one_buf(buf, rec, read_size,
7958540SReza.Sabdar@Sun.COM 				    size, local_commands) == 0) {
7968540SReza.Sabdar@Sun.COM 					free(buf);
7978540SReza.Sabdar@Sun.COM 					goto tear_down;
7988540SReza.Sabdar@Sun.COM 				}
7998540SReza.Sabdar@Sun.COM 				free(buf);
8008540SReza.Sabdar@Sun.COM 			}
8018540SReza.Sabdar@Sun.COM 
8028540SReza.Sabdar@Sun.COM 
8037917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
8047917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
8057917SReza.Sabdar@Sun.COM 
8067917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
8077917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
8087917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
8097917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
8107917SReza.Sabdar@Sun.COM 				goto tear_down;
8117917SReza.Sabdar@Sun.COM 			}
8127917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
8137917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
8147917SReza.Sabdar@Sun.COM 		}
8159323SReza.Sabdar@Sun.COM 		(void) close(afd);
8169323SReza.Sabdar@Sun.COM 		afd = -1;
8177917SReza.Sabdar@Sun.COM 	}
8187917SReza.Sabdar@Sun.COM 
8197917SReza.Sabdar@Sun.COM tear_down:
8207917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
8217917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
8227917SReza.Sabdar@Sun.COM 
8239323SReza.Sabdar@Sun.COM 	if (afd > 0)
8249323SReza.Sabdar@Sun.COM 		(void) close(afd);
8259323SReza.Sabdar@Sun.COM 
8269323SReza.Sabdar@Sun.COM 	/* closedir closes fd too */
8277917SReza.Sabdar@Sun.COM 	(void) closedir(dp);
8287917SReza.Sabdar@Sun.COM 
8297917SReza.Sabdar@Sun.COM err_out:
8307917SReza.Sabdar@Sun.COM 	free(fullname);
8317917SReza.Sabdar@Sun.COM 	free(attrname);
8327917SReza.Sabdar@Sun.COM 	free(snapname);
8337917SReza.Sabdar@Sun.COM 	return (rv);
8347917SReza.Sabdar@Sun.COM }
8357917SReza.Sabdar@Sun.COM 
8367917SReza.Sabdar@Sun.COM 
8377917SReza.Sabdar@Sun.COM /*
8387917SReza.Sabdar@Sun.COM  * tlm_output_file
8397917SReza.Sabdar@Sun.COM  *
8407917SReza.Sabdar@Sun.COM  * Put this file into the output buffers.
8417917SReza.Sabdar@Sun.COM  */
8427917SReza.Sabdar@Sun.COM 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)8437917SReza.Sabdar@Sun.COM tlm_output_file(char *dir, char *name, char *chkdir,
8447917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
8457917SReza.Sabdar@Sun.COM     tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
8467917SReza.Sabdar@Sun.COM {
8477917SReza.Sabdar@Sun.COM 	char	*fullname;		/* directory + name */
8487917SReza.Sabdar@Sun.COM 	char	*snapname;		/* snapshot name */
8497917SReza.Sabdar@Sun.COM 	char	*linkname;		/* where this file points */
8507917SReza.Sabdar@Sun.COM 	int	section = 0;		/* section of a huge file */
8517917SReza.Sabdar@Sun.COM 	int	fd;
8527917SReza.Sabdar@Sun.COM 	longlong_t real_size;		/* the origional file size */
8537917SReza.Sabdar@Sun.COM 	longlong_t file_size;		/* real size of this file */
8547917SReza.Sabdar@Sun.COM 	longlong_t seek_spot = 0;	/* location in the file */
8557917SReza.Sabdar@Sun.COM 					/* for Multi Volume record */
8567917SReza.Sabdar@Sun.COM 	u_longlong_t pos;
8577917SReza.Sabdar@Sun.COM 	char *fnamep;
8587917SReza.Sabdar@Sun.COM 
8597917SReza.Sabdar@Sun.COM 	/* Indicate whether a file with the same inode has been backed up. */
8607917SReza.Sabdar@Sun.COM 	int hardlink_done = 0;
8617917SReza.Sabdar@Sun.COM 
8627917SReza.Sabdar@Sun.COM 	/*
8637917SReza.Sabdar@Sun.COM 	 * If a file with the same inode has been backed up, hardlink_pos holds
8647917SReza.Sabdar@Sun.COM 	 * the tape offset of the data record.
8657917SReza.Sabdar@Sun.COM 	 */
8667917SReza.Sabdar@Sun.COM 	u_longlong_t hardlink_pos = 0;
8677917SReza.Sabdar@Sun.COM 
8687917SReza.Sabdar@Sun.COM 	if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
8697917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name);
8707917SReza.Sabdar@Sun.COM 		return (-TLM_NO_SCRATCH_SPACE);
8717917SReza.Sabdar@Sun.COM 	}
8727917SReza.Sabdar@Sun.COM 
8737917SReza.Sabdar@Sun.COM 	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
8747917SReza.Sabdar@Sun.COM 	linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
8757917SReza.Sabdar@Sun.COM 	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
8767917SReza.Sabdar@Sun.COM 	if (fullname == NULL || linkname == NULL || snapname == NULL) {
8777917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
8787917SReza.Sabdar@Sun.COM 		goto err_out;
8797917SReza.Sabdar@Sun.COM 	}
8807917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(fullname, dir, name) ||
8817917SReza.Sabdar@Sun.COM 	    !tlm_cat_path(snapname, chkdir, name)) {
8827917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long.");
8837917SReza.Sabdar@Sun.COM 		real_size = -TLM_NO_SCRATCH_SPACE;
8847917SReza.Sabdar@Sun.COM 		goto err_out;
8857917SReza.Sabdar@Sun.COM 	}
8867917SReza.Sabdar@Sun.COM 
8877917SReza.Sabdar@Sun.COM 	pos = tlm_get_data_offset(local_commands);
8887917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
8897917SReza.Sabdar@Sun.COM 
890*12353SReza.Sabdar@Sun.COM 	if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
8919659SReza.Sabdar@Sun.COM 		if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
8929659SReza.Sabdar@Sun.COM 			file_size = tlm_readlink(fullname, snapname, linkname,
8939659SReza.Sabdar@Sun.COM 			    TLM_MAX_PATH_NAME-1);
8949659SReza.Sabdar@Sun.COM 			if (file_size < 0) {
8959659SReza.Sabdar@Sun.COM 				real_size = -ENOENT;
8969659SReza.Sabdar@Sun.COM 				goto err_out;
8979659SReza.Sabdar@Sun.COM 			}
8987917SReza.Sabdar@Sun.COM 		}
8997917SReza.Sabdar@Sun.COM 
9007917SReza.Sabdar@Sun.COM 		/*
9017917SReza.Sabdar@Sun.COM 		 * Since soft links can not be read(2), we should only
9027917SReza.Sabdar@Sun.COM 		 * backup the file header.
9037917SReza.Sabdar@Sun.COM 		 */
9047917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
9057917SReza.Sabdar@Sun.COM 		    linkname,
9067917SReza.Sabdar@Sun.COM 		    tlm_acls,
9077917SReza.Sabdar@Sun.COM 		    section,
9087917SReza.Sabdar@Sun.COM 		    local_commands);
9097917SReza.Sabdar@Sun.COM 
9107917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
9117917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
9127917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhpath_name(job_stats, fullname,
9137917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
9147917SReza.Sabdar@Sun.COM 
9157917SReza.Sabdar@Sun.COM 		free(fullname);
9167917SReza.Sabdar@Sun.COM 		free(linkname);
9177917SReza.Sabdar@Sun.COM 		free(snapname);
9187917SReza.Sabdar@Sun.COM 		return (0);
9197917SReza.Sabdar@Sun.COM 	}
9207917SReza.Sabdar@Sun.COM 
9217917SReza.Sabdar@Sun.COM 	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
9227917SReza.Sabdar@Sun.COM 
9237917SReza.Sabdar@Sun.COM 	/*
9247917SReza.Sabdar@Sun.COM 	 * For hardlink, only read the data if no other link
9257917SReza.Sabdar@Sun.COM 	 * belonging to the same inode has been backed up.
9267917SReza.Sabdar@Sun.COM 	 */
9277917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1) {
9287917SReza.Sabdar@Sun.COM 		hardlink_done = !hardlink_q_get(hardlink_q,
9297917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
9307917SReza.Sabdar@Sun.COM 	}
9317917SReza.Sabdar@Sun.COM 
9327917SReza.Sabdar@Sun.COM 	if (!hardlink_done) {
9337917SReza.Sabdar@Sun.COM 		/*
9347917SReza.Sabdar@Sun.COM 		 * Open the file for reading.
9357917SReza.Sabdar@Sun.COM 		 */
9367917SReza.Sabdar@Sun.COM 		fd = open(fnamep, O_RDONLY);
9377917SReza.Sabdar@Sun.COM 		if (fd == -1) {
9387917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG,
9398540SReza.Sabdar@Sun.COM 			    "BACKUP> Can't open file [%s][%s] err(%d)",
9408540SReza.Sabdar@Sun.COM 			    fullname, fnamep, errno);
9417917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SOURCE_FILE;
9427917SReza.Sabdar@Sun.COM 			goto err_out;
9437917SReza.Sabdar@Sun.COM 		}
9447917SReza.Sabdar@Sun.COM 	} else {
9458193SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
9467917SReza.Sabdar@Sun.COM 		    tlm_acls->acl_attr.st_ino, hardlink_pos);
9477917SReza.Sabdar@Sun.COM 
9487917SReza.Sabdar@Sun.COM 		fd = -1;
9497917SReza.Sabdar@Sun.COM 	}
9507917SReza.Sabdar@Sun.COM 
9517917SReza.Sabdar@Sun.COM 	linkname[0] = 0;
9527917SReza.Sabdar@Sun.COM 
9537917SReza.Sabdar@Sun.COM 	real_size = tlm_acls->acl_attr.st_size;
9547917SReza.Sabdar@Sun.COM 	(void) output_acl_header(&tlm_acls->acl_info,
9557917SReza.Sabdar@Sun.COM 	    local_commands);
9567917SReza.Sabdar@Sun.COM 
9577917SReza.Sabdar@Sun.COM 	/*
9587917SReza.Sabdar@Sun.COM 	 * section = 0: file is small enough for TAR
9597917SReza.Sabdar@Sun.COM 	 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
9607917SReza.Sabdar@Sun.COM 	 * 		and the file name gets munged
9617917SReza.Sabdar@Sun.COM 	 */
9627917SReza.Sabdar@Sun.COM 	file_size = real_size;
9637917SReza.Sabdar@Sun.COM 	if (file_size > TLM_MAX_TAR_IMAGE) {
9647917SReza.Sabdar@Sun.COM 		if (output_humongus_header(fullname, file_size,
9657917SReza.Sabdar@Sun.COM 		    local_commands) < 0) {
9667917SReza.Sabdar@Sun.COM 			(void) close(fd);
9677917SReza.Sabdar@Sun.COM 			real_size = -TLM_NO_SCRATCH_SPACE;
9687917SReza.Sabdar@Sun.COM 			goto err_out;
9697917SReza.Sabdar@Sun.COM 		}
9707917SReza.Sabdar@Sun.COM 		section = 1;
9717917SReza.Sabdar@Sun.COM 	} else {
9727917SReza.Sabdar@Sun.COM 		section = 0;
9737917SReza.Sabdar@Sun.COM 	}
9747917SReza.Sabdar@Sun.COM 
9757917SReza.Sabdar@Sun.COM 	/*
9767917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode
9777917SReza.Sabdar@Sun.COM 	 * has been backed up, only backup an empty record.
9787917SReza.Sabdar@Sun.COM 	 */
9797917SReza.Sabdar@Sun.COM 	if (hardlink_done)
9807917SReza.Sabdar@Sun.COM 		file_size = 0;
9817917SReza.Sabdar@Sun.COM 
9827917SReza.Sabdar@Sun.COM 	/*
9837917SReza.Sabdar@Sun.COM 	 * work
9847917SReza.Sabdar@Sun.COM 	 */
9857917SReza.Sabdar@Sun.COM 	if (file_size == 0) {
9867917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
9877917SReza.Sabdar@Sun.COM 		    linkname,
9887917SReza.Sabdar@Sun.COM 		    tlm_acls,
9897917SReza.Sabdar@Sun.COM 		    section,
9907917SReza.Sabdar@Sun.COM 		    local_commands);
9917917SReza.Sabdar@Sun.COM 		/*
9927917SReza.Sabdar@Sun.COM 		 * this can fall right through since zero size files
9937917SReza.Sabdar@Sun.COM 		 * will be skipped by the WHILE loop anyway
9947917SReza.Sabdar@Sun.COM 		 */
9957917SReza.Sabdar@Sun.COM 	}
9967917SReza.Sabdar@Sun.COM 
9977917SReza.Sabdar@Sun.COM 	while (file_size > 0) {
9987917SReza.Sabdar@Sun.COM 		int section_size = llmin(file_size,
9997917SReza.Sabdar@Sun.COM 		    (longlong_t)TLM_MAX_TAR_IMAGE);
10007917SReza.Sabdar@Sun.COM 
10017917SReza.Sabdar@Sun.COM 		tlm_acls->acl_attr.st_size = (longlong_t)section_size;
10027917SReza.Sabdar@Sun.COM 		(void) output_file_header(fullname,
10037917SReza.Sabdar@Sun.COM 		    linkname,
10047917SReza.Sabdar@Sun.COM 		    tlm_acls,
10057917SReza.Sabdar@Sun.COM 		    section,
10067917SReza.Sabdar@Sun.COM 		    local_commands);
10077917SReza.Sabdar@Sun.COM 		while (section_size > 0) {
10087917SReza.Sabdar@Sun.COM 			char	*buf;
10097917SReza.Sabdar@Sun.COM 			long	actual_size;
10107917SReza.Sabdar@Sun.COM 			int	read_size;
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 			local_commands->tc_buffers->tbs_buffer[
10217917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
10227917SReza.Sabdar@Sun.COM 			    tb_file_size = section_size;
10237917SReza.Sabdar@Sun.COM 			local_commands->tc_buffers->tbs_buffer[
10247917SReza.Sabdar@Sun.COM 			    local_commands->tc_buffers->tbs_buffer_in].
10257917SReza.Sabdar@Sun.COM 			    tb_seek_spot = seek_spot;
10267917SReza.Sabdar@Sun.COM 
10277917SReza.Sabdar@Sun.COM 			buf = get_write_buffer(section_size,
10287917SReza.Sabdar@Sun.COM 			    &actual_size, FALSE, local_commands);
10297917SReza.Sabdar@Sun.COM 			if (!buf)
10307917SReza.Sabdar@Sun.COM 				goto tear_down;
10317917SReza.Sabdar@Sun.COM 
10327917SReza.Sabdar@Sun.COM 			/*
10337917SReza.Sabdar@Sun.COM 			 * check for Abort commands
10347917SReza.Sabdar@Sun.COM 			 */
10357917SReza.Sabdar@Sun.COM 			if (commands->tcs_reader != TLM_BACKUP_RUN) {
10367917SReza.Sabdar@Sun.COM 				local_commands->tc_writer = TLM_ABORT;
10377917SReza.Sabdar@Sun.COM 				goto tear_down;
10387917SReza.Sabdar@Sun.COM 			}
10397917SReza.Sabdar@Sun.COM 
10407917SReza.Sabdar@Sun.COM 			read_size = min(section_size, actual_size);
10417917SReza.Sabdar@Sun.COM 			actual_size = read(fd, buf, read_size);
10427917SReza.Sabdar@Sun.COM 			NS_ADD(rdisk, actual_size);
10437917SReza.Sabdar@Sun.COM 			NS_INC(rfile);
10447917SReza.Sabdar@Sun.COM 
10457917SReza.Sabdar@Sun.COM 			if (actual_size == 0)
10467917SReza.Sabdar@Sun.COM 				break;
10477917SReza.Sabdar@Sun.COM 
10487917SReza.Sabdar@Sun.COM 			if (actual_size == -1) {
10497917SReza.Sabdar@Sun.COM 				NDMP_LOG(LOG_DEBUG,
10507917SReza.Sabdar@Sun.COM 				    "problem(%d) reading file [%s][%s]",
10517917SReza.Sabdar@Sun.COM 				    errno, fullname, snapname);
10527917SReza.Sabdar@Sun.COM 				goto tear_down;
10537917SReza.Sabdar@Sun.COM 			}
10547917SReza.Sabdar@Sun.COM 			seek_spot += actual_size;
10557917SReza.Sabdar@Sun.COM 			file_size -= actual_size;
10567917SReza.Sabdar@Sun.COM 			section_size -= actual_size;
10577917SReza.Sabdar@Sun.COM 		}
10587917SReza.Sabdar@Sun.COM 		section++;
10597917SReza.Sabdar@Sun.COM 	}
10607917SReza.Sabdar@Sun.COM 
10617917SReza.Sabdar@Sun.COM 	/*
10627917SReza.Sabdar@Sun.COM 	 * If data belonging to this hardlink has been backed up, add the link
10637917SReza.Sabdar@Sun.COM 	 * to hardlink queue.
10647917SReza.Sabdar@Sun.COM 	 */
10657917SReza.Sabdar@Sun.COM 	if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
10667917SReza.Sabdar@Sun.COM 		(void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
10677917SReza.Sabdar@Sun.COM 		    pos, NULL, 0);
10687917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10698193SReza.Sabdar@Sun.COM 		    "backed up hardlink file %s, inode = %llu, pos = %llu ",
10707917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, pos);
10717917SReza.Sabdar@Sun.COM 	}
10727917SReza.Sabdar@Sun.COM 
10737917SReza.Sabdar@Sun.COM 	/*
10747917SReza.Sabdar@Sun.COM 	 * For hardlink, if other link belonging to the same inode has been
10758193SReza.Sabdar@Sun.COM 	 * backed up, no add_node entry should be sent for this link.
10767917SReza.Sabdar@Sun.COM 	 */
10777917SReza.Sabdar@Sun.COM 	if (hardlink_done) {
10787917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10798193SReza.Sabdar@Sun.COM 		    "backed up hardlink link %s, inode = %llu, pos = %llu ",
10807917SReza.Sabdar@Sun.COM 		    fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
10817917SReza.Sabdar@Sun.COM 	} else {
10827917SReza.Sabdar@Sun.COM 		(void) tlm_log_fhnode(job_stats, dir, name,
10837917SReza.Sabdar@Sun.COM 		    &tlm_acls->acl_attr, pos);
10847917SReza.Sabdar@Sun.COM 	}
10857917SReza.Sabdar@Sun.COM 
10867917SReza.Sabdar@Sun.COM 	(void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
10877917SReza.Sabdar@Sun.COM 	    pos);
10887917SReza.Sabdar@Sun.COM 
10897917SReza.Sabdar@Sun.COM tear_down:
10907917SReza.Sabdar@Sun.COM 	local_commands->tc_buffers->tbs_buffer[
10917917SReza.Sabdar@Sun.COM 	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
10927917SReza.Sabdar@Sun.COM 
10937917SReza.Sabdar@Sun.COM 	(void) close(fd);
10947917SReza.Sabdar@Sun.COM 
10957917SReza.Sabdar@Sun.COM err_out:
10967917SReza.Sabdar@Sun.COM 	free(fullname);
10977917SReza.Sabdar@Sun.COM 	free(linkname);
10987917SReza.Sabdar@Sun.COM 	free(snapname);
10997917SReza.Sabdar@Sun.COM 	return (real_size);
11007917SReza.Sabdar@Sun.COM }
11017917SReza.Sabdar@Sun.COM 
11027917SReza.Sabdar@Sun.COM /*
11037917SReza.Sabdar@Sun.COM  * tar_putfile
11047917SReza.Sabdar@Sun.COM  *
11057917SReza.Sabdar@Sun.COM  * Main file backup function for tar
11067917SReza.Sabdar@Sun.COM  */
11077917SReza.Sabdar@Sun.COM 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)11087917SReza.Sabdar@Sun.COM tar_putfile(char *dir, char *name, char *chkdir,
11097917SReza.Sabdar@Sun.COM     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
11107917SReza.Sabdar@Sun.COM     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
11117917SReza.Sabdar@Sun.COM     struct hardlink_q *hardlink_q)
11127917SReza.Sabdar@Sun.COM {
11137917SReza.Sabdar@Sun.COM 	int rv;
11147917SReza.Sabdar@Sun.COM 
11157917SReza.Sabdar@Sun.COM 	rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
11167917SReza.Sabdar@Sun.COM 	    local_commands, job_stats, hardlink_q);
11177917SReza.Sabdar@Sun.COM 	if (rv < 0)
11187917SReza.Sabdar@Sun.COM 		return (rv);
11197917SReza.Sabdar@Sun.COM 
11207917SReza.Sabdar@Sun.COM 	rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
11217917SReza.Sabdar@Sun.COM 	    local_commands, job_stats);
11227917SReza.Sabdar@Sun.COM 
11237917SReza.Sabdar@Sun.COM 	return (rv < 0 ? rv : 0);
11247917SReza.Sabdar@Sun.COM }
11257917SReza.Sabdar@Sun.COM 
11267917SReza.Sabdar@Sun.COM /*
11277917SReza.Sabdar@Sun.COM  * get_write_buffer
11287917SReza.Sabdar@Sun.COM  *
11297917SReza.Sabdar@Sun.COM  * a wrapper to tlm_get_write_buffer so that
11307917SReza.Sabdar@Sun.COM  * we can cleanly detect ABORT commands
11317917SReza.Sabdar@Sun.COM  * without involving the TLM library with
11327917SReza.Sabdar@Sun.COM  * our problems.
11337917SReza.Sabdar@Sun.COM  */
11347917SReza.Sabdar@Sun.COM static char *
get_write_buffer(long size,long * actual_size,boolean_t zero,tlm_cmd_t * local_commands)11357917SReza.Sabdar@Sun.COM get_write_buffer(long size, long *actual_size,
11367917SReza.Sabdar@Sun.COM     boolean_t zero, tlm_cmd_t *local_commands)
11377917SReza.Sabdar@Sun.COM {
11387917SReza.Sabdar@Sun.COM 	while (local_commands->tc_reader == TLM_BACKUP_RUN) {
11397917SReza.Sabdar@Sun.COM 		char *rec = tlm_get_write_buffer(size, actual_size,
11407917SReza.Sabdar@Sun.COM 		    local_commands->tc_buffers, zero);
11417917SReza.Sabdar@Sun.COM 		if (rec != 0) {
11427917SReza.Sabdar@Sun.COM 			return (rec);
11437917SReza.Sabdar@Sun.COM 		}
11447917SReza.Sabdar@Sun.COM 	}
11457917SReza.Sabdar@Sun.COM 	return (NULL);
11467917SReza.Sabdar@Sun.COM }
11477917SReza.Sabdar@Sun.COM 
11487917SReza.Sabdar@Sun.COM #define	NDMP_MORE_RECORDS	2
11497917SReza.Sabdar@Sun.COM 
11507917SReza.Sabdar@Sun.COM /*
11517917SReza.Sabdar@Sun.COM  * write_tar_eof
11527917SReza.Sabdar@Sun.COM  *
11537917SReza.Sabdar@Sun.COM  * This function is initially written for NDMP support.  It appends
11547917SReza.Sabdar@Sun.COM  * two tar headers to the tar file, and also N more empty buffers
11557917SReza.Sabdar@Sun.COM  * to make sure that the two tar headers will be read as a part of
11567917SReza.Sabdar@Sun.COM  * a mover record and don't get locked because of EOM on the mover
11577917SReza.Sabdar@Sun.COM  * side.
11587917SReza.Sabdar@Sun.COM  */
11597917SReza.Sabdar@Sun.COM void
write_tar_eof(tlm_cmd_t * local_commands)11607917SReza.Sabdar@Sun.COM write_tar_eof(tlm_cmd_t *local_commands)
11617917SReza.Sabdar@Sun.COM {
11627917SReza.Sabdar@Sun.COM 	int i;
11637917SReza.Sabdar@Sun.COM 	long actual_size;
11647917SReza.Sabdar@Sun.COM 	tlm_buffers_t *bufs;
11657917SReza.Sabdar@Sun.COM 
11667917SReza.Sabdar@Sun.COM 	/*
11677917SReza.Sabdar@Sun.COM 	 * output 2 zero filled records,
11687917SReza.Sabdar@Sun.COM 	 * TAR wants this.
11697917SReza.Sabdar@Sun.COM 	 */
11707917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11717917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11727917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(sizeof (tlm_tar_hdr_t),
11737917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11747917SReza.Sabdar@Sun.COM 
11757917SReza.Sabdar@Sun.COM 	/*
11767917SReza.Sabdar@Sun.COM 	 * NDMP: Clear the rest of the buffer and write two more buffers
11777917SReza.Sabdar@Sun.COM 	 * to the tape.
11787917SReza.Sabdar@Sun.COM 	 */
11797917SReza.Sabdar@Sun.COM 	bufs = local_commands->tc_buffers;
11807917SReza.Sabdar@Sun.COM 	(void) get_write_buffer(bufs->tbs_data_transfer_size,
11817917SReza.Sabdar@Sun.COM 	    &actual_size, TRUE, local_commands);
11827917SReza.Sabdar@Sun.COM 
11837917SReza.Sabdar@Sun.COM 	for (i = 0; i < NDMP_MORE_RECORDS &&
11847917SReza.Sabdar@Sun.COM 	    local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
11857917SReza.Sabdar@Sun.COM 		/*
11867917SReza.Sabdar@Sun.COM 		 * We don't need the return value of get_write_buffer(),
11877917SReza.Sabdar@Sun.COM 		 * since it's already zeroed out if the buffer is returned.
11887917SReza.Sabdar@Sun.COM 		 */
11897917SReza.Sabdar@Sun.COM 		(void) get_write_buffer(bufs->tbs_data_transfer_size,
11907917SReza.Sabdar@Sun.COM 		    &actual_size, TRUE, local_commands);
11917917SReza.Sabdar@Sun.COM 	}
11927917SReza.Sabdar@Sun.COM 
11937917SReza.Sabdar@Sun.COM 	bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
11947917SReza.Sabdar@Sun.COM 	tlm_buffer_release_in_buf(bufs);
11957917SReza.Sabdar@Sun.COM }
11967917SReza.Sabdar@Sun.COM 
11977917SReza.Sabdar@Sun.COM /*
11987917SReza.Sabdar@Sun.COM  * Callback to backup each ZFS property
11997917SReza.Sabdar@Sun.COM  */
12007917SReza.Sabdar@Sun.COM static int
zfs_put_prop_cb(int prop,void * pp)12017917SReza.Sabdar@Sun.COM zfs_put_prop_cb(int prop, void *pp)
12027917SReza.Sabdar@Sun.COM {
120311170SReza.Sabdar@Sun.COM 	ndmp_metadata_handle_t *mhd;
120411170SReza.Sabdar@Sun.COM 	ndmp_metadata_header_ext_t *mhp;
120511170SReza.Sabdar@Sun.COM 	ndmp_metadata_property_ext_t *mpp;
120611170SReza.Sabdar@Sun.COM 	char vbuf[ZFS_MAXPROPLEN];
120711170SReza.Sabdar@Sun.COM 	char sbuf[ZFS_MAXPROPLEN];
12087917SReza.Sabdar@Sun.COM 	zprop_source_t stype;
12098800SReza.Sabdar@Sun.COM 	char *sourcestr;
12107917SReza.Sabdar@Sun.COM 
12117917SReza.Sabdar@Sun.COM 	if (pp == NULL)
12127917SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
12137917SReza.Sabdar@Sun.COM 
121411170SReza.Sabdar@Sun.COM 	mhd = (ndmp_metadata_handle_t *)pp;
121511170SReza.Sabdar@Sun.COM 	mhp = mhd->ml_xhdr;
121611170SReza.Sabdar@Sun.COM 	mpp = &mhp->nh_property[mhp->nh_count];
121710608SReza.Sabdar@Sun.COM 
121811170SReza.Sabdar@Sun.COM 	if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
121911170SReza.Sabdar@Sun.COM 	    sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
122011170SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
122111170SReza.Sabdar@Sun.COM 
122211170SReza.Sabdar@Sun.COM 	if (zfs_prop_get(mhd->ml_handle, prop, vbuf, sizeof (vbuf),
122311170SReza.Sabdar@Sun.COM 	    &stype, sbuf, sizeof (sbuf), B_TRUE) != 0) {
122411170SReza.Sabdar@Sun.COM 		mhp->nh_count++;
122510608SReza.Sabdar@Sun.COM 		return (ZPROP_CONT);
122611170SReza.Sabdar@Sun.COM 	}
122710608SReza.Sabdar@Sun.COM 
122811170SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), ZFS_MAXNAMELEN);
122911170SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_value, vbuf, ZFS_MAXPROPLEN);
12308800SReza.Sabdar@Sun.COM 
12318800SReza.Sabdar@Sun.COM 	switch (stype) {
12328800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_NONE:
12338800SReza.Sabdar@Sun.COM 		sourcestr = "none";
12348800SReza.Sabdar@Sun.COM 		break;
123511170SReza.Sabdar@Sun.COM 	case ZPROP_SRC_RECEIVED:
123611170SReza.Sabdar@Sun.COM 		sourcestr = "received";
123711170SReza.Sabdar@Sun.COM 		break;
12388800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_LOCAL:
12398800SReza.Sabdar@Sun.COM 		sourcestr = mhp->nh_dataset;
12408800SReza.Sabdar@Sun.COM 		break;
12418800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_TEMPORARY:
12428800SReza.Sabdar@Sun.COM 		sourcestr = "temporary";
12438800SReza.Sabdar@Sun.COM 		break;
12448800SReza.Sabdar@Sun.COM 	case ZPROP_SRC_DEFAULT:
12458800SReza.Sabdar@Sun.COM 		sourcestr = "default";
12468800SReza.Sabdar@Sun.COM 		break;
12478800SReza.Sabdar@Sun.COM 	default:
12488800SReza.Sabdar@Sun.COM 		sourcestr = sbuf;
12498800SReza.Sabdar@Sun.COM 		break;
12508800SReza.Sabdar@Sun.COM 	}
125111170SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_source, sourcestr, ZFS_MAXPROPLEN);
12527917SReza.Sabdar@Sun.COM 
125311170SReza.Sabdar@Sun.COM 	mhp->nh_count++;
12547917SReza.Sabdar@Sun.COM 	return (ZPROP_CONT);
12557917SReza.Sabdar@Sun.COM }
12567917SReza.Sabdar@Sun.COM 
125711170SReza.Sabdar@Sun.COM /*
125811170SReza.Sabdar@Sun.COM  * Callback to backup each ZFS user/group quota
125911170SReza.Sabdar@Sun.COM  */
126011170SReza.Sabdar@Sun.COM static int
zfs_put_quota_cb(void * pp,const char * domain,uid_t rid,uint64_t space)126111170SReza.Sabdar@Sun.COM zfs_put_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
126211170SReza.Sabdar@Sun.COM {
126311170SReza.Sabdar@Sun.COM 	ndmp_metadata_handle_t *mhd;
126411170SReza.Sabdar@Sun.COM 	ndmp_metadata_header_ext_t *mhp;
126511170SReza.Sabdar@Sun.COM 	ndmp_metadata_property_ext_t *mpp;
126611170SReza.Sabdar@Sun.COM 	char *typestr;
126711170SReza.Sabdar@Sun.COM 
126811170SReza.Sabdar@Sun.COM 	if (pp == NULL)
126911170SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
127011170SReza.Sabdar@Sun.COM 
127111170SReza.Sabdar@Sun.COM 	mhd = (ndmp_metadata_handle_t *)pp;
127211170SReza.Sabdar@Sun.COM 	mhp = mhd->ml_xhdr;
127311170SReza.Sabdar@Sun.COM 	mpp = &mhp->nh_property[mhp->nh_count];
127411170SReza.Sabdar@Sun.COM 
127511170SReza.Sabdar@Sun.COM 	if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
127611170SReza.Sabdar@Sun.COM 	    sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
127711170SReza.Sabdar@Sun.COM 		return (ZPROP_INVAL);
127811170SReza.Sabdar@Sun.COM 
127911170SReza.Sabdar@Sun.COM 	if (mhd->ml_quota_prop == ZFS_PROP_USERQUOTA)
128011170SReza.Sabdar@Sun.COM 		typestr = "userquota";
128111170SReza.Sabdar@Sun.COM 	else
128211170SReza.Sabdar@Sun.COM 		typestr = "groupquota";
128311170SReza.Sabdar@Sun.COM 
128411170SReza.Sabdar@Sun.COM 	if (domain == NULL || *domain == '\0')
128511170SReza.Sabdar@Sun.COM 		(void) snprintf(mpp->mp_name, ZFS_MAXNAMELEN, "%s@%llu",
128611170SReza.Sabdar@Sun.COM 		    typestr, (longlong_t)rid);
128711170SReza.Sabdar@Sun.COM 	else
128811170SReza.Sabdar@Sun.COM 		(void) snprintf(mpp->mp_name, ZFS_MAXNAMELEN, "%s@%s-%llu",
128911170SReza.Sabdar@Sun.COM 		    typestr, domain, (longlong_t)rid);
129011170SReza.Sabdar@Sun.COM 	(void) snprintf(mpp->mp_value, ZFS_MAXPROPLEN, "%llu", space);
129111170SReza.Sabdar@Sun.COM 	(void) strlcpy(mpp->mp_source, mhp->nh_dataset, ZFS_MAXPROPLEN);
129211170SReza.Sabdar@Sun.COM 
129311170SReza.Sabdar@Sun.COM 	mhp->nh_count++;
129411170SReza.Sabdar@Sun.COM 	return (0);
129511170SReza.Sabdar@Sun.COM }
129611170SReza.Sabdar@Sun.COM 
129711170SReza.Sabdar@Sun.COM /*
129811170SReza.Sabdar@Sun.COM  * Callback to count each ZFS property
129911170SReza.Sabdar@Sun.COM  */
130011170SReza.Sabdar@Sun.COM /*ARGSUSED*/
130111170SReza.Sabdar@Sun.COM static int
zfs_count_prop_cb(int prop,void * pp)130211170SReza.Sabdar@Sun.COM zfs_count_prop_cb(int prop, void *pp)
130311170SReza.Sabdar@Sun.COM {
130411170SReza.Sabdar@Sun.COM 	(*(int *)pp)++;
130511170SReza.Sabdar@Sun.COM 	return (ZPROP_CONT);
130611170SReza.Sabdar@Sun.COM }
130711170SReza.Sabdar@Sun.COM 
130811170SReza.Sabdar@Sun.COM /*
130911170SReza.Sabdar@Sun.COM  * Callback to count each ZFS user/group quota
131011170SReza.Sabdar@Sun.COM  */
131111170SReza.Sabdar@Sun.COM /*ARGSUSED*/
131211170SReza.Sabdar@Sun.COM static int
zfs_count_quota_cb(void * pp,const char * domain,uid_t rid,uint64_t space)131311170SReza.Sabdar@Sun.COM zfs_count_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
131411170SReza.Sabdar@Sun.COM {
131511170SReza.Sabdar@Sun.COM 	(*(int *)pp)++;
131611170SReza.Sabdar@Sun.COM 	return (0);
131711170SReza.Sabdar@Sun.COM }
131811170SReza.Sabdar@Sun.COM 
131911170SReza.Sabdar@Sun.COM /*
132011170SReza.Sabdar@Sun.COM  * Count the number of ZFS properties and user/group quotas
132111170SReza.Sabdar@Sun.COM  */
132211170SReza.Sabdar@Sun.COM int
zfs_get_prop_counts(zfs_handle_t * zhp)132311170SReza.Sabdar@Sun.COM zfs_get_prop_counts(zfs_handle_t *zhp)
132411170SReza.Sabdar@Sun.COM {
132511170SReza.Sabdar@Sun.COM 	int count = 0;
132611170SReza.Sabdar@Sun.COM 	nvlist_t *uprops;
132711170SReza.Sabdar@Sun.COM 	nvpair_t *elp;
132811170SReza.Sabdar@Sun.COM 
132911170SReza.Sabdar@Sun.COM 	if (zhp == NULL)
133011170SReza.Sabdar@Sun.COM 		return (0);
133111170SReza.Sabdar@Sun.COM 
133211170SReza.Sabdar@Sun.COM 	(void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE,
133311170SReza.Sabdar@Sun.COM 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
133411170SReza.Sabdar@Sun.COM 
133511170SReza.Sabdar@Sun.COM 	(void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb,
133611170SReza.Sabdar@Sun.COM 	    &count);
133711170SReza.Sabdar@Sun.COM 	(void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb,
133811170SReza.Sabdar@Sun.COM 	    &count);
133911170SReza.Sabdar@Sun.COM 
134011170SReza.Sabdar@Sun.COM 	uprops = zfs_get_user_props(zhp);
134111170SReza.Sabdar@Sun.COM 
134211170SReza.Sabdar@Sun.COM 	elp = nvlist_next_nvpair(uprops, NULL);
134311170SReza.Sabdar@Sun.COM 	for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp))
134411170SReza.Sabdar@Sun.COM 		count++;
134511170SReza.Sabdar@Sun.COM 
134611170SReza.Sabdar@Sun.COM 	return (count);
134711170SReza.Sabdar@Sun.COM }
13487917SReza.Sabdar@Sun.COM 
13497917SReza.Sabdar@Sun.COM /*
13507917SReza.Sabdar@Sun.COM  * Notifies ndmpd that the metadata associated with the given ZFS dataset
13517917SReza.Sabdar@Sun.COM  * should be backed up.
13527917SReza.Sabdar@Sun.COM  */
13537917SReza.Sabdar@Sun.COM int
ndmp_include_zfs(ndmp_context_t * nctx,const char * dataset)13547917SReza.Sabdar@Sun.COM ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
13557917SReza.Sabdar@Sun.COM {
13567917SReza.Sabdar@Sun.COM 	tlm_commands_t *cmds;
135711170SReza.Sabdar@Sun.COM 	ndmp_metadata_handle_t mhd;
135811170SReza.Sabdar@Sun.COM 	ndmp_metadata_header_ext_t *mhp;
135911170SReza.Sabdar@Sun.COM 	ndmp_metadata_property_ext_t *mpp;
136011170SReza.Sabdar@Sun.COM 	zfs_handle_t *zhp;
13617917SReza.Sabdar@Sun.COM 	tlm_cmd_t *lcmd;
13627917SReza.Sabdar@Sun.COM 	long actual_size;
13637917SReza.Sabdar@Sun.COM 	nvlist_t *uprops, *ulist;
13647917SReza.Sabdar@Sun.COM 	const char *pname;
13657917SReza.Sabdar@Sun.COM 	nvpair_t *elp;
13667917SReza.Sabdar@Sun.COM 	char *sval, *ssrc;
13677917SReza.Sabdar@Sun.COM 	char *wbuf, *pp, *tp;
13687917SReza.Sabdar@Sun.COM 	long size, lsize, sz;
13697917SReza.Sabdar@Sun.COM 	int align = RECORDSIZE - 1;
137011170SReza.Sabdar@Sun.COM 	int pcount;
13717917SReza.Sabdar@Sun.COM 
13727917SReza.Sabdar@Sun.COM 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
13737917SReza.Sabdar@Sun.COM 		return (-1);
13747917SReza.Sabdar@Sun.COM 
13757917SReza.Sabdar@Sun.COM 	if ((lcmd = cmds->tcs_command) == NULL ||
13767917SReza.Sabdar@Sun.COM 	    lcmd->tc_buffers == NULL)
13777917SReza.Sabdar@Sun.COM 		return (-1);
13787917SReza.Sabdar@Sun.COM 
137911170SReza.Sabdar@Sun.COM 	(void) mutex_lock(&zlib_mtx);
138011170SReza.Sabdar@Sun.COM 	if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) {
138111170SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
138211170SReza.Sabdar@Sun.COM 		return (-1);
138311170SReza.Sabdar@Sun.COM 	}
138411170SReza.Sabdar@Sun.COM 
138511170SReza.Sabdar@Sun.COM 	pcount = zfs_get_prop_counts(zhp);
138611170SReza.Sabdar@Sun.COM 	size = sizeof (ndmp_metadata_header_ext_t) +
138711170SReza.Sabdar@Sun.COM 	    pcount * sizeof (ndmp_metadata_property_ext_t);
138811170SReza.Sabdar@Sun.COM 
13897917SReza.Sabdar@Sun.COM 	size += align;
13907917SReza.Sabdar@Sun.COM 	size &= ~align;
13917917SReza.Sabdar@Sun.COM 
139211170SReza.Sabdar@Sun.COM 	if ((mhp = malloc(size)) == NULL) {
139311170SReza.Sabdar@Sun.COM 		zfs_close(zhp);
139411170SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
13957917SReza.Sabdar@Sun.COM 		return (-1);
139611170SReza.Sabdar@Sun.COM 	}
139711170SReza.Sabdar@Sun.COM 
13987917SReza.Sabdar@Sun.COM 	(void) memset(mhp, 0, size);
13997917SReza.Sabdar@Sun.COM 
140011170SReza.Sabdar@Sun.COM 	mhd.ml_handle = zhp;
140111170SReza.Sabdar@Sun.COM 	mhd.ml_xhdr = mhp;
140211170SReza.Sabdar@Sun.COM 	mhp->nh_total_bytes = size;
140311170SReza.Sabdar@Sun.COM 	mhp->nh_major = META_HDR_MAJOR_VERSION;
140411170SReza.Sabdar@Sun.COM 	mhp->nh_minor = META_HDR_MINOR_VERSION;
14057917SReza.Sabdar@Sun.COM 	mhp->nh_plversion = nctx->nc_plversion;
140611170SReza.Sabdar@Sun.COM 
14077917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_plname, nctx->nc_plname,
14087917SReza.Sabdar@Sun.COM 	    sizeof (mhp->nh_plname));
140911170SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT,
141011170SReza.Sabdar@Sun.COM 	    sizeof (mhp->nh_magic));
14117917SReza.Sabdar@Sun.COM 	(void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
14127917SReza.Sabdar@Sun.COM 
14137917SReza.Sabdar@Sun.COM 	/* Get all the ZFS properties */
141411170SReza.Sabdar@Sun.COM 	(void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE,
14157917SReza.Sabdar@Sun.COM 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
14167917SReza.Sabdar@Sun.COM 
14177917SReza.Sabdar@Sun.COM 	/* Get user properties */
141811170SReza.Sabdar@Sun.COM 	uprops = zfs_get_user_props(mhd.ml_handle);
14197917SReza.Sabdar@Sun.COM 
14207917SReza.Sabdar@Sun.COM 	elp = nvlist_next_nvpair(uprops, NULL);
14217917SReza.Sabdar@Sun.COM 
14227917SReza.Sabdar@Sun.COM 	while (elp != NULL) {
14237917SReza.Sabdar@Sun.COM 		mpp = &mhp->nh_property[mhp->nh_count];
14247917SReza.Sabdar@Sun.COM 		if (nvpair_value_nvlist(elp, &ulist) != 0 ||
14257917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
14267917SReza.Sabdar@Sun.COM 		    nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
142711170SReza.Sabdar@Sun.COM 			zfs_close(mhd.ml_handle);
142810260SReza.Sabdar@Sun.COM 			(void) mutex_unlock(&zlib_mtx);
14297917SReza.Sabdar@Sun.COM 			free(mhp);
14307917SReza.Sabdar@Sun.COM 			return (-1);
14317917SReza.Sabdar@Sun.COM 		}
14327917SReza.Sabdar@Sun.COM 		if ((pname = nvpair_name(elp)) != NULL)
143311170SReza.Sabdar@Sun.COM 			(void) strlcpy(mpp->mp_name, pname, ZFS_MAXNAMELEN);
14347917SReza.Sabdar@Sun.COM 
143511170SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN);
143611170SReza.Sabdar@Sun.COM 		(void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN);
14377917SReza.Sabdar@Sun.COM 		mhp->nh_count++;
14387917SReza.Sabdar@Sun.COM 		elp = nvlist_next_nvpair(uprops, elp);
14397917SReza.Sabdar@Sun.COM 	}
14407917SReza.Sabdar@Sun.COM 
144111170SReza.Sabdar@Sun.COM 	mhd.ml_quota_prop = ZFS_PROP_USERQUOTA;
144211170SReza.Sabdar@Sun.COM 	(void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA,
144311170SReza.Sabdar@Sun.COM 	    zfs_put_quota_cb, &mhd);
144411170SReza.Sabdar@Sun.COM 	mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA;
144511170SReza.Sabdar@Sun.COM 	(void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA,
144611170SReza.Sabdar@Sun.COM 	    zfs_put_quota_cb, &mhd);
144711170SReza.Sabdar@Sun.COM 	mhp->nh_count = pcount;
144811170SReza.Sabdar@Sun.COM 
144911170SReza.Sabdar@Sun.COM 	zfs_close(mhd.ml_handle);
145010260SReza.Sabdar@Sun.COM 	(void) mutex_unlock(&zlib_mtx);
14517917SReza.Sabdar@Sun.COM 
14527917SReza.Sabdar@Sun.COM 	if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
14537917SReza.Sabdar@Sun.COM 	    lcmd)) != NULL) {
14547917SReza.Sabdar@Sun.COM 		pp = (char *)mhp;
14557917SReza.Sabdar@Sun.COM 
14567917SReza.Sabdar@Sun.COM 		(void) memcpy(wbuf, pp, (actual_size < size) ?
14577917SReza.Sabdar@Sun.COM 		    actual_size : size);
14587917SReza.Sabdar@Sun.COM 		pp += (actual_size < size) ? actual_size : size;
14597917SReza.Sabdar@Sun.COM 
14607917SReza.Sabdar@Sun.COM 		sz = actual_size;
14617917SReza.Sabdar@Sun.COM 		while (sz < size &&
14627917SReza.Sabdar@Sun.COM 		    ((tp = get_write_buffer(size - sz, &lsize,
14637917SReza.Sabdar@Sun.COM 		    TRUE, lcmd))) != NULL) {
146411170SReza.Sabdar@Sun.COM 			(void) memcpy(tp, pp, lsize);
14657917SReza.Sabdar@Sun.COM 			sz += lsize;
14667917SReza.Sabdar@Sun.COM 			pp += lsize;
14677917SReza.Sabdar@Sun.COM 		}
14687917SReza.Sabdar@Sun.COM 		if (sz > size) {
14697917SReza.Sabdar@Sun.COM 			tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
14707917SReza.Sabdar@Sun.COM 		}
14717917SReza.Sabdar@Sun.COM 	}
14727917SReza.Sabdar@Sun.COM 
14737917SReza.Sabdar@Sun.COM 	free(mhp);
14747917SReza.Sabdar@Sun.COM 	return (0);
14757917SReza.Sabdar@Sun.COM }
1476