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