Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- dir.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dir.h | 2 + read-cache.c | 5 +++ 3 files changed, 142 insertions(+) diff --git a/dir.c b/dir.c index 4e15f20..bc196b3 100644 --- a/dir.c +++ b/dir.c @@ -2223,3 +2223,138 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra if (untracked->root) write_one_dir(out, untracked->root); } + +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); +} + +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_, + const unsigned char *data_, unsigned long sz) +{ +#define NEXT(x) \ + next = data + (x); \ + if (next > data_ + sz) \ + return -1; + + struct untracked_cache_dir ud, *untracked; + const unsigned char *next, *data = data_; + unsigned int value; + int i, len; + + memset(&ud, 0, sizeof(ud)); + + NEXT(sizeof(struct stat_data)); + stat_data_from_disk(&ud.stat_data, (struct stat_data *)data); + data = next; + + NEXT(20); + hashcpy(ud.exclude_sha1, data); + data = next; + + next = data; + value = decode_varint(&next); + if (next > data_ + sz) + return -1; + ud.recurse = 1; + ud.valid = value & 1; + ud.check_only = (value >> 1) & 1; + ud.untracked_alloc = ud.untracked_nr = value >> 2; + 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 > data_ + sz) + return -1; + ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr); + data = next; + + len = strlen((const char *)data); + NEXT(len + 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(len + 1); + untracked->untracked[i] = xstrdup((const char*)data); + data = next; + } + + for (i = 0; i < untracked->dirs_nr; i++) { + len = read_one_dir(untracked->dirs + i, data, sz - (data - data_)); + if (len < 0) + return -1; + data += len; + } + return data - data_; +} + +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 = data; + struct untracked_cache *uc; + int len; + + if (sz < sizeof(*ouc)) + 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); + len = sizeof(*ouc) + strlen(ouc->exclude_per_dir); + if (sz == len) + return uc; + if (sz > len && + read_one_dir(&uc->root, (const unsigned char *)data + len, + sz - len) == sz - len) + return uc; + free_untracked_cache(uc); + return NULL; +} diff --git a/dir.h b/dir.h index c771057..14ee4fd 100644 --- a/dir.h +++ b/dir.h @@ -298,5 +298,7 @@ static inline int dir_path_match(const struct dir_entry *ent, 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); #endif diff --git a/read-cache.c b/read-cache.c index 26e938d..f5bd174 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1366,6 +1366,9 @@ static int read_index_extension(struct index_state *istate, if (read_link_extension(istate, data, sz)) return -1; break; + case CACHE_EXT_UNTRACKED: + istate->untracked = read_untracked_extension(data, sz); + break; default: if (*ext < 'A' || 'Z' < *ext) return error("index uses %.4s extension, which we do not understand", @@ -1631,6 +1634,8 @@ int discard_index(struct index_state *istate) istate->cache = NULL; istate->cache_alloc = 0; discard_split_index(istate); + free_untracked_cache(istate->untracked); + istate->untracked = NULL; return 0; } -- 2.1.0.rc0.78.gc0d8480 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html