]> git.ipfire.org Git - thirdparty/git.git/blame - csum-file.c
hashfile: use write_in_full()
[thirdparty/git.git] / csum-file.c
CommitLineData
c38138cd
LT
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"
2a128d63 11#include "progress.h"
c38138cd
LT
12#include "csum-file.h"
13
98a3beab 14static void flush(struct hashfile *f, const void *buf, unsigned int count)
c38138cd 15{
e337a04d
JH
16 if (0 <= f->check_fd && count) {
17 unsigned char check_buffer[8192];
18 ssize_t ret = read_in_full(f->check_fd, check_buffer, count);
19
20 if (ret < 0)
21 die_errno("%s: sha1 file read error", f->name);
61d36330 22 if (ret != count)
e337a04d
JH
23 die("%s: sha1 file truncated", f->name);
24 if (memcmp(buf, check_buffer, count))
25 die("sha1 file '%s' validation error", f->name);
26 }
27
68142e11
DS
28 if (write_in_full(f->fd, buf, count) < 0) {
29 if (errno == ENOSPC)
e1808845 30 die("sha1 file '%s' write error. Out of diskspace", f->name);
d824cbba 31 die_errno("sha1 file '%s' write error", f->name);
c38138cd 32 }
68142e11
DS
33
34 f->total += count;
35 display_throughput(f->tp, f->total);
c38138cd
LT
36}
37
98a3beab 38void hashflush(struct hashfile *f)
c38138cd
LT
39{
40 unsigned offset = f->offset;
4c81b03e 41
c38138cd 42 if (offset) {
4d273500 43 the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
e782e12f 44 flush(f, f->buffer, offset);
f0215369 45 f->offset = 0;
c38138cd 46 }
838cd346
NP
47}
48
f2af9f5e 49int finalize_hashfile(struct hashfile *f, unsigned char *result, unsigned int flags)
838cd346
NP
50{
51 int fd;
52
98a3beab 53 hashflush(f);
4d273500 54 the_hash_algo->final_fn(f->buffer, &f->ctx);
ac0463ed
NP
55 if (result)
56 hashcpy(result, f->buffer);
cfe83216 57 if (flags & CSUM_HASH_IN_STREAM)
4d273500 58 flush(f, f->buffer, the_hash_algo->rawsz);
cfe83216
DS
59 if (flags & CSUM_FSYNC)
60 fsync_or_die(f->fd, f->name);
61 if (flags & CSUM_CLOSE) {
7ba502c4 62 if (close(f->fd))
d824cbba 63 die_errno("%s: sha1 file error on close", f->name);
7ba502c4
NP
64 fd = 0;
65 } else
66 fd = f->fd;
e337a04d
JH
67 if (0 <= f->check_fd) {
68 char discard;
69 int cnt = read_in_full(f->check_fd, &discard, 1);
70 if (cnt < 0)
71 die_errno("%s: error when reading the tail of sha1 file",
72 f->name);
73 if (cnt)
74 die("%s: sha1 file has trailing garbage", f->name);
75 if (close(f->check_fd))
76 die_errno("%s: sha1 file error on close", f->name);
77 }
7bf058f0 78 free(f);
7ba502c4 79 return fd;
c38138cd
LT
80}
81
98a3beab 82void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
c38138cd
LT
83{
84 while (count) {
ddaf1f62 85 unsigned left = sizeof(f->buffer) - f->offset;
c38138cd 86 unsigned nr = count > left ? left : count;
a8032d12
NP
87
88 if (f->do_crc)
89 f->crc32 = crc32(f->crc32, buf, nr);
90
91 if (nr == sizeof(f->buffer)) {
ddaf1f62
DS
92 /*
93 * Flush a full batch worth of data directly
94 * from the input, skipping the memcpy() to
95 * the hashfile's buffer. In this block,
96 * f->offset is necessarily zero.
97 */
98 the_hash_algo->update_fn(&f->ctx, buf, nr);
99 flush(f, buf, nr);
a8032d12 100 } else {
ddaf1f62
DS
101 /*
102 * Copy to the hashfile's buffer, flushing only
103 * if it became full.
104 */
105 memcpy(f->buffer + f->offset, buf, nr);
106 f->offset += nr;
107 left -= nr;
108 if (!left)
109 hashflush(f);
a8032d12 110 }
c38138cd 111
c38138cd 112 count -= nr;
1d7f171c 113 buf = (char *) buf + nr;
c38138cd 114 }
c38138cd
LT
115}
116
98a3beab 117struct hashfile *hashfd(int fd, const char *name)
2a128d63 118{
98a3beab 119 return hashfd_throughput(fd, name, NULL);
2a128d63
NP
120}
121
98a3beab 122struct hashfile *hashfd_check(const char *name)
e337a04d
JH
123{
124 int sink, check;
98a3beab 125 struct hashfile *f;
e337a04d
JH
126
127 sink = open("/dev/null", O_WRONLY);
128 if (sink < 0)
599d2231 129 die_errno("unable to open /dev/null");
e337a04d 130 check = open(name, O_RDONLY);
599d2231
JK
131 if (check < 0)
132 die_errno("unable to open '%s'", name);
98a3beab 133 f = hashfd(sink, name);
e337a04d
JH
134 f->check_fd = check;
135 return f;
136}
137
98a3beab 138struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp)
4397f014 139{
98a3beab 140 struct hashfile *f = xmalloc(sizeof(*f));
4397f014 141 f->fd = fd;
e337a04d 142 f->check_fd = -1;
4397f014 143 f->offset = 0;
218558af 144 f->total = 0;
2a128d63 145 f->tp = tp;
ec640ed1 146 f->name = name;
78d1e84f 147 f->do_crc = 0;
4d273500 148 the_hash_algo->init_fn(&f->ctx);
4397f014
LT
149 return f;
150}
151
98a3beab 152void hashfile_checkpoint(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
6c526148 153{
98a3beab 154 hashflush(f);
6c526148 155 checkpoint->offset = f->total;
768e30ea 156 the_hash_algo->clone_fn(&checkpoint->ctx, &f->ctx);
6c526148
JH
157}
158
98a3beab 159int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint)
6c526148
JH
160{
161 off_t offset = checkpoint->offset;
162
163 if (ftruncate(f->fd, offset) ||
164 lseek(f->fd, offset, SEEK_SET) != offset)
165 return -1;
166 f->total = offset;
167 f->ctx = checkpoint->ctx;
98a3beab 168 f->offset = 0; /* hashflush() was called in checkpoint */
6c526148
JH
169 return 0;
170}
171
98a3beab 172void crc32_begin(struct hashfile *f)
78d1e84f 173{
1e4cd68c 174 f->crc32 = crc32(0, NULL, 0);
78d1e84f
NP
175 f->do_crc = 1;
176}
c38138cd 177
98a3beab 178uint32_t crc32_end(struct hashfile *f)
78d1e84f
NP
179{
180 f->do_crc = 0;
181 return f->crc32;
182}