Merge branch 'jn/gitweb'
[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 "progress.h"
12 #include "csum-file.h"
13
14 static void sha1flush(struct sha1file *f, unsigned int count)
15 {
16         void *buf = f->buffer;
17
18         for (;;) {
19                 int ret = xwrite(f->fd, buf, count);
20                 if (ret > 0) {
21                         display_throughput(f->tp, ret);
22                         buf = (char *) buf + ret;
23                         count -= ret;
24                         if (count)
25                                 continue;
26                         return;
27                 }
28                 if (!ret)
29                         die("sha1 file '%s' write error. Out of diskspace", f->name);
30                 die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
31         }
32 }
33
34 int sha1close(struct sha1file *f, unsigned char *result, int final)
35 {
36         int fd;
37         unsigned offset = f->offset;
38         if (offset) {
39                 SHA1_Update(&f->ctx, f->buffer, offset);
40                 sha1flush(f, offset);
41                 f->offset = 0;
42         }
43         if (final) {
44                 /* write checksum and close fd */
45                 SHA1_Final(f->buffer, &f->ctx);
46                 if (result)
47                         hashcpy(result, f->buffer);
48                 sha1flush(f, 20);
49                 if (close(f->fd))
50                         die("%s: sha1 file error on close (%s)",
51                             f->name, strerror(errno));
52                 fd = 0;
53         } else
54                 fd = f->fd;
55         free(f);
56         return fd;
57 }
58
59 int sha1write(struct sha1file *f, void *buf, unsigned int count)
60 {
61         if (f->do_crc)
62                 f->crc32 = crc32(f->crc32, buf, count);
63         while (count) {
64                 unsigned offset = f->offset;
65                 unsigned left = sizeof(f->buffer) - offset;
66                 unsigned nr = count > left ? left : count;
67
68                 memcpy(f->buffer + offset, buf, nr);
69                 count -= nr;
70                 offset += nr;
71                 buf = (char *) buf + nr;
72                 left -= nr;
73                 if (!left) {
74                         SHA1_Update(&f->ctx, f->buffer, offset);
75                         sha1flush(f, offset);
76                         offset = 0;
77                 }
78                 f->offset = offset;
79         }
80         return 0;
81 }
82
83 struct sha1file *sha1fd(int fd, const char *name)
84 {
85         return sha1fd_throughput(fd, name, NULL);
86 }
87
88 struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
89 {
90         struct sha1file *f;
91         unsigned len;
92
93         f = xmalloc(sizeof(*f));
94
95         len = strlen(name);
96         if (len >= PATH_MAX)
97                 die("you wascally wabbit, you");
98         f->namelen = len;
99         memcpy(f->name, name, len+1);
100
101         f->fd = fd;
102         f->error = 0;
103         f->offset = 0;
104         f->tp = tp;
105         f->do_crc = 0;
106         SHA1_Init(&f->ctx);
107         return f;
108 }
109
110 void crc32_begin(struct sha1file *f)
111 {
112         f->crc32 = crc32(0, Z_NULL, 0);
113         f->do_crc = 1;
114 }
115
116 uint32_t crc32_end(struct sha1file *f)
117 {
118         f->do_crc = 0;
119         return f->crc32;
120 }