Skip to content

Commit 7ef2d9a

Browse files
committed
streaming: read non-delta incrementally from a pack
Helped-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent de6182d commit 7ef2d9a

File tree

1 file changed

+102
-3
lines changed

1 file changed

+102
-3
lines changed

streaming.c

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ static open_istream_fn open_istream_tbl[] = {
5151
struct git_istream {
5252
const struct stream_vtbl *vtbl;
5353
unsigned long size; /* inflated size of full object */
54+
z_stream z;
55+
enum { z_unused, z_used, z_done, z_error } z_state;
5456

5557
union {
5658
struct {
@@ -64,8 +66,8 @@ struct git_istream {
6466
} loose;
6567

6668
struct {
67-
int fd; /* open for reading */
68-
/* NEEDSWORK: what else? */
69+
struct packed_git *pack;
70+
off_t pos;
6971
} in_pack;
7072
} u;
7173
};
@@ -128,6 +130,20 @@ struct git_istream *open_istream(const unsigned char *sha1,
128130
return st;
129131
}
130132

133+
134+
/*****************************************************************
135+
*
136+
* Common helpers
137+
*
138+
*****************************************************************/
139+
140+
static void close_deflated_stream(struct git_istream *st)
141+
{
142+
if (st->z_state == z_used)
143+
git_inflate_end(&st->z);
144+
}
145+
146+
131147
/*****************************************************************
132148
*
133149
* Loose object stream
@@ -146,9 +162,92 @@ static open_method_decl(loose)
146162
*
147163
*****************************************************************/
148164

165+
static read_method_decl(pack_non_delta)
166+
{
167+
size_t total_read = 0;
168+
169+
switch (st->z_state) {
170+
case z_unused:
171+
memset(&st->z, 0, sizeof(st->z));
172+
git_inflate_init(&st->z);
173+
st->z_state = z_used;
174+
break;
175+
case z_done:
176+
return 0;
177+
case z_error:
178+
return -1;
179+
case z_used:
180+
break;
181+
}
182+
183+
while (total_read < sz) {
184+
int status;
185+
struct pack_window *window = NULL;
186+
unsigned char *mapped;
187+
188+
mapped = use_pack(st->u.in_pack.pack, &window,
189+
st->u.in_pack.pos, &st->z.avail_in);
190+
191+
st->z.next_out = (unsigned char *)buf + total_read;
192+
st->z.avail_out = sz - total_read;
193+
st->z.next_in = mapped;
194+
status = git_inflate(&st->z, Z_FINISH);
195+
196+
st->u.in_pack.pos += st->z.next_in - mapped;
197+
total_read = st->z.next_out - (unsigned char *)buf;
198+
unuse_pack(&window);
199+
200+
if (status == Z_STREAM_END) {
201+
git_inflate_end(&st->z);
202+
st->z_state = z_done;
203+
break;
204+
}
205+
if (status != Z_OK && status != Z_BUF_ERROR) {
206+
git_inflate_end(&st->z);
207+
st->z_state = z_error;
208+
return -1;
209+
}
210+
}
211+
return total_read;
212+
}
213+
214+
static close_method_decl(pack_non_delta)
215+
{
216+
close_deflated_stream(st);
217+
return 0;
218+
}
219+
220+
static struct stream_vtbl pack_non_delta_vtbl = {
221+
close_istream_pack_non_delta,
222+
read_istream_pack_non_delta,
223+
};
224+
149225
static open_method_decl(pack_non_delta)
150226
{
151-
return -1; /* for now */
227+
struct pack_window *window;
228+
enum object_type in_pack_type;
229+
230+
st->u.in_pack.pack = oi->u.packed.pack;
231+
st->u.in_pack.pos = oi->u.packed.offset;
232+
window = NULL;
233+
234+
in_pack_type = unpack_object_header(st->u.in_pack.pack,
235+
&window,
236+
&st->u.in_pack.pos,
237+
&st->size);
238+
unuse_pack(&window);
239+
switch (in_pack_type) {
240+
default:
241+
return -1; /* we do not do deltas for now */
242+
case OBJ_COMMIT:
243+
case OBJ_TREE:
244+
case OBJ_BLOB:
245+
case OBJ_TAG:
246+
break;
247+
}
248+
st->z_state = z_unused;
249+
st->vtbl = &pack_non_delta_vtbl;
250+
return 0;
152251
}
153252

154253

0 commit comments

Comments
 (0)