1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2015 by Delphix. All rights reserved.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 #include <stdio.h>
  40 #include <limits.h>
  41 #include <time.h>
  42 #include <sys/stat.h>
  43 #include <unistd.h>
  44 #include <dirent.h>
  45 #include <pthread.h>
  46 #include <archives.h>
  47 #include <tlm.h>
  48 #include <sys/fs/zfs.h>
  49 #include <sys/mkdev.h>
  50 #include <libzfs.h>
  51 #include <libcmdutils.h>
  52 #include <pwd.h>
  53 #include <grp.h>
  54 #include "tlm_proto.h"
  55 
  56 
  57 static char *get_write_buffer(long size,
  58     long *actual_size,
  59     boolean_t zero,
  60     tlm_cmd_t *);
  61 static int output_acl_header(sec_attr_t *,
  62     tlm_cmd_t *);
  63 static int output_file_header(char *name,
  64     char *link,
  65     tlm_acls_t *,
  66     int section,
  67     tlm_cmd_t *);
  68 static int output_xattr_header(char *fname,
  69     char *aname,
  70     int fd,
  71     tlm_acls_t *,
  72     int section,
  73     tlm_cmd_t *);
  74 
  75 extern  libzfs_handle_t *zlibh;
  76 extern  mutex_t zlib_mtx;
  77 
  78 #define S_ISPECIAL(a)   (S_ISLNK(a) || S_ISFIFO(a) || S_ISBLK(a) || \
  79         S_ISCHR(a))
  80 
  81 /*
  82  * output_mem
  83  *
  84  * Gets a IO write buffer and copies memory to the that.
  85  */
  86 static void
  87 output_mem(tlm_cmd_t *local_commands, char *mem,
  88     int len)
  89 {
  90         long actual_size, rec_size;
  91         char *rec;
  92 
  93         while (len > 0) {
  94                 rec = get_write_buffer(len, &actual_size,
  95                     FALSE, local_commands);
  96                 rec_size = min(actual_size, len);
  97                 (void) memcpy(rec, mem, rec_size);
  98                 mem += rec_size;
  99                 len -= rec_size;
 100         }
 101 }
 102 
 103 /*
 104  * tlm_output_dir
 105  *
 106  * Put the directory information into the output buffers.
 107  */
 108 int
 109 tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
 110     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
 111 {
 112         u_longlong_t pos;
 113 
 114         /*
 115          * Send the node or path history of the directory itself.
 116          */
 117         pos = tlm_get_data_offset(local_commands);
 118         NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
 119         (void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
 120         (void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
 121         /* fhdir_cb is handled in ndmpd_tar3.c */
 122 
 123         (void) output_acl_header(&tlm_acls->acl_info,
 124             local_commands);
 125         (void) output_file_header(name, "", tlm_acls, 0,
 126             local_commands);
 127 
 128         return (0);
 129 }
 130 
 131 /*
 132  * tar_putdir
 133  *
 134  * Main dir backup function for tar
 135  */
 136 int
 137 tar_putdir(char *name, tlm_acls_t *tlm_acls,
 138     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
 139 {
 140         int rv;
 141 
 142         rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats);
 143         return (rv < 0 ? rv : 0);
 144 }
 145 
 146 /*
 147  * output_acl_header
 148  *
 149  * output the ACL header record and data
 150  */
 151 static int
 152 output_acl_header(sec_attr_t *acl_info,
 153     tlm_cmd_t *local_commands)
 154 {
 155         long    actual_size;
 156         tlm_tar_hdr_t *tar_hdr;
 157         long    acl_size;
 158 
 159         if ((acl_info == NULL) || (*acl_info->attr_info == '\0'))
 160                 return (0);
 161 
 162         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 163             &actual_size, TRUE, local_commands);
 164         if (!tar_hdr)
 165                 return (0);
 166 
 167         tar_hdr->th_linkflag = LF_ACL;
 168         acl_info->attr_type = UFSD_ACL;
 169         (void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len),
 170             "%06o", strlen(acl_info->attr_info));
 171 
 172         acl_size = sizeof (*acl_info);
 173         (void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE);
 174         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 175             acl_size);
 176         (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
 177             0444);
 178         (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0);
 179         (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0);
 180         (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
 181             "%011o ", 0);
 182         (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 183             sizeof (tar_hdr->th_magic));
 184 
 185         tlm_build_header_checksum(tar_hdr);
 186 
 187         (void) output_mem(local_commands, (void *)acl_info, acl_size);
 188         return (0);
 189 }
 190 
 191 /*
 192  * output_humongus_header
 193  *
 194  * output a special header record for HUGE files
 195  * output is:   1) a TAR "HUGE" header redord
 196  *              2) a "file" of size, name
 197  */
 198 static int
 199 output_humongus_header(char *fullname, longlong_t file_size,
 200     tlm_cmd_t *local_commands)
 201 {
 202         char    *buf;
 203         int     len;
 204         long    actual_size;
 205         tlm_tar_hdr_t *tar_hdr;
 206 
 207         /*
 208          * buf will contain: "%llu %s":
 209          * - 20 is the maximum length of 'ulong_tlong' decimal notation.
 210          * - The first '1' is for the ' ' between the "%llu" and the fullname.
 211          * - The last '1' is for the null-terminator of fullname.
 212          */
 213         len = 20 + 1 + strlen(fullname) + 1;
 214 
 215         if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
 216                 return (-1);
 217 
 218         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 219             &actual_size, TRUE, local_commands);
 220         if (!tar_hdr) {
 221                 free(buf);
 222                 return (0);
 223         }
 224 
 225         tar_hdr->th_linkflag = LF_HUMONGUS;
 226         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 227             len);
 228         tlm_build_header_checksum(tar_hdr);
 229         (void) snprintf(buf, len, "%lld %s", file_size, fullname);
 230         (void) output_mem(local_commands, buf, len);
 231 
 232         free(buf);
 233         return (0);
 234 }
 235 
 236 
 237 /*
 238  * output_xattr_header
 239  *
 240  * output the TAR header record for extended attributes
 241  */
 242 static int
 243 output_xattr_header(char *fname, char *aname, int fd,
 244     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
 245 {
 246         struct stat64 *attr = &tlm_acls->acl_attr;
 247         struct xattr_hdr *xhdr;
 248         struct xattr_buf *xbuf;
 249         tlm_tar_hdr_t *tar_hdr;
 250         long    actual_size;
 251         char    *section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
 252         int     hsize;
 253         int     comlen;
 254         int     namesz;
 255 
 256         if (section_name == NULL)
 257                 return (-TLM_NO_SCRATCH_SPACE);
 258 
 259         if (fstat64(fd, attr) == -1) {
 260                 NDMP_LOG(LOG_DEBUG, "output_file_header stat failed.");
 261                 free(section_name);
 262                 return (-TLM_OPEN_ERR);
 263         }
 264 
 265         /*
 266          * if the file has to go out in sections,
 267          * we must mung the name.
 268          */
 269         if (section == 0) {
 270                 (void) snprintf(section_name, TLM_MAX_PATH_NAME,
 271                     "/dev/null/%s.hdr", aname);
 272         } else {
 273                 (void) snprintf(section_name,
 274                     TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
 275         }
 276         namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
 277         hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
 278         comlen = namesz + sizeof (struct xattr_buf);
 279 
 280         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 281             &actual_size, TRUE, local_commands);
 282         if (!tar_hdr) {
 283                 free(section_name);
 284                 return (0);
 285         }
 286 
 287         (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
 288 
 289         tar_hdr->th_linkflag = LF_XATTR;
 290         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 291             hsize);
 292         (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
 293             attr->st_mode & 07777);
 294         (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
 295             attr->st_uid);
 296         (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
 297             attr->st_gid);
 298         (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
 299             attr->st_mtime);
 300         (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 301             sizeof (tar_hdr->th_magic));
 302 
 303         NDMP_LOG(LOG_DEBUG, "xattr_hdr: %s size %d mode %06o uid %d gid %d",
 304             aname, hsize, attr->st_mode & 07777, attr->st_uid, attr->st_gid);
 305 
 306         tlm_build_header_checksum(tar_hdr);
 307 
 308         xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE,
 309             &actual_size, TRUE, local_commands);
 310         if (!xhdr) {
 311                 free(section_name);
 312                 return (0);
 313         }
 314 
 315         (void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s",
 316             XATTR_ARCH_VERS);
 317         (void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d",
 318             sizeof (xhdr->h_size) - 1, hsize);
 319         (void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len),
 320             "%0*d", sizeof (xhdr->h_component_len) - 1, comlen);
 321         (void) snprintf(xhdr->h_link_component_len,
 322             sizeof (xhdr->h_link_component_len), "%0*d",
 323             sizeof (xhdr->h_link_component_len) - 1, 0);
 324 
 325         xbuf = (struct xattr_buf *)(((caddr_t)xhdr) +
 326             sizeof (struct xattr_hdr));
 327         (void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d",
 328             sizeof (xbuf->h_namesz) - 1, namesz);
 329 
 330         /* No support for links in extended attributes */
 331         xbuf->h_typeflag = LF_NORMAL;
 332 
 333         (void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE);
 334         (void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname,
 335             TLM_NAME_SIZE);
 336 
 337         free(section_name);
 338         return (0);
 339 }
 340 
 341 
 342 /*
 343  * output_file_header
 344  *
 345  * output the TAR header record
 346  */
 347 static int
 348 output_file_header(char *name, char *link,
 349     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
 350 {
 351         static  longlong_t file_count = 0;
 352         struct stat64 *attr = &tlm_acls->acl_attr;
 353         tlm_tar_hdr_t *tar_hdr;
 354         long    actual_size;
 355         boolean_t long_name = FALSE;
 356         boolean_t long_link = FALSE;
 357         char    *section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
 358         int     nmlen, lnklen;
 359         uid_t uid;
 360         gid_t gid;
 361         char *uname = "";
 362         char *gname = "";
 363         struct passwd *pwd;
 364         struct group *grp;
 365 
 366         if (section_name == NULL)
 367                 return (-TLM_NO_SCRATCH_SPACE);
 368 
 369         /*
 370          * if the file has to go out in sections,
 371          * we must mung the name.
 372          */
 373         if (section == 0) {
 374                 (void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
 375         } else {
 376                 (void) snprintf(section_name,
 377                     TLM_MAX_PATH_NAME, "%s.%03d", name, section);
 378         }
 379 
 380         if ((pwd = getpwuid(attr->st_uid)) != NULL)
 381                 uname = pwd->pw_name;
 382         if ((grp = getgrgid(attr->st_gid)) != NULL)
 383                 gname = grp->gr_name;
 384 
 385         if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR)
 386                 uid = UID_NOBODY;
 387         if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR)
 388                 gid = GID_NOBODY;
 389 
 390         nmlen = strlen(section_name);
 391         if (nmlen >= NAMSIZ) {
 392                 /*
 393                  * file name is too big, it must go out
 394                  * in its own data file
 395                  */
 396                 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 397                     &actual_size, TRUE, local_commands);
 398                 if (!tar_hdr) {
 399                         free(section_name);
 400                         return (0);
 401                 }
 402                 (void) snprintf(tar_hdr->th_name,
 403                     sizeof (tar_hdr->th_name),
 404                     "%s%08qd.fil",
 405                     LONGNAME_PREFIX,
 406                     file_count++);
 407 
 408                 tar_hdr->th_linkflag = LF_LONGNAME;
 409                 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
 410                     "%011o ", nmlen);
 411                 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
 412                     "%06o ", attr->st_mode & 07777);
 413                 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
 414                     "%06o ", uid);
 415                 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
 416                     "%06o ", gid);
 417                 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
 418                     "%.31s", uname);
 419                 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
 420                     "%.31s", gname);
 421                 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
 422                     "%011o ", attr->st_mtime);
 423                 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 424                     sizeof (tar_hdr->th_magic));
 425 
 426                 tlm_build_header_checksum(tar_hdr);
 427 
 428                 (void) output_mem(local_commands,
 429                     (void *)section_name, nmlen);
 430                 long_name = TRUE;
 431         }
 432 
 433         lnklen = strlen(link);
 434         if (lnklen >= NAMSIZ) {
 435                 /*
 436                  * link name is too big, it must go out
 437                  * in its own data file
 438                  */
 439                 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 440                     &actual_size, TRUE, local_commands);
 441                 if (!tar_hdr) {
 442                         free(section_name);
 443                         return (0);
 444                 }
 445                 (void) snprintf(tar_hdr->th_linkname,
 446                     sizeof (tar_hdr->th_name),
 447                     "%s%08qd.slk",
 448                     LONGNAME_PREFIX,
 449                     file_count++);
 450 
 451                 tar_hdr->th_linkflag = LF_LONGLINK;
 452                 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
 453                     "%011o ", lnklen);
 454                 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
 455                     "%06o ", attr->st_mode & 07777);
 456                 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
 457                     "%06o ", uid);
 458                 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
 459                     "%06o ", gid);
 460                 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
 461                     "%.31s", uname);
 462                 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
 463                     "%.31s", gname);
 464                 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
 465                     "%011o ", attr->st_mtime);
 466                 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 467                     sizeof (tar_hdr->th_magic));
 468 
 469                 tlm_build_header_checksum(tar_hdr);
 470 
 471                 (void) output_mem(local_commands, (void *)link,
 472                     lnklen);
 473                 long_link = TRUE;
 474         }
 475         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 476             &actual_size, TRUE, local_commands);
 477         if (!tar_hdr) {
 478                 free(section_name);
 479                 return (0);
 480         }
 481         if (long_name) {
 482                 (void) snprintf(tar_hdr->th_name,
 483                     sizeof (tar_hdr->th_name),
 484                     "%s%08qd.fil",
 485                     LONGNAME_PREFIX,
 486                     file_count++);
 487         } else {
 488                 (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
 489         }
 490 
 491         NDMP_LOG(LOG_DEBUG, "long_link: %s [%s]", long_link ? "TRUE" : "FALSE",
 492             link);
 493 
 494         if (long_link) {
 495                 (void) snprintf(tar_hdr->th_linkname,
 496                     sizeof (tar_hdr->th_name),
 497                     "%s%08qd.slk",
 498                     LONGNAME_PREFIX,
 499                     file_count++);
 500         } else {
 501                 (void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
 502         }
 503         switch (attr->st_mode & S_IFMT) {
 504         case S_IFDIR:
 505                 tar_hdr->th_linkflag = LF_DIR;
 506                 break;
 507         case S_IFIFO:
 508                 tar_hdr->th_linkflag = LF_FIFO;
 509                 break;
 510         case S_IFBLK:
 511         case S_IFCHR:
 512                 if (S_ISBLK(attr->st_mode))
 513                         tar_hdr->th_linkflag = LF_BLK;
 514                 else
 515                         tar_hdr->th_linkflag = LF_CHR;
 516                 (void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor,
 517                     sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ",
 518                     major(attr->st_rdev));
 519                 (void) snprintf(tar_hdr->th_shared.th_dev.th_devminor,
 520                     sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ",
 521                     minor(attr->st_rdev));
 522                 break;
 523         default:
 524                 if (attr->st_nlink > 1) {
 525                         /* mark file with hardlink LF_LINK */
 526                         tar_hdr->th_linkflag = LF_LINK;
 527                         (void) snprintf(tar_hdr->th_shared.th_hlink_ino,
 528                             sizeof (tar_hdr->th_shared.th_hlink_ino),
 529                             "%011llo ", attr->st_ino);
 530                 } else {
 531                         tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL :
 532                             LF_SYMLINK;
 533                         NDMP_LOG(LOG_DEBUG, "linkflag: '%c'",
 534                             tar_hdr->th_linkflag);
 535                 }
 536         }
 537         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 538             (long)attr->st_size);
 539         (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
 540             attr->st_mode & 07777);
 541         (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
 542             uid);
 543         (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
 544             gid);
 545         (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
 546             uname);
 547         (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
 548             gname);
 549         (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
 550             attr->st_mtime);
 551         (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 552             sizeof (tar_hdr->th_magic));
 553 
 554         tlm_build_header_checksum(tar_hdr);
 555         if (long_name || long_link) {
 556                 if (file_count > 99999990) {
 557                         file_count = 0;
 558                 }
 559         }
 560         free(section_name);
 561         return (0);
 562 }
 563 
 564 
 565 /*
 566  * tlm_readlink
 567  *
 568  * Read where the softlink points to.  Read the link in the checkpointed
 569  * path if the backup is being done on a checkpointed file system.
 570  */
 571 static int
 572 tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
 573 {
 574         int len;
 575 
 576         if ((len = readlink(snap, buf, bufsize)) >= 0) {
 577                 /*
 578                  * realink(2) doesn't null terminate the link name.  We must
 579                  * do it here.
 580                  */
 581                 buf[len] = '\0';
 582         } else {
 583                 NDMP_LOG(LOG_DEBUG, "Error %d reading softlink of [%s]",
 584                     errno, nm);
 585                 buf[0] = '\0';
 586 
 587                 /* Backup the link if the destination missing */
 588                 if (errno == ENOENT)
 589                         return (0);
 590 
 591         }
 592 
 593         return (len);
 594 }
 595 
 596 /*
 597  * Read the system attribute file in a single buffer to write
 598  * it as a single write. A partial write to system attribute would
 599  * cause an EINVAL on write.
 600  */
 601 static char *
 602 get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
 603     tlm_cmd_t *lc)
 604 {
 605         int len;
 606         long write_size;
 607 
 608         if (rec_size > buf_size)
 609                 return (rec);
 610 
 611         len = rec_size;
 612         (void) memcpy(rec, buf, len);
 613         buf += len;
 614         while (rec_size < buf_size) {
 615                 rec = get_write_buffer(buf_size - rec_size,
 616                     &write_size, FALSE, lc);
 617                 if (!rec)
 618                         return (0);
 619 
 620                 len = min(buf_size - rec_size, write_size);
 621                 (void) memcpy(rec, buf, len);
 622                 rec_size += len;
 623                 buf += len;
 624         }
 625         return (rec);
 626 }
 627 
 628 
 629 /*
 630  * tlm_output_xattr
 631  *
 632  * Put this file into the output buffers.
 633  */
 634 /*ARGSUSED*/
 635 longlong_t
 636 tlm_output_xattr(char  *dir, char *name, char *chkdir,
 637     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
 638     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
 639 {
 640         char    *fullname;              /* directory + name */
 641         char    *snapname;              /* snapshot name */
 642         int     section;                /* section of a huge file */
 643         int     fd;
 644         int     afd = 0;
 645         longlong_t seek_spot = 0;       /* location in the file */
 646                                         /* for Multi Volume record */
 647         u_longlong_t pos;
 648         DIR *dp;
 649         struct dirent *dtp;
 650         char *attrname;
 651         char *fnamep;
 652         int rv = 0;
 653 
 654         if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
 655                 return (TLM_NO_SOURCE_FILE);
 656         }
 657 
 658         fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
 659         if (fullname == NULL) {
 660                 free(fullname);
 661                 return (-TLM_NO_SCRATCH_SPACE);
 662         }
 663 
 664         if (!tlm_cat_path(fullname, dir, name)) {
 665                 NDMP_LOG(LOG_DEBUG, "Path too long.");
 666                 free(fullname);
 667                 return (-TLM_NO_SCRATCH_SPACE);
 668         }
 669 
 670         if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
 671             sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
 672                 free(fullname);
 673                 return (0);
 674         }
 675 
 676         attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
 677         snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
 678         if (attrname == NULL || snapname == NULL) {
 679                 rv = -TLM_NO_SCRATCH_SPACE;
 680                 goto err_out;
 681         }
 682 
 683         if (!tlm_cat_path(snapname, chkdir, name)) {
 684                 NDMP_LOG(LOG_DEBUG, "Path too long.");
 685                 rv = -TLM_NO_SCRATCH_SPACE;
 686                 goto err_out;
 687         }
 688 
 689         fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
 690 
 691         /*
 692          * Open the file for reading.
 693          */
 694         fd = attropen(fnamep, ".", O_RDONLY);
 695         if (fd == -1) {
 696                 NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s][%s]",
 697                     fullname, fnamep);
 698                 rv = TLM_NO_SOURCE_FILE;
 699                 goto err_out;
 700         }
 701 
 702         pos = tlm_get_data_offset(local_commands);
 703         NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
 704 
 705         section = 0;
 706 
 707         dp = (DIR *)fdopendir(fd);
 708         if (dp == NULL) {
 709                 NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname);
 710                 (void) close(fd);
 711                 rv = TLM_NO_SOURCE_FILE;
 712                 goto err_out;
 713         }
 714 
 715         while ((dtp = readdir(dp)) != NULL) {
 716                 int section_size;
 717 
 718                 if (*dtp->d_name == '.')
 719                         continue;
 720 
 721                 if (sysattr_rdonly(dtp->d_name))
 722                         continue;
 723 
 724                 afd = attropen(fnamep, dtp->d_name, O_RDONLY);
 725                 if (afd == -1) {
 726                         NDMP_LOG(LOG_DEBUG,
 727                             "problem(%d) opening xattr file [%s][%s]", errno,
 728                             fullname, fnamep);
 729                         goto tear_down;
 730                 }
 731 
 732                 (void) output_xattr_header(fullname, dtp->d_name, afd,
 733                     tlm_acls, section, local_commands);
 734                 (void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
 735                     dtp->d_name);
 736                 (void) output_file_header(attrname, "", tlm_acls, 0,
 737                     local_commands);
 738 
 739                 section_size = (long)llmin(tlm_acls->acl_attr.st_size,
 740                     (longlong_t)TLM_MAX_TAR_IMAGE);
 741 
 742                 /* We only can read upto one section extended attribute */
 743                 while (section_size > 0) {
 744                         char    *buf;
 745                         long    actual_size;
 746                         int     read_size;
 747                         int sysattr_read = 0;
 748                         char *rec;
 749                         int size;
 750 
 751                         /*
 752                          * check for Abort commands
 753                          */
 754                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
 755                                 local_commands->tc_writer = TLM_ABORT;
 756                                 goto tear_down;
 757                         }
 758 
 759                         local_commands->tc_buffers->tbs_buffer[
 760                             local_commands->tc_buffers->tbs_buffer_in].
 761                             tb_file_size = section_size;
 762                         local_commands->tc_buffers->tbs_buffer[
 763                             local_commands->tc_buffers->tbs_buffer_in].
 764                             tb_seek_spot = seek_spot;
 765 
 766                         buf = get_write_buffer(section_size,
 767                             &actual_size, FALSE, local_commands);
 768                         if (!buf)
 769                                 goto tear_down;
 770 
 771                         if ((actual_size < section_size) &&
 772                             sysattr_rw(dtp->d_name)) {
 773                                 rec = buf;
 774                                 buf = ndmp_malloc(section_size);
 775                                 if (!buf)
 776                                         goto tear_down;
 777                                 size = actual_size;
 778                                 actual_size = section_size;
 779                                 sysattr_read = 1;
 780                         }
 781 
 782                         /*
 783                          * check for Abort commands
 784                          */
 785                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
 786                                 local_commands->tc_writer = TLM_ABORT;
 787                                 goto tear_down;
 788                         }
 789 
 790                         read_size = min(section_size, actual_size);
 791                         if ((actual_size = read(afd, buf, read_size)) < 0)
 792                                 break;
 793 
 794                         if (sysattr_read) {
 795                                 if (get_write_one_buf(buf, rec, read_size,
 796                                     size, local_commands) == 0) {
 797                                         free(buf);
 798                                         goto tear_down;
 799                                 }
 800                                 free(buf);
 801                         }
 802 
 803 
 804                         NS_ADD(rdisk, actual_size);
 805                         NS_INC(rfile);
 806 
 807                         if (actual_size == -1) {
 808                                 NDMP_LOG(LOG_DEBUG,
 809                                     "problem(%d) reading file [%s][%s]",
 810                                     errno, fullname, snapname);
 811                                 goto tear_down;
 812                         }
 813                         seek_spot += actual_size;
 814                         section_size -= actual_size;
 815                 }
 816                 (void) close(afd);
 817                 afd = -1;
 818         }
 819 
 820 tear_down:
 821         local_commands->tc_buffers->tbs_buffer[
 822             local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
 823 
 824         if (afd > 0)
 825                 (void) close(afd);
 826 
 827         /* closedir closes fd too */
 828         (void) closedir(dp);
 829 
 830 err_out:
 831         free(fullname);
 832         free(attrname);
 833         free(snapname);
 834         return (rv);
 835 }
 836 
 837 
 838 /*
 839  * tlm_output_file
 840  *
 841  * Put this file into the output buffers.
 842  */
 843 longlong_t
 844 tlm_output_file(char *dir, char *name, char *chkdir,
 845     tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
 846     tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
 847 {
 848         char    *fullname;              /* directory + name */
 849         char    *snapname;              /* snapshot name */
 850         char    *linkname;              /* where this file points */
 851         int     section = 0;            /* section of a huge file */
 852         int     fd;
 853         longlong_t real_size;           /* the origional file size */
 854         longlong_t file_size;           /* real size of this file */
 855         longlong_t seek_spot = 0;       /* location in the file */
 856                                         /* for Multi Volume record */
 857         u_longlong_t pos;
 858         char *fnamep;
 859 
 860         /* Indicate whether a file with the same inode has been backed up. */
 861         int hardlink_done = 0;
 862 
 863         /*
 864          * If a file with the same inode has been backed up, hardlink_pos holds
 865          * the tape offset of the data record.
 866          */
 867         u_longlong_t hardlink_pos = 0;
 868 
 869         if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
 870                 NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name);
 871                 return (-TLM_NO_SCRATCH_SPACE);
 872         }
 873 
 874         fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
 875         linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
 876         snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
 877         if (fullname == NULL || linkname == NULL || snapname == NULL) {
 878                 real_size = -TLM_NO_SCRATCH_SPACE;
 879                 goto err_out;
 880         }
 881         if (!tlm_cat_path(fullname, dir, name) ||
 882             !tlm_cat_path(snapname, chkdir, name)) {
 883                 NDMP_LOG(LOG_DEBUG, "Path too long.");
 884                 real_size = -TLM_NO_SCRATCH_SPACE;
 885                 goto err_out;
 886         }
 887 
 888         pos = tlm_get_data_offset(local_commands);
 889         NDMP_LOG(LOG_DEBUG, "pos: %10lld  [%s]", pos, name);
 890 
 891         if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
 892                 if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
 893                         file_size = tlm_readlink(fullname, snapname, linkname,
 894                             TLM_MAX_PATH_NAME-1);
 895                         if (file_size < 0) {
 896                                 real_size = -ENOENT;
 897                                 goto err_out;
 898                         }
 899                 }
 900 
 901                 /*
 902                  * Since soft links can not be read(2), we should only
 903                  * backup the file header.
 904                  */
 905                 (void) output_file_header(fullname,
 906                     linkname,
 907                     tlm_acls,
 908                     section,
 909                     local_commands);
 910 
 911                 (void) tlm_log_fhnode(job_stats, dir, name,
 912                     &tlm_acls->acl_attr, pos);
 913                 (void) tlm_log_fhpath_name(job_stats, fullname,
 914                     &tlm_acls->acl_attr, pos);
 915 
 916                 free(fullname);
 917                 free(linkname);
 918                 free(snapname);
 919                 return (0);
 920         }
 921 
 922         fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
 923 
 924         /*
 925          * For hardlink, only read the data if no other link
 926          * belonging to the same inode has been backed up.
 927          */
 928         if (tlm_acls->acl_attr.st_nlink > 1) {
 929                 hardlink_done = !hardlink_q_get(hardlink_q,
 930                     tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
 931         }
 932 
 933         if (!hardlink_done) {
 934                 /*
 935                  * Open the file for reading.
 936                  */
 937                 fd = open(fnamep, O_RDONLY);
 938                 if (fd == -1) {
 939                         NDMP_LOG(LOG_DEBUG,
 940                             "BACKUP> Can't open file [%s][%s] err(%d)",
 941                             fullname, fnamep, errno);
 942                         real_size = -TLM_NO_SOURCE_FILE;
 943                         goto err_out;
 944                 }
 945         } else {
 946                 NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
 947                     tlm_acls->acl_attr.st_ino, hardlink_pos);
 948 
 949                 fd = -1;
 950         }
 951 
 952         linkname[0] = 0;
 953 
 954         real_size = tlm_acls->acl_attr.st_size;
 955         (void) output_acl_header(&tlm_acls->acl_info,
 956             local_commands);
 957 
 958         /*
 959          * section = 0: file is small enough for TAR
 960          * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
 961          *              and the file name gets munged
 962          */
 963         file_size = real_size;
 964         if (file_size > TLM_MAX_TAR_IMAGE) {
 965                 if (output_humongus_header(fullname, file_size,
 966                     local_commands) < 0) {
 967                         (void) close(fd);
 968                         real_size = -TLM_NO_SCRATCH_SPACE;
 969                         goto err_out;
 970                 }
 971                 section = 1;
 972         } else {
 973                 section = 0;
 974         }
 975 
 976         /*
 977          * For hardlink, if other link belonging to the same inode
 978          * has been backed up, only backup an empty record.
 979          */
 980         if (hardlink_done)
 981                 file_size = 0;
 982 
 983         /*
 984          * work
 985          */
 986         if (file_size == 0) {
 987                 (void) output_file_header(fullname,
 988                     linkname,
 989                     tlm_acls,
 990                     section,
 991                     local_commands);
 992                 /*
 993                  * this can fall right through since zero size files
 994                  * will be skipped by the WHILE loop anyway
 995                  */
 996         }
 997 
 998         while (file_size > 0) {
 999                 int section_size = llmin(file_size,
1000                     (longlong_t)TLM_MAX_TAR_IMAGE);
1001 
1002                 tlm_acls->acl_attr.st_size = (longlong_t)section_size;
1003                 (void) output_file_header(fullname,
1004                     linkname,
1005                     tlm_acls,
1006                     section,
1007                     local_commands);
1008                 while (section_size > 0) {
1009                         char    *buf;
1010                         long    actual_size;
1011                         int     read_size;
1012 
1013                         /*
1014                          * check for Abort commands
1015                          */
1016                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
1017                                 local_commands->tc_writer = TLM_ABORT;
1018                                 goto tear_down;
1019                         }
1020 
1021                         local_commands->tc_buffers->tbs_buffer[
1022                             local_commands->tc_buffers->tbs_buffer_in].
1023                             tb_file_size = section_size;
1024                         local_commands->tc_buffers->tbs_buffer[
1025                             local_commands->tc_buffers->tbs_buffer_in].
1026                             tb_seek_spot = seek_spot;
1027 
1028                         buf = get_write_buffer(section_size,
1029                             &actual_size, FALSE, local_commands);
1030                         if (!buf)
1031                                 goto tear_down;
1032 
1033                         /*
1034                          * check for Abort commands
1035                          */
1036                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
1037                                 local_commands->tc_writer = TLM_ABORT;
1038                                 goto tear_down;
1039                         }
1040 
1041                         read_size = min(section_size, actual_size);
1042                         actual_size = read(fd, buf, read_size);
1043                         NS_ADD(rdisk, actual_size);
1044                         NS_INC(rfile);
1045 
1046                         if (actual_size == 0)
1047                                 break;
1048 
1049                         if (actual_size == -1) {
1050                                 NDMP_LOG(LOG_DEBUG,
1051                                     "problem(%d) reading file [%s][%s]",
1052                                     errno, fullname, snapname);
1053                                 goto tear_down;
1054                         }
1055                         seek_spot += actual_size;
1056                         file_size -= actual_size;
1057                         section_size -= actual_size;
1058                 }
1059                 section++;
1060         }
1061 
1062         /*
1063          * If data belonging to this hardlink has been backed up, add the link
1064          * to hardlink queue.
1065          */
1066         if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
1067                 (void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
1068                     pos, NULL, 0);
1069                 NDMP_LOG(LOG_DEBUG,
1070                     "backed up hardlink file %s, inode = %llu, pos = %llu ",
1071                     fullname, tlm_acls->acl_attr.st_ino, pos);
1072         }
1073 
1074         /*
1075          * For hardlink, if other link belonging to the same inode has been
1076          * backed up, no add_node entry should be sent for this link.
1077          */
1078         if (hardlink_done) {
1079                 NDMP_LOG(LOG_DEBUG,
1080                     "backed up hardlink link %s, inode = %llu, pos = %llu ",
1081                     fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
1082         } else {
1083                 (void) tlm_log_fhnode(job_stats, dir, name,
1084                     &tlm_acls->acl_attr, pos);
1085         }
1086 
1087         (void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
1088             pos);
1089 
1090 tear_down:
1091         local_commands->tc_buffers->tbs_buffer[
1092             local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
1093 
1094         (void) close(fd);
1095 
1096 err_out:
1097         free(fullname);
1098         free(linkname);
1099         free(snapname);
1100         return (real_size);
1101 }
1102 
1103 /*
1104  * tar_putfile
1105  *
1106  * Main file backup function for tar
1107  */
1108 int
1109 tar_putfile(char *dir, char *name, char *chkdir,
1110     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
1111     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
1112     struct hardlink_q *hardlink_q)
1113 {
1114         int rv;
1115 
1116         rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
1117             local_commands, job_stats, hardlink_q);
1118         if (rv < 0)
1119                 return (rv);
1120 
1121         rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
1122             local_commands, job_stats);
1123 
1124         return (rv < 0 ? rv : 0);
1125 }
1126 
1127 /*
1128  * get_write_buffer
1129  *
1130  * a wrapper to tlm_get_write_buffer so that
1131  * we can cleanly detect ABORT commands
1132  * without involving the TLM library with
1133  * our problems.
1134  */
1135 static char *
1136 get_write_buffer(long size, long *actual_size,
1137     boolean_t zero, tlm_cmd_t *local_commands)
1138 {
1139         while (local_commands->tc_reader == TLM_BACKUP_RUN) {
1140                 char *rec = tlm_get_write_buffer(size, actual_size,
1141                     local_commands->tc_buffers, zero);
1142                 if (rec != 0) {
1143                         return (rec);
1144                 }
1145         }
1146         return (NULL);
1147 }
1148 
1149 #define NDMP_MORE_RECORDS       2
1150 
1151 /*
1152  * write_tar_eof
1153  *
1154  * This function is initially written for NDMP support.  It appends
1155  * two tar headers to the tar file, and also N more empty buffers
1156  * to make sure that the two tar headers will be read as a part of
1157  * a mover record and don't get locked because of EOM on the mover
1158  * side.
1159  */
1160 void
1161 write_tar_eof(tlm_cmd_t *local_commands)
1162 {
1163         int i;
1164         long actual_size;
1165         tlm_buffers_t *bufs;
1166 
1167         /*
1168          * output 2 zero filled records,
1169          * TAR wants this.
1170          */
1171         (void) get_write_buffer(sizeof (tlm_tar_hdr_t),
1172             &actual_size, TRUE, local_commands);
1173         (void) get_write_buffer(sizeof (tlm_tar_hdr_t),
1174             &actual_size, TRUE, local_commands);
1175 
1176         /*
1177          * NDMP: Clear the rest of the buffer and write two more buffers
1178          * to the tape.
1179          */
1180         bufs = local_commands->tc_buffers;
1181         (void) get_write_buffer(bufs->tbs_data_transfer_size,
1182             &actual_size, TRUE, local_commands);
1183 
1184         for (i = 0; i < NDMP_MORE_RECORDS &&
1185             local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
1186                 /*
1187                  * We don't need the return value of get_write_buffer(),
1188                  * since it's already zeroed out if the buffer is returned.
1189                  */
1190                 (void) get_write_buffer(bufs->tbs_data_transfer_size,
1191                     &actual_size, TRUE, local_commands);
1192         }
1193 
1194         bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
1195         tlm_buffer_release_in_buf(bufs);
1196 }
1197 
1198 /*
1199  * Callback to backup each ZFS property
1200  */
1201 static int
1202 zfs_put_prop_cb(int prop, void *pp)
1203 {
1204         ndmp_metadata_handle_t *mhd;
1205         ndmp_metadata_header_ext_t *mhp;
1206         ndmp_metadata_property_ext_t *mpp;
1207         char vbuf[ZFS_MAXPROPLEN];
1208         char sbuf[ZFS_MAXPROPLEN];
1209         zprop_source_t stype;
1210         char *sourcestr;
1211 
1212         if (pp == NULL)
1213                 return (ZPROP_INVAL);
1214 
1215         mhd = (ndmp_metadata_handle_t *)pp;
1216         mhp = mhd->ml_xhdr;
1217         mpp = &mhp->nh_property[mhp->nh_count];
1218 
1219         if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
1220             sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
1221                 return (ZPROP_INVAL);
1222 
1223         if (zfs_prop_get(mhd->ml_handle, prop, vbuf, sizeof (vbuf),
1224             &stype, sbuf, sizeof (sbuf), B_TRUE) != 0) {
1225                 mhp->nh_count++;
1226                 return (ZPROP_CONT);
1227         }
1228 
1229         (void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop),
1230             ZFS_MAX_DATASET_NAME_LEN);
1231         (void) strlcpy(mpp->mp_value, vbuf, ZFS_MAXPROPLEN);
1232 
1233         switch (stype) {
1234         case ZPROP_SRC_NONE:
1235                 sourcestr = "none";
1236                 break;
1237         case ZPROP_SRC_RECEIVED:
1238                 sourcestr = "received";
1239                 break;
1240         case ZPROP_SRC_LOCAL:
1241                 sourcestr = mhp->nh_dataset;
1242                 break;
1243         case ZPROP_SRC_TEMPORARY:
1244                 sourcestr = "temporary";
1245                 break;
1246         case ZPROP_SRC_DEFAULT:
1247                 sourcestr = "default";
1248                 break;
1249         default:
1250                 sourcestr = sbuf;
1251                 break;
1252         }
1253         (void) strlcpy(mpp->mp_source, sourcestr, ZFS_MAXPROPLEN);
1254 
1255         mhp->nh_count++;
1256         return (ZPROP_CONT);
1257 }
1258 
1259 /*
1260  * Callback to backup each ZFS user/group quota
1261  */
1262 static int
1263 zfs_put_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
1264 {
1265         ndmp_metadata_handle_t *mhd;
1266         ndmp_metadata_header_ext_t *mhp;
1267         ndmp_metadata_property_ext_t *mpp;
1268         char *typestr;
1269 
1270         if (pp == NULL)
1271                 return (ZPROP_INVAL);
1272 
1273         mhd = (ndmp_metadata_handle_t *)pp;
1274         mhp = mhd->ml_xhdr;
1275         mpp = &mhp->nh_property[mhp->nh_count];
1276 
1277         if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
1278             sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
1279                 return (ZPROP_INVAL);
1280 
1281         if (mhd->ml_quota_prop == ZFS_PROP_USERQUOTA)
1282                 typestr = "userquota";
1283         else
1284                 typestr = "groupquota";
1285 
1286         if (domain == NULL || *domain == '\0') {
1287                 (void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN,
1288                     "%s@%llu", typestr, (longlong_t)rid);
1289         } else {
1290                 (void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN,
1291                     "%s@%s-%llu", typestr, domain, (longlong_t)rid);
1292         }
1293         (void) snprintf(mpp->mp_value, ZFS_MAXPROPLEN, "%llu", space);
1294         (void) strlcpy(mpp->mp_source, mhp->nh_dataset, ZFS_MAXPROPLEN);
1295 
1296         mhp->nh_count++;
1297         return (0);
1298 }
1299 
1300 /*
1301  * Callback to count each ZFS property
1302  */
1303 /*ARGSUSED*/
1304 static int
1305 zfs_count_prop_cb(int prop, void *pp)
1306 {
1307         (*(int *)pp)++;
1308         return (ZPROP_CONT);
1309 }
1310 
1311 /*
1312  * Callback to count each ZFS user/group quota
1313  */
1314 /*ARGSUSED*/
1315 static int
1316 zfs_count_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
1317 {
1318         (*(int *)pp)++;
1319         return (0);
1320 }
1321 
1322 /*
1323  * Count the number of ZFS properties and user/group quotas
1324  */
1325 int
1326 zfs_get_prop_counts(zfs_handle_t *zhp)
1327 {
1328         int count = 0;
1329         nvlist_t *uprops;
1330         nvpair_t *elp;
1331 
1332         if (zhp == NULL)
1333                 return (0);
1334 
1335         (void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE,
1336             ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
1337 
1338         (void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb,
1339             &count);
1340         (void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb,
1341             &count);
1342 
1343         uprops = zfs_get_user_props(zhp);
1344 
1345         elp = nvlist_next_nvpair(uprops, NULL);
1346         for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp))
1347                 count++;
1348 
1349         return (count);
1350 }
1351 
1352 /*
1353  * Notifies ndmpd that the metadata associated with the given ZFS dataset
1354  * should be backed up.
1355  */
1356 int
1357 ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
1358 {
1359         tlm_commands_t *cmds;
1360         ndmp_metadata_handle_t mhd;
1361         ndmp_metadata_header_ext_t *mhp;
1362         ndmp_metadata_property_ext_t *mpp;
1363         zfs_handle_t *zhp;
1364         tlm_cmd_t *lcmd;
1365         long actual_size;
1366         nvlist_t *uprops, *ulist;
1367         const char *pname;
1368         nvpair_t *elp;
1369         char *sval, *ssrc;
1370         char *wbuf, *pp, *tp;
1371         long size, lsize, sz;
1372         int align = RECORDSIZE - 1;
1373         int pcount;
1374 
1375         if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
1376                 return (-1);
1377 
1378         if ((lcmd = cmds->tcs_command) == NULL ||
1379             lcmd->tc_buffers == NULL)
1380                 return (-1);
1381 
1382         (void) mutex_lock(&zlib_mtx);
1383         if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) {
1384                 (void) mutex_unlock(&zlib_mtx);
1385                 return (-1);
1386         }
1387 
1388         pcount = zfs_get_prop_counts(zhp);
1389         size = sizeof (ndmp_metadata_header_ext_t) +
1390             pcount * sizeof (ndmp_metadata_property_ext_t);
1391 
1392         size += align;
1393         size &= ~align;
1394 
1395         if ((mhp = malloc(size)) == NULL) {
1396                 zfs_close(zhp);
1397                 (void) mutex_unlock(&zlib_mtx);
1398                 return (-1);
1399         }
1400 
1401         (void) memset(mhp, 0, size);
1402 
1403         mhd.ml_handle = zhp;
1404         mhd.ml_xhdr = mhp;
1405         mhp->nh_total_bytes = size;
1406         mhp->nh_major = META_HDR_MAJOR_VERSION;
1407         mhp->nh_minor = META_HDR_MINOR_VERSION;
1408         mhp->nh_plversion = nctx->nc_plversion;
1409 
1410         (void) strlcpy(mhp->nh_plname, nctx->nc_plname,
1411             sizeof (mhp->nh_plname));
1412         (void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT,
1413             sizeof (mhp->nh_magic));
1414         (void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
1415 
1416         /* Get all the ZFS properties */
1417         (void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE,
1418             ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
1419 
1420         /* Get user properties */
1421         uprops = zfs_get_user_props(mhd.ml_handle);
1422 
1423         elp = nvlist_next_nvpair(uprops, NULL);
1424 
1425         while (elp != NULL) {
1426                 mpp = &mhp->nh_property[mhp->nh_count];
1427                 if (nvpair_value_nvlist(elp, &ulist) != 0 ||
1428                     nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
1429                     nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
1430                         zfs_close(mhd.ml_handle);
1431                         (void) mutex_unlock(&zlib_mtx);
1432                         free(mhp);
1433                         return (-1);
1434                 }
1435                 if ((pname = nvpair_name(elp)) != NULL) {
1436                         (void) strlcpy(mpp->mp_name, pname,
1437                             ZFS_MAX_DATASET_NAME_LEN);
1438                 }
1439 
1440                 (void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN);
1441                 (void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN);
1442                 mhp->nh_count++;
1443                 elp = nvlist_next_nvpair(uprops, elp);
1444         }
1445 
1446         mhd.ml_quota_prop = ZFS_PROP_USERQUOTA;
1447         (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA,
1448             zfs_put_quota_cb, &mhd);
1449         mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA;
1450         (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA,
1451             zfs_put_quota_cb, &mhd);
1452         mhp->nh_count = pcount;
1453 
1454         zfs_close(mhd.ml_handle);
1455         (void) mutex_unlock(&zlib_mtx);
1456 
1457         if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
1458             lcmd)) != NULL) {
1459                 pp = (char *)mhp;
1460 
1461                 (void) memcpy(wbuf, pp, (actual_size < size) ?
1462                     actual_size : size);
1463                 pp += (actual_size < size) ? actual_size : size;
1464 
1465                 sz = actual_size;
1466                 while (sz < size &&
1467                     ((tp = get_write_buffer(size - sz, &lsize,
1468                     TRUE, lcmd))) != NULL) {
1469                         (void) memcpy(tp, pp, lsize);
1470                         sz += lsize;
1471                         pp += lsize;
1472                 }
1473                 if (sz > size) {
1474                         tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
1475                 }
1476         }
1477 
1478         free(mhp);
1479         return (0);
1480 }