builtin-fsck: move common object checking code to fsck.c
Signed-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									4516338243
								
							
						
					
					
						commit
						ba002f3b28
					
				
							
								
								
									
										274
									
								
								builtin-fsck.c
								
								
								
								
							
							
						
						
									
										274
									
								
								builtin-fsck.c
								
								
								
								
							|  | @ -55,13 +55,13 @@ static int objerror(struct object *obj, const char *err, ...) | |||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int objwarning(struct object *obj, const char *err, ...) | ||||
| static int fsck_error_func(struct object *obj, int type, const char *err, ...) | ||||
| { | ||||
| 	va_list params; | ||||
| 	va_start(params, err); | ||||
| 	objreport(obj, "warning", err, params); | ||||
| 	objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params); | ||||
| 	va_end(params); | ||||
| 	return -1; | ||||
| 	return (type == FSCK_WARN) ? 0 : 1; | ||||
| } | ||||
|  | ||||
| static int mark_object(struct object *obj, int type, void *data) | ||||
|  | @ -246,229 +246,6 @@ static void check_connectivity(void) | |||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * The entries in a tree are ordered in the _path_ order, | ||||
|  * which means that a directory entry is ordered by adding | ||||
|  * a slash to the end of it. | ||||
|  * | ||||
|  * So a directory called "a" is ordered _after_ a file | ||||
|  * called "a.c", because "a/" sorts after "a.c". | ||||
|  */ | ||||
| #define TREE_UNORDERED (-1) | ||||
| #define TREE_HAS_DUPS  (-2) | ||||
|  | ||||
| static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2) | ||||
| { | ||||
| 	int len1 = strlen(name1); | ||||
| 	int len2 = strlen(name2); | ||||
| 	int len = len1 < len2 ? len1 : len2; | ||||
| 	unsigned char c1, c2; | ||||
| 	int cmp; | ||||
|  | ||||
| 	cmp = memcmp(name1, name2, len); | ||||
| 	if (cmp < 0) | ||||
| 		return 0; | ||||
| 	if (cmp > 0) | ||||
| 		return TREE_UNORDERED; | ||||
|  | ||||
| 	/* | ||||
| 	 * Ok, the first <len> characters are the same. | ||||
| 	 * Now we need to order the next one, but turn | ||||
| 	 * a '\0' into a '/' for a directory entry. | ||||
| 	 */ | ||||
| 	c1 = name1[len]; | ||||
| 	c2 = name2[len]; | ||||
| 	if (!c1 && !c2) | ||||
| 		/* | ||||
| 		 * git-write-tree used to write out a nonsense tree that has | ||||
| 		 * entries with the same name, one blob and one tree.  Make | ||||
| 		 * sure we do not have duplicate entries. | ||||
| 		 */ | ||||
| 		return TREE_HAS_DUPS; | ||||
| 	if (!c1 && S_ISDIR(mode1)) | ||||
| 		c1 = '/'; | ||||
| 	if (!c2 && S_ISDIR(mode2)) | ||||
| 		c2 = '/'; | ||||
| 	return c1 < c2 ? 0 : TREE_UNORDERED; | ||||
| } | ||||
|  | ||||
| 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; | ||||
| 	int not_properly_sorted = 0; | ||||
| 	struct tree_desc desc; | ||||
| 	unsigned o_mode; | ||||
| 	const char *o_name; | ||||
| 	const unsigned char *o_sha1; | ||||
|  | ||||
| 	if (verbose) | ||||
| 		fprintf(stderr, "Checking tree %s\n", | ||||
| 				sha1_to_hex(item->object.sha1)); | ||||
|  | ||||
| 	init_tree_desc(&desc, item->buffer, item->size); | ||||
|  | ||||
| 	o_mode = 0; | ||||
| 	o_name = NULL; | ||||
| 	o_sha1 = NULL; | ||||
| 	while (desc.size) { | ||||
| 		unsigned mode; | ||||
| 		const char *name; | ||||
| 		const unsigned char *sha1; | ||||
|  | ||||
| 		sha1 = tree_entry_extract(&desc, &name, &mode); | ||||
|  | ||||
| 		if (strchr(name, '/')) | ||||
| 			has_full_path = 1; | ||||
| 		if (!*name) | ||||
| 			has_empty_name = 1; | ||||
| 		has_zero_pad |= *(char *)desc.buffer == '0'; | ||||
| 		update_tree_entry(&desc); | ||||
|  | ||||
| 		switch (mode) { | ||||
| 		/* | ||||
| 		 * Standard modes.. | ||||
| 		 */ | ||||
| 		case S_IFREG | 0755: | ||||
| 		case S_IFREG | 0644: | ||||
| 		case S_IFLNK: | ||||
| 		case S_IFDIR: | ||||
| 		case S_IFGITLINK: | ||||
| 			break; | ||||
| 		/* | ||||
| 		 * This is nonstandard, but we had a few of these | ||||
| 		 * early on when we honored the full set of mode | ||||
| 		 * bits.. | ||||
| 		 */ | ||||
| 		case S_IFREG | 0664: | ||||
| 			if (!check_strict) | ||||
| 				break; | ||||
| 		default: | ||||
| 			has_bad_modes = 1; | ||||
| 		} | ||||
|  | ||||
| 		if (o_name) { | ||||
| 			switch (verify_ordered(o_mode, o_name, mode, name)) { | ||||
| 			case TREE_UNORDERED: | ||||
| 				not_properly_sorted = 1; | ||||
| 				break; | ||||
| 			case TREE_HAS_DUPS: | ||||
| 				has_dup_entries = 1; | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		o_mode = mode; | ||||
| 		o_name = name; | ||||
| 		o_sha1 = sha1; | ||||
| 	} | ||||
| 	free(item->buffer); | ||||
| 	item->buffer = NULL; | ||||
|  | ||||
| 	retval = 0; | ||||
| 	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"); | ||||
| 	} | ||||
| 	if (has_bad_modes) { | ||||
| 		objwarning(&item->object, "contains bad file modes"); | ||||
| 	} | ||||
| 	if (has_dup_entries) { | ||||
| 		retval = objerror(&item->object, "contains duplicate file entries"); | ||||
| 	} | ||||
| 	if (not_properly_sorted) { | ||||
| 		retval = objerror(&item->object, "not properly sorted"); | ||||
| 	} | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| static int fsck_commit(struct commit *commit) | ||||
| { | ||||
| 	char *buffer = commit->buffer; | ||||
| 	unsigned char tree_sha1[20], sha1[20]; | ||||
| 	struct commit_graft *graft; | ||||
| 	int parents = 0; | ||||
|  | ||||
| 	if (verbose) | ||||
| 		fprintf(stderr, "Checking commit %s\n", | ||||
| 			sha1_to_hex(commit->object.sha1)); | ||||
|  | ||||
| 	if (memcmp(buffer, "tree ", 5)) | ||||
| 		return objerror(&commit->object, "invalid format - expected 'tree' line"); | ||||
| 	if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n') | ||||
| 		return objerror(&commit->object, "invalid 'tree' line format - bad sha1"); | ||||
| 	buffer += 46; | ||||
| 	while (!memcmp(buffer, "parent ", 7)) { | ||||
| 		if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n') | ||||
| 			return objerror(&commit->object, "invalid 'parent' line format - bad sha1"); | ||||
| 		buffer += 48; | ||||
| 		parents++; | ||||
| 	} | ||||
| 	graft = lookup_commit_graft(commit->object.sha1); | ||||
| 	if (graft) { | ||||
| 		struct commit_list *p = commit->parents; | ||||
| 		parents = 0; | ||||
| 		while (p) { | ||||
| 			p = p->next; | ||||
| 			parents++; | ||||
| 		} | ||||
| 		if (graft->nr_parent == -1 && !parents) | ||||
| 			; /* shallow commit */ | ||||
| 		else if (graft->nr_parent != parents) | ||||
| 			return objerror(&commit->object, "graft objects missing"); | ||||
| 	} else { | ||||
| 		struct commit_list *p = commit->parents; | ||||
| 		while (p && parents) { | ||||
| 			p = p->next; | ||||
| 			parents--; | ||||
| 		} | ||||
| 		if (p || parents) | ||||
| 			return objerror(&commit->object, "parent objects missing"); | ||||
| 	} | ||||
| 	if (memcmp(buffer, "author ", 7)) | ||||
| 		return objerror(&commit->object, "invalid format - expected 'author' line"); | ||||
| 	free(commit->buffer); | ||||
| 	commit->buffer = NULL; | ||||
| 	if (!commit->tree) | ||||
| 		return objerror(&commit->object, "could not load commit's tree %s", tree_sha1); | ||||
| 	if (!commit->parents && show_root) | ||||
| 		printf("root %s\n", sha1_to_hex(commit->object.sha1)); | ||||
| 	if (!commit->date) | ||||
| 		printf("bad commit date in %s\n", | ||||
| 		       sha1_to_hex(commit->object.sha1)); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int fsck_tag(struct tag *tag) | ||||
| { | ||||
| 	struct object *tagged = tag->tagged; | ||||
|  | ||||
| 	if (verbose) | ||||
| 		fprintf(stderr, "Checking tag %s\n", | ||||
| 			sha1_to_hex(tag->object.sha1)); | ||||
|  | ||||
| 	if (!tagged) { | ||||
| 		return objerror(&tag->object, "could not load tagged object"); | ||||
| 	} | ||||
| 	if (!show_tags) | ||||
| 		return 0; | ||||
|  | ||||
| 	printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1)); | ||||
| 	printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1)); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int fsck_sha1(const unsigned char *sha1) | ||||
| { | ||||
| 	struct object *obj = parse_object(sha1); | ||||
|  | @ -480,20 +257,43 @@ static int fsck_sha1(const unsigned char *sha1) | |||
| 	if (obj->flags & SEEN) | ||||
| 		return 0; | ||||
| 	obj->flags |= SEEN; | ||||
|  | ||||
| 	if (verbose) | ||||
| 		fprintf(stderr, "Checking %s %s\n", | ||||
| 			typename(obj->type), sha1_to_hex(obj->sha1)); | ||||
|  | ||||
| 	if (fsck_walk(obj, mark_used, 0)) | ||||
| 		objerror(obj, "broken links"); | ||||
| 	if (obj->type == OBJ_BLOB) | ||||
| 		return 0; | ||||
| 	if (obj->type == OBJ_TREE) | ||||
| 		return fsck_tree((struct tree *) obj); | ||||
| 	if (obj->type == OBJ_COMMIT) | ||||
| 		return fsck_commit((struct commit *) obj); | ||||
| 	if (obj->type == OBJ_TAG) | ||||
| 		return fsck_tag((struct tag *) obj); | ||||
| 	if (fsck_object(obj, check_strict, fsck_error_func)) | ||||
| 		return -1; | ||||
|  | ||||
| 	/* By now, parse_object() would've returned NULL instead. */ | ||||
| 	return objerror(obj, "unknown type '%d' (internal fsck error)", | ||||
| 			obj->type); | ||||
| 	if (obj->type == OBJ_TREE) { | ||||
| 		struct tree *item = (struct tree *) obj; | ||||
|  | ||||
| 		free(item->buffer); | ||||
| 		item->buffer = NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (obj->type == OBJ_COMMIT) { | ||||
| 		struct commit *commit = (struct commit *) obj; | ||||
|  | ||||
| 		free(commit->buffer); | ||||
| 		commit->buffer = NULL; | ||||
|  | ||||
| 		if (!commit->parents && show_root) | ||||
| 			printf("root %s\n", sha1_to_hex(commit->object.sha1)); | ||||
| 	} | ||||
|  | ||||
| 	if (obj->type == OBJ_TAG) { | ||||
| 		struct tag *tag = (struct tag *) obj; | ||||
|  | ||||
| 		if (show_tags && tag->tagged) { | ||||
| 			printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1)); | ||||
| 			printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  |  | |||
							
								
								
									
										215
									
								
								fsck.c
								
								
								
								
							
							
						
						
									
										215
									
								
								fsck.c
								
								
								
								
							|  | @ -89,3 +89,218 @@ int fsck_walk(struct object *obj, fsck_walk_func walk, void *data) | |||
| 		return -1; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * The entries in a tree are ordered in the _path_ order, | ||||
|  * which means that a directory entry is ordered by adding | ||||
|  * a slash to the end of it. | ||||
|  * | ||||
|  * So a directory called "a" is ordered _after_ a file | ||||
|  * called "a.c", because "a/" sorts after "a.c". | ||||
|  */ | ||||
| #define TREE_UNORDERED (-1) | ||||
| #define TREE_HAS_DUPS  (-2) | ||||
|  | ||||
| static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2) | ||||
| { | ||||
| 	int len1 = strlen(name1); | ||||
| 	int len2 = strlen(name2); | ||||
| 	int len = len1 < len2 ? len1 : len2; | ||||
| 	unsigned char c1, c2; | ||||
| 	int cmp; | ||||
|  | ||||
| 	cmp = memcmp(name1, name2, len); | ||||
| 	if (cmp < 0) | ||||
| 		return 0; | ||||
| 	if (cmp > 0) | ||||
| 		return TREE_UNORDERED; | ||||
|  | ||||
| 	/* | ||||
| 	 * Ok, the first <len> characters are the same. | ||||
| 	 * Now we need to order the next one, but turn | ||||
| 	 * a '\0' into a '/' for a directory entry. | ||||
| 	 */ | ||||
| 	c1 = name1[len]; | ||||
| 	c2 = name2[len]; | ||||
| 	if (!c1 && !c2) | ||||
| 		/* | ||||
| 		 * git-write-tree used to write out a nonsense tree that has | ||||
| 		 * entries with the same name, one blob and one tree.  Make | ||||
| 		 * sure we do not have duplicate entries. | ||||
| 		 */ | ||||
| 		return TREE_HAS_DUPS; | ||||
| 	if (!c1 && S_ISDIR(mode1)) | ||||
| 		c1 = '/'; | ||||
| 	if (!c2 && S_ISDIR(mode2)) | ||||
| 		c2 = '/'; | ||||
| 	return c1 < c2 ? 0 : TREE_UNORDERED; | ||||
| } | ||||
|  | ||||
| static int fsck_tree(struct tree *item, int strict, fsck_error error_func) | ||||
| { | ||||
| 	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; | ||||
| 	int not_properly_sorted = 0; | ||||
| 	struct tree_desc desc; | ||||
| 	unsigned o_mode; | ||||
| 	const char *o_name; | ||||
| 	const unsigned char *o_sha1; | ||||
|  | ||||
| 	init_tree_desc(&desc, item->buffer, item->size); | ||||
|  | ||||
| 	o_mode = 0; | ||||
| 	o_name = NULL; | ||||
| 	o_sha1 = NULL; | ||||
| 	if (!desc.size) | ||||
| 		return error_func(&item->object, FSCK_ERROR, "empty tree"); | ||||
|  | ||||
| 	while (desc.size) { | ||||
| 		unsigned mode; | ||||
| 		const char *name; | ||||
| 		const unsigned char *sha1; | ||||
|  | ||||
| 		sha1 = tree_entry_extract(&desc, &name, &mode); | ||||
|  | ||||
| 		if (strchr(name, '/')) | ||||
| 			has_full_path = 1; | ||||
| 		if (!*name) | ||||
| 			has_empty_name = 1; | ||||
| 		has_zero_pad |= *(char *)desc.buffer == '0'; | ||||
| 		update_tree_entry(&desc); | ||||
|  | ||||
| 		switch (mode) { | ||||
| 		/* | ||||
| 		 * Standard modes.. | ||||
| 		 */ | ||||
| 		case S_IFREG | 0755: | ||||
| 		case S_IFREG | 0644: | ||||
| 		case S_IFLNK: | ||||
| 		case S_IFDIR: | ||||
| 		case S_IFGITLINK: | ||||
| 			break; | ||||
| 		/* | ||||
| 		 * This is nonstandard, but we had a few of these | ||||
| 		 * early on when we honored the full set of mode | ||||
| 		 * bits.. | ||||
| 		 */ | ||||
| 		case S_IFREG | 0664: | ||||
| 			if (!strict) | ||||
| 				break; | ||||
| 		default: | ||||
| 			has_bad_modes = 1; | ||||
| 		} | ||||
|  | ||||
| 		if (o_name) { | ||||
| 			switch (verify_ordered(o_mode, o_name, mode, name)) { | ||||
| 			case TREE_UNORDERED: | ||||
| 				not_properly_sorted = 1; | ||||
| 				break; | ||||
| 			case TREE_HAS_DUPS: | ||||
| 				has_dup_entries = 1; | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		o_mode = mode; | ||||
| 		o_name = name; | ||||
| 		o_sha1 = sha1; | ||||
| 	} | ||||
|  | ||||
| 	retval = 0; | ||||
| 	if (has_full_path) | ||||
| 		retval += error_func(&item->object, FSCK_WARN, "contains full pathnames"); | ||||
| 	if (has_empty_name) | ||||
| 		retval += error_func(&item->object, FSCK_WARN, "contains empty pathname"); | ||||
| 	if (has_zero_pad) | ||||
| 		retval += error_func(&item->object, FSCK_WARN, "contains zero-padded file modes"); | ||||
| 	if (has_bad_modes) | ||||
| 		retval += error_func(&item->object, FSCK_WARN, "contains bad file modes"); | ||||
| 	if (has_dup_entries) | ||||
| 		retval += error_func(&item->object, FSCK_ERROR, "contains duplicate file entries"); | ||||
| 	if (not_properly_sorted) | ||||
| 		retval += error_func(&item->object, FSCK_ERROR, "not properly sorted"); | ||||
| 	return retval; | ||||
| } | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	if (!commit->date) | ||||
| 		return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line"); | ||||
|  | ||||
| 	if (memcmp(buffer, "tree ", 5)) | ||||
| 		return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line"); | ||||
| 	if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n') | ||||
| 		return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1"); | ||||
| 	buffer += 46; | ||||
| 	while (!memcmp(buffer, "parent ", 7)) { | ||||
| 		if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n') | ||||
| 			return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1"); | ||||
| 		buffer += 48; | ||||
| 		parents++; | ||||
| 	} | ||||
| 	graft = lookup_commit_graft(commit->object.sha1); | ||||
| 	if (graft) { | ||||
| 		struct commit_list *p = commit->parents; | ||||
| 		parents = 0; | ||||
| 		while (p) { | ||||
| 			p = p->next; | ||||
| 			parents++; | ||||
| 		} | ||||
| 		if (graft->nr_parent == -1 && !parents) | ||||
| 			; /* shallow commit */ | ||||
| 		else if (graft->nr_parent != parents) | ||||
| 			return error_func(&commit->object, FSCK_ERROR, "graft objects missing"); | ||||
| 	} else { | ||||
| 		struct commit_list *p = commit->parents; | ||||
| 		while (p && parents) { | ||||
| 			p = p->next; | ||||
| 			parents--; | ||||
| 		} | ||||
| 		if (p || parents) | ||||
| 			return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); | ||||
| 	} | ||||
| 	if (memcmp(buffer, "author ", 7)) | ||||
| 		return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line"); | ||||
| 	if (!commit->tree) | ||||
| 		return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int fsck_tag(struct tag *tag, fsck_error error_func) | ||||
| { | ||||
| 	struct object *tagged = tag->tagged; | ||||
|  | ||||
| 	if (!tagged) | ||||
| 		return error_func(&tag->object, FSCK_ERROR, "could not load tagged object"); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int fsck_object(struct object *obj, int strict, fsck_error error_func) | ||||
| { | ||||
| 	if (!obj) | ||||
| 		return error_func(obj, FSCK_ERROR, "no valid object to fsck"); | ||||
|  | ||||
| 	if (obj->type == OBJ_BLOB) | ||||
| 		return 0; | ||||
| 	if (obj->type == OBJ_TREE) | ||||
| 		return fsck_tree((struct tree *) obj, strict, error_func); | ||||
| 	if (obj->type == OBJ_COMMIT) | ||||
| 		return fsck_commit((struct commit *) obj, error_func); | ||||
| 	if (obj->type == OBJ_TAG) | ||||
| 		return fsck_tag((struct tag *) obj, error_func); | ||||
|  | ||||
| 	return error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)", | ||||
| 			  obj->type); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										7
									
								
								fsck.h
								
								
								
								
							
							
						
						
									
										7
									
								
								fsck.h
								
								
								
								
							|  | @ -1,6 +1,9 @@ | |||
| #ifndef GIT_FSCK_H | ||||
| #define GIT_FSCK_H | ||||
|  | ||||
| #define FSCK_ERROR 1 | ||||
| #define FSCK_WARN 2 | ||||
|  | ||||
| /* | ||||
|  * callback function for fsck_walk | ||||
|  * type is the expected type of the object or OBJ_ANY | ||||
|  | @ -11,6 +14,9 @@ | |||
|  */ | ||||
| typedef int (*fsck_walk_func)(struct object *obj, int type, void *data); | ||||
|  | ||||
| /* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */ | ||||
| typedef int (*fsck_error)(struct object *obj, int type, const char *err, ...); | ||||
|  | ||||
| /* descend in all linked child objects | ||||
|  * the return value is: | ||||
|  *    -1	error in processing the object | ||||
|  | @ -19,5 +25,6 @@ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data); | |||
|  *    0		everything OK | ||||
|  */ | ||||
| int fsck_walk(struct object *obj, fsck_walk_func walk, void *data); | ||||
| int fsck_object(struct object *obj, int strict, fsck_error error_func); | ||||
|  | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Martin Koegler
						Martin Koegler