Code

13cbce7aabd1ad8552b2948c9935a77d96fc6dcb
[git.git] / streaming.c
1 /*
2  * Copyright (c) 2011, Google Inc.
3  */
4 #include "cache.h"
5 #include "streaming.h"
7 enum input_source {
8         stream_error = -1,
9         incore = 0,
10         loose = 1,
11         pack_non_delta = 2
12 };
14 typedef int (*open_istream_fn)(struct git_istream *,
15                                struct object_info *,
16                                const unsigned char *,
17                                enum object_type *);
18 typedef int (*close_istream_fn)(struct git_istream *);
19 typedef ssize_t (*read_istream_fn)(struct git_istream *, char *, size_t);
21 struct stream_vtbl {
22         close_istream_fn close;
23         read_istream_fn read;
24 };
26 #define open_method_decl(name) \
27         int open_istream_ ##name \
28         (struct git_istream *st, struct object_info *oi, \
29          const unsigned char *sha1, \
30          enum object_type *type)
32 #define close_method_decl(name) \
33         int close_istream_ ##name \
34         (struct git_istream *st)
36 #define read_method_decl(name) \
37         ssize_t read_istream_ ##name \
38         (struct git_istream *st, char *buf, size_t sz)
40 /* forward declaration */
41 static open_method_decl(incore);
42 static open_method_decl(loose);
43 static open_method_decl(pack_non_delta);
45 static open_istream_fn open_istream_tbl[] = {
46         open_istream_incore,
47         open_istream_loose,
48         open_istream_pack_non_delta,
49 };
51 struct git_istream {
52         const struct stream_vtbl *vtbl;
53         unsigned long size; /* inflated size of full object */
55         union {
56                 struct {
57                         char *buf; /* from read_object() */
58                         unsigned long read_ptr;
59                 } incore;
61                 struct {
62                         int fd; /* open for reading */
63                         /* NEEDSWORK: what else? */
64                 } loose;
66                 struct {
67                         int fd; /* open for reading */
68                         /* NEEDSWORK: what else? */
69                 } in_pack;
70         } u;
71 };
73 int close_istream(struct git_istream *st)
74 {
75         return st->vtbl->close(st);
76 }
78 ssize_t read_istream(struct git_istream *st, char *buf, size_t sz)
79 {
80         return st->vtbl->read(st, buf, sz);
81 }
83 static enum input_source istream_source(const unsigned char *sha1,
84                                         enum object_type *type,
85                                         struct object_info *oi)
86 {
87         unsigned long size;
88         int status;
90         oi->sizep = &size;
91         status = sha1_object_info_extended(sha1, oi);
92         if (status < 0)
93                 return stream_error;
94         *type = status;
96         switch (oi->whence) {
97         case OI_LOOSE:
98                 return loose;
99         case OI_PACKED:
100                 if (!oi->u.packed.is_delta && big_file_threshold <= size)
101                         return pack_non_delta;
102                 /* fallthru */
103         default:
104                 return incore;
105         }
108 struct git_istream *open_istream(const unsigned char *sha1,
109                                  enum object_type *type,
110                                  unsigned long *size)
112         struct git_istream *st;
113         struct object_info oi;
114         const unsigned char *real = lookup_replace_object(sha1);
115         enum input_source src = istream_source(real, type, &oi);
117         if (src < 0)
118                 return NULL;
120         st = xmalloc(sizeof(*st));
121         if (open_istream_tbl[src](st, &oi, real, type)) {
122                 if (open_istream_incore(st, &oi, real, type)) {
123                         free(st);
124                         return NULL;
125                 }
126         }
127         *size = st->size;
128         return st;
131 /*****************************************************************
132  *
133  * Loose object stream
134  *
135  *****************************************************************/
137 static open_method_decl(loose)
139         return -1; /* for now */
143 /*****************************************************************
144  *
145  * Non-delta packed object stream
146  *
147  *****************************************************************/
149 static open_method_decl(pack_non_delta)
151         return -1; /* for now */
155 /*****************************************************************
156  *
157  * In-core stream
158  *
159  *****************************************************************/
161 static close_method_decl(incore)
163         free(st->u.incore.buf);
164         return 0;
167 static read_method_decl(incore)
169         size_t read_size = sz;
170         size_t remainder = st->size - st->u.incore.read_ptr;
172         if (remainder <= read_size)
173                 read_size = remainder;
174         if (read_size) {
175                 memcpy(buf, st->u.incore.buf + st->u.incore.read_ptr, read_size);
176                 st->u.incore.read_ptr += read_size;
177         }
178         return read_size;
181 static struct stream_vtbl incore_vtbl = {
182         close_istream_incore,
183         read_istream_incore,
184 };
186 static open_method_decl(incore)
188         st->u.incore.buf = read_sha1_file_extended(sha1, type, &st->size, 0);
189         st->u.incore.read_ptr = 0;
190         st->vtbl = &incore_vtbl;
192         return st->u.incore.buf ? 0 : -1;