From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH v3 00/23] nd/untracked-cache updates
Date: Mon, 8 Dec 2014 21:04:43 +0700 [thread overview]
Message-ID: <1418047507-22892-1-git-send-email-pclouds@gmail.com> (raw)
Compare to v1 (the one on 'pu' as v2 never got to 'pu'):
- New cleanup patch 09/23
- New patch 17/23 allows to ignore untracked cache without destroying
it (for comparison and verification)
- New patches 22/23 and 23/23 add some protection against filesystem
or operating system changes
- Document UNTR extension
- Reorganize UNTR to avoid saving SHA-1/stat data when it's useless
- Fix writing UNTR to base index in split index mode
- Various review comments since v1
-- 8< --
diff --git a/Documentation/technical/index-format.txt b/Documentation/technical/index-format.txt
index fe6f316..5dc2bee 100644
--- a/Documentation/technical/index-format.txt
+++ b/Documentation/technical/index-format.txt
@@ -233,3 +233,64 @@ Git index format
The remaining index entries after replaced ones will be added to the
final index. These added entries are also sorted by entry namme then
stage.
+
+== Untracked cache
+
+ Untracked cache saves the untracked file list and necessary data to
+ verify the cache. The signature for this extension is { 'U', 'N',
+ 'T', 'R' }.
+
+ The extension starts with
+
+ - A NUL-terminated string describing the environment when the cache
+ is created.
+
+ - Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
+ ctime field until "file size".
+
+ - Stat data of core.excludesfile
+
+ - 32-bit dir_flags (see struct dir_struct)
+
+ - 160-bit SHA-1 of $GIT_DIR/info/exclude. Null SHA-1 means the file
+ does not exist.
+
+ - 160-bit SHA-1 of core.excludesfile. Null SHA-1 means the file does
+ not exist.
+
+ - NUL-terminated string of per-dir exclude file name. This usually
+ is ".gitignore".
+
+ - The number of following directory blocks, variable width
+ encoding. If this number is zero, the extension ends here with a
+ following NUL.
+
+ - A number of directory blocks in depth-first-search order, each
+ consists of
+
+ - The number of untracked entries, variable witdh encoding.
+
+ - The number of sub-directory blocks, variable with encoding.
+
+ - The directory name terminated by NUL.
+
+ - A number of untrached file/dir names terminated by NUL.
+
+The remaining data of each directory block is grouped by type:
+
+ - An ewah bitmap, the n-th bit marks whether the n-th directory has
+ valid untracked cache entries.
+
+ - An ewah bitmap, the n-th bit records "check-only" bit of
+ read_directory_recursive() for the n-th directory.
+
+ - An ewah bitmap, the n-th bit indicates whether SHA-1 and stat data
+ is valid for the n-th directory and exists in the next data.
+
+ - An array of stat data. The n-th data corresponds with the n-th
+ "one" bit in the previous ewah bitmap.
+
+ - An array of SHA-1. The n-th SHA-1 corresponds with the n-th "one" bit
+ in the previous ewah bitmap.
+
+ - One NUL.
diff --git a/builtin/update-index.c b/builtin/update-index.c
index c1c18db..f23ec83 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -115,6 +115,7 @@ static int test_if_untracked_cache_is_supported(void)
fd = create_file("dir-mtime-test/newfile");
xstat("dir-mtime-test", &st);
if (!match_stat_data(&base, &st)) {
+ close(fd);
fputc('\n', stderr);
fprintf_ln(stderr,_("directory stat info does not "
"change after adding a new file"));
@@ -127,6 +128,7 @@ static int test_if_untracked_cache_is_supported(void)
xmkdir("dir-mtime-test/new-dir");
xstat("dir-mtime-test", &st);
if (!match_stat_data(&base, &st)) {
+ close(fd);
fputc('\n', stderr);
fprintf_ln(stderr, _("directory stat info does not change "
"after adding a new directory"));
@@ -1094,10 +1096,10 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
/* should be the same flags used by git-status */
uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
the_index.untracked = uc;
- the_index.cache_changed |= SOMETHING_CHANGED;
+ the_index.cache_changed |= UNTRACKED_CHANGED;
} else if (!untracked_cache && the_index.untracked) {
the_index.untracked = NULL;
- the_index.cache_changed |= SOMETHING_CHANGED;
+ the_index.cache_changed |= UNTRACKED_CHANGED;
}
if (active_cache_changed) {
diff --git a/cache.h b/cache.h
index 201b22e..fca979b 100644
--- a/cache.h
+++ b/cache.h
@@ -295,7 +295,7 @@ static inline unsigned int canon_mode(unsigned int mode)
#define RESOLVE_UNDO_CHANGED (1 << 4)
#define CACHE_TREE_CHANGED (1 << 5)
#define SPLIT_INDEX_ORDERED (1 << 6)
-#define UNTRACKED_CHANGED (1 << 7)
+#define UNTRACKED_CHANGED (1 << 7)
struct split_index;
struct untracked_cache;
diff --git a/compat/mingw.c b/compat/mingw.c
index c5c37e5..88140e4 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2128,3 +2128,14 @@ void mingw_startup()
/* initialize Unicode console */
winansi_init();
}
+
+int uname(struct utsname *buf)
+{
+ DWORD v = GetVersion();
+ memset(buf, 0, sizeof(*buf));
+ strcpy(buf->sysname, "Windows");
+ sprintf(buf->release, "%u.%u", v & 0xff, (v >> 8) & 0xff);
+ /* assuming NT variants only.. */
+ sprintf(buf->version, "%u", (v >> 16) & 0x7fff);
+ return 0;
+}
diff --git a/compat/mingw.h b/compat/mingw.h
index df0e320..d00ba7a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -77,6 +77,14 @@ struct itimerval {
};
#define ITIMER_REAL 0
+struct utsname {
+ char sysname[16];
+ char nodename[1];
+ char release[16];
+ char version[16];
+ char machine[1];
+};
+
/*
* sanitize preprocessor namespace polluted by Windows headers defining
* macros which collide with git local versions
@@ -166,6 +174,7 @@ struct passwd *getpwuid(uid_t uid);
int setitimer(int type, struct itimerval *in, struct itimerval *out);
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
int link(const char *oldpath, const char *newpath);
+int uname(struct utsname *buf);
/*
* replacements of existing functions
diff --git a/dir.c b/dir.c
index 0ae2188..ef58547 100644
--- a/dir.c
+++ b/dir.c
@@ -13,6 +13,7 @@
#include "wildmatch.h"
#include "pathspec.h"
#include "varint.h"
+#include "ewah/ewok.h"
struct path_simplify {
int len;
@@ -482,7 +483,7 @@ void add_exclude(const char *string, const char *base,
}
static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
- struct sha1_stat *ss)
+ struct sha1_stat *sha1_stat)
{
int pos, len;
unsigned long sz;
@@ -501,9 +502,9 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
return NULL;
}
*size = xsize_t(sz);
- if (ss) {
- memset(&ss->stat, 0, sizeof(ss->stat));
- hashcpy(ss->sha1, active_cache[pos]->sha1);
+ if (sha1_stat) {
+ memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
+ hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
}
return data;
}
@@ -584,9 +585,10 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,
}
uc->dir_created++;
- d = xmalloc(sizeof(*d) + len);
- memset(d, 0, sizeof(*d) + len);
+ d = xmalloc(sizeof(*d) + len + 1);
+ memset(d, 0, sizeof(*d));
memcpy(d->name, name, len);
+ d->name[len] = '\0';
ALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);
memmove(dir->dirs + first + 1, dir->dirs + first,
@@ -634,7 +636,7 @@ static void invalidate_directory(struct untracked_cache *uc,
*/
static int add_excludes(const char *fname, const char *base, int baselen,
struct exclude_list *el, int check_index,
- struct sha1_stat *ss, int ss_valid)
+ struct sha1_stat *sha1_stat)
{
struct stat st;
int fd, i, lineno = 1;
@@ -648,7 +650,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,
if (0 <= fd)
close(fd);
if (!check_index ||
- (buf = read_skip_worktree_file_from_index(fname, &size, ss)) == NULL)
+ (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL)
return -1;
if (size == 0) {
free(buf);
@@ -661,9 +663,10 @@ static int add_excludes(const char *fname, const char *base, int baselen,
} else {
size = xsize_t(st.st_size);
if (size == 0) {
- if (ss) {
- fill_stat_data(&ss->stat, &st);
- hashcpy(ss->sha1, EMPTY_BLOB_SHA1_BIN);
+ if (sha1_stat) {
+ fill_stat_data(&sha1_stat->stat, &st);
+ hashcpy(sha1_stat->sha1, EMPTY_BLOB_SHA1_BIN);
+ sha1_stat->valid = 1;
}
close(fd);
return 0;
@@ -676,19 +679,20 @@ static int add_excludes(const char *fname, const char *base, int baselen,
}
buf[size++] = '\n';
close(fd);
- if (ss) {
+ if (sha1_stat) {
int pos;
- if (ss_valid &&
- !match_stat_data_racy(&the_index, &ss->stat, &st))
+ if (sha1_stat->valid &&
+ !match_stat_data_racy(&the_index, &sha1_stat->stat, &st))
; /* no content change, ss->sha1 still good */
else if (check_index &&
(pos = cache_name_pos(fname, strlen(fname))) >= 0 &&
!ce_stage(active_cache[pos]) &&
ce_uptodate(active_cache[pos]))
- hashcpy(ss->sha1, active_cache[pos]->sha1);
+ hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
else
- hash_sha1_file(buf, size, "blob", ss->sha1);
- fill_stat_data(&ss->stat, &st);
+ hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
+ fill_stat_data(&sha1_stat->stat, &st);
+ sha1_stat->valid = 1;
}
}
@@ -712,7 +716,7 @@ int add_excludes_from_file_to_list(const char *fname, const char *base,
int baselen, struct exclude_list *el,
int check_index)
{
- return add_excludes(fname, base, baselen, el, check_index, NULL, 0);
+ return add_excludes(fname, base, baselen, el, check_index, NULL);
}
struct exclude_list *add_exclude_list(struct dir_struct *dir,
@@ -733,7 +737,7 @@ struct exclude_list *add_exclude_list(struct dir_struct *dir,
* Used to set up core.excludesfile and .git/info/exclude lists.
*/
static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
- struct sha1_stat *ss, int ss_valid)
+ struct sha1_stat *sha1_stat)
{
struct exclude_list *el;
/*
@@ -744,14 +748,14 @@ static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
if (!dir->untracked)
dir->unmanaged_exclude_files++;
el = add_exclude_list(dir, EXC_FILE, fname);
- if (add_excludes(fname, "", 0, el, 0, ss, ss_valid) < 0)
+ if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0)
die("cannot use %s as an exclude file", fname);
}
void add_excludes_from_file(struct dir_struct *dir, const char *fname)
{
dir->unmanaged_exclude_files++; /* see validate_untracked_cache() */
- add_excludes_from_file_1(dir, fname, NULL, 0);
+ add_excludes_from_file_1(dir, fname, NULL);
}
int match_basename(const char *basename, int basenamelen,
@@ -974,7 +978,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
while (current < baselen) {
struct exclude_stack *stk = xcalloc(1, sizeof(*stk));
const char *cp;
- struct sha1_stat ss;
+ struct sha1_stat sha1_stat;
if (current < 0) {
cp = base;
@@ -1015,7 +1019,8 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
}
/* Try to read per-directory file */
- hashclr(ss.sha1);
+ hashclr(sha1_stat.sha1);
+ sha1_stat.valid = 0;
if (dir->exclude_per_dir &&
/*
* If we know that no files have been added in
@@ -1044,7 +1049,7 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
strbuf_addstr(&sb, dir->exclude_per_dir);
el->src = strbuf_detach(&sb, NULL);
add_excludes(el->src, el->src, stk->baselen, el, 1,
- untracked ? &ss : NULL, 0);
+ untracked ? &sha1_stat : NULL);
}
/*
* NEEDSWORK: when untracked cache is enabled, prep_exclude()
@@ -1060,9 +1065,10 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
* last_exclude_matching(). Be careful about ignore rule
* order, though, if you do that.
*/
- if (untracked && hashcmp(ss.sha1, untracked->exclude_sha1)) {
+ if (untracked &&
+ hashcmp(sha1_stat.sha1, untracked->exclude_sha1)) {
invalidate_gitignore(dir->untracked, untracked);
- hashcpy(untracked->exclude_sha1, ss.sha1);
+ hashcpy(untracked->exclude_sha1, sha1_stat.sha1);
}
dir->exclude_stack = stk;
current = stk->baselen;
@@ -1457,12 +1463,11 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
int baselen,
const struct path_simplify *simplify)
{
+ strbuf_setlen(path, baselen);
if (!cdir->ucd) {
- strbuf_setlen(path, baselen);
strbuf_addstr(path, cdir->file);
return path_untracked;
}
- strbuf_setlen(path, baselen);
strbuf_addstr(path, cdir->ucd->name);
/* treat_one_path() does this before it calls treat_directory() */
if (path->buf[path->len - 1] != '/')
@@ -1474,7 +1479,6 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
* with check_only set.
*/
return read_directory_recursive(dir, path->buf, path->len,
-
cdir->ucd, 1, simplify);
/*
* We get path_recurse in the first run when
@@ -1582,7 +1586,7 @@ static int open_cached_dir(struct cached_dir *cdir,
return 0;
}
-int read_cached_dir(struct cached_dir *cdir)
+static int read_cached_dir(struct cached_dir *cdir)
{
if (cdir->fdir) {
cdir->de = readdir(cdir->fdir);
@@ -1796,7 +1800,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
struct untracked_cache_dir *root;
int i;
- if (!dir->untracked)
+ if (!dir->untracked || getenv("GIT_DISABLE_UNTRACKED_CACHE"))
return NULL;
/*
@@ -2101,30 +2105,12 @@ void setup_standard_excludes(struct dir_struct *dir)
home_config_paths(NULL, &xdg_path, "ignore");
excludes_file = xdg_path;
}
- if (!access_or_warn(path, R_OK, 0)) {
- struct sha1_stat *ss = NULL;
- int ss_valid = 0;
- if (dir->untracked) {
- ss = &dir->ss_info_exclude;
- 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;
- int ss_valid = 0;
- if (dir->untracked) {
- ss = &dir->ss_excludes_file;
- if (dir->untracked->loaded) {
- *ss = dir->untracked->ss_excludes_file;
- ss_valid = 1;
- }
- }
- add_excludes_from_file_1(dir, excludes_file, ss, ss_valid);
- }
+ if (!access_or_warn(path, R_OK, 0))
+ add_excludes_from_file_1(dir, path,
+ dir->untracked ? &dir->ss_info_exclude : NULL);
+ if (excludes_file && !access_or_warn(excludes_file, R_OK, 0))
+ add_excludes_from_file_1(dir, excludes_file,
+ dir->untracked ? &dir->ss_excludes_file : NULL);
}
int remove_path(const char *name)
@@ -2186,6 +2172,16 @@ struct ondisk_untracked_cache {
char exclude_per_dir[1];
};
+struct write_data {
+ int index; /* number of written untracked_cache_dir */
+ struct ewah_bitmap *check_only; /* from untracked_cache_dir */
+ struct ewah_bitmap *valid; /* from untracked_cache_dir */
+ struct ewah_bitmap *sha1_valid; /* set if exclude_sha1 is not null */
+ struct strbuf out;
+ struct strbuf sb_stat;
+ struct strbuf sb_sha1;
+};
+
static void stat_data_to_disk(struct stat_data *to, const struct stat_data *from)
{
to->sd_ctime.sec = htonl(from->sd_ctime.sec);
@@ -2199,16 +2195,14 @@ static void stat_data_to_disk(struct stat_data *to, const struct stat_data *from
to->sd_size = htonl(from->sd_size);
}
-static void write_one_dir(struct strbuf *out, struct untracked_cache_dir *untracked)
+static void write_one_dir(struct untracked_cache_dir *untracked,
+ struct write_data *wd)
{
struct stat_data stat_data;
+ struct strbuf *out = &wd->out;
unsigned char intbuf[16];
unsigned int intlen, value;
- int i;
-
- stat_data_to_disk(&stat_data, &untracked->stat_data);
- strbuf_add(out, &stat_data, sizeof(stat_data));
- strbuf_add(out, untracked->exclude_sha1, 20);
+ int i = wd->index++;
/*
* untracked_nr should be reset whenever valid is clear, but
@@ -2219,10 +2213,19 @@ static void write_one_dir(struct strbuf *out, struct untracked_cache_dir *untrac
untracked->check_only = 0;
}
- value = untracked->valid;
- value |= untracked->check_only << 1;
- value |= untracked->untracked_nr << 2;
- intlen = encode_varint(value, intbuf);
+ if (untracked->check_only)
+ ewah_set(wd->check_only, i);
+ if (untracked->valid) {
+ ewah_set(wd->valid, i);
+ stat_data_to_disk(&stat_data, &untracked->stat_data);
+ strbuf_add(&wd->sb_stat, &stat_data, sizeof(stat_data));
+ }
+ if (!is_null_sha1(untracked->exclude_sha1)) {
+ ewah_set(wd->sha1_valid, i);
+ strbuf_add(&wd->sb_sha1, untracked->exclude_sha1, 20);
+ }
+
+ intlen = encode_varint(untracked->untracked_nr, intbuf);
strbuf_add(out, intbuf, intlen);
/* skip non-recurse directories */
@@ -2240,13 +2243,26 @@ static void write_one_dir(struct strbuf *out, struct untracked_cache_dir *untrac
for (i = 0; i < untracked->dirs_nr; i++)
if (untracked->dirs[i]->recurse)
- write_one_dir(out, untracked->dirs[i]);
+ write_one_dir(untracked->dirs[i], wd);
+}
+
+static void get_ident_string(struct strbuf *sb)
+{
+ struct utsname uts;
+
+ if (uname(&uts))
+ die_errno(_("failed to get kernel name and information"));
+ strbuf_addf(sb, "Location %s, system %s %s %s", get_git_work_tree(),
+ uts.sysname, uts.release, uts.version);
}
void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked)
{
struct ondisk_untracked_cache *ouc;
- int len = 0;
+ struct write_data wd;
+ struct strbuf sb = STRBUF_INIT;
+ unsigned char varbuf[16];
+ int len = 0, varint_len;
if (untracked->exclude_per_dir)
len = strlen(untracked->exclude_per_dir);
ouc = xmalloc(sizeof(*ouc) + len);
@@ -2256,9 +2272,43 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
ouc->dir_flags = htonl(untracked->dir_flags);
memcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);
+
+ get_ident_string(&sb);
+ strbuf_add(out, sb.buf, sb.len + 1);
+ strbuf_release(&sb);
+
strbuf_add(out, ouc, sizeof(*ouc) + len);
- if (untracked->root)
- write_one_dir(out, untracked->root);
+ if (!untracked->root) {
+ varint_len = encode_varint(0, varbuf);
+ strbuf_add(out, varbuf, varint_len);
+ return;
+ }
+
+ wd.index = 0;
+ wd.check_only = ewah_new();
+ wd.valid = ewah_new();
+ wd.sha1_valid = ewah_new();
+ strbuf_init(&wd.out, 1024);
+ strbuf_init(&wd.sb_stat, 1024);
+ strbuf_init(&wd.sb_sha1, 1024);
+ write_one_dir(untracked->root, &wd);
+
+ varint_len = encode_varint(wd.index, varbuf);
+ strbuf_add(out, varbuf, varint_len);
+ strbuf_addbuf(out, &wd.out);
+ ewah_serialize_strbuf(wd.valid, out);
+ ewah_serialize_strbuf(wd.check_only, out);
+ ewah_serialize_strbuf(wd.sha1_valid, out);
+ strbuf_addbuf(out, &wd.sb_stat);
+ strbuf_addbuf(out, &wd.sb_sha1);
+ strbuf_addch(out, '\0'); /* safe guard for string lists */
+
+ ewah_free(wd.valid);
+ ewah_free(wd.check_only);
+ ewah_free(wd.sha1_valid);
+ strbuf_release(&wd.out);
+ strbuf_release(&wd.sb_stat);
+ strbuf_release(&wd.sb_sha1);
}
static void free_untracked(struct untracked_cache_dir *ucd)
@@ -2282,6 +2332,16 @@ void free_untracked_cache(struct untracked_cache *uc)
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);
@@ -2296,43 +2356,34 @@ static void stat_data_from_disk(struct stat_data *to, const struct stat_data *fr
}
static int read_one_dir(struct untracked_cache_dir **untracked_,
- const unsigned char *data_, unsigned long sz)
+ struct read_data *rd)
{
#define NEXT(x) \
next = data + (x); \
- if (next > data_ + sz) \
+ if (next > rd->end) \
return -1;
struct untracked_cache_dir ud, *untracked;
- const unsigned char *next, *data = data_;
+ const unsigned char *next, *data = rd->data, *end = rd->end;
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)
+ if (next > end)
return -1;
- ud.recurse = 1;
- ud.valid = value & 1;
- ud.check_only = (value >> 1) & 1;
- ud.untracked_alloc = ud.untracked_nr = value >> 2;
+ 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 > data_ + sz)
+ if (next > end)
return -1;
ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);
data = next;
@@ -2351,41 +2402,145 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,
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, data, sz - (data - data_));
+ len = read_one_dir(untracked->dirs + i, rd);
if (len < 0)
return -1;
- data += len;
}
- return data - data_;
+ 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 = data;
+ const struct ondisk_untracked_cache *ouc;
struct untracked_cache *uc;
+ struct read_data rd;
+ const unsigned char *next = data, *end = data + sz;
+ struct strbuf sb = STRBUF_INIT;
int len;
- if (sz < sizeof(*ouc))
+ if (sz <= 1 || end[-1] != '\0')
+ return NULL;
+ end--;
+
+ get_ident_string(&sb);
+ if (strcmp(sb.buf, (const char *)next)) {
+ warning(_("system identification does not match, untracked cache disabled.\n"
+ "Stored: %s\nCurrent: %s\n"),
+ next, sb.buf);
+ strbuf_release(&sb);
+ return NULL;
+ }
+ next += sb.len + 1;
+ strbuf_release(&sb);
+
+ ouc = (const struct ondisk_untracked_cache *)next;
+ if (next + sizeof(*ouc) > end)
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);
+ 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);
- 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;
+ /* NUL after exclude_per_dir is covered by sizeof(*ouc) */
+ next += sizeof(*ouc) + 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;
}
void untracked_cache_invalidate_path(struct index_state *istate,
diff --git a/dir.h b/dir.h
index 8c29324..2ce7dd3 100644
--- a/dir.h
+++ b/dir.h
@@ -77,6 +77,7 @@ struct exclude_list_group {
struct sha1_stat {
struct stat_data stat;
unsigned char sha1[20];
+ int valid;
};
/*
@@ -85,7 +86,7 @@ struct sha1_stat {
* The following inputs are sufficient to determine what files in a
* directory are excluded:
*
- * - The list of files and directories of the direction in question
+ * - The list of files and directories of the directory in question
* - The $GIT_DIR/index
* - dir_struct flags
* - The content of $GIT_DIR/info/exclude
@@ -110,16 +111,16 @@ struct sha1_stat {
struct untracked_cache_dir {
struct untracked_cache_dir **dirs;
char **untracked;
- /* null SHA-1 means this directory does not have .gitignore */
- unsigned char exclude_sha1[20];
struct stat_data stat_data;
- unsigned int recurse : 1;
+ unsigned int untracked_alloc, dirs_nr, dirs_alloc;
+ unsigned int untracked_nr;
unsigned int check_only : 1;
/* all data except 'dirs' in this struct are good */
unsigned int valid : 1;
- unsigned int untracked_nr : 29;
- unsigned int untracked_alloc, dirs_nr, dirs_alloc;
- char name[1];
+ unsigned int recurse : 1;
+ /* null SHA-1 means this directory does not have .gitignore */
+ unsigned char exclude_sha1[20];
+ char name[FLEX_ARRAY];
};
struct untracked_cache {
@@ -137,7 +138,6 @@ struct untracked_cache {
int gitignore_invalidated;
int dir_invalidated;
int dir_opened;
- int loaded;
};
struct dir_struct {
diff --git a/ewah/ewah_io.c b/ewah/ewah_io.c
index 1c2d7af..43481b9 100644
--- a/ewah/ewah_io.c
+++ b/ewah/ewah_io.c
@@ -19,6 +19,7 @@
*/
#include "git-compat-util.h"
#include "ewok.h"
+#include "strbuf.h"
int ewah_serialize_native(struct ewah_bitmap *self, int fd)
{
@@ -110,6 +111,18 @@ int ewah_serialize(struct ewah_bitmap *self, int fd)
return ewah_serialize_to(self, write_helper, (void *)(intptr_t)fd);
}
+static int write_strbuf(void *user_data, const void *data, size_t len)
+{
+ struct strbuf *sb = user_data;
+ strbuf_add(sb, data, len);
+ return len;
+}
+
+int ewah_serialize_strbuf(struct ewah_bitmap *self, struct strbuf *sb)
+{
+ return ewah_serialize_to(self, write_strbuf, sb);
+}
+
int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len)
{
const uint8_t *ptr = map;
diff --git a/ewah/ewok.h b/ewah/ewok.h
index f6ad190..4d7f5e9 100644
--- a/ewah/ewok.h
+++ b/ewah/ewok.h
@@ -30,6 +30,7 @@
# define ewah_calloc xcalloc
#endif
+struct strbuf;
typedef uint64_t eword_t;
#define BITS_IN_WORD (sizeof(eword_t) * 8)
@@ -97,6 +98,7 @@ int ewah_serialize_to(struct ewah_bitmap *self,
void *out);
int ewah_serialize(struct ewah_bitmap *self, int fd);
int ewah_serialize_native(struct ewah_bitmap *self, int fd);
+int ewah_serialize_strbuf(struct ewah_bitmap *self, struct strbuf *);
int ewah_deserialize(struct ewah_bitmap *self, int fd);
int ewah_read_mmap(struct ewah_bitmap *self, const void *map, size_t len);
diff --git a/git-compat-util.h b/git-compat-util.h
index f587749..e9502a1 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -132,6 +132,7 @@
#elif defined(_MSC_VER)
#include "compat/msvc.h"
#else
+#include <sys/utsname.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/socket.h>
diff --git a/read-cache.c b/read-cache.c
index 21ae963..71d8e20 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -2040,7 +2040,7 @@ static int do_write_index(struct index_state *istate, int newfd,
if (err)
return -1;
}
- if (istate->untracked) {
+ if (!strip_extensions && istate->untracked) {
struct strbuf sb = STRBUF_INIT;
write_untracked_extension(&sb, istate->untracked);
diff --git a/split-index.c b/split-index.c
index 21485e2..968b780 100644
--- a/split-index.c
+++ b/split-index.c
@@ -41,13 +41,6 @@ int read_link_extension(struct index_state *istate,
return 0;
}
-static int write_strbuf(void *user_data, const void *data, size_t len)
-{
- struct strbuf *sb = user_data;
- strbuf_add(sb, data, len);
- return len;
-}
-
int write_link_extension(struct strbuf *sb,
struct index_state *istate)
{
@@ -55,8 +48,8 @@ int write_link_extension(struct strbuf *sb,
strbuf_add(sb, si->base_sha1, 20);
if (!si->delete_bitmap && !si->replace_bitmap)
return 0;
- ewah_serialize_to(si->delete_bitmap, write_strbuf, sb);
- ewah_serialize_to(si->replace_bitmap, write_strbuf, sb);
+ ewah_serialize_strbuf(si->delete_bitmap, sb);
+ ewah_serialize_strbuf(si->replace_bitmap, sb);
return 0;
}
diff --git a/test-dump-untracked-cache.c b/test-dump-untracked-cache.c
index 710441e..25d855d 100644
--- a/test-dump-untracked-cache.c
+++ b/test-dump-untracked-cache.c
@@ -44,6 +44,7 @@ int main(int ac, char **av)
{
struct untracked_cache *uc;
struct strbuf base = STRBUF_INIT;
+ setup_git_directory();
if (read_cache() < 0)
die("unable to read index file");
uc = the_index.untracked;
-- 8< --
--
2.2.0.60.gb7b3c64
next reply other threads:[~2014-12-08 13:54 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-08 14:04 Nguyễn Thái Ngọc Duy [this message]
2014-12-08 14:04 ` [PATCH] checkout: add --ignore-other-wortrees Nguyễn Thái Ngọc Duy
2014-12-08 13:58 ` Duy Nguyen
2014-12-08 14:04 ` [PATCH v3 01/23] dir.c: optionally compute sha-1 of a .gitignore file Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 02/23] untracked cache: record .gitignore information and dir hierarchy Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 03/23] untracked cache: initial untracked cache validation Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 04/23] untracked cache: invalidate dirs recursively if .gitignore changes Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 05/23] untracked cache: make a wrapper around {open,read,close}dir() Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 06/23] untracked cache: record/validate dir mtime and reuse cached output Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 07/23] untracked cache: mark what dirs should be recursed/saved Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 08/23] untracked cache: don't open non-existent .gitignore Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 09/23] ewah: add convenient wrapper ewah_serialize_strbuf() Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 10/23] untracked cache: save to an index extension Nguyễn Thái Ngọc Duy
2014-12-09 23:28 ` Eric Sunshine
2014-12-10 0:21 ` Duy Nguyen
2014-12-08 14:04 ` [PATCH v3 11/23] untracked cache: load from UNTR " Nguyễn Thái Ngọc Duy
2014-12-15 19:35 ` Junio C Hamano
2014-12-08 14:04 ` [PATCH v3 12/23] untracked cache: invalidate at index addition or removal Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 13/23] read-cache.c: split racy stat test to a separate function Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 14/23] untracked cache: avoid racy timestamps Nguyễn Thái Ngọc Duy
2014-12-08 14:04 ` [PATCH v3 15/23] untracked cache: print stats with $GIT_TRACE_UNTRACKED_STATS Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 16/23] untracked cache: mark index dirty if untracked cache is updated Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 17/23] untracked-cache: temporarily disable with $GIT_DISABLE_UNTRACKED_CACHE Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 18/23] status: enable untracked cache Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 19/23] update-index: manually enable or disable " Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 20/23] update-index: test the system before enabling " Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 21/23] t7063: tests for " Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 22/23] mingw32: add uname() Nguyễn Thái Ngọc Duy
2014-12-08 14:05 ` [PATCH v3 23/23] untracked cache: guard and disable on system changes Nguyễn Thái Ngọc Duy
2014-12-09 10:04 ` brian m. carlson
2014-12-09 22:53 ` Duy Nguyen
2014-12-10 5:08 ` Torsten Bögershausen
2014-12-10 12:22 ` Duy Nguyen
2014-12-11 20:41 ` Torsten Bögershausen
2014-12-15 3:02 ` Duy Nguyen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1418047507-22892-1-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.