PageRenderTime 56ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/cvs/src/update.c

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