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