Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 dir.c        | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 dir.h        |   3 ++
 read-cache.c |   5 ++
 3 files changed, 151 insertions(+), 4 deletions(-)

diff --git a/dir.c b/dir.c
index d696388..c97b0c3 100644
--- a/dir.c
+++ b/dir.c
@@ -2085,15 +2085,27 @@ void setup_standard_excludes(struct dir_struct *dir)
        }
        if (!access_or_warn(path, R_OK, 0)) {
                struct sha1_stat *ss = NULL;
-               if (dir->untracked)
+               int ss_valid = 0;
+               if (dir->untracked) {
                        ss = &dir->ss_info_exclude;
-               add_excludes_from_file_1(dir, path, ss, 0);
+                       if (dir->untracked->loaded) {
+                               *ss = dir->untracked->ss_info_exclude;
+                               ss_valid = 1;
+                       }
+               }
+               add_excludes_from_file_1(dir, path, ss, ss_valid);
        }
        if (excludes_file && !access_or_warn(excludes_file, R_OK, 0)) {
                struct sha1_stat *ss = NULL;
-               if (dir->untracked)
+               int ss_valid = 0;
+               if (dir->untracked) {
                        ss = &dir->ss_excludes_file;
-               add_excludes_from_file_1(dir, excludes_file, ss, 0);
+                       if (dir->untracked->loaded) {
+                               *ss = dir->untracked->ss_excludes_file;
+                               ss_valid = 1;
+                       }
+               }
+               add_excludes_from_file_1(dir, excludes_file, ss, ss_valid);
        }
 }
 
@@ -2230,3 +2242,130 @@ 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_;
+}
+
+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));
+       stat_data_from_disk(&uc->ss_info_exclude.stat, &ouc->info_exclude_stat);
+       stat_data_from_disk(&uc->ss_excludes_file.stat, 
&ouc->excludes_file_stat);
+       hashcpy(uc->ss_info_exclude.sha1, ouc->info_exclude_sha1);
+       hashcpy(uc->ss_excludes_file.sha1, ouc->excludes_file_sha1);
+       uc->dir_flags = get_be32(&ouc->dir_flags);
+       uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir);
+       uc->loaded = 1;
+       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 7ef0f63..014f3ed 100644
--- a/dir.h
+++ b/dir.h
@@ -137,6 +137,7 @@ struct untracked_cache {
        int gitignore_invalidated;
        int dir_invalidated;
        int dir_opened;
+       int loaded;
 };
 
 struct dir_struct {
@@ -297,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 efff4e2..60baeaf 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1359,6 +1359,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",
@@ -1650,6 +1653,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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to