git-pack-objects: write the pack files with a SHA1 csum
[git.git] / csum-file.c
1 /*
2  * csum-file.c
3  *
4  * Copyright (C) 2005 Linus Torvalds
5  *
6  * Simple file write infrastructure for writing SHA1-summed
7  * files. Useful when you write a file that you want to be
8  * able to verify hasn't been messed with afterwards.
9  */
10 #include "cache.h"
11 #include "csum-file.h"
12
13 static int sha1flush(struct sha1file *f, unsigned int count)
14 {
15         void *buf = f->buffer;
16
17         for (;;) {
18                 int ret = write(f->fd, buf, count);
19                 if (ret > 0) {
20                         buf += ret;
21                         count -= ret;
22                         if (count)
23                                 continue;
24                         return 0;
25                 }
26                 if (!ret)
27                         die("sha1 file write error. Out of diskspace");
28                 if (errno == EAGAIN || errno == EINTR)
29                         continue;
30                 die("sha1 file write error (%s)", strerror(errno));
31         }
32 }
33
34 int sha1close(struct sha1file *f)
35 {
36         unsigned offset = f->offset;
37         if (offset) {
38                 SHA1_Update(&f->ctx, f->buffer, offset);
39                 sha1flush(f, offset);
40         }
41         SHA1_Final(f->buffer, &f->ctx);
42         sha1flush(f, 20);
43         return 0;
44 }
45
46 int sha1write(struct sha1file *f, void *buf, unsigned int count)
47 {
48         while (count) {
49                 unsigned offset = f->offset;
50                 unsigned left = sizeof(f->buffer) - offset;
51                 unsigned nr = count > left ? left : count;
52
53                 memcpy(f->buffer + offset, buf, nr);
54                 count -= nr;
55                 offset += nr;
56                 left -= nr;
57                 if (!left) {
58                         SHA1_Update(&f->ctx, f->buffer, offset);
59                         sha1flush(f, offset);
60                         offset = 0;
61                 }
62                 f->offset = offset;
63         }
64         return 0;
65 }
66
67 struct sha1file *sha1create(const char *fmt, ...)
68 {
69         static char filename[PATH_MAX];
70         struct sha1file *f;
71         unsigned len;
72         va_list arg;
73         int fd;
74
75         va_start(arg, fmt);
76         len = vsnprintf(filename, PATH_MAX, fmt, arg);
77         va_end(arg);
78
79         if (len >= PATH_MAX)
80                 die("you wascally wabbit, you");
81         fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0644);
82         if (fd < 0)
83                 die("unable to open %s (%s)", filename, strerror(errno));
84         f = xmalloc(sizeof(*f));
85         f->fd = fd;
86         f->error = 0;
87         f->offset = 0;
88         SHA1_Init(&f->ctx);
89         return f;
90 }
91
92 int sha1write_compressed(struct sha1file *f, void *in, unsigned int size)
93 {
94         z_stream stream;
95         unsigned long maxsize;
96         void *out;
97
98         memset(&stream, 0, sizeof(stream));
99         deflateInit(&stream, Z_DEFAULT_COMPRESSION);
100         maxsize = deflateBound(&stream, size);
101         out = xmalloc(maxsize);
102
103         /* Compress it */
104         stream.next_in = in;
105         stream.avail_in = size;
106
107         stream.next_out = out;
108         stream.avail_out = maxsize;
109
110         while (deflate(&stream, Z_FINISH) == Z_OK)
111                 /* nothing */;
112         deflateEnd(&stream);
113
114         size = stream.total_out;
115         sha1write(f, out, size);
116         free(out);
117         return size;
118 }
119
120