Status update on merge-recursive in C
This is just an update for people being interested. Alex and me were busy with that project for a few days now. While it has progressed nicely, there are quite a couple TODOs in merge-recursive.c, just search for "TODO". For impatient people: yes, it passes all the tests, and yes, according to the evil test Alex did, it is faster than the Python script. But no, it is not yet finished. Biggest points are: - there are still three external calls - in the end, it should not be necessary to write the index more than once (just before exiting) - a lot of things can be refactored to make the code easier and shorter BTW we cannot just plug in git-merge-tree yet, because git-merge-tree does not handle renames at all. This patch is meant for testing, and as such, - it compile the program to git-merge-recur - it adjusts the scripts and tests to use git-merge-recur instead of git-merge-recursive - it provides "TEST", a script to execute the tests regarding -recursive - it inlines the changes to read-cache.c (read_cache_from(), discard_cache() and refresh_cache_entry()) Brought to you by Alex Riesen and Dscho Signed-off-by: Junio C Hamano <junkio@cox.net>maint
							parent
							
								
									4b7ce6e2d6
								
							
						
					
					
						commit
						6d297f8137
					
				
							
								
								
									
										8
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										8
									
								
								Makefile
								
								
								
								
							|  | @ -167,7 +167,8 @@ PROGRAMS = \ | ||||||
| 	git-upload-pack$X git-verify-pack$X \ | 	git-upload-pack$X git-verify-pack$X \ | ||||||
| 	git-symbolic-ref$X \ | 	git-symbolic-ref$X \ | ||||||
| 	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ | 	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \ | ||||||
| 	git-describe$X git-merge-tree$X git-blame$X git-imap-send$X | 	git-describe$X git-merge-tree$X git-blame$X git-imap-send$X \ | ||||||
|  | 	git-merge-recur$X | ||||||
|  |  | ||||||
| BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \ | BUILT_INS = git-log$X git-whatchanged$X git-show$X git-update-ref$X \ | ||||||
| 	git-count-objects$X git-diff$X git-push$X git-mailsplit$X \ | 	git-count-objects$X git-diff$X git-push$X git-mailsplit$X \ | ||||||
|  | @ -615,6 +616,11 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) | ||||||
| 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ | 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ | ||||||
| 		$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) | 		$(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) | ||||||
|  |  | ||||||
|  | merge-recursive.o path-list.o: path-list.h | ||||||
|  | git-merge-recur$X: merge-recursive.o path-list.o $(LIB_FILE) | ||||||
|  | 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ | ||||||
|  | 		$(LIBS) | ||||||
|  |  | ||||||
| $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) | $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) | ||||||
| $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) | $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) | ||||||
| $(DIFF_OBJS): diffcore.h | $(DIFF_OBJS): diffcore.h | ||||||
|  |  | ||||||
|  | @ -0,0 +1,10 @@ | ||||||
|  | #!/bin/sh -x | ||||||
|  | cd t || exit | ||||||
|  | ./t3400-rebase.sh              "$@" && \ | ||||||
|  | ./t6020-merge-df.sh            "$@" && \ | ||||||
|  | ./t3401-rebase-partial.sh      "$@" && \ | ||||||
|  | ./t6021-merge-criss-cross.sh   "$@" && \ | ||||||
|  | ./t3402-rebase-merge.sh        "$@" && \ | ||||||
|  | ./t6022-merge-rename.sh        "$@" && \ | ||||||
|  | ./t6010-merge-base.sh          "$@" && \ | ||||||
|  | : | ||||||
							
								
								
									
										4
									
								
								cache.h
								
								
								
								
							
							
						
						
									
										4
									
								
								cache.h
								
								
								
								
							|  | @ -115,6 +115,7 @@ static inline unsigned int create_ce_mode(unsigned int mode) | ||||||
| extern struct cache_entry **active_cache; | extern struct cache_entry **active_cache; | ||||||
| extern unsigned int active_nr, active_alloc, active_cache_changed; | extern unsigned int active_nr, active_alloc, active_cache_changed; | ||||||
| extern struct cache_tree *active_cache_tree; | extern struct cache_tree *active_cache_tree; | ||||||
|  | extern int cache_errno; | ||||||
|  |  | ||||||
| #define GIT_DIR_ENVIRONMENT "GIT_DIR" | #define GIT_DIR_ENVIRONMENT "GIT_DIR" | ||||||
| #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" | #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" | ||||||
|  | @ -142,13 +143,16 @@ extern void verify_non_filename(const char *prefix, const char *name); | ||||||
|  |  | ||||||
| /* Initialize and use the cache information */ | /* Initialize and use the cache information */ | ||||||
| extern int read_cache(void); | extern int read_cache(void); | ||||||
|  | extern int read_cache_from(const char *path); | ||||||
| extern int write_cache(int newfd, struct cache_entry **cache, int entries); | extern int write_cache(int newfd, struct cache_entry **cache, int entries); | ||||||
|  | extern int discard_cache(void); | ||||||
| extern int verify_path(const char *path); | extern int verify_path(const char *path); | ||||||
| extern int cache_name_pos(const char *name, int namelen); | extern int cache_name_pos(const char *name, int namelen); | ||||||
| #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */ | #define ADD_CACHE_OK_TO_ADD 1		/* Ok to add */ | ||||||
| #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */ | #define ADD_CACHE_OK_TO_REPLACE 2	/* Ok to replace file/directory */ | ||||||
| #define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */ | #define ADD_CACHE_SKIP_DFCHECK 4	/* Ok to skip DF conflict checks */ | ||||||
| extern int add_cache_entry(struct cache_entry *ce, int option); | extern int add_cache_entry(struct cache_entry *ce, int option); | ||||||
|  | extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); | ||||||
| extern int remove_cache_entry_at(int pos); | extern int remove_cache_entry_at(int pos); | ||||||
| extern int remove_file_from_cache(const char *path); | extern int remove_file_from_cache(const char *path); | ||||||
| extern int ce_same_name(struct cache_entry *a, struct cache_entry *b); | extern int ce_same_name(struct cache_entry *a, struct cache_entry *b); | ||||||
|  |  | ||||||
|  | @ -9,15 +9,15 @@ USAGE='[-n] [--no-commit] [--squash] [-s <strategy>]... <merge-message> <head> < | ||||||
| LF=' | LF=' | ||||||
| ' | ' | ||||||
|  |  | ||||||
| all_strategies='recursive octopus resolve stupid ours' | all_strategies='recur recur octopus resolve stupid ours' | ||||||
| default_twohead_strategies='recursive' | default_twohead_strategies='recur' | ||||||
| default_octopus_strategies='octopus' | default_octopus_strategies='octopus' | ||||||
| no_trivial_merge_strategies='ours' | no_trivial_merge_strategies='ours' | ||||||
| use_strategies= | use_strategies= | ||||||
|  |  | ||||||
| index_merge=t | index_merge=t | ||||||
| if test "@@NO_PYTHON@@"; then | if test "@@NO_PYTHON@@"; then | ||||||
| 	all_strategies='resolve octopus stupid ours' | 	all_strategies='recur resolve octopus stupid ours' | ||||||
| 	default_twohead_strategies='resolve' | 	default_twohead_strategies='resolve' | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ -35,7 +35,7 @@ If you would prefer to skip this patch, instead run \"git rebase --skip\". | ||||||
| To restore the original branch and stop rebasing run \"git rebase --abort\". | To restore the original branch and stop rebasing run \"git rebase --abort\". | ||||||
| " | " | ||||||
| unset newbase | unset newbase | ||||||
| strategy=recursive | strategy=recur | ||||||
| do_merge= | do_merge= | ||||||
| dotest=$GIT_DIR/.dotest-merge | dotest=$GIT_DIR/.dotest-merge | ||||||
| prec=4 | prec=4 | ||||||
|  | @ -292,7 +292,7 @@ then | ||||||
| 	exit $? | 	exit $? | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if test "@@NO_PYTHON@@" && test "$strategy" = "recursive" | if test "@@NO_PYTHON@@" && test "$strategy" = "recur" | ||||||
| then | then | ||||||
| 	die 'The recursive merge strategy currently relies on Python, | 	die 'The recursive merge strategy currently relies on Python, | ||||||
| which this installation of git was not configured with.  Please consider | which this installation of git was not configured with.  Please consider | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,105 @@ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include "cache.h" | ||||||
|  | #include "path-list.h" | ||||||
|  |  | ||||||
|  | /* if there is no exact match, point to the index where the entry could be | ||||||
|  |  * inserted */ | ||||||
|  | static int get_entry_index(const struct path_list *list, const char *path, | ||||||
|  | 		int *exact_match) | ||||||
|  | { | ||||||
|  | 	int left = -1, right = list->nr; | ||||||
|  |  | ||||||
|  | 	while (left + 1 < right) { | ||||||
|  | 		int middle = (left + right) / 2; | ||||||
|  | 		int compare = strcmp(path, list->items[middle].path); | ||||||
|  | 		if (compare < 0) | ||||||
|  | 			right = middle; | ||||||
|  | 		else if (compare > 0) | ||||||
|  | 			left = middle; | ||||||
|  | 		else { | ||||||
|  | 			*exact_match = 1; | ||||||
|  | 			return middle; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	*exact_match = 0; | ||||||
|  | 	return right; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* returns -1-index if already exists */ | ||||||
|  | static int add_entry(struct path_list *list, const char *path) | ||||||
|  | { | ||||||
|  | 	int exact_match; | ||||||
|  | 	int index = get_entry_index(list, path, &exact_match); | ||||||
|  |  | ||||||
|  | 	if (exact_match) | ||||||
|  | 		return -1 - index; | ||||||
|  |  | ||||||
|  | 	if (list->nr + 1 >= list->alloc) { | ||||||
|  | 		list->alloc += 32; | ||||||
|  | 		list->items = xrealloc(list->items, list->alloc | ||||||
|  | 				* sizeof(struct path_list_item)); | ||||||
|  | 	} | ||||||
|  | 	if (index < list->nr) | ||||||
|  | 		memmove(list->items + index + 1, list->items + index, | ||||||
|  | 				(list->nr - index) | ||||||
|  | 				* sizeof(struct path_list_item)); | ||||||
|  | 	list->items[index].path = list->strdup_paths ? | ||||||
|  | 		strdup(path) : (char *)path; | ||||||
|  | 	list->items[index].util = NULL; | ||||||
|  | 	list->nr++; | ||||||
|  |  | ||||||
|  | 	return index; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct path_list_item *path_list_insert(const char *path, struct path_list *list) | ||||||
|  | { | ||||||
|  | 	int index = add_entry(list, path); | ||||||
|  |  | ||||||
|  | 	if (index < 0) | ||||||
|  | 		index = 1 - index; | ||||||
|  |  | ||||||
|  | 	return list->items + index; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int path_list_has_path(const struct path_list *list, const char *path) | ||||||
|  | { | ||||||
|  | 	int exact_match; | ||||||
|  | 	get_entry_index(list, path, &exact_match); | ||||||
|  | 	return exact_match; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct path_list_item *path_list_lookup(const char *path, struct path_list *list) | ||||||
|  | { | ||||||
|  | 	int exact_match, i = get_entry_index(list, path, &exact_match); | ||||||
|  | 	if (!exact_match) | ||||||
|  | 		return NULL; | ||||||
|  | 	return list->items + i; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void path_list_clear(struct path_list *list, int free_items) | ||||||
|  | { | ||||||
|  | 	if (list->items) { | ||||||
|  | 		int i; | ||||||
|  | 		if (free_items) | ||||||
|  | 			for (i = 0; i < list->nr; i++) { | ||||||
|  | 				if (list->strdup_paths) | ||||||
|  | 					free(list->items[i].path); | ||||||
|  | 				if (list->items[i].util) | ||||||
|  | 					free(list->items[i].util); | ||||||
|  | 			} | ||||||
|  | 		free(list->items); | ||||||
|  | 	} | ||||||
|  | 	list->items = NULL; | ||||||
|  | 	list->nr = list->alloc = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void print_path_list(const char *text, const struct path_list *p) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	if ( text ) | ||||||
|  | 		printf("%s\n", text); | ||||||
|  | 	for (i = 0; i < p->nr; i++) | ||||||
|  | 		printf("%s:%p\n", p->items[i].path, p->items[i].util); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | #ifndef _PATH_LIST_H_ | ||||||
|  | #define _PATH_LIST_H_ | ||||||
|  |  | ||||||
|  | struct path_list_item { | ||||||
|  | 	char *path; | ||||||
|  | 	void *util; | ||||||
|  | }; | ||||||
|  | struct path_list | ||||||
|  | { | ||||||
|  | 	struct path_list_item *items; | ||||||
|  | 	unsigned int nr, alloc; | ||||||
|  | 	unsigned int strdup_paths:1; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | void print_path_list(const char *text, const struct path_list *p); | ||||||
|  |  | ||||||
|  | int path_list_has_path(const struct path_list *list, const char *path); | ||||||
|  | void path_list_clear(struct path_list *list, int free_items); | ||||||
|  | struct path_list_item *path_list_insert(const char *path, struct path_list *list); | ||||||
|  | struct path_list_item *path_list_lookup(const char *path, struct path_list *list); | ||||||
|  |  | ||||||
|  | #endif /* _PATH_LIST_H_ */ | ||||||
							
								
								
									
										104
									
								
								read-cache.c
								
								
								
								
							
							
						
						
									
										104
									
								
								read-cache.c
								
								
								
								
							|  | @ -24,6 +24,11 @@ unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0; | ||||||
|  |  | ||||||
| struct cache_tree *active_cache_tree = NULL; | struct cache_tree *active_cache_tree = NULL; | ||||||
|  |  | ||||||
|  | int cache_errno = 0; | ||||||
|  |  | ||||||
|  | static void *cache_mmap = NULL; | ||||||
|  | static size_t cache_mmap_size = 0; | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * This only updates the "non-critical" parts of the directory |  * This only updates the "non-critical" parts of the directory | ||||||
|  * cache, ie the parts that aren't tracked by GIT, and only used |  * cache, ie the parts that aren't tracked by GIT, and only used | ||||||
|  | @ -577,22 +582,6 @@ int add_cache_entry(struct cache_entry *ce, int option) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Three functions to allow overloaded pointer return; see linux/err.h */ |  | ||||||
| static inline void *ERR_PTR(long error) |  | ||||||
| { |  | ||||||
| 	return (void *) error; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline long PTR_ERR(const void *ptr) |  | ||||||
| { |  | ||||||
| 	return (long) ptr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static inline long IS_ERR(const void *ptr) |  | ||||||
| { |  | ||||||
| 	return (unsigned long)ptr > (unsigned long)-1000L; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * "refresh" does not calculate a new sha1 file or bring the |  * "refresh" does not calculate a new sha1 file or bring the | ||||||
|  * cache up-to-date for mode/content changes. But what it |  * cache up-to-date for mode/content changes. But what it | ||||||
|  | @ -604,14 +593,16 @@ static inline long IS_ERR(const void *ptr) | ||||||
|  * For example, you'd want to do this after doing a "git-read-tree", |  * For example, you'd want to do this after doing a "git-read-tree", | ||||||
|  * to link up the stat cache details with the proper files. |  * to link up the stat cache details with the proper files. | ||||||
|  */ |  */ | ||||||
| static struct cache_entry *refresh_entry(struct cache_entry *ce, int really) | struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) | ||||||
| { | { | ||||||
| 	struct stat st; | 	struct stat st; | ||||||
| 	struct cache_entry *updated; | 	struct cache_entry *updated; | ||||||
| 	int changed, size; | 	int changed, size; | ||||||
|  |  | ||||||
| 	if (lstat(ce->name, &st) < 0) | 	if (lstat(ce->name, &st) < 0) { | ||||||
| 		return ERR_PTR(-errno); | 		cache_errno = errno; | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	changed = ce_match_stat(ce, &st, really); | 	changed = ce_match_stat(ce, &st, really); | ||||||
| 	if (!changed) { | 	if (!changed) { | ||||||
|  | @ -619,11 +610,13 @@ static struct cache_entry *refresh_entry(struct cache_entry *ce, int really) | ||||||
| 		    !(ce->ce_flags & htons(CE_VALID))) | 		    !(ce->ce_flags & htons(CE_VALID))) | ||||||
| 			; /* mark this one VALID again */ | 			; /* mark this one VALID again */ | ||||||
| 		else | 		else | ||||||
| 			return NULL; | 			return ce; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (ce_modified(ce, &st, really)) | 	if (ce_modified(ce, &st, really)) { | ||||||
| 		return ERR_PTR(-EINVAL); | 		cache_errno = EINVAL; | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	size = ce_size(ce); | 	size = ce_size(ce); | ||||||
| 	updated = xmalloc(size); | 	updated = xmalloc(size); | ||||||
|  | @ -666,13 +659,13 @@ int refresh_cache(unsigned int flags) | ||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		new = refresh_entry(ce, really); | 		new = refresh_cache_entry(ce, really); | ||||||
| 		if (!new) | 		if (new == ce) | ||||||
| 			continue; | 			continue; | ||||||
| 		if (IS_ERR(new)) { | 		if (!new) { | ||||||
| 			if (not_new && PTR_ERR(new) == -ENOENT) | 			if (not_new && cache_errno == ENOENT) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (really && PTR_ERR(new) == -EINVAL) { | 			if (really && cache_errno == EINVAL) { | ||||||
| 				/* If we are doing --really-refresh that | 				/* If we are doing --really-refresh that | ||||||
| 				 * means the index is not valid anymore. | 				 * means the index is not valid anymore. | ||||||
| 				 */ | 				 */ | ||||||
|  | @ -728,40 +721,44 @@ static int read_index_extension(const char *ext, void *data, unsigned long sz) | ||||||
| } | } | ||||||
|  |  | ||||||
| int read_cache(void) | int read_cache(void) | ||||||
|  | { | ||||||
|  | 	return read_cache_from(get_index_file()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* remember to discard_cache() before reading a different cache! */ | ||||||
|  | int read_cache_from(const char *path) | ||||||
| { | { | ||||||
| 	int fd, i; | 	int fd, i; | ||||||
| 	struct stat st; | 	struct stat st; | ||||||
| 	unsigned long size, offset; | 	unsigned long offset; | ||||||
| 	void *map; |  | ||||||
| 	struct cache_header *hdr; | 	struct cache_header *hdr; | ||||||
|  |  | ||||||
| 	errno = EBUSY; | 	errno = EBUSY; | ||||||
| 	if (active_cache) | 	if (cache_mmap) | ||||||
| 		return active_nr; | 		return active_nr; | ||||||
|  |  | ||||||
| 	errno = ENOENT; | 	errno = ENOENT; | ||||||
| 	index_file_timestamp = 0; | 	index_file_timestamp = 0; | ||||||
| 	fd = open(get_index_file(), O_RDONLY); | 	fd = open(path, O_RDONLY); | ||||||
| 	if (fd < 0) { | 	if (fd < 0) { | ||||||
| 		if (errno == ENOENT) | 		if (errno == ENOENT) | ||||||
| 			return 0; | 			return 0; | ||||||
| 		die("index file open failed (%s)", strerror(errno)); | 		die("index file open failed (%s)", strerror(errno)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	size = 0; /* avoid gcc warning */ | 	cache_mmap = MAP_FAILED; | ||||||
| 	map = MAP_FAILED; |  | ||||||
| 	if (!fstat(fd, &st)) { | 	if (!fstat(fd, &st)) { | ||||||
| 		size = st.st_size; | 		cache_mmap_size = st.st_size; | ||||||
| 		errno = EINVAL; | 		errno = EINVAL; | ||||||
| 		if (size >= sizeof(struct cache_header) + 20) | 		if (cache_mmap_size >= sizeof(struct cache_header) + 20) | ||||||
| 			map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | 			cache_mmap = mmap(NULL, cache_mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); | ||||||
| 	} | 	} | ||||||
| 	close(fd); | 	close(fd); | ||||||
| 	if (map == MAP_FAILED) | 	if (cache_mmap == MAP_FAILED) | ||||||
| 		die("index file mmap failed (%s)", strerror(errno)); | 		die("index file mmap failed (%s)", strerror(errno)); | ||||||
|  |  | ||||||
| 	hdr = map; | 	hdr = cache_mmap; | ||||||
| 	if (verify_hdr(hdr, size) < 0) | 	if (verify_hdr(hdr, cache_mmap_size) < 0) | ||||||
| 		goto unmap; | 		goto unmap; | ||||||
|  |  | ||||||
| 	active_nr = ntohl(hdr->hdr_entries); | 	active_nr = ntohl(hdr->hdr_entries); | ||||||
|  | @ -770,12 +767,12 @@ int read_cache(void) | ||||||
|  |  | ||||||
| 	offset = sizeof(*hdr); | 	offset = sizeof(*hdr); | ||||||
| 	for (i = 0; i < active_nr; i++) { | 	for (i = 0; i < active_nr; i++) { | ||||||
| 		struct cache_entry *ce = (struct cache_entry *) ((char *) map + offset); | 		struct cache_entry *ce = (struct cache_entry *) ((char *) cache_mmap + offset); | ||||||
| 		offset = offset + ce_size(ce); | 		offset = offset + ce_size(ce); | ||||||
| 		active_cache[i] = ce; | 		active_cache[i] = ce; | ||||||
| 	} | 	} | ||||||
| 	index_file_timestamp = st.st_mtime; | 	index_file_timestamp = st.st_mtime; | ||||||
| 	while (offset <= size - 20 - 8) { | 	while (offset <= cache_mmap_size - 20 - 8) { | ||||||
| 		/* After an array of active_nr index entries, | 		/* After an array of active_nr index entries, | ||||||
| 		 * there can be arbitrary number of extended | 		 * there can be arbitrary number of extended | ||||||
| 		 * sections, each of which is prefixed with | 		 * sections, each of which is prefixed with | ||||||
|  | @ -783,10 +780,10 @@ int read_cache(void) | ||||||
| 		 * in 4-byte network byte order. | 		 * in 4-byte network byte order. | ||||||
| 		 */ | 		 */ | ||||||
| 		unsigned long extsize; | 		unsigned long extsize; | ||||||
| 		memcpy(&extsize, (char *) map + offset + 4, 4); | 		memcpy(&extsize, (char *) cache_mmap + offset + 4, 4); | ||||||
| 		extsize = ntohl(extsize); | 		extsize = ntohl(extsize); | ||||||
| 		if (read_index_extension(((const char *) map) + offset, | 		if (read_index_extension(((const char *) cache_mmap) + offset, | ||||||
| 					 (char *) map + offset + 8, | 					 (char *) cache_mmap + offset + 8, | ||||||
| 					 extsize) < 0) | 					 extsize) < 0) | ||||||
| 			goto unmap; | 			goto unmap; | ||||||
| 		offset += 8; | 		offset += 8; | ||||||
|  | @ -795,11 +792,28 @@ int read_cache(void) | ||||||
| 	return active_nr; | 	return active_nr; | ||||||
|  |  | ||||||
| unmap: | unmap: | ||||||
| 	munmap(map, size); | 	munmap(cache_mmap, cache_mmap_size); | ||||||
| 	errno = EINVAL; | 	errno = EINVAL; | ||||||
| 	die("index file corrupt"); | 	die("index file corrupt"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int discard_cache() | ||||||
|  | { | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
|  | 	if (cache_mmap == NULL) | ||||||
|  | 		return 0; | ||||||
|  | 	ret = munmap(cache_mmap, cache_mmap_size); | ||||||
|  | 	cache_mmap = NULL; | ||||||
|  | 	cache_mmap_size = 0; | ||||||
|  | 	active_nr = active_cache_changed = 0; | ||||||
|  | 	index_file_timestamp = 0; | ||||||
|  | 	cache_tree_free(&active_cache_tree); | ||||||
|  |  | ||||||
|  | 	/* no need to throw away allocated active_cache */ | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
| #define WRITE_BUFFER_SIZE 8192 | #define WRITE_BUFFER_SIZE 8192 | ||||||
| static unsigned char write_buffer[WRITE_BUFFER_SIZE]; | static unsigned char write_buffer[WRITE_BUFFER_SIZE]; | ||||||
| static unsigned long write_buffer_len; | static unsigned long write_buffer_len; | ||||||
|  |  | ||||||
|  | @ -51,7 +51,7 @@ test_expect_success setup ' | ||||||
| ' | ' | ||||||
|  |  | ||||||
| test_expect_success 'reference merge' ' | test_expect_success 'reference merge' ' | ||||||
| 	git merge -s recursive "reference merge" HEAD master | 	git merge -s recur "reference merge" HEAD master | ||||||
| ' | ' | ||||||
|  |  | ||||||
| test_expect_success rebase ' | test_expect_success rebase ' | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Johannes Schindelin
						Johannes Schindelin