]> git.ipfire.org Git - thirdparty/git.git/blobdiff - streaming.c
object-file.c: use "enum" return type for unpack_loose_header()
[thirdparty/git.git] / streaming.c
index 800f07a52cc850d7f972d7c651a8641eda2dfe38..6df0247a4cb5bedca5406cce392a5b708b74a761 100644 (file)
@@ -8,54 +8,13 @@
 #include "replace-object.h"
 #include "packfile.h"
 
-enum input_source {
-       stream_error = -1,
-       incore = 0,
-       loose = 1,
-       pack_non_delta = 2
-};
-
 typedef int (*open_istream_fn)(struct git_istream *,
                               struct repository *,
-                              struct object_info *,
                               const struct object_id *,
                               enum object_type *);
 typedef int (*close_istream_fn)(struct git_istream *);
 typedef ssize_t (*read_istream_fn)(struct git_istream *, char *, size_t);
 
-struct stream_vtbl {
-       close_istream_fn close;
-       read_istream_fn read;
-};
-
-#define open_method_decl(name) \
-       int open_istream_ ##name \
-       (struct git_istream *st, struct repository *r, \
-        struct object_info *oi, const struct object_id *oid, \
-        enum object_type *type)
-
-#define close_method_decl(name) \
-       int close_istream_ ##name \
-       (struct git_istream *st)
-
-#define read_method_decl(name) \
-       ssize_t read_istream_ ##name \
-       (struct git_istream *st, char *buf, size_t sz)
-
-/* forward declaration */
-static open_method_decl(incore);
-static open_method_decl(loose);
-static open_method_decl(pack_non_delta);
-static struct git_istream *attach_stream_filter(struct git_istream *st,
-                                               struct stream_filter *filter);
-
-
-static open_istream_fn open_istream_tbl[] = {
-       open_istream_incore,
-       open_istream_loose,
-       open_istream_pack_non_delta,
-};
-
 #define FILTER_BUFFER (1024*16)
 
 struct filtered_istream {
@@ -69,7 +28,10 @@ struct filtered_istream {
 };
 
 struct git_istream {
-       const struct stream_vtbl *vtbl;
+       open_istream_fn open;
+       close_istream_fn close;
+       read_istream_fn read;
+
        unsigned long size; /* inflated size of full object */
        git_zstream z;
        enum { z_unused, z_used, z_done, z_error } z_state;
@@ -97,80 +59,6 @@ struct git_istream {
        } u;
 };
 
-int close_istream(struct git_istream *st)
-{
-       int r = st->vtbl->close(st);
-       free(st);
-       return r;
-}
-
-ssize_t read_istream(struct git_istream *st, void *buf, size_t sz)
-{
-       return st->vtbl->read(st, buf, sz);
-}
-
-static enum input_source istream_source(struct repository *r,
-                                       const struct object_id *oid,
-                                       enum object_type *type,
-                                       struct object_info *oi)
-{
-       unsigned long size;
-       int status;
-
-       oi->typep = type;
-       oi->sizep = &size;
-       status = oid_object_info_extended(r, oid, oi, 0);
-       if (status < 0)
-               return stream_error;
-
-       switch (oi->whence) {
-       case OI_LOOSE:
-               return loose;
-       case OI_PACKED:
-               if (!oi->u.packed.is_delta && big_file_threshold < size)
-                       return pack_non_delta;
-               /* fallthru */
-       default:
-               return incore;
-       }
-}
-
-struct git_istream *open_istream(struct repository *r,
-                                const struct object_id *oid,
-                                enum object_type *type,
-                                unsigned long *size,
-                                struct stream_filter *filter)
-{
-       struct git_istream *st;
-       struct object_info oi = OBJECT_INFO_INIT;
-       const struct object_id *real = lookup_replace_object(r, oid);
-       enum input_source src = istream_source(r, real, type, &oi);
-
-       if (src < 0)
-               return NULL;
-
-       st = xmalloc(sizeof(*st));
-       if (open_istream_tbl[src](st, r, &oi, real, type)) {
-               if (open_istream_incore(st, r, &oi, real, type)) {
-                       free(st);
-                       return NULL;
-               }
-       }
-       if (filter) {
-               /* Add "&& !is_null_stream_filter(filter)" for performance */
-               struct git_istream *nst = attach_stream_filter(st, filter);
-               if (!nst) {
-                       close_istream(st);
-                       return NULL;
-               }
-               st = nst;
-       }
-
-       *size = st->size;
-       return st;
-}
-
-
 /*****************************************************************
  *
  * Common helpers
@@ -190,13 +78,14 @@ static void close_deflated_stream(struct git_istream *st)
  *
  *****************************************************************/
 
-static close_method_decl(filtered)
+static int close_istream_filtered(struct git_istream *st)
 {
        free_stream_filter(st->u.filtered.filter);
        return close_istream(st->u.filtered.upstream);
 }
 
-static read_method_decl(filtered)
+static ssize_t read_istream_filtered(struct git_istream *st, char *buf,
+                                    size_t sz)
 {
        struct filtered_istream *fs = &(st->u.filtered);
        size_t filled = 0;
@@ -255,18 +144,14 @@ static read_method_decl(filtered)
        return filled;
 }
 
-static struct stream_vtbl filtered_vtbl = {
-       close_istream_filtered,
-       read_istream_filtered,
-};
-
 static struct git_istream *attach_stream_filter(struct git_istream *st,
                                                struct stream_filter *filter)
 {
        struct git_istream *ifs = xmalloc(sizeof(*ifs));
        struct filtered_istream *fs = &(ifs->u.filtered);
 
-       ifs->vtbl = &filtered_vtbl;
+       ifs->close = close_istream_filtered;
+       ifs->read = read_istream_filtered;
        fs->upstream = st;
        fs->filter = filter;
        fs->i_end = fs->i_ptr = 0;
@@ -282,7 +167,7 @@ static struct git_istream *attach_stream_filter(struct git_istream *st,
  *
  *****************************************************************/
 
-static read_method_decl(loose)
+static ssize_t read_istream_loose(struct git_istream *st, char *buf, size_t sz)
 {
        size_t total_read = 0;
 
@@ -327,40 +212,45 @@ static read_method_decl(loose)
        return total_read;
 }
 
-static close_method_decl(loose)
+static int close_istream_loose(struct git_istream *st)
 {
        close_deflated_stream(st);
        munmap(st->u.loose.mapped, st->u.loose.mapsize);
        return 0;
 }
 
-static struct stream_vtbl loose_vtbl = {
-       close_istream_loose,
-       read_istream_loose,
-};
-
-static open_method_decl(loose)
+static int open_istream_loose(struct git_istream *st, struct repository *r,
+                             const struct object_id *oid,
+                             enum object_type *type)
 {
+       struct object_info oi = OBJECT_INFO_INIT;
+       oi.sizep = &st->size;
+
        st->u.loose.mapped = map_loose_object(r, oid, &st->u.loose.mapsize);
        if (!st->u.loose.mapped)
                return -1;
-       if ((unpack_loose_header(&st->z,
-                                st->u.loose.mapped,
-                                st->u.loose.mapsize,
-                                st->u.loose.hdr,
-                                sizeof(st->u.loose.hdr)) < 0) ||
-           (parse_loose_header(st->u.loose.hdr, &st->size) < 0)) {
-               git_inflate_end(&st->z);
-               munmap(st->u.loose.mapped, st->u.loose.mapsize);
-               return -1;
+       switch (unpack_loose_header(&st->z, st->u.loose.mapped,
+                                   st->u.loose.mapsize, st->u.loose.hdr,
+                                   sizeof(st->u.loose.hdr), NULL)) {
+       case ULHR_OK:
+               break;
+       case ULHR_BAD:
+               goto error;
        }
+       if (parse_loose_header(st->u.loose.hdr, &oi, 0) < 0)
+               goto error;
 
        st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1;
        st->u.loose.hdr_avail = st->z.total_out;
        st->z_state = z_used;
+       st->close = close_istream_loose;
+       st->read = read_istream_loose;
 
-       st->vtbl = &loose_vtbl;
        return 0;
+error:
+       git_inflate_end(&st->z);
+       munmap(st->u.loose.mapped, st->u.loose.mapsize);
+       return -1;
 }
 
 
@@ -370,7 +260,8 @@ static open_method_decl(loose)
  *
  *****************************************************************/
 
-static read_method_decl(pack_non_delta)
+static ssize_t read_istream_pack_non_delta(struct git_istream *st, char *buf,
+                                          size_t sz)
 {
        size_t total_read = 0;
 
@@ -428,24 +319,20 @@ static read_method_decl(pack_non_delta)
        return total_read;
 }
 
-static close_method_decl(pack_non_delta)
+static int close_istream_pack_non_delta(struct git_istream *st)
 {
        close_deflated_stream(st);
        return 0;
 }
 
-static struct stream_vtbl pack_non_delta_vtbl = {
-       close_istream_pack_non_delta,
-       read_istream_pack_non_delta,
-};
-
-static open_method_decl(pack_non_delta)
+static int open_istream_pack_non_delta(struct git_istream *st,
+                                      struct repository *r,
+                                      const struct object_id *oid,
+                                      enum object_type *type)
 {
        struct pack_window *window;
        enum object_type in_pack_type;
 
-       st->u.in_pack.pack = oi->u.packed.pack;
-       st->u.in_pack.pos = oi->u.packed.offset;
        window = NULL;
 
        in_pack_type = unpack_object_header(st->u.in_pack.pack,
@@ -463,7 +350,9 @@ static open_method_decl(pack_non_delta)
                break;
        }
        st->z_state = z_unused;
-       st->vtbl = &pack_non_delta_vtbl;
+       st->close = close_istream_pack_non_delta;
+       st->read = read_istream_pack_non_delta;
+
        return 0;
 }
 
@@ -474,13 +363,13 @@ static open_method_decl(pack_non_delta)
  *
  *****************************************************************/
 
-static close_method_decl(incore)
+static int close_istream_incore(struct git_istream *st)
 {
        free(st->u.incore.buf);
        return 0;
 }
 
-static read_method_decl(incore)
+static ssize_t read_istream_incore(struct git_istream *st, char *buf, size_t sz)
 {
        size_t read_size = sz;
        size_t remainder = st->size - st->u.incore.read_ptr;
@@ -494,25 +383,105 @@ static read_method_decl(incore)
        return read_size;
 }
 
-static struct stream_vtbl incore_vtbl = {
-       close_istream_incore,
-       read_istream_incore,
-};
-
-static open_method_decl(incore)
+static int open_istream_incore(struct git_istream *st, struct repository *r,
+                              const struct object_id *oid, enum object_type *type)
 {
        st->u.incore.buf = read_object_file_extended(r, oid, type, &st->size, 0);
        st->u.incore.read_ptr = 0;
-       st->vtbl = &incore_vtbl;
+       st->close = close_istream_incore;
+       st->read = read_istream_incore;
 
        return st->u.incore.buf ? 0 : -1;
 }
 
+/*****************************************************************************
+ * static helpers variables and functions for users of streaming interface
+ *****************************************************************************/
+
+static int istream_source(struct git_istream *st,
+                         struct repository *r,
+                         const struct object_id *oid,
+                         enum object_type *type)
+{
+       unsigned long size;
+       int status;
+       struct object_info oi = OBJECT_INFO_INIT;
+
+       oi.typep = type;
+       oi.sizep = &size;
+       status = oid_object_info_extended(r, oid, &oi, 0);
+       if (status < 0)
+               return status;
+
+       switch (oi.whence) {
+       case OI_LOOSE:
+               st->open = open_istream_loose;
+               return 0;
+       case OI_PACKED:
+               if (!oi.u.packed.is_delta && big_file_threshold < size) {
+                       st->u.in_pack.pack = oi.u.packed.pack;
+                       st->u.in_pack.pos = oi.u.packed.offset;
+                       st->open = open_istream_pack_non_delta;
+                       return 0;
+               }
+               /* fallthru */
+       default:
+               st->open = open_istream_incore;
+               return 0;
+       }
+}
 
 /****************************************************************
  * Users of streaming interface
  ****************************************************************/
 
+int close_istream(struct git_istream *st)
+{
+       int r = st->close(st);
+       free(st);
+       return r;
+}
+
+ssize_t read_istream(struct git_istream *st, void *buf, size_t sz)
+{
+       return st->read(st, buf, sz);
+}
+
+struct git_istream *open_istream(struct repository *r,
+                                const struct object_id *oid,
+                                enum object_type *type,
+                                unsigned long *size,
+                                struct stream_filter *filter)
+{
+       struct git_istream *st = xmalloc(sizeof(*st));
+       const struct object_id *real = lookup_replace_object(r, oid);
+       int ret = istream_source(st, r, real, type);
+
+       if (ret) {
+               free(st);
+               return NULL;
+       }
+
+       if (st->open(st, r, real, type)) {
+               if (open_istream_incore(st, r, real, type)) {
+                       free(st);
+                       return NULL;
+               }
+       }
+       if (filter) {
+               /* Add "&& !is_null_stream_filter(filter)" for performance */
+               struct git_istream *nst = attach_stream_filter(st, filter);
+               if (!nst) {
+                       close_istream(st);
+                       return NULL;
+               }
+               st = nst;
+       }
+
+       *size = st->size;
+       return st;
+}
+
 int stream_blob_to_fd(int fd, const struct object_id *oid, struct stream_filter *filter,
                      int can_seek)
 {