Merge branch 'nd/travis-gcc-8'
[gitweb.git] / builtin / fsck.c
index d18244ab546bae863e6ef81d58663dc5c27c49c0..916109ac1c05664da895d832ec10c8b5ee4465fb 100644 (file)
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "repository.h"
 #include "config.h"
 #include "commit.h"
 #include "tree.h"
@@ -15,6 +16,8 @@
 #include "progress.h"
 #include "streaming.h"
 #include "decorate.h"
+#include "packfile.h"
+#include "object-store.h"
 
 #define REACHABLE 0x0001
 #define SEEN      0x0002
@@ -64,12 +67,13 @@ static const char *printable_type(struct object *obj)
        const char *ret;
 
        if (obj->type == OBJ_NONE) {
-               enum object_type type = sha1_object_info(obj->oid.hash, NULL);
+               enum object_type type = oid_object_info(the_repository,
+                                                       &obj->oid, NULL);
                if (type > 0)
                        object_as_type(obj, type, 0);
        }
 
-       ret = typename(obj->type);
+       ret = type_name(obj->type);
        if (!ret)
                ret = "unknown";
 
@@ -136,7 +140,7 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
                printf("broken link from %7s %s\n",
                           printable_type(parent), describe_object(parent));
                printf("broken link from %7s %s\n",
-                          (type == OBJ_ANY ? "unknown" : typename(type)), "unknown");
+                          (type == OBJ_ANY ? "unknown" : type_name(type)), "unknown");
                errors_found |= ERROR_REACHABLE;
                return 1;
        }
@@ -148,6 +152,15 @@ static int mark_object(struct object *obj, int type, void *data, struct fsck_opt
        if (obj->flags & REACHABLE)
                return 0;
        obj->flags |= REACHABLE;
+
+       if (is_promisor_object(&obj->oid))
+               /*
+                * Further recursion does not need to be performed on this
+                * object since it is a promisor object (so it does not need to
+                * be added to "pending").
+                */
+               return 0;
+
        if (!(obj->flags & HAS_OBJ)) {
                if (parent && !has_object_file(&obj->oid)) {
                        printf("broken link from %7s %s\n",
@@ -170,7 +183,13 @@ static void mark_object_reachable(struct object *obj)
 
 static int traverse_one_object(struct object *obj)
 {
-       return fsck_walk(obj, obj, &fsck_walk_options);
+       int result = fsck_walk(obj, obj, &fsck_walk_options);
+
+       if (obj->type == OBJ_TREE) {
+               struct tree *tree = (struct tree *)obj;
+               free_tree_buffer(tree);
+       }
+       return result;
 }
 
 static int traverse_reachable(void)
@@ -179,14 +198,9 @@ static int traverse_reachable(void)
        unsigned int nr = 0;
        int result = 0;
        if (show_progress)
-               progress = start_progress_delay(_("Checking connectivity"), 0, 0, 2);
+               progress = start_delayed_progress(_("Checking connectivity"), 0);
        while (pending.nr) {
-               struct object_array_entry *entry;
-               struct object *obj;
-
-               entry = pending.objects + --pending.nr;
-               obj = entry->item;
-               result |= traverse_one_object(obj);
+               result |= traverse_one_object(object_array_pop(&pending));
                display_progress(progress, ++nr);
        }
        stop_progress(&progress);
@@ -212,6 +226,8 @@ static void check_reachable_object(struct object *obj)
         * do a full fsck
         */
        if (!(obj->flags & HAS_OBJ)) {
+               if (is_promisor_object(&obj->oid))
+                       return;
                if (has_sha1_pack(obj->oid.hash))
                        return; /* it is in pack - forget about it */
                printf("missing %s %s\n", printable_type(obj),
@@ -324,7 +340,7 @@ static void check_connectivity(void)
        }
 }
 
-static int fsck_obj(struct object *obj)
+static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
 {
        int err;
 
@@ -338,7 +354,7 @@ static int fsck_obj(struct object *obj)
 
        if (fsck_walk(obj, NULL, &fsck_obj_options))
                objerror(obj, "broken links");
-       err = fsck_object(obj, NULL, 0, &fsck_obj_options);
+       err = fsck_object(obj, buffer, size, &fsck_obj_options);
        if (err)
                goto out;
 
@@ -383,7 +399,7 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
        }
        obj->flags &= ~(REACHABLE | SEEN);
        obj->flags |= HAS_OBJ;
-       return fsck_obj(obj);
+       return fsck_obj(obj, buffer, size);
 }
 
 static int default_refs;
@@ -402,7 +418,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
                                        xstrfmt("%s@{%"PRItime"}", refname, timestamp));
                        obj->flags |= USED;
                        mark_object_reachable(obj);
-               } else {
+               } else if (!is_promisor_object(oid)) {
                        error("%s: invalid reflog entry %s", refname, oid_to_hex(oid));
                        errors_found |= ERROR_REACHABLE;
                }
@@ -438,6 +454,14 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
 
        obj = parse_object(oid);
        if (!obj) {
+               if (is_promisor_object(oid)) {
+                       /*
+                        * Increment default_refs anyway, because this is a
+                        * valid ref.
+                        */
+                        default_refs++;
+                        return 0;
+               }
                error("%s: invalid sha1 pointer %s", refname, oid_to_hex(oid));
                errors_found |= ERROR_REACHABLE;
                /* We'll continue with the rest despite the error.. */
@@ -483,44 +507,42 @@ static void get_default_heads(void)
        }
 }
 
-static struct object *parse_loose_object(const struct object_id *oid,
-                                        const char *path)
+static int fsck_loose(const struct object_id *oid, const char *path, void *data)
 {
        struct object *obj;
-       void *contents;
        enum object_type type;
        unsigned long size;
+       void *contents;
        int eaten;
 
-       if (read_loose_object(path, oid->hash, &type, &size, &contents) < 0)
-               return NULL;
+       if (read_loose_object(path, oid, &type, &size, &contents) < 0) {
+               errors_found |= ERROR_OBJECT;
+               error("%s: object corrupt or missing: %s",
+                     oid_to_hex(oid), path);
+               return 0; /* keep checking other objects */
+       }
 
        if (!contents && type != OBJ_BLOB)
-               die("BUG: read_loose_object streamed a non-blob");
+               BUG("read_loose_object streamed a non-blob");
 
        obj = parse_object_buffer(oid, type, size, contents, &eaten);
-
-       if (!eaten)
-               free(contents);
-       return obj;
-}
-
-static int fsck_loose(const struct object_id *oid, const char *path, void *data)
-{
-       struct object *obj = parse_loose_object(oid, path);
-
        if (!obj) {
                errors_found |= ERROR_OBJECT;
-               error("%s: object corrupt or missing: %s",
+               error("%s: object could not be parsed: %s",
                      oid_to_hex(oid), path);
+               if (!eaten)
+                       free(contents);
                return 0; /* keep checking other objects */
        }
 
        obj->flags &= ~(REACHABLE | SEEN);
        obj->flags |= HAS_OBJ;
-       if (fsck_obj(obj))
+       if (fsck_obj(obj, contents, size))
                errors_found |= ERROR_OBJECT;
-       return 0;
+
+       if (!eaten)
+               free(contents);
+       return 0; /* keep checking other objects, even if we saw an error */
 }
 
 static int fsck_cruft(const char *basename, const char *path, void *data)
@@ -559,7 +581,7 @@ static int fsck_head_link(void)
        if (verbose)
                fprintf(stderr, "Checking HEAD link\n");
 
-       head_points_at = resolve_ref_unsafe("HEAD", 0, head_oid.hash, NULL);
+       head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL);
        if (!head_points_at) {
                errors_found |= ERROR_REFS;
                return error("Invalid HEAD");
@@ -663,6 +685,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
        int i;
        struct alternate_object_database *alt;
 
+       /* fsck knows how to handle missing promisor objects */
+       fetch_if_missing = 0;
+
        errors_found = 0;
        check_replace_refs = 0;
 
@@ -695,9 +720,12 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
                for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
        } else {
+               struct alternate_object_database *alt_odb_list;
+
                fsck_object_dir(get_object_directory());
 
-               prepare_alt_odb();
+               prepare_alt_odb(the_repository);
+               alt_odb_list = the_repository->objects->alt_odb_list;
                for (alt = alt_odb_list; alt; alt = alt->next)
                        fsck_object_dir(alt->path);
 
@@ -706,10 +734,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        uint32_t total = 0, count = 0;
                        struct progress *progress = NULL;
 
-                       prepare_packed_git();
-
                        if (show_progress) {
-                               for (p = packed_git; p; p = p->next) {
+                               for (p = get_packed_git(the_repository); p;
+                                    p = p->next) {
                                        if (open_pack_index(p))
                                                continue;
                                        total += p->num_objects;
@@ -717,7 +744,8 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 
                                progress = start_progress(_("Checking objects"), total);
                        }
-                       for (p = packed_git; p; p = p->next) {
+                       for (p = get_packed_git(the_repository); p;
+                            p = p->next) {
                                /* verify gives error messages itself */
                                if (verify_pack(p, fsck_obj_buffer,
                                                progress, count))
@@ -726,16 +754,21 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        }
                        stop_progress(&progress);
                }
+
+               if (fsck_finish(&fsck_obj_options))
+                       errors_found |= ERROR_OBJECT;
        }
 
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
-               unsigned char sha1[20];
-               if (!get_sha1(arg, sha1)) {
-                       struct object *obj = lookup_object(sha1);
+               struct object_id oid;
+               if (!get_oid(arg, &oid)) {
+                       struct object *obj = lookup_object(oid.hash);
 
                        if (!obj || !(obj->flags & HAS_OBJ)) {
-                               error("%s: object missing", sha1_to_hex(sha1));
+                               if (is_promisor_object(&oid))
+                                       continue;
+                               error("%s: object missing", oid_to_hex(&oid));
                                errors_found |= ERROR_OBJECT;
                                continue;
                        }
@@ -763,6 +796,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
 
        if (keep_cache_objects) {
                verify_index_checksum = 1;
+               verify_ce_order = 1;
                read_cache();
                for (i = 0; i < active_nr; i++) {
                        unsigned int mode;