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