static int ent_compare(const void *a_, const void *b_) { struct treeent *a = *(struct treeent **)a_; struct treeent *b = *(struct treeent **)b_; return base_name_compare(a->name, a->len, a->mode, b->name, b->len, b->mode); }
static int compare_paths(const struct combine_diff_path *one, const struct diff_filespec *two) { if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode)) return strcmp(one->path, two->path); return base_name_compare(one->path, strlen(one->path), one->mode, two->path, strlen(two->path), two->mode); }
static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; char *fullname; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); pathlen1 = tree_entry_len(path1, sha1); pathlen2 = tree_entry_len(path2, sha2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { show_entry(opt, "-", t1, base, baselen); return -1; } if (cmp > 0) { show_entry(opt, "+", t2, base, baselen); return 1; } if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2) return 0; /* * If the filemode has changed to/from a directory from/to a regular * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { show_entry(opt, "-", t1, base, baselen); show_entry(opt, "+", t2, base, baselen); return 0; } if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { int retval; char *newbase = malloc_base(base, baselen, path1, pathlen1); if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { newbase[baselen + pathlen1] = 0; opt->change(opt, mode1, mode2, sha1, sha2, newbase); newbase[baselen + pathlen1] = '/'; } retval = diff_tree_sha1(sha1, sha2, newbase, opt); free(newbase); return retval; } fullname = malloc_fullname(base, baselen, path1, pathlen1); opt->change(opt, mode1, mode2, sha1, sha2, fullname); free(fullname); return 0; }
static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, struct strbuf *base, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; int old_baselen = base->len; sha1 = tree_entry_extract(t1, &path1, &mode1); sha2 = tree_entry_extract(t2, &path2, &mode2); pathlen1 = tree_entry_len(path1, sha1); pathlen2 = tree_entry_len(path2, sha2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { show_entry(opt, "-", t1, base); return -1; } if (cmp > 0) { show_entry(opt, "+", t2, base); return 1; } if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2) return 0; /* * If the filemode has changed to/from a directory from/to a regular * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { show_entry(opt, "-", t1, base); show_entry(opt, "+", t2, base); return 0; } strbuf_add(base, path1, pathlen1); if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } strbuf_addch(base, '/'); diff_tree_sha1(sha1, sha2, base->buf, opt); } else { opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); } strbuf_setlen(base, old_baselen); return 0; }
static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt) { unsigned mode1, mode2; const char *path1, *path2; const unsigned char *sha1, *sha2; int cmp, pathlen1, pathlen2; sha1 = extract(t1, &path1, &mode1); sha2 = extract(t2, &path2, &mode2); pathlen1 = strlen(path1); pathlen2 = strlen(path2); cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2); if (cmp < 0) { show_entry(opt, "-", t1, base); return -1; } if (cmp > 0) { show_entry(opt, "+", t2, base); return 1; } if (!opt->find_copies_harder && !memcmp(sha1, sha2, 20) && mode1 == mode2) return 0; /* * If the filemode has changed to/from a directory from/to a regular * file, we need to consider it a remove and an add. */ if (S_ISDIR(mode1) != S_ISDIR(mode2)) { show_entry(opt, "-", t1, base); show_entry(opt, "+", t2, base); return 0; } if (opt->recursive && S_ISDIR(mode1)) { int retval; char *newbase = malloc_base(base, path1, pathlen1); if (opt->tree_in_recursive) opt->change(opt, mode1, mode2, sha1, sha2, base, path1); retval = diff_tree_sha1(sha1, sha2, newbase, opt); free(newbase); return retval; } opt->change(opt, mode1, mode2, sha1, sha2, base, path1); return 0; }
/* * Compare two tree entries, taking into account only path/S_ISDIR(mode), * but not their sha1's. * * NOTE files and directories *always* compare differently, even when having * the same name - thanks to base_name_compare(). * * NOTE empty (=invalid) descriptor(s) take part in comparison as +infty, * so that they sort *after* valid tree entries. * * Due to this convention, if trees are scanned in sorted order, all * non-empty descriptors will be processed first. */ static int tree_entry_pathcmp(struct tree_desc *t1, struct tree_desc *t2) { struct name_entry *e1, *e2; int cmp; /* empty descriptors sort after valid tree entries */ if (!t1->size) return t2->size ? 1 : 0; else if (!t2->size) return -1; e1 = &t1->entry; e2 = &t2->entry; cmp = base_name_compare(e1->path, tree_entry_len(e1), e1->mode, e2->path, tree_entry_len(e2), e2->mode); return cmp; }
static int base_name_entries_compare(const struct name_entry *a, const struct name_entry *b) { return base_name_compare(a->path, tree_entry_len(a), a->mode, b->path, tree_entry_len(b), b->mode); }
/* * Inspect two trees, and give a score that tells how similar they are. */ static int score_trees(const unsigned char *hash1, const unsigned char *hash2) { struct tree_desc one; struct tree_desc two; void *one_buf, *two_buf; int score = 0; enum object_type type; unsigned long size; one_buf = read_sha1_file(hash1, &type, &size); if (!one_buf) die("unable to read tree (%s)", sha1_to_hex(hash1)); if (type != OBJ_TREE) die("%s is not a tree", sha1_to_hex(hash1)); init_tree_desc(&one, one_buf, size); two_buf = read_sha1_file(hash2, &type, &size); if (!two_buf) die("unable to read tree (%s)", sha1_to_hex(hash2)); if (type != OBJ_TREE) die("%s is not a tree", sha1_to_hex(hash2)); init_tree_desc(&two, two_buf, size); while (one.size | two.size) { const unsigned char *elem1 = elem1; const unsigned char *elem2 = elem2; const char *path1 = path1; const char *path2 = path2; unsigned mode1 = mode1; unsigned mode2 = mode2; int cmp; if (one.size) elem1 = tree_entry_extract(&one, &path1, &mode1); if (two.size) elem2 = tree_entry_extract(&two, &path2, &mode2); if (!one.size) { /* two has more entries */ score += score_missing(mode2, path2); update_tree_entry(&two); continue; } if (!two.size) { /* two lacks this entry */ score += score_missing(mode1, path1); update_tree_entry(&one); continue; } cmp = base_name_compare(path1, strlen(path1), mode1, path2, strlen(path2), mode2); if (cmp < 0) { /* path1 does not appear in two */ score += score_missing(mode1, path1); update_tree_entry(&one); continue; } else if (cmp > 0) { /* path2 does not appear in one */ score += score_missing(mode2, path2); update_tree_entry(&two); continue; } else if (hashcmp(elem1, elem2)) /* they are different */ score += score_differs(mode1, mode2, path1); else /* same subtree or blob */ score += score_matches(mode1, mode2, path1); update_tree_entry(&one); update_tree_entry(&two); } free(one_buf); free(two_buf); return score; }