@matheusbsbs / matheus-bagliano / commits / 6e180cdcec
Fork 0

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 <gitster@pobox.com>

Junio C Hamano committed Feb 24, 2009 at 23:11 UTC 6e180cdcecbb3e828aa892925d7ef67abf81ad80
7 files changed +72 -27
builtin-pack-objects.c
+2 -3
@@ -473,9 +473,8 @@ static void write_pack_file(void)
473 } else {
474 char tmpname[PATH_MAX];
475 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");
478 pack_tmp_name = xstrdup(tmpname);
479 f = sha1fd(fd, pack_tmp_name);
480 }
fast-import.c
+5 -9
@@ -815,9 +815,8 @@ static void start_packfile(void)
815 struct pack_header hdr;
816 int pack_fd;
817
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");
820 p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
821 strcpy(p->pack_name, tmpfile);
822 p->pack_fd = pack_fd;
@@ -877,9 +876,8 @@ static char *create_index(void)
876 c = next;
877 }
878
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");
881 f = sha1fd(idx_fd, tmpfile);
882 sha1write(f, array, 256 * sizeof(int));
883 SHA1_Init(&ctx);
@@ -905,9 +903,7 @@ static char *keep_pack(char *curr_index_name)
903 chmod(pack_data->pack_name, 0444);
904 chmod(curr_index_name, 0444);
905
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);
907 if (keep_fd < 0)
908 die("cannot create keep file");
909 write_or_die(keep_fd, keep_msg, strlen(keep_msg));
git-compat-util.h
+2
@@ -294,6 +294,8 @@ extern ssize_t xwrite(int fd, const void *buf, size_t len);
294 extern int xdup(int fd);
295 extern FILE *xfdopen(int fd, const char *mode);
296 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);
299
300 static inline size_t xsize_t(off_t len)
301 {
index-pack.c
+12 -11
@@ -171,9 +171,8 @@ static char *open_pack_file(char *pack_name)
171 input_fd = 0;
172 if (!pack_name) {
173 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");
176 pack_name = xstrdup(tmpfile);
177 } else
178 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,
794
795 if (keep_msg) {
796 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 +
803 if (keep_fd < 0) {
804 if (errno != EEXIST)
806 - die("cannot write keep file");
805 + die("cannot write keep file '%s' (%s)",
806 + keep_name, strerror(errno));
807 } else {
808 if (keep_msg_len > 0) {
809 write_or_die(keep_fd, keep_msg, keep_msg_len);
810 write_or_die(keep_fd, "\n", 1);
811 }
812 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));
815 report = "keep";
816 }
817 }
pack-write.c
+2 -4
@@ -44,9 +44,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects,
44
45 if (!index_name) {
46 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");
48 index_name = xstrdup(tmpfile);
49 } else {
50 unlink(index_name);
@@ -239,7 +237,7 @@ char *index_pack_lockfile(int ip_out)
237 char packname[46];
238
239 /*
242 - * The first thing we expects from index-pack's output
240 + * The first thing we expect from index-pack's output
241 * is "pack\t%40s\n" or "keep\t%40s\n" (46 bytes) where
242 * %40s is the newly created pack SHA1 name. In the "keep"
243 * case, we need it to remove the corresponding .keep file
t/t5300-pack-object.sh
+17
@@ -180,6 +180,23 @@ test_expect_success \
180
181 unset GIT_OBJECT_DIRECTORY
182
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 +
200 test_expect_success \
201 'verify pack' \
202 'git verify-pack test-1-${packname_1}.idx \
wrapper.c
+32
@@ -196,3 +196,35 @@ int xmkstemp(char *template)
196 die("Unable to create temporary file: %s", strerror(errno));
197 return fd;
198 }
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 +}