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 <limits.h>
36 #include <pthread.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include "compat_stdbool.h"
41 #include "compat_stdint.h"
42 #include "compat_inttypes.h"
43 #include "compat_limits.h"
44 #include "compat_unistd.h"
45 #include "basedef.h"
46
47 #include "attribute.h"
48 #include "collection.h"
49 #include "cvsync.h"
50 #include "cvsync_attr.h"
51 #include "filetypes.h"
52 #include "list.h"
53 #include "mdirent.h"
54 #include "mux.h"
55
56 #include "dircmp.h"
57 #include "filescan.h"
58
59 bool dircmp_rcs_fetch(struct dircmp_args *);
60
61 bool dircmp_rcs_add(struct dircmp_args *, struct mdirent_rcs *);
62 bool dircmp_rcs_add_dir(struct dircmp_args *, struct mdirent_rcs *);
63 bool dircmp_rcs_add_file(struct dircmp_args *, struct mdirent_rcs *);
64 bool dircmp_rcs_add_symlink(struct dircmp_args *, struct mdirent_rcs *);
65 bool dircmp_rcs_remove(struct dircmp_args *);
66 bool dircmp_rcs_remove_dir(struct dircmp_args *);
67 bool dircmp_rcs_remove_file(struct dircmp_args *);
68 bool dircmp_rcs_replace(struct dircmp_args *, struct mdirent_rcs *);
69 bool dircmp_rcs_update(struct dircmp_args *, struct mdirent_rcs *);
70
71 struct mDIR *dircmp_rcs_opendir(struct dircmp_args *, size_t);
72
73 bool
dircmp_rcs(struct dircmp_args * dca)74 dircmp_rcs(struct dircmp_args *dca)
75 {
76 struct mDIR *mdirp;
77 struct mdirent_rcs *mdp, *entries;
78 struct cvsync_attr *cap = &dca->dca_attr;
79 struct list *lp;
80 int rv;
81 bool fetched;
82
83 if (dca->dca_collection->cl_scanfile != NULL)
84 return (dircmp_rcs_scanfile(dca));
85
86 if ((lp = list_init()) == NULL)
87 return (false);
88 list_set_destructor(lp, mclosedir);
89
90 if ((mdirp = dircmp_rcs_opendir(dca, dca->dca_pathlen)) == NULL) {
91 list_destroy(lp);
92 return (false);
93 }
94 mdirp->m_parent_pathlen = dca->dca_pathlen;
95
96 fetched = false;
97
98 for (;;) {
99 if (!fetched) {
100 if (!dircmp_rcs_fetch(dca)) {
101 mclosedir(mdirp);
102 list_destroy(lp);
103 return (false);
104 }
105 fetched = true;
106 }
107
108 if (cap->ca_tag == DIRCMP_END)
109 break;
110
111 if (cap->ca_tag == DIRCMP_UP) {
112 while (mdirp->m_offset < mdirp->m_nentries) {
113 entries = mdirp->m_entries;
114 mdp = &entries[mdirp->m_offset++];
115 if (!dircmp_access(dca, mdp))
116 continue;
117 if (!dircmp_rcs_add(dca, mdp)) {
118 mclosedir(mdirp);
119 list_destroy(lp);
120 return (false);
121 }
122 }
123 dca->dca_pathlen = mdirp->m_parent_pathlen;
124 dca->dca_path[dca->dca_pathlen] = '\0';
125 mclosedir(mdirp);
126
127 if ((mdirp = list_remove_tail(lp)) == NULL) {
128 list_destroy(lp);
129 return (false);
130 }
131 mdirp->m_offset++;
132
133 fetched = false;
134 continue;
135 }
136
137 if (mdirp->m_offset == mdirp->m_nentries) {
138 if (!dircmp_rcs_remove(dca)) {
139 mclosedir(mdirp);
140 list_destroy(lp);
141 return (false);
142 }
143
144 fetched = false;
145 continue;
146 }
147
148 entries = mdirp->m_entries;
149 mdp = &entries[mdirp->m_offset];
150 if (!dircmp_access(dca, mdp)) {
151 mdirp->m_offset++;
152 continue;
153 }
154
155 if (mdp->md_namelen == cap->ca_namelen) {
156 rv = memcmp(mdp->md_name, cap->ca_name,
157 cap->ca_namelen);
158 } else {
159 if (mdp->md_namelen < cap->ca_namelen) {
160 rv = memcmp(mdp->md_name, cap->ca_name,
161 mdp->md_namelen);
162 } else {
163 rv = memcmp(mdp->md_name, cap->ca_name,
164 cap->ca_namelen);
165 }
166 if (rv == 0) {
167 if (mdp->md_namelen < cap->ca_namelen)
168 rv = -1;
169 else
170 rv = 1;
171 }
172 }
173 if (rv == 0) {
174 if (!dircmp_rcs_update(dca, mdp)) {
175 mclosedir(mdirp);
176 list_destroy(lp);
177 return (false);
178 }
179 if (cap->ca_tag != DIRCMP_DOWN) {
180 mdirp->m_offset++;
181 } else {
182 size_t len;
183
184 if (!list_insert_tail(lp, mdirp)) {
185 mclosedir(mdirp);
186 list_destroy(lp);
187 return (false);
188 }
189
190 len = dca->dca_pathlen + mdp->md_namelen + 1;
191 if (len >= dca->dca_pathmax) {
192 list_destroy(lp);
193 return (false);
194 }
195 (void)memcpy(&dca->dca_path[dca->dca_pathlen],
196 mdp->md_name, mdp->md_namelen);
197 dca->dca_path[len - 1] = '/';
198 dca->dca_path[len] = '\0';
199
200 mdirp = dircmp_rcs_opendir(dca, len);
201 if (mdirp == NULL) {
202 list_destroy(lp);
203 return (false);
204 }
205 mdirp->m_parent_pathlen = dca->dca_pathlen;
206 dca->dca_pathlen = len;
207 }
208 fetched = false;
209 } else if (rv < 0) {
210 if (!dircmp_rcs_add(dca, mdp)) {
211 mclosedir(mdirp);
212 list_destroy(lp);
213 return (false);
214 }
215 mdirp->m_offset++;
216 } else { /* rv > 0 */
217 if (!dircmp_rcs_remove(dca)) {
218 mclosedir(mdirp);
219 list_destroy(lp);
220 return (false);
221 }
222 fetched = false;
223 }
224 }
225
226 for (;;) {
227 while (mdirp->m_offset < mdirp->m_nentries) {
228 entries = mdirp->m_entries;
229 mdp = &entries[mdirp->m_offset++];
230 if (!dircmp_access(dca, mdp))
231 continue;
232
233 if (!dircmp_rcs_add(dca, mdp)) {
234 mclosedir(mdirp);
235 list_destroy(lp);
236 return (false);
237 }
238 }
239 mclosedir(mdirp);
240
241 if (list_isempty(lp))
242 break;
243
244 if ((mdirp = list_remove_tail(lp)) == NULL) {
245 list_destroy(lp);
246 return (false);
247 }
248 }
249
250 list_destroy(lp);
251
252 return (true);
253 }
254
255 bool
dircmp_rcs_fetch(struct dircmp_args * dca)256 dircmp_rcs_fetch(struct dircmp_args *dca)
257 {
258 struct cvsync_attr *cap = &dca->dca_attr;
259 uint8_t *cmd = dca->dca_cmd;
260 size_t len;
261
262 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cmd, 3))
263 return (false);
264 len = GetWord(cmd);
265 if ((len == 0) || (len > dca->dca_cmdmax - 2))
266 return (false);
267 if ((cap->ca_tag = cmd[2]) == DIRCMP_END)
268 return (len == 1);
269 if (cap->ca_tag == DIRCMP_UP) {
270 cap->ca_type = FILETYPE_DIR;
271 return (len == 1);
272 }
273 if (len < 2)
274 return (false);
275
276 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cmd, 1))
277 return (false);
278 cap->ca_namelen = cmd[0];
279
280 switch (cap->ca_tag) {
281 case DIRCMP_DOWN:
282 cap->ca_type = FILETYPE_DIR;
283 if ((cap->ca_namelen == 0) ||
284 (cap->ca_namelen > sizeof(cap->ca_name)) ||
285 (cap->ca_namelen != len - RCS_ATTRLEN_DIR - 2)) {
286 return (false);
287 }
288 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cap->ca_name,
289 cap->ca_namelen)) {
290 return (false);
291 }
292 if (!cvsync_rcs_filename((char *)cap->ca_name,
293 cap->ca_namelen)) {
294 return (false);
295 }
296 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cmd,
297 RCS_ATTRLEN_DIR)) {
298 return (false);
299 }
300 if (!attr_rcs_decode_dir(cmd, RCS_ATTRLEN_DIR, cap))
301 return (false);
302 break;
303 case DIRCMP_FILE:
304 cap->ca_type = FILETYPE_FILE;
305 if ((cap->ca_namelen == 0) ||
306 (cap->ca_namelen > sizeof(cap->ca_name)) ||
307 (cap->ca_namelen != len - RCS_ATTRLEN_FILE - 2)) {
308 return (false);
309 }
310 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cap->ca_name,
311 cap->ca_namelen)) {
312 return (false);
313 }
314 if (!cvsync_rcs_filename((char *)cap->ca_name,
315 cap->ca_namelen)) {
316 return (false);
317 }
318 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cmd,
319 RCS_ATTRLEN_FILE)) {
320 return (false);
321 }
322 if (!attr_rcs_decode_file(cmd, RCS_ATTRLEN_FILE, cap))
323 return (false);
324 break;
325 case DIRCMP_RCS:
326 case DIRCMP_RCS_ATTIC:
327 if (cap->ca_tag == DIRCMP_RCS)
328 cap->ca_type = FILETYPE_RCS;
329 else
330 cap->ca_type = FILETYPE_RCS_ATTIC;
331 if ((cap->ca_namelen == 0) ||
332 (cap->ca_namelen > sizeof(cap->ca_name)) ||
333 (cap->ca_namelen != len - RCS_ATTRLEN_RCS - 2)) {
334 return (false);
335 }
336 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cap->ca_name,
337 cap->ca_namelen)) {
338 return (false);
339 }
340 if (!cvsync_rcs_filename((char *)cap->ca_name,
341 cap->ca_namelen)) {
342 return (false);
343 }
344 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cmd,
345 RCS_ATTRLEN_RCS)) {
346 return (false);
347 }
348 if (!attr_rcs_decode_rcs(cmd, RCS_ATTRLEN_RCS, cap))
349 return (false);
350 break;
351 case DIRCMP_SYMLINK:
352 cap->ca_type = FILETYPE_SYMLINK;
353 if ((cap->ca_namelen == 0) ||
354 (cap->ca_namelen > sizeof(cap->ca_name))) {
355 return (false);
356 }
357 if (len <= cap->ca_namelen + 2)
358 return (false);
359 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cap->ca_name,
360 cap->ca_namelen)) {
361 return (false);
362 }
363 if (!cvsync_rcs_filename((char *)cap->ca_name,
364 cap->ca_namelen)) {
365 return (false);
366 }
367 cap->ca_auxlen = len - cap->ca_namelen - 2;
368 if (cap->ca_auxlen > sizeof(cap->ca_aux))
369 return (false);
370 if (!mux_recv(dca->dca_mux, MUX_DIRCMP_IN, cap->ca_aux,
371 cap->ca_auxlen)) {
372 return (false);
373 }
374 break;
375 default:
376 return (false);
377 }
378
379 return (true);
380 }
381
382 bool
dircmp_rcs_add(struct dircmp_args * dca,struct mdirent_rcs * mdp)383 dircmp_rcs_add(struct dircmp_args *dca, struct mdirent_rcs *mdp)
384 {
385 struct mDIR *mdirp;
386 struct mdirent_rcs *entries;
387 struct list *lp;
388 struct stat *st = &mdp->md_stat;
389 size_t len;
390
391 if (S_ISREG(st->st_mode))
392 return (dircmp_rcs_add_file(dca, mdp));
393 if (S_ISLNK(st->st_mode))
394 return (dircmp_rcs_add_symlink(dca, mdp));
395
396 if (!S_ISDIR(st->st_mode))
397 return (false);
398 if (!dircmp_rcs_add_dir(dca, mdp))
399 return (false);
400
401 if ((lp = list_init()) == NULL)
402 return (false);
403 list_set_destructor(lp, mclosedir);
404
405 len = dca->dca_pathlen + mdp->md_namelen + 1;
406 if (len >= dca->dca_pathmax) {
407 list_destroy(lp);
408 return (false);
409 }
410
411 (void)memcpy(&dca->dca_path[dca->dca_pathlen], mdp->md_name,
412 mdp->md_namelen);
413 dca->dca_path[len - 1] = '/';
414 dca->dca_path[len] = '\0';
415
416 if ((mdirp = dircmp_rcs_opendir(dca, len)) == NULL) {
417 list_destroy(lp);
418 return (false);
419 }
420 mdirp->m_parent_pathlen = dca->dca_pathlen;
421 dca->dca_pathlen = len;
422
423 if (!list_insert_tail(lp, mdirp)) {
424 mclosedir(mdirp);
425 list_destroy(lp);
426 return (false);
427 }
428
429 do {
430 if ((mdirp = list_remove_tail(lp)) == NULL) {
431 list_destroy(lp);
432 return (false);
433 }
434
435 while (mdirp->m_offset < mdirp->m_nentries) {
436 entries = mdirp->m_entries;
437 mdp = &entries[mdirp->m_offset++];
438 if (!dircmp_access(dca, mdp))
439 continue;
440
441 switch (mdp->md_stat.st_mode & S_IFMT) {
442 case S_IFDIR:
443 if (!dircmp_rcs_add_dir(dca, mdp)) {
444 mclosedir(mdirp);
445 list_destroy(lp);
446 return (false);
447 }
448
449 len = dca->dca_pathlen + mdp->md_namelen + 1;
450 if (len >= dca->dca_pathmax) {
451 mclosedir(mdirp);
452 list_destroy(lp);
453 return (false);
454 }
455 (void)memcpy(&dca->dca_path[dca->dca_pathlen],
456 mdp->md_name, mdp->md_namelen);
457 dca->dca_path[len - 1] = '/';
458 dca->dca_path[len] = '\0';
459
460 if (!list_insert_tail(lp, mdirp)) {
461 mclosedir(mdirp);
462 list_destroy(lp);
463 return (false);
464 }
465
466 mdirp = dircmp_rcs_opendir(dca, len);
467 if (mdirp == NULL) {
468 list_destroy(lp);
469 return (false);
470 }
471 mdirp->m_parent_pathlen = dca->dca_pathlen;
472 dca->dca_pathlen = len;
473
474 break;
475 case S_IFREG:
476 if (!dircmp_rcs_add_file(dca, mdp)) {
477 mclosedir(mdirp);
478 list_destroy(lp);
479 return (false);
480 }
481 break;
482 case S_IFLNK:
483 if (!dircmp_rcs_add_symlink(dca, mdp)) {
484 mclosedir(mdirp);
485 list_destroy(lp);
486 return (false);
487 }
488 break;
489 default:
490 mclosedir(mdirp);
491 list_destroy(lp);
492 return (false);
493 }
494 }
495
496 dca->dca_pathlen = mdirp->m_parent_pathlen;
497 dca->dca_path[dca->dca_pathlen] = '\0';
498
499 mclosedir(mdirp);
500 } while (!list_isempty(lp));
501
502 list_destroy(lp);
503
504 return (true);
505 }
506
507 bool
dircmp_rcs_add_dir(struct dircmp_args * dca,struct mdirent_rcs * mdp)508 dircmp_rcs_add_dir(struct dircmp_args *dca, struct mdirent_rcs *mdp)
509 {
510 uint8_t *cmd = dca->dca_cmd;
511 size_t len, rlen;
512
513 if ((len = dca->dca_pathlen + mdp->md_namelen) >= dca->dca_pathmax)
514 return (false);
515 rlen = dca->dca_pathlen - dca->dca_rpathlen;
516 if ((len = rlen + mdp->md_namelen + 6) > dca->dca_cmdmax)
517 return (false);
518
519 SetWord(cmd, len - 2);
520 cmd[2] = FILESCAN_ADD;
521 cmd[3] = FILETYPE_DIR;
522 SetWord(&cmd[4], rlen + mdp->md_namelen);
523 if (!mux_send(dca->dca_mux, MUX_FILESCAN, cmd, 6))
524 return (false);
525 if (!mux_send(dca->dca_mux, MUX_FILESCAN, dca->dca_rpath, rlen))
526 return (false);
527 if (!mux_send(dca->dca_mux, MUX_FILESCAN, mdp->md_name,
528 mdp->md_namelen)) {
529 return (false);
530 }
531
532 return (true);
533 }
534
535 bool
dircmp_rcs_add_file(struct dircmp_args * dca,struct mdirent_rcs * mdp)536 dircmp_rcs_add_file(struct dircmp_args *dca, struct mdirent_rcs *mdp)
537 {
538 uint8_t *cmd = dca->dca_cmd;
539 size_t len, rlen;
540
541 if ((len = dca->dca_pathlen + mdp->md_namelen) >= dca->dca_pathmax)
542 return (false);
543 rlen = dca->dca_pathlen - dca->dca_rpathlen;
544 if ((len = rlen + mdp->md_namelen + 6) > dca->dca_cmdmax)
545 return (false);
546
547 if (IS_FILE_RCS(mdp->md_name, mdp->md_namelen)) {
548 if (mdp->md_attic)
549 cmd[3] = FILETYPE_RCS_ATTIC;
550 else
551 cmd[3] = FILETYPE_RCS;
552 } else {
553 cmd[3] = FILETYPE_FILE;
554 }
555
556 SetWord(cmd, len - 2);
557 cmd[2] = FILESCAN_ADD;
558 SetWord(&cmd[4], rlen + mdp->md_namelen);
559 if (!mux_send(dca->dca_mux, MUX_FILESCAN, cmd, 6))
560 return (false);
561 if (!mux_send(dca->dca_mux, MUX_FILESCAN, dca->dca_rpath, rlen))
562 return (false);
563 if (!mux_send(dca->dca_mux, MUX_FILESCAN, mdp->md_name,
564 mdp->md_namelen)) {
565 return (false);
566 }
567
568 return (true);
569 }
570
571 bool
dircmp_rcs_add_symlink(struct dircmp_args * dca,struct mdirent_rcs * mdp)572 dircmp_rcs_add_symlink(struct dircmp_args *dca, struct mdirent_rcs *mdp)
573 {
574 uint8_t *cmd = dca->dca_cmd;
575 size_t len, rlen;
576
577 if ((len = dca->dca_pathlen + mdp->md_namelen) >= dca->dca_pathmax)
578 return (false);
579 rlen = dca->dca_pathlen - dca->dca_rpathlen;
580 if ((len = rlen + mdp->md_namelen + 6) > dca->dca_cmdmax)
581 return (false);
582
583 SetWord(cmd, len - 2);
584 cmd[2] = FILESCAN_ADD;
585 cmd[3] = FILETYPE_SYMLINK;
586 SetWord(&cmd[4], rlen + mdp->md_namelen);
587 if (!mux_send(dca->dca_mux, MUX_FILESCAN, cmd, 6))
588 return (false);
589 if (!mux_send(dca->dca_mux, MUX_FILESCAN, dca->dca_rpath, rlen))
590 return (false);
591 if (!mux_send(dca->dca_mux, MUX_FILESCAN, mdp->md_name,
592 mdp->md_namelen)) {
593 return (false);
594 }
595
596 return (true);
597 }
598
599 bool
dircmp_rcs_remove(struct dircmp_args * dca)600 dircmp_rcs_remove(struct dircmp_args *dca)
601 {
602 struct cvsync_attr *cap = &dca->dca_attr;
603 size_t len, *plen_stack, c, n;
604
605 if (cap->ca_type != FILETYPE_DIR)
606 return (dircmp_rcs_remove_file(dca));
607
608 n = 4;
609 if ((plen_stack = malloc(n * sizeof(*plen_stack))) == NULL)
610 return (false);
611 plen_stack[0] = dca->dca_pathlen;
612 c = 1;
613
614 len = dca->dca_pathlen + cap->ca_namelen + 1;
615 if (len >= dca->dca_pathmax) {
616 free(plen_stack);
617 return (false);
618 }
619
620 (void)memcpy(&dca->dca_path[dca->dca_pathlen], cap->ca_name,
621 cap->ca_namelen);
622 dca->dca_path[len - 1] = '/';
623 dca->dca_path[len] = '\0';
624 dca->dca_pathlen = len;
625
626 do {
627 if (!dircmp_rcs_fetch(dca)) {
628 free(plen_stack);
629 return (false);
630 }
631
632 switch (cap->ca_tag) {
633 case DIRCMP_END:
634 free(plen_stack);
635 return (false);
636 case DIRCMP_DOWN:
637 if (c == n) {
638 size_t *newp, old = n, new = old * 2;
639
640 newp = malloc(new * sizeof(*newp));
641 if (newp == NULL) {
642 free(plen_stack);
643 return (false);
644 }
645 (void)memcpy(newp, plen_stack,
646 old * sizeof(*newp));
647 (void)memset(&newp[old], 0,
648 (new - old) * sizeof(*newp));
649
650 free(plen_stack);
651 plen_stack = newp;
652 n = new;
653 }
654 plen_stack[c++] = dca->dca_pathlen;
655
656 len = dca->dca_pathlen + cap->ca_namelen + 1;
657 if (len >= dca->dca_pathmax) {
658 free(plen_stack);
659 return (false);
660 }
661
662 (void)memcpy(&dca->dca_path[dca->dca_pathlen],
663 cap->ca_name, cap->ca_namelen);
664 dca->dca_path[len - 1] = '/';
665 dca->dca_path[len] = '\0';
666 dca->dca_pathlen = len;
667
668 break;
669 case DIRCMP_UP:
670 dca->dca_path[dca->dca_pathlen - 1] = '\0';
671
672 if (!dircmp_rcs_remove_dir(dca)) {
673 free(plen_stack);
674 return (false);
675 }
676
677 dca->dca_pathlen = plen_stack[--c];
678 dca->dca_path[dca->dca_pathlen] = '\0';
679
680 break;
681 case DIRCMP_FILE:
682 case DIRCMP_RCS:
683 case DIRCMP_RCS_ATTIC:
684 case DIRCMP_SYMLINK:
685 if (!dircmp_rcs_remove_file(dca)) {
686 free(plen_stack);
687 return (false);
688 }
689 break;
690 default:
691 free(plen_stack);
692 return (false);
693 }
694 } while (c > 0);
695
696 free(plen_stack);
697
698 return (true);
699 }
700
701 bool
dircmp_rcs_remove_dir(struct dircmp_args * dca)702 dircmp_rcs_remove_dir(struct dircmp_args *dca)
703 {
704 uint8_t *cmd = dca->dca_cmd;
705 size_t len, rlen;
706
707 rlen = dca->dca_pathlen - dca->dca_rpathlen - 1;
708 if ((len = rlen + 6) > dca->dca_cmdmax)
709 return (false);
710
711 SetWord(cmd, len - 2);
712 cmd[2] = FILESCAN_REMOVE;
713 cmd[3] = FILETYPE_DIR;
714 SetWord(&cmd[4], rlen);
715 if (!mux_send(dca->dca_mux, MUX_FILESCAN, cmd, 6))
716 return (false);
717 if (!mux_send(dca->dca_mux, MUX_FILESCAN, dca->dca_rpath, rlen))
718 return (false);
719
720 return (true);
721 }
722
723 bool
dircmp_rcs_remove_file(struct dircmp_args * dca)724 dircmp_rcs_remove_file(struct dircmp_args *dca)
725 {
726 struct cvsync_attr *cap = &dca->dca_attr;
727 uint8_t *cmd = dca->dca_cmd;
728 size_t len, rlen;
729
730 if ((len = dca->dca_pathlen + cap->ca_namelen) >= dca->dca_pathmax)
731 return (false);
732 rlen = dca->dca_pathlen - dca->dca_rpathlen;
733 if ((len = rlen + cap->ca_namelen + 6) > dca->dca_cmdmax)
734 return (false);
735
736 SetWord(cmd, len - 2);
737 cmd[2] = FILESCAN_REMOVE;
738 cmd[3] = cap->ca_type;
739 SetWord(&cmd[4], rlen + cap->ca_namelen);
740 if (!mux_send(dca->dca_mux, MUX_FILESCAN, cmd, 6))
741 return (false);
742 if (!mux_send(dca->dca_mux, MUX_FILESCAN, dca->dca_rpath, rlen))
743 return (false);
744 if (!mux_send(dca->dca_mux, MUX_FILESCAN, cap->ca_name,
745 cap->ca_namelen)) {
746 return (false);
747 }
748
749 return (true);
750 }
751
752 bool
dircmp_rcs_replace(struct dircmp_args * dca,struct mdirent_rcs * mdp)753 dircmp_rcs_replace(struct dircmp_args *dca, struct mdirent_rcs *mdp)
754 {
755 switch (mdp->md_stat.st_mode & S_IFMT) {
756 case S_IFDIR:
757 case S_IFREG:
758 case S_IFLNK:
759 if (!dircmp_rcs_remove(dca))
760 return (false);
761 if (!dircmp_rcs_add(dca, mdp))
762 return (false);
763 break;
764 default:
765 return (false);
766 }
767
768 return (true);
769 }
770
771 bool
dircmp_rcs_update(struct dircmp_args * dca,struct mdirent_rcs * mdp)772 dircmp_rcs_update(struct dircmp_args *dca, struct mdirent_rcs *mdp)
773 {
774 struct cvsync_attr *cap = &dca->dca_attr;
775 struct stat *st = &mdp->md_stat;
776 uint16_t mode = RCS_MODE(st->st_mode, dca->dca_collection->cl_umask);
777 uint8_t *cmd = dca->dca_cmd;
778 size_t base, len, rlen;
779 int wn;
780
781 if ((len = dca->dca_pathlen + mdp->md_namelen) >= dca->dca_pathmax)
782 return (false);
783 rlen = dca->dca_pathlen - dca->dca_rpathlen;
784 if ((base = rlen + mdp->md_namelen + 6) > dca->dca_cmdmax)
785 return (false);
786
787 len = dca->dca_cmdmax - base;
788
789 switch (st->st_mode & S_IFMT) {
790 case S_IFDIR:
791 if (cap->ca_type != FILETYPE_DIR)
792 return (dircmp_rcs_replace(dca, mdp));
793 if (mode == cap->ca_mode)
794 return (true);
795 cmd[2] = FILESCAN_SETATTR;
796 cmd[3] = FILETYPE_DIR;
797 if ((len = attr_rcs_encode_dir(&cmd[6], len, mode)) == 0)
798 return (false);
799 break;
800 case S_IFREG:
801 if (IS_FILE_RCS(mdp->md_name, mdp->md_namelen)) {
802 if ((cap->ca_type != FILETYPE_RCS) &&
803 (cap->ca_type != FILETYPE_RCS_ATTIC)) {
804 return (dircmp_rcs_replace(dca, mdp));
805 }
806 if (mdp->md_attic)
807 cmd[3] = FILETYPE_RCS_ATTIC;
808 else
809 cmd[3] = FILETYPE_RCS;
810 if ((cmd[3] == cap->ca_type) &&
811 ((int64_t)st->st_mtime == cap->ca_mtime) &&
812 (mode == cap->ca_mode)) {
813 return (true);
814 }
815 if (cap->ca_type != cmd[3]) {
816 cmd[2] = FILESCAN_RCS_ATTIC;
817 } else {
818 if ((int64_t)st->st_mtime != cap->ca_mtime)
819 cmd[2] = FILESCAN_UPDATE;
820 else
821 cmd[2] = FILESCAN_SETATTR;
822 }
823 if ((len = attr_rcs_encode_rcs(&cmd[6], len,
824 st->st_mtime,
825 mode)) == 0) {
826 return (false);
827 }
828 } else {
829 if (cap->ca_type != FILETYPE_FILE)
830 return (dircmp_rcs_replace(dca, mdp));
831 if (((int64_t)st->st_mtime == cap->ca_mtime) &&
832 ((uint64_t)st->st_size == cap->ca_size) &&
833 (mode == cap->ca_mode)) {
834 return (true);
835 }
836 if (((int64_t)st->st_mtime != cap->ca_mtime) ||
837 ((uint64_t)st->st_size != cap->ca_size)) {
838 if (st->st_size == 0)
839 return (dircmp_rcs_replace(dca, mdp));
840
841 cmd[2] = FILESCAN_UPDATE;
842 } else {
843 cmd[2] = FILESCAN_SETATTR;
844 }
845 cmd[3] = FILETYPE_FILE;
846 if ((len = attr_rcs_encode_file(&cmd[6], len,
847 st->st_mtime,
848 st->st_size,
849 mode)) == 0) {
850 return (false);
851 }
852 }
853 break;
854 case S_IFLNK:
855 if (cap->ca_type != FILETYPE_SYMLINK)
856 return (dircmp_rcs_replace(dca, mdp));
857 (void)memcpy(&dca->dca_path[dca->dca_pathlen], mdp->md_name,
858 mdp->md_namelen);
859 dca->dca_path[dca->dca_pathlen + mdp->md_namelen] = '\0';
860 if ((wn = readlink(dca->dca_path, dca->dca_symlink,
861 dca->dca_pathmax)) == -1) {
862 return (false);
863 }
864 len = (size_t)wn;
865 if ((len == cap->ca_auxlen) &&
866 (memcmp(cap->ca_aux, dca->dca_symlink, len) == 0)) {
867 return (true);
868 }
869 cmd[2] = FILESCAN_UPDATE;
870 cmd[3] = FILETYPE_SYMLINK;
871 len = 0;
872 break;
873 default:
874 return (false);
875 }
876
877 SetWord(cmd, len + base - 2);
878 SetWord(&cmd[4], rlen + mdp->md_namelen);
879 if (!mux_send(dca->dca_mux, MUX_FILESCAN, cmd, 6))
880 return (false);
881 if (!mux_send(dca->dca_mux, MUX_FILESCAN, dca->dca_rpath, rlen))
882 return (false);
883 if (!mux_send(dca->dca_mux, MUX_FILESCAN, mdp->md_name,
884 mdp->md_namelen)) {
885 return (false);
886 }
887 if (len > 0) {
888 if (!mux_send(dca->dca_mux, MUX_FILESCAN, &cmd[6], len))
889 return (false);
890 }
891
892 return (true);
893 }
894
895 struct mDIR *
dircmp_rcs_opendir(struct dircmp_args * dca,size_t pathlen)896 dircmp_rcs_opendir(struct dircmp_args *dca, size_t pathlen)
897 {
898 struct mDIR *mdirp;
899 struct mdirent_rcs *mdp;
900 struct mdirent_args mda;
901 struct collection *cl = dca->dca_collection;
902 size_t rpathlen = pathlen - (dca->dca_rpath - dca->dca_path), len;
903 int rv;
904
905 mda.mda_errormode = cl->cl_errormode;
906 mda.mda_symfollow = cl->cl_symfollow;
907 mda.mda_remove = false;
908
909 if (rpathlen >= cl->cl_rprefixlen) {
910 if ((mdirp = mopendir_rcs(dca->dca_path, pathlen,
911 dca->dca_pathmax, &mda)) == NULL) {
912 return (NULL);
913 }
914
915 return (mdirp);
916 }
917
918 if ((mdp = malloc(sizeof(*mdp))) == NULL)
919 return (NULL);
920
921 for (len = rpathlen ; len < cl->cl_rprefixlen ; len++) {
922 if (cl->cl_rprefix[len] == '/')
923 break;
924 }
925 if ((len -= rpathlen) >= sizeof(mdp->md_name)) {
926 free(mdp);
927 return (NULL);
928 }
929 (void)memcpy(mdp->md_name, &cl->cl_rprefix[rpathlen], len);
930 mdp->md_namelen = len;
931 mdp->md_attic = false;
932 mdp->md_dead = false;
933
934 len = cl->cl_prefixlen + rpathlen + mdp->md_namelen;
935 if (len >= dca->dca_pathmax) {
936 free(mdp);
937 return (NULL);
938 }
939 (void)memcpy(&dca->dca_path[cl->cl_prefixlen], cl->cl_rprefix,
940 rpathlen + mdp->md_namelen);
941 dca->dca_path[len] = '\0';
942
943 if (cl->cl_symfollow)
944 rv = stat(dca->dca_path, &mdp->md_stat);
945 else
946 rv = lstat(dca->dca_path, &mdp->md_stat);
947 if (rv == -1) {
948 free(mdp);
949 return (NULL);
950 }
951 if (!S_ISDIR(mdp->md_stat.st_mode)) {
952 free(mdp);
953 return (NULL);
954 }
955
956 if ((mdirp = malloc(sizeof(*mdirp))) == NULL) {
957 free(mdp);
958 return (NULL);
959 }
960 mdirp->m_entries = mdp;
961 mdirp->m_nentries = 1;
962 mdirp->m_offset = 0;
963 mdirp->m_parent = NULL;
964 mdirp->m_parent_pathlen = 0;
965
966 return (mdirp);
967 }
968