list-objects-filter: correct usage of ALLOC_GROW
[gitweb.git] / list-objects-filter.c
index 5b14d2711ad3791169f5d8cbc03836b4254bd55c..7824a480e18faad51b6c7161061f25c71c262b71 100644 (file)
@@ -11,6 +11,7 @@
 #include "list-objects-filter.h"
 #include "list-objects-filter-options.h"
 #include "oidset.h"
+#include "object-store.h"
 
 /* Remember to update object flag allocation in object.h */
 /*
@@ -43,8 +44,7 @@ static enum list_objects_filter_result filter_blobs_none(
 
        switch (filter_situation) {
        default:
-               die("unknown filter_situation");
-               return LOFR_ZERO;
+               BUG("unknown filter_situation: %d", filter_situation);
 
        case LOFS_BEGIN_TREE:
                assert(obj->type == OBJ_TREE);
@@ -79,6 +79,61 @@ static void *filter_blobs_none__init(
        return d;
 }
 
+/*
+ * A filter for list-objects to omit ALL trees and blobs from the traversal.
+ * Can OPTIONALLY collect a list of the omitted OIDs.
+ */
+struct filter_trees_none_data {
+       struct oidset *omits;
+};
+
+static enum list_objects_filter_result filter_trees_none(
+       enum list_objects_filter_situation filter_situation,
+       struct object *obj,
+       const char *pathname,
+       const char *filename,
+       void *filter_data_)
+{
+       struct filter_trees_none_data *filter_data = filter_data_;
+
+       switch (filter_situation) {
+       default:
+               BUG("unknown filter_situation: %d", filter_situation);
+
+       case LOFS_BEGIN_TREE:
+       case LOFS_BLOB:
+               if (filter_data->omits) {
+                       oidset_insert(filter_data->omits, &obj->oid);
+                       /* _MARK_SEEN but not _DO_SHOW (hard omit) */
+                       return LOFR_MARK_SEEN;
+               } else {
+                       /*
+                        * Not collecting omits so no need to to traverse tree.
+                        */
+                       return LOFR_SKIP_TREE | LOFR_MARK_SEEN;
+               }
+
+       case LOFS_END_TREE:
+               assert(obj->type == OBJ_TREE);
+               return LOFR_ZERO;
+
+       }
+}
+
+static void* filter_trees_none__init(
+       struct oidset *omitted,
+       struct list_objects_filter_options *filter_options,
+       filter_object_fn *filter_fn,
+       filter_free_fn *filter_free_fn)
+{
+       struct filter_trees_none_data *d = xcalloc(1, sizeof(*d));
+       d->omits = omitted;
+
+       *filter_fn = filter_trees_none;
+       *filter_free_fn = free;
+       return d;
+}
+
 /*
  * A filter for list-objects to omit large blobs.
  * And to OPTIONALLY collect a list of the omitted OIDs.
@@ -101,8 +156,7 @@ static enum list_objects_filter_result filter_blobs_limit(
 
        switch (filter_situation) {
        default:
-               die("unknown filter_situation");
-               return LOFR_ZERO;
+               BUG("unknown filter_situation: %d", filter_situation);
 
        case LOFS_BEGIN_TREE:
                assert(obj->type == OBJ_TREE);
@@ -207,8 +261,7 @@ static enum list_objects_filter_result filter_sparse(
 
        switch (filter_situation) {
        default:
-               die("unknown filter_situation");
-               return LOFR_ZERO;
+               BUG("unknown filter_situation: %d", filter_situation);
 
        case LOFS_BEGIN_TREE:
                assert(obj->type == OBJ_TREE);
@@ -217,13 +270,13 @@ static enum list_objects_filter_result filter_sparse(
                                            filename, &dtype, &filter_data->el,
                                            &the_index);
                if (val < 0)
-                       val = filter_data->array_frame[filter_data->nr].defval;
+                       val = filter_data->array_frame[filter_data->nr - 1].defval;
 
                ALLOC_GROW(filter_data->array_frame, filter_data->nr + 1,
                           filter_data->alloc);
-               filter_data->nr++;
                filter_data->array_frame[filter_data->nr].defval = val;
                filter_data->array_frame[filter_data->nr].child_prov_omit = 0;
+               filter_data->nr++;
 
                /*
                 * A directory with this tree OID may appear in multiple
@@ -248,16 +301,15 @@ static enum list_objects_filter_result filter_sparse(
 
        case LOFS_END_TREE:
                assert(obj->type == OBJ_TREE);
-               assert(filter_data->nr > 0);
+               assert(filter_data->nr > 1);
 
-               frame = &filter_data->array_frame[filter_data->nr];
-               filter_data->nr--;
+               frame = &filter_data->array_frame[--filter_data->nr];
 
                /*
                 * Tell our parent directory if any of our children were
                 * provisionally omitted.
                 */
-               filter_data->array_frame[filter_data->nr].child_prov_omit |=
+               filter_data->array_frame[filter_data->nr - 1].child_prov_omit |=
                        frame->child_prov_omit;
 
                /*
@@ -273,7 +325,7 @@ static enum list_objects_filter_result filter_sparse(
                assert(obj->type == OBJ_BLOB);
                assert((obj->flags & SEEN) == 0);
 
-               frame = &filter_data->array_frame[filter_data->nr];
+               frame = &filter_data->array_frame[filter_data->nr - 1];
 
                dtype = DT_REG;
                val = is_excluded_from_list(pathname, strlen(pathname),
@@ -314,7 +366,7 @@ static enum list_objects_filter_result filter_sparse(
 static void filter_sparse_free(void *filter_data)
 {
        struct filter_sparse_data *d = filter_data;
-       /* TODO free contents of 'd' */
+       free(d->array_frame);
        free(d);
 }
 
@@ -333,6 +385,7 @@ static void *filter_sparse_oid__init(
        ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc);
        d->array_frame[d->nr].defval = 0; /* default to include */
        d->array_frame[d->nr].child_prov_omit = 0;
+       d->nr++;
 
        *filter_fn = filter_sparse;
        *filter_free_fn = filter_sparse_free;
@@ -354,6 +407,7 @@ static void *filter_sparse_path__init(
        ALLOC_GROW(d->array_frame, d->nr + 1, d->alloc);
        d->array_frame[d->nr].defval = 0; /* default to include */
        d->array_frame[d->nr].child_prov_omit = 0;
+       d->nr++;
 
        *filter_fn = filter_sparse;
        *filter_free_fn = filter_sparse_free;
@@ -373,6 +427,7 @@ static filter_init_fn s_filters[] = {
        NULL,
        filter_blobs_none__init,
        filter_blobs_limit__init,
+       filter_trees_none__init,
        filter_sparse_oid__init,
        filter_sparse_path__init,
 };
@@ -388,7 +443,7 @@ void *list_objects_filter__init(
        assert((sizeof(s_filters) / sizeof(s_filters[0])) == LOFC__COUNT);
 
        if (filter_options->choice >= LOFC__COUNT)
-               die("invalid list-objects filter choice: %d",
+               BUG("invalid list-objects filter choice: %d",
                    filter_options->choice);
 
        init_fn = s_filters[filter_options->choice];