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/mman.h>
32 #include <sys/stat.h>
33
34 #include <stdlib.h>
35
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <limits.h>
39 #include <pthread.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <unistd.h>
43
44 #include "compat_stdbool.h"
45 #include "compat_stdint.h"
46 #include "compat_inttypes.h"
47 #include "compat_limits.h"
48 #include "compat_strings.h"
49 #include "basedef.h"
50
51 #include "attribute.h"
52 #include "collection.h"
53 #include "cvsync.h"
54 #include "cvsync_attr.h"
55 #include "hash.h"
56 #include "logmsg.h"
57 #include "mux.h"
58
59 #include "filescan.h"
60 #include "filecmp.h"
61
62 bool filescan_fetch(struct filescan_args *);
63 bool filescan_close(struct filescan_args *);
64
65 struct filescan_args *
filescan_init(struct mux * mx,struct collection * cls,uint32_t proto,int type)66 filescan_init(struct mux *mx, struct collection *cls, uint32_t proto, int type)
67 {
68 struct filescan_args *fsa;
69
70 if ((fsa = malloc(sizeof(*fsa))) == NULL) {
71 logmsg_err("%s", strerror(errno));
72 return (NULL);
73 }
74 fsa->fsa_mux = mx;
75 fsa->fsa_proto = proto;
76 fsa->fsa_collections = cls;
77 fsa->fsa_pathmax = sizeof(fsa->fsa_path);
78 fsa->fsa_namemax = CVSYNC_NAME_MAX;
79 fsa->fsa_cmdmax = sizeof(fsa->fsa_cmd);
80
81 if (!hash_set(type, &fsa->fsa_hash_ops)) {
82 free(fsa);
83 return (NULL);
84 }
85
86 return (fsa);
87 }
88
89 void
filescan_destroy(struct filescan_args * fsa)90 filescan_destroy(struct filescan_args *fsa)
91 {
92 free(fsa);
93 }
94
95 void *
filescan(void * arg)96 filescan(void *arg)
97 {
98 struct filescan_args *fsa = arg;
99 struct collection *cl;
100
101 for (cl = fsa->fsa_collections ; cl != NULL ; cl = cl->cl_next) {
102 if (cl->cl_flags & CLFLAGS_DISABLE)
103 continue;
104
105 if (cvsync_isinterrupted()) {
106 mux_abort(fsa->fsa_mux);
107 return (CVSYNC_THREAD_FAILURE);
108 }
109
110 if (!filescan_fetch(fsa)) {
111 logmsg_err("FileScan: Fetch Error");
112 mux_abort(fsa->fsa_mux);
113 return (CVSYNC_THREAD_FAILURE);
114 }
115
116 if (fsa->fsa_tag != FILESCAN_START) {
117 logmsg_err("FileScan: invalid tag: %02x",
118 fsa->fsa_tag);
119 mux_abort(fsa->fsa_mux);
120 return (CVSYNC_THREAD_FAILURE);
121 }
122
123 if ((strcasecmp(cl->cl_name, fsa->fsa_name) != 0) ||
124 (strcasecmp(cl->cl_release, fsa->fsa_release) != 0)) {
125 logmsg_err("FileScan: Collection Error");
126 mux_abort(fsa->fsa_mux);
127 return (CVSYNC_THREAD_FAILURE);
128 }
129
130 if (!filescan_start(fsa, cl->cl_name, cl->cl_release)) {
131 logmsg_err("FileScan: Initializer Error");
132 mux_abort(fsa->fsa_mux);
133 return (CVSYNC_THREAD_FAILURE);
134 }
135
136 fsa->fsa_refuse = cl->cl_refuse;
137 fsa->fsa_pathlen = cl->cl_prefixlen;
138 if (fsa->fsa_pathlen >= fsa->fsa_pathmax) {
139 logmsg_err("FileScan: Initializer Error");
140 mux_abort(fsa->fsa_mux);
141 return (CVSYNC_THREAD_FAILURE);
142 }
143 (void)memcpy(fsa->fsa_path, cl->cl_prefix, fsa->fsa_pathlen);
144 fsa->fsa_path[fsa->fsa_pathlen] = '\0';
145 fsa->fsa_rpath = &fsa->fsa_path[fsa->fsa_pathlen];
146 fsa->fsa_umask = cl->cl_umask;
147
148 switch (cvsync_release_pton(cl->cl_release)) {
149 case CVSYNC_RELEASE_LIST:
150 if (!filescan_fetch(fsa)) {
151 logmsg_err("FileScan: Fetch Error");
152 mux_abort(fsa->fsa_mux);
153 return (CVSYNC_THREAD_FAILURE);
154 }
155 if (fsa->fsa_tag != FILESCAN_END) {
156 logmsg_err("FileScan: LIST Error");
157 mux_abort(fsa->fsa_mux);
158 return (CVSYNC_THREAD_FAILURE);
159 }
160 break;
161 case CVSYNC_RELEASE_RCS:
162 if (!filescan_rcs(fsa)) {
163 logmsg_err("FileScan: RCS Error");
164 mux_abort(fsa->fsa_mux);
165 return (CVSYNC_THREAD_FAILURE);
166 }
167 break;
168 default:
169 logmsg_err("FileScan: Release Error");
170 mux_abort(fsa->fsa_mux);
171 return (CVSYNC_THREAD_FAILURE);
172 }
173
174 if (!filescan_end(fsa)) {
175 logmsg_err("FileScan: Collection Finalizer Error");
176 mux_abort(fsa->fsa_mux);
177 return (CVSYNC_THREAD_FAILURE);
178 }
179 }
180
181 if (!filescan_fetch(fsa)) {
182 logmsg_err("FileScan: Fetch Error");
183 mux_abort(fsa->fsa_mux);
184 return (CVSYNC_THREAD_FAILURE);
185 }
186
187 if (fsa->fsa_tag != FILESCAN_END) {
188 logmsg_err("FileScan: invalid tag: %02x", fsa->fsa_tag);
189 mux_abort(fsa->fsa_mux);
190 return (CVSYNC_THREAD_FAILURE);
191 }
192
193 if (!filescan_end(fsa)) {
194 logmsg_err("FileScan: Finalizer Error");
195 mux_abort(fsa->fsa_mux);
196 return (CVSYNC_THREAD_FAILURE);
197 }
198
199 if (!filescan_close(fsa)) {
200 logmsg_err("FileScan: Finalizer Error");
201 mux_abort(fsa->fsa_mux);
202 return (CVSYNC_THREAD_FAILURE);
203 }
204
205 return (CVSYNC_THREAD_SUCCESS);
206 }
207
208 bool
filescan_fetch(struct filescan_args * fsa)209 filescan_fetch(struct filescan_args *fsa)
210 {
211 uint8_t *cmd = fsa->fsa_cmd;
212 size_t len, namelen, relnamelen;
213
214 if (!mux_recv(fsa->fsa_mux, MUX_FILESCAN_IN, cmd, 3))
215 return (false);
216 len = GetWord(cmd);
217 if ((len == 0) || (len > fsa->fsa_cmdmax - 2))
218 return (false);
219 fsa->fsa_tag = cmd[2];
220
221 switch (fsa->fsa_tag) {
222 case FILESCAN_START:
223 if (len < 3)
224 return (false);
225 if (!mux_recv(fsa->fsa_mux, MUX_FILESCAN_IN, cmd, 2))
226 return (false);
227 if ((namelen = cmd[0]) > fsa->fsa_namemax)
228 return (false);
229 if ((relnamelen = cmd[1]) > fsa->fsa_namemax)
230 return (false);
231 if (len != namelen + relnamelen + 3)
232 return (false);
233
234 if (!mux_recv(fsa->fsa_mux, MUX_FILESCAN_IN, fsa->fsa_name,
235 namelen)) {
236 return (false);
237 }
238 fsa->fsa_name[namelen] = '\0';
239 if (!mux_recv(fsa->fsa_mux, MUX_FILESCAN_IN, fsa->fsa_release,
240 relnamelen)) {
241 return (false);
242 }
243 fsa->fsa_release[relnamelen] = '\0';
244
245 break;
246 case FILESCAN_END:
247 if (len != 1)
248 return (false);
249 break;
250 default:
251 return (false);
252 }
253
254 return (true);
255 }
256
257 bool
filescan_start(struct filescan_args * fsa,const char * name,const char * relname)258 filescan_start(struct filescan_args *fsa, const char *name, const char *relname)
259 {
260 uint8_t *cmd = fsa->fsa_cmd;
261 size_t len, namelen, relnamelen;
262
263 if (((namelen = strlen(name)) > fsa->fsa_namemax) ||
264 ((relnamelen = strlen(relname)) > fsa->fsa_namemax)) {
265 return (false);
266 }
267 if ((len = namelen + relnamelen + 5) > fsa->fsa_cmdmax)
268 return (false);
269
270 SetWord(cmd, len - 2);
271 cmd[2] = FILECMP_START;
272 cmd[3] = namelen;
273 cmd[4] = relnamelen;
274 if (!mux_send(fsa->fsa_mux, MUX_FILECMP, cmd, 5))
275 return (false);
276 if (!mux_send(fsa->fsa_mux, MUX_FILECMP, name, namelen))
277 return (false);
278 if (!mux_send(fsa->fsa_mux, MUX_FILECMP, relname, relnamelen))
279 return (false);
280
281 if (!mux_flush(fsa->fsa_mux, MUX_FILECMP))
282 return (false);
283
284 return (true);
285 }
286
287 bool
filescan_end(struct filescan_args * fsa)288 filescan_end(struct filescan_args *fsa)
289 {
290 static const uint8_t _cmd[3] = { 0x00, 0x01, FILECMP_END };
291
292 if (!mux_send(fsa->fsa_mux, MUX_FILECMP, _cmd, sizeof(_cmd)))
293 return (false);
294
295 return (true);
296 }
297
298 bool
filescan_close(struct filescan_args * fsa)299 filescan_close(struct filescan_args *fsa)
300 {
301 if (!mux_close_out(fsa->fsa_mux, MUX_FILECMP))
302 return (false);
303 return (mux_close_in(fsa->fsa_mux, MUX_FILESCAN_IN));
304 }
305