Skip to content

Commit aac1794

Browse files
author
Linus Torvalds
committed
Improve sha1 object file writing.
Make it much safer: we write to a temporary file, and then link that temporary file to the final destination. This avoids all the nasty races if several people write the same object at the same time. It should also result in nicer on-disk layout, since it means that objects all get created in the same subdirectory. That makes a lot of block allocation algorithms happier, since the objects will now be allocated from the same zone.
1 parent 92d4c85 commit aac1794

File tree

2 files changed

+39
-96
lines changed

2 files changed

+39
-96
lines changed

cache.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,6 @@ extern int index_fd(unsigned char *sha1, int fd, struct stat *st);
128128
/* Return a statically allocated filename matching the sha1 signature */
129129
extern char *sha1_file_name(const unsigned char *sha1);
130130

131-
/* Write a memory buffer out to the sha file */
132-
extern int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size);
133-
134131
/* Read and unpack a sha1 file into memory, write memory to a sha1 file */
135132
extern void * map_sha1_file(const unsigned char *sha1, unsigned long *size);
136133
extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);

sha1_file.c

Lines changed: 39 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,9 @@ int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned cha
284284
unsigned char sha1[20];
285285
SHA_CTX c;
286286
char *filename;
287+
static char tmpfile[PATH_MAX];
287288
char hdr[50];
288-
int fd, hdrlen;
289+
int fd, hdrlen, ret;
289290

290291
/* Generate the header */
291292
hdrlen = sprintf(hdr, "%s %lu", type, len)+1;
@@ -300,18 +301,28 @@ int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned cha
300301
memcpy(returnsha1, sha1, 20);
301302

302303
filename = sha1_file_name(sha1);
303-
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
304-
if (fd < 0) {
305-
if (errno != EEXIST)
306-
return -1;
307-
304+
fd = open(filename, O_RDONLY);
305+
if (fd >= 0) {
308306
/*
309-
* We might do collision checking here, but we'd need to
310-
* uncompress the old file and check it. Later.
307+
* FIXME!!! We might do collision checking here, but we'd
308+
* need to uncompress the old file and check it. Later.
311309
*/
310+
close(fd);
312311
return 0;
313312
}
314313

314+
if (errno != ENOENT) {
315+
fprintf(stderr, "sha1 file %s: %s", filename, strerror(errno));
316+
return -1;
317+
}
318+
319+
snprintf(tmpfile, sizeof(tmpfile), "%s/obj_XXXXXX", get_object_directory());
320+
fd = mkstemp(tmpfile);
321+
if (fd < 0) {
322+
fprintf(stderr, "unable to create temporary sha1 filename %s: %s", tmpfile, strerror(errno));
323+
return -1;
324+
}
325+
315326
/* Set it up */
316327
memset(&stream, 0, sizeof(stream));
317328
deflateInit(&stream, Z_BEST_COMPRESSION);
@@ -338,54 +349,21 @@ int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned cha
338349

339350
if (write(fd, compressed, size) != size)
340351
die("unable to write file");
352+
fchmod(fd, 0444);
341353
close(fd);
342-
343-
return 0;
344-
}
345354

346-
static inline int collision_check(char *filename, void *buf, unsigned int size)
347-
{
348-
#ifdef COLLISION_CHECK
349-
void *map;
350-
int fd = open(filename, O_RDONLY);
351-
struct stat st;
352-
int cmp;
353-
354-
/* Unreadable object, or object went away? Strange. */
355-
if (fd < 0)
356-
return -1;
357-
358-
if (fstat(fd, &st) < 0 || size != st.st_size)
359-
return -1;
360-
361-
map = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
362-
close(fd);
363-
if (map == MAP_FAILED)
364-
return -1;
365-
cmp = memcmp(buf, map, size);
366-
munmap(map, size);
367-
if (cmp)
368-
return -1;
369-
#endif
370-
return 0;
371-
}
372-
373-
int write_sha1_buffer(const unsigned char *sha1, void *buf, unsigned int size)
374-
{
375-
char *filename = sha1_file_name(sha1);
376-
int fd;
377-
378-
fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
379-
if (fd < 0) {
380-
if (errno != EEXIST)
355+
ret = link(tmpfile, filename);
356+
if (ret < 0)
357+
ret = errno;
358+
unlink(tmpfile);
359+
if (ret) {
360+
if (ret != EEXIST) {
361+
fprintf(stderr, "unable to write sha1 filename %s: %s", filename, strerror(ret));
381362
return -1;
382-
if (collision_check(filename, buf, size))
383-
return error("SHA1 collision detected!"
384-
" This is bad, bad, BAD!\a\n");
385-
return 0;
363+
}
364+
/* FIXME!!! Collision check here ? */
386365
}
387-
write(fd, buf, size);
388-
close(fd);
366+
389367
return 0;
390368
}
391369

@@ -463,51 +441,19 @@ int has_sha1_file(const unsigned char *sha1)
463441

464442
int index_fd(unsigned char *sha1, int fd, struct stat *st)
465443
{
466-
z_stream stream;
467444
unsigned long size = st->st_size;
468-
int max_out_bytes = size + 200;
469-
void *out = xmalloc(max_out_bytes);
470-
void *metadata = xmalloc(200);
471-
int metadata_size;
472-
void *in;
473-
SHA_CTX c;
445+
void *buf;
446+
int ret;
474447

475-
in = "";
448+
buf = "";
476449
if (size)
477-
in = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
450+
buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
478451
close(fd);
479-
if (!out || (int)(long)in == -1)
452+
if ((int)(long)buf == -1)
480453
return -1;
481454

482-
metadata_size = 1+sprintf(metadata, "blob %lu", size);
483-
484-
SHA1_Init(&c);
485-
SHA1_Update(&c, metadata, metadata_size);
486-
SHA1_Update(&c, in, size);
487-
SHA1_Final(sha1, &c);
488-
489-
memset(&stream, 0, sizeof(stream));
490-
deflateInit(&stream, Z_BEST_COMPRESSION);
491-
492-
/*
493-
* ASCII size + nul byte
494-
*/
495-
stream.next_in = metadata;
496-
stream.avail_in = metadata_size;
497-
stream.next_out = out;
498-
stream.avail_out = max_out_bytes;
499-
while (deflate(&stream, 0) == Z_OK)
500-
/* nothing */;
501-
502-
/*
503-
* File content
504-
*/
505-
stream.next_in = in;
506-
stream.avail_in = size;
507-
while (deflate(&stream, Z_FINISH) == Z_OK)
508-
/*nothing */;
509-
510-
deflateEnd(&stream);
511-
512-
return write_sha1_buffer(sha1, out, stream.total_out);
455+
ret = write_sha1_file(buf, size, "blob", sha1);
456+
if (size)
457+
munmap(buf, size);
458+
return ret;
513459
}

0 commit comments

Comments
 (0)