Skip to content

Commit 3e14384

Browse files
committed
Merge branch 'jk/shallow-update-fix'
Serving objects from a shallow repository needs to write a new file to hold the temporary shallow boundaries but it was not cleaned when we exit due to die() or a signal. * jk/shallow-update-fix: shallow: verify shallow file after taking lock shallow: automatically clean up shallow tempfiles shallow: use stat_validity to check for up-to-date file
2 parents 4291cc1 + 7839632 commit 3e14384

File tree

5 files changed

+49
-56
lines changed

5 files changed

+49
-56
lines changed

builtin/receive-pack.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -828,14 +828,10 @@ static void execute_commands(struct command *commands,
828828
}
829829
}
830830

831-
if (shallow_update) {
832-
if (!checked_connectivity)
833-
error("BUG: run 'git fsck' for safety.\n"
834-
"If there are errors, try to remove "
835-
"the reported refs above");
836-
if (alt_shallow_file && *alt_shallow_file)
837-
unlink(alt_shallow_file);
838-
}
831+
if (shallow_update && !checked_connectivity)
832+
error("BUG: run 'git fsck' for safety.\n"
833+
"If there are errors, try to remove "
834+
"the reported refs above");
839835
}
840836

841837
static struct command *read_head_info(struct sha1_array *shallow)
@@ -1087,10 +1083,6 @@ static void update_shallow_info(struct command *commands,
10871083
cmd->skip_update = 1;
10881084
}
10891085
}
1090-
if (alt_shallow_file && *alt_shallow_file) {
1091-
unlink(alt_shallow_file);
1092-
alt_shallow_file = NULL;
1093-
}
10941086
free(ref_status);
10951087
}
10961088

commit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
209209
extern void setup_alternate_shallow(struct lock_file *shallow_lock,
210210
const char **alternate_shallow_file,
211211
const struct sha1_array *extra);
212-
extern char *setup_temporary_shallow(const struct sha1_array *extra);
212+
extern const char *setup_temporary_shallow(const struct sha1_array *extra);
213213
extern void advertise_shallow_grafts(int);
214214

215215
struct shallow_info {

fetch-pack.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -948,17 +948,6 @@ static void update_shallow(struct fetch_pack_args *args,
948948
if (!si->shallow || !si->shallow->nr)
949949
return;
950950

951-
if (alternate_shallow_file) {
952-
/*
953-
* The temporary shallow file is only useful for
954-
* index-pack and unpack-objects because it may
955-
* contain more roots than we want. Delete it.
956-
*/
957-
if (*alternate_shallow_file)
958-
unlink(alternate_shallow_file);
959-
free((char *)alternate_shallow_file);
960-
}
961-
962951
if (args->cloning) {
963952
/*
964953
* remote is shallow, but this is a clone, there are

shallow.c

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
#include "diff.h"
99
#include "revision.h"
1010
#include "commit-slab.h"
11+
#include "sigchain.h"
1112

1213
static int is_shallow = -1;
13-
static struct stat shallow_stat;
14+
static struct stat_validity shallow_stat;
1415
static char *alternate_shallow_file;
1516

1617
void set_alternate_shallow_file(const char *path, int override)
@@ -52,12 +53,12 @@ int is_repository_shallow(void)
5253
* shallow file should be used. We could just open it and it
5354
* will likely fail. But let's do an explicit check instead.
5455
*/
55-
if (!*path ||
56-
stat(path, &shallow_stat) ||
57-
(fp = fopen(path, "r")) == NULL) {
56+
if (!*path || (fp = fopen(path, "r")) == NULL) {
57+
stat_validity_clear(&shallow_stat);
5858
is_shallow = 0;
5959
return is_shallow;
6060
}
61+
stat_validity_update(&shallow_stat, fileno(fp));
6162
is_shallow = 1;
6263

6364
while (fgets(buf, sizeof(buf), fp)) {
@@ -137,21 +138,11 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
137138

138139
void check_shallow_file_for_update(void)
139140
{
140-
struct stat st;
141-
142-
if (!is_shallow)
143-
return;
144-
else if (is_shallow == -1)
141+
if (is_shallow == -1)
145142
die("BUG: shallow must be initialized by now");
146143

147-
if (stat(git_path("shallow"), &st))
148-
die("shallow file was removed during fetch");
149-
else if (st.st_mtime != shallow_stat.st_mtime
150-
#ifdef USE_NSEC
151-
|| ST_MTIME_NSEC(st) != ST_MTIME_NSEC(shallow_stat)
152-
#endif
153-
)
154-
die("shallow file was changed during fetch");
144+
if (!stat_validity_check(&shallow_stat, git_path("shallow")))
145+
die("shallow file has changed since we read it");
155146
}
156147

157148
#define SEEN_ONLY 1
@@ -216,27 +207,53 @@ int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
216207
return write_shallow_commits_1(out, use_pack_protocol, extra, 0);
217208
}
218209

219-
char *setup_temporary_shallow(const struct sha1_array *extra)
210+
static struct strbuf temporary_shallow = STRBUF_INIT;
211+
212+
static void remove_temporary_shallow(void)
213+
{
214+
if (temporary_shallow.len) {
215+
unlink_or_warn(temporary_shallow.buf);
216+
strbuf_reset(&temporary_shallow);
217+
}
218+
}
219+
220+
static void remove_temporary_shallow_on_signal(int signo)
221+
{
222+
remove_temporary_shallow();
223+
sigchain_pop(signo);
224+
raise(signo);
225+
}
226+
227+
const char *setup_temporary_shallow(const struct sha1_array *extra)
220228
{
229+
static int installed_handler;
221230
struct strbuf sb = STRBUF_INIT;
222231
int fd;
223232

233+
if (temporary_shallow.len)
234+
die("BUG: attempt to create two temporary shallow files");
235+
224236
if (write_shallow_commits(&sb, 0, extra)) {
225-
struct strbuf path = STRBUF_INIT;
226-
strbuf_addstr(&path, git_path("shallow_XXXXXX"));
227-
fd = xmkstemp(path.buf);
237+
strbuf_addstr(&temporary_shallow, git_path("shallow_XXXXXX"));
238+
fd = xmkstemp(temporary_shallow.buf);
239+
240+
if (!installed_handler) {
241+
atexit(remove_temporary_shallow);
242+
sigchain_push_common(remove_temporary_shallow_on_signal);
243+
}
244+
228245
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
229246
die_errno("failed to write to %s",
230-
path.buf);
247+
temporary_shallow.buf);
231248
close(fd);
232249
strbuf_release(&sb);
233-
return strbuf_detach(&path, NULL);
250+
return temporary_shallow.buf;
234251
}
235252
/*
236253
* is_repository_shallow() sees empty string as "no shallow
237254
* file".
238255
*/
239-
return xstrdup("");
256+
return temporary_shallow.buf;
240257
}
241258

242259
void setup_alternate_shallow(struct lock_file *shallow_lock,
@@ -246,9 +263,9 @@ void setup_alternate_shallow(struct lock_file *shallow_lock,
246263
struct strbuf sb = STRBUF_INIT;
247264
int fd;
248265

249-
check_shallow_file_for_update();
250266
fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
251267
LOCK_DIE_ON_ERROR);
268+
check_shallow_file_for_update();
252269
if (write_shallow_commits(&sb, 0, extra)) {
253270
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
254271
die_errno("failed to write to %s",
@@ -293,9 +310,9 @@ void prune_shallow(int show_only)
293310
strbuf_release(&sb);
294311
return;
295312
}
296-
check_shallow_file_for_update();
297313
fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
298314
LOCK_DIE_ON_ERROR);
315+
check_shallow_file_for_update();
299316
if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
300317
if (write_in_full(fd, sb.buf, sb.len) != sb.len)
301318
die_errno("failed to write to %s",

upload-pack.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static void create_pack_file(void)
8181
const char *argv[12];
8282
int i, arg = 0;
8383
FILE *pipe_fd;
84-
char *shallow_file = NULL;
84+
const char *shallow_file = NULL;
8585

8686
if (shallow_nr) {
8787
shallow_file = setup_temporary_shallow(NULL);
@@ -242,11 +242,6 @@ static void create_pack_file(void)
242242
error("git upload-pack: git-pack-objects died with error.");
243243
goto fail;
244244
}
245-
if (shallow_file) {
246-
if (*shallow_file)
247-
unlink(shallow_file);
248-
free(shallow_file);
249-
}
250245

251246
/* flush the data */
252247
if (0 <= buffered) {

0 commit comments

Comments
 (0)