Clean up sha1 file writing
This cleans up and future-proofs the sha1 file writing in sha1_file.c. In particular, instead of doing a simple "write()" call and just verifying that it succeeds (or - as in one place - just assuming it does), it uses "write_buffer()" to write data to the file descriptor while correctly checking for partial writes, EINTR etc. It also splits up write_sha1_to_fd() to be a lot more readable: if we need to re-create the compressed object, we do so in a separate helper function, making the logic a whole lot more modular and obvious. Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
f81daefe56
commit
4d548150ac
145
sha1_file.c
145
sha1_file.c
@ -1399,6 +1399,25 @@ int move_temp_to_file(const char *tmpfile, char *filename)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int write_buffer(int fd, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
while (len) {
|
||||||
|
ssize_t size;
|
||||||
|
|
||||||
|
size = write(fd, buf, len);
|
||||||
|
if (!size)
|
||||||
|
return error("file write: disk full");
|
||||||
|
if (size < 0) {
|
||||||
|
if (errno == EINTR || errno == EAGAIN)
|
||||||
|
continue;
|
||||||
|
return error("file write error (%s)", strerror(errno));
|
||||||
|
}
|
||||||
|
len -= size;
|
||||||
|
buf += size;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
|
int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
@ -1465,8 +1484,8 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
|
|||||||
deflateEnd(&stream);
|
deflateEnd(&stream);
|
||||||
size = stream.total_out;
|
size = stream.total_out;
|
||||||
|
|
||||||
if (write(fd, compressed, size) != size)
|
if (write_buffer(fd, compressed, size) < 0)
|
||||||
die("unable to write file");
|
die("unable to write sha1 file");
|
||||||
fchmod(fd, 0444);
|
fchmod(fd, 0444);
|
||||||
close(fd);
|
close(fd);
|
||||||
free(compressed);
|
free(compressed);
|
||||||
@ -1474,73 +1493,70 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
|
|||||||
return move_temp_to_file(tmpfile, filename);
|
return move_temp_to_file(tmpfile, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to unpack and recompress the object for writing
|
||||||
|
* it out to a different file.
|
||||||
|
*/
|
||||||
|
static void *repack_object(const unsigned char *sha1, unsigned long *objsize)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
z_stream stream;
|
||||||
|
unsigned char *unpacked;
|
||||||
|
unsigned long len;
|
||||||
|
char type[20];
|
||||||
|
char hdr[50];
|
||||||
|
int hdrlen;
|
||||||
|
void *buf;
|
||||||
|
|
||||||
|
// need to unpack and recompress it by itself
|
||||||
|
unpacked = read_packed_sha1(sha1, type, &len);
|
||||||
|
|
||||||
|
hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
|
||||||
|
|
||||||
|
/* Set it up */
|
||||||
|
memset(&stream, 0, sizeof(stream));
|
||||||
|
deflateInit(&stream, Z_BEST_COMPRESSION);
|
||||||
|
size = deflateBound(&stream, len + hdrlen);
|
||||||
|
buf = xmalloc(size);
|
||||||
|
|
||||||
|
/* Compress it */
|
||||||
|
stream.next_out = buf;
|
||||||
|
stream.avail_out = size;
|
||||||
|
|
||||||
|
/* First header.. */
|
||||||
|
stream.next_in = (void *)hdr;
|
||||||
|
stream.avail_in = hdrlen;
|
||||||
|
while (deflate(&stream, 0) == Z_OK)
|
||||||
|
/* nothing */;
|
||||||
|
|
||||||
|
/* Then the data itself.. */
|
||||||
|
stream.next_in = unpacked;
|
||||||
|
stream.avail_in = len;
|
||||||
|
while (deflate(&stream, Z_FINISH) == Z_OK)
|
||||||
|
/* nothing */;
|
||||||
|
deflateEnd(&stream);
|
||||||
|
free(unpacked);
|
||||||
|
|
||||||
|
*objsize = stream.total_out;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
int write_sha1_to_fd(int fd, const unsigned char *sha1)
|
int write_sha1_to_fd(int fd, const unsigned char *sha1)
|
||||||
{
|
{
|
||||||
ssize_t size;
|
int retval;
|
||||||
unsigned long objsize;
|
unsigned long objsize;
|
||||||
int posn = 0;
|
void *buf = map_sha1_file_internal(sha1, &objsize);
|
||||||
void *map = map_sha1_file_internal(sha1, &objsize);
|
|
||||||
void *buf = map;
|
|
||||||
void *temp_obj = NULL;
|
|
||||||
z_stream stream;
|
|
||||||
|
|
||||||
if (!buf) {
|
if (buf) {
|
||||||
unsigned char *unpacked;
|
retval = write_buffer(fd, buf, objsize);
|
||||||
unsigned long len;
|
munmap(buf, objsize);
|
||||||
char type[20];
|
return retval;
|
||||||
char hdr[50];
|
|
||||||
int hdrlen;
|
|
||||||
// need to unpack and recompress it by itself
|
|
||||||
unpacked = read_packed_sha1(sha1, type, &len);
|
|
||||||
|
|
||||||
hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
|
|
||||||
|
|
||||||
/* Set it up */
|
|
||||||
memset(&stream, 0, sizeof(stream));
|
|
||||||
deflateInit(&stream, Z_BEST_COMPRESSION);
|
|
||||||
size = deflateBound(&stream, len + hdrlen);
|
|
||||||
temp_obj = buf = xmalloc(size);
|
|
||||||
|
|
||||||
/* Compress it */
|
|
||||||
stream.next_out = buf;
|
|
||||||
stream.avail_out = size;
|
|
||||||
|
|
||||||
/* First header.. */
|
|
||||||
stream.next_in = (void *)hdr;
|
|
||||||
stream.avail_in = hdrlen;
|
|
||||||
while (deflate(&stream, 0) == Z_OK)
|
|
||||||
/* nothing */;
|
|
||||||
|
|
||||||
/* Then the data itself.. */
|
|
||||||
stream.next_in = unpacked;
|
|
||||||
stream.avail_in = len;
|
|
||||||
while (deflate(&stream, Z_FINISH) == Z_OK)
|
|
||||||
/* nothing */;
|
|
||||||
deflateEnd(&stream);
|
|
||||||
free(unpacked);
|
|
||||||
|
|
||||||
objsize = stream.total_out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
buf = repack_object(sha1, &objsize);
|
||||||
size = write(fd, buf + posn, objsize - posn);
|
retval = write_buffer(fd, buf, objsize);
|
||||||
if (size <= 0) {
|
free(buf);
|
||||||
if (!size) {
|
return retval;
|
||||||
fprintf(stderr, "write closed\n");
|
|
||||||
} else {
|
|
||||||
perror("write ");
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
posn += size;
|
|
||||||
} while (posn < objsize);
|
|
||||||
|
|
||||||
if (map)
|
|
||||||
munmap(map, objsize);
|
|
||||||
if (temp_obj)
|
|
||||||
free(temp_obj);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
|
int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
|
||||||
@ -1579,7 +1595,8 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
|
|||||||
SHA1_Update(&c, discard, sizeof(discard) -
|
SHA1_Update(&c, discard, sizeof(discard) -
|
||||||
stream.avail_out);
|
stream.avail_out);
|
||||||
} while (stream.avail_in && ret == Z_OK);
|
} while (stream.avail_in && ret == Z_OK);
|
||||||
write(local, buffer, *bufposn - stream.avail_in);
|
if (write_buffer(local, buffer, *bufposn - stream.avail_in) < 0)
|
||||||
|
die("unable to write sha1 file");
|
||||||
memmove(buffer, buffer + *bufposn - stream.avail_in,
|
memmove(buffer, buffer + *bufposn - stream.avail_in,
|
||||||
stream.avail_in);
|
stream.avail_in);
|
||||||
*bufposn = stream.avail_in;
|
*bufposn = stream.avail_in;
|
||||||
|
Loading…
Reference in New Issue
Block a user