1 /*-
2  * Copyright (c) 2000-2005 MAEKAWA Masahide <maekawa@cvsync.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 
33 #include <stdlib.h>
34 
35 #include <errno.h>
36 #include <limits.h>
37 #include <pthread.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <utime.h>
41 
42 #include "compat_sys_stat.h"
43 #include "compat_stdbool.h"
44 #include "compat_stdint.h"
45 #include "compat_inttypes.h"
46 #include "compat_limits.h"
47 #include "basedef.h"
48 
49 #include "attribute.h"
50 #include "collection.h"
51 #include "cvsync.h"
52 #include "cvsync_attr.h"
53 #include "hash.h"
54 #include "logmsg.h"
55 #include "mux.h"
56 
57 #include "updater.h"
58 
59 bool
updater_generic_update(struct updater_args * uda)60 updater_generic_update(struct updater_args *uda)
61 {
62 	const struct hash_args *hashops = uda->uda_hash_ops;
63 	struct cvsync_attr *cap = &uda->uda_attr;
64 	struct utimbuf times;
65 	uint64_t size;
66 	uint8_t *cmd = uda->uda_cmd;
67 	ssize_t wn;
68 	size_t len;
69 	int fd;
70 
71 	if (!mux_recv(uda->uda_mux, MUX_UPDATER_IN, cmd, 8)) {
72 		logmsg_err("Updater Error: generic: recv");
73 		return (false);
74 	}
75 	size = GetDDWord(cmd);
76 
77 	if ((fd = mkstemp(uda->uda_tmpfile)) == -1) {
78 		logmsg_err("Updater Error: generic: %s", strerror(errno));
79 		return (false);
80 	}
81 
82 	if (!(*hashops->init)(&uda->uda_hash_ctx)) {
83 		logmsg_err("Updater Error: generic: hash init");
84 		(void)unlink(uda->uda_tmpfile);
85 		return (false);
86 	}
87 
88 	while (size > 0) {
89 		if (size < (uint64_t)uda->uda_bufsize)
90 			len = (size_t)size;
91 		else
92 			len = uda->uda_bufsize;
93 
94 		if (!mux_recv(uda->uda_mux, MUX_UPDATER_IN,
95 			      uda->uda_buffer, len)) {
96 			logmsg_err("Updater Error: generic: recv");
97 			(*hashops->destroy)(uda->uda_hash_ctx);
98 			(void)unlink(uda->uda_tmpfile);
99 			(void)close(fd);
100 			return (false);
101 		}
102 
103 		if ((wn = write(fd, uda->uda_buffer, len)) == -1) {
104 			logmsg_err("Updater Error: generic: %s",
105 				   strerror(errno));
106 			(*hashops->destroy)(uda->uda_hash_ctx);
107 			(void)unlink(uda->uda_tmpfile);
108 			(void)close(fd);
109 			return (false);
110 		}
111 		if (wn == 0)
112 			break;
113 
114 		(*hashops->update)(uda->uda_hash_ctx, uda->uda_buffer, wn);
115 		size -= (uint64_t)wn;
116 	}
117 	if (size != 0) {
118 		logmsg_err("Updater Error: generic: residue %" PRIu64, size);
119 		(*hashops->destroy)(uda->uda_hash_ctx);
120 		(void)unlink(uda->uda_tmpfile);
121 		(void)close(fd);
122 		return (false);
123 	}
124 
125 	(*hashops->final)(uda->uda_hash_ctx, uda->uda_hash);
126 
127 	if (!mux_recv(uda->uda_mux, MUX_UPDATER_IN, cmd, hashops->length)) {
128 		logmsg_err("Updater Error: generic: recv");
129 		(void)unlink(uda->uda_tmpfile);
130 		(void)close(fd);
131 		return (false);
132 	}
133 	if (memcmp(uda->uda_hash, cmd, hashops->length) != 0) {
134 		logmsg_err("Updater Error: generic: %s: hash mismatch",
135 			   uda->uda_path);
136 		(void)unlink(uda->uda_tmpfile);
137 		(void)close(fd);
138 		return (false);
139 	}
140 
141 	if (fchmod(fd, cap->ca_mode) == -1) {
142 		logmsg_err("Updater Error: generic: %s", strerror(errno));
143 		(void)unlink(uda->uda_tmpfile);
144 		(void)close(fd);
145 		return (false);
146 	}
147 
148 	if (close(fd) == -1) {
149 		logmsg_err("Updater Error: generic: %s", strerror(errno));
150 		(void)unlink(uda->uda_tmpfile);
151 		return (false);
152 	}
153 
154 	times.actime = (time_t)cap->ca_mtime;
155 	times.modtime = (time_t)cap->ca_mtime;
156 
157 	if (utime(uda->uda_tmpfile, &times) == -1) {
158 		logmsg_err("Updater Error: generic: %s", strerror(errno));
159 		(void)unlink(uda->uda_tmpfile);
160 		return (false);
161 	}
162 
163 	return (true);
164 }
165