]> git.ipfire.org Git - thirdparty/git.git/blobdiff - fsck.c
submodule: make zero-oid comparison hash function agnostic
[thirdparty/git.git] / fsck.c
diff --git a/fsck.c b/fsck.c
index 9339f315131786c50c9fa10dd702fe20562e167e..0f56977d6aa6499c06e31eddb8ed4afe484fcdc4 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -1,4 +1,6 @@
 #include "cache.h"
+#include "object-store.h"
+#include "repository.h"
 #include "object.h"
 #include "blob.h"
 #include "tree.h"
@@ -14,6 +16,7 @@
 #include "packfile.h"
 #include "submodule-config.h"
 #include "config.h"
+#include "help.h"
 
 static struct oidset gitmodules_found = OIDSET_INIT;
 static struct oidset gitmodules_done = OIDSET_INIT;
@@ -61,9 +64,11 @@ static struct oidset gitmodules_done = OIDSET_INIT;
        FUNC(ZERO_PADDED_DATE, ERROR) \
        FUNC(GITMODULES_MISSING, ERROR) \
        FUNC(GITMODULES_BLOB, ERROR) \
-       FUNC(GITMODULES_PARSE, ERROR) \
+       FUNC(GITMODULES_LARGE, ERROR) \
        FUNC(GITMODULES_NAME, ERROR) \
        FUNC(GITMODULES_SYMLINK, ERROR) \
+       FUNC(GITMODULES_URL, ERROR) \
+       FUNC(GITMODULES_PATH, ERROR) \
        /* warnings */ \
        FUNC(BAD_FILEMODE, WARN) \
        FUNC(EMPTY_NAME, WARN) \
@@ -75,6 +80,7 @@ static struct oidset gitmodules_done = OIDSET_INIT;
        FUNC(ZERO_PADDED_FILEMODE, WARN) \
        FUNC(NUL_IN_COMMIT, WARN) \
        /* infos (reported as warnings, but ignored by default) */ \
+       FUNC(GITMODULES_PARSE, INFO) \
        FUNC(BAD_TAG_NAME, INFO) \
        FUNC(MISSING_TAGGER_ENTRY, INFO)
 
@@ -86,37 +92,60 @@ enum fsck_msg_id {
 #undef MSG_ID
 
 #define STR(x) #x
-#define MSG_ID(id, msg_type) { STR(id), NULL, FSCK_##msg_type },
+#define MSG_ID(id, msg_type) { STR(id), NULL, NULL, FSCK_##msg_type },
 static struct {
        const char *id_string;
        const char *downcased;
+       const char *camelcased;
        int msg_type;
 } msg_id_info[FSCK_MSG_MAX + 1] = {
        FOREACH_MSG_ID(MSG_ID)
-       { NULL, NULL, -1 }
+       { NULL, NULL, NULL, -1 }
 };
 #undef MSG_ID
 
-static int parse_msg_id(const char *text)
+static void prepare_msg_ids(void)
 {
        int i;
 
-       if (!msg_id_info[0].downcased) {
-               /* convert id_string to lower case, without underscores. */
-               for (i = 0; i < FSCK_MSG_MAX; i++) {
-                       const char *p = msg_id_info[i].id_string;
-                       int len = strlen(p);
-                       char *q = xmalloc(len);
-
-                       msg_id_info[i].downcased = q;
-                       while (*p)
-                               if (*p == '_')
-                                       p++;
-                               else
-                                       *(q)++ = tolower(*(p)++);
-                       *q = '\0';
+       if (msg_id_info[0].downcased)
+               return;
+
+       /* convert id_string to lower case, without underscores. */
+       for (i = 0; i < FSCK_MSG_MAX; i++) {
+               const char *p = msg_id_info[i].id_string;
+               int len = strlen(p);
+               char *q = xmalloc(len);
+
+               msg_id_info[i].downcased = q;
+               while (*p)
+                       if (*p == '_')
+                               p++;
+                       else
+                               *(q)++ = tolower(*(p)++);
+               *q = '\0';
+
+               p = msg_id_info[i].id_string;
+               q = xmalloc(len);
+               msg_id_info[i].camelcased = q;
+               while (*p) {
+                       if (*p == '_') {
+                               p++;
+                               if (*p)
+                                       *q++ = *p++;
+                       } else {
+                               *q++ = tolower(*p++);
+                       }
                }
+               *q = '\0';
        }
+}
+
+static int parse_msg_id(const char *text)
+{
+       int i;
+
+       prepare_msg_ids();
 
        for (i = 0; i < FSCK_MSG_MAX; i++)
                if (!strcmp(text, msg_id_info[i].downcased))
@@ -125,6 +154,16 @@ static int parse_msg_id(const char *text)
        return -1;
 }
 
+void list_config_fsck_msg_ids(struct string_list *list, const char *prefix)
+{
+       int i;
+
+       prepare_msg_ids();
+
+       for (i = 0; i < FSCK_MSG_MAX; i++)
+               list_config_item(list, prefix, msg_id_info[i].camelcased);
+}
+
 static int fsck_msg_type(enum fsck_msg_id msg_id,
        struct fsck_options *options)
 {
@@ -281,6 +320,13 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id)
        strbuf_addstr(sb, ": ");
 }
 
+static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
+{
+       if (opts && opts->skiplist && obj)
+               return oid_array_lookup(opts->skiplist, &obj->oid) >= 0;
+       return 0;
+}
+
 __attribute__((format (printf, 4, 5)))
 static int report(struct fsck_options *options, struct object *object,
        enum fsck_msg_id id, const char *fmt, ...)
@@ -292,8 +338,7 @@ static int report(struct fsck_options *options, struct object *object,
        if (msg_type == FSCK_IGNORE)
                return 0;
 
-       if (options->skiplist && object &&
-                       oid_array_lookup(options->skiplist, &object->oid) >= 0)
+       if (object_on_skiplist(options, object))
                return 0;
 
        if (msg_type == FSCK_FATAL)
@@ -371,14 +416,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
                        continue;
 
                if (S_ISDIR(entry.mode)) {
-                       obj = (struct object *)lookup_tree(entry.oid);
+                       obj = (struct object *)lookup_tree(the_repository, entry.oid);
                        if (name && obj)
                                put_object_name(options, obj, "%s%s/", name,
                                        entry.path);
                        result = options->walk(obj, OBJ_TREE, data, options);
                }
                else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
-                       obj = (struct object *)lookup_blob(entry.oid);
+                       obj = (struct object *)lookup_blob(the_repository, entry.oid);
                        if (name && obj)
                                put_object_name(options, obj, "%s%s", name,
                                        entry.path);
@@ -409,9 +454,11 @@ static int fsck_walk_commit(struct commit *commit, void *data, struct fsck_optio
 
        name = get_object_name(options, &commit->object);
        if (name)
-               put_object_name(options, &commit->tree->object, "%s:", name);
+               put_object_name(options, &get_commit_tree(commit)->object,
+                               "%s:", name);
 
-       result = options->walk((struct object *)commit->tree, OBJ_TREE, data, options);
+       result = options->walk((struct object *)get_commit_tree(commit),
+                              OBJ_TREE, data, options);
        if (result < 0)
                return result;
        res = result;
@@ -474,7 +521,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options)
                return -1;
 
        if (obj->type == OBJ_NONE)
-               parse_object(&obj->oid);
+               parse_object(the_repository, &obj->oid);
 
        switch (obj->type) {
        case OBJ_BLOB:
@@ -732,33 +779,34 @@ static int fsck_ident(const char **ident, struct object *obj, struct fsck_option
 static int fsck_commit_buffer(struct commit *commit, const char *buffer,
        unsigned long size, struct fsck_options *options)
 {
-       unsigned char tree_sha1[20], sha1[20];
+       struct object_id tree_oid, oid;
        struct commit_graft *graft;
        unsigned parent_count, parent_line_count = 0, author_count;
        int err;
        const char *buffer_begin = buffer;
+       const char *p;
 
        if (verify_headers(buffer, size, &commit->object, options))
                return -1;
 
        if (!skip_prefix(buffer, "tree ", &buffer))
                return report(options, &commit->object, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
-       if (get_sha1_hex(buffer, tree_sha1) || buffer[40] != '\n') {
+       if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
                err = report(options, &commit->object, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
                if (err)
                        return err;
        }
-       buffer += 41;
+       buffer = p + 1;
        while (skip_prefix(buffer, "parent ", &buffer)) {
-               if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
+               if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
                        err = report(options, &commit->object, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
                        if (err)
                                return err;
                }
-               buffer += 41;
+               buffer = p + 1;
                parent_line_count++;
        }
-       graft = lookup_commit_graft(&commit->object.oid);
+       graft = lookup_commit_graft(the_repository, &commit->object.oid);
        parent_count = commit_list_count(commit->parents);
        if (graft) {
                if (graft->nr_parent == -1 && !parent_count)
@@ -793,8 +841,8 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
        err = fsck_ident(&buffer, &commit->object, options);
        if (err)
                return err;
-       if (!commit->tree) {
-               err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
+       if (!get_commit_tree(commit)) {
+               err = report(options, &commit->object, FSCK_MSG_BAD_TREE, "could not load commit's tree %s", oid_to_hex(&tree_oid));
                if (err)
                        return err;
        }
@@ -820,11 +868,12 @@ static int fsck_commit(struct commit *commit, const char *data,
 static int fsck_tag_buffer(struct tag *tag, const char *data,
        unsigned long size, struct fsck_options *options)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        int ret = 0;
        const char *buffer;
        char *to_free = NULL, *eol;
        struct strbuf sb = STRBUF_INIT;
+       const char *p;
 
        if (data)
                buffer = data;
@@ -832,7 +881,7 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
                enum object_type type;
 
                buffer = to_free =
-                       read_sha1_file(tag->object.oid.hash, &type, &size);
+                       read_object_file(&tag->object.oid, &type, &size);
                if (!buffer)
                        return report(options, &tag->object,
                                FSCK_MSG_MISSING_TAG_OBJECT,
@@ -855,12 +904,12 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
                ret = report(options, &tag->object, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
                goto done;
        }
-       if (get_sha1_hex(buffer, sha1) || buffer[40] != '\n') {
+       if (parse_oid_hex(buffer, &oid, &p) || *p != '\n') {
                ret = report(options, &tag->object, FSCK_MSG_BAD_OBJECT_SHA1, "invalid 'object' line format - bad sha1");
                if (ret)
                        goto done;
        }
-       buffer += 41;
+       buffer = p + 1;
 
        if (!skip_prefix(buffer, "type ", &buffer)) {
                ret = report(options, &tag->object, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
@@ -945,6 +994,18 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
                                    FSCK_MSG_GITMODULES_NAME,
                                    "disallowed submodule name: %s",
                                    name);
+       if (!strcmp(key, "url") && value &&
+           looks_like_command_line_option(value))
+               data->ret |= report(data->options, data->obj,
+                                   FSCK_MSG_GITMODULES_URL,
+                                   "disallowed submodule url: %s",
+                                   value);
+       if (!strcmp(key, "path") && value &&
+           looks_like_command_line_option(value))
+               data->ret |= report(data->options, data->obj,
+                                   FSCK_MSG_GITMODULES_PATH,
+                                   "disallowed submodule path: %s",
+                                   value);
        free(name);
 
        return 0;
@@ -954,11 +1015,15 @@ static int fsck_blob(struct blob *blob, const char *buf,
                     unsigned long size, struct fsck_options *options)
 {
        struct fsck_gitmodules_data data;
+       struct config_options config_opts = { 0 };
 
        if (!oidset_contains(&gitmodules_found, &blob->object.oid))
                return 0;
        oidset_insert(&gitmodules_done, &blob->object.oid);
 
+       if (object_on_skiplist(options, &blob->object))
+               return 0;
+
        if (!buf) {
                /*
                 * A missing buffer here is a sign that the caller found the
@@ -966,15 +1031,16 @@ static int fsck_blob(struct blob *blob, const char *buf,
                 * that an error.
                 */
                return report(options, &blob->object,
-                             FSCK_MSG_GITMODULES_PARSE,
+                             FSCK_MSG_GITMODULES_LARGE,
                              ".gitmodules too large to parse");
        }
 
        data.obj = &blob->object;
        data.options = options;
        data.ret = 0;
+       config_opts.error_action = CONFIG_ERROR_SILENT;
        if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
-                               ".gitmodules", buf, size, &data))
+                               ".gitmodules", buf, size, &data, &config_opts))
                data.ret |= report(options, &blob->object,
                                   FSCK_MSG_GITMODULES_PARSE,
                                   "could not parse gitmodules blob");
@@ -1030,15 +1096,16 @@ int fsck_finish(struct fsck_options *options)
                if (oidset_contains(&gitmodules_done, oid))
                        continue;
 
-               blob = lookup_blob(oid);
+               blob = lookup_blob(the_repository, oid);
                if (!blob) {
-                       ret |= report(options, &blob->object,
+                       struct object *obj = lookup_unknown_object(oid->hash);
+                       ret |= report(options, obj,
                                      FSCK_MSG_GITMODULES_BLOB,
                                      "non-blob found at .gitmodules");
                        continue;
                }
 
-               buf = read_sha1_file(oid->hash, &type, &size);
+               buf = read_object_file(oid, &type, &size);
                if (!buf) {
                        if (is_promisor_object(&blob->object.oid))
                                continue;