4 * Copyright (C) 2005 Linus Torvalds
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.
12 #include "csum-file.h"
14 static void verify_buffer_or_die(struct hashfile
*f
,
18 ssize_t ret
= read_in_full(f
->check_fd
, f
->check_buffer
, count
);
21 die_errno("%s: sha1 file read error", f
->name
);
23 die("%s: sha1 file truncated", f
->name
);
24 if (memcmp(buf
, f
->check_buffer
, count
))
25 die("sha1 file '%s' validation error", f
->name
);
28 static void flush(struct hashfile
*f
, const void *buf
, unsigned int count
)
30 if (0 <= f
->check_fd
&& count
)
31 verify_buffer_or_die(f
, buf
, count
);
33 if (write_in_full(f
->fd
, buf
, count
) < 0) {
35 die("sha1 file '%s' write error. Out of diskspace", f
->name
);
36 die_errno("sha1 file '%s' write error", f
->name
);
40 display_throughput(f
->tp
, f
->total
);
43 void hashflush(struct hashfile
*f
)
45 unsigned offset
= f
->offset
;
48 the_hash_algo
->update_fn(&f
->ctx
, f
->buffer
, offset
);
49 flush(f
, f
->buffer
, offset
);
54 static void free_hashfile(struct hashfile
*f
)
57 free(f
->check_buffer
);
61 int finalize_hashfile(struct hashfile
*f
, unsigned char *result
, unsigned int flags
)
66 the_hash_algo
->final_fn(f
->buffer
, &f
->ctx
);
68 hashcpy(result
, f
->buffer
);
69 if (flags
& CSUM_HASH_IN_STREAM
)
70 flush(f
, f
->buffer
, the_hash_algo
->rawsz
);
71 if (flags
& CSUM_FSYNC
)
72 fsync_or_die(f
->fd
, f
->name
);
73 if (flags
& CSUM_CLOSE
) {
75 die_errno("%s: sha1 file error on close", f
->name
);
79 if (0 <= f
->check_fd
) {
81 int cnt
= read_in_full(f
->check_fd
, &discard
, 1);
83 die_errno("%s: error when reading the tail of sha1 file",
86 die("%s: sha1 file has trailing garbage", f
->name
);
87 if (close(f
->check_fd
))
88 die_errno("%s: sha1 file error on close", f
->name
);
94 void hashwrite(struct hashfile
*f
, const void *buf
, unsigned int count
)
97 unsigned left
= f
->buffer_len
- f
->offset
;
98 unsigned nr
= count
> left
? left
: count
;
101 f
->crc32
= crc32(f
->crc32
, buf
, nr
);
103 if (nr
== f
->buffer_len
) {
105 * Flush a full batch worth of data directly
106 * from the input, skipping the memcpy() to
107 * the hashfile's buffer. In this block,
108 * f->offset is necessarily zero.
110 the_hash_algo
->update_fn(&f
->ctx
, buf
, nr
);
114 * Copy to the hashfile's buffer, flushing only
117 memcpy(f
->buffer
+ f
->offset
, buf
, nr
);
125 buf
= (char *) buf
+ nr
;
129 struct hashfile
*hashfd_check(const char *name
)
134 sink
= open("/dev/null", O_WRONLY
);
136 die_errno("unable to open /dev/null");
137 check
= open(name
, O_RDONLY
);
139 die_errno("unable to open '%s'", name
);
140 f
= hashfd(sink
, name
);
142 f
->check_buffer
= xmalloc(f
->buffer_len
);
147 static struct hashfile
*hashfd_internal(int fd
, const char *name
,
151 struct hashfile
*f
= xmalloc(sizeof(*f
));
159 the_hash_algo
->init_fn(&f
->ctx
);
161 f
->buffer_len
= buffer_len
;
162 f
->buffer
= xmalloc(buffer_len
);
163 f
->check_buffer
= NULL
;
168 struct hashfile
*hashfd(int fd
, const char *name
)
171 * Since we are not going to use a progress meter to
172 * measure the rate of data passing through this hashfile,
173 * use a larger buffer size to reduce fsync() calls.
175 return hashfd_internal(fd
, name
, NULL
, 128 * 1024);
178 struct hashfile
*hashfd_throughput(int fd
, const char *name
, struct progress
*tp
)
181 * Since we are expecting to report progress of the
182 * write into this hashfile, use a smaller buffer
183 * size so the progress indicators arrive at a more
186 return hashfd_internal(fd
, name
, tp
, 8 * 1024);
189 void hashfile_checkpoint(struct hashfile
*f
, struct hashfile_checkpoint
*checkpoint
)
192 checkpoint
->offset
= f
->total
;
193 the_hash_algo
->clone_fn(&checkpoint
->ctx
, &f
->ctx
);
196 int hashfile_truncate(struct hashfile
*f
, struct hashfile_checkpoint
*checkpoint
)
198 off_t offset
= checkpoint
->offset
;
200 if (ftruncate(f
->fd
, offset
) ||
201 lseek(f
->fd
, offset
, SEEK_SET
) != offset
)
204 f
->ctx
= checkpoint
->ctx
;
205 f
->offset
= 0; /* hashflush() was called in checkpoint */
209 void crc32_begin(struct hashfile
*f
)
211 f
->crc32
= crc32(0, NULL
, 0);
215 uint32_t crc32_end(struct hashfile
*f
)