1*59c8e88eSDag-Erling Smørgrav/* 2*59c8e88eSDag-Erling Smørgrav * Copyright (c) 2017 Stefan Sperling <stsp@openbsd.org> 3*59c8e88eSDag-Erling Smørgrav * 4*59c8e88eSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 5*59c8e88eSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 6*59c8e88eSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 7*59c8e88eSDag-Erling Smørgrav * 8*59c8e88eSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9*59c8e88eSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10*59c8e88eSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11*59c8e88eSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12*59c8e88eSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13*59c8e88eSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14*59c8e88eSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15*59c8e88eSDag-Erling Smørgrav */ 16*59c8e88eSDag-Erling Smørgrav 17*59c8e88eSDag-Erling Smørgrav#include <sys/queue.h> 18*59c8e88eSDag-Erling Smørgrav#include <sys/stat.h> 19*59c8e88eSDag-Erling Smørgrav 20*59c8e88eSDag-Erling Smørgrav#include <stdbool.h> 21*59c8e88eSDag-Erling Smørgrav#include <stdio.h> 22*59c8e88eSDag-Erling Smørgrav#include <stdlib.h> 23*59c8e88eSDag-Erling Smørgrav#include <string.h> 24*59c8e88eSDag-Erling Smørgrav#include <limits.h> 25*59c8e88eSDag-Erling Smørgrav#include <sha1.h> 26*59c8e88eSDag-Erling Smørgrav#include <zlib.h> 27*59c8e88eSDag-Erling Smørgrav 28*59c8e88eSDag-Erling Smørgrav#include "got_object.h" 29*59c8e88eSDag-Erling Smørgrav#include "got_repository.h" 30*59c8e88eSDag-Erling Smørgrav#include "got_error.h" 31*59c8e88eSDag-Erling Smørgrav#include "got_diff.h" 32*59c8e88eSDag-Erling Smørgrav#include "got_opentemp.h" 33*59c8e88eSDag-Erling Smørgrav#include "got_path.h" 34*59c8e88eSDag-Erling Smørgrav#include "got_cancel.h" 35*59c8e88eSDag-Erling Smørgrav#include "got_worktree.h" 36*59c8e88eSDag-Erling Smørgrav 37*59c8e88eSDag-Erling Smørgrav#include "got_lib_diff.h" 38*59c8e88eSDag-Erling Smørgrav#include "got_lib_delta.h" 39*59c8e88eSDag-Erling Smørgrav#include "got_lib_inflate.h" 40*59c8e88eSDag-Erling Smørgrav#include "got_lib_object.h" 41*59c8e88eSDag-Erling Smørgrav 42*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 43*59c8e88eSDag-Erling Smørgravdiff_blobs(struct got_diffreg_result **resultp, 44*59c8e88eSDag-Erling Smørgravstruct got_blob_object *blob1, struct got_blob_object *blob2, 45*59c8e88eSDag-Erling Smørgrav const char *label1, const char *label2, mode_t mode1, mode_t mode2, 46*59c8e88eSDag-Erling Smørgrav int diff_context, int ignore_whitespace, FILE *outfile) 47*59c8e88eSDag-Erling Smørgrav{ 48*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL, *free_err; 49*59c8e88eSDag-Erling Smørgrav FILE *f1 = NULL, *f2 = NULL; 50*59c8e88eSDag-Erling Smørgrav char hex1[SHA1_DIGEST_STRING_LENGTH]; 51*59c8e88eSDag-Erling Smørgrav char hex2[SHA1_DIGEST_STRING_LENGTH]; 52*59c8e88eSDag-Erling Smørgrav char *idstr1 = NULL, *idstr2 = NULL; 53*59c8e88eSDag-Erling Smørgrav size_t size1, size2; 54*59c8e88eSDag-Erling Smørgrav struct got_diffreg_result *result; 55*59c8e88eSDag-Erling Smørgrav 56*59c8e88eSDag-Erling Smørgrav if (resultp) 57*59c8e88eSDag-Erling Smørgrav *resultp = NULL; 58*59c8e88eSDag-Erling Smørgrav 59*59c8e88eSDag-Erling Smørgrav if (blob1) { 60*59c8e88eSDag-Erling Smørgrav f1 = got_opentemp(); 61*59c8e88eSDag-Erling Smørgrav if (f1 == NULL) 62*59c8e88eSDag-Erling Smørgrav return got_error_from_errno("got_opentemp"); 63*59c8e88eSDag-Erling Smørgrav } 64*59c8e88eSDag-Erling Smørgrav 65*59c8e88eSDag-Erling Smørgrav if (blob2) { 66*59c8e88eSDag-Erling Smørgrav f2 = got_opentemp(); 67*59c8e88eSDag-Erling Smørgrav if (f2 == NULL) { 68*59c8e88eSDag-Erling Smørgrav err = got_error_from_errno("got_opentemp"); 69*59c8e88eSDag-Erling Smørgrav fclose(f1); 70*59c8e88eSDag-Erling Smørgrav return err; 71*59c8e88eSDag-Erling Smørgrav } 72*59c8e88eSDag-Erling Smørgrav } 73*59c8e88eSDag-Erling Smørgrav 74*59c8e88eSDag-Erling Smørgrav size1 = 0; 75*59c8e88eSDag-Erling Smørgrav if (blob1) { 76*59c8e88eSDag-Erling Smørgrav idstr1 = got_object_blob_id_str(blob1, hex1, sizeof(hex1)); 77*59c8e88eSDag-Erling Smørgrav err = got_object_blob_dump_to_file(&size1, NULL, NULL, f1, 78*59c8e88eSDag-Erling Smørgrav blob1); 79*59c8e88eSDag-Erling Smørgrav if (err) 80*59c8e88eSDag-Erling Smørgrav goto done; 81*59c8e88eSDag-Erling Smørgrav } else 82*59c8e88eSDag-Erling Smørgrav idstr1 = "/dev/null"; 83*59c8e88eSDag-Erling Smørgrav 84*59c8e88eSDag-Erling Smørgrav size2 = 0; 85*59c8e88eSDag-Erling Smørgrav if (blob2) { 86*59c8e88eSDag-Erling Smørgrav idstr2 = got_object_blob_id_str(blob2, hex2, sizeof(hex2)); 87*59c8e88eSDag-Erling Smørgrav err = got_object_blob_dump_to_file(&size2, NULL, NULL, f2, 88*59c8e88eSDag-Erling Smørgrav blob2); 89*59c8e88eSDag-Erling Smørgrav if (err) 90*59c8e88eSDag-Erling Smørgrav goto done; 91*59c8e88eSDag-Erling Smørgrav } else 92*59c8e88eSDag-Erling Smørgrav idstr2 = "/dev/null"; 93*59c8e88eSDag-Erling Smørgrav 94*59c8e88eSDag-Erling Smørgrav if (outfile) { 95*59c8e88eSDag-Erling Smørgrav char *modestr1 = NULL, *modestr2 = NULL; 96*59c8e88eSDag-Erling Smørgrav int modebits; 97*59c8e88eSDag-Erling Smørgrav if (mode1 && mode1 != mode2) { 98*59c8e88eSDag-Erling Smørgrav if (S_ISLNK(mode1)) 99*59c8e88eSDag-Erling Smørgrav modebits = S_IFLNK; 100*59c8e88eSDag-Erling Smørgrav else 101*59c8e88eSDag-Erling Smørgrav modebits = (S_IRWXU | S_IRWXG | S_IRWXO); 102*59c8e88eSDag-Erling Smørgrav if (asprintf(&modestr1, " (mode %o)", 103*59c8e88eSDag-Erling Smørgrav mode1 & modebits) == -1) { 104*59c8e88eSDag-Erling Smørgrav err = got_error_from_errno("asprintf"); 105*59c8e88eSDag-Erling Smørgrav goto done; 106*59c8e88eSDag-Erling Smørgrav } 107*59c8e88eSDag-Erling Smørgrav } 108*59c8e88eSDag-Erling Smørgrav if (mode2 && mode1 != mode2) { 109*59c8e88eSDag-Erling Smørgrav if (S_ISLNK(mode2)) 110*59c8e88eSDag-Erling Smørgrav modebits = S_IFLNK; 111*59c8e88eSDag-Erling Smørgrav else 112*59c8e88eSDag-Erling Smørgrav modebits = (S_IRWXU | S_IRWXG | S_IRWXO); 113*59c8e88eSDag-Erling Smørgrav if (asprintf(&modestr2, " (mode %o)", 114*59c8e88eSDag-Erling Smørgrav mode2 & modebits) == -1) { 115*59c8e88eSDag-Erling Smørgrav err = got_error_from_errno("asprintf"); 116*59c8e88eSDag-Erling Smørgrav goto done; 117*59c8e88eSDag-Erling Smørgrav } 118*59c8e88eSDag-Erling Smørgrav } 119*59c8e88eSDag-Erling Smørgrav fprintf(outfile, "blob - %s%s\n", idstr1, 120*59c8e88eSDag-Erling Smørgrav modestr1 ? modestr1 : ""); 121*59c8e88eSDag-Erling Smørgrav fprintf(outfile, "blob + %s%s\n", idstr2, 122*59c8e88eSDag-Erling Smørgrav modestr2 ? modestr2 : ""); 123*59c8e88eSDag-Erling Smørgrav free(modestr1); 124*59c8e88eSDag-Erling Smørgrav free(modestr2); 125*59c8e88eSDag-Erling Smørgrav } 126*59c8e88eSDag-Erling Smørgrav err = got_diffreg(&result, f1, f2, GOT_DIFF_ALGORITHM_MYERS, 127*59c8e88eSDag-Erling Smørgrav ignore_whitespace); 128*59c8e88eSDag-Erling Smørgrav if (err) 129*59c8e88eSDag-Erling Smørgrav goto done; 130*59c8e88eSDag-Erling Smørgrav 131*59c8e88eSDag-Erling Smørgrav if (outfile) { 132*59c8e88eSDag-Erling Smørgrav err = got_diffreg_output(NULL, NULL, result, f1, f2, 133*59c8e88eSDag-Erling Smørgrav label1 ? label1 : idstr1, 134*59c8e88eSDag-Erling Smørgrav label2 ? label2 : idstr2, 135*59c8e88eSDag-Erling Smørgrav GOT_DIFF_OUTPUT_UNIDIFF, diff_context, outfile); 136*59c8e88eSDag-Erling Smørgrav if (err) 137*59c8e88eSDag-Erling Smørgrav goto done; 138*59c8e88eSDag-Erling Smørgrav } 139*59c8e88eSDag-Erling Smørgrav 140*59c8e88eSDag-Erling Smørgrav if (resultp && err == NULL) 141*59c8e88eSDag-Erling Smørgrav *resultp = result; 142*59c8e88eSDag-Erling Smørgrav else { 143*59c8e88eSDag-Erling Smørgrav free_err = got_diffreg_result_free(result); 144*59c8e88eSDag-Erling Smørgrav if (free_err && err == NULL) 145*59c8e88eSDag-Erling Smørgrav err = free_err; 146*59c8e88eSDag-Erling Smørgrav } 147*59c8e88eSDag-Erling Smørgravdone: 148*59c8e88eSDag-Erling Smørgrav if (f1 && fclose(f1) != 0 && err == NULL) 149*59c8e88eSDag-Erling Smørgrav err = got_error_from_errno("fclose"); 150*59c8e88eSDag-Erling Smørgrav if (f2 && fclose(f2) != 0 && err == NULL) 151*59c8e88eSDag-Erling Smørgrav err = got_error_from_errno("fclose"); 152*59c8e88eSDag-Erling Smørgrav return err; 153*59c8e88eSDag-Erling Smørgrav} 154*59c8e88eSDag-Erling Smørgrav 155*59c8e88eSDag-Erling Smørgravconst struct got_error * 156*59c8e88eSDag-Erling Smørgravgot_diff_blob_output_unidiff(void *arg, struct got_blob_object *blob1, 157*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob2, struct got_object_id *id1, 158*59c8e88eSDag-Erling Smørgrav struct got_object_id *id2, const char *label1, const char *label2, 159*59c8e88eSDag-Erling Smørgrav mode_t mode1, mode_t mode2, struct got_repository *repo) 160*59c8e88eSDag-Erling Smørgrav{ 161*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 162*59c8e88eSDag-Erling Smørgrav struct got_diff_blob_output_unidiff_arg *a = arg; 163*59c8e88eSDag-Erling Smørgrav 164*59c8e88eSDag-Erling Smørgrav err = diff_blobs(NULL, blob1, blob2, label1, label2, mode1, mode2, 165*59c8e88eSDag-Erling Smørgrav a->diff_context, a->ignore_whitespace, a->outfile); 166*59c8e88eSDag-Erling Smørgrav return err; 167*59c8e88eSDag-Erling Smørgrav} 168*59c8e88eSDag-Erling Smørgrav 169*59c8e88eSDag-Erling Smørgravconst struct got_error * 170*59c8e88eSDag-Erling Smørgravgot_diff_blob(struct got_blob_object *blob1, struct got_blob_object *blob2, 171*59c8e88eSDag-Erling Smørgrav const char *label1, const char *label2, int diff_context, 172*59c8e88eSDag-Erling Smørgrav int ignore_whitespace, FILE *outfile) 173*59c8e88eSDag-Erling Smørgrav{ 174*59c8e88eSDag-Erling Smørgrav return diff_blobs(NULL, blob1, blob2, label1, label2, 0, 0, diff_context, 175*59c8e88eSDag-Erling Smørgrav ignore_whitespace, outfile); 176*59c8e88eSDag-Erling Smørgrav} 177*59c8e88eSDag-Erling Smørgrav 178*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 179*59c8e88eSDag-Erling Smørgravdiff_blob_file(struct got_diffreg_result **resultp, 180*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob1, const char *label1, FILE *f2, size_t size2, 181*59c8e88eSDag-Erling Smørgrav const char *label2, int diff_context, int ignore_whitespace, FILE *outfile) 182*59c8e88eSDag-Erling Smørgrav{ 183*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL, *free_err; 184*59c8e88eSDag-Erling Smørgrav FILE *f1 = NULL; 185*59c8e88eSDag-Erling Smørgrav char hex1[SHA1_DIGEST_STRING_LENGTH]; 186*59c8e88eSDag-Erling Smørgrav char *idstr1 = NULL; 187*59c8e88eSDag-Erling Smørgrav size_t size1; 188*59c8e88eSDag-Erling Smørgrav struct got_diffreg_result *result = NULL; 189*59c8e88eSDag-Erling Smørgrav 190*59c8e88eSDag-Erling Smørgrav if (resultp) 191*59c8e88eSDag-Erling Smørgrav *resultp = NULL; 192*59c8e88eSDag-Erling Smørgrav 193*59c8e88eSDag-Erling Smørgrav size1 = 0; 194*59c8e88eSDag-Erling Smørgrav if (blob1) { 195*59c8e88eSDag-Erling Smørgrav f1 = got_opentemp(); 196*59c8e88eSDag-Erling Smørgrav if (f1 == NULL) 197*59c8e88eSDag-Erling Smørgrav return got_error_from_errno("got_opentemp"); 198*59c8e88eSDag-Erling Smørgrav idstr1 = got_object_blob_id_str(blob1, hex1, sizeof(hex1)); 199*59c8e88eSDag-Erling Smørgrav err = got_object_blob_dump_to_file(&size1, NULL, NULL, f1, 200*59c8e88eSDag-Erling Smørgrav blob1); 201*59c8e88eSDag-Erling Smørgrav if (err) 202*59c8e88eSDag-Erling Smørgrav goto done; 203*59c8e88eSDag-Erling Smørgrav } else { 204*59c8e88eSDag-Erling Smørgrav idstr1 = "/dev/null"; 205*59c8e88eSDag-Erling Smørgrav } 206*59c8e88eSDag-Erling Smørgrav 207*59c8e88eSDag-Erling Smørgrav if (outfile) { 208*59c8e88eSDag-Erling Smørgrav fprintf(outfile, "blob - %s\n", label1 ? label1 : idstr1); 209*59c8e88eSDag-Erling Smørgrav fprintf(outfile, "file + %s\n", 210*59c8e88eSDag-Erling Smørgrav f2 == NULL ? "/dev/null" : label2); 211*59c8e88eSDag-Erling Smørgrav } 212*59c8e88eSDag-Erling Smørgrav 213*59c8e88eSDag-Erling Smørgrav err = got_diffreg(&result, f1, f2, GOT_DIFF_ALGORITHM_MYERS, 214*59c8e88eSDag-Erling Smørgrav ignore_whitespace); 215*59c8e88eSDag-Erling Smørgrav if (err) 216*59c8e88eSDag-Erling Smørgrav goto done; 217*59c8e88eSDag-Erling Smørgrav 218*59c8e88eSDag-Erling Smørgrav if (outfile) { 219*59c8e88eSDag-Erling Smørgrav err = got_diffreg_output(NULL, NULL, result, f1, f2, 220*59c8e88eSDag-Erling Smørgrav label2, label2, GOT_DIFF_OUTPUT_UNIDIFF, diff_context, 221*59c8e88eSDag-Erling Smørgrav outfile); 222*59c8e88eSDag-Erling Smørgrav if (err) 223*59c8e88eSDag-Erling Smørgrav goto done; 224*59c8e88eSDag-Erling Smørgrav } 225*59c8e88eSDag-Erling Smørgrav 226*59c8e88eSDag-Erling Smørgrav if (resultp && err == NULL) 227*59c8e88eSDag-Erling Smørgrav *resultp = result; 228*59c8e88eSDag-Erling Smørgrav else if (result) { 229*59c8e88eSDag-Erling Smørgrav free_err = got_diffreg_result_free(result); 230*59c8e88eSDag-Erling Smørgrav if (free_err && err == NULL) 231*59c8e88eSDag-Erling Smørgrav err = free_err; 232*59c8e88eSDag-Erling Smørgrav } 233*59c8e88eSDag-Erling Smørgravdone: 234*59c8e88eSDag-Erling Smørgrav if (f1 && fclose(f1) != 0 && err == NULL) 235*59c8e88eSDag-Erling Smørgrav err = got_error_from_errno("fclose"); 236*59c8e88eSDag-Erling Smørgrav return err; 237*59c8e88eSDag-Erling Smørgrav} 238*59c8e88eSDag-Erling Smørgrav 239*59c8e88eSDag-Erling Smørgravconst struct got_error * 240*59c8e88eSDag-Erling Smørgravgot_diff_blob_file(struct got_blob_object *blob1, const char *label1, 241*59c8e88eSDag-Erling Smørgrav FILE *f2, size_t size2, const char *label2, int diff_context, 242*59c8e88eSDag-Erling Smørgrav int ignore_whitespace, FILE *outfile) 243*59c8e88eSDag-Erling Smørgrav{ 244*59c8e88eSDag-Erling Smørgrav return diff_blob_file(NULL, blob1, label1, f2, size2, label2, 245*59c8e88eSDag-Erling Smørgrav diff_context, ignore_whitespace, outfile); 246*59c8e88eSDag-Erling Smørgrav} 247*59c8e88eSDag-Erling Smørgrav 248*59c8e88eSDag-Erling Smørgravconst struct got_error * 249*59c8e88eSDag-Erling Smørgravgot_diff_blob_file_lines_changed(struct got_diffreg_result **result, 250*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob1, FILE *f2, size_t size2) 251*59c8e88eSDag-Erling Smørgrav{ 252*59c8e88eSDag-Erling Smørgrav return diff_blob_file(result, blob1, NULL, f2, size2, NULL, 253*59c8e88eSDag-Erling Smørgrav 0, 0, NULL); 254*59c8e88eSDag-Erling Smørgrav} 255*59c8e88eSDag-Erling Smørgrav 256*59c8e88eSDag-Erling Smørgravconst struct got_error * 257*59c8e88eSDag-Erling Smørgravgot_diff_blob_lines_changed(struct got_diffreg_result **result, 258*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob1, struct got_blob_object *blob2) 259*59c8e88eSDag-Erling Smørgrav{ 260*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL; 261*59c8e88eSDag-Erling Smørgrav 262*59c8e88eSDag-Erling Smørgrav err = diff_blobs(result, blob1, blob2, NULL, NULL, 0, 0, 3, 0, NULL); 263*59c8e88eSDag-Erling Smørgrav if (err) { 264*59c8e88eSDag-Erling Smørgrav got_diffreg_result_free(*result); 265*59c8e88eSDag-Erling Smørgrav *result = NULL; 266*59c8e88eSDag-Erling Smørgrav } 267*59c8e88eSDag-Erling Smørgrav return err; 268*59c8e88eSDag-Erling Smørgrav} 269*59c8e88eSDag-Erling Smørgrav 270*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 271*59c8e88eSDag-Erling Smørgravdiff_added_blob(struct got_object_id *id, const char *label, mode_t mode, 272*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg) 273*59c8e88eSDag-Erling Smørgrav{ 274*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 275*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob = NULL; 276*59c8e88eSDag-Erling Smørgrav struct got_object *obj = NULL; 277*59c8e88eSDag-Erling Smørgrav 278*59c8e88eSDag-Erling Smørgrav err = got_object_open(&obj, repo, id); 279*59c8e88eSDag-Erling Smørgrav if (err) 280*59c8e88eSDag-Erling Smørgrav return err; 281*59c8e88eSDag-Erling Smørgrav 282*59c8e88eSDag-Erling Smørgrav err = got_object_blob_open(&blob, repo, obj, 8192); 283*59c8e88eSDag-Erling Smørgrav if (err) 284*59c8e88eSDag-Erling Smørgrav goto done; 285*59c8e88eSDag-Erling Smørgrav err = cb(cb_arg, NULL, blob, NULL, id, NULL, label, 0, mode, repo); 286*59c8e88eSDag-Erling Smørgravdone: 287*59c8e88eSDag-Erling Smørgrav got_object_close(obj); 288*59c8e88eSDag-Erling Smørgrav if (blob) 289*59c8e88eSDag-Erling Smørgrav got_object_blob_close(blob); 290*59c8e88eSDag-Erling Smørgrav return err; 291*59c8e88eSDag-Erling Smørgrav} 292*59c8e88eSDag-Erling Smørgrav 293*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 294*59c8e88eSDag-Erling Smørgravdiff_modified_blob(struct got_object_id *id1, struct got_object_id *id2, 295*59c8e88eSDag-Erling Smørgrav const char *label1, const char *label2, mode_t mode1, mode_t mode2, 296*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg) 297*59c8e88eSDag-Erling Smørgrav{ 298*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 299*59c8e88eSDag-Erling Smørgrav struct got_object *obj1 = NULL; 300*59c8e88eSDag-Erling Smørgrav struct got_object *obj2 = NULL; 301*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob1 = NULL; 302*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob2 = NULL; 303*59c8e88eSDag-Erling Smørgrav 304*59c8e88eSDag-Erling Smørgrav err = got_object_open(&obj1, repo, id1); 305*59c8e88eSDag-Erling Smørgrav if (err) 306*59c8e88eSDag-Erling Smørgrav return err; 307*59c8e88eSDag-Erling Smørgrav if (obj1->type != GOT_OBJ_TYPE_BLOB) { 308*59c8e88eSDag-Erling Smørgrav err = got_error(GOT_ERR_OBJ_TYPE); 309*59c8e88eSDag-Erling Smørgrav goto done; 310*59c8e88eSDag-Erling Smørgrav } 311*59c8e88eSDag-Erling Smørgrav 312*59c8e88eSDag-Erling Smørgrav err = got_object_open(&obj2, repo, id2); 313*59c8e88eSDag-Erling Smørgrav if (err) 314*59c8e88eSDag-Erling Smørgrav goto done; 315*59c8e88eSDag-Erling Smørgrav if (obj2->type != GOT_OBJ_TYPE_BLOB) { 316*59c8e88eSDag-Erling Smørgrav err = got_error(GOT_ERR_BAD_OBJ_DATA); 317*59c8e88eSDag-Erling Smørgrav goto done; 318*59c8e88eSDag-Erling Smørgrav } 319*59c8e88eSDag-Erling Smørgrav 320*59c8e88eSDag-Erling Smørgrav err = got_object_blob_open(&blob1, repo, obj1, 8192); 321*59c8e88eSDag-Erling Smørgrav if (err) 322*59c8e88eSDag-Erling Smørgrav goto done; 323*59c8e88eSDag-Erling Smørgrav 324*59c8e88eSDag-Erling Smørgrav err = got_object_blob_open(&blob2, repo, obj2, 8192); 325*59c8e88eSDag-Erling Smørgrav if (err) 326*59c8e88eSDag-Erling Smørgrav goto done; 327*59c8e88eSDag-Erling Smørgrav 328*59c8e88eSDag-Erling Smørgrav err = cb(cb_arg, blob1, blob2, id1, id2, label1, label2, mode1, mode2, 329*59c8e88eSDag-Erling Smørgrav repo); 330*59c8e88eSDag-Erling Smørgravdone: 331*59c8e88eSDag-Erling Smørgrav if (obj1) 332*59c8e88eSDag-Erling Smørgrav got_object_close(obj1); 333*59c8e88eSDag-Erling Smørgrav if (obj2) 334*59c8e88eSDag-Erling Smørgrav got_object_close(obj2); 335*59c8e88eSDag-Erling Smørgrav if (blob1) 336*59c8e88eSDag-Erling Smørgrav got_object_blob_close(blob1); 337*59c8e88eSDag-Erling Smørgrav if (blob2) 338*59c8e88eSDag-Erling Smørgrav got_object_blob_close(blob2); 339*59c8e88eSDag-Erling Smørgrav return err; 340*59c8e88eSDag-Erling Smørgrav} 341*59c8e88eSDag-Erling Smørgrav 342*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 343*59c8e88eSDag-Erling Smørgravdiff_deleted_blob(struct got_object_id *id, const char *label, mode_t mode, 344*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg) 345*59c8e88eSDag-Erling Smørgrav{ 346*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 347*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob = NULL; 348*59c8e88eSDag-Erling Smørgrav struct got_object *obj = NULL; 349*59c8e88eSDag-Erling Smørgrav 350*59c8e88eSDag-Erling Smørgrav err = got_object_open(&obj, repo, id); 351*59c8e88eSDag-Erling Smørgrav if (err) 352*59c8e88eSDag-Erling Smørgrav return err; 353*59c8e88eSDag-Erling Smørgrav 354*59c8e88eSDag-Erling Smørgrav err = got_object_blob_open(&blob, repo, obj, 8192); 355*59c8e88eSDag-Erling Smørgrav if (err) 356*59c8e88eSDag-Erling Smørgrav goto done; 357*59c8e88eSDag-Erling Smørgrav err = cb(cb_arg, blob, NULL, id, NULL, label, NULL, mode, 0, repo); 358*59c8e88eSDag-Erling Smørgravdone: 359*59c8e88eSDag-Erling Smørgrav got_object_close(obj); 360*59c8e88eSDag-Erling Smørgrav if (blob) 361*59c8e88eSDag-Erling Smørgrav got_object_blob_close(blob); 362*59c8e88eSDag-Erling Smørgrav return err; 363*59c8e88eSDag-Erling Smørgrav} 364*59c8e88eSDag-Erling Smørgrav 365*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 366*59c8e88eSDag-Erling Smørgravdiff_added_tree(struct got_object_id *id, const char *label, 367*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg, 368*59c8e88eSDag-Erling Smørgrav int diff_content) 369*59c8e88eSDag-Erling Smørgrav{ 370*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL; 371*59c8e88eSDag-Erling Smørgrav struct got_object *treeobj = NULL; 372*59c8e88eSDag-Erling Smørgrav struct got_tree_object *tree = NULL; 373*59c8e88eSDag-Erling Smørgrav 374*59c8e88eSDag-Erling Smørgrav err = got_object_open(&treeobj, repo, id); 375*59c8e88eSDag-Erling Smørgrav if (err) 376*59c8e88eSDag-Erling Smørgrav goto done; 377*59c8e88eSDag-Erling Smørgrav 378*59c8e88eSDag-Erling Smørgrav if (treeobj->type != GOT_OBJ_TYPE_TREE) { 379*59c8e88eSDag-Erling Smørgrav err = got_error(GOT_ERR_OBJ_TYPE); 380*59c8e88eSDag-Erling Smørgrav goto done; 381*59c8e88eSDag-Erling Smørgrav } 382*59c8e88eSDag-Erling Smørgrav 383*59c8e88eSDag-Erling Smørgrav err = got_object_tree_open(&tree, repo, treeobj); 384*59c8e88eSDag-Erling Smørgrav if (err) 385*59c8e88eSDag-Erling Smørgrav goto done; 386*59c8e88eSDag-Erling Smørgrav 387*59c8e88eSDag-Erling Smørgrav err = got_diff_tree(NULL, tree, NULL, label, repo, cb, cb_arg, 388*59c8e88eSDag-Erling Smørgrav diff_content); 389*59c8e88eSDag-Erling Smørgravdone: 390*59c8e88eSDag-Erling Smørgrav if (tree) 391*59c8e88eSDag-Erling Smørgrav got_object_tree_close(tree); 392*59c8e88eSDag-Erling Smørgrav if (treeobj) 393*59c8e88eSDag-Erling Smørgrav got_object_close(treeobj); 394*59c8e88eSDag-Erling Smørgrav return err; 395*59c8e88eSDag-Erling Smørgrav} 396*59c8e88eSDag-Erling Smørgrav 397*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 398*59c8e88eSDag-Erling Smørgravdiff_modified_tree(struct got_object_id *id1, struct got_object_id *id2, 399*59c8e88eSDag-Erling Smørgrav const char *label1, const char *label2, struct got_repository *repo, 400*59c8e88eSDag-Erling Smørgrav got_diff_blob_cb cb, void *cb_arg, int diff_content) 401*59c8e88eSDag-Erling Smørgrav{ 402*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 403*59c8e88eSDag-Erling Smørgrav struct got_object *treeobj1 = NULL; 404*59c8e88eSDag-Erling Smørgrav struct got_object *treeobj2 = NULL; 405*59c8e88eSDag-Erling Smørgrav struct got_tree_object *tree1 = NULL; 406*59c8e88eSDag-Erling Smørgrav struct got_tree_object *tree2 = NULL; 407*59c8e88eSDag-Erling Smørgrav 408*59c8e88eSDag-Erling Smørgrav err = got_object_open(&treeobj1, repo, id1); 409*59c8e88eSDag-Erling Smørgrav if (err) 410*59c8e88eSDag-Erling Smørgrav goto done; 411*59c8e88eSDag-Erling Smørgrav 412*59c8e88eSDag-Erling Smørgrav if (treeobj1->type != GOT_OBJ_TYPE_TREE) { 413*59c8e88eSDag-Erling Smørgrav err = got_error(GOT_ERR_OBJ_TYPE); 414*59c8e88eSDag-Erling Smørgrav goto done; 415*59c8e88eSDag-Erling Smørgrav } 416*59c8e88eSDag-Erling Smørgrav 417*59c8e88eSDag-Erling Smørgrav err = got_object_open(&treeobj2, repo, id2); 418*59c8e88eSDag-Erling Smørgrav if (err) 419*59c8e88eSDag-Erling Smørgrav goto done; 420*59c8e88eSDag-Erling Smørgrav 421*59c8e88eSDag-Erling Smørgrav if (treeobj2->type != GOT_OBJ_TYPE_TREE) { 422*59c8e88eSDag-Erling Smørgrav err = got_error(GOT_ERR_OBJ_TYPE); 423*59c8e88eSDag-Erling Smørgrav goto done; 424*59c8e88eSDag-Erling Smørgrav } 425*59c8e88eSDag-Erling Smørgrav 426*59c8e88eSDag-Erling Smørgrav err = got_object_tree_open(&tree1, repo, treeobj1); 427*59c8e88eSDag-Erling Smørgrav if (err) 428*59c8e88eSDag-Erling Smørgrav goto done; 429*59c8e88eSDag-Erling Smørgrav 430*59c8e88eSDag-Erling Smørgrav err = got_object_tree_open(&tree2, repo, treeobj2); 431*59c8e88eSDag-Erling Smørgrav if (err) 432*59c8e88eSDag-Erling Smørgrav goto done; 433*59c8e88eSDag-Erling Smørgrav 434*59c8e88eSDag-Erling Smørgrav err = got_diff_tree(tree1, tree2, label1, label2, repo, cb, cb_arg, 435*59c8e88eSDag-Erling Smørgrav diff_content); 436*59c8e88eSDag-Erling Smørgrav 437*59c8e88eSDag-Erling Smørgravdone: 438*59c8e88eSDag-Erling Smørgrav if (tree1) 439*59c8e88eSDag-Erling Smørgrav got_object_tree_close(tree1); 440*59c8e88eSDag-Erling Smørgrav if (tree2) 441*59c8e88eSDag-Erling Smørgrav got_object_tree_close(tree2); 442*59c8e88eSDag-Erling Smørgrav if (treeobj1) 443*59c8e88eSDag-Erling Smørgrav got_object_close(treeobj1); 444*59c8e88eSDag-Erling Smørgrav if (treeobj2) 445*59c8e88eSDag-Erling Smørgrav got_object_close(treeobj2); 446*59c8e88eSDag-Erling Smørgrav return err; 447*59c8e88eSDag-Erling Smørgrav} 448*59c8e88eSDag-Erling Smørgrav 449*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 450*59c8e88eSDag-Erling Smørgravdiff_deleted_tree(struct got_object_id *id, const char *label, 451*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg, 452*59c8e88eSDag-Erling Smørgrav int diff_content) 453*59c8e88eSDag-Erling Smørgrav{ 454*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 455*59c8e88eSDag-Erling Smørgrav struct got_object *treeobj = NULL; 456*59c8e88eSDag-Erling Smørgrav struct got_tree_object *tree = NULL; 457*59c8e88eSDag-Erling Smørgrav 458*59c8e88eSDag-Erling Smørgrav err = got_object_open(&treeobj, repo, id); 459*59c8e88eSDag-Erling Smørgrav if (err) 460*59c8e88eSDag-Erling Smørgrav goto done; 461*59c8e88eSDag-Erling Smørgrav 462*59c8e88eSDag-Erling Smørgrav if (treeobj->type != GOT_OBJ_TYPE_TREE) { 463*59c8e88eSDag-Erling Smørgrav err = got_error(GOT_ERR_OBJ_TYPE); 464*59c8e88eSDag-Erling Smørgrav goto done; 465*59c8e88eSDag-Erling Smørgrav } 466*59c8e88eSDag-Erling Smørgrav 467*59c8e88eSDag-Erling Smørgrav err = got_object_tree_open(&tree, repo, treeobj); 468*59c8e88eSDag-Erling Smørgrav if (err) 469*59c8e88eSDag-Erling Smørgrav goto done; 470*59c8e88eSDag-Erling Smørgrav 471*59c8e88eSDag-Erling Smørgrav err = got_diff_tree(tree, NULL, label, NULL, repo, cb, cb_arg, 472*59c8e88eSDag-Erling Smørgrav diff_content); 473*59c8e88eSDag-Erling Smørgravdone: 474*59c8e88eSDag-Erling Smørgrav if (tree) 475*59c8e88eSDag-Erling Smørgrav got_object_tree_close(tree); 476*59c8e88eSDag-Erling Smørgrav if (treeobj) 477*59c8e88eSDag-Erling Smørgrav got_object_close(treeobj); 478*59c8e88eSDag-Erling Smørgrav return err; 479*59c8e88eSDag-Erling Smørgrav} 480*59c8e88eSDag-Erling Smørgrav 481*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 482*59c8e88eSDag-Erling Smørgravdiff_kind_mismatch(struct got_object_id *id1, struct got_object_id *id2, 483*59c8e88eSDag-Erling Smørgrav const char *label1, const char *label2, struct got_repository *repo, 484*59c8e88eSDag-Erling Smørgrav got_diff_blob_cb cb, void *cb_arg) 485*59c8e88eSDag-Erling Smørgrav{ 486*59c8e88eSDag-Erling Smørgrav /* XXX TODO */ 487*59c8e88eSDag-Erling Smørgrav return NULL; 488*59c8e88eSDag-Erling Smørgrav} 489*59c8e88eSDag-Erling Smørgrav 490*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 491*59c8e88eSDag-Erling Smørgravdiff_entry_old_new(struct got_tree_entry *te1, 492*59c8e88eSDag-Erling Smørgrav struct got_tree_entry *te2, const char *label1, const char *label2, 493*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg, 494*59c8e88eSDag-Erling Smørgrav int diff_content) 495*59c8e88eSDag-Erling Smørgrav{ 496*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL; 497*59c8e88eSDag-Erling Smørgrav int id_match; 498*59c8e88eSDag-Erling Smørgrav 499*59c8e88eSDag-Erling Smørgrav if (got_object_tree_entry_is_submodule(te1)) 500*59c8e88eSDag-Erling Smørgrav return NULL; 501*59c8e88eSDag-Erling Smørgrav 502*59c8e88eSDag-Erling Smørgrav if (te2 == NULL) { 503*59c8e88eSDag-Erling Smørgrav if (S_ISDIR(te1->mode)) 504*59c8e88eSDag-Erling Smørgrav err = diff_deleted_tree(&te1->id, label1, repo, 505*59c8e88eSDag-Erling Smørgrav cb, cb_arg, diff_content); 506*59c8e88eSDag-Erling Smørgrav else { 507*59c8e88eSDag-Erling Smørgrav if (diff_content) 508*59c8e88eSDag-Erling Smørgrav err = diff_deleted_blob(&te1->id, label1, 509*59c8e88eSDag-Erling Smørgrav te1->mode, repo, cb, cb_arg); 510*59c8e88eSDag-Erling Smørgrav else 511*59c8e88eSDag-Erling Smørgrav err = cb(cb_arg, NULL, NULL, &te1->id, NULL, 512*59c8e88eSDag-Erling Smørgrav label1, NULL, te1->mode, 0, repo); 513*59c8e88eSDag-Erling Smørgrav } 514*59c8e88eSDag-Erling Smørgrav return err; 515*59c8e88eSDag-Erling Smørgrav } else if (got_object_tree_entry_is_submodule(te2)) 516*59c8e88eSDag-Erling Smørgrav return NULL; 517*59c8e88eSDag-Erling Smørgrav 518*59c8e88eSDag-Erling Smørgrav id_match = (got_object_id_cmp(&te1->id, &te2->id) == 0); 519*59c8e88eSDag-Erling Smørgrav if (S_ISDIR(te1->mode) && S_ISDIR(te2->mode)) { 520*59c8e88eSDag-Erling Smørgrav if (!id_match) 521*59c8e88eSDag-Erling Smørgrav return diff_modified_tree(&te1->id, &te2->id, 522*59c8e88eSDag-Erling Smørgrav label1, label2, repo, cb, cb_arg, diff_content); 523*59c8e88eSDag-Erling Smørgrav } else if ((S_ISREG(te1->mode) || S_ISLNK(te1->mode)) && 524*59c8e88eSDag-Erling Smørgrav (S_ISREG(te2->mode) || S_ISLNK(te2->mode))) { 525*59c8e88eSDag-Erling Smørgrav if (!id_match || 526*59c8e88eSDag-Erling Smørgrav ((te1->mode & (S_IFLNK | S_IXUSR))) != 527*59c8e88eSDag-Erling Smørgrav (te2->mode & (S_IFLNK | S_IXUSR))) { 528*59c8e88eSDag-Erling Smørgrav if (diff_content) 529*59c8e88eSDag-Erling Smørgrav return diff_modified_blob(&te1->id, &te2->id, 530*59c8e88eSDag-Erling Smørgrav label1, label2, te1->mode, te2->mode, 531*59c8e88eSDag-Erling Smørgrav repo, cb, cb_arg); 532*59c8e88eSDag-Erling Smørgrav else 533*59c8e88eSDag-Erling Smørgrav return cb(cb_arg, NULL, NULL, &te1->id, 534*59c8e88eSDag-Erling Smørgrav &te2->id, label1, label2, te1->mode, 535*59c8e88eSDag-Erling Smørgrav te2->mode, repo); 536*59c8e88eSDag-Erling Smørgrav } 537*59c8e88eSDag-Erling Smørgrav } 538*59c8e88eSDag-Erling Smørgrav 539*59c8e88eSDag-Erling Smørgrav if (id_match) 540*59c8e88eSDag-Erling Smørgrav return NULL; 541*59c8e88eSDag-Erling Smørgrav 542*59c8e88eSDag-Erling Smørgrav return diff_kind_mismatch(&te1->id, &te2->id, label1, label2, repo, 543*59c8e88eSDag-Erling Smørgrav cb, cb_arg); 544*59c8e88eSDag-Erling Smørgrav} 545*59c8e88eSDag-Erling Smørgrav 546*59c8e88eSDag-Erling Smørgravstatic const struct got_error * 547*59c8e88eSDag-Erling Smørgravdiff_entry_new_old(struct got_tree_entry *te2, 548*59c8e88eSDag-Erling Smørgrav struct got_tree_entry *te1, const char *label2, 549*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg, 550*59c8e88eSDag-Erling Smørgrav int diff_content) 551*59c8e88eSDag-Erling Smørgrav{ 552*59c8e88eSDag-Erling Smørgrav if (te1 != NULL) /* handled by diff_entry_old_new() */ 553*59c8e88eSDag-Erling Smørgrav return NULL; 554*59c8e88eSDag-Erling Smørgrav 555*59c8e88eSDag-Erling Smørgrav if (got_object_tree_entry_is_submodule(te2)) 556*59c8e88eSDag-Erling Smørgrav return NULL; 557*59c8e88eSDag-Erling Smørgrav 558*59c8e88eSDag-Erling Smørgrav if (S_ISDIR(te2->mode)) 559*59c8e88eSDag-Erling Smørgrav return diff_added_tree(&te2->id, label2, repo, cb, cb_arg, 560*59c8e88eSDag-Erling Smørgrav diff_content); 561*59c8e88eSDag-Erling Smørgrav 562*59c8e88eSDag-Erling Smørgrav if (diff_content) 563*59c8e88eSDag-Erling Smørgrav return diff_added_blob(&te2->id, label2, te2->mode, repo, cb, 564*59c8e88eSDag-Erling Smørgrav cb_arg); 565*59c8e88eSDag-Erling Smørgrav 566*59c8e88eSDag-Erling Smørgrav return cb(cb_arg, NULL, NULL, NULL, &te2->id, NULL, label2, 0, 567*59c8e88eSDag-Erling Smørgrav te2->mode, repo); 568*59c8e88eSDag-Erling Smørgrav} 569*59c8e88eSDag-Erling Smørgrav 570*59c8e88eSDag-Erling Smørgravconst struct got_error * 571*59c8e88eSDag-Erling Smørgravgot_diff_tree_collect_changed_paths(void *arg, struct got_blob_object *blob1, 572*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob2, struct got_object_id *id1, 573*59c8e88eSDag-Erling Smørgrav struct got_object_id *id2, const char *label1, const char *label2, 574*59c8e88eSDag-Erling Smørgrav mode_t mode1, mode_t mode2, struct got_repository *repo) 575*59c8e88eSDag-Erling Smørgrav{ 576*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL; 577*59c8e88eSDag-Erling Smørgrav struct got_pathlist_head *paths = arg; 578*59c8e88eSDag-Erling Smørgrav struct got_diff_changed_path *change = NULL; 579*59c8e88eSDag-Erling Smørgrav char *path = NULL; 580*59c8e88eSDag-Erling Smørgrav 581*59c8e88eSDag-Erling Smørgrav path = strdup(label2 ? label2 : label1); 582*59c8e88eSDag-Erling Smørgrav if (path == NULL) 583*59c8e88eSDag-Erling Smørgrav return got_error_from_errno("malloc"); 584*59c8e88eSDag-Erling Smørgrav 585*59c8e88eSDag-Erling Smørgrav change = malloc(sizeof(*change)); 586*59c8e88eSDag-Erling Smørgrav if (change == NULL) { 587*59c8e88eSDag-Erling Smørgrav err = got_error_from_errno("malloc"); 588*59c8e88eSDag-Erling Smørgrav goto done; 589*59c8e88eSDag-Erling Smørgrav } 590*59c8e88eSDag-Erling Smørgrav 591*59c8e88eSDag-Erling Smørgrav change->status = GOT_STATUS_NO_CHANGE; 592*59c8e88eSDag-Erling Smørgrav if (id1 == NULL) 593*59c8e88eSDag-Erling Smørgrav change->status = GOT_STATUS_ADD; 594*59c8e88eSDag-Erling Smørgrav else if (id2 == NULL) 595*59c8e88eSDag-Erling Smørgrav change->status = GOT_STATUS_DELETE; 596*59c8e88eSDag-Erling Smørgrav else { 597*59c8e88eSDag-Erling Smørgrav if (got_object_id_cmp(id1, id2) != 0) 598*59c8e88eSDag-Erling Smørgrav change->status = GOT_STATUS_MODIFY; 599*59c8e88eSDag-Erling Smørgrav else if (mode1 != mode2) 600*59c8e88eSDag-Erling Smørgrav change->status = GOT_STATUS_MODE_CHANGE; 601*59c8e88eSDag-Erling Smørgrav } 602*59c8e88eSDag-Erling Smørgrav 603*59c8e88eSDag-Erling Smørgrav err = got_pathlist_insert(NULL, paths, path, change); 604*59c8e88eSDag-Erling Smørgravdone: 605*59c8e88eSDag-Erling Smørgrav if (err) { 606*59c8e88eSDag-Erling Smørgrav free(path); 607*59c8e88eSDag-Erling Smørgrav free(change); 608*59c8e88eSDag-Erling Smørgrav } 609*59c8e88eSDag-Erling Smørgrav return err; 610*59c8e88eSDag-Erling Smørgrav} 611*59c8e88eSDag-Erling Smørgrav 612*59c8e88eSDag-Erling Smørgravconst struct got_error * 613*59c8e88eSDag-Erling Smørgravgot_diff_tree(struct got_tree_object *tree1, struct got_tree_object *tree2, 614*59c8e88eSDag-Erling Smørgrav const char *label1, const char *label2, struct got_repository *repo, 615*59c8e88eSDag-Erling Smørgrav got_diff_blob_cb cb, void *cb_arg, int diff_content) 616*59c8e88eSDag-Erling Smørgrav{ 617*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL; 618*59c8e88eSDag-Erling Smørgrav struct got_tree_entry *te1 = NULL; 619*59c8e88eSDag-Erling Smørgrav struct got_tree_entry *te2 = NULL; 620*59c8e88eSDag-Erling Smørgrav char *l1 = NULL, *l2 = NULL; 621*59c8e88eSDag-Erling Smørgrav int tidx1 = 0, tidx2 = 0; 622*59c8e88eSDag-Erling Smørgrav 623*59c8e88eSDag-Erling Smørgrav if (tree1) { 624*59c8e88eSDag-Erling Smørgrav te1 = got_object_tree_get_entry(tree1, 0); 625*59c8e88eSDag-Erling Smørgrav if (te1 && asprintf(&l1, "%s%s%s", label1, label1[0] ? "/" : "", 626*59c8e88eSDag-Erling Smørgrav te1->name) == -1) 627*59c8e88eSDag-Erling Smørgrav return got_error_from_errno("asprintf"); 628*59c8e88eSDag-Erling Smørgrav } 629*59c8e88eSDag-Erling Smørgrav if (tree2) { 630*59c8e88eSDag-Erling Smørgrav te2 = got_object_tree_get_entry(tree2, 0); 631*59c8e88eSDag-Erling Smørgrav if (te2 && asprintf(&l2, "%s%s%s", label2, label2[0] ? "/" : "", 632*59c8e88eSDag-Erling Smørgrav te2->name) == -1) 633*59c8e88eSDag-Erling Smørgrav return got_error_from_errno("asprintf"); 634*59c8e88eSDag-Erling Smørgrav } 635*59c8e88eSDag-Erling Smørgrav 636*59c8e88eSDag-Erling Smørgrav do { 637*59c8e88eSDag-Erling Smørgrav if (te1) { 638*59c8e88eSDag-Erling Smørgrav struct got_tree_entry *te = NULL; 639*59c8e88eSDag-Erling Smørgrav if (tree2) 640*59c8e88eSDag-Erling Smørgrav te = got_object_tree_find_entry(tree2, 641*59c8e88eSDag-Erling Smørgrav te1->name); 642*59c8e88eSDag-Erling Smørgrav if (te) { 643*59c8e88eSDag-Erling Smørgrav free(l2); 644*59c8e88eSDag-Erling Smørgrav l2 = NULL; 645*59c8e88eSDag-Erling Smørgrav if (te && asprintf(&l2, "%s%s%s", label2, 646*59c8e88eSDag-Erling Smørgrav label2[0] ? "/" : "", te->name) == -1) 647*59c8e88eSDag-Erling Smørgrav return 648*59c8e88eSDag-Erling Smørgrav got_error_from_errno("asprintf"); 649*59c8e88eSDag-Erling Smørgrav } 650*59c8e88eSDag-Erling Smørgrav err = diff_entry_old_new(te1, te, l1, l2, repo, cb, 651*59c8e88eSDag-Erling Smørgrav cb_arg, diff_content); 652*59c8e88eSDag-Erling Smørgrav if (err) 653*59c8e88eSDag-Erling Smørgrav break; 654*59c8e88eSDag-Erling Smørgrav } 655*59c8e88eSDag-Erling Smørgrav 656*59c8e88eSDag-Erling Smørgrav if (te2) { 657*59c8e88eSDag-Erling Smørgrav struct got_tree_entry *te = NULL; 658*59c8e88eSDag-Erling Smørgrav if (tree1) 659*59c8e88eSDag-Erling Smørgrav te = got_object_tree_find_entry(tree1, 660*59c8e88eSDag-Erling Smørgrav te2->name); 661*59c8e88eSDag-Erling Smørgrav free(l2); 662*59c8e88eSDag-Erling Smørgrav if (te) { 663*59c8e88eSDag-Erling Smørgrav if (asprintf(&l2, "%s%s%s", label2, 664*59c8e88eSDag-Erling Smørgrav label2[0] ? "/" : "", te->name) == -1) 665*59c8e88eSDag-Erling Smørgrav return 666*59c8e88eSDag-Erling Smørgrav got_error_from_errno("asprintf"); 667*59c8e88eSDag-Erling Smørgrav } else { 668*59c8e88eSDag-Erling Smørgrav if (asprintf(&l2, "%s%s%s", label2, 669*59c8e88eSDag-Erling Smørgrav label2[0] ? "/" : "", te2->name) == -1) 670*59c8e88eSDag-Erling Smørgrav return 671*59c8e88eSDag-Erling Smørgrav got_error_from_errno("asprintf"); 672*59c8e88eSDag-Erling Smørgrav } 673*59c8e88eSDag-Erling Smørgrav err = diff_entry_new_old(te2, te, l2, repo, 674*59c8e88eSDag-Erling Smørgrav cb, cb_arg, diff_content); 675*59c8e88eSDag-Erling Smørgrav if (err) 676*59c8e88eSDag-Erling Smørgrav break; 677*59c8e88eSDag-Erling Smørgrav } 678*59c8e88eSDag-Erling Smørgrav 679*59c8e88eSDag-Erling Smørgrav free(l1); 680*59c8e88eSDag-Erling Smørgrav l1 = NULL; 681*59c8e88eSDag-Erling Smørgrav if (te1) { 682*59c8e88eSDag-Erling Smørgrav tidx1++; 683*59c8e88eSDag-Erling Smørgrav te1 = got_object_tree_get_entry(tree1, tidx1); 684*59c8e88eSDag-Erling Smørgrav if (te1 && 685*59c8e88eSDag-Erling Smørgrav asprintf(&l1, "%s%s%s", label1, 686*59c8e88eSDag-Erling Smørgrav label1[0] ? "/" : "", te1->name) == -1) 687*59c8e88eSDag-Erling Smørgrav return got_error_from_errno("asprintf"); 688*59c8e88eSDag-Erling Smørgrav } 689*59c8e88eSDag-Erling Smørgrav free(l2); 690*59c8e88eSDag-Erling Smørgrav l2 = NULL; 691*59c8e88eSDag-Erling Smørgrav if (te2) { 692*59c8e88eSDag-Erling Smørgrav tidx2++; 693*59c8e88eSDag-Erling Smørgrav te2 = got_object_tree_get_entry(tree2, tidx2); 694*59c8e88eSDag-Erling Smørgrav if (te2 && 695*59c8e88eSDag-Erling Smørgrav asprintf(&l2, "%s%s%s", label2, 696*59c8e88eSDag-Erling Smørgrav label2[0] ? "/" : "", te2->name) == -1) 697*59c8e88eSDag-Erling Smørgrav return got_error_from_errno("asprintf"); 698*59c8e88eSDag-Erling Smørgrav } 699*59c8e88eSDag-Erling Smørgrav } while (te1 || te2); 700*59c8e88eSDag-Erling Smørgrav 701*59c8e88eSDag-Erling Smørgrav return err; 702*59c8e88eSDag-Erling Smørgrav} 703*59c8e88eSDag-Erling Smørgrav 704*59c8e88eSDag-Erling Smørgravconst struct got_error * 705*59c8e88eSDag-Erling Smørgravgot_diff_objects_as_blobs(struct got_object_id *id1, struct got_object_id *id2, 706*59c8e88eSDag-Erling Smørgrav const char *label1, const char *label2, int diff_context, 707*59c8e88eSDag-Erling Smørgrav int ignore_whitespace, struct got_repository *repo, FILE *outfile) 708*59c8e88eSDag-Erling Smørgrav{ 709*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 710*59c8e88eSDag-Erling Smørgrav struct got_blob_object *blob1 = NULL, *blob2 = NULL; 711*59c8e88eSDag-Erling Smørgrav 712*59c8e88eSDag-Erling Smørgrav if (id1 == NULL && id2 == NULL) 713*59c8e88eSDag-Erling Smørgrav return got_error(GOT_ERR_NO_OBJ); 714*59c8e88eSDag-Erling Smørgrav 715*59c8e88eSDag-Erling Smørgrav if (id1) { 716*59c8e88eSDag-Erling Smørgrav err = got_object_open_as_blob(&blob1, repo, id1, 8192); 717*59c8e88eSDag-Erling Smørgrav if (err) 718*59c8e88eSDag-Erling Smørgrav goto done; 719*59c8e88eSDag-Erling Smørgrav } 720*59c8e88eSDag-Erling Smørgrav if (id2) { 721*59c8e88eSDag-Erling Smørgrav err = got_object_open_as_blob(&blob2, repo, id2, 8192); 722*59c8e88eSDag-Erling Smørgrav if (err) 723*59c8e88eSDag-Erling Smørgrav goto done; 724*59c8e88eSDag-Erling Smørgrav } 725*59c8e88eSDag-Erling Smørgrav err = got_diff_blob(blob1, blob2, label1, label2, diff_context, 726*59c8e88eSDag-Erling Smørgrav ignore_whitespace, outfile); 727*59c8e88eSDag-Erling Smørgravdone: 728*59c8e88eSDag-Erling Smørgrav if (blob1) 729*59c8e88eSDag-Erling Smørgrav got_object_blob_close(blob1); 730*59c8e88eSDag-Erling Smørgrav if (blob2) 731*59c8e88eSDag-Erling Smørgrav got_object_blob_close(blob2); 732*59c8e88eSDag-Erling Smørgrav return err; 733*59c8e88eSDag-Erling Smørgrav} 734*59c8e88eSDag-Erling Smørgrav 735*59c8e88eSDag-Erling Smørgravconst struct got_error * 736*59c8e88eSDag-Erling Smørgravgot_diff_objects_as_trees(struct got_object_id *id1, struct got_object_id *id2, 737*59c8e88eSDag-Erling Smørgrav char *label1, char *label2, int diff_context, int ignore_whitespace, 738*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, FILE *outfile) 739*59c8e88eSDag-Erling Smørgrav{ 740*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 741*59c8e88eSDag-Erling Smørgrav struct got_tree_object *tree1 = NULL, *tree2 = NULL; 742*59c8e88eSDag-Erling Smørgrav struct got_diff_blob_output_unidiff_arg arg; 743*59c8e88eSDag-Erling Smørgrav 744*59c8e88eSDag-Erling Smørgrav if (id1 == NULL && id2 == NULL) 745*59c8e88eSDag-Erling Smørgrav return got_error(GOT_ERR_NO_OBJ); 746*59c8e88eSDag-Erling Smørgrav 747*59c8e88eSDag-Erling Smørgrav if (id1) { 748*59c8e88eSDag-Erling Smørgrav err = got_object_open_as_tree(&tree1, repo, id1); 749*59c8e88eSDag-Erling Smørgrav if (err) 750*59c8e88eSDag-Erling Smørgrav goto done; 751*59c8e88eSDag-Erling Smørgrav } 752*59c8e88eSDag-Erling Smørgrav if (id2) { 753*59c8e88eSDag-Erling Smørgrav err = got_object_open_as_tree(&tree2, repo, id2); 754*59c8e88eSDag-Erling Smørgrav if (err) 755*59c8e88eSDag-Erling Smørgrav goto done; 756*59c8e88eSDag-Erling Smørgrav } 757*59c8e88eSDag-Erling Smørgrav arg.diff_context = diff_context; 758*59c8e88eSDag-Erling Smørgrav arg.ignore_whitespace = ignore_whitespace; 759*59c8e88eSDag-Erling Smørgrav arg.outfile = outfile; 760*59c8e88eSDag-Erling Smørgrav err = got_diff_tree(tree1, tree2, label1, label2, repo, 761*59c8e88eSDag-Erling Smørgrav got_diff_blob_output_unidiff, &arg, 1); 762*59c8e88eSDag-Erling Smørgravdone: 763*59c8e88eSDag-Erling Smørgrav if (tree1) 764*59c8e88eSDag-Erling Smørgrav got_object_tree_close(tree1); 765*59c8e88eSDag-Erling Smørgrav if (tree2) 766*59c8e88eSDag-Erling Smørgrav got_object_tree_close(tree2); 767*59c8e88eSDag-Erling Smørgrav return err; 768*59c8e88eSDag-Erling Smørgrav} 769*59c8e88eSDag-Erling Smørgrav 770*59c8e88eSDag-Erling Smørgravconst struct got_error * 771*59c8e88eSDag-Erling Smørgravgot_diff_objects_as_commits(struct got_object_id *id1, 772*59c8e88eSDag-Erling Smørgrav struct got_object_id *id2, int diff_context, int ignore_whitespace, 773*59c8e88eSDag-Erling Smørgrav struct got_repository *repo, FILE *outfile) 774*59c8e88eSDag-Erling Smørgrav{ 775*59c8e88eSDag-Erling Smørgrav const struct got_error *err; 776*59c8e88eSDag-Erling Smørgrav struct got_commit_object *commit1 = NULL, *commit2 = NULL; 777*59c8e88eSDag-Erling Smørgrav 778*59c8e88eSDag-Erling Smørgrav if (id2 == NULL) 779*59c8e88eSDag-Erling Smørgrav return got_error(GOT_ERR_NO_OBJ); 780*59c8e88eSDag-Erling Smørgrav 781*59c8e88eSDag-Erling Smørgrav if (id1) { 782*59c8e88eSDag-Erling Smørgrav err = got_object_open_as_commit(&commit1, repo, id1); 783*59c8e88eSDag-Erling Smørgrav if (err) 784*59c8e88eSDag-Erling Smørgrav goto done; 785*59c8e88eSDag-Erling Smørgrav } 786*59c8e88eSDag-Erling Smørgrav 787*59c8e88eSDag-Erling Smørgrav err = got_object_open_as_commit(&commit2, repo, id2); 788*59c8e88eSDag-Erling Smørgrav if (err) 789*59c8e88eSDag-Erling Smørgrav goto done; 790*59c8e88eSDag-Erling Smørgrav 791*59c8e88eSDag-Erling Smørgrav err = got_diff_objects_as_trees( 792*59c8e88eSDag-Erling Smørgrav commit1 ? got_object_commit_get_tree_id(commit1) : NULL, 793*59c8e88eSDag-Erling Smørgrav got_object_commit_get_tree_id(commit2), "", "", diff_context, 794*59c8e88eSDag-Erling Smørgrav ignore_whitespace, repo, outfile); 795*59c8e88eSDag-Erling Smørgravdone: 796*59c8e88eSDag-Erling Smørgrav if (commit1) 797*59c8e88eSDag-Erling Smørgrav got_object_commit_close(commit1); 798*59c8e88eSDag-Erling Smørgrav if (commit2) 799*59c8e88eSDag-Erling Smørgrav got_object_commit_close(commit2); 800*59c8e88eSDag-Erling Smørgrav return err; 801*59c8e88eSDag-Erling Smørgrav} 802*59c8e88eSDag-Erling Smørgrav 803*59c8e88eSDag-Erling Smørgravconst struct got_error * 804*59c8e88eSDag-Erling Smørgravgot_diff_files(struct got_diffreg_result **resultp, 805*59c8e88eSDag-Erling Smørgrav FILE *f1, const char *label1, FILE *f2, const char *label2, 806*59c8e88eSDag-Erling Smørgrav int diff_context, int ignore_whitespace, FILE *outfile) 807*59c8e88eSDag-Erling Smørgrav{ 808*59c8e88eSDag-Erling Smørgrav const struct got_error *err = NULL; 809*59c8e88eSDag-Erling Smørgrav struct got_diffreg_result *diffreg_result = NULL; 810*59c8e88eSDag-Erling Smørgrav 811*59c8e88eSDag-Erling Smørgrav if (resultp) 812*59c8e88eSDag-Erling Smørgrav *resultp = NULL; 813*59c8e88eSDag-Erling Smørgrav 814*59c8e88eSDag-Erling Smørgrav if (outfile) { 815*59c8e88eSDag-Erling Smørgrav fprintf(outfile, "file - %s\n", 816*59c8e88eSDag-Erling Smørgrav f1 == NULL ? "/dev/null" : label1); 817*59c8e88eSDag-Erling Smørgrav fprintf(outfile, "file + %s\n", 818*59c8e88eSDag-Erling Smørgrav f2 == NULL ? "/dev/null" : label2); 819*59c8e88eSDag-Erling Smørgrav } 820*59c8e88eSDag-Erling Smørgrav 821*59c8e88eSDag-Erling Smørgrav err = got_diffreg(&diffreg_result, f1, f2, GOT_DIFF_ALGORITHM_MYERS, 822*59c8e88eSDag-Erling Smørgrav ignore_whitespace); 823*59c8e88eSDag-Erling Smørgrav if (err) 824*59c8e88eSDag-Erling Smørgrav goto done; 825*59c8e88eSDag-Erling Smørgrav 826*59c8e88eSDag-Erling Smørgrav if (outfile) { 827*59c8e88eSDag-Erling Smørgrav err = got_diffreg_output(NULL, NULL, diffreg_result, 828*59c8e88eSDag-Erling Smørgrav f1, f2, label1, label2, GOT_DIFF_OUTPUT_UNIDIFF, 829*59c8e88eSDag-Erling Smørgrav diff_context, outfile); 830*59c8e88eSDag-Erling Smørgrav if (err) 831*59c8e88eSDag-Erling Smørgrav goto done; 832*59c8e88eSDag-Erling Smørgrav } 833*59c8e88eSDag-Erling Smørgrav 834*59c8e88eSDag-Erling Smørgravdone: 835*59c8e88eSDag-Erling Smørgrav if (resultp && err == NULL) 836*59c8e88eSDag-Erling Smørgrav *resultp = diffreg_result; 837*59c8e88eSDag-Erling Smørgrav else if (diffreg_result) { 838*59c8e88eSDag-Erling Smørgrav const struct got_error *free_err; 839*59c8e88eSDag-Erling Smørgrav free_err = got_diffreg_result_free(diffreg_result); 840*59c8e88eSDag-Erling Smørgrav if (free_err && err == NULL) 841*59c8e88eSDag-Erling Smørgrav err = free_err; 842*59c8e88eSDag-Erling Smørgrav } 843*59c8e88eSDag-Erling Smørgrav 844*59c8e88eSDag-Erling Smørgrav return err; 845*59c8e88eSDag-Erling Smørgrav} 846