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