Skip to content

Commit 1e8fef6

Browse files
pcloudsgitster
authored andcommitted
untracked cache: guard and disable on system changes
If the user enables untracked cache, then - move worktree to an unsupported filesystem - or simply upgrade OS - or move the whole (portable) disk from one machine to another - or access a shared fs from another machine there's no guarantee that untracked cache can still function properly. Record the worktree location and OS footprint in the cache. If it changes, err on the safe side and disable the cache. The user can 'update-index --untracked-cache' again to make sure all conditions are met. This adds a new requirement that setup_git_directory* must be called before read_cache() because we need worktree location by then, or the cache is dropped. This change does not cover all bases, you can fool it if you try hard. The point is to stop accidents. Helped-by: Eric Sunshine <[email protected]> Helped-by: brian m. carlson <[email protected]> Helped-by: Torsten Bögershausen <[email protected]> Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7b6aff0 commit 1e8fef6

File tree

6 files changed

+72
-7
lines changed

6 files changed

+72
-7
lines changed

Documentation/technical/index-format.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ Git index format
242242

243243
The extension starts with
244244

245+
- A sequence of NUL-terminated strings, preceded by the size of the
246+
sequence in variable width encoding. Each string describes the
247+
environment where the cache can be used.
248+
245249
- Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
246250
ctime field until "file size".
247251

builtin/update-index.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,19 +1104,23 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
11041104
the_index.split_index = NULL;
11051105
the_index.cache_changed |= SOMETHING_CHANGED;
11061106
}
1107-
if (untracked_cache > 0 && !the_index.untracked) {
1107+
if (untracked_cache > 0) {
11081108
struct untracked_cache *uc;
11091109

11101110
if (untracked_cache < 2) {
11111111
setup_work_tree();
11121112
if (!test_if_untracked_cache_is_supported())
11131113
return 1;
11141114
}
1115-
uc = xcalloc(1, sizeof(*uc));
1116-
uc->exclude_per_dir = ".gitignore";
1117-
/* should be the same flags used by git-status */
1118-
uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
1119-
the_index.untracked = uc;
1115+
if (!the_index.untracked) {
1116+
uc = xcalloc(1, sizeof(*uc));
1117+
strbuf_init(&uc->ident, 100);
1118+
uc->exclude_per_dir = ".gitignore";
1119+
/* should be the same flags used by git-status */
1120+
uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
1121+
the_index.untracked = uc;
1122+
}
1123+
add_untracked_ident(the_index.untracked);
11201124
the_index.cache_changed |= UNTRACKED_CHANGED;
11211125
} else if (!untracked_cache && the_index.untracked) {
11221126
the_index.untracked = NULL;

dir.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,40 @@ static int treat_leading_path(struct dir_struct *dir,
17941794
return rc;
17951795
}
17961796

1797+
static const char *get_ident_string(void)
1798+
{
1799+
static struct strbuf sb = STRBUF_INIT;
1800+
struct utsname uts;
1801+
1802+
if (sb.len)
1803+
return sb.buf;
1804+
if (uname(&uts))
1805+
die_errno(_("failed to get kernel name and information"));
1806+
strbuf_addf(&sb, "Location %s, system %s %s %s", get_git_work_tree(),
1807+
uts.sysname, uts.release, uts.version);
1808+
return sb.buf;
1809+
}
1810+
1811+
static int ident_in_untracked(const struct untracked_cache *uc)
1812+
{
1813+
const char *end = uc->ident.buf + uc->ident.len;
1814+
const char *p = uc->ident.buf;
1815+
1816+
for (p = uc->ident.buf; p < end; p += strlen(p) + 1)
1817+
if (!strcmp(p, get_ident_string()))
1818+
return 1;
1819+
return 0;
1820+
}
1821+
1822+
void add_untracked_ident(struct untracked_cache *uc)
1823+
{
1824+
if (ident_in_untracked(uc))
1825+
return;
1826+
strbuf_addstr(&uc->ident, get_ident_string());
1827+
/* this strbuf contains a list of strings, save NUL too */
1828+
strbuf_addch(&uc->ident, 0);
1829+
}
1830+
17971831
static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir,
17981832
int base_len,
17991833
const struct pathspec *pathspec)
@@ -1860,6 +1894,11 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
18601894
if (ce_skip_worktree(active_cache[i]))
18611895
return NULL;
18621896

1897+
if (!ident_in_untracked(dir->untracked)) {
1898+
warning(_("Untracked cache is disabled on this system."));
1899+
return NULL;
1900+
}
1901+
18631902
if (!dir->untracked->root) {
18641903
const int len = sizeof(*dir->untracked->root);
18651904
dir->untracked->root = xmalloc(len);
@@ -2268,6 +2307,11 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
22682307
hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
22692308
ouc->dir_flags = htonl(untracked->dir_flags);
22702309
memcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);
2310+
2311+
varint_len = encode_varint(untracked->ident.len, varbuf);
2312+
strbuf_add(out, varbuf, varint_len);
2313+
strbuf_add(out, untracked->ident.buf, untracked->ident.len);
2314+
22712315
strbuf_add(out, ouc, ouc_size(len));
22722316
free(ouc);
22732317
ouc = NULL;
@@ -2453,17 +2497,26 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
24532497
struct untracked_cache *uc;
24542498
struct read_data rd;
24552499
const unsigned char *next = data, *end = (const unsigned char *)data + sz;
2456-
int len;
2500+
const char *ident;
2501+
int ident_len, len;
24572502

24582503
if (sz <= 1 || end[-1] != '\0')
24592504
return NULL;
24602505
end--;
24612506

2507+
ident_len = decode_varint(&next);
2508+
if (next + ident_len > end)
2509+
return NULL;
2510+
ident = (const char *)next;
2511+
next += ident_len;
2512+
24622513
ouc = (const struct ondisk_untracked_cache *)next;
24632514
if (next + ouc_size(0) > end)
24642515
return NULL;
24652516

24662517
uc = xcalloc(1, sizeof(*uc));
2518+
strbuf_init(&uc->ident, ident_len);
2519+
strbuf_add(&uc->ident, ident, ident_len);
24672520
load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat,
24682521
ouc->info_exclude_sha1);
24692522
load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat,

dir.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ struct untracked_cache {
127127
struct sha1_stat ss_info_exclude;
128128
struct sha1_stat ss_excludes_file;
129129
const char *exclude_per_dir;
130+
struct strbuf ident;
130131
/*
131132
* dir_struct#flags must match dir_flags or the untracked
132133
* cache is ignored.
@@ -305,4 +306,5 @@ void untracked_cache_add_to_index(struct index_state *, const char *);
305306
void free_untracked_cache(struct untracked_cache *);
306307
struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz);
307308
void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);
309+
void add_untracked_ident(struct untracked_cache *);
308310
#endif

git-compat-util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
#elif defined(_MSC_VER)
135135
#include "compat/msvc.h"
136136
#else
137+
#include <sys/utsname.h>
137138
#include <sys/wait.h>
138139
#include <sys/resource.h>
139140
#include <sys/socket.h>

test-dump-untracked-cache.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ int main(int ac, char **av)
4444
{
4545
struct untracked_cache *uc;
4646
struct strbuf base = STRBUF_INIT;
47+
setup_git_directory();
4748
if (read_cache() < 0)
4849
die("unable to read index file");
4950
uc = the_index.untracked;

0 commit comments

Comments
 (0)