xref: /openbsd-src/usr.bin/rsync/copy.c (revision d9a51c353c88dac7b4a389c112b4cfe97b8e3a46)
1*d9a51c35Sjmc /*	$OpenBSD: copy.c,v 1.4 2022/12/26 19:16:02 jmc Exp $ */
2e397242dSclaudio /*
3e397242dSclaudio  * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
4e397242dSclaudio  *
5e397242dSclaudio  * Permission to use, copy, modify, and distribute this software for any
6e397242dSclaudio  * purpose with or without fee is hereby granted, provided that the above
7e397242dSclaudio  * copyright notice and this permission notice appear in all copies.
8e397242dSclaudio  *
9e397242dSclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10e397242dSclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11e397242dSclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12e397242dSclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13e397242dSclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14e397242dSclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15e397242dSclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16e397242dSclaudio  */
17e397242dSclaudio 
181a0afcdeSderaadt #include <sys/types.h>
19e397242dSclaudio 
20e397242dSclaudio #include <err.h>
21e397242dSclaudio #include <fcntl.h>
22e397242dSclaudio #include <unistd.h>
23e397242dSclaudio 
24e397242dSclaudio #include "extern.h"
25e397242dSclaudio 
261a0afcdeSderaadt #define _MAXBSIZE (64 * 1024)
271a0afcdeSderaadt 
28e397242dSclaudio /*
29e397242dSclaudio  * Return true if all bytes in buffer are zero.
30*d9a51c35Sjmc  * A buffer of zero length is also considered a zero buffer.
31e397242dSclaudio  */
32e397242dSclaudio static int
iszero(const void * b,size_t len)33e397242dSclaudio iszero(const void *b, size_t len)
34e397242dSclaudio {
35e397242dSclaudio 	const unsigned char *c = b;
36e397242dSclaudio 
37e397242dSclaudio 	for (; len > 0; len--) {
38e397242dSclaudio 		if (*c++ != '\0')
39e397242dSclaudio 			return 0;
40e397242dSclaudio 	}
41e397242dSclaudio 	return 1;
42e397242dSclaudio }
43e397242dSclaudio 
44e397242dSclaudio static int
copy_internal(int fromfd,int tofd)45e397242dSclaudio copy_internal(int fromfd, int tofd)
46e397242dSclaudio {
471a0afcdeSderaadt 	char buf[_MAXBSIZE];
48e397242dSclaudio 	ssize_t r, w;
49e397242dSclaudio 
50e397242dSclaudio 	while ((r = read(fromfd, buf, sizeof(buf))) > 0) {
51e397242dSclaudio 		if (iszero(buf, sizeof(buf))) {
52e397242dSclaudio 			if (lseek(tofd, r, SEEK_CUR) == -1)
53e397242dSclaudio 				return -1;
54e397242dSclaudio 		} else {
55e397242dSclaudio 			w = write(tofd, buf, r);
56e397242dSclaudio 			if (r != w || w == -1)
57e397242dSclaudio 				return -1;
58e397242dSclaudio 		}
59e397242dSclaudio 	}
60e397242dSclaudio 	if (r == -1)
61e397242dSclaudio 		return -1;
62e397242dSclaudio 	if (ftruncate(tofd, lseek(tofd, 0, SEEK_CUR)) == -1)
63e397242dSclaudio 		return -1;
64e397242dSclaudio 	return 0;
65e397242dSclaudio }
66e397242dSclaudio 
67e397242dSclaudio void
copy_file(int rootfd,const char * basedir,const struct flist * f)68e397242dSclaudio copy_file(int rootfd, const char *basedir, const struct flist *f)
69e397242dSclaudio {
70e397242dSclaudio 	int fromfd, tofd, dfd;
71e397242dSclaudio 
72b7041c07Sderaadt 	dfd = openat(rootfd, basedir, O_RDONLY | O_DIRECTORY);
73e397242dSclaudio 	if (dfd == -1)
74e397242dSclaudio 		err(ERR_FILE_IO, "%s: openat", basedir);
75e397242dSclaudio 
76b7041c07Sderaadt 	fromfd = openat(dfd, f->path, O_RDONLY | O_NOFOLLOW);
77e397242dSclaudio 	if (fromfd == -1)
78e397242dSclaudio 		err(ERR_FILE_IO, "%s/%s: openat", basedir, f->path);
79e397242dSclaudio 	close(dfd);
80e397242dSclaudio 
81e397242dSclaudio 	tofd = openat(rootfd, f->path,
82e397242dSclaudio 	    O_WRONLY | O_NOFOLLOW | O_TRUNC | O_CREAT | O_EXCL,
83e397242dSclaudio 	    0600);
84e397242dSclaudio 	if (tofd == -1)
85e397242dSclaudio 		err(ERR_FILE_IO, "%s: openat", f->path);
86e397242dSclaudio 
87e397242dSclaudio 	if (copy_internal(fromfd, tofd) == -1)
88e397242dSclaudio 		err(ERR_FILE_IO, "%s: copy file", f->path);
89e397242dSclaudio 
90e397242dSclaudio 	close(fromfd);
91e397242dSclaudio 	close(tofd);
92e397242dSclaudio }
93