Code

diff -M: release the preimage candidate blobs after rename detection.
[git.git] / builtin-fsck.c
index 39cfc32818dc80d8bda04ff45fbf5996d1506922..44ce629a498f986f239e008a61d32e10968907e0 100644 (file)
 static int show_root;
 static int show_tags;
 static int show_unreachable;
+static int include_reflogs = 1;
 static int check_full;
 static int check_strict;
 static int keep_cache_objects;
 static unsigned char head_sha1[20];
+static int errors_found;
+#define ERROR_OBJECT 01
+#define ERROR_REACHABLE 02
 
 #ifdef NO_D_INO_IN_DIRENT
 #define SORT_DIRENT 0
@@ -40,6 +44,7 @@ static int objerror(struct object *obj, const char *err, ...)
 {
        va_list params;
        va_start(params, err);
+       errors_found |= ERROR_OBJECT;
        objreport(obj, "error", err, params);
        va_end(params);
        return -1;
@@ -67,9 +72,10 @@ static void check_reachable_object(struct object *obj)
         * do a full fsck
         */
        if (!obj->parsed) {
-               if (has_sha1_file(obj->sha1))
+               if (has_sha1_pack(obj->sha1, NULL))
                        return; /* it is in pack - forget about it */
                printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
+               errors_found |= ERROR_REACHABLE;
                return;
        }
 
@@ -88,6 +94,7 @@ static void check_reachable_object(struct object *obj)
                               typename(obj->type), sha1_to_hex(obj->sha1));
                        printf("              to %7s %s\n",
                               typename(ref->type), sha1_to_hex(ref->sha1));
+                       errors_found |= ERROR_REACHABLE;
                }
        }
 }
@@ -212,6 +219,7 @@ static int fsck_tree(struct tree *item)
 {
        int retval;
        int has_full_path = 0;
+       int has_empty_name = 0;
        int has_zero_pad = 0;
        int has_bad_modes = 0;
        int has_dup_entries = 0;
@@ -221,8 +229,7 @@ static int fsck_tree(struct tree *item)
        const char *o_name;
        const unsigned char *o_sha1;
 
-       desc.buf = item->buffer;
-       desc.size = item->size;
+       init_tree_desc(&desc, item->buffer, item->size);
 
        o_mode = 0;
        o_name = NULL;
@@ -236,7 +243,9 @@ static int fsck_tree(struct tree *item)
 
                if (strchr(name, '/'))
                        has_full_path = 1;
-               has_zero_pad |= *(char *)desc.buf == '0';
+               if (!*name)
+                       has_empty_name = 1;
+               has_zero_pad |= *(char *)desc.buffer == '0';
                update_tree_entry(&desc);
 
                switch (mode) {
@@ -247,6 +256,7 @@ static int fsck_tree(struct tree *item)
                case S_IFREG | 0644:
                case S_IFLNK:
                case S_IFDIR:
+               case S_IFDIRLNK:
                        break;
                /*
                 * This is nonstandard, but we had a few of these
@@ -284,6 +294,9 @@ static int fsck_tree(struct tree *item)
        if (has_full_path) {
                objwarning(&item->object, "contains full pathnames");
        }
+       if (has_empty_name) {
+               objwarning(&item->object, "contains empty pathname");
+       }
        if (has_zero_pad) {
                objwarning(&item->object, "contains zero-padded file modes");
        }
@@ -343,11 +356,14 @@ static int fsck_tag(struct tag *tag)
        return 0;
 }
 
-static int fsck_sha1(unsigned char *sha1)
+static int fsck_sha1(const unsigned char *sha1)
 {
        struct object *obj = parse_object(sha1);
-       if (!obj)
-               return error("%s: object corrupt or missing", sha1_to_hex(sha1));
+       if (!obj) {
+               errors_found |= ERROR_OBJECT;
+               return error("%s: object corrupt or missing",
+                            sha1_to_hex(sha1));
+       }
        if (obj->flags & SEEN)
                return 0;
        obj->flags |= SEEN;
@@ -359,8 +375,10 @@ static int fsck_sha1(unsigned char *sha1)
                return fsck_commit((struct commit *) obj);
        if (obj->type == OBJ_TAG)
                return fsck_tag((struct tag *) obj);
+
        /* By now, parse_object() would've returned NULL instead. */
-       return objerror(obj, "unknown type '%d' (internal fsck error)", obj->type);
+       return objerror(obj, "unknown type '%d' (internal fsck error)",
+                       obj->type);
 }
 
 /*
@@ -507,7 +525,8 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f
 static void get_default_heads(void)
 {
        for_each_ref(fsck_handle_ref, NULL);
-       for_each_reflog(fsck_handle_reflog, NULL);
+       if (include_reflogs)
+               for_each_reflog(fsck_handle_reflog, NULL);
 
        /*
         * Not having any default heads isn't really fatal, but
@@ -522,7 +541,7 @@ static void get_default_heads(void)
         * "show_unreachable" flag.
         */
        if (!default_refs) {
-               error("No default references");
+               fprintf(stderr, "notice: No default references\n");
                show_unreachable = 0;
        }
 }
@@ -542,15 +561,23 @@ static int fsck_head_link(void)
 {
        unsigned char sha1[20];
        int flag;
-       const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
-
-       if (!head_points_at || !(flag & REF_ISSYMREF))
-               return error("HEAD is not a symbolic ref");
-       if (prefixcmp(head_points_at, "refs/heads/"))
+       int null_is_error = 0;
+       const char *head_points_at = resolve_ref("HEAD", sha1, 0, &flag);
+
+       if (!head_points_at)
+               return error("Invalid HEAD");
+       if (!strcmp(head_points_at, "HEAD"))
+               /* detached HEAD */
+               null_is_error = 1;
+       else if (prefixcmp(head_points_at, "refs/heads/"))
                return error("HEAD points to something strange (%s)",
                             head_points_at);
-       if (is_null_sha1(sha1))
-               return error("HEAD: not a valid git pointer");
+       if (is_null_sha1(sha1)) {
+               if (null_is_error)
+                       return error("HEAD: detached HEAD points at nothing");
+               fprintf(stderr, "notice: HEAD points to an unborn branch (%s)\n",
+                       head_points_at + 11);
+       }
        return 0;
 }
 
@@ -576,11 +603,16 @@ static int fsck_cache_tree(struct cache_tree *it)
        return err;
 }
 
+static const char fsck_usage[] =
+"git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] "
+"[--strict] <head-sha1>*]";
+
 int cmd_fsck(int argc, char **argv, const char *prefix)
 {
        int i, heads;
 
        track_object_refs = 1;
+       errors_found = 0;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
@@ -601,6 +633,10 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
                        keep_cache_objects = 1;
                        continue;
                }
+               if (!strcmp(arg, "--no-reflogs")) {
+                       include_reflogs = 0;
+                       continue;
+               }
                if (!strcmp(arg, "--full")) {
                        check_full = 1;
                        continue;
@@ -610,7 +646,7 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
                        continue;
                }
                if (*arg == '-')
-                       usage("git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] [--strict] <head-sha1>*]");
+                       usage(fsck_usage);
        }
 
        fsck_head_link();
@@ -632,12 +668,9 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
                        verify_pack(p, 0);
 
                for (p = packed_git; p; p = p->next) {
-                       uint32_t i, num = num_packed_objects(p);
-                       for (i = 0; i < num; i++) {
-                               unsigned char sha1[20];
-                               nth_packed_object_sha1(p, i, sha1);
-                               fsck_sha1(sha1);
-                       }
+                       uint32_t i, num = p->num_objects;
+                       for (i = 0; i < num; i++)
+                               fsck_sha1(nth_packed_object_sha1(p, i));
                }
        }
 
@@ -677,8 +710,14 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
                int i;
                read_cache();
                for (i = 0; i < active_nr; i++) {
-                       struct blob *blob = lookup_blob(active_cache[i]->sha1);
+                       unsigned int mode;
+                       struct blob *blob;
                        struct object *obj;
+
+                       mode = ntohl(active_cache[i]->ce_mode);
+                       if (S_ISDIRLNK(mode))
+                               continue;
+                       blob = lookup_blob(active_cache[i]->sha1);
                        if (!blob)
                                continue;
                        obj = &blob->object;
@@ -690,5 +729,5 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
        }
 
        check_connectivity();
-       return 0;
+       return errors_found;
 }