Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2
3 #include "test-tool.h"
4 #include "git-compat-util.h"
5 #include "delta.h"
6 #include "git-zlib.h"
7 #include "hash.h"
8 #include "hex.h"
9 #include "pack.h"
10 #include "pack-objects.h"
11 #include "parse-options.h"
12 #include "setup.h"
13 #include "strbuf.h"
14 #include "string-list.h"
15
16 static const char *usage_str[] = {
17 "test-tool pack-deltas --num-objects <num-objects>",
18 NULL
19 };
20
21 static unsigned long do_compress(void **pptr, unsigned long size)
22 {
23 git_zstream stream;
24 void *in, *out;
25 unsigned long maxsize;
26
27 git_deflate_init(&stream, 1);
28 maxsize = git_deflate_bound(&stream, size);
29
30 in = *pptr;
31 out = xmalloc(maxsize);
32 *pptr = out;
33
34 stream.next_in = in;
35 stream.avail_in = size;
36 stream.next_out = out;
37 stream.avail_out = maxsize;
38 while (git_deflate(&stream, Z_FINISH) == Z_OK)
39 ; /* nothing */
40 git_deflate_end(&stream);
41
42 free(in);
43 return stream.total_out;
44 }
45
46 static void write_ref_delta(struct hashfile *f,
47 struct object_id *oid,
48 struct object_id *base)
49 {
50 unsigned char header[MAX_PACK_OBJECT_HEADER];
51 unsigned long delta_size, compressed_size, hdrlen;
52 size_t size, base_size;
53 enum object_type type;
54 void *base_buf, *delta_buf;
55 void *buf = odb_read_object(the_repository->objects,
56 oid, &type, &size);
57
58 if (!buf)
59 die("unable to read %s", oid_to_hex(oid));
60
61 base_buf = odb_read_object(the_repository->objects,
62 base, &type, &base_size);
63
64 if (!base_buf)
65 die("unable to read %s", oid_to_hex(base));
66
67 delta_buf = diff_delta(base_buf, base_size,
68 buf, size, &delta_size, 0);
69
70 compressed_size = do_compress(&delta_buf, delta_size);
71
72 hdrlen = encode_in_pack_object_header(header, sizeof(header),
73 OBJ_REF_DELTA, delta_size);
74 hashwrite(f, header, hdrlen);
75 hashwrite(f, base->hash, the_repository->hash_algo->rawsz);
76 hashwrite(f, delta_buf, compressed_size);
77
78 free(buf);
79 free(base_buf);
80 free(delta_buf);
81 }
82
83 int cmd__pack_deltas(int argc, const char **argv)
84 {
85 int num_objects = -1;
86 struct hashfile *f;
87 struct strbuf line = STRBUF_INIT;
88 struct option options[] = {
89 OPT_INTEGER('n', "num-objects", &num_objects, N_("the number of objects to write")),
90 OPT_END()
91 };
92
93 argc = parse_options(argc, argv, NULL,
94 options, usage_str, 0);
95
96 if (argc || num_objects < 0)
97 usage_with_options(usage_str, options);
98
99 setup_git_directory(the_repository);
100
101 f = hashfd(the_repository->hash_algo, 1, "<stdout>");
102 write_pack_header(f, num_objects);
103
104 /* Read each line from stdin into 'line' */
105 while (strbuf_getline_lf(&line, stdin) != EOF) {
106 const char *type_str, *content_oid_str, *base_oid_str = NULL;
107 struct object_id content_oid, base_oid;
108 struct string_list items = STRING_LIST_INIT_NODUP;
109 /*
110 * Tokenize into two or three parts:
111 * 1. REF_DELTA, OFS_DELTA, or FULL.
112 * 2. The object ID for the content object.
113 * 3. The object ID for the base object (optional).
114 */
115 if (string_list_split_in_place(&items, line.buf, " ", 3) < 0)
116 die("invalid input format: %s", line.buf);
117
118 if (items.nr < 2)
119 die("invalid input format: %s", line.buf);
120
121 type_str = items.items[0].string;
122 content_oid_str = items.items[1].string;
123
124 if (get_oid_hex(content_oid_str, &content_oid))
125 die("invalid object: %s", content_oid_str);
126 if (items.nr >= 3) {
127 base_oid_str = items.items[2].string;
128 if (get_oid_hex(base_oid_str, &base_oid))
129 die("invalid object: %s", base_oid_str);
130 }
131 string_list_clear(&items, 0);
132
133 if (!strcmp(type_str, "REF_DELTA"))
134 write_ref_delta(f, &content_oid, &base_oid);
135 else if (!strcmp(type_str, "OFS_DELTA"))
136 die("OFS_DELTA not implemented");
137 else if (!strcmp(type_str, "FULL"))
138 die("FULL not implemented");
139 else
140 die("unknown pack type: %s", type_str);
141 }
142
143 finalize_hashfile(f, NULL, FSYNC_COMPONENT_PACK,
144 CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
145 strbuf_release(&line);
146 return 0;
147 }