untracked cache: load from UNTR index extension
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									83c094ad0d
								
							
						
					
					
						commit
						f9e6c64958
					
				
							
								
								
									
										219
									
								
								dir.c
								
								
								
								
							
							
						
						
									
										219
									
								
								dir.c
								
								
								
								
							|  | @ -2283,3 +2283,222 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra | ||||||
| 	strbuf_release(&wd.sb_stat); | 	strbuf_release(&wd.sb_stat); | ||||||
| 	strbuf_release(&wd.sb_sha1); | 	strbuf_release(&wd.sb_sha1); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void free_untracked(struct untracked_cache_dir *ucd) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	if (!ucd) | ||||||
|  | 		return; | ||||||
|  | 	for (i = 0; i < ucd->dirs_nr; i++) | ||||||
|  | 		free_untracked(ucd->dirs[i]); | ||||||
|  | 	for (i = 0; i < ucd->untracked_nr; i++) | ||||||
|  | 		free(ucd->untracked[i]); | ||||||
|  | 	free(ucd->untracked); | ||||||
|  | 	free(ucd->dirs); | ||||||
|  | 	free(ucd); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void free_untracked_cache(struct untracked_cache *uc) | ||||||
|  | { | ||||||
|  | 	if (uc) | ||||||
|  | 		free_untracked(uc->root); | ||||||
|  | 	free(uc); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct read_data { | ||||||
|  | 	int index; | ||||||
|  | 	struct untracked_cache_dir **ucd; | ||||||
|  | 	struct ewah_bitmap *check_only; | ||||||
|  | 	struct ewah_bitmap *valid; | ||||||
|  | 	struct ewah_bitmap *sha1_valid; | ||||||
|  | 	const unsigned char *data; | ||||||
|  | 	const unsigned char *end; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static void stat_data_from_disk(struct stat_data *to, const struct stat_data *from) | ||||||
|  | { | ||||||
|  | 	to->sd_ctime.sec  = get_be32(&from->sd_ctime.sec); | ||||||
|  | 	to->sd_ctime.nsec = get_be32(&from->sd_ctime.nsec); | ||||||
|  | 	to->sd_mtime.sec  = get_be32(&from->sd_mtime.sec); | ||||||
|  | 	to->sd_mtime.nsec = get_be32(&from->sd_mtime.nsec); | ||||||
|  | 	to->sd_dev	  = get_be32(&from->sd_dev); | ||||||
|  | 	to->sd_ino	  = get_be32(&from->sd_ino); | ||||||
|  | 	to->sd_uid	  = get_be32(&from->sd_uid); | ||||||
|  | 	to->sd_gid	  = get_be32(&from->sd_gid); | ||||||
|  | 	to->sd_size	  = get_be32(&from->sd_size); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int read_one_dir(struct untracked_cache_dir **untracked_, | ||||||
|  | 			struct read_data *rd) | ||||||
|  | { | ||||||
|  | 	struct untracked_cache_dir ud, *untracked; | ||||||
|  | 	const unsigned char *next, *data = rd->data, *end = rd->end; | ||||||
|  | 	unsigned int value; | ||||||
|  | 	int i, len; | ||||||
|  |  | ||||||
|  | 	memset(&ud, 0, sizeof(ud)); | ||||||
|  |  | ||||||
|  | 	next = data; | ||||||
|  | 	value = decode_varint(&next); | ||||||
|  | 	if (next > end) | ||||||
|  | 		return -1; | ||||||
|  | 	ud.recurse	   = 1; | ||||||
|  | 	ud.untracked_alloc = value; | ||||||
|  | 	ud.untracked_nr	   = value; | ||||||
|  | 	if (ud.untracked_nr) | ||||||
|  | 		ud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr); | ||||||
|  | 	data = next; | ||||||
|  |  | ||||||
|  | 	next = data; | ||||||
|  | 	ud.dirs_alloc = ud.dirs_nr = decode_varint(&next); | ||||||
|  | 	if (next > end) | ||||||
|  | 		return -1; | ||||||
|  | 	ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr); | ||||||
|  | 	data = next; | ||||||
|  |  | ||||||
|  | 	len = strlen((const char *)data); | ||||||
|  | 	next = data + len + 1; | ||||||
|  | 	if (next > rd->end) | ||||||
|  | 		return -1; | ||||||
|  | 	*untracked_ = untracked = xmalloc(sizeof(*untracked) + len); | ||||||
|  | 	memcpy(untracked, &ud, sizeof(ud)); | ||||||
|  | 	memcpy(untracked->name, data, len + 1); | ||||||
|  | 	data = next; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < untracked->untracked_nr; i++) { | ||||||
|  | 		len = strlen((const char *)data); | ||||||
|  | 		next = data + len + 1; | ||||||
|  | 		if (next > rd->end) | ||||||
|  | 			return -1; | ||||||
|  | 		untracked->untracked[i] = xstrdup((const char*)data); | ||||||
|  | 		data = next; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	rd->ucd[rd->index++] = untracked; | ||||||
|  | 	rd->data = data; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < untracked->dirs_nr; i++) { | ||||||
|  | 		len = read_one_dir(untracked->dirs + i, rd); | ||||||
|  | 		if (len < 0) | ||||||
|  | 			return -1; | ||||||
|  | 	} | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void set_check_only(size_t pos, void *cb) | ||||||
|  | { | ||||||
|  | 	struct read_data *rd = cb; | ||||||
|  | 	struct untracked_cache_dir *ud = rd->ucd[pos]; | ||||||
|  | 	ud->check_only = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void read_stat(size_t pos, void *cb) | ||||||
|  | { | ||||||
|  | 	struct read_data *rd = cb; | ||||||
|  | 	struct untracked_cache_dir *ud = rd->ucd[pos]; | ||||||
|  | 	if (rd->data + sizeof(struct stat_data) > rd->end) { | ||||||
|  | 		rd->data = rd->end + 1; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	stat_data_from_disk(&ud->stat_data, (struct stat_data *)rd->data); | ||||||
|  | 	rd->data += sizeof(struct stat_data); | ||||||
|  | 	ud->valid = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void read_sha1(size_t pos, void *cb) | ||||||
|  | { | ||||||
|  | 	struct read_data *rd = cb; | ||||||
|  | 	struct untracked_cache_dir *ud = rd->ucd[pos]; | ||||||
|  | 	if (rd->data + 20 > rd->end) { | ||||||
|  | 		rd->data = rd->end + 1; | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	hashcpy(ud->exclude_sha1, rd->data); | ||||||
|  | 	rd->data += 20; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void load_sha1_stat(struct sha1_stat *sha1_stat, | ||||||
|  | 			   const struct stat_data *stat, | ||||||
|  | 			   const unsigned char *sha1) | ||||||
|  | { | ||||||
|  | 	stat_data_from_disk(&sha1_stat->stat, stat); | ||||||
|  | 	hashcpy(sha1_stat->sha1, sha1); | ||||||
|  | 	sha1_stat->valid = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz) | ||||||
|  | { | ||||||
|  | 	const struct ondisk_untracked_cache *ouc; | ||||||
|  | 	struct untracked_cache *uc; | ||||||
|  | 	struct read_data rd; | ||||||
|  | 	const unsigned char *next = data, *end = (const unsigned char *)data + sz; | ||||||
|  | 	int len; | ||||||
|  |  | ||||||
|  | 	if (sz <= 1 || end[-1] != '\0') | ||||||
|  | 		return NULL; | ||||||
|  | 	end--; | ||||||
|  |  | ||||||
|  | 	ouc = (const struct ondisk_untracked_cache *)next; | ||||||
|  | 	if (next + ouc_size(0) > end) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	uc = xcalloc(1, sizeof(*uc)); | ||||||
|  | 	load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat, | ||||||
|  | 		       ouc->info_exclude_sha1); | ||||||
|  | 	load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat, | ||||||
|  | 		       ouc->excludes_file_sha1); | ||||||
|  | 	uc->dir_flags = get_be32(&ouc->dir_flags); | ||||||
|  | 	uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir); | ||||||
|  | 	/* NUL after exclude_per_dir is covered by sizeof(*ouc) */ | ||||||
|  | 	next += ouc_size(strlen(ouc->exclude_per_dir)); | ||||||
|  | 	if (next >= end) | ||||||
|  | 		goto done2; | ||||||
|  |  | ||||||
|  | 	len = decode_varint(&next); | ||||||
|  | 	if (next > end || len == 0) | ||||||
|  | 		goto done2; | ||||||
|  |  | ||||||
|  | 	rd.valid      = ewah_new(); | ||||||
|  | 	rd.check_only = ewah_new(); | ||||||
|  | 	rd.sha1_valid = ewah_new(); | ||||||
|  | 	rd.data	      = next; | ||||||
|  | 	rd.end	      = end; | ||||||
|  | 	rd.index      = 0; | ||||||
|  | 	rd.ucd        = xmalloc(sizeof(*rd.ucd) * len); | ||||||
|  |  | ||||||
|  | 	if (read_one_dir(&uc->root, &rd) || rd.index != len) | ||||||
|  | 		goto done; | ||||||
|  |  | ||||||
|  | 	next = rd.data; | ||||||
|  | 	len = ewah_read_mmap(rd.valid, next, end - next); | ||||||
|  | 	if (len < 0) | ||||||
|  | 		goto done; | ||||||
|  |  | ||||||
|  | 	next += len; | ||||||
|  | 	len = ewah_read_mmap(rd.check_only, next, end - next); | ||||||
|  | 	if (len < 0) | ||||||
|  | 		goto done; | ||||||
|  |  | ||||||
|  | 	next += len; | ||||||
|  | 	len = ewah_read_mmap(rd.sha1_valid, next, end - next); | ||||||
|  | 	if (len < 0) | ||||||
|  | 		goto done; | ||||||
|  |  | ||||||
|  | 	ewah_each_bit(rd.check_only, set_check_only, &rd); | ||||||
|  | 	rd.data = next + len; | ||||||
|  | 	ewah_each_bit(rd.valid, read_stat, &rd); | ||||||
|  | 	ewah_each_bit(rd.sha1_valid, read_sha1, &rd); | ||||||
|  | 	next = rd.data; | ||||||
|  |  | ||||||
|  | done: | ||||||
|  | 	free(rd.ucd); | ||||||
|  | 	ewah_free(rd.valid); | ||||||
|  | 	ewah_free(rd.check_only); | ||||||
|  | 	ewah_free(rd.sha1_valid); | ||||||
|  | done2: | ||||||
|  | 	if (next != end) { | ||||||
|  | 		free_untracked_cache(uc); | ||||||
|  | 		uc = NULL; | ||||||
|  | 	} | ||||||
|  | 	return uc; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								dir.h
								
								
								
								
							
							
						
						
									
										2
									
								
								dir.h
								
								
								
								
							|  | @ -298,5 +298,7 @@ static inline int dir_path_match(const struct dir_entry *ent, | ||||||
| 			      has_trailing_dir); | 			      has_trailing_dir); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void free_untracked_cache(struct untracked_cache *); | ||||||
|  | struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz); | ||||||
| void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked); | void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -1371,6 +1371,9 @@ static int read_index_extension(struct index_state *istate, | ||||||
| 		if (read_link_extension(istate, data, sz)) | 		if (read_link_extension(istate, data, sz)) | ||||||
| 			return -1; | 			return -1; | ||||||
| 		break; | 		break; | ||||||
|  | 	case CACHE_EXT_UNTRACKED: | ||||||
|  | 		istate->untracked = read_untracked_extension(data, sz); | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		if (*ext < 'A' || 'Z' < *ext) | 		if (*ext < 'A' || 'Z' < *ext) | ||||||
| 			return error("index uses %.4s extension, which we do not understand", | 			return error("index uses %.4s extension, which we do not understand", | ||||||
|  | @ -1662,6 +1665,8 @@ int discard_index(struct index_state *istate) | ||||||
| 	istate->cache = NULL; | 	istate->cache = NULL; | ||||||
| 	istate->cache_alloc = 0; | 	istate->cache_alloc = 0; | ||||||
| 	discard_split_index(istate); | 	discard_split_index(istate); | ||||||
|  | 	free_untracked_cache(istate->untracked); | ||||||
|  | 	istate->untracked = NULL; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Nguyễn Thái Ngọc Duy
						Nguyễn Thái Ngọc Duy