1*ebd92267Sjoris /* $OpenBSD: diff.c,v 1.142 2008/06/17 06:38:21 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; 4267caf486Sjoris 43e4276007Sjfb struct cvs_cmd cvs_cmd_diff = { 44f331ff59Stobias CVS_OP_DIFF, CVS_USE_WDIR, "diff", 45e4276007Sjfb { "di", "dif" }, 46e4276007Sjfb "Show differences between revisions", 47bcf22459Stobias "[-cilNnpRu] [[-D date] [-r rev] [-D date2 | -r rev2]] " 48c9150269Sxsa "[-k mode] [file ...]", 4937fdff3fStobias "cfD:ik:lNnpr:Ru", 50fd660bf2Stobias NULL, 51fd660bf2Stobias cvs_diff 52fd660bf2Stobias }; 53fd660bf2Stobias 54fd660bf2Stobias struct cvs_cmd cvs_cmd_rdiff = { 55fd660bf2Stobias CVS_OP_RDIFF, 0, "rdiff", 56fd660bf2Stobias { "patch", "pa" }, 57fd660bf2Stobias "Show differences between revisions", 58fd660bf2Stobias "[-flR] [-c | -u] [-s | -t] [-V ver] -D date | -r rev\n" 59fd660bf2Stobias "[-D date2 | -r rev2] [-k mode] module ...", 6037fdff3fStobias "cfD:k:lr:RuV:", 6116cfc147Sjoris NULL, 623ad3fb45Sjoris cvs_diff 63e4276007Sjfb }; 64e4276007Sjfb 653ad3fb45Sjoris int 663ad3fb45Sjoris cvs_diff(int argc, char **argv) 6708f90673Sjfb { 68e9d83458Stobias int ch, flags; 693ad3fb45Sjoris char *arg = "."; 703ad3fb45Sjoris struct cvs_recursion cr; 7108f90673Sjfb 721890abdaSjoris flags = CR_RECURSE_DIRS; 73bc6ad1fbStobias strlcpy(diffargs, cvs_cmdop == CVS_OP_DIFF ? "diff" : "rdiff", 74bc6ad1fbStobias sizeof(diffargs)); 75dc6a6879Sjfb 76e9d83458Stobias while ((ch = getopt(argc, argv, cvs_cmdop == CVS_OP_DIFF ? 77e9d83458Stobias cvs_cmd_diff.cmd_opts : cvs_cmd_rdiff.cmd_opts)) != -1) { 7808f90673Sjfb switch (ch) { 7908f90673Sjfb case 'c': 80f5638424Sjfb strlcat(diffargs, " -c", sizeof(diffargs)); 81f9b67873Sniallo diff_format = D_CONTEXT; 8208f90673Sjfb break; 83be756b91Stobias case 'D': 84be756b91Stobias if (date1 == -1 && rev1 == NULL) { 85be756b91Stobias date1 = cvs_date_parse(optarg); 86be756b91Stobias } else if (date2 == -1 && rev2 == NULL) { 87be756b91Stobias date2 = cvs_date_parse(optarg); 88be756b91Stobias } else { 89be756b91Stobias fatal("no more than 2 revisions/dates can" 90be756b91Stobias " be specified"); 91be756b91Stobias } 92be756b91Stobias break; 93fd660bf2Stobias case 'f': 94fd660bf2Stobias force_head = 1; 95fd660bf2Stobias break; 96fd660bf2Stobias case 'i': 97fd660bf2Stobias strlcat(diffargs, " -i", sizeof(diffargs)); 98fd660bf2Stobias diff_iflag = 1; 99fd660bf2Stobias break; 10037fdff3fStobias case 'k': 10137fdff3fStobias koptstr = optarg; 10237fdff3fStobias kflag = rcs_kflag_get(koptstr); 10337fdff3fStobias if (RCS_KWEXP_INVAL(kflag)) { 10437fdff3fStobias cvs_log(LP_ERR, 1050bc1d395Stobias "invalid RCS keyword expansion mode"); 106aeaaf4a6Stobias fatal("%s", cvs_cmdop == CVS_OP_DIFF ? 107aeaaf4a6Stobias cvs_cmd_diff.cmd_synopsis : 108aeaaf4a6Stobias cvs_cmd_rdiff.cmd_synopsis); 10937fdff3fStobias } 11037fdff3fStobias break; 1111890abdaSjoris case 'l': 1121890abdaSjoris flags &= ~CR_RECURSE_DIRS; 1131890abdaSjoris break; 114394180a4Sjfb case 'n': 115394180a4Sjfb strlcat(diffargs, " -n", sizeof(diffargs)); 116f9b67873Sniallo diff_format = D_RCSDIFF; 117394180a4Sjfb break; 11867caf486Sjoris case 'N': 119fd687d09Stobias strlcat(diffargs, " -N", sizeof(diffargs)); 1202d6f447eSjoris Nflag = 1; 12167caf486Sjoris break; 122261cb0daSjoris case 'p': 123261cb0daSjoris strlcat(diffargs, " -p", sizeof(diffargs)); 124261cb0daSjoris diff_pflag = 1; 125261cb0daSjoris break; 126bcf22459Stobias case 'R': 127bcf22459Stobias flags |= CR_RECURSE_DIRS; 128bcf22459Stobias break; 12908f90673Sjfb case 'r': 130be756b91Stobias if (date1 == -1 && rev1 == NULL) { 1314230e8b3Sjoris rev1 = optarg; 132be756b91Stobias } else if (date2 == -1 && rev2 == NULL) { 1334230e8b3Sjoris rev2 = optarg; 13416cfc147Sjoris } else { 1353ad3fb45Sjoris fatal("no more than 2 revisions/dates can" 13608f90673Sjfb " be specified"); 13708f90673Sjfb } 13808f90673Sjfb break; 13908f90673Sjfb case 'u': 140f5638424Sjfb strlcat(diffargs, " -u", sizeof(diffargs)); 141f9b67873Sniallo diff_format = D_UNIFIED; 14208f90673Sjfb break; 14337fdff3fStobias case 'V': 14437fdff3fStobias fatal("the -V option is obsolete " 14537fdff3fStobias "and should not be used"); 14608f90673Sjfb default: 147aeaaf4a6Stobias fatal("%s", cvs_cmdop == CVS_OP_DIFF ? 148aeaaf4a6Stobias cvs_cmd_diff.cmd_synopsis : 149aeaaf4a6Stobias cvs_cmd_rdiff.cmd_synopsis); 15008f90673Sjfb } 15108f90673Sjfb } 15208f90673Sjfb 1533ad3fb45Sjoris argc -= optind; 1543ad3fb45Sjoris argv += optind; 155dc6a6879Sjfb 1563ad3fb45Sjoris cr.enterdir = NULL; 1573ad3fb45Sjoris cr.leavedir = NULL; 1589fac60a5Sjoris 159fd660bf2Stobias if (cvs_cmdop == CVS_OP_RDIFF) { 160fd660bf2Stobias if (rev1 == NULL) 161fd660bf2Stobias fatal("must specify at least one revision/date!"); 162fd660bf2Stobias 163fd687d09Stobias if (!argc) 164fd687d09Stobias fatal("%s", cvs_cmd_rdiff.cmd_synopsis); 165fd687d09Stobias 166fd660bf2Stobias if (!diff_format) { 167fd660bf2Stobias strlcat(diffargs, " -c", sizeof(diffargs)); 168fd660bf2Stobias diff_format = D_CONTEXT; 169fd660bf2Stobias } 170fd660bf2Stobias 171fd660bf2Stobias flags |= CR_REPO; 172fd660bf2Stobias } 173fd660bf2Stobias 1749fac60a5Sjoris if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 17580f6ca9bSjoris cvs_client_connect_to_server(); 1769fac60a5Sjoris cr.fileproc = cvs_client_sendfile; 1779fac60a5Sjoris 1789fac60a5Sjoris if (!(flags & CR_RECURSE_DIRS)) 1799fac60a5Sjoris cvs_client_send_request("Argument -l"); 1809fac60a5Sjoris 18137fdff3fStobias if (kflag) 18237fdff3fStobias cvs_client_send_request("Argument -k%s", koptstr); 18337fdff3fStobias 1849fac60a5Sjoris switch (diff_format) { 1859fac60a5Sjoris case D_CONTEXT: 1869fac60a5Sjoris cvs_client_send_request("Argument -c"); 1879fac60a5Sjoris break; 1889fac60a5Sjoris case D_RCSDIFF: 1899fac60a5Sjoris cvs_client_send_request("Argument -n"); 1909fac60a5Sjoris break; 1919fac60a5Sjoris case D_UNIFIED: 1929fac60a5Sjoris cvs_client_send_request("Argument -u"); 1939fac60a5Sjoris break; 1949fac60a5Sjoris default: 1959fac60a5Sjoris break; 1969fac60a5Sjoris } 1979fac60a5Sjoris 1989fac60a5Sjoris if (Nflag == 1) 1999fac60a5Sjoris cvs_client_send_request("Argument -N"); 2009fac60a5Sjoris 2019fac60a5Sjoris if (diff_pflag == 1) 2029fac60a5Sjoris cvs_client_send_request("Argument -p"); 2039fac60a5Sjoris 2049fac60a5Sjoris if (rev1 != NULL) 2059fac60a5Sjoris cvs_client_send_request("Argument -r%s", rev1); 2069fac60a5Sjoris if (rev2 != NULL) 2079fac60a5Sjoris cvs_client_send_request("Argument -r%s", rev2); 2089fac60a5Sjoris } else { 209fd660bf2Stobias if (cvs_cmdop == CVS_OP_RDIFF && 210fd660bf2Stobias chdir(current_cvsroot->cr_dir) == -1) 211fd660bf2Stobias fatal("cvs_diff: %s", strerror(errno)); 212fd660bf2Stobias 213bc5d89feSjoris cr.fileproc = cvs_diff_local; 2149fac60a5Sjoris } 2159fac60a5Sjoris 2161890abdaSjoris cr.flags = flags; 217dc6a6879Sjfb 2184230e8b3Sjoris diff_rev1 = diff_rev2 = NULL; 2194230e8b3Sjoris 220fd660bf2Stobias if (cvs_cmdop == CVS_OP_DIFF || 221fd660bf2Stobias current_cvsroot->cr_method == CVS_METHOD_LOCAL) { 2223ad3fb45Sjoris if (argc > 0) 2233ad3fb45Sjoris cvs_file_run(argc, argv, &cr); 224d990145dSray else 2253ad3fb45Sjoris cvs_file_run(1, &arg, &cr); 226fd660bf2Stobias } 227e4276007Sjfb 2289fac60a5Sjoris if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 2299fac60a5Sjoris cvs_client_send_files(argv, argc); 2309fac60a5Sjoris cvs_client_senddir("."); 231fd660bf2Stobias 232fd660bf2Stobias cvs_client_send_request((cvs_cmdop == CVS_OP_RDIFF) ? 233fd660bf2Stobias "rdiff" : "diff"); 234fd660bf2Stobias 2359fac60a5Sjoris cvs_client_get_responses(); 2369fac60a5Sjoris } 2379fac60a5Sjoris 238e4276007Sjfb return (0); 239e4276007Sjfb } 240e4276007Sjfb 24101af718aSjoris void 2423ad3fb45Sjoris cvs_diff_local(struct cvs_file *cf) 243f9b67873Sniallo { 244741443cbSjoris BUF *b1; 2452e0d696aSjoris int fd1, fd2; 2463ad3fb45Sjoris struct stat st; 2473ad3fb45Sjoris struct timeval tv[2], tv2[2]; 2486534056aStobias struct tm datetm; 249be756b91Stobias char rbuf[CVS_REV_BUFSZ], tbuf[CVS_TIME_BUFSZ], *p1, *p2; 250d71a0c9bSxsa 251741443cbSjoris b1 = NULL; 252fd687d09Stobias fd1 = fd2 = -1; 253fd687d09Stobias p1 = p2 = NULL; 254f9b67873Sniallo 2553ad3fb45Sjoris cvs_log(LP_TRACE, "cvs_diff_local(%s)", cf->file_path); 2563ad3fb45Sjoris 2573ad3fb45Sjoris if (cf->file_type == CVS_DIR) { 2583ad3fb45Sjoris if (verbosity > 1) 2593ad3fb45Sjoris cvs_log(LP_NOTICE, "Diffing inside %s", cf->file_path); 2603ad3fb45Sjoris return; 2613ad3fb45Sjoris } 2623ad3fb45Sjoris 26351ef6581Sjoris cvs_file_classify(cf, cvs_directory_tag); 2643ad3fb45Sjoris 265fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF) { 266fd687d09Stobias if (cf->file_ent == NULL) { 267fd687d09Stobias cvs_log(LP_ERR, "I know nothing about %s", 26867caf486Sjoris cf->file_path); 2693ad3fb45Sjoris return; 27067caf486Sjoris } 2713ad3fb45Sjoris 272fd687d09Stobias switch (cf->file_ent->ce_status) { 273fd687d09Stobias case CVS_ENT_ADDED: 274fd687d09Stobias if (Nflag == 0) { 275fd687d09Stobias cvs_log(LP_ERR, "%s is a new entry, no " 276fd687d09Stobias "comparison available", cf->file_path); 277fd687d09Stobias return; 278fd687d09Stobias } 279fd687d09Stobias if (cf->fd == -1) { 28010e77a1eStobias if (!cvs_server_active) 281fd687d09Stobias cvs_log(LP_ERR, "cannot find %s", 282fd687d09Stobias cf->file_path); 283fd687d09Stobias return; 284fd687d09Stobias } 285fd687d09Stobias break; 286fd687d09Stobias case CVS_ENT_REMOVED: 287fd687d09Stobias if (Nflag == 0) { 288fd687d09Stobias cvs_log(LP_ERR, "%s was removed, no " 289fd687d09Stobias "comparison available", cf->file_path); 290fd687d09Stobias return; 291fd687d09Stobias } 292fd687d09Stobias if (cf->file_rcs == NULL) { 293fd687d09Stobias cvs_log(LP_ERR, "cannot find RCS file for %s", 294fd687d09Stobias cf->file_path); 295fd687d09Stobias return; 296fd687d09Stobias } 297fd687d09Stobias break; 298fd687d09Stobias default: 299c638a04bSjoris if (cvs_server_active != 1 && cf->fd == -1) { 300fd687d09Stobias cvs_log(LP_ERR, "cannot find %s", 301fd687d09Stobias cf->file_path); 302fd687d09Stobias return; 303fd687d09Stobias } 304c638a04bSjoris 305fd687d09Stobias if (cf->file_rcs == NULL) { 306fd687d09Stobias cvs_log(LP_ERR, "cannot find RCS file for %s", 307fd687d09Stobias cf->file_path); 308fd687d09Stobias return; 309fd687d09Stobias } 310fd687d09Stobias break; 311fd687d09Stobias } 312fd687d09Stobias } 313fd687d09Stobias 314be756b91Stobias if (cf->file_status == FILE_UPTODATE && rev1 == NULL && rev2 == NULL && 315be756b91Stobias date1 == -1 && date2 == -1) 316fd687d09Stobias return; 317fd687d09Stobias 318*ebd92267Sjoris if (cf->file_rcs != NULL && cf->file_rcs->rf_head == NULL) { 319e28eda4eStobias cvs_log(LP_ERR, "no head revision in RCS file for %s\n", 320e28eda4eStobias cf->file_path); 321e28eda4eStobias return; 322e28eda4eStobias } 323e28eda4eStobias 324fd687d09Stobias if (kflag && cf->file_rcs != NULL) 32537fdff3fStobias rcs_kwexp_set(cf->file_rcs, kflag); 32637fdff3fStobias 327fd687d09Stobias if (cf->file_rcs == NULL) 328fd687d09Stobias diff_rev1 = NULL; 329be756b91Stobias else if (rev1 != NULL || date1 != -1) { 330be756b91Stobias cvs_specified_date = date1; 331fd687d09Stobias diff_rev1 = rcs_translate_tag(rev1, cf->file_rcs); 332fd687d09Stobias if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_DIFF) { 333be756b91Stobias if (rev1 != NULL) 334fd687d09Stobias cvs_log(LP_ERR, "tag %s not in file %s", rev1, 335fd687d09Stobias cf->file_path); 336be756b91Stobias else { 3376534056aStobias gmtime_r(&cvs_specified_date, &datetm); 338be756b91Stobias strftime(tbuf, sizeof(tbuf), 3396534056aStobias "%Y.%m.%d.%H.%M.%S", &datetm); 340be756b91Stobias cvs_log(LP_ERR, "no revision for date %s in " 341be756b91Stobias "file %s", tbuf, cf->file_path); 342be756b91Stobias } 343fd687d09Stobias goto cleanup; 344fd687d09Stobias } else if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_RDIFF && 345fd687d09Stobias force_head) { 346fd660bf2Stobias /* -f is not allowed for unknown symbols */ 347fd687d09Stobias if ((diff_rev1 = rcsnum_parse(rev1)) == NULL) 348fd660bf2Stobias fatal("no such tag %s", rev1); 349fd660bf2Stobias rcsnum_free(diff_rev1); 350fd660bf2Stobias 351fd687d09Stobias diff_rev1 = cf->file_rcs->rf_head; 352fd660bf2Stobias } 353be756b91Stobias cvs_specified_date = -1; 354fd687d09Stobias } else if (cvs_cmdop == CVS_OP_DIFF) { 355fd687d09Stobias if (cf->file_ent->ce_status == CVS_ENT_ADDED) 356fd687d09Stobias diff_rev1 = NULL; 357fd687d09Stobias else 358fd687d09Stobias diff_rev1 = cf->file_ent->ce_rev; 359fd660bf2Stobias } 36051ef6581Sjoris 361fd687d09Stobias if (cf->file_rcs == NULL) 362fd687d09Stobias diff_rev2 = NULL; 363be756b91Stobias else if (rev2 != NULL || date2 != -1) { 364be756b91Stobias cvs_specified_date = date2; 365fd687d09Stobias diff_rev2 = rcs_translate_tag(rev2, cf->file_rcs); 366fd687d09Stobias if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_DIFF) { 367be756b91Stobias if (rev2 != NULL) { 368fd687d09Stobias cvs_log(LP_ERR, "tag %s not in file %s", rev2, 369fd687d09Stobias cf->file_path); 370be756b91Stobias } else { 3716534056aStobias gmtime_r(&cvs_specified_date, &datetm); 372be756b91Stobias strftime(tbuf, sizeof(tbuf), 3736534056aStobias "%Y.%m.%d.%H.%M.%S", &datetm); 374be756b91Stobias cvs_log(LP_ERR, "no revision for date %s in " 375be756b91Stobias "file %s", tbuf, cf->file_path); 376be756b91Stobias } 377fd687d09Stobias goto cleanup; 378fd687d09Stobias } else if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_RDIFF && 379fd687d09Stobias force_head) { 380fd660bf2Stobias /* -f is not allowed for unknown symbols */ 381fd687d09Stobias if ((diff_rev2 = rcsnum_parse(rev2)) == NULL) 382fd660bf2Stobias fatal("no such tag %s", rev2); 383fd660bf2Stobias rcsnum_free(diff_rev2); 384fd660bf2Stobias 385fd687d09Stobias diff_rev2 = cf->file_rcs->rf_head; 386fd660bf2Stobias } 387be756b91Stobias cvs_specified_date = -1; 388fd687d09Stobias } else if (cvs_cmdop == CVS_OP_RDIFF) 389fd687d09Stobias diff_rev2 = cf->file_rcs->rf_head; 390fd687d09Stobias else if (cf->file_ent->ce_status == CVS_ENT_REMOVED) 391fd687d09Stobias diff_rev2 = NULL; 392fd687d09Stobias 393fd687d09Stobias if (diff_rev1 != NULL && diff_rev2 != NULL && 394fd687d09Stobias rcsnum_cmp(diff_rev1, diff_rev2, 0) == 0) 395fd687d09Stobias goto cleanup; 396fd687d09Stobias 397fd687d09Stobias switch (cvs_cmdop) { 398fd687d09Stobias case CVS_OP_DIFF: 399fd687d09Stobias if (cf->file_status == FILE_UPTODATE && 400fd687d09Stobias rcsnum_cmp(diff_rev1, cf->file_rcsrev, 0) == 0) 401fd687d09Stobias goto cleanup; 402fd687d09Stobias break; 403fd687d09Stobias case CVS_OP_RDIFF: 404fd687d09Stobias if (diff_rev1 == NULL && diff_rev2 == NULL) 405fd687d09Stobias goto cleanup; 406fd687d09Stobias break; 407fd660bf2Stobias } 408fd660bf2Stobias 409fd660bf2Stobias cvs_printf("Index: %s\n", cf->file_path); 410fd660bf2Stobias if (cvs_cmdop == CVS_OP_DIFF) 411fd687d09Stobias cvs_printf("%s\nRCS file: %s\n", RCS_DIFF_DIV, 412fd687d09Stobias cf->file_rcs != NULL ? cf->file_rpath : cf->file_path); 413fd660bf2Stobias 414fd660bf2Stobias if (diff_rev1 != NULL) { 415fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF && diff_rev1 != NULL) { 416fd687d09Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 417fd687d09Stobias cvs_printf("retrieving revision %s\n", rbuf); 418fd687d09Stobias } 4193ad3fb45Sjoris 420fd687d09Stobias tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev1); 4213ad3fb45Sjoris tv[0].tv_usec = 0; 4223ad3fb45Sjoris tv[1] = tv[0]; 423741443cbSjoris 424fd687d09Stobias (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 425fd687d09Stobias fd1 = rcs_rev_write_stmp(cf->file_rcs, diff_rev1, p1, 0); 4262e0d696aSjoris if (futimes(fd1, tv) == -1) 427fd660bf2Stobias fatal("cvs_diff_local: utimes failed"); 428fd660bf2Stobias } 4293ad3fb45Sjoris 430fd687d09Stobias if (diff_rev2 != NULL) { 431fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF && rev2 != NULL) { 432fd660bf2Stobias (void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); 433fd687d09Stobias cvs_printf("retrieving revision %s\n", rbuf); 434fd687d09Stobias } 4353ad3fb45Sjoris 4363ad3fb45Sjoris tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2); 4373ad3fb45Sjoris tv2[0].tv_usec = 0; 4383ad3fb45Sjoris tv2[1] = tv2[0]; 439741443cbSjoris 440fd687d09Stobias (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 4412e0d696aSjoris fd2 = rcs_rev_write_stmp(cf->file_rcs, diff_rev2, p2, 0); 4422e0d696aSjoris if (futimes(fd2, tv2) == -1) 443fd660bf2Stobias fatal("cvs_diff_local: utimes failed"); 444fd687d09Stobias } else if (cvs_cmdop == CVS_OP_DIFF && cf->fd != -1 && 445fd687d09Stobias cf->file_ent->ce_status != CVS_ENT_REMOVED) { 4463ad3fb45Sjoris if (fstat(cf->fd, &st) == -1) 4473ad3fb45Sjoris fatal("fstat failed %s", strerror(errno)); 4489aad96bcStobias b1 = cvs_buf_load_fd(cf->fd); 4493ad3fb45Sjoris 4503ad3fb45Sjoris tv2[0].tv_sec = st.st_mtime; 4513ad3fb45Sjoris tv2[0].tv_usec = 0; 4523ad3fb45Sjoris tv2[1] = tv2[0]; 453741443cbSjoris 454fd687d09Stobias (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 4552e0d696aSjoris fd2 = cvs_buf_write_stmp(b1, p2, tv2); 456741443cbSjoris cvs_buf_free(b1); 4573ad3fb45Sjoris } 4583ad3fb45Sjoris 459fd687d09Stobias switch (cvs_cmdop) { 460fd687d09Stobias case CVS_OP_DIFF: 4613ad3fb45Sjoris cvs_printf("%s", diffargs); 4623ad3fb45Sjoris 463fd687d09Stobias if (rev1 != NULL && diff_rev1 != NULL) { 464fd687d09Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 4653ad3fb45Sjoris cvs_printf(" -r%s", rbuf); 4663ad3fb45Sjoris 467fd687d09Stobias if (rev2 != NULL && diff_rev2 != NULL) { 468fd660bf2Stobias (void)rcsnum_tostr(diff_rev2, rbuf, 469fd660bf2Stobias sizeof(rbuf)); 4703ad3fb45Sjoris cvs_printf(" -r%s", rbuf); 4713ad3fb45Sjoris } 47267caf486Sjoris } 4733ad3fb45Sjoris 474fd660bf2Stobias if (diff_rev2 == NULL) 475fd687d09Stobias cvs_printf(" %s", cf->file_path); 47609d59ca3Stobias cvs_printf("\n"); 477fd687d09Stobias break; 478fd687d09Stobias case CVS_OP_RDIFF: 479fd660bf2Stobias cvs_printf("diff "); 480fd660bf2Stobias switch (diff_format) { 481fd660bf2Stobias case D_CONTEXT: 482fd660bf2Stobias cvs_printf("-c "); 483fd660bf2Stobias break; 484fd660bf2Stobias case D_RCSDIFF: 485fd660bf2Stobias cvs_printf("-n "); 486fd660bf2Stobias break; 487fd660bf2Stobias case D_UNIFIED: 488fd660bf2Stobias cvs_printf("-u "); 489fd660bf2Stobias break; 490fd660bf2Stobias default: 491fd660bf2Stobias break; 492fd660bf2Stobias } 493fd660bf2Stobias if (diff_rev1 == NULL) { 494fd660bf2Stobias cvs_printf("%s ", CVS_PATH_DEVNULL); 495fd660bf2Stobias } else { 496fd660bf2Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 497fd660bf2Stobias cvs_printf("%s:%s ", cf->file_path, rbuf); 498fd660bf2Stobias } 4993ad3fb45Sjoris 500fd660bf2Stobias if (diff_rev2 == NULL) { 501fd660bf2Stobias cvs_printf("%s:removed\n", cf->file_path); 502fd660bf2Stobias } else { 503fd660bf2Stobias (void)rcsnum_tostr(diff_rev2 != NULL ? diff_rev2 : 504fd660bf2Stobias cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); 505fd660bf2Stobias cvs_printf("%s:%s\n", cf->file_path, rbuf); 506fd660bf2Stobias } 507fd687d09Stobias break; 508fd660bf2Stobias } 509fd660bf2Stobias 510fd687d09Stobias if (fd1 == -1) { 511fd687d09Stobias if ((fd1 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) 512fd687d09Stobias fatal("cannot open %s", CVS_PATH_DEVNULL); 513fd687d09Stobias } 514fd687d09Stobias if (fd2 == -1) { 515fd687d09Stobias if ((fd2 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) 516fd687d09Stobias fatal("cannot open %s", CVS_PATH_DEVNULL); 517741443cbSjoris } 5183ad3fb45Sjoris 519fd687d09Stobias if (cvs_diffreg(p1 != NULL ? cf->file_path : CVS_PATH_DEVNULL, 520fd687d09Stobias p2 != NULL ? cf->file_path : CVS_PATH_DEVNULL, fd1, fd2, NULL) 521fd687d09Stobias == D_ERROR) 522d71a0c9bSxsa fatal("cvs_diff_local: failed to get RCS patch"); 523d71a0c9bSxsa 5242e0d696aSjoris close(fd1); 5252e0d696aSjoris close(fd2); 5262e0d696aSjoris 5273ad3fb45Sjoris cvs_worklist_run(&temp_files, cvs_worklist_unlink); 52867caf486Sjoris 529d71a0c9bSxsa if (p1 != NULL) 530d71a0c9bSxsa xfree(p1); 531d71a0c9bSxsa if (p2 != NULL) 532d71a0c9bSxsa xfree(p2); 533d71a0c9bSxsa 534fd687d09Stobias cleanup: 535fd687d09Stobias if (diff_rev1 != NULL && 536fd687d09Stobias (cf->file_rcs == NULL || diff_rev1 != cf->file_rcs->rf_head) && 537fd687d09Stobias (cf->file_ent == NULL || diff_rev1 != cf->file_ent->ce_rev)) 538fd687d09Stobias xfree(diff_rev1); 539fd687d09Stobias diff_rev1 = NULL; 540261cb0daSjoris 541fd687d09Stobias if (diff_rev2 != NULL && 542fd687d09Stobias (cf->file_rcs == NULL || diff_rev2 != cf->file_rcs->rf_head)) 543fd687d09Stobias xfree(diff_rev2); 544fd687d09Stobias diff_rev2 = NULL; 545f9b67873Sniallo } 546