/* * We anonymize each component of a path individually, * so that paths a/b and a/c will share a common root. * The paths are cached via anonymize_mem so that repeated * lookups for "a" will yield the same value. */ static void anonymize_path(struct strbuf *out, const char *path, struct hashmap *map, void *(*generate)(const void *, size_t *)) { while (*path) { const char *end_of_component = strchrnul(path, '/'); size_t len = end_of_component - path; const char *c = anonymize_mem(map, generate, path, &len); strbuf_add(out, c, len); path = end_of_component; if (*path) strbuf_addch(out, *path++); } }
/* * Our strategy here is to anonymize the names and email addresses, * but keep timestamps intact, as they influence things like traversal * order (and by themselves should not be too revealing). */ static void anonymize_ident_line(const char **beg, const char **end) { static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT }; static unsigned which_buffer; struct strbuf *out; struct ident_split split; const char *end_of_header; out = &buffers[which_buffer++]; which_buffer %= ARRAY_SIZE(buffers); strbuf_reset(out); /* skip "committer", "author", "tagger", etc */ end_of_header = strchr(*beg, ' '); if (!end_of_header) die("BUG: malformed line fed to anonymize_ident_line: %.*s", (int)(*end - *beg), *beg); end_of_header++; strbuf_add(out, *beg, end_of_header - *beg); if (!split_ident_line(&split, end_of_header, *end - end_of_header) && split.date_begin) { const char *ident; size_t len; len = split.mail_end - split.name_begin; ident = anonymize_mem(&idents, anonymize_ident, split.name_begin, &len); strbuf_add(out, ident, len); strbuf_addch(out, ' '); strbuf_add(out, split.date_begin, split.tz_end - split.date_begin); } else { strbuf_addstr(out, "Malformed Ident <*****@*****.**> 0 -0000"); } *beg = out->buf; *end = out->buf + out->len; }
static void handle_tag(const char *name, struct tag *tag) { unsigned long size; enum object_type type; char *buf; const char *tagger, *tagger_end, *message; size_t message_size = 0; struct object *tagged; int tagged_mark; struct commit *p; /* Trees have no identifier in fast-export output, thus we have no way * to output tags of trees, tags of tags of trees, etc. Simply omit * such tags. */ tagged = tag->tagged; while (tagged->type == OBJ_TAG) { tagged = ((struct tag *)tagged)->tagged; } if (tagged->type == OBJ_TREE) { warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.", sha1_to_hex(tag->object.sha1)); return; } buf = read_sha1_file(tag->object.sha1, &type, &size); if (!buf) die ("Could not read tag %s", sha1_to_hex(tag->object.sha1)); message = memmem(buf, size, "\n\n", 2); if (message) { message += 2; message_size = strlen(message); } tagger = memmem(buf, message ? message - buf : size, "\ntagger ", 8); if (!tagger) { if (fake_missing_tagger) tagger = "tagger Unspecified Tagger " "<unspecified-tagger> 0 +0000"; else tagger = ""; tagger_end = tagger + strlen(tagger); } else { tagger++; tagger_end = strchrnul(tagger, '\n'); if (anonymize) anonymize_ident_line(&tagger, &tagger_end); } if (anonymize) { name = anonymize_refname(name); if (message) { static struct hashmap tags; message = anonymize_mem(&tags, anonymize_tag, message, &message_size); } } /* handle signed tags */ if (message) { const char *signature = strstr(message, "\n-----BEGIN PGP SIGNATURE-----\n"); if (signature) switch(signed_tag_mode) { case ABORT: die ("Encountered signed tag %s; use " "--signed-tags=<mode> to handle it.", sha1_to_hex(tag->object.sha1)); case WARN: warning ("Exporting signed tag %s", sha1_to_hex(tag->object.sha1)); /* fallthru */ case VERBATIM: break; case WARN_STRIP: warning ("Stripping signature from tag %s", sha1_to_hex(tag->object.sha1)); /* fallthru */ case STRIP: message_size = signature + 1 - message; break; } } /* handle tag->tagged having been filtered out due to paths specified */ tagged = tag->tagged; tagged_mark = get_object_mark(tagged); if (!tagged_mark) { switch(tag_of_filtered_mode) { case ABORT: die ("Tag %s tags unexported object; use " "--tag-of-filtered-object=<mode> to handle it.", sha1_to_hex(tag->object.sha1)); case DROP: /* Ignore this tag altogether */ return; case REWRITE: if (tagged->type != OBJ_COMMIT) { die ("Tag %s tags unexported %s!", sha1_to_hex(tag->object.sha1), typename(tagged->type)); } p = (struct commit *)tagged; for (;;) { if (p->parents && p->parents->next) break; if (p->object.flags & UNINTERESTING) break; if (!(p->object.flags & TREESAME)) break; if (!p->parents) die ("Can't find replacement commit for tag %s\n", sha1_to_hex(tag->object.sha1)); p = p->parents->item; } tagged_mark = get_object_mark(&p->object); } }
static const unsigned char *anonymize_sha1(const unsigned char *sha1) { static struct hashmap sha1s; size_t len = 20; return anonymize_mem(&sha1s, generate_fake_sha1, sha1, &len); }
static const unsigned char *anonymize_sha1(const struct object_id *oid) { static struct hashmap sha1s; size_t len = GIT_SHA1_RAWSZ; return anonymize_mem(&sha1s, generate_fake_oid, oid, &len); }