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