Skip to content

Commit f64cb88

Browse files
pcloudsgitster
authored andcommitted
update-index: test the system before enabling untracked cache
Helped-by: Eric Sunshine <[email protected]> Helped-by: Junio C Hamano <[email protected]> Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9e59724 commit f64cb88

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

Documentation/git-update-index.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ may not support it yet.
178178
system must change `st_mtime` field of a directory if files
179179
are added or deleted in that directory.
180180

181+
--force-untracked-cache::
182+
For safety, `--untracked-cache` performs tests on the working
183+
directory to make sure untracked cache can be used. These
184+
tests can take a few seconds. `--force-untracked-cache` can be
185+
used to skip the tests.
186+
181187
\--::
182188
Do not interpret any more arguments as options.
183189

builtin/update-index.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ static int mark_valid_only;
3333
static int mark_skip_worktree_only;
3434
#define MARK_FLAG 1
3535
#define UNMARK_FLAG 2
36+
static struct strbuf mtime_dir = STRBUF_INIT;
3637

3738
__attribute__((format (printf, 1, 2)))
3839
static void report(const char *fmt, ...)
@@ -48,6 +49,166 @@ static void report(const char *fmt, ...)
4849
va_end(vp);
4950
}
5051

52+
static void remove_test_directory(void)
53+
{
54+
if (mtime_dir.len)
55+
remove_dir_recursively(&mtime_dir, 0);
56+
}
57+
58+
static const char *get_mtime_path(const char *path)
59+
{
60+
static struct strbuf sb = STRBUF_INIT;
61+
strbuf_reset(&sb);
62+
strbuf_addf(&sb, "%s/%s", mtime_dir.buf, path);
63+
return sb.buf;
64+
}
65+
66+
static void xmkdir(const char *path)
67+
{
68+
path = get_mtime_path(path);
69+
if (mkdir(path, 0700))
70+
die_errno(_("failed to create directory %s"), path);
71+
}
72+
73+
static int xstat_mtime_dir(struct stat *st)
74+
{
75+
if (stat(mtime_dir.buf, st))
76+
die_errno(_("failed to stat %s"), mtime_dir.buf);
77+
return 0;
78+
}
79+
80+
static int create_file(const char *path)
81+
{
82+
int fd;
83+
path = get_mtime_path(path);
84+
fd = open(path, O_CREAT | O_RDWR, 0644);
85+
if (fd < 0)
86+
die_errno(_("failed to create file %s"), path);
87+
return fd;
88+
}
89+
90+
static void xunlink(const char *path)
91+
{
92+
path = get_mtime_path(path);
93+
if (unlink(path))
94+
die_errno(_("failed to delete file %s"), path);
95+
}
96+
97+
static void xrmdir(const char *path)
98+
{
99+
path = get_mtime_path(path);
100+
if (rmdir(path))
101+
die_errno(_("failed to delete directory %s"), path);
102+
}
103+
104+
static void avoid_racy(void)
105+
{
106+
/*
107+
* not use if we could usleep(10) if USE_NSEC is defined. The
108+
* field nsec could be there, but the OS could choose to
109+
* ignore it?
110+
*/
111+
sleep(1);
112+
}
113+
114+
static int test_if_untracked_cache_is_supported(void)
115+
{
116+
struct stat st;
117+
struct stat_data base;
118+
int fd, ret = 0;
119+
120+
strbuf_addstr(&mtime_dir, "mtime-test-XXXXXX");
121+
if (!mkdtemp(mtime_dir.buf))
122+
die_errno("Could not make temporary directory");
123+
124+
fprintf(stderr, _("Testing "));
125+
atexit(remove_test_directory);
126+
xstat_mtime_dir(&st);
127+
fill_stat_data(&base, &st);
128+
fputc('.', stderr);
129+
130+
avoid_racy();
131+
fd = create_file("newfile");
132+
xstat_mtime_dir(&st);
133+
if (!match_stat_data(&base, &st)) {
134+
close(fd);
135+
fputc('\n', stderr);
136+
fprintf_ln(stderr,_("directory stat info does not "
137+
"change after adding a new file"));
138+
goto done;
139+
}
140+
fill_stat_data(&base, &st);
141+
fputc('.', stderr);
142+
143+
avoid_racy();
144+
xmkdir("new-dir");
145+
xstat_mtime_dir(&st);
146+
if (!match_stat_data(&base, &st)) {
147+
close(fd);
148+
fputc('\n', stderr);
149+
fprintf_ln(stderr, _("directory stat info does not change "
150+
"after adding a new directory"));
151+
goto done;
152+
}
153+
fill_stat_data(&base, &st);
154+
fputc('.', stderr);
155+
156+
avoid_racy();
157+
write_or_die(fd, "data", 4);
158+
close(fd);
159+
xstat_mtime_dir(&st);
160+
if (match_stat_data(&base, &st)) {
161+
fputc('\n', stderr);
162+
fprintf_ln(stderr, _("directory stat info changes "
163+
"after updating a file"));
164+
goto done;
165+
}
166+
fputc('.', stderr);
167+
168+
avoid_racy();
169+
close(create_file("new-dir/new"));
170+
xstat_mtime_dir(&st);
171+
if (match_stat_data(&base, &st)) {
172+
fputc('\n', stderr);
173+
fprintf_ln(stderr, _("directory stat info changes after "
174+
"adding a file inside subdirectory"));
175+
goto done;
176+
}
177+
fputc('.', stderr);
178+
179+
avoid_racy();
180+
xunlink("newfile");
181+
xstat_mtime_dir(&st);
182+
if (!match_stat_data(&base, &st)) {
183+
fputc('\n', stderr);
184+
fprintf_ln(stderr, _("directory stat info does not "
185+
"change after deleting a file"));
186+
goto done;
187+
}
188+
fill_stat_data(&base, &st);
189+
fputc('.', stderr);
190+
191+
avoid_racy();
192+
xunlink("new-dir/new");
193+
xrmdir("new-dir");
194+
xstat_mtime_dir(&st);
195+
if (!match_stat_data(&base, &st)) {
196+
fputc('\n', stderr);
197+
fprintf_ln(stderr, _("directory stat info does not "
198+
"change after deleting a directory"));
199+
goto done;
200+
}
201+
202+
if (rmdir(mtime_dir.buf))
203+
die_errno(_("failed to delete directory %s"), mtime_dir.buf);
204+
fprintf_ln(stderr, _(" OK"));
205+
ret = 1;
206+
207+
done:
208+
strbuf_release(&mtime_dir);
209+
return ret;
210+
}
211+
51212
static int mark_ce_flags(const char *path, int flag, int mark)
52213
{
53214
int namelen = strlen(path);
@@ -835,6 +996,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
835996
N_("enable or disable split index")),
836997
OPT_BOOL(0, "untracked-cache", &untracked_cache,
837998
N_("enable/disable untracked cache")),
999+
OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
1000+
N_("enable untracked cache without testing the filesystem"), 2),
8381001
OPT_END()
8391002
};
8401003

@@ -944,6 +1107,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
9441107
if (untracked_cache > 0 && !the_index.untracked) {
9451108
struct untracked_cache *uc;
9461109

1110+
if (untracked_cache < 2) {
1111+
setup_work_tree();
1112+
if (!test_if_untracked_cache_is_supported())
1113+
return 1;
1114+
}
9471115
uc = xcalloc(1, sizeof(*uc));
9481116
uc->exclude_per_dir = ".gitignore";
9491117
/* should be the same flags used by git-status */

0 commit comments

Comments
 (0)