1*e91b8a58Sjoris /* $OpenBSD: diff.c,v 1.149 2009/04/02 21:13:50 joris Exp $ */ 208f90673Sjfb /* 3fd687d09Stobias * Copyright (c) 2008 Tobias Stoeckmann <tobias@openbsd.org> 43ad3fb45Sjoris * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 508f90673Sjfb * 63ad3fb45Sjoris * Permission to use, copy, modify, and distribute this software for any 73ad3fb45Sjoris * purpose with or without fee is hereby granted, provided that the above 83ad3fb45Sjoris * copyright notice and this permission notice appear in all copies. 908f90673Sjfb * 103ad3fb45Sjoris * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 113ad3fb45Sjoris * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 123ad3fb45Sjoris * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 133ad3fb45Sjoris * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 143ad3fb45Sjoris * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 153ad3fb45Sjoris * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 163ad3fb45Sjoris * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1708f90673Sjfb */ 1808f90673Sjfb 191f8531bdSotto #include <sys/stat.h> 20fd660bf2Stobias #include <sys/time.h> 211f8531bdSotto 221f8531bdSotto #include <errno.h> 232e0d696aSjoris #include <fcntl.h> 24fd660bf2Stobias #include <stdlib.h> 251f8531bdSotto #include <string.h> 266534056aStobias #include <time.h> 271f8531bdSotto #include <unistd.h> 2808f90673Sjfb 2908f90673Sjfb #include "cvs.h" 30af5bb824Sniallo #include "diff.h" 319fac60a5Sjoris #include "remote.h" 3208f90673Sjfb 333ad3fb45Sjoris void cvs_diff_local(struct cvs_file *); 34ec6ed1abSjoris 354230e8b3Sjoris static int Nflag = 0; 36fd660bf2Stobias static int force_head = 0; 3737fdff3fStobias static char *koptstr; 384230e8b3Sjoris static char *rev1 = NULL; 394230e8b3Sjoris static char *rev2 = NULL; 40be756b91Stobias static time_t date1 = -1; 41be756b91Stobias static time_t date2 = -1; 42909bf3e0Stobias static char *dateflag1 = NULL; 43909bf3e0Stobias static char *dateflag2 = NULL; 4467caf486Sjoris 45e4276007Sjfb struct cvs_cmd cvs_cmd_diff = { 46f331ff59Stobias CVS_OP_DIFF, CVS_USE_WDIR, "diff", 47e4276007Sjfb { "di", "dif" }, 48e4276007Sjfb "Show differences between revisions", 49bcf22459Stobias "[-cilNnpRu] [[-D date] [-r rev] [-D date2 | -r rev2]] " 50c9150269Sxsa "[-k mode] [file ...]", 5137fdff3fStobias "cfD:ik:lNnpr:Ru", 52fd660bf2Stobias NULL, 53fd660bf2Stobias cvs_diff 54fd660bf2Stobias }; 55fd660bf2Stobias 56fd660bf2Stobias struct cvs_cmd cvs_cmd_rdiff = { 57fd660bf2Stobias CVS_OP_RDIFF, 0, "rdiff", 58fd660bf2Stobias { "patch", "pa" }, 59fd660bf2Stobias "Show differences between revisions", 60fd660bf2Stobias "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev\n" 61fd660bf2Stobias "[-D date2 | -r rev2] [-k mode] module ...", 6237fdff3fStobias "cfD:k:lr:RuV:", 6316cfc147Sjoris NULL, 643ad3fb45Sjoris cvs_diff 65e4276007Sjfb }; 66e4276007Sjfb 673ad3fb45Sjoris int 683ad3fb45Sjoris cvs_diff(int argc, char **argv) 6908f90673Sjfb { 70e9d83458Stobias int ch, flags; 713ad3fb45Sjoris char *arg = "."; 723ad3fb45Sjoris struct cvs_recursion cr; 7308f90673Sjfb 741890abdaSjoris flags = CR_RECURSE_DIRS; 75bc6ad1fbStobias strlcpy(diffargs, cvs_cmdop == CVS_OP_DIFF ? "diff" : "rdiff", 76bc6ad1fbStobias sizeof(diffargs)); 77dc6a6879Sjfb 78e9d83458Stobias while ((ch = getopt(argc, argv, cvs_cmdop == CVS_OP_DIFF ? 79e9d83458Stobias cvs_cmd_diff.cmd_opts : cvs_cmd_rdiff.cmd_opts)) != -1) { 8008f90673Sjfb switch (ch) { 8108f90673Sjfb case 'c': 82f5638424Sjfb strlcat(diffargs, " -c", sizeof(diffargs)); 83f9b67873Sniallo diff_format = D_CONTEXT; 8408f90673Sjfb break; 85be756b91Stobias case 'D': 86be756b91Stobias if (date1 == -1 && rev1 == NULL) { 87be756b91Stobias date1 = cvs_date_parse(optarg); 88909bf3e0Stobias dateflag1 = optarg; 89be756b91Stobias } else if (date2 == -1 && rev2 == NULL) { 90be756b91Stobias date2 = cvs_date_parse(optarg); 91909bf3e0Stobias dateflag2 = optarg; 92be756b91Stobias } else { 93be756b91Stobias fatal("no more than 2 revisions/dates can" 94be756b91Stobias " be specified"); 95be756b91Stobias } 96be756b91Stobias break; 97fd660bf2Stobias case 'f': 98fd660bf2Stobias force_head = 1; 99fd660bf2Stobias break; 100fd660bf2Stobias case 'i': 101fd660bf2Stobias strlcat(diffargs, " -i", sizeof(diffargs)); 102fd660bf2Stobias diff_iflag = 1; 103fd660bf2Stobias break; 10437fdff3fStobias case 'k': 10537fdff3fStobias koptstr = optarg; 10637fdff3fStobias kflag = rcs_kflag_get(koptstr); 10737fdff3fStobias if (RCS_KWEXP_INVAL(kflag)) { 10837fdff3fStobias cvs_log(LP_ERR, 1090bc1d395Stobias "invalid RCS keyword expansion mode"); 110aeaaf4a6Stobias fatal("%s", cvs_cmdop == CVS_OP_DIFF ? 111aeaaf4a6Stobias cvs_cmd_diff.cmd_synopsis : 112aeaaf4a6Stobias cvs_cmd_rdiff.cmd_synopsis); 11337fdff3fStobias } 11437fdff3fStobias break; 1151890abdaSjoris case 'l': 1161890abdaSjoris flags &= ~CR_RECURSE_DIRS; 1171890abdaSjoris break; 118394180a4Sjfb case 'n': 119394180a4Sjfb strlcat(diffargs, " -n", sizeof(diffargs)); 120f9b67873Sniallo diff_format = D_RCSDIFF; 121394180a4Sjfb break; 12267caf486Sjoris case 'N': 123fd687d09Stobias strlcat(diffargs, " -N", sizeof(diffargs)); 1242d6f447eSjoris Nflag = 1; 12567caf486Sjoris break; 126261cb0daSjoris case 'p': 127261cb0daSjoris strlcat(diffargs, " -p", sizeof(diffargs)); 128261cb0daSjoris diff_pflag = 1; 129261cb0daSjoris break; 130bcf22459Stobias case 'R': 131bcf22459Stobias flags |= CR_RECURSE_DIRS; 132bcf22459Stobias break; 13308f90673Sjfb case 'r': 134be756b91Stobias if (date1 == -1 && rev1 == NULL) { 1354230e8b3Sjoris rev1 = optarg; 136be756b91Stobias } else if (date2 == -1 && rev2 == NULL) { 1374230e8b3Sjoris rev2 = optarg; 13816cfc147Sjoris } else { 1393ad3fb45Sjoris fatal("no more than 2 revisions/dates can" 14008f90673Sjfb " be specified"); 14108f90673Sjfb } 14208f90673Sjfb break; 14308f90673Sjfb case 'u': 144f5638424Sjfb strlcat(diffargs, " -u", sizeof(diffargs)); 145f9b67873Sniallo diff_format = D_UNIFIED; 14608f90673Sjfb break; 14737fdff3fStobias case 'V': 14837fdff3fStobias fatal("the -V option is obsolete " 14937fdff3fStobias "and should not be used"); 15008f90673Sjfb default: 151aeaaf4a6Stobias fatal("%s", cvs_cmdop == CVS_OP_DIFF ? 152aeaaf4a6Stobias cvs_cmd_diff.cmd_synopsis : 153aeaaf4a6Stobias cvs_cmd_rdiff.cmd_synopsis); 15408f90673Sjfb } 15508f90673Sjfb } 15608f90673Sjfb 1573ad3fb45Sjoris argc -= optind; 1583ad3fb45Sjoris argv += optind; 159dc6a6879Sjfb 1603ad3fb45Sjoris cr.enterdir = NULL; 1613ad3fb45Sjoris cr.leavedir = NULL; 1629fac60a5Sjoris 163fd660bf2Stobias if (cvs_cmdop == CVS_OP_RDIFF) { 164909bf3e0Stobias if (rev1 == NULL && rev2 == NULL && dateflag1 == NULL && 165909bf3e0Stobias dateflag2 == NULL) 166fd660bf2Stobias fatal("must specify at least one revision/date!"); 167fd660bf2Stobias 168fd687d09Stobias if (!argc) 169fd687d09Stobias fatal("%s", cvs_cmd_rdiff.cmd_synopsis); 170fd687d09Stobias 171fd660bf2Stobias if (!diff_format) { 172fd660bf2Stobias strlcat(diffargs, " -c", sizeof(diffargs)); 173fd660bf2Stobias diff_format = D_CONTEXT; 174fd660bf2Stobias } 175fd660bf2Stobias 176fd660bf2Stobias flags |= CR_REPO; 177fd660bf2Stobias } 178fd660bf2Stobias 1799fac60a5Sjoris if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 18080f6ca9bSjoris cvs_client_connect_to_server(); 1819fac60a5Sjoris cr.fileproc = cvs_client_sendfile; 1829fac60a5Sjoris 1839fac60a5Sjoris if (!(flags & CR_RECURSE_DIRS)) 1849fac60a5Sjoris cvs_client_send_request("Argument -l"); 1859fac60a5Sjoris 18637fdff3fStobias if (kflag) 18737fdff3fStobias cvs_client_send_request("Argument -k%s", koptstr); 18837fdff3fStobias 1899fac60a5Sjoris switch (diff_format) { 1909fac60a5Sjoris case D_CONTEXT: 1919fac60a5Sjoris cvs_client_send_request("Argument -c"); 1929fac60a5Sjoris break; 1939fac60a5Sjoris case D_RCSDIFF: 1949fac60a5Sjoris cvs_client_send_request("Argument -n"); 1959fac60a5Sjoris break; 1969fac60a5Sjoris case D_UNIFIED: 1979fac60a5Sjoris cvs_client_send_request("Argument -u"); 1989fac60a5Sjoris break; 1999fac60a5Sjoris default: 2009fac60a5Sjoris break; 2019fac60a5Sjoris } 2029fac60a5Sjoris 2039fac60a5Sjoris if (Nflag == 1) 2049fac60a5Sjoris cvs_client_send_request("Argument -N"); 2059fac60a5Sjoris 2069fac60a5Sjoris if (diff_pflag == 1) 2079fac60a5Sjoris cvs_client_send_request("Argument -p"); 2089fac60a5Sjoris 2099fac60a5Sjoris if (rev1 != NULL) 2109fac60a5Sjoris cvs_client_send_request("Argument -r%s", rev1); 2119fac60a5Sjoris if (rev2 != NULL) 2129fac60a5Sjoris cvs_client_send_request("Argument -r%s", rev2); 213909bf3e0Stobias 214909bf3e0Stobias if (dateflag1 != NULL) 215909bf3e0Stobias cvs_client_send_request("Argument -D%s", dateflag1); 216909bf3e0Stobias if (dateflag2 != NULL) 217909bf3e0Stobias cvs_client_send_request("Argument -D%s", dateflag2); 2189fac60a5Sjoris } else { 219fd660bf2Stobias if (cvs_cmdop == CVS_OP_RDIFF && 220fd660bf2Stobias chdir(current_cvsroot->cr_dir) == -1) 221fd660bf2Stobias fatal("cvs_diff: %s", strerror(errno)); 222fd660bf2Stobias 223bc5d89feSjoris cr.fileproc = cvs_diff_local; 2249fac60a5Sjoris } 2259fac60a5Sjoris 2261890abdaSjoris cr.flags = flags; 227dc6a6879Sjfb 2284230e8b3Sjoris diff_rev1 = diff_rev2 = NULL; 2294230e8b3Sjoris 230fd660bf2Stobias if (cvs_cmdop == CVS_OP_DIFF || 231fd660bf2Stobias current_cvsroot->cr_method == CVS_METHOD_LOCAL) { 2323ad3fb45Sjoris if (argc > 0) 2333ad3fb45Sjoris cvs_file_run(argc, argv, &cr); 234d990145dSray else 2353ad3fb45Sjoris cvs_file_run(1, &arg, &cr); 236fd660bf2Stobias } 237e4276007Sjfb 2389fac60a5Sjoris if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 2399fac60a5Sjoris cvs_client_send_files(argv, argc); 2409fac60a5Sjoris cvs_client_senddir("."); 241fd660bf2Stobias 242fd660bf2Stobias cvs_client_send_request((cvs_cmdop == CVS_OP_RDIFF) ? 243fd660bf2Stobias "rdiff" : "diff"); 244fd660bf2Stobias 2459fac60a5Sjoris cvs_client_get_responses(); 2469fac60a5Sjoris } 2479fac60a5Sjoris 248e4276007Sjfb return (0); 249e4276007Sjfb } 250e4276007Sjfb 25101af718aSjoris void 2523ad3fb45Sjoris cvs_diff_local(struct cvs_file *cf) 253f9b67873Sniallo { 254741443cbSjoris BUF *b1; 2552e0d696aSjoris int fd1, fd2; 2563ad3fb45Sjoris struct stat st; 2573ad3fb45Sjoris struct timeval tv[2], tv2[2]; 2586534056aStobias struct tm datetm; 259be756b91Stobias char rbuf[CVS_REV_BUFSZ], tbuf[CVS_TIME_BUFSZ], *p1, *p2; 260d71a0c9bSxsa 261741443cbSjoris b1 = NULL; 262fd687d09Stobias fd1 = fd2 = -1; 263fd687d09Stobias p1 = p2 = NULL; 264f9b67873Sniallo 2653ad3fb45Sjoris cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path); 2663ad3fb45Sjoris 2673ad3fb45Sjoris if (cf->file_type == CVS_DIR) { 2683ad3fb45Sjoris if (verbosity > 1) 2691489d205Sjoris cvs_log(LP_ERR, "Diffing inside %s", cf->file_path); 2703ad3fb45Sjoris return; 2713ad3fb45Sjoris } 2723ad3fb45Sjoris 27351ef6581Sjoris cvs_file_classify(cf, cvs_directory_tag); 2743ad3fb45Sjoris 275fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF) { 276fd687d09Stobias if (cf->file_ent == NULL) { 277fd687d09Stobias cvs_log(LP_ERR, "I know nothing about %s", 27867caf486Sjoris cf->file_path); 2793ad3fb45Sjoris return; 28067caf486Sjoris } 2813ad3fb45Sjoris 282fd687d09Stobias switch (cf->file_ent->ce_status) { 283fd687d09Stobias case CVS_ENT_ADDED: 284fd687d09Stobias if (Nflag == 0) { 285fd687d09Stobias cvs_log(LP_ERR, "%s is a new entry, no " 286fd687d09Stobias "comparison available", cf->file_path); 287fd687d09Stobias return; 288fd687d09Stobias } 2895cf15c45Sjoris if (!(cf->file_flags & FILE_ON_DISK)) { 290fd687d09Stobias cvs_log(LP_ERR, "cannot find %s", 291fd687d09Stobias cf->file_path); 292fd687d09Stobias return; 293fd687d09Stobias } 294fd687d09Stobias break; 295fd687d09Stobias case CVS_ENT_REMOVED: 296fd687d09Stobias if (Nflag == 0) { 297fd687d09Stobias cvs_log(LP_ERR, "%s was removed, no " 298fd687d09Stobias "comparison available", cf->file_path); 299fd687d09Stobias return; 300fd687d09Stobias } 301fd687d09Stobias if (cf->file_rcs == NULL) { 302fd687d09Stobias cvs_log(LP_ERR, "cannot find RCS file for %s", 303fd687d09Stobias cf->file_path); 304fd687d09Stobias return; 305fd687d09Stobias } 306fd687d09Stobias break; 307fd687d09Stobias default: 3085cf15c45Sjoris if (!(cf->file_flags & FILE_ON_DISK)) { 3091489d205Sjoris cvs_printf("? %s\n", cf->file_path); 310fd687d09Stobias return; 311fd687d09Stobias } 312c638a04bSjoris 313fd687d09Stobias if (cf->file_rcs == NULL) { 314fd687d09Stobias cvs_log(LP_ERR, "cannot find RCS file for %s", 315fd687d09Stobias cf->file_path); 316fd687d09Stobias return; 317fd687d09Stobias } 318fd687d09Stobias break; 319fd687d09Stobias } 320fd687d09Stobias } 321fd687d09Stobias 322be756b91Stobias if (cf->file_status == FILE_UPTODATE && rev1 == NULL && rev2 == NULL && 323be756b91Stobias date1 == -1 && date2 == -1) 324fd687d09Stobias return; 325fd687d09Stobias 326ebd92267Sjoris if (cf->file_rcs != NULL && cf->file_rcs->rf_head == NULL) { 327e28eda4eStobias cvs_log(LP_ERR, "no head revision in RCS file for %s\n", 328e28eda4eStobias cf->file_path); 329e28eda4eStobias return; 330e28eda4eStobias } 331e28eda4eStobias 332fd687d09Stobias if (kflag && cf->file_rcs != NULL) 33337fdff3fStobias rcs_kwexp_set(cf->file_rcs, kflag); 33437fdff3fStobias 335fd687d09Stobias if (cf->file_rcs == NULL) 336fd687d09Stobias diff_rev1 = NULL; 337be756b91Stobias else if (rev1 != NULL || date1 != -1) { 338be756b91Stobias cvs_specified_date = date1; 339fd687d09Stobias diff_rev1 = rcs_translate_tag(rev1, cf->file_rcs); 340fd687d09Stobias if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_DIFF) { 341223285fdStobias if (rev1 != NULL) { 342fd687d09Stobias cvs_log(LP_ERR, "tag %s not in file %s", rev1, 343fd687d09Stobias cf->file_path); 344223285fdStobias goto cleanup; 345223285fdStobias } else if (Nflag) { 346223285fdStobias diff_rev1 = NULL; 347223285fdStobias } else { 3486534056aStobias gmtime_r(&cvs_specified_date, &datetm); 349be756b91Stobias strftime(tbuf, sizeof(tbuf), 3506534056aStobias "%Y.%m.%d.%H.%M.%S", &datetm); 351be756b91Stobias cvs_log(LP_ERR, "no revision for date %s in " 352be756b91Stobias "file %s", tbuf, cf->file_path); 353fd687d09Stobias goto cleanup; 354223285fdStobias } 355fd687d09Stobias } else if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_RDIFF && 356fd687d09Stobias force_head) { 357fd660bf2Stobias /* -f is not allowed for unknown symbols */ 358fd687d09Stobias if ((diff_rev1 = rcsnum_parse(rev1)) == NULL) 359fd660bf2Stobias fatal("no such tag %s", rev1); 360fd660bf2Stobias rcsnum_free(diff_rev1); 361fd660bf2Stobias 362fd687d09Stobias diff_rev1 = cf->file_rcs->rf_head; 363fd660bf2Stobias } 364be756b91Stobias cvs_specified_date = -1; 365fd687d09Stobias } else if (cvs_cmdop == CVS_OP_DIFF) { 366fd687d09Stobias if (cf->file_ent->ce_status == CVS_ENT_ADDED) 367fd687d09Stobias diff_rev1 = NULL; 368fd687d09Stobias else 369fd687d09Stobias diff_rev1 = cf->file_ent->ce_rev; 370fd660bf2Stobias } 37151ef6581Sjoris 372fd687d09Stobias if (cf->file_rcs == NULL) 373fd687d09Stobias diff_rev2 = NULL; 374be756b91Stobias else if (rev2 != NULL || date2 != -1) { 375be756b91Stobias cvs_specified_date = date2; 376fd687d09Stobias diff_rev2 = rcs_translate_tag(rev2, cf->file_rcs); 377fd687d09Stobias if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_DIFF) { 378be756b91Stobias if (rev2 != NULL) { 379fd687d09Stobias cvs_log(LP_ERR, "tag %s not in file %s", rev2, 380fd687d09Stobias cf->file_path); 381223285fdStobias goto cleanup; 382223285fdStobias } else if (Nflag) { 383223285fdStobias diff_rev2 = NULL; 384be756b91Stobias } else { 3856534056aStobias gmtime_r(&cvs_specified_date, &datetm); 386be756b91Stobias strftime(tbuf, sizeof(tbuf), 3876534056aStobias "%Y.%m.%d.%H.%M.%S", &datetm); 388be756b91Stobias cvs_log(LP_ERR, "no revision for date %s in " 389be756b91Stobias "file %s", tbuf, cf->file_path); 390fd687d09Stobias goto cleanup; 391223285fdStobias } 392fd687d09Stobias } else if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_RDIFF && 393fd687d09Stobias force_head) { 394fd660bf2Stobias /* -f is not allowed for unknown symbols */ 395fd687d09Stobias if ((diff_rev2 = rcsnum_parse(rev2)) == NULL) 396fd660bf2Stobias fatal("no such tag %s", rev2); 397fd660bf2Stobias rcsnum_free(diff_rev2); 398fd660bf2Stobias 399fd687d09Stobias diff_rev2 = cf->file_rcs->rf_head; 400fd660bf2Stobias } 401be756b91Stobias cvs_specified_date = -1; 402fd687d09Stobias } else if (cvs_cmdop == CVS_OP_RDIFF) 403fd687d09Stobias diff_rev2 = cf->file_rcs->rf_head; 404fd687d09Stobias else if (cf->file_ent->ce_status == CVS_ENT_REMOVED) 405fd687d09Stobias diff_rev2 = NULL; 406fd687d09Stobias 407fd687d09Stobias if (diff_rev1 != NULL && diff_rev2 != NULL && 408fd687d09Stobias rcsnum_cmp(diff_rev1, diff_rev2, 0) == 0) 409fd687d09Stobias goto cleanup; 410fd687d09Stobias 411fd687d09Stobias switch (cvs_cmdop) { 412fd687d09Stobias case CVS_OP_DIFF: 413*e91b8a58Sjoris if (diff_rev1 != NULL && diff_rev2 == NULL && 414*e91b8a58Sjoris rcsnum_cmp(diff_rev1, cf->file_ent->ce_rev, 0) == 0) 415fd687d09Stobias goto cleanup; 416fd687d09Stobias break; 417fd687d09Stobias case CVS_OP_RDIFF: 418fd687d09Stobias if (diff_rev1 == NULL && diff_rev2 == NULL) 419fd687d09Stobias goto cleanup; 420fd687d09Stobias break; 421fd660bf2Stobias } 422fd660bf2Stobias 423fd660bf2Stobias cvs_printf("Index: %s\n", cf->file_path); 424fd660bf2Stobias if (cvs_cmdop == CVS_OP_DIFF) 425fd687d09Stobias cvs_printf("%s\nRCS file: %s\n", RCS_DIFF_DIV, 426fd687d09Stobias cf->file_rcs != NULL ? cf->file_rpath : cf->file_path); 427fd660bf2Stobias 428fd660bf2Stobias if (diff_rev1 != NULL) { 429fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF && diff_rev1 != NULL) { 430fd687d09Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 431fd687d09Stobias cvs_printf("retrieving revision %s\n", rbuf); 432fd687d09Stobias } 4333ad3fb45Sjoris 434fd687d09Stobias tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev1); 4353ad3fb45Sjoris tv[0].tv_usec = 0; 4363ad3fb45Sjoris tv[1] = tv[0]; 437741443cbSjoris 438fd687d09Stobias (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 439fd687d09Stobias fd1 = rcs_rev_write_stmp(cf->file_rcs, diff_rev1, p1, 0); 4402e0d696aSjoris if (futimes(fd1, tv) == -1) 441fd660bf2Stobias fatal("cvs_diff_local: utimes failed"); 442fd660bf2Stobias } 4433ad3fb45Sjoris 444fd687d09Stobias if (diff_rev2 != NULL) { 445fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF && rev2 != NULL) { 446fd660bf2Stobias (void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); 447fd687d09Stobias cvs_printf("retrieving revision %s\n", rbuf); 448fd687d09Stobias } 4493ad3fb45Sjoris 4503ad3fb45Sjoris tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2); 4513ad3fb45Sjoris tv2[0].tv_usec = 0; 4523ad3fb45Sjoris tv2[1] = tv2[0]; 453741443cbSjoris 454fd687d09Stobias (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 4552e0d696aSjoris fd2 = rcs_rev_write_stmp(cf->file_rcs, diff_rev2, p2, 0); 4562e0d696aSjoris if (futimes(fd2, tv2) == -1) 457fd660bf2Stobias fatal("cvs_diff_local: utimes failed"); 4585cf15c45Sjoris } else if (cvs_cmdop == CVS_OP_DIFF && 4595cf15c45Sjoris (cf->file_flags & FILE_ON_DISK) && 460fd687d09Stobias cf->file_ent->ce_status != CVS_ENT_REMOVED) { 461*e91b8a58Sjoris (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 462*e91b8a58Sjoris if (cvs_server_active == 1 && cf->fd == -1) { 463*e91b8a58Sjoris tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, 464*e91b8a58Sjoris cf->file_ent->ce_rev); 465*e91b8a58Sjoris tv2[0].tv_usec = 0; 466*e91b8a58Sjoris tv2[1] = tv2[0]; 467*e91b8a58Sjoris 468*e91b8a58Sjoris fd2 = rcs_rev_write_stmp(cf->file_rcs, 469*e91b8a58Sjoris cf->file_ent->ce_rev, p2, 0); 470*e91b8a58Sjoris if (futimes(fd2, tv2) == -1) 471*e91b8a58Sjoris fatal("cvs_diff_local: futimes failed"); 472*e91b8a58Sjoris } else { 4733ad3fb45Sjoris if (fstat(cf->fd, &st) == -1) 4743ad3fb45Sjoris fatal("fstat failed %s", strerror(errno)); 4759aad96bcStobias b1 = cvs_buf_load_fd(cf->fd); 4763ad3fb45Sjoris 4773ad3fb45Sjoris tv2[0].tv_sec = st.st_mtime; 4783ad3fb45Sjoris tv2[0].tv_usec = 0; 4793ad3fb45Sjoris tv2[1] = tv2[0]; 480741443cbSjoris 4812e0d696aSjoris fd2 = cvs_buf_write_stmp(b1, p2, tv2); 482741443cbSjoris cvs_buf_free(b1); 4833ad3fb45Sjoris } 484*e91b8a58Sjoris } 4853ad3fb45Sjoris 486fd687d09Stobias switch (cvs_cmdop) { 487fd687d09Stobias case CVS_OP_DIFF: 4883ad3fb45Sjoris cvs_printf("%s", diffargs); 4893ad3fb45Sjoris 490fd687d09Stobias if (rev1 != NULL && diff_rev1 != NULL) { 491fd687d09Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 4923ad3fb45Sjoris cvs_printf(" -r%s", rbuf); 4933ad3fb45Sjoris 494fd687d09Stobias if (rev2 != NULL && diff_rev2 != NULL) { 495fd660bf2Stobias (void)rcsnum_tostr(diff_rev2, rbuf, 496fd660bf2Stobias sizeof(rbuf)); 4973ad3fb45Sjoris cvs_printf(" -r%s", rbuf); 4983ad3fb45Sjoris } 49967caf486Sjoris } 5003ad3fb45Sjoris 501fd660bf2Stobias if (diff_rev2 == NULL) 502fd687d09Stobias cvs_printf(" %s", cf->file_path); 50309d59ca3Stobias cvs_printf("\n"); 504fd687d09Stobias break; 505fd687d09Stobias case CVS_OP_RDIFF: 506fd660bf2Stobias cvs_printf("diff "); 507fd660bf2Stobias switch (diff_format) { 508fd660bf2Stobias case D_CONTEXT: 509fd660bf2Stobias cvs_printf("-c "); 510fd660bf2Stobias break; 511fd660bf2Stobias case D_RCSDIFF: 512fd660bf2Stobias cvs_printf("-n "); 513fd660bf2Stobias break; 514fd660bf2Stobias case D_UNIFIED: 515fd660bf2Stobias cvs_printf("-u "); 516fd660bf2Stobias break; 517fd660bf2Stobias default: 518fd660bf2Stobias break; 519fd660bf2Stobias } 520fd660bf2Stobias if (diff_rev1 == NULL) { 521fd660bf2Stobias cvs_printf("%s ", CVS_PATH_DEVNULL); 522fd660bf2Stobias } else { 523fd660bf2Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 524fd660bf2Stobias cvs_printf("%s:%s ", cf->file_path, rbuf); 525fd660bf2Stobias } 5263ad3fb45Sjoris 527fd660bf2Stobias if (diff_rev2 == NULL) { 528fd660bf2Stobias cvs_printf("%s:removed\n", cf->file_path); 529fd660bf2Stobias } else { 530fd660bf2Stobias (void)rcsnum_tostr(diff_rev2 != NULL ? diff_rev2 : 531fd660bf2Stobias cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); 532fd660bf2Stobias cvs_printf("%s:%s\n", cf->file_path, rbuf); 533fd660bf2Stobias } 534fd687d09Stobias break; 535fd660bf2Stobias } 536fd660bf2Stobias 537fd687d09Stobias if (fd1 == -1) { 538fd687d09Stobias if ((fd1 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) 539fd687d09Stobias fatal("cannot open %s", CVS_PATH_DEVNULL); 540fd687d09Stobias } 541fd687d09Stobias if (fd2 == -1) { 542fd687d09Stobias if ((fd2 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) 543fd687d09Stobias fatal("cannot open %s", CVS_PATH_DEVNULL); 544741443cbSjoris } 5453ad3fb45Sjoris 546fd687d09Stobias if (cvs_diffreg(p1 != NULL ? cf->file_path : CVS_PATH_DEVNULL, 547fd687d09Stobias p2 != NULL ? cf->file_path : CVS_PATH_DEVNULL, fd1, fd2, NULL) 548fd687d09Stobias == D_ERROR) 549d71a0c9bSxsa fatal("cvs_diff_local: failed to get RCS patch"); 550d71a0c9bSxsa 5512e0d696aSjoris close(fd1); 5522e0d696aSjoris close(fd2); 5532e0d696aSjoris 5543ad3fb45Sjoris cvs_worklist_run(&temp_files, cvs_worklist_unlink); 55567caf486Sjoris 556d71a0c9bSxsa if (p1 != NULL) 557d71a0c9bSxsa xfree(p1); 558d71a0c9bSxsa if (p2 != NULL) 559d71a0c9bSxsa xfree(p2); 560d71a0c9bSxsa 561fd687d09Stobias cleanup: 562fd687d09Stobias if (diff_rev1 != NULL && 563fd687d09Stobias (cf->file_rcs == NULL || diff_rev1 != cf->file_rcs->rf_head) && 564fd687d09Stobias (cf->file_ent == NULL || diff_rev1 != cf->file_ent->ce_rev)) 565fd687d09Stobias xfree(diff_rev1); 566fd687d09Stobias diff_rev1 = NULL; 567261cb0daSjoris 568fd687d09Stobias if (diff_rev2 != NULL && 569fd687d09Stobias (cf->file_rcs == NULL || diff_rev2 != cf->file_rcs->rf_head)) 570fd687d09Stobias xfree(diff_rev2); 571fd687d09Stobias diff_rev2 = NULL; 572f9b67873Sniallo } 573