1*223285fdStobias /* $OpenBSD: diff.c,v 1.143 2008/06/20 13:59:14 tobias 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 318ebd92267Sjoris 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) { 333*223285fdStobias if (rev1 != NULL) { 334fd687d09Stobias cvs_log(LP_ERR, "tag %s not in file %s", rev1, 335fd687d09Stobias cf->file_path); 336*223285fdStobias goto cleanup; 337*223285fdStobias } else if (Nflag) { 338*223285fdStobias diff_rev1 = NULL; 339*223285fdStobias } else { 3406534056aStobias gmtime_r(&cvs_specified_date, &datetm); 341be756b91Stobias strftime(tbuf, sizeof(tbuf), 3426534056aStobias "%Y.%m.%d.%H.%M.%S", &datetm); 343be756b91Stobias cvs_log(LP_ERR, "no revision for date %s in " 344be756b91Stobias "file %s", tbuf, cf->file_path); 345fd687d09Stobias goto cleanup; 346*223285fdStobias } 347fd687d09Stobias } else if (diff_rev1 == NULL && cvs_cmdop == CVS_OP_RDIFF && 348fd687d09Stobias force_head) { 349fd660bf2Stobias /* -f is not allowed for unknown symbols */ 350fd687d09Stobias if ((diff_rev1 = rcsnum_parse(rev1)) == NULL) 351fd660bf2Stobias fatal("no such tag %s", rev1); 352fd660bf2Stobias rcsnum_free(diff_rev1); 353fd660bf2Stobias 354fd687d09Stobias diff_rev1 = cf->file_rcs->rf_head; 355fd660bf2Stobias } 356be756b91Stobias cvs_specified_date = -1; 357fd687d09Stobias } else if (cvs_cmdop == CVS_OP_DIFF) { 358fd687d09Stobias if (cf->file_ent->ce_status == CVS_ENT_ADDED) 359fd687d09Stobias diff_rev1 = NULL; 360fd687d09Stobias else 361fd687d09Stobias diff_rev1 = cf->file_ent->ce_rev; 362fd660bf2Stobias } 36351ef6581Sjoris 364fd687d09Stobias if (cf->file_rcs == NULL) 365fd687d09Stobias diff_rev2 = NULL; 366be756b91Stobias else if (rev2 != NULL || date2 != -1) { 367be756b91Stobias cvs_specified_date = date2; 368fd687d09Stobias diff_rev2 = rcs_translate_tag(rev2, cf->file_rcs); 369fd687d09Stobias if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_DIFF) { 370be756b91Stobias if (rev2 != NULL) { 371fd687d09Stobias cvs_log(LP_ERR, "tag %s not in file %s", rev2, 372fd687d09Stobias cf->file_path); 373*223285fdStobias goto cleanup; 374*223285fdStobias } else if (Nflag) { 375*223285fdStobias diff_rev2 = NULL; 376be756b91Stobias } else { 3776534056aStobias gmtime_r(&cvs_specified_date, &datetm); 378be756b91Stobias strftime(tbuf, sizeof(tbuf), 3796534056aStobias "%Y.%m.%d.%H.%M.%S", &datetm); 380be756b91Stobias cvs_log(LP_ERR, "no revision for date %s in " 381be756b91Stobias "file %s", tbuf, cf->file_path); 382fd687d09Stobias goto cleanup; 383*223285fdStobias } 384fd687d09Stobias } else if (diff_rev2 == NULL && cvs_cmdop == CVS_OP_RDIFF && 385fd687d09Stobias force_head) { 386fd660bf2Stobias /* -f is not allowed for unknown symbols */ 387fd687d09Stobias if ((diff_rev2 = rcsnum_parse(rev2)) == NULL) 388fd660bf2Stobias fatal("no such tag %s", rev2); 389fd660bf2Stobias rcsnum_free(diff_rev2); 390fd660bf2Stobias 391fd687d09Stobias diff_rev2 = cf->file_rcs->rf_head; 392fd660bf2Stobias } 393be756b91Stobias cvs_specified_date = -1; 394fd687d09Stobias } else if (cvs_cmdop == CVS_OP_RDIFF) 395fd687d09Stobias diff_rev2 = cf->file_rcs->rf_head; 396fd687d09Stobias else if (cf->file_ent->ce_status == CVS_ENT_REMOVED) 397fd687d09Stobias diff_rev2 = NULL; 398fd687d09Stobias 399fd687d09Stobias if (diff_rev1 != NULL && diff_rev2 != NULL && 400fd687d09Stobias rcsnum_cmp(diff_rev1, diff_rev2, 0) == 0) 401fd687d09Stobias goto cleanup; 402fd687d09Stobias 403fd687d09Stobias switch (cvs_cmdop) { 404fd687d09Stobias case CVS_OP_DIFF: 405*223285fdStobias if (cf->file_status == FILE_UPTODATE && diff_rev1 != NULL && 406fd687d09Stobias rcsnum_cmp(diff_rev1, cf->file_rcsrev, 0) == 0) 407fd687d09Stobias goto cleanup; 408fd687d09Stobias break; 409fd687d09Stobias case CVS_OP_RDIFF: 410fd687d09Stobias if (diff_rev1 == NULL && diff_rev2 == NULL) 411fd687d09Stobias goto cleanup; 412fd687d09Stobias break; 413fd660bf2Stobias } 414fd660bf2Stobias 415fd660bf2Stobias cvs_printf("Index: %s\n", cf->file_path); 416fd660bf2Stobias if (cvs_cmdop == CVS_OP_DIFF) 417fd687d09Stobias cvs_printf("%s\nRCS file: %s\n", RCS_DIFF_DIV, 418fd687d09Stobias cf->file_rcs != NULL ? cf->file_rpath : cf->file_path); 419fd660bf2Stobias 420fd660bf2Stobias if (diff_rev1 != NULL) { 421fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF && diff_rev1 != NULL) { 422fd687d09Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 423fd687d09Stobias cvs_printf("retrieving revision %s\n", rbuf); 424fd687d09Stobias } 4253ad3fb45Sjoris 426fd687d09Stobias tv[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev1); 4273ad3fb45Sjoris tv[0].tv_usec = 0; 4283ad3fb45Sjoris tv[1] = tv[0]; 429741443cbSjoris 430fd687d09Stobias (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 431fd687d09Stobias fd1 = rcs_rev_write_stmp(cf->file_rcs, diff_rev1, p1, 0); 4322e0d696aSjoris if (futimes(fd1, tv) == -1) 433fd660bf2Stobias fatal("cvs_diff_local: utimes failed"); 434fd660bf2Stobias } 4353ad3fb45Sjoris 436fd687d09Stobias if (diff_rev2 != NULL) { 437fd687d09Stobias if (cvs_cmdop == CVS_OP_DIFF && rev2 != NULL) { 438fd660bf2Stobias (void)rcsnum_tostr(diff_rev2, rbuf, sizeof(rbuf)); 439fd687d09Stobias cvs_printf("retrieving revision %s\n", rbuf); 440fd687d09Stobias } 4413ad3fb45Sjoris 4423ad3fb45Sjoris tv2[0].tv_sec = rcs_rev_getdate(cf->file_rcs, diff_rev2); 4433ad3fb45Sjoris tv2[0].tv_usec = 0; 4443ad3fb45Sjoris tv2[1] = tv2[0]; 445741443cbSjoris 446fd687d09Stobias (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 4472e0d696aSjoris fd2 = rcs_rev_write_stmp(cf->file_rcs, diff_rev2, p2, 0); 4482e0d696aSjoris if (futimes(fd2, tv2) == -1) 449fd660bf2Stobias fatal("cvs_diff_local: utimes failed"); 450fd687d09Stobias } else if (cvs_cmdop == CVS_OP_DIFF && cf->fd != -1 && 451fd687d09Stobias cf->file_ent->ce_status != CVS_ENT_REMOVED) { 4523ad3fb45Sjoris if (fstat(cf->fd, &st) == -1) 4533ad3fb45Sjoris fatal("fstat failed %s", strerror(errno)); 4549aad96bcStobias b1 = cvs_buf_load_fd(cf->fd); 4553ad3fb45Sjoris 4563ad3fb45Sjoris tv2[0].tv_sec = st.st_mtime; 4573ad3fb45Sjoris tv2[0].tv_usec = 0; 4583ad3fb45Sjoris tv2[1] = tv2[0]; 459741443cbSjoris 460fd687d09Stobias (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 4612e0d696aSjoris fd2 = cvs_buf_write_stmp(b1, p2, tv2); 462741443cbSjoris cvs_buf_free(b1); 4633ad3fb45Sjoris } 4643ad3fb45Sjoris 465fd687d09Stobias switch (cvs_cmdop) { 466fd687d09Stobias case CVS_OP_DIFF: 4673ad3fb45Sjoris cvs_printf("%s", diffargs); 4683ad3fb45Sjoris 469fd687d09Stobias if (rev1 != NULL && diff_rev1 != NULL) { 470fd687d09Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 4713ad3fb45Sjoris cvs_printf(" -r%s", rbuf); 4723ad3fb45Sjoris 473fd687d09Stobias if (rev2 != NULL && diff_rev2 != NULL) { 474fd660bf2Stobias (void)rcsnum_tostr(diff_rev2, rbuf, 475fd660bf2Stobias sizeof(rbuf)); 4763ad3fb45Sjoris cvs_printf(" -r%s", rbuf); 4773ad3fb45Sjoris } 47867caf486Sjoris } 4793ad3fb45Sjoris 480fd660bf2Stobias if (diff_rev2 == NULL) 481fd687d09Stobias cvs_printf(" %s", cf->file_path); 48209d59ca3Stobias cvs_printf("\n"); 483fd687d09Stobias break; 484fd687d09Stobias case CVS_OP_RDIFF: 485fd660bf2Stobias cvs_printf("diff "); 486fd660bf2Stobias switch (diff_format) { 487fd660bf2Stobias case D_CONTEXT: 488fd660bf2Stobias cvs_printf("-c "); 489fd660bf2Stobias break; 490fd660bf2Stobias case D_RCSDIFF: 491fd660bf2Stobias cvs_printf("-n "); 492fd660bf2Stobias break; 493fd660bf2Stobias case D_UNIFIED: 494fd660bf2Stobias cvs_printf("-u "); 495fd660bf2Stobias break; 496fd660bf2Stobias default: 497fd660bf2Stobias break; 498fd660bf2Stobias } 499fd660bf2Stobias if (diff_rev1 == NULL) { 500fd660bf2Stobias cvs_printf("%s ", CVS_PATH_DEVNULL); 501fd660bf2Stobias } else { 502fd660bf2Stobias (void)rcsnum_tostr(diff_rev1, rbuf, sizeof(rbuf)); 503fd660bf2Stobias cvs_printf("%s:%s ", cf->file_path, rbuf); 504fd660bf2Stobias } 5053ad3fb45Sjoris 506fd660bf2Stobias if (diff_rev2 == NULL) { 507fd660bf2Stobias cvs_printf("%s:removed\n", cf->file_path); 508fd660bf2Stobias } else { 509fd660bf2Stobias (void)rcsnum_tostr(diff_rev2 != NULL ? diff_rev2 : 510fd660bf2Stobias cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); 511fd660bf2Stobias cvs_printf("%s:%s\n", cf->file_path, rbuf); 512fd660bf2Stobias } 513fd687d09Stobias break; 514fd660bf2Stobias } 515fd660bf2Stobias 516fd687d09Stobias if (fd1 == -1) { 517fd687d09Stobias if ((fd1 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) 518fd687d09Stobias fatal("cannot open %s", CVS_PATH_DEVNULL); 519fd687d09Stobias } 520fd687d09Stobias if (fd2 == -1) { 521fd687d09Stobias if ((fd2 = open(CVS_PATH_DEVNULL, O_RDONLY, 0)) == -1) 522fd687d09Stobias fatal("cannot open %s", CVS_PATH_DEVNULL); 523741443cbSjoris } 5243ad3fb45Sjoris 525fd687d09Stobias if (cvs_diffreg(p1 != NULL ? cf->file_path : CVS_PATH_DEVNULL, 526fd687d09Stobias p2 != NULL ? cf->file_path : CVS_PATH_DEVNULL, fd1, fd2, NULL) 527fd687d09Stobias == D_ERROR) 528d71a0c9bSxsa fatal("cvs_diff_local: failed to get RCS patch"); 529d71a0c9bSxsa 5302e0d696aSjoris close(fd1); 5312e0d696aSjoris close(fd2); 5322e0d696aSjoris 5333ad3fb45Sjoris cvs_worklist_run(&temp_files, cvs_worklist_unlink); 53467caf486Sjoris 535d71a0c9bSxsa if (p1 != NULL) 536d71a0c9bSxsa xfree(p1); 537d71a0c9bSxsa if (p2 != NULL) 538d71a0c9bSxsa xfree(p2); 539d71a0c9bSxsa 540fd687d09Stobias cleanup: 541fd687d09Stobias if (diff_rev1 != NULL && 542fd687d09Stobias (cf->file_rcs == NULL || diff_rev1 != cf->file_rcs->rf_head) && 543fd687d09Stobias (cf->file_ent == NULL || diff_rev1 != cf->file_ent->ce_rev)) 544fd687d09Stobias xfree(diff_rev1); 545fd687d09Stobias diff_rev1 = NULL; 546261cb0daSjoris 547fd687d09Stobias if (diff_rev2 != NULL && 548fd687d09Stobias (cf->file_rcs == NULL || diff_rev2 != cf->file_rcs->rf_head)) 549fd687d09Stobias xfree(diff_rev2); 550fd687d09Stobias diff_rev2 = NULL; 551f9b67873Sniallo } 552