Skip to content

Commit 6e180cd

Browse files
committed
Make sure objects/pack exists before creating a new pack
In a repository created with git older than f49fb35 (git-init-db: create "pack" subdirectory under objects, 2005-06-27), objects/pack/ directory is not created upon initialization. It was Ok because subdirectories are created as needed inside directories init-db creates, and back then, packfiles were recent invention. After the said commit, new codepaths started relying on the presense of objects/pack/ directory in the repository. This was exacerbated with 8b4eb6b (Do not perform cross-directory renames when creating packs, 2008-09-22) that moved the location temporary pack files are created from objects/ directory to objects/pack/ directory, because moving temporary to the final location was done carefully with lazy leading directory creation. Many packfile related operations in such an old repository can fail mysteriously because of this. This commit introduces two helper functions to make things work better. - odb_mkstemp() is a specialized version of mkstemp() to refactor the code and teach it to create leading directories as needed; - odb_pack_keep() refactors the code to create a ".keep" file while create leading directories as needed. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 718258e commit 6e180cd

File tree

7 files changed

+72
-27
lines changed

7 files changed

+72
-27
lines changed

builtin-pack-objects.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,9 +473,8 @@ static void write_pack_file(void)
473473
} else {
474474
char tmpname[PATH_MAX];
475475
int fd;
476-
snprintf(tmpname, sizeof(tmpname),
477-
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
478-
fd = xmkstemp(tmpname);
476+
fd = odb_mkstemp(tmpname, sizeof(tmpname),
477+
"pack/tmp_pack_XXXXXX");
479478
pack_tmp_name = xstrdup(tmpname);
480479
f = sha1fd(fd, pack_tmp_name);
481480
}

fast-import.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -815,9 +815,8 @@ static void start_packfile(void)
815815
struct pack_header hdr;
816816
int pack_fd;
817817

818-
snprintf(tmpfile, sizeof(tmpfile),
819-
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
820-
pack_fd = xmkstemp(tmpfile);
818+
pack_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
819+
"pack/tmp_pack_XXXXXX");
821820
p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
822821
strcpy(p->pack_name, tmpfile);
823822
p->pack_fd = pack_fd;
@@ -877,9 +876,8 @@ static char *create_index(void)
877876
c = next;
878877
}
879878

880-
snprintf(tmpfile, sizeof(tmpfile),
881-
"%s/pack/tmp_idx_XXXXXX", get_object_directory());
882-
idx_fd = xmkstemp(tmpfile);
879+
idx_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
880+
"pack/tmp_idx_XXXXXX");
883881
f = sha1fd(idx_fd, tmpfile);
884882
sha1write(f, array, 256 * sizeof(int));
885883
SHA1_Init(&ctx);
@@ -905,9 +903,7 @@ static char *keep_pack(char *curr_index_name)
905903
chmod(pack_data->pack_name, 0444);
906904
chmod(curr_index_name, 0444);
907905

908-
snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
909-
get_object_directory(), sha1_to_hex(pack_data->sha1));
910-
keep_fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
906+
keep_fd = odb_pack_keep(name, sizeof(name), pack_data->sha1);
911907
if (keep_fd < 0)
912908
die("cannot create keep file");
913909
write_or_die(keep_fd, keep_msg, strlen(keep_msg));

git-compat-util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ extern ssize_t xwrite(int fd, const void *buf, size_t len);
294294
extern int xdup(int fd);
295295
extern FILE *xfdopen(int fd, const char *mode);
296296
extern int xmkstemp(char *template);
297+
extern int odb_mkstemp(char *template, size_t limit, const char *pattern);
298+
extern int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1);
297299

298300
static inline size_t xsize_t(off_t len)
299301
{

index-pack.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,8 @@ static char *open_pack_file(char *pack_name)
171171
input_fd = 0;
172172
if (!pack_name) {
173173
static char tmpfile[PATH_MAX];
174-
snprintf(tmpfile, sizeof(tmpfile),
175-
"%s/pack/tmp_pack_XXXXXX", get_object_directory());
176-
output_fd = xmkstemp(tmpfile);
174+
output_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
175+
"pack/tmp_pack_XXXXXX");
177176
pack_name = xstrdup(tmpfile);
178177
} else
179178
output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
@@ -795,22 +794,24 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
795794

796795
if (keep_msg) {
797796
int keep_fd, keep_msg_len = strlen(keep_msg);
798-
if (!keep_name) {
799-
snprintf(name, sizeof(name), "%s/pack/pack-%s.keep",
800-
get_object_directory(), sha1_to_hex(sha1));
801-
keep_name = name;
802-
}
803-
keep_fd = open(keep_name, O_RDWR|O_CREAT|O_EXCL, 0600);
797+
798+
if (!keep_name)
799+
keep_fd = odb_pack_keep(name, sizeof(name), sha1);
800+
else
801+
keep_fd = open(keep_name, O_RDWR|O_CREAT|O_EXCL, 0600);
802+
804803
if (keep_fd < 0) {
805804
if (errno != EEXIST)
806-
die("cannot write keep file");
805+
die("cannot write keep file '%s' (%s)",
806+
keep_name, strerror(errno));
807807
} else {
808808
if (keep_msg_len > 0) {
809809
write_or_die(keep_fd, keep_msg, keep_msg_len);
810810
write_or_die(keep_fd, "\n", 1);
811811
}
812812
if (close(keep_fd) != 0)
813-
die("cannot write keep file");
813+
die("cannot close written keep file '%s' (%s)",
814+
keep_name, strerror(errno));
814815
report = "keep";
815816
}
816817
}

pack-write.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects,
4444

4545
if (!index_name) {
4646
static char tmpfile[PATH_MAX];
47-
snprintf(tmpfile, sizeof(tmpfile),
48-
"%s/pack/tmp_idx_XXXXXX", get_object_directory());
49-
fd = xmkstemp(tmpfile);
47+
fd = odb_mkstemp(tmpfile, sizeof(tmpfile), "pack/tmp_idx_XXXXXX");
5048
index_name = xstrdup(tmpfile);
5149
} else {
5250
unlink(index_name);
@@ -239,7 +237,7 @@ char *index_pack_lockfile(int ip_out)
239237
char packname[46];
240238

241239
/*
242-
* The first thing we expects from index-pack's output
240+
* The first thing we expect from index-pack's output
243241
* is "pack\t%40s\n" or "keep\t%40s\n" (46 bytes) where
244242
* %40s is the newly created pack SHA1 name. In the "keep"
245243
* case, we need it to remove the corresponding .keep file

t/t5300-pack-object.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ test_expect_success \
180180

181181
unset GIT_OBJECT_DIRECTORY
182182

183+
test_expect_success 'survive missing objects/pack directory' '
184+
(
185+
rm -fr missing-pack &&
186+
mkdir missing-pack &&
187+
cd missing-pack &&
188+
git init &&
189+
GOP=.git/objects/pack
190+
rm -fr $GOP &&
191+
git index-pack --stdin --keep=test <../test-3-${packname_3}.pack &&
192+
test -f $GOP/pack-${packname_3}.pack &&
193+
test_cmp $GOP/pack-${packname_3}.pack ../test-3-${packname_3}.pack &&
194+
test -f $GOP/pack-${packname_3}.idx &&
195+
test_cmp $GOP/pack-${packname_3}.idx ../test-3-${packname_3}.idx &&
196+
test -f $GOP/pack-${packname_3}.keep
197+
)
198+
'
199+
183200
test_expect_success \
184201
'verify pack' \
185202
'git verify-pack test-1-${packname_1}.idx \

wrapper.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,35 @@ int xmkstemp(char *template)
196196
die("Unable to create temporary file: %s", strerror(errno));
197197
return fd;
198198
}
199+
200+
int odb_mkstemp(char *template, size_t limit, const char *pattern)
201+
{
202+
int fd;
203+
204+
snprintf(template, limit, "%s/%s",
205+
get_object_directory(), pattern);
206+
fd = mkstemp(template);
207+
if (0 <= fd)
208+
return fd;
209+
210+
/* slow path */
211+
safe_create_leading_directories(template);
212+
snprintf(template, limit, "%s/%s",
213+
get_object_directory(), pattern);
214+
return xmkstemp(template);
215+
}
216+
217+
int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1)
218+
{
219+
int fd;
220+
221+
snprintf(name, namesz, "%s/pack/pack-%s.keep",
222+
get_object_directory(), sha1_to_hex(sha1));
223+
fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
224+
if (0 <= fd)
225+
return fd;
226+
227+
/* slow path */
228+
safe_create_leading_directories(name);
229+
return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
230+
}

0 commit comments

Comments
 (0)