cvsserver: add comments about database schema/usage
[gitweb.git] / fsck.c
diff --git a/fsck.c b/fsck.c
index 511b82cba9977c14d6dcba5efbd6d38591d3aacc..7395ef6a425f5c7725767f34a0383f61907fce93 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -27,7 +27,7 @@ static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data)
                else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode))
                        result = walk(&lookup_blob(entry.sha1)->object, OBJ_BLOB, data);
                else {
-                       result = error("in tree %s: entry %s has bad mode %.6o\n",
+                       result = error("in tree %s: entry %s has bad mode %.6o",
                                        sha1_to_hex(tree->object.sha1), entry.path, entry.mode);
                }
                if (result < 0)
@@ -139,6 +139,7 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con
 static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
 {
        int retval;
+       int has_null_sha1 = 0;
        int has_full_path = 0;
        int has_empty_name = 0;
        int has_zero_pad = 0;
@@ -157,9 +158,12 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        while (desc.size) {
                unsigned mode;
                const char *name;
+               const unsigned char *sha1;
 
-               tree_entry_extract(&desc, &name, &mode);
+               sha1 = tree_entry_extract(&desc, &name, &mode);
 
+               if (is_null_sha1(sha1))
+                       has_null_sha1 = 1;
                if (strchr(name, '/'))
                        has_full_path = 1;
                if (!*name)
@@ -207,6 +211,8 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        }
 
        retval = 0;
+       if (has_null_sha1)
+               retval += error_func(&item->object, FSCK_WARN, "contains entries pointing to null sha1");
        if (has_full_path)
                retval += error_func(&item->object, FSCK_WARN, "contains full pathnames");
        if (has_empty_name)
@@ -222,14 +228,51 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        return retval;
 }
 
+static int fsck_ident(char **ident, struct object *obj, fsck_error error_func)
+{
+       if (**ident == '<')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - missing space before email");
+       *ident += strcspn(*ident, "<>\n");
+       if (**ident == '>')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - bad name");
+       if (**ident != '<')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - missing email");
+       if ((*ident)[-1] != ' ')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - missing space before email");
+       (*ident)++;
+       *ident += strcspn(*ident, "<>\n");
+       if (**ident != '>')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - bad email");
+       (*ident)++;
+       if (**ident != ' ')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - missing space before date");
+       (*ident)++;
+       if (**ident == '0' && (*ident)[1] != ' ')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - zero-padded date");
+       *ident += strspn(*ident, "0123456789");
+       if (**ident != ' ')
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - bad date");
+       (*ident)++;
+       if ((**ident != '+' && **ident != '-') ||
+           !isdigit((*ident)[1]) ||
+           !isdigit((*ident)[2]) ||
+           !isdigit((*ident)[3]) ||
+           !isdigit((*ident)[4]) ||
+           ((*ident)[5] != '\n'))
+               return error_func(obj, FSCK_ERROR, "invalid author/committer line - bad time zone");
+       (*ident) += 6;
+       return 0;
+}
+
 static int fsck_commit(struct commit *commit, fsck_error error_func)
 {
        char *buffer = commit->buffer;
        unsigned char tree_sha1[20], sha1[20];
        struct commit_graft *graft;
        int parents = 0;
+       int err;
 
-       if (!commit->date)
+       if (commit->date == ULONG_MAX)
                return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line");
 
        if (memcmp(buffer, "tree ", 5))
@@ -266,6 +309,16 @@ static int fsck_commit(struct commit *commit, fsck_error error_func)
        }
        if (memcmp(buffer, "author ", 7))
                return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line");
+       buffer += 7;
+       err = fsck_ident(&buffer, &commit->object, error_func);
+       if (err)
+               return err;
+       if (memcmp(buffer, "committer ", strlen("committer ")))
+               return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'committer' line");
+       buffer += strlen("committer ");
+       err = fsck_ident(&buffer, &commit->object, error_func);
+       if (err)
+               return err;
        if (!commit->tree)
                return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
 
@@ -302,26 +355,14 @@ int fsck_object(struct object *obj, int strict, fsck_error error_func)
 int fsck_error_function(struct object *obj, int type, const char *fmt, ...)
 {
        va_list ap;
-       int len;
        struct strbuf sb = STRBUF_INIT;
 
-       strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)");
+       strbuf_addf(&sb, "object %s:", sha1_to_hex(obj->sha1));
 
        va_start(ap, fmt);
-       len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
+       strbuf_vaddf(&sb, fmt, ap);
        va_end(ap);
 
-       if (len < 0)
-               len = 0;
-       if (len >= strbuf_avail(&sb)) {
-               strbuf_grow(&sb, len + 2);
-               va_start(ap, fmt);
-               len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
-               va_end(ap);
-               if (len >= strbuf_avail(&sb))
-                       die("this should not happen, your snprintf is broken");
-       }
-
        error("%s", sb.buf);
        strbuf_release(&sb);
        return 1;