1#include"cache.h" 2#include"strbuf.h" 3#include"tag.h" 4 5/* 6 * A signature file has a very simple fixed format: four lines 7 * of "object <sha1>" + "type <typename>" + "tag <tagname>" + 8 * "tagger <committer>", followed by a blank line, a free-form tag 9 * message and a signature block that git itself doesn't care about, 10 * but that can be verified with gpg or similar. 11 * 12 * The first three lines are guaranteed to be at least 63 bytes: 13 * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the 14 * shortest possible type-line, and "tag .\n" at 6 bytes is the 15 * shortest single-character-tag line. 16 */ 17 18/* 19 * We refuse to tag something we can't verify. Just because. 20 */ 21static intverify_object(unsigned char*sha1,const char*expected_type) 22{ 23int ret = -1; 24enum object_type type; 25unsigned long size; 26void*buffer =read_sha1_file(sha1, &type, &size); 27 28if(buffer) { 29if(type ==type_from_string(expected_type)) 30 ret =check_sha1_signature(sha1, buffer, size, expected_type); 31free(buffer); 32} 33return ret; 34} 35 36#ifdef NO_C99_FORMAT 37#define PD_FMT"%d" 38#else 39#define PD_FMT"%td" 40#endif 41 42static intverify_tag(char*buffer,unsigned long size) 43{ 44int typelen; 45char type[20]; 46unsigned char sha1[20]; 47const char*object, *type_line, *tag_line, *tagger_line; 48 49if(size <64) 50returnerror("wanna fool me ? you obviously got the size wrong !"); 51 52 buffer[size] =0; 53 54/* Verify object line */ 55 object = buffer; 56if(memcmp(object,"object ",7)) 57returnerror("char%d: does not start with\"object\"",0); 58 59if(get_sha1_hex(object +7, sha1)) 60returnerror("char%d: could not get SHA1 hash",7); 61 62/* Verify type line */ 63 type_line = object +48; 64if(memcmp(type_line -1,"\ntype ",6)) 65returnerror("char%d: could not find\"\\ntype\"",47); 66 67/* Verify tag-line */ 68 tag_line =strchr(type_line,'\n'); 69if(!tag_line) 70returnerror("char" PD_FMT ": could not find next\"\\n\"", type_line - buffer); 71 tag_line++; 72if(memcmp(tag_line,"tag ",4) || tag_line[4] =='\n') 73returnerror("char" PD_FMT ": no\"tag\"found", tag_line - buffer); 74 75/* Get the actual type */ 76 typelen = tag_line - type_line -strlen("type\n"); 77if(typelen >=sizeof(type)) 78returnerror("char" PD_FMT ": type too long", type_line+5- buffer); 79 80memcpy(type, type_line+5, typelen); 81 type[typelen] =0; 82 83/* Verify that the object matches */ 84if(verify_object(sha1, type)) 85returnerror("char%d: could not verify object%s",7,sha1_to_hex(sha1)); 86 87/* Verify the tag-name: we don't allow control characters or spaces in it */ 88 tag_line +=4; 89for(;;) { 90unsigned char c = *tag_line++; 91if(c =='\n') 92break; 93if(c >' ') 94continue; 95returnerror("char" PD_FMT ": could not verify tag name", tag_line - buffer); 96} 97 98/* Verify the tagger line */ 99 tagger_line = tag_line; 100 101if(memcmp(tagger_line,"tagger",6) || (tagger_line[6] =='\n')) 102returnerror("char" PD_FMT ": could not find\"tagger\"", tagger_line - buffer); 103 104/* TODO: check for committer info + blank line? */ 105/* Also, the minimum length is probably + "tagger .", or 63+8=71 */ 106 107/* The actual stuff afterwards we don't care about.. */ 108return0; 109} 110 111#undef PD_FMT 112 113intmain(int argc,char**argv) 114{ 115struct strbuf buf; 116unsigned char result_sha1[20]; 117 118if(argc !=1) 119usage("git-mktag < signaturefile"); 120 121setup_git_directory(); 122 123strbuf_init(&buf,0); 124if(strbuf_read(&buf,0,4096) <0) { 125die("could not read from stdin"); 126} 127 128/* Verify it for some basic sanity: it needs to start with 129 "object <sha1>\ntype\ntagger " */ 130if(verify_tag(buf.buf, buf.len) <0) 131die("invalid tag signature file"); 132 133if(write_sha1_file(buf.buf, buf.len, tag_type, result_sha1) <0) 134die("unable to write tag file"); 135 136strbuf_release(&buf); 137printf("%s\n",sha1_to_hex(result_sha1)); 138return0; 139}