1 /*
2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3 *
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5 * and others.
6 *
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
9 *
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
12 *
13 * "update" updates the version in the present directory with respect to the RCS
14 * repository. The present version must have been created by "checkout". The
15 * user can keep up-to-date by calling "update" whenever he feels like it.
16 *
17 * The present version can be committed by "commit", but this keeps the version
18 * in tact.
19 *
20 * Arguments following the options are taken to be file names to be updated,
21 * rather than updating the entire directory.
22 *
23 * Modified or non-existent RCS files are checked out and reported as U
24 * <user_file>
25 *
26 * Modified user files are reported as M <user_file>. If both the RCS file and
27 * the user file have been modified, the user file is replaced by the result
28 * of rcsmerge, and a backup file is written for the user in .#file.version.
29 * If this throws up irreconcilable differences, the file is reported as C
30 * <user_file>, and as M <user_file> otherwise.
31 *
32 * Files added but not yet committed are reported as A <user_file>. Files
33 * removed but not yet committed are reported as R <user_file>.
34 *
35 * If the current directory contains subdirectories that hold concurrent
36 * versions, these are updated too. If the -d option was specified, new
37 * directories added to the repository are automatically created and updated
38 * as well.
39 */
40 #include <sys/cdefs.h>
41 __RCSID("$NetBSD: update.c,v 1.12 2017/09/15 21:03:26 christos Exp $");
42
43 #include "cvs.h"
44 #include <assert.h>
45 #include "save-cwd.h"
46 #ifdef SERVER_SUPPORT
47 # include "md5.h"
48 #endif
49 #include "watch.h"
50 #include "fileattr.h"
51 #include "edit.h"
52 #include "getline.h"
53 #include "buffer.h"
54 #include "hardlink.h"
55
56 static int checkout_file (struct file_info *finfo, Vers_TS *vers_ts,
57 int adding, int merging, int update_server);
58 #ifdef SERVER_SUPPORT
59 static void checkout_to_buffer (void *, const char *, size_t);
60 static int patch_file (struct file_info *finfo,
61 Vers_TS *vers_ts,
62 int *docheckout, struct stat *file_info,
63 unsigned char *checksum);
64 static void patch_file_write (void *, const char *, size_t);
65 #endif
66 static int merge_file (struct file_info *finfo, Vers_TS *vers);
67 static int scratch_file (struct file_info *finfo, Vers_TS *vers);
68 static Dtype update_dirent_proc (void *callerdat, const char *dir,
69 const char *repository,
70 const char *update_dir,
71 List *entries);
72 static int update_dirleave_proc (void *callerdat, const char *dir,
73 int err, const char *update_dir,
74 List *entries);
75 static int update_fileproc (void *callerdat, struct file_info *);
76 static int update_filesdone_proc (void *callerdat, int err,
77 const char *repository,
78 const char *update_dir, List *entries);
79 #ifdef PRESERVE_PERMISSIONS_SUPPORT
80 static int get_linkinfo_proc( void *_callerdat, struct _finfo * );
81 #endif
82 static void join_file (struct file_info *finfo, Vers_TS *vers_ts);
83
84 static char *options = NULL;
85 static char *tag = NULL;
86 static char *date = NULL;
87 /* This is a bit of a kludge. We call WriteTag at the beginning
88 before we know whether nonbranch is set or not. And then at the
89 end, once we have the right value for nonbranch, we call WriteTag
90 again. I don't know whether the first call is necessary or not.
91 rewrite_tag is nonzero if we are going to have to make that second
92 call. warned is nonzero if we've already warned the user that the
93 tag occurs as both a revision tag and a branch tag. */
94 static int rewrite_tag;
95 static int nonbranch;
96 static int warned;
97
98 /* If we set the tag or date for a subdirectory, we use this to undo
99 the setting. See update_dirent_proc. */
100 static char *tag_update_dir;
101
102 static char *join_rev1, *join_date1;
103 static char *join_rev2, *join_date2;
104 static int aflag = 0;
105 static int toss_local_changes = 0;
106 static int force_tag_match = 1;
107 static int update_build_dirs = 0;
108 static int update_prune_dirs = 0;
109 static int preserve_timestamps_on_update = 0;
110 static int pipeout = 0;
111 static int dotemplate = 0;
112 #ifdef SERVER_SUPPORT
113 static int patches = 0;
114 static int rcs_diff_patches = 0;
115 #endif
116 static List *ignlist = NULL;
117 static time_t last_register_time;
118 static const char *const update_usage[] =
119 {
120 "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n",
121 " [-I ign] [-W spec] [files...]\n",
122 "\t-A\tReset any sticky tags/date/kopts.\n",
123 "\t-P\tPrune empty directories.\n",
124 "\t-C\tOverwrite locally modified files with clean repository copies.\n",
125 "\t-d\tBuild directories, like checkout does.\n",
126 "\t-f\tForce a head revision match if tag/date not found.\n",
127 "\t-l\tLocal directory only, no recursion.\n",
128 "\t-R\tProcess directories recursively.\n",
129 "\t-p\tSend updates to standard output (avoids stickiness).\n",
130 "\t-t\tPreserve timestamps on update.\n",
131 "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n",
132 "\t-r rev\tUpdate using specified revision/tag (is sticky).\n",
133 "\t-D date\tSet date to update from (is sticky).\n",
134 "\t-j rev\tMerge in changes made between current revision and rev.\n",
135 "\t-I ign\tMore files to ignore (! to reset).\n",
136 "\t-W spec\tWrappers specification line.\n",
137 "(Specify the --help global option for a list of other help options)\n",
138 NULL
139 };
140
141
142
143 /*
144 * update is the argv,argc based front end for arg parsing
145 */
146 int
update(int argc,char ** argv)147 update (int argc, char **argv)
148 {
149 int c, err;
150 int local = 0; /* recursive by default */
151 int which; /* where to look for files and dirs */
152 char *xjoin_rev1, *xjoin_date1,
153 *xjoin_rev2, *xjoin_date2,
154 *join_orig1, *join_orig2;
155
156 if (argc == -1)
157 usage (update_usage);
158
159 xjoin_rev1 = xjoin_date1 = xjoin_rev2 = xjoin_date2 = join_orig1 =
160 join_orig2 = NULL;
161
162 ign_setup ();
163 wrap_setup ();
164
165 /* parse the args */
166 getoptreset ();
167 while ((c = getopt (argc, argv, "+ApCPflRQqduk:r:tD:j:I:W:")) != -1)
168 {
169 switch (c)
170 {
171 case 'A':
172 aflag = 1;
173 break;
174 case 'C':
175 toss_local_changes = 1;
176 break;
177 case 'I':
178 ign_add (optarg, 0);
179 break;
180 case 'W':
181 wrap_add (optarg, 0);
182 break;
183 case 'k':
184 if (options)
185 free (options);
186 options = RCS_check_kflag (optarg);
187 break;
188 case 'l':
189 local = 1;
190 break;
191 case 'R':
192 local = 0;
193 break;
194 case 'Q':
195 case 'q':
196 /* The CVS 1.5 client sends these options (in addition to
197 Global_option requests), so we must ignore them. */
198 if (!server_active)
199 error (1, 0,
200 "-q or -Q must be specified before \"%s\"",
201 cvs_cmd_name);
202 break;
203 case 'd':
204 update_build_dirs = 1;
205 break;
206 case 'f':
207 force_tag_match = 0;
208 break;
209 case 'r':
210 parse_tagdate (&tag, &date, optarg);
211 break;
212 case 'D':
213 if (date) free (date);
214 date = Make_Date (optarg);
215 break;
216 case 'P':
217 update_prune_dirs = 1;
218 break;
219 case 'p':
220 pipeout = 1;
221 noexec = 1; /* so no locks will be created */
222 break;
223 case 't':
224 preserve_timestamps_on_update = 1;
225 break;
226 case 'j':
227 if (join_orig2)
228 error (1, 0, "only two -j options can be specified");
229 if (join_orig1)
230 {
231 join_orig2 = xstrdup (optarg);
232 parse_tagdate (&xjoin_rev2, &xjoin_date2, optarg);
233 }
234 else
235 {
236 join_orig1 = xstrdup (optarg);
237 parse_tagdate (&xjoin_rev1, &xjoin_date1, optarg);
238 }
239 break;
240 case 'u':
241 #ifdef SERVER_SUPPORT
242 if (server_active)
243 {
244 patches = 1;
245 rcs_diff_patches = server_use_rcs_diff ();
246 }
247 else
248 #endif
249 usage (update_usage);
250 break;
251 case '?':
252 default:
253 usage (update_usage);
254 break;
255 }
256 }
257 argc -= optind;
258 argv += optind;
259
260 #ifdef CLIENT_SUPPORT
261 if (current_parsed_root->isremote)
262 {
263 int pass;
264
265 /* The first pass does the regular update. If we receive at least
266 one patch which failed, we do a second pass and just fetch
267 those files whose patches failed. */
268 pass = 1;
269 do
270 {
271 int status;
272
273 start_server ();
274
275 if (local)
276 send_arg("-l");
277 if (update_build_dirs)
278 send_arg("-d");
279 if (pipeout)
280 send_arg("-p");
281 if (!force_tag_match)
282 send_arg("-f");
283 if (aflag)
284 send_arg("-A");
285 if (toss_local_changes)
286 send_arg("-C");
287 if (update_prune_dirs)
288 send_arg("-P");
289 if (preserve_timestamps_on_update)
290 send_arg("-t");
291 client_prune_dirs = update_prune_dirs;
292 option_with_arg ("-r", tag);
293 if (options && options[0] != '\0')
294 send_arg (options);
295 if (date)
296 client_senddate (date);
297 if (join_orig1)
298 option_with_arg ("-j", join_orig1);
299 if (join_orig2)
300 option_with_arg ("-j", join_orig2);
301 wrap_send ();
302
303 if (failed_patches_count == 0)
304 {
305 unsigned int flags = 0;
306
307 /* If the server supports the command "update-patches", that
308 means that it knows how to handle the -u argument to update,
309 which means to send patches instead of complete files.
310
311 We don't send -u if failed_patches != NULL, so that the
312 server doesn't try to send patches which will just fail
313 again. At least currently, the client also clobbers the
314 file and tells the server it is lost, which also will get
315 a full file instead of a patch, but it seems clean to omit
316 -u. */
317 if (supported_request ("update-patches"))
318 send_arg ("-u");
319
320 send_arg ("--");
321
322 if (update_build_dirs)
323 flags |= SEND_BUILD_DIRS;
324
325 if (toss_local_changes) {
326 flags |= SEND_NO_CONTENTS;
327 flags |= BACKUP_MODIFIED_FILES;
328 }
329
330 /* If noexec, probably could be setting SEND_NO_CONTENTS.
331 Same caveats as for "cvs status" apply. */
332
333 send_files (argc, argv, local, aflag, flags);
334 send_file_names (argc, argv, SEND_EXPAND_WILD);
335 }
336 else
337 {
338 int i;
339
340 (void) printf ("%s client: refetching unpatchable files\n",
341 program_name);
342
343 if (toplevel_wd != NULL
344 && CVS_CHDIR (toplevel_wd) < 0)
345 {
346 error (1, errno, "could not chdir to %s", toplevel_wd);
347 }
348
349 send_arg ("--");
350
351 for (i = 0; i < failed_patches_count; i++)
352 if (unlink_file (failed_patches[i]) < 0
353 && !existence_error (errno))
354 error (0, errno, "cannot remove %s",
355 failed_patches[i]);
356 send_files (failed_patches_count, failed_patches, local,
357 aflag, update_build_dirs ? SEND_BUILD_DIRS : 0);
358 send_file_names (failed_patches_count, failed_patches, 0);
359 free_names (&failed_patches_count, failed_patches);
360 }
361
362 send_to_server ("update\012", 0);
363
364 status = get_responses_and_close ();
365
366 /* If there are any conflicts, the server will return a
367 non-zero exit status. If any patches failed, we still
368 want to run the update again. We use a pass count to
369 avoid an endless loop. */
370
371 /* Notes: (1) assuming that status != 0 implies a
372 potential conflict is the best we can cleanly do given
373 the current protocol. I suppose that trying to
374 re-fetch in cases where there was a more serious error
375 is probably more or less harmless, but it isn't really
376 ideal. (2) it would be nice to have a testsuite case for the
377 conflict-and-patch-failed case. */
378
379 if (status != 0
380 && (failed_patches_count == 0 || pass > 1))
381 {
382 if (failed_patches_count > 0)
383 free_names (&failed_patches_count, failed_patches);
384 return status;
385 }
386
387 ++pass;
388 } while (failed_patches_count > 0);
389
390 return 0;
391 }
392 #endif
393
394 if (tag != NULL)
395 tag_check_valid (tag, argc, argv, local, aflag, "", false);
396 if (join_rev1 != NULL)
397 tag_check_valid (xjoin_rev1, argc, argv, local, aflag, "", false);
398 if (join_rev2 != NULL)
399 tag_check_valid (xjoin_rev2, argc, argv, local, aflag, "", false);
400
401 /*
402 * If we are updating the entire directory (for real) and building dirs
403 * as we go, we make sure there is no static entries file and write the
404 * tag file as appropriate
405 */
406 if (argc <= 0 && !pipeout)
407 {
408 if (update_build_dirs)
409 {
410 if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
411 error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
412 #ifdef SERVER_SUPPORT
413 if (server_active)
414 {
415 char *repos = Name_Repository (NULL, NULL);
416 server_clear_entstat (".", repos);
417 free (repos);
418 }
419 #endif
420 }
421
422 /* keep the CVS/Tag file current with the specified arguments */
423 if (aflag || tag || date)
424 {
425 char *repos = Name_Repository (NULL, NULL);
426 WriteTag (NULL, tag, date, 0, ".", repos);
427 free (repos);
428 rewrite_tag = 1;
429 nonbranch = -1;
430 warned = 0;
431 }
432 }
433
434 /* look for files/dirs locally and in the repository */
435 which = W_LOCAL | W_REPOS;
436
437 /* look in the attic too if a tag or date is specified */
438 if (tag || date || join_orig1)
439 {
440 TRACE (TRACE_DATA, "update: searching attic");
441 which |= W_ATTIC;
442 }
443
444 /* call the command line interface */
445 err = do_update (argc, argv, options, tag, date, force_tag_match,
446 local, update_build_dirs, aflag, update_prune_dirs,
447 pipeout, which, xjoin_rev1, xjoin_date1, xjoin_rev2,
448 xjoin_date2, NULL, 1, NULL);
449
450 /* Free the space allocated for tags and dates, if necessary. */
451 if (tag) free (tag);
452 if (date) free (date);
453
454 return err;
455 }
456
457
458
459 /*
460 * Command line interface to update (used by checkout)
461 *
462 * repository = cvsroot->repository + update_dir. This is necessary for
463 * checkout so that start_recursion can determine our repository. In the
464 * update case, start_recursion can use the CVS/Root & CVS/Repository file
465 * to determine this value.
466 */
467 int
do_update(int argc,char ** argv,char * xoptions,char * xtag,char * xdate,int xforce,int local,int xbuild,int xaflag,int xprune,int xpipeout,int which,char * xjoin_rev1,char * xjoin_date1,char * xjoin_rev2,char * xjoin_date2,char * preload_update_dir,int xdotemplate,char * repository)468 do_update (int argc, char **argv, char *xoptions, char *xtag, char *xdate,
469 int xforce, int local, int xbuild, int xaflag, int xprune,
470 int xpipeout, int which, char *xjoin_rev1, char *xjoin_date1,
471 char *xjoin_rev2, char *xjoin_date2,
472 char *preload_update_dir, int xdotemplate, char *repository)
473 {
474 int err = 0;
475
476 TRACE (TRACE_FUNCTION,
477 "do_update (%s, %s, %s, %d, %d, %d, %d, %d, %d, %d, %s, %s, %s, %s, %s, %d, %s)",
478 xoptions ? xoptions : "(null)", xtag ? xtag : "(null)",
479 xdate ? xdate : "(null)", xforce, local, xbuild, xaflag, xprune,
480 xpipeout, which, xjoin_rev1 ? xjoin_rev1 : "(null)",
481 xjoin_date1 ? xjoin_date1 : "(null)",
482 xjoin_rev2 ? xjoin_rev2 : "(null)",
483 xjoin_date2 ? xjoin_date2 : "(null)",
484 preload_update_dir ? preload_update_dir : "(null)", xdotemplate,
485 repository ? repository : "(null)");
486
487 /* fill in the statics */
488 options = xoptions;
489 tag = xtag;
490 date = xdate;
491 force_tag_match = xforce;
492 update_build_dirs = xbuild;
493 aflag = xaflag;
494 update_prune_dirs = xprune;
495 pipeout = xpipeout;
496 dotemplate = xdotemplate;
497
498 /* setup the join support */
499 join_rev1 = xjoin_rev1;
500 join_date1 = xjoin_date1;
501 join_rev2 = xjoin_rev2;
502 join_date2 = xjoin_date2;
503
504 #ifdef PRESERVE_PERMISSIONS_SUPPORT
505 if (preserve_perms)
506 {
507 /* We need to do an extra recursion, bleah. It's to make sure
508 that we know as much as possible about file linkage. */
509 hardlist = getlist();
510 working_dir = xgetcwd (); /* save top-level working dir */
511
512 /* FIXME-twp: the arguments to start_recursion make me dizzy. This
513 function call was copied from the update_fileproc call that
514 follows it; someone should make sure that I did it right. */
515 err = start_recursion
516 (get_linkinfo_proc, NULL, NULL, NULL, NULL,
517 argc, argv, local, which, aflag, CVS_LOCK_READ,
518 preload_update_dir, 1, NULL);
519 if (err)
520 return err;
521
522 /* FIXME-twp: at this point we should walk the hardlist
523 and update the `links' field of each hardlink_info struct
524 to list the files that are linked on dist. That would make
525 it easier & more efficient to compare the disk linkage with
526 the repository linkage (a simple strcmp). */
527 }
528 #endif
529
530 /* call the recursion processor */
531 err = start_recursion (update_fileproc, update_filesdone_proc,
532 update_dirent_proc, update_dirleave_proc, NULL,
533 argc, argv, local, which, aflag, CVS_LOCK_READ,
534 preload_update_dir, 1, repository);
535
536 /* see if we need to sleep before returning to avoid time-stamp races */
537 if (!server_active && last_register_time)
538 {
539 sleep_past (last_register_time);
540 }
541
542 return err;
543 }
544
545
546
547 #ifdef PRESERVE_PERMISSIONS_SUPPORT
548 /*
549 * The get_linkinfo_proc callback adds each file to the hardlist
550 * (see hardlink.c).
551 */
552
553 static int
get_linkinfo_proc(void * callerdat,struct file_info * finfo)554 get_linkinfo_proc (void *callerdat, struct file_info *finfo)
555 {
556 char *fullpath;
557 Node *linkp;
558 struct hardlink_info *hlinfo;
559
560 /* Get the full pathname of the current file. */
561 fullpath = Xasprintf ("%s/%s", working_dir, finfo->fullname);
562
563 /* To permit recursing into subdirectories, files
564 are keyed on the full pathname and not on the basename. */
565 linkp = lookup_file_by_inode (fullpath);
566 if (linkp == NULL)
567 {
568 /* The file isn't on disk; we are probably restoring
569 a file that was removed. */
570 return 0;
571 }
572
573 /* Create a new, empty hardlink_info node. */
574 hlinfo = xmalloc (sizeof (struct hardlink_info));
575
576 hlinfo->status = (Ctype) 0; /* is this dumb? */
577 hlinfo->checked_out = 0;
578
579 linkp->data = hlinfo;
580
581 return 0;
582 }
583 #endif
584
585
586
587 /*
588 * This is the callback proc for update. It is called for each file in each
589 * directory by the recursion code. The current directory is the local
590 * instantiation. file is the file name we are to operate on. update_dir is
591 * set to the path relative to where we started (for pretty printing).
592 * repository is the repository. entries and srcfiles are the pre-parsed
593 * entries and source control files.
594 *
595 * This routine decides what needs to be done for each file and does the
596 * appropriate magic for checkout
597 */
598 static int
update_fileproc(void * callerdat,struct file_info * finfo)599 update_fileproc (void *callerdat, struct file_info *finfo)
600 {
601 int retval, nb;
602 Ctype status;
603 Vers_TS *vers;
604
605 status = Classify_File (finfo, tag, date, options, force_tag_match,
606 aflag, &vers, pipeout);
607
608 /* cvsacl patch */
609 #ifdef SERVER_SUPPORT
610 if (use_cvs_acl /* && server_active */)
611 {
612 if (!access_allowed (finfo->file, finfo->repository, vers->tag, 5,
613 NULL, NULL, 1))
614 {
615 if (stop_at_first_permission_denied)
616 error (1, 0, "permission denied for %s",
617 Short_Repository (finfo->repository));
618 else
619 error (0, 0, "permission denied for %s/%s",
620 Short_Repository (finfo->repository), finfo->file);
621
622 return (0);
623 }
624 }
625 #endif
626
627 /* Keep track of whether TAG is a branch tag.
628 Note that if it is a branch tag in some files and a nonbranch tag
629 in others, treat it as a nonbranch tag. */
630 if (rewrite_tag
631 && tag != NULL
632 && finfo->rcs != NULL)
633 {
634 char *rev = RCS_getversion (finfo->rcs, tag, NULL, 1, NULL);
635 if (rev != NULL
636 && nonbranch != (nb = !RCS_nodeisbranch (finfo->rcs, tag)))
637 {
638 if (nonbranch >= 0 && !warned && !quiet)
639 {
640 error (0, 0,
641 "warning: %s is a branch tag in some files and a revision tag in others.",
642 tag);
643 warned = 1;
644 }
645 if (nonbranch < nb) nonbranch = nb;
646 }
647 if (rev != NULL)
648 free (rev);
649 }
650
651 if (pipeout)
652 {
653 /*
654 * We just return success without doing anything if any of the really
655 * funky cases occur
656 *
657 * If there is still a valid RCS file, do a regular checkout type
658 * operation
659 */
660 switch (status)
661 {
662 case T_UNKNOWN: /* unknown file was explicitly asked
663 * about */
664 case T_REMOVE_ENTRY: /* needs to be un-registered */
665 case T_ADDED: /* added but not committed */
666 retval = 0;
667 break;
668 case T_CONFLICT: /* old punt-type errors */
669 retval = 1;
670 break;
671 case T_UPTODATE: /* file was already up-to-date */
672 case T_NEEDS_MERGE: /* needs merging */
673 case T_MODIFIED: /* locally modified */
674 case T_REMOVED: /* removed but not committed */
675 case T_CHECKOUT: /* needs checkout */
676 case T_PATCH: /* needs patch */
677 retval = checkout_file (finfo, vers, 0, 0, 0);
678 break;
679
680 default: /* can't ever happen :-) */
681 error (0, 0,
682 "unknown file status %d for file %s", status, finfo->file);
683 retval = 0;
684 break;
685 }
686 }
687 else
688 {
689 switch (status)
690 {
691 case T_UNKNOWN: /* unknown file was explicitly asked
692 * about */
693 case T_UPTODATE: /* file was already up-to-date */
694 retval = 0;
695 break;
696 case T_CONFLICT: /* old punt-type errors */
697 retval = 1;
698 write_letter (finfo, 'C');
699 break;
700 case T_NEEDS_MERGE: /* needs merging */
701 if (! toss_local_changes)
702 {
703 retval = merge_file (finfo, vers);
704 break;
705 }
706 /* else FALL THROUGH */
707 case T_MODIFIED: /* locally modified */
708 retval = 0;
709 if (toss_local_changes)
710 {
711 char *bakname;
712 bakname = backup_file (finfo->file, vers->vn_user);
713 /* This behavior is sufficiently unexpected to
714 justify overinformativeness, I think. */
715 if (!really_quiet && !server_active)
716 (void) printf ("(Locally modified %s moved to %s)\n",
717 finfo->file, bakname);
718 free (bakname);
719
720 /* The locally modified file is still present, but
721 it will be overwritten by the repository copy
722 after this. */
723 status = T_CHECKOUT;
724 retval = checkout_file (finfo, vers, 0, 0, 1);
725 }
726 else
727 {
728 if (vers->ts_conflict)
729 {
730 if (file_has_markers (finfo))
731 {
732 write_letter (finfo, 'C');
733 retval = 1;
734 }
735 else
736 {
737 /* Reregister to clear conflict flag. */
738 Register (finfo->entries, finfo->file,
739 vers->vn_rcs, vers->ts_rcs,
740 vers->options, vers->tag,
741 vers->date, NULL);
742 }
743 }
744 if (!retval)
745 write_letter (finfo, 'M');
746 }
747 break;
748 case T_PATCH: /* needs patch */
749 #ifdef SERVER_SUPPORT
750 if (patches)
751 {
752 int docheckout;
753 struct stat file_info;
754 unsigned char checksum[16];
755
756 retval = patch_file (finfo,
757 vers, &docheckout,
758 &file_info, checksum);
759 if (! docheckout)
760 {
761 if (server_active && retval == 0)
762 server_updated (finfo, vers,
763 (rcs_diff_patches
764 ? SERVER_RCS_DIFF
765 : SERVER_PATCHED),
766 file_info.st_mode, checksum,
767 NULL);
768 break;
769 }
770 }
771 #endif
772 /* If we're not running as a server, just check the
773 file out. It's simpler and faster than producing
774 and applying patches. */
775 /* Fall through. */
776 case T_CHECKOUT: /* needs checkout */
777 retval = checkout_file (finfo, vers, 0, 0, 1);
778 break;
779 case T_ADDED: /* added but not committed */
780 write_letter (finfo, 'A');
781 retval = 0;
782 break;
783 case T_REMOVED: /* removed but not committed */
784 write_letter (finfo, 'R');
785 retval = 0;
786 break;
787 case T_REMOVE_ENTRY: /* needs to be un-registered */
788 retval = scratch_file (finfo, vers);
789 break;
790 default: /* can't ever happen :-) */
791 error (0, 0,
792 "unknown file status %d for file %s", status, finfo->file);
793 retval = 0;
794 break;
795 }
796 }
797
798 /* only try to join if things have gone well thus far */
799 if (retval == 0 && join_rev1)
800 join_file (finfo, vers);
801
802 /* if this directory has an ignore list, add this file to it */
803 if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL))
804 {
805 Node *p;
806
807 p = getnode ();
808 p->type = FILES;
809 p->key = xstrdup (finfo->file);
810 if (addnode (ignlist, p) != 0)
811 freenode (p);
812 }
813
814 freevers_ts (&vers);
815 return retval;
816 }
817
818
819
820 static void
update_ignproc(const char * file,const char * dir)821 update_ignproc (const char *file, const char *dir)
822 {
823 struct file_info finfo;
824 char *tmp;
825
826 memset (&finfo, 0, sizeof (finfo));
827 finfo.file = file;
828 finfo.update_dir = dir;
829
830 finfo.fullname = tmp = Xasprintf ("%s%s%s",
831 dir[0] == '\0' ? "" : dir,
832 dir[0] == '\0' ? "" : "/",
833 file);
834 write_letter (&finfo, '?');
835 free (tmp);
836 }
837
838
839
840 /* ARGSUSED */
841 static int
update_filesdone_proc(void * callerdat,int err,const char * repository,const char * update_dir,List * entries)842 update_filesdone_proc (void *callerdat, int err, const char *repository,
843 const char *update_dir, List *entries)
844 {
845 if (nonbranch < 0) nonbranch = 0;
846 if (rewrite_tag)
847 {
848 WriteTag (NULL, tag, date, nonbranch, update_dir, repository);
849 rewrite_tag = 0;
850 }
851
852 /* if this directory has an ignore list, process it then free it */
853 if (ignlist)
854 {
855 ignore_files (ignlist, entries, update_dir, update_ignproc);
856 dellist (&ignlist);
857 }
858
859 /* Clean up CVS admin dirs if we are export */
860 if (strcmp (cvs_cmd_name, "export") == 0)
861 {
862 /* I'm not sure the existence_error is actually possible (except
863 in cases where we really should print a message), but since
864 this code used to ignore all errors, I'll play it safe. */
865 if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
866 error (0, errno, "cannot remove %s directory", CVSADM);
867 }
868 else if (!server_active && !pipeout)
869 {
870 /* If there is no CVS/Root file, add one */
871 if (!isfile (CVSADM_ROOT))
872 Create_Root (NULL, original_parsed_root->original);
873 }
874
875 return err;
876 }
877
878
879
880 /*
881 * update_dirent_proc () is called back by the recursion processor before a
882 * sub-directory is processed for update. In this case, update_dirent proc
883 * will probably create the directory unless -d isn't specified and this is a
884 * new directory. A return code of 0 indicates the directory should be
885 * processed by the recursion code. A return of non-zero indicates the
886 * recursion code should skip this directory.
887 */
888 static Dtype
update_dirent_proc(void * callerdat,const char * dir,const char * repository,const char * update_dir,List * entries)889 update_dirent_proc (void *callerdat, const char *dir, const char *repository,
890 const char *update_dir, List *entries)
891 {
892 if (ignore_directory (update_dir))
893 {
894 /* print the warm fuzzy message */
895 if (!quiet)
896 error (0, 0, "Ignoring %s", update_dir);
897 return R_SKIP_ALL;
898 }
899
900 if (!isdir (dir))
901 {
902 /* if we aren't building dirs, blow it off */
903 if (!update_build_dirs)
904 return R_SKIP_ALL;
905
906 /* Various CVS administrators are in the habit of removing
907 the repository directory for things they don't want any
908 more. I've even been known to do it myself (on rare
909 occasions). Not the usual recommended practice, but we
910 want to try to come up with some kind of
911 reasonable/documented/sensible behavior. Generally
912 the behavior is to just skip over that directory (see
913 dirs test in sanity.sh; the case which reaches here
914 is when update -d is specified, and the working directory
915 is gone but the subdirectory is still mentioned in
916 CVS/Entries). */
917 /* In the remote case, the client should refrain from
918 sending us the directory in the first place. So we
919 want to continue to give an error, so clients make
920 sure to do this. */
921 if (!server_active && !isdir (repository))
922 return R_SKIP_ALL;
923
924 if (noexec)
925 {
926 /* ignore the missing dir if -n is specified */
927 error (0, 0, "New directory `%s' -- ignored", update_dir);
928 return R_SKIP_ALL;
929 }
930 else
931 {
932 /* otherwise, create the dir and appropriate adm files */
933
934 /* If no tag or date were specified on the command line,
935 and we're not using -A, we want the subdirectory to use
936 the tag and date, if any, of the current directory.
937 That way, update -d will work correctly when working on
938 a branch.
939
940 We use TAG_UPDATE_DIR to undo the tag setting in
941 update_dirleave_proc. If we did not do this, we would
942 not correctly handle a working directory with multiple
943 tags (and maybe we should prohibit such working
944 directories, but they work now and we shouldn't make
945 them stop working without more thought). */
946 if ((tag == NULL && date == NULL) && ! aflag)
947 {
948 ParseTag (&tag, &date, &nonbranch);
949 if (tag != NULL || date != NULL)
950 tag_update_dir = xstrdup (update_dir);
951 }
952
953 make_directory (dir);
954 Create_Admin (dir, update_dir, repository, tag, date,
955 /* This is a guess. We will rewrite it later
956 via WriteTag. */
957 0,
958 0,
959 dotemplate);
960 rewrite_tag = 1;
961 nonbranch = -1;
962 warned = 0;
963 Subdir_Register (entries, NULL, dir);
964 }
965 }
966 /* Do we need to check noexec here? */
967 else if (!pipeout)
968 {
969 char *cvsadmdir;
970
971 /* The directory exists. Check to see if it has a CVS
972 subdirectory. */
973
974 cvsadmdir = Xasprintf ("%s/%s", dir, CVSADM);
975
976 if (!isdir (cvsadmdir))
977 {
978 /* We cannot successfully recurse into a directory without a CVS
979 subdirectory. Generally we will have already printed
980 "? foo". */
981 free (cvsadmdir);
982 return R_SKIP_ALL;
983 }
984 free (cvsadmdir);
985 }
986
987 /*
988 * If we are building dirs and not going to stdout, we make sure there is
989 * no static entries file and write the tag file as appropriate
990 */
991 if (!pipeout)
992 {
993 if (update_build_dirs)
994 {
995 char *tmp = Xasprintf ("%s/%s", dir, CVSADM_ENTSTAT);
996
997 if (unlink_file (tmp) < 0 && ! existence_error (errno))
998 error (1, errno, "cannot remove file %s", tmp);
999 #ifdef SERVER_SUPPORT
1000 if (server_active)
1001 server_clear_entstat (update_dir, repository);
1002 #endif
1003 free (tmp);
1004 }
1005
1006 /* keep the CVS/Tag file current with the specified arguments */
1007 if (aflag || tag || date)
1008 {
1009 WriteTag (dir, tag, date, 0, update_dir, repository);
1010 rewrite_tag = 1;
1011 nonbranch = -1;
1012 warned = 0;
1013 }
1014
1015 WriteTemplate (update_dir, dotemplate, repository);
1016
1017 /* initialize the ignore list for this directory */
1018 ignlist = getlist ();
1019 }
1020
1021 /* print the warm fuzzy message */
1022 if (!quiet)
1023 error (0, 0, "Updating %s", update_dir);
1024
1025 return R_PROCESS;
1026 }
1027
1028
1029
1030 /*
1031 * update_dirleave_proc () is called back by the recursion code upon leaving
1032 * a directory. It will prune empty directories if needed and will execute
1033 * any appropriate update programs.
1034 */
1035 /* ARGSUSED */
1036 static int
update_dirleave_proc(void * callerdat,const char * dir,int err,const char * update_dir,List * entries)1037 update_dirleave_proc (void *callerdat, const char *dir, int err,
1038 const char *update_dir, List *entries)
1039 {
1040 /* Delete the ignore list if it hasn't already been done. */
1041 if (ignlist)
1042 dellist (&ignlist);
1043
1044 /* If we set the tag or date for a new subdirectory in
1045 update_dirent_proc, and we're now done with that subdirectory,
1046 undo the tag/date setting. Note that we know that the tag and
1047 date were both originally NULL in this case. */
1048 if (tag_update_dir != NULL && strcmp (update_dir, tag_update_dir) == 0)
1049 {
1050 if (tag != NULL)
1051 {
1052 free (tag);
1053 tag = NULL;
1054 }
1055 if (date != NULL)
1056 {
1057 free (date);
1058 date = NULL;
1059 }
1060 nonbranch = -1;
1061 warned = 0;
1062 free (tag_update_dir);
1063 tag_update_dir = NULL;
1064 }
1065
1066 if (strchr (dir, '/') == NULL)
1067 {
1068 /* FIXME: chdir ("..") loses with symlinks. */
1069 /* Prune empty dirs on the way out - if necessary */
1070 if (CVS_CHDIR ("..") == -1)
1071 error (0, errno, "Cannot chdir to ..");
1072 if (update_prune_dirs && isemptydir (dir, 0))
1073 {
1074 /* I'm not sure the existence_error is actually possible (except
1075 in cases where we really should print a message), but since
1076 this code used to ignore all errors, I'll play it safe. */
1077 if (unlink_file_dir (dir) < 0 && !existence_error (errno))
1078 error (0, errno, "cannot remove %s directory", dir);
1079 Subdir_Deregister (entries, NULL, dir);
1080 }
1081 }
1082
1083 return err;
1084 }
1085
1086
1087
1088 /* Returns 1 if the file indicated by node has been removed. */
1089 static int
isremoved(Node * node,void * closure)1090 isremoved (Node *node, void *closure)
1091 {
1092 Entnode *entdata = node->data;
1093
1094 /* If the first character of the version is a '-', the file has been
1095 removed. */
1096 return (entdata->version && entdata->version[0] == '-') ? 1 : 0;
1097 }
1098
1099
1100
1101 /* Returns 1 if the argument directory is completely empty, other than the
1102 existence of the CVS directory entry. Zero otherwise. If MIGHT_NOT_EXIST
1103 and the directory doesn't exist, then just return 0. */
1104 int
isemptydir(const char * dir,int might_not_exist)1105 isemptydir (const char *dir, int might_not_exist)
1106 {
1107 DIR *dirp;
1108 struct dirent *dp;
1109
1110 if ((dirp = CVS_OPENDIR (dir)) == NULL)
1111 {
1112 if (might_not_exist && existence_error (errno))
1113 return 0;
1114 error (0, errno, "cannot open directory %s for empty check", dir);
1115 return 0;
1116 }
1117 errno = 0;
1118 while ((dp = CVS_READDIR (dirp)) != NULL)
1119 {
1120 if (strcmp (dp->d_name, ".") != 0
1121 && strcmp (dp->d_name, "..") != 0)
1122 {
1123 if (strcmp (dp->d_name, CVSADM) != 0)
1124 {
1125 /* An entry other than the CVS directory. The directory
1126 is certainly not empty. */
1127 (void) CVS_CLOSEDIR (dirp);
1128 return 0;
1129 }
1130 else
1131 {
1132 /* The CVS directory entry. We don't have to worry about
1133 this unless the Entries file indicates that files have
1134 been removed, but not committed, in this directory.
1135 (Removing the directory would prevent people from
1136 comitting the fact that they removed the files!) */
1137 List *l;
1138 int files_removed;
1139 struct saved_cwd cwd;
1140
1141 if (save_cwd (&cwd))
1142 error (1, errno, "Failed to save current directory.");
1143
1144 if (CVS_CHDIR (dir) < 0)
1145 error (1, errno, "cannot change directory to %s", dir);
1146 l = Entries_Open (0, NULL);
1147 files_removed = walklist (l, isremoved, 0);
1148 Entries_Close (l);
1149
1150 if (restore_cwd (&cwd))
1151 error (1, errno,
1152 "Failed to restore current directory, `%s'.",
1153 cwd.name);
1154 free_cwd (&cwd);
1155
1156 if (files_removed != 0)
1157 {
1158 /* There are files that have been removed, but not
1159 committed! Do not consider the directory empty. */
1160 (void) CVS_CLOSEDIR (dirp);
1161 return 0;
1162 }
1163 }
1164 }
1165 errno = 0;
1166 }
1167 if (errno != 0)
1168 {
1169 error (0, errno, "cannot read directory %s", dir);
1170 (void) CVS_CLOSEDIR (dirp);
1171 return 0;
1172 }
1173 (void) CVS_CLOSEDIR (dirp);
1174 return 1;
1175 }
1176
1177
1178
1179 /*
1180 * scratch the Entries file entry associated with a file
1181 */
1182 static int
scratch_file(struct file_info * finfo,Vers_TS * vers)1183 scratch_file (struct file_info *finfo, Vers_TS *vers)
1184 {
1185 history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository);
1186 Scratch_Entry (finfo->entries, finfo->file);
1187 #ifdef SERVER_SUPPORT
1188 if (server_active)
1189 {
1190 if (vers->ts_user == NULL)
1191 server_scratch_entry_only ();
1192 server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1, NULL, NULL);
1193 }
1194 #endif
1195 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1196 error (0, errno, "unable to remove %s", finfo->fullname);
1197 else if (!server_active)
1198 {
1199 /* skip this step when the server is running since
1200 * server_updated should have handled it */
1201 /* keep the vers structure up to date in case we do a join
1202 * - if there isn't a file, it can't very well have a version number, can it?
1203 */
1204 if (vers->vn_user != NULL)
1205 {
1206 free (vers->vn_user);
1207 vers->vn_user = NULL;
1208 }
1209 if (vers->ts_user != NULL)
1210 {
1211 free (vers->ts_user);
1212 vers->ts_user = NULL;
1213 }
1214 }
1215 return 0;
1216 }
1217
1218
1219
1220 /*
1221 * Check out a file.
1222 */
1223 static int
checkout_file(struct file_info * finfo,Vers_TS * vers_ts,int adding,int merging,int update_server)1224 checkout_file (struct file_info *finfo, Vers_TS *vers_ts, int adding,
1225 int merging, int update_server)
1226 {
1227 char *backup;
1228 int set_time, retval = 0;
1229 int status;
1230 int file_is_dead;
1231 struct buffer *revbuf;
1232
1233 backup = NULL;
1234 revbuf = NULL;
1235
1236 /* Don't screw with backup files if we're going to stdout, or if
1237 we are the server. */
1238 if (!pipeout && !server_active)
1239 {
1240 backup = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1241 if (isfile (finfo->file))
1242 rename_file (finfo->file, backup);
1243 else
1244 {
1245 /* If -f/-t wrappers are being used to wrap up a directory,
1246 then backup might be a directory instead of just a file. */
1247 if (unlink_file_dir (backup) < 0)
1248 {
1249 /* Not sure if the existence_error check is needed here. */
1250 if (!existence_error (errno))
1251 /* FIXME: should include update_dir in message. */
1252 error (0, errno, "error removing %s", backup);
1253 }
1254 free (backup);
1255 backup = NULL;
1256 }
1257 }
1258
1259 file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
1260
1261 if (!file_is_dead)
1262 {
1263 /*
1264 * if we are checking out to stdout, print a nice message to
1265 * stderr, and add the -p flag to the command */
1266 if (pipeout)
1267 {
1268 if (!quiet)
1269 {
1270 cvs_outerr ("\
1271 ===================================================================\n\
1272 Checking out ", 0);
1273 cvs_outerr (finfo->fullname, 0);
1274 cvs_outerr ("\n\
1275 RCS: ", 0);
1276 cvs_outerr (vers_ts->srcfile->print_path, 0);
1277 cvs_outerr ("\n\
1278 VERS: ", 0);
1279 cvs_outerr (vers_ts->vn_rcs, 0);
1280 cvs_outerr ("\n***************\n", 0);
1281 }
1282 }
1283
1284 #ifdef SERVER_SUPPORT
1285 if (update_server
1286 && server_active
1287 && ! pipeout
1288 && ! file_gzip_level
1289 && ! joining ()
1290 && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
1291 {
1292 revbuf = buf_nonio_initialize (NULL);
1293 status = RCS_checkout (vers_ts->srcfile, NULL,
1294 vers_ts->vn_rcs, vers_ts->tag,
1295 vers_ts->options, RUN_TTY,
1296 checkout_to_buffer, revbuf);
1297 }
1298 else
1299 #endif
1300 status = RCS_checkout (vers_ts->srcfile,
1301 pipeout ? NULL : finfo->file,
1302 vers_ts->vn_rcs, vers_ts->tag,
1303 vers_ts->options, RUN_TTY, NULL, NULL);
1304 }
1305 if (file_is_dead || status == 0)
1306 {
1307 mode_t mode;
1308
1309 mode = (mode_t) -1;
1310
1311 if (!pipeout)
1312 {
1313 Vers_TS *xvers_ts;
1314
1315 if (revbuf != NULL && !noexec)
1316 {
1317 struct stat sb;
1318
1319 /* FIXME: We should have RCS_checkout return the mode.
1320 That would also fix the kludge with noexec, above, which
1321 is here only because noexec doesn't write srcfile->path
1322 for us to stat. */
1323 if (stat (vers_ts->srcfile->path, &sb) < 0)
1324 {
1325 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
1326 buf_free (revbuf);
1327 #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
1328 error (1, errno, "cannot stat %s",
1329 vers_ts->srcfile->path);
1330 }
1331 mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
1332 }
1333
1334 if (cvswrite
1335 && !file_is_dead
1336 && !fileattr_get (finfo->file, "_watched"))
1337 {
1338 if (revbuf == NULL)
1339 xchmod (finfo->file, 1);
1340 else
1341 {
1342 mode_t oumask, writeaccess;
1343
1344 /* We know that we are the server here, so
1345 although xchmod checks umask, we don't bother. */
1346 /* Not bothering with the umask makes the files
1347 mode 0777 on old clients, though. -chb */
1348 oumask = umask(0);
1349 (void) umask(oumask);
1350 writeaccess = (((mode & S_IRUSR) ? S_IWUSR : 0)
1351 | ((mode & S_IRGRP) ? S_IWGRP : 0)
1352 | ((mode & S_IROTH) ? S_IWOTH : 0));
1353 mode |= (~oumask) & writeaccess;
1354 }
1355 }
1356
1357 {
1358 /* A newly checked out file is never under the spell
1359 of "cvs edit". If we think we were editing it
1360 from a previous life, clean up. Would be better to
1361 check for same the working directory instead of
1362 same user, but that is hairy. */
1363
1364 struct addremove_args args;
1365
1366 editor_set (finfo->file, getcaller (), NULL);
1367
1368 memset (&args, 0, sizeof args);
1369 args.remove_temp = 1;
1370 watch_modify_watchers (finfo->file, &args);
1371 }
1372
1373 /* set the time from the RCS file iff it was unknown before */
1374 set_time =
1375 (!noexec
1376 && (preserve_timestamps_on_update ||
1377 vers_ts->vn_user == NULL ||
1378 strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
1379 && !file_is_dead);
1380
1381 wrap_fromcvs_process_file (finfo->file);
1382
1383 xvers_ts = Version_TS (finfo, options, tag, date,
1384 force_tag_match, set_time);
1385 if (strcmp (xvers_ts->options, "-V4") == 0)
1386 xvers_ts->options[0] = '\0';
1387
1388 if (revbuf != NULL)
1389 {
1390 /* If we stored the file data into a buffer, then we
1391 didn't create a file at all, so xvers_ts->ts_user
1392 is wrong. The correct value is to have it be the
1393 same as xvers_ts->ts_rcs, meaning that the working
1394 file is unchanged from the RCS file.
1395
1396 FIXME: We should tell Version_TS not to waste time
1397 statting the nonexistent file.
1398
1399 FIXME: Actually, I don't think the ts_user value
1400 matters at all here. The only use I know of is
1401 that it is printed in a trace message by
1402 Server_Register. */
1403
1404 if (xvers_ts->ts_user != NULL)
1405 free (xvers_ts->ts_user);
1406 xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
1407 }
1408
1409 (void) time (&last_register_time);
1410
1411 if (file_is_dead)
1412 {
1413 if (xvers_ts->vn_user != NULL)
1414 {
1415 error (0, 0,
1416 "warning: %s is not (any longer) pertinent",
1417 finfo->fullname);
1418 }
1419 Scratch_Entry (finfo->entries, finfo->file);
1420 #ifdef SERVER_SUPPORT
1421 if (server_active && xvers_ts->ts_user == NULL)
1422 server_scratch_entry_only ();
1423 #endif
1424 /* FIXME: Rather than always unlink'ing, and ignoring the
1425 existence_error, we should do the unlink only if
1426 vers_ts->ts_user is non-NULL. Then there would be no
1427 need to ignore an existence_error (for example, if the
1428 user removes the file while we are running). */
1429 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
1430 {
1431 error (0, errno, "cannot remove %s", finfo->fullname);
1432 }
1433 }
1434 else
1435 Register (finfo->entries, finfo->file,
1436 adding ? "0" : xvers_ts->vn_rcs,
1437 xvers_ts->ts_user, xvers_ts->options,
1438 xvers_ts->tag, xvers_ts->date,
1439 NULL); /* Clear conflict flag on fresh checkout */
1440
1441 /* fix up the vers structure, in case it is used by join */
1442 if (join_rev1)
1443 {
1444 /* FIXME: Throwing away the original revision info is almost
1445 certainly wrong -- what if join_rev1 is "BASE"? */
1446 if (vers_ts->vn_user != NULL)
1447 free (vers_ts->vn_user);
1448 if (vers_ts->vn_rcs != NULL)
1449 free (vers_ts->vn_rcs);
1450 vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
1451 vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
1452 }
1453
1454 /* If this is really Update and not Checkout, recode history */
1455 if (strcmp (cvs_cmd_name, "update") == 0)
1456 history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, finfo->file,
1457 finfo->repository);
1458
1459 freevers_ts (&xvers_ts);
1460
1461 if (!really_quiet && !file_is_dead)
1462 {
1463 write_letter (finfo, 'U');
1464 }
1465 }
1466
1467 #ifdef SERVER_SUPPORT
1468 if (update_server && server_active)
1469 server_updated (finfo, vers_ts,
1470 merging ? SERVER_MERGED : SERVER_UPDATED,
1471 mode, NULL, revbuf);
1472 #endif
1473 }
1474 else
1475 {
1476 if (backup != NULL)
1477 {
1478 rename_file (backup, finfo->file);
1479 free (backup);
1480 backup = NULL;
1481 }
1482
1483 error (0, 0, "could not check out %s", finfo->fullname);
1484
1485 retval = status;
1486 }
1487
1488 if (backup != NULL)
1489 {
1490 /* If -f/-t wrappers are being used to wrap up a directory,
1491 then backup might be a directory instead of just a file. */
1492 if (unlink_file_dir (backup) < 0)
1493 {
1494 /* Not sure if the existence_error check is needed here. */
1495 if (!existence_error (errno))
1496 /* FIXME: should include update_dir in message. */
1497 error (0, errno, "error removing %s", backup);
1498 }
1499 free (backup);
1500 }
1501
1502 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
1503 if (revbuf != NULL)
1504 buf_free (revbuf);
1505 #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
1506 return retval;
1507 }
1508
1509
1510
1511 #ifdef SERVER_SUPPORT
1512
1513 /* This function is used to write data from a file being checked out
1514 into a buffer. */
1515
1516 static void
checkout_to_buffer(void * callerdat,const char * data,size_t len)1517 checkout_to_buffer (void *callerdat, const char *data, size_t len)
1518 {
1519 struct buffer *buf = (struct buffer *) callerdat;
1520
1521 buf_output (buf, data, len);
1522 }
1523
1524 #endif /* SERVER_SUPPORT */
1525
1526 #ifdef SERVER_SUPPORT
1527
1528 /* This structure is used to pass information between patch_file and
1529 patch_file_write. */
1530
1531 struct patch_file_data
1532 {
1533 /* File name, for error messages. */
1534 const char *filename;
1535 /* File to which to write. */
1536 FILE *fp;
1537 /* Whether to compute the MD5 checksum. */
1538 int compute_checksum;
1539 /* Data structure for computing the MD5 checksum. */
1540 struct md5_ctx context;
1541 /* Set if the file has a final newline. */
1542 int final_nl;
1543 };
1544
1545 /* Patch a file. Runs diff. This is only done when running as the
1546 * server. The hope is that the diff will be smaller than the file
1547 * itself.
1548 */
1549 static int
patch_file(struct file_info * finfo,Vers_TS * vers_ts,int * docheckout,struct stat * file_info,unsigned char * checksum)1550 patch_file (struct file_info *finfo, Vers_TS *vers_ts, int *docheckout,
1551 struct stat *file_info, unsigned char *checksum)
1552 {
1553 char *backup;
1554 char *file1;
1555 char *file2;
1556 int retval = 0;
1557 int retcode = 0;
1558 int fail;
1559 FILE *e;
1560 struct patch_file_data data;
1561
1562 *docheckout = 0;
1563
1564 if (noexec || pipeout || joining ())
1565 {
1566 *docheckout = 1;
1567 return 0;
1568 }
1569
1570 /* If this file has been marked as being binary, then never send a
1571 patch. */
1572 if (strcmp (vers_ts->options, "-kb") == 0)
1573 {
1574 *docheckout = 1;
1575 return 0;
1576 }
1577
1578 /* First check that the first revision exists. If it has been nuked
1579 by cvs admin -o, then just fall back to checking out entire
1580 revisions. In some sense maybe we don't have to do this; after
1581 all cvs.texinfo says "Make sure that no-one has checked out a
1582 copy of the revision you outdate" but then again, that advice
1583 doesn't really make complete sense, because "cvs admin" operates
1584 on a working directory and so _someone_ will almost always have
1585 _some_ revision checked out. */
1586 {
1587 char *rev;
1588
1589 rev = RCS_gettag (finfo->rcs, vers_ts->vn_user, 1, NULL);
1590 if (rev == NULL)
1591 {
1592 *docheckout = 1;
1593 return 0;
1594 }
1595 else
1596 free (rev);
1597 }
1598
1599 /* If the revision is dead, let checkout_file handle it rather
1600 than duplicating the processing here. */
1601 if (RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs))
1602 {
1603 *docheckout = 1;
1604 return 0;
1605 }
1606
1607 backup = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
1608 if (isfile (finfo->file))
1609 rename_file (finfo->file, backup);
1610 else
1611 {
1612 if (unlink_file (backup) < 0
1613 && !existence_error (errno))
1614 error (0, errno, "cannot remove %s", backup);
1615 }
1616
1617 file1 = Xasprintf ("%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
1618 file2 = Xasprintf ("%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
1619
1620 fail = 0;
1621
1622 /* We need to check out both revisions first, to see if either one
1623 has a trailing newline. Because of this, we don't use rcsdiff,
1624 but just use diff. */
1625
1626 e = CVS_FOPEN (file1, "w");
1627 if (e == NULL)
1628 error (1, errno, "cannot open %s", file1);
1629
1630 data.filename = file1;
1631 data.fp = e;
1632 data.final_nl = 0;
1633 data.compute_checksum = 0;
1634
1635 /* FIXME - Passing vers_ts->tag here is wrong in the least number
1636 * of cases. Since we don't know whether vn_user was checked out
1637 * using a tag, we pass vers_ts->tag, which, assuming the user did
1638 * not specify a new TAG to -r, will be the branch we are on.
1639 *
1640 * The only thing it is used for is to substitute in for the Name
1641 * RCS keyword, so in the error case, the patch fails to apply on
1642 * the client end and we end up resending the whole file.
1643 *
1644 * At least, if we are keeping track of the tag vn_user came from,
1645 * I don't know where yet. -DRP
1646 */
1647 retcode = RCS_checkout (vers_ts->srcfile, NULL,
1648 vers_ts->vn_user, vers_ts->tag,
1649 vers_ts->options, RUN_TTY,
1650 patch_file_write, (void *) &data);
1651
1652 if (fclose (e) < 0)
1653 error (1, errno, "cannot close %s", file1);
1654
1655 if (retcode != 0 || ! data.final_nl)
1656 fail = 1;
1657
1658 if (! fail)
1659 {
1660 e = CVS_FOPEN (file2, "w");
1661 if (e == NULL)
1662 error (1, errno, "cannot open %s", file2);
1663
1664 data.filename = file2;
1665 data.fp = e;
1666 data.final_nl = 0;
1667 data.compute_checksum = 1;
1668 md5_init_ctx (&data.context);
1669
1670 retcode = RCS_checkout (vers_ts->srcfile, NULL,
1671 vers_ts->vn_rcs, vers_ts->tag,
1672 vers_ts->options, RUN_TTY,
1673 patch_file_write, (void *) &data);
1674
1675 if (fclose (e) < 0)
1676 error (1, errno, "cannot close %s", file2);
1677
1678 if (retcode != 0 || ! data.final_nl)
1679 fail = 1;
1680 else
1681 md5_finish_ctx (&data.context, checksum);
1682 }
1683
1684 retcode = 0;
1685 if (! fail)
1686 {
1687 int dargc = 0;
1688 size_t darg_allocated = 0;
1689 char **dargv = NULL;
1690
1691 /* If the client does not support the Rcs-diff command, we
1692 send a context diff, and the client must invoke patch.
1693 That approach was problematical for various reasons. The
1694 new approach only requires running diff in the server; the
1695 client can handle everything without invoking an external
1696 program. */
1697 if (!rcs_diff_patches)
1698 /* We use -c, not -u, because that is what CVS has
1699 traditionally used. Kind of a moot point, now that
1700 Rcs-diff is preferred, so there is no point in making
1701 the compatibility issues worse. */
1702 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-c");
1703 else
1704 /* Now that diff is librarified, we could be passing -a if
1705 we wanted to. However, it is unclear to me whether we
1706 would want to. Does diff -a, in any significant
1707 percentage of cases, produce patches which are smaller
1708 than the files it is patching? I guess maybe text
1709 files with character sets which diff regards as
1710 'binary'. Conversely, do they tend to be much larger
1711 in the bad cases? This needs some more
1712 thought/investigation, I suspect. */
1713 run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
1714 retcode = diff_exec (file1, file2, NULL, NULL, dargc, dargv,
1715 finfo->file);
1716 run_arg_free_p (dargc, dargv);
1717 free (dargv);
1718
1719 /* A retcode of 0 means no differences. 1 means some differences. */
1720 if (retcode != 0 && retcode != 1)
1721 fail = 1;
1722 }
1723
1724 if (!fail)
1725 {
1726 struct stat file2_info;
1727
1728 /* Check to make sure the patch is really shorter */
1729 if (stat (file2, &file2_info) < 0)
1730 error (1, errno, "could not stat %s", file2);
1731 if (stat (finfo->file, file_info) < 0)
1732 error (1, errno, "could not stat %s", finfo->file);
1733 if (file2_info.st_size <= file_info->st_size)
1734 fail = 1;
1735 }
1736
1737 if (! fail)
1738 {
1739 # define BINARY "Binary"
1740 char buf[sizeof BINARY];
1741 unsigned int c;
1742
1743 /* Check the diff output to make sure patch will be handle it. */
1744 e = CVS_FOPEN (finfo->file, "r");
1745 if (e == NULL)
1746 error (1, errno, "could not open diff output file %s",
1747 finfo->fullname);
1748 c = fread (buf, 1, sizeof BINARY - 1, e);
1749 buf[c] = '\0';
1750 if (strcmp (buf, BINARY) == 0)
1751 {
1752 /* These are binary files. We could use diff -a, but
1753 patch can't handle that. */
1754 fail = 1;
1755 }
1756 fclose (e);
1757 }
1758
1759 if (! fail)
1760 {
1761 Vers_TS *xvers_ts;
1762
1763 /* Stat the original RCS file, and then adjust it the way
1764 that RCS_checkout would. FIXME: This is an abstraction
1765 violation. */
1766 if (stat (vers_ts->srcfile->path, file_info) < 0)
1767 error (1, errno, "could not stat %s", vers_ts->srcfile->path);
1768 if (chmod (finfo->file,
1769 file_info->st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH))
1770 < 0)
1771 error (0, errno, "cannot change mode of file %s", finfo->file);
1772 if (cvswrite
1773 && !fileattr_get (finfo->file, "_watched"))
1774 xchmod (finfo->file, 1);
1775
1776 /* This stuff is just copied blindly from checkout_file. I
1777 don't really know what it does. */
1778 xvers_ts = Version_TS (finfo, options, tag, date,
1779 force_tag_match, preserve_timestamps_on_update);
1780 if (strcmp (xvers_ts->options, "-V4") == 0)
1781 xvers_ts->options[0] = '\0';
1782
1783 Register (finfo->entries, finfo->file, xvers_ts->vn_rcs,
1784 xvers_ts->ts_user, xvers_ts->options,
1785 xvers_ts->tag, xvers_ts->date, NULL);
1786
1787 if (stat (finfo->file, file_info) < 0)
1788 error (1, errno, "could not stat %s", finfo->file);
1789
1790 /* If this is really Update and not Checkout, record history. */
1791 if (strcmp (cvs_cmd_name, "update") == 0)
1792 history_write ('P', finfo->update_dir, xvers_ts->vn_rcs,
1793 finfo->file, finfo->repository);
1794
1795 freevers_ts (&xvers_ts);
1796
1797 if (!really_quiet)
1798 {
1799 write_letter (finfo, 'P');
1800 }
1801 }
1802 else
1803 {
1804 int old_errno = errno; /* save errno value over the rename */
1805
1806 if (isfile (backup))
1807 rename_file (backup, finfo->file);
1808
1809 if (retcode != 0 && retcode != 1)
1810 error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
1811 "could not diff %s", finfo->fullname);
1812
1813 *docheckout = 1;
1814 retval = retcode;
1815 }
1816
1817 if (unlink_file (backup) < 0
1818 && !existence_error (errno))
1819 error (0, errno, "cannot remove %s", backup);
1820 if (unlink_file (file1) < 0
1821 && !existence_error (errno))
1822 error (0, errno, "cannot remove %s", file1);
1823 if (unlink_file (file2) < 0
1824 && !existence_error (errno))
1825 error (0, errno, "cannot remove %s", file2);
1826
1827 free (backup);
1828 free (file1);
1829 free (file2);
1830 return retval;
1831 }
1832
1833
1834
1835 /* Write data to a file. Record whether the last byte written was a
1836 newline. Optionally compute a checksum. This is called by
1837 patch_file via RCS_checkout. */
1838
1839 static void
patch_file_write(void * callerdat,const char * buffer,size_t len)1840 patch_file_write (void *callerdat, const char *buffer, size_t len)
1841 {
1842 struct patch_file_data *data = (struct patch_file_data *) callerdat;
1843
1844 if (fwrite (buffer, 1, len, data->fp) != len)
1845 error (1, errno, "cannot write %s", data->filename);
1846
1847 data->final_nl = (buffer[len - 1] == '\n');
1848
1849 if (data->compute_checksum)
1850 md5_process_bytes (buffer, len, &data->context);
1851 }
1852
1853 #endif /* SERVER_SUPPORT */
1854
1855 /*
1856 * Several of the types we process only print a bit of information consisting
1857 * of a single letter and the name.
1858 */
1859 void
write_letter(struct file_info * finfo,int letter)1860 write_letter (struct file_info *finfo, int letter)
1861 {
1862 if (!really_quiet)
1863 {
1864 char *tag = NULL;
1865 /* Big enough for "+updated" or any of its ilk. */
1866 char buf[80];
1867
1868 switch (letter)
1869 {
1870 case 'U':
1871 tag = "updated";
1872 break;
1873 default:
1874 /* We don't yet support tagged output except for "U". */
1875 break;
1876 }
1877
1878 if (tag != NULL)
1879 {
1880 sprintf (buf, "+%s", tag);
1881 cvs_output_tagged (buf, NULL);
1882 }
1883 buf[0] = letter;
1884 buf[1] = ' ';
1885 buf[2] = '\0';
1886 cvs_output_tagged ("text", buf);
1887 cvs_output_tagged ("fname", finfo->fullname);
1888 cvs_output_tagged ("newline", NULL);
1889 if (tag != NULL)
1890 {
1891 sprintf (buf, "-%s", tag);
1892 cvs_output_tagged (buf, NULL);
1893 }
1894 }
1895 return;
1896 }
1897
1898
1899
1900 /* Reregister a file after a merge. */
1901 static void
RegisterMerge(struct file_info * finfo,Vers_TS * vers,const char * backup,int has_conflicts)1902 RegisterMerge (struct file_info *finfo, Vers_TS *vers,
1903 const char *backup, int has_conflicts)
1904 {
1905 /* This file is the result of a merge, which means that it has
1906 been modified. We use a special timestamp string which will
1907 not compare equal to any actual timestamp. */
1908 char *cp = NULL;
1909
1910 if (has_conflicts)
1911 {
1912 time (&last_register_time);
1913 cp = time_stamp (finfo->file);
1914 }
1915 Register (finfo->entries, finfo->file, vers->vn_rcs ? vers->vn_rcs : "0",
1916 "Result of merge", vers->options, vers->tag, vers->date, cp);
1917 if (cp)
1918 free (cp);
1919
1920 #ifdef SERVER_SUPPORT
1921 /* Send the new contents of the file before the message. If we
1922 wanted to be totally correct, we would have the client write
1923 the message only after the file has safely been written. */
1924 if (server_active)
1925 {
1926 server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
1927 backup);
1928 server_updated (finfo, vers, SERVER_MERGED, (mode_t) -1, NULL, NULL);
1929 }
1930 #endif
1931 }
1932
1933
1934
1935 /*
1936 * Do all the magic associated with a file which needs to be merged
1937 */
1938 static int
merge_file(struct file_info * finfo,Vers_TS * vers)1939 merge_file (struct file_info *finfo, Vers_TS *vers)
1940 {
1941 char *backup;
1942 int status;
1943 int retval;
1944
1945 assert (vers->vn_user);
1946
1947 /*
1948 * The users currently modified file is moved to a backup file name
1949 * ".#filename.version", so that it will stay around for a few days
1950 * before being automatically removed by some cron daemon. The "version"
1951 * is the version of the file that the user was most up-to-date with
1952 * before the merge.
1953 */
1954 backup = Xasprintf ("%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
1955
1956 if (unlink_file (backup) && !existence_error (errno))
1957 error (0, errno, "unable to remove %s", backup);
1958 copy_file (finfo->file, backup);
1959 xchmod (finfo->file, 1);
1960
1961 if (strcmp (vers->options, "-kb") == 0
1962 || wrap_merge_is_copy (finfo->file)
1963 || special_file_mismatch (finfo, NULL, vers->vn_rcs))
1964 {
1965 /* For binary files, a merge is always a conflict. Same for
1966 files whose permissions or linkage do not match. We give the
1967 user the two files, and let them resolve it. It is possible
1968 that we should require a "touch foo" or similar step before
1969 we allow a checkin. */
1970
1971 /* TODO: it may not always be necessary to regard a permission
1972 mismatch as a conflict. The working file and the RCS file
1973 have a common ancestor `A'; if the working file's permissions
1974 match A's, then it's probably safe to overwrite them with the
1975 RCS permissions. Only if the working file, the RCS file, and
1976 A all disagree should this be considered a conflict. But more
1977 thought needs to go into this, and in the meantime it is safe
1978 to treat any such mismatch as an automatic conflict. -twp */
1979
1980 status = RCS_checkout (finfo->rcs, finfo->file, vers->vn_rcs,
1981 vers->tag, vers->options, NULL, NULL, NULL);
1982 if (status)
1983 {
1984 error (0, 0, "failed to check out `%s' file", finfo->fullname);
1985 error (0, 0, "restoring `%s' from backup file `%s'",
1986 finfo->fullname, backup);
1987 rename_file (backup, finfo->file);
1988 retval = 1;
1989 goto out;
1990 }
1991
1992 xchmod (finfo->file, 1);
1993
1994 RegisterMerge (finfo, vers, backup, 1);
1995
1996 /* Is there a better term than "nonmergeable file"? What we
1997 really mean is, not something that CVS cannot or does not
1998 want to merge (there might be an external manual or
1999 automatic merge process). */
2000 error (0, 0, "nonmergeable file needs merge");
2001 error (0, 0, "revision %s from repository is now in %s",
2002 vers->vn_rcs, finfo->fullname);
2003 error (0, 0, "file from working directory is now in %s", backup);
2004 write_letter (finfo, 'C');
2005
2006 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
2007 finfo->repository);
2008 retval = 0;
2009 goto out;
2010 }
2011
2012 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2013 vers->options, vers->vn_user, vers->vn_rcs);
2014 if (status != 0 && status != 1)
2015 {
2016 error (0, status == -1 ? errno : 0,
2017 "could not merge revision %s of %s", vers->vn_user, finfo->fullname);
2018 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2019 finfo->fullname, backup);
2020 rename_file (backup, finfo->file);
2021 retval = 1;
2022 goto out;
2023 }
2024
2025 if (strcmp (vers->options, "-V4") == 0)
2026 vers->options[0] = '\0';
2027
2028 /* fix up the vers structure, in case it is used by join */
2029 if (join_rev1)
2030 {
2031 /* FIXME: Throwing away the original revision info is almost
2032 certainly wrong -- what if join_rev1 is "BASE"? */
2033 if (vers->vn_user != NULL)
2034 free (vers->vn_user);
2035 vers->vn_user = xstrdup (vers->vn_rcs);
2036 }
2037
2038 RegisterMerge (finfo, vers, backup, status);
2039
2040 if (status == 1)
2041 {
2042 error (0, 0, "conflicts found in %s", finfo->fullname);
2043
2044 write_letter (finfo, 'C');
2045
2046 history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
2047 finfo->repository);
2048
2049 }
2050 else /* status == 0 */
2051 {
2052 history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
2053 finfo->repository);
2054
2055 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2056 xcmp on the temporary files without much hassle, I think. */
2057 if (!noexec && !xcmp (backup, finfo->file))
2058 {
2059 cvs_output (finfo->fullname, 0);
2060 cvs_output (" already contains the differences between ", 0);
2061 cvs_output (vers->vn_user, 0);
2062 cvs_output (" and ", 0);
2063 cvs_output (vers->vn_rcs, 0);
2064 cvs_output ("\n", 1);
2065
2066 retval = 0;
2067 goto out;
2068 }
2069
2070 write_letter (finfo, 'M');
2071 }
2072 retval = 0;
2073 out:
2074 free (backup);
2075 return retval;
2076 }
2077
2078
2079
2080 /*
2081 * Do all the magic associated with a file which needs to be joined
2082 * (reached via the -j option to checkout or update).
2083 *
2084 * INPUTS
2085 * finfo File information about the destination file.
2086 * vers The Vers_TS structure for finfo.
2087 *
2088 * GLOBALS
2089 * join_rev1 From the command line.
2090 * join_rev2 From the command line.
2091 * server_active Natch.
2092 *
2093 * ASSUMPTIONS
2094 * 1. Is not called in client mode.
2095 */
2096 static void
join_file(struct file_info * finfo,Vers_TS * vers)2097 join_file (struct file_info *finfo, Vers_TS *vers)
2098 {
2099 char *backup;
2100 char *t_options;
2101 int status;
2102
2103 char *rev1;
2104 char *rev2;
2105 char *jrev1;
2106 char *jrev2;
2107 char *jdate1;
2108 char *jdate2;
2109
2110 TRACE (TRACE_FUNCTION, "join_file(%s, %s%s%s%s, %s, %s)",
2111 finfo->file,
2112 vers->tag ? vers->tag : "",
2113 vers->tag ? " (" : "",
2114 vers->vn_rcs ? vers->vn_rcs : "",
2115 vers->tag ? ")" : "",
2116 join_rev1 ? join_rev1 : "",
2117 join_rev2 ? join_rev2 : "");
2118
2119 jrev1 = join_rev1;
2120 jrev2 = join_rev2;
2121 jdate1 = join_date1;
2122 jdate2 = join_date2;
2123
2124 /* Determine if we need to do anything at all. */
2125 if (vers->srcfile == NULL ||
2126 vers->srcfile->path == NULL)
2127 {
2128 return;
2129 }
2130
2131 /* If only one join revision is specified, it becomes the second
2132 revision. */
2133 if (jrev2 == NULL)
2134 {
2135 jrev2 = jrev1;
2136 jrev1 = NULL;
2137 jdate2 = jdate1;
2138 jdate1 = NULL;
2139 }
2140
2141 /* FIXME: Need to handle "BASE" for jrev1 and/or jrev2. Note caveat
2142 below about vn_user. */
2143
2144 /* Convert the second revision, walking branches and dates. */
2145 rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, NULL);
2146
2147 /* If this is a merge of two revisions, get the first revision.
2148 If only one join tag was specified, then the first revision is
2149 the greatest common ancestor of the second revision and the
2150 working file. */
2151 if (jrev1 != NULL)
2152 rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, NULL);
2153 else
2154 {
2155 /* Note that we use vn_rcs here, since vn_user may contain a
2156 special string such as "-nn". */
2157 if (vers->vn_rcs == NULL)
2158 rev1 = NULL;
2159 else if (rev2 == NULL)
2160 {
2161 /* This means that the file never existed on the branch.
2162 It does not mean that the file was removed on the
2163 branch: that case is represented by a dead rev2. If
2164 the file never existed on the branch, then we have
2165 nothing to merge, so we just return. */
2166 return;
2167 }
2168 else
2169 rev1 = gca (vers->vn_rcs, rev2);
2170 }
2171
2172 /* Handle a nonexistent or dead merge target. */
2173 if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2))
2174 {
2175 char *mrev;
2176
2177 if (rev2 != NULL)
2178 free (rev2);
2179
2180 /* If the first revision doesn't exist either, then there is
2181 no change between the two revisions, so we don't do
2182 anything. */
2183 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2184 {
2185 if (rev1 != NULL)
2186 free (rev1);
2187 return;
2188 }
2189
2190 /* If we are merging two revisions, then the file was removed
2191 between the first revision and the second one. In this
2192 case we want to mark the file for removal.
2193
2194 If we are merging one revision, then the file has been
2195 removed between the greatest common ancestor and the merge
2196 revision. From the perspective of the branch on to which
2197 we ar emerging, which may be the trunk, either 1) the file
2198 does not currently exist on the target, or 2) the file has
2199 not been modified on the target branch since the greatest
2200 common ancestor, or 3) the file has been modified on the
2201 target branch since the greatest common ancestor. In case
2202 1 there is nothing to do. In case 2 we mark the file for
2203 removal. In case 3 we have a conflict.
2204
2205 Note that the handling is slightly different depending upon
2206 whether one or two join targets were specified. If two
2207 join targets were specified, we don't check whether the
2208 file was modified since a given point. My reasoning is
2209 that if you ask for an explicit merge between two tags,
2210 then you want to merge in whatever was changed between
2211 those two tags. If a file was removed between the two
2212 tags, then you want it to be removed. However, if you ask
2213 for a merge of a branch, then you want to merge in all
2214 changes which were made on the branch. If a file was
2215 removed on the branch, that is a change to the file. If
2216 the file was also changed on the main line, then that is
2217 also a change. These two changes--the file removal and the
2218 modification--must be merged. This is a conflict. */
2219
2220 /* If the user file is dead, or does not exist, or has been
2221 marked for removal, then there is nothing to do. */
2222 if (vers->vn_user == NULL
2223 || vers->vn_user[0] == '-'
2224 || RCS_isdead (vers->srcfile, vers->vn_user))
2225 {
2226 if (rev1 != NULL)
2227 free (rev1);
2228 return;
2229 }
2230
2231 /* If the user file has been marked for addition, or has been
2232 locally modified, then we have a conflict which we can not
2233 resolve. No_Difference will already have been called in
2234 this case, so comparing the timestamps is sufficient to
2235 determine whether the file is locally modified. */
2236 if (strcmp (vers->vn_user, "0") == 0
2237 || (vers->ts_user != NULL
2238 && strcmp (vers->ts_user, vers->ts_rcs) != 0))
2239 {
2240 if (jdate2 != NULL)
2241 error (0, 0,
2242 "file %s is locally modified, but has been removed in revision %s as of %s",
2243 finfo->fullname, jrev2, jdate2);
2244 else
2245 error (0, 0,
2246 "file %s is locally modified, but has been removed in revision %s",
2247 finfo->fullname, jrev2);
2248
2249 /* FIXME: Should we arrange to return a non-zero exit
2250 status? */
2251
2252 if (rev1 != NULL)
2253 free (rev1);
2254
2255 return;
2256 }
2257
2258 /* If only one join tag was specified, and the user file has
2259 been changed since the greatest common ancestor (rev1),
2260 then there is a conflict we can not resolve. See above for
2261 the rationale. */
2262 if (join_rev2 == NULL
2263 && strcmp (rev1, vers->vn_user) != 0)
2264 {
2265 if (jdate2 != NULL)
2266 error (0, 0,
2267 "file %s has been modified, but has been removed in revision %s as of %s",
2268 finfo->fullname, jrev2, jdate2);
2269 else
2270 error (0, 0,
2271 "file %s has been modified, but has been removed in revision %s",
2272 finfo->fullname, jrev2);
2273
2274 /* FIXME: Should we arrange to return a non-zero exit
2275 status? */
2276
2277 if (rev1 != NULL)
2278 free (rev1);
2279
2280 return;
2281 }
2282
2283 if (rev1 != NULL)
2284 free (rev1);
2285
2286 /* The user file exists and has not been modified. Mark it
2287 for removal. FIXME: If we are doing a checkout, this has
2288 the effect of first checking out the file, and then
2289 removing it. It would be better to just register the
2290 removal.
2291
2292 The same goes for a removal then an add. e.g.
2293 cvs up -rbr -jbr2 could remove and readd the same file
2294 */
2295 /* save the rev since server_updated might invalidate it */
2296 mrev = Xasprintf ("-%s", vers->vn_user);
2297 #ifdef SERVER_SUPPORT
2298 if (server_active)
2299 {
2300 server_scratch (finfo->file);
2301 server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
2302 NULL, NULL);
2303 }
2304 #endif
2305 Register (finfo->entries, finfo->file, mrev, vers->ts_rcs,
2306 vers->options, vers->tag, vers->date, vers->ts_conflict);
2307 free (mrev);
2308 /* We need to check existence_error here because if we are
2309 running as the server, and the file is up to date in the
2310 working directory, the client will not have sent us a copy. */
2311 if (unlink_file (finfo->file) < 0 && ! existence_error (errno))
2312 error (0, errno, "cannot remove file %s", finfo->fullname);
2313 #ifdef SERVER_SUPPORT
2314 if (server_active)
2315 server_checked_in (finfo->file, finfo->update_dir,
2316 finfo->repository);
2317 #endif
2318 if (! really_quiet)
2319 error (0, 0, "scheduling `%s' for removal", finfo->fullname);
2320
2321 return;
2322 }
2323
2324 /* If the two merge revisions are the same, then there is nothing
2325 * to do. This needs to be checked before the rev2 == up-to-date base
2326 * revision check tha comes next. Otherwise, rev1 can == rev2 and get an
2327 * "already contains the changes between <rev1> and <rev1>" message.
2328 */
2329 if (rev1 && strcmp (rev1, rev2) == 0)
2330 {
2331 free (rev1);
2332 free (rev2);
2333 return;
2334 }
2335
2336 /* If we know that the user file is up-to-date, then it becomes an
2337 * optimization to skip the merge when rev2 is the same as the base
2338 * revision. i.e. we know that diff3(file2,file1,file2) will produce
2339 * file2.
2340 */
2341 if (vers->vn_user != NULL && vers->ts_user != NULL
2342 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2343 && strcmp (rev2, vers->vn_user) == 0)
2344 {
2345 if (!really_quiet)
2346 {
2347 cvs_output (finfo->fullname, 0);
2348 cvs_output (" already contains the differences between ", 0);
2349 cvs_output (rev1 ? rev1 : "creation", 0);
2350 cvs_output (" and ", 0);
2351 cvs_output (rev2, 0);
2352 cvs_output ("\n", 1);
2353 }
2354
2355 if (rev1 != NULL)
2356 free (rev1);
2357 free (rev2);
2358
2359 return;
2360 }
2361
2362 /* If rev1 is dead or does not exist, then the file was added
2363 between rev1 and rev2. */
2364 if (rev1 == NULL || RCS_isdead (vers->srcfile, rev1))
2365 {
2366 if (rev1 != NULL)
2367 free (rev1);
2368 free (rev2);
2369
2370 /* If the file does not exist in the working directory, then
2371 we can just check out the new revision and mark it for
2372 addition. */
2373 if (vers->vn_user == NULL)
2374 {
2375 char *saved_options = options;
2376 Vers_TS *xvers;
2377
2378 xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
2379
2380 /* Reset any keyword expansion option. Otherwise, when a
2381 command like `cvs update -kk -jT1 -jT2' creates a new file
2382 (because a file had the T2 tag, but not T1), the subsequent
2383 commit of that just-added file effectively would set the
2384 admin `-kk' option for that file in the repository. */
2385 options = NULL;
2386
2387 /* FIXME: If checkout_file fails, we should arrange to
2388 return a non-zero exit status. */
2389 status = checkout_file (finfo, xvers, 1, 0, 1);
2390 options = saved_options;
2391
2392 freevers_ts (&xvers);
2393
2394 return;
2395 }
2396
2397 /* The file currently exists in the working directory, so we
2398 have a conflict which we can not resolve. Note that this
2399 is true even if the file is marked for addition or removal. */
2400
2401 if (jdate2 != NULL)
2402 error (0, 0,
2403 "file %s exists, but has been added in revision %s as of %s",
2404 finfo->fullname, jrev2, jdate2);
2405 else
2406 error (0, 0,
2407 "file %s exists, but has been added in revision %s",
2408 finfo->fullname, jrev2);
2409
2410 return;
2411 }
2412
2413 /* If there is no working file, then we can't do the merge. */
2414 if (vers->vn_user == NULL || vers->vn_user[0] == '-')
2415 {
2416 free (rev1);
2417 free (rev2);
2418
2419 if (jdate2 != NULL)
2420 error (0, 0,
2421 "file %s does not exist, but is present in revision %s as of %s",
2422 finfo->fullname, jrev2, jdate2);
2423 else
2424 error (0, 0,
2425 "file %s does not exist, but is present in revision %s",
2426 finfo->fullname, jrev2);
2427
2428 /* FIXME: Should we arrange to return a non-zero exit status? */
2429
2430 return;
2431 }
2432
2433 #ifdef SERVER_SUPPORT
2434 if (server_active && !isreadable (finfo->file))
2435 {
2436 int retcode;
2437 /* The file is up to date. Need to check out the current contents. */
2438 /* FIXME - see the FIXME comment above the call to RCS_checkout in the
2439 * patch_file function.
2440 */
2441 retcode = RCS_checkout (vers->srcfile, finfo->file,
2442 vers->vn_user, vers->tag,
2443 NULL, RUN_TTY, NULL, NULL);
2444 if (retcode != 0)
2445 error (1, 0,
2446 "failed to check out %s file", finfo->fullname);
2447 }
2448 #endif
2449
2450 /*
2451 * The users currently modified file is moved to a backup file name
2452 * ".#filename.version", so that it will stay around for a few days
2453 * before being automatically removed by some cron daemon. The "version"
2454 * is the version of the file that the user was most up-to-date with
2455 * before the merge.
2456 */
2457 backup = Xasprintf ("%s%s.%s", BAKPREFIX, finfo->file, vers->vn_user);
2458
2459 if (unlink_file (backup) < 0
2460 && !existence_error (errno))
2461 error (0, errno, "cannot remove %s", backup);
2462 copy_file (finfo->file, backup);
2463 xchmod (finfo->file, 1);
2464
2465 t_options = vers->options;
2466 #if 0
2467 if (*t_options == '\0')
2468 t_options = "-kk"; /* to ignore keyword expansions */
2469 #endif
2470
2471 /* If the source of the merge is the same as the working file
2472 revision, then we can just RCS_checkout the target (no merging
2473 as such). In the text file case, this is probably quite
2474 similar to the RCS_merge, but in the binary file case,
2475 RCS_merge gives all kinds of trouble. */
2476 if (vers->vn_user != NULL
2477 && strcmp (rev1, vers->vn_user) == 0
2478 /* See comments above about how No_Difference has already been
2479 called. */
2480 && vers->ts_user != NULL
2481 && strcmp (vers->ts_user, vers->ts_rcs) == 0
2482
2483 /* Avoid this in the text file case. See below for why.
2484 */
2485 && (strcmp (t_options, "-kb") == 0
2486 || wrap_merge_is_copy (finfo->file)))
2487 {
2488 /* FIXME: Verify my comment below:
2489 *
2490 * RCS_merge does nothing with keywords. It merges the changes between
2491 * two revisions without expanding the keywords (it might expand in
2492 * -kk mode before computing the diff between rev1 and rev2 - I'm not
2493 * sure). In other words, the keyword lines in the current work file
2494 * get left alone.
2495 *
2496 * Therfore, checking out the destination revision (rev2) is probably
2497 * incorrect in the text case since we should see the keywords that were
2498 * substituted into the original file at the time it was checked out
2499 * and not the keywords from rev2.
2500 *
2501 * Also, it is safe to pass in NULL for nametag since we know no
2502 * substitution is happening during the binary mode checkout.
2503 */
2504 if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options,
2505 RUN_TTY, NULL, NULL) != 0)
2506 status = 2;
2507 else
2508 status = 0;
2509
2510 /* OK, this is really stupid. RCS_checkout carefully removes
2511 write permissions, and we carefully put them back. But
2512 until someone gets around to fixing it, that seems like the
2513 easiest way to get what would seem to be the right mode.
2514 I don't check CVSWRITE or _watched; I haven't thought about
2515 that in great detail, but it seems like a watched file should
2516 be checked out (writable) after a merge. */
2517 xchmod (finfo->file, 1);
2518
2519 /* Traditionally, the text file case prints a whole bunch of
2520 scary looking and verbose output which fails to tell the user
2521 what is really going on (it gives them rev1 and rev2 but doesn't
2522 indicate in any way that rev1 == vn_user). I think just a
2523 simple "U foo" is good here; it seems analogous to the case in
2524 which the file was added on the branch in terms of what to
2525 print. */
2526 write_letter (finfo, 'U');
2527 }
2528 else if (strcmp (t_options, "-kb") == 0
2529 || wrap_merge_is_copy (finfo->file)
2530 || special_file_mismatch (finfo, rev1, rev2))
2531 {
2532 /* We are dealing with binary files, or files with a
2533 permission/linkage mismatch (this second case only occurs when
2534 PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would
2535 need to take place. This is a conflict. We give the user
2536 the two files, and let them resolve it. It is possible
2537 that we should require a "touch foo" or similar step before
2538 we allow a checkin. */
2539 if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL,
2540 t_options, RUN_TTY, NULL, NULL) != 0)
2541 status = 2;
2542 else
2543 status = 0;
2544
2545 /* OK, this is really stupid. RCS_checkout carefully removes
2546 write permissions, and we carefully put them back. But
2547 until someone gets around to fixing it, that seems like the
2548 easiest way to get what would seem to be the right mode.
2549 I don't check CVSWRITE or _watched; I haven't thought about
2550 that in great detail, but it seems like a watched file should
2551 be checked out (writable) after a merge. */
2552 xchmod (finfo->file, 1);
2553
2554 /* Hmm. We don't give them REV1 anywhere. I guess most people
2555 probably don't have a 3-way merge tool for the file type in
2556 question, and might just get confused if we tried to either
2557 provide them with a copy of the file from REV1, or even just
2558 told them what REV1 is so they can get it themself, but it
2559 might be worth thinking about. */
2560 /* See comment in merge_file about the "nonmergeable file"
2561 terminology. */
2562 error (0, 0, "nonmergeable file needs merge");
2563 error (0, 0, "revision %s from repository is now in %s",
2564 rev2, finfo->fullname);
2565 error (0, 0, "file from working directory is now in %s", backup);
2566 write_letter (finfo, 'C');
2567 }
2568 else
2569 status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
2570 t_options, rev1, rev2);
2571
2572 if (status != 0)
2573 {
2574 if (status != 1)
2575 {
2576 error (0, status == -1 ? errno : 0,
2577 "could not merge revision %s of %s", rev2, finfo->fullname);
2578 error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
2579 finfo->fullname, backup);
2580 rename_file (backup, finfo->file);
2581 }
2582 }
2583 else /* status == 0 */
2584 {
2585 /* FIXME: the noexec case is broken. RCS_merge could be doing the
2586 xcmp on the temporary files without much hassle, I think. */
2587 if (!noexec && !xcmp (backup, finfo->file))
2588 {
2589 if (!really_quiet)
2590 {
2591 cvs_output (finfo->fullname, 0);
2592 cvs_output (" already contains the differences between ", 0);
2593 cvs_output (rev1, 0);
2594 cvs_output (" and ", 0);
2595 cvs_output (rev2, 0);
2596 cvs_output ("\n", 1);
2597 }
2598
2599 /* and skip the registering and sending the new file since it
2600 * hasn't been updated.
2601 */
2602 goto out;
2603 }
2604 }
2605
2606 /* The file has changed, but if we just checked it out it may
2607 still have the same timestamp it did when it was first
2608 registered above in checkout_file. We register it again with a
2609 dummy timestamp to make sure that later runs of CVS will
2610 recognize that it has changed.
2611
2612 We don't actually need to register again if we called
2613 RCS_checkout above, and we aren't running as the server.
2614 However, that is not the normal case, and calling Register
2615 again won't cost much in that case. */
2616 RegisterMerge (finfo, vers, backup, status);
2617
2618 out:
2619 free (rev1);
2620 free (rev2);
2621 free (backup);
2622 }
2623
2624
2625
2626 /*
2627 * Report whether revisions REV1 and REV2 of FINFO agree on:
2628 * . file ownership
2629 * . permissions
2630 * . major and minor device numbers
2631 * . symbolic links
2632 * . hard links
2633 *
2634 * If either REV1 or REV2 is NULL, the working copy is used instead.
2635 *
2636 * Return 1 if the files differ on these data.
2637 */
2638
2639 int
special_file_mismatch(struct file_info * finfo,char * rev1,char * rev2)2640 special_file_mismatch (struct file_info *finfo, char *rev1, char *rev2)
2641 {
2642 #ifdef PRESERVE_PERMISSIONS_SUPPORT
2643 struct stat sb;
2644 RCSVers *vp;
2645 Node *n;
2646 uid_t rev1_uid, rev2_uid;
2647 gid_t rev1_gid, rev2_gid;
2648 mode_t rev1_mode, rev2_mode;
2649 unsigned long dev_long;
2650 dev_t rev1_dev, rev2_dev;
2651 char *rev1_symlink = NULL;
2652 char *rev2_symlink = NULL;
2653 List *rev1_hardlinks = NULL;
2654 List *rev2_hardlinks = NULL;
2655 int check_uids, check_gids, check_modes;
2656 int result;
2657
2658 /* If we don't care about special file info, then
2659 don't report a mismatch in any case. */
2660 if (!preserve_perms)
2661 return 0;
2662
2663 /* When special_file_mismatch is called from No_Difference, the
2664 RCS file has been only partially parsed. We must read the
2665 delta tree in order to compare special file info recorded in
2666 the delta nodes. (I think this is safe. -twp) */
2667 if (finfo->rcs->flags & PARTIAL)
2668 RCS_reparsercsfile (finfo->rcs, NULL, NULL);
2669
2670 check_uids = check_gids = check_modes = 1;
2671
2672 /* Obtain file information for REV1. If this is null, then stat
2673 finfo->file and use that info. */
2674 /* If a revision does not know anything about its status,
2675 then presumably it doesn't matter, and indicates no conflict. */
2676
2677 if (rev1 == NULL)
2678 {
2679 ssize_t rsize;
2680
2681 if ((rsize = islink (finfo->file, &sb)) > 0)
2682 rev1_symlink = Xreadlink (finfo->file, rsize);
2683 else
2684 {
2685 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2686 if (sb.st_ino == -1)
2687 error (1, errno, "could not get file information for %s",
2688 finfo->file);
2689 rev1_uid = sb.st_uid;
2690 rev1_gid = sb.st_gid;
2691 rev1_mode = sb.st_mode;
2692 if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode))
2693 rev1_dev = sb.st_rdev;
2694 # else
2695 error (1, 0, "cannot handle device files on this system (%s)",
2696 finfo->file);
2697 # endif
2698 }
2699 rev1_hardlinks = list_linked_files_on_disk (finfo->file);
2700 }
2701 else
2702 {
2703 n = findnode (finfo->rcs->versions, rev1);
2704 vp = n->data;
2705
2706 n = findnode (vp->other_delta, "symlink");
2707 if (n != NULL)
2708 rev1_symlink = xstrdup (n->data);
2709 else
2710 {
2711 n = findnode (vp->other_delta, "owner");
2712 if (n == NULL)
2713 check_uids = 0; /* don't care */
2714 else
2715 rev1_uid = strtoul (n->data, NULL, 10);
2716
2717 n = findnode (vp->other_delta, "group");
2718 if (n == NULL)
2719 check_gids = 0; /* don't care */
2720 else
2721 rev1_gid = strtoul (n->data, NULL, 10);
2722
2723 n = findnode (vp->other_delta, "permissions");
2724 if (n == NULL)
2725 check_modes = 0; /* don't care */
2726 else
2727 rev1_mode = strtoul (n->data, NULL, 8);
2728
2729 n = findnode (vp->other_delta, "special");
2730 if (n == NULL)
2731 rev1_mode |= S_IFREG;
2732 else
2733 {
2734 /* If the size of `ftype' changes, fix the sscanf call also */
2735 char ftype[16];
2736 if (sscanf (n->data, "%15s %lu", ftype,
2737 &dev_long) < 2)
2738 error (1, 0, "%s:%s has bad `special' newphrase %s",
2739 finfo->file, rev1, (char *)n->data);
2740 rev1_dev = dev_long;
2741 if (strcmp (ftype, "character") == 0)
2742 rev1_mode |= S_IFCHR;
2743 else if (strcmp (ftype, "block") == 0)
2744 rev1_mode |= S_IFBLK;
2745 else
2746 error (0, 0, "%s:%s unknown file type `%s'",
2747 finfo->file, rev1, ftype);
2748 }
2749
2750 rev1_hardlinks = vp->hardlinks;
2751 if (rev1_hardlinks == NULL)
2752 rev1_hardlinks = getlist();
2753 }
2754 }
2755
2756 /* Obtain file information for REV2. */
2757 if (rev2 == NULL)
2758 {
2759 ssize_t rsize;
2760
2761 if ((rsize = islink (finfo->file, &sb)) > 0)
2762 rev2_symlink = Xreadlink (finfo->file, rsize);
2763 else
2764 {
2765 # ifdef HAVE_STRUCT_STAT_ST_RDEV
2766 if (sb.st_ino == -1)
2767 error (1, errno, "could not get file information for %s",
2768 finfo->file);
2769 rev2_uid = sb.st_uid;
2770 rev2_gid = sb.st_gid;
2771 rev2_mode = sb.st_mode;
2772 if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode))
2773 rev2_dev = sb.st_rdev;
2774 # else
2775 error (1, 0, "cannot handle device files on this system (%s)",
2776 finfo->file);
2777 # endif
2778 }
2779 rev2_hardlinks = list_linked_files_on_disk (finfo->file);
2780 }
2781 else
2782 {
2783 n = findnode (finfo->rcs->versions, rev2);
2784 vp = n->data;
2785
2786 n = findnode (vp->other_delta, "symlink");
2787 if (n != NULL)
2788 rev2_symlink = xstrdup (n->data);
2789 else
2790 {
2791 n = findnode (vp->other_delta, "owner");
2792 if (n == NULL)
2793 check_uids = 0; /* don't care */
2794 else
2795 rev2_uid = strtoul (n->data, NULL, 10);
2796
2797 n = findnode (vp->other_delta, "group");
2798 if (n == NULL)
2799 check_gids = 0; /* don't care */
2800 else
2801 rev2_gid = strtoul (n->data, NULL, 10);
2802
2803 n = findnode (vp->other_delta, "permissions");
2804 if (n == NULL)
2805 check_modes = 0; /* don't care */
2806 else
2807 rev2_mode = strtoul (n->data, NULL, 8);
2808
2809 n = findnode (vp->other_delta, "special");
2810 if (n == NULL)
2811 rev2_mode |= S_IFREG;
2812 else
2813 {
2814 /* If the size of `ftype' changes, fix the sscanf call also */
2815 char ftype[16];
2816 if (sscanf (n->data, "%15s %lu", ftype,
2817 &dev_long) < 2)
2818 error (1, 0, "%s:%s has bad `special' newphrase %s",
2819 finfo->file, rev2, (char *)n->data);
2820 rev2_dev = dev_long;
2821 if (strcmp (ftype, "character") == 0)
2822 rev2_mode |= S_IFCHR;
2823 else if (strcmp (ftype, "block") == 0)
2824 rev2_mode |= S_IFBLK;
2825 else
2826 error (0, 0, "%s:%s unknown file type `%s'",
2827 finfo->file, rev2, ftype);
2828 }
2829
2830 rev2_hardlinks = vp->hardlinks;
2831 if (rev2_hardlinks == NULL)
2832 rev2_hardlinks = getlist();
2833 }
2834 }
2835
2836 /* Check the user/group ownerships and file permissions, printing
2837 an error for each mismatch found. Return 0 if all characteristics
2838 matched, and 1 otherwise. */
2839
2840 result = 0;
2841
2842 /* Compare symlinks first, since symlinks are simpler (don't have
2843 any other characteristics). */
2844 if (rev1_symlink != NULL && rev2_symlink == NULL)
2845 {
2846 error (0, 0, "%s is a symbolic link",
2847 (rev1 == NULL ? "working file" : rev1));
2848 result = 1;
2849 }
2850 else if (rev1_symlink == NULL && rev2_symlink != NULL)
2851 {
2852 error (0, 0, "%s is a symbolic link",
2853 (rev2 == NULL ? "working file" : rev2));
2854 result = 1;
2855 }
2856 else if (rev1_symlink != NULL)
2857 result = (strcmp (rev1_symlink, rev2_symlink) == 0);
2858 else
2859 {
2860 /* Compare user ownership. */
2861 if (check_uids && rev1_uid != rev2_uid)
2862 {
2863 error (0, 0, "%s: owner mismatch between %s and %s",
2864 finfo->file,
2865 (rev1 == NULL ? "working file" : rev1),
2866 (rev2 == NULL ? "working file" : rev2));
2867 result = 1;
2868 }
2869
2870 /* Compare group ownership. */
2871 if (check_gids && rev1_gid != rev2_gid)
2872 {
2873 error (0, 0, "%s: group mismatch between %s and %s",
2874 finfo->file,
2875 (rev1 == NULL ? "working file" : rev1),
2876 (rev2 == NULL ? "working file" : rev2));
2877 result = 1;
2878 }
2879
2880 /* Compare permissions. */
2881 if (check_modes &&
2882 (rev1_mode & 07777) != (rev2_mode & 07777))
2883 {
2884 error (0, 0, "%s: permission mismatch between %s and %s",
2885 finfo->file,
2886 (rev1 == NULL ? "working file" : rev1),
2887 (rev2 == NULL ? "working file" : rev2));
2888 result = 1;
2889 }
2890
2891 /* Compare device file characteristics. */
2892 if ((rev1_mode & S_IFMT) != (rev2_mode & S_IFMT))
2893 {
2894 error (0, 0, "%s: %s and %s are different file types",
2895 finfo->file,
2896 (rev1 == NULL ? "working file" : rev1),
2897 (rev2 == NULL ? "working file" : rev2));
2898 result = 1;
2899 }
2900 else if (S_ISBLK (rev1_mode))
2901 {
2902 if (rev1_dev != rev2_dev)
2903 {
2904 error (0, 0, "%s: device numbers of %s and %s do not match",
2905 finfo->file,
2906 (rev1 == NULL ? "working file" : rev1),
2907 (rev2 == NULL ? "working file" : rev2));
2908 result = 1;
2909 }
2910 }
2911
2912 /* Compare hard links. */
2913 if (compare_linkage_lists (rev1_hardlinks, rev2_hardlinks) == 0)
2914 {
2915 error (0, 0, "%s: hard linkage of %s and %s do not match",
2916 finfo->file,
2917 (rev1 == NULL ? "working file" : rev1),
2918 (rev2 == NULL ? "working file" : rev2));
2919 result = 1;
2920 }
2921 }
2922
2923 if (rev1_symlink != NULL)
2924 free (rev1_symlink);
2925 if (rev2_symlink != NULL)
2926 free (rev2_symlink);
2927 if (rev1_hardlinks != NULL)
2928 dellist (&rev1_hardlinks);
2929 if (rev2_hardlinks != NULL)
2930 dellist (&rev2_hardlinks);
2931
2932 return result;
2933 #else
2934 return 0;
2935 #endif
2936 }
2937
2938
2939
2940 int
joining(void)2941 joining (void)
2942 {
2943 return join_rev1 || join_date1;
2944 }
2945