summaryrefslogtreecommitdiff
path: root/fsck.c
diff options
context:
space:
mode:
authorJohannes Schindelin <johannes.schindelin@gmx.de>2015-06-22 17:25:25 +0200
committerJunio C Hamano <gitster@pobox.com>2015-06-23 14:26:46 -0700
commit0282f4dced029230024196e460b9d9f971f494dd (patch)
tree0634d3385343ed12356328275ad40984058ff080 /fsck.c
parentf417eed8cde2e7def06091977f888c296cbeae00 (diff)
downloadgit-0282f4dced029230024196e460b9d9f971f494dd.tar.gz
fsck: offer a function to demote fsck errors to warnings
There are legacy repositories out there whose older commits and tags have issues that prevent pushing them when 'receive.fsckObjects' is set. One real-life example is a commit object that has been hand-crafted to list two authors. Often, it is not possible to fix those issues without disrupting the work with said repositories, yet it is still desirable to perform checks by setting `receive.fsckObjects = true`. This commit is the first step to allow demoting specific fsck issues to mere warnings. The `fsck_set_msg_types()` function added by this commit parses a list of settings in the form: missingemail=warn,badname=warn,... Unfortunately, the FSCK_WARN/FSCK_ERROR flag is only really heeded by git fsck so far, but other call paths (e.g. git index-pack --strict) error out *always* no matter what type was specified. Therefore, we need to take extra care to set all message types to FSCK_ERROR by default in those cases. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'fsck.c')
-rw-r--r--fsck.c76
1 files changed, 73 insertions, 3 deletions
diff --git a/fsck.c b/fsck.c
index 30c1a19aa5..41208a412a 100644
--- a/fsck.c
+++ b/fsck.c
@@ -108,13 +108,79 @@ static int fsck_msg_type(enum fsck_msg_id msg_id,
{
int msg_type;
- msg_type = msg_id_info[msg_id].msg_type;
- if (options->strict && msg_type == FSCK_WARN)
- msg_type = FSCK_ERROR;
+ assert(msg_id >= 0 && msg_id < FSCK_MSG_MAX);
+
+ if (options->msg_type)
+ msg_type = options->msg_type[msg_id];
+ else {
+ msg_type = msg_id_info[msg_id].msg_type;
+ if (options->strict && msg_type == FSCK_WARN)
+ msg_type = FSCK_ERROR;
+ }
return msg_type;
}
+static int parse_msg_type(const char *str)
+{
+ if (!strcmp(str, "error"))
+ return FSCK_ERROR;
+ else if (!strcmp(str, "warn"))
+ return FSCK_WARN;
+ else
+ die("Unknown fsck message type: '%s'", str);
+}
+
+void fsck_set_msg_type(struct fsck_options *options,
+ const char *msg_id, const char *msg_type)
+{
+ int id = parse_msg_id(msg_id), type;
+
+ if (id < 0)
+ die("Unhandled message id: %s", msg_id);
+ type = parse_msg_type(msg_type);
+
+ if (!options->msg_type) {
+ int i;
+ int *msg_type = xmalloc(sizeof(int) * FSCK_MSG_MAX);
+ for (i = 0; i < FSCK_MSG_MAX; i++)
+ msg_type[i] = fsck_msg_type(i, options);
+ options->msg_type = msg_type;
+ }
+
+ options->msg_type[id] = type;
+}
+
+void fsck_set_msg_types(struct fsck_options *options, const char *values)
+{
+ char *buf = xstrdup(values), *to_free = buf;
+ int done = 0;
+
+ while (!done) {
+ int len = strcspn(buf, " ,|"), equal;
+
+ done = !buf[len];
+ if (!len) {
+ buf++;
+ continue;
+ }
+ buf[len] = '\0';
+
+ for (equal = 0;
+ equal < len && buf[equal] != '=' && buf[equal] != ':';
+ equal++)
+ buf[equal] = tolower(buf[equal]);
+ buf[equal] = '\0';
+
+ if (equal == len)
+ die("Missing '=': '%s'", buf);
+
+ fsck_set_msg_type(options, buf, buf + equal + 1);
+ buf += len + 1;
+ }
+ free(to_free);
+}
+
__attribute__((format (printf, 4, 5)))
static int report(struct fsck_options *options, struct object *object,
enum fsck_msg_id id, const char *fmt, ...)
@@ -604,6 +670,10 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
int fsck_error_function(struct object *obj, int msg_type, const char *message)
{
+ if (msg_type == FSCK_WARN) {
+ warning("object %s: %s", sha1_to_hex(obj->sha1), message);
+ return 0;
+ }
error("object %s: %s", sha1_to_hex(obj->sha1), message);
return 1;
}