1/*2* csum-file.c3*4* Copyright (C) 2005 Linus Torvalds5*6* Simple file write infrastructure for writing SHA1-summed7* files. Useful when you write a file that you want to be8* able to verify hasn't been messed with afterwards.9*/10#include "cache.h"11#include "csum-file.h"1213static int sha1flush(struct sha1file *f, unsigned int count)14{15void *buf = f->buffer;1617for (;;) {18int ret = xwrite(f->fd, buf, count);19if (ret > 0) {20buf = (char *) buf + ret;21count -= ret;22if (count)23continue;24return 0;25}26if (!ret)27die("sha1 file '%s' write error. Out of diskspace", f->name);28die("sha1 file '%s' write error (%s)", f->name, strerror(errno));29}30}3132int sha1close(struct sha1file *f, unsigned char *result, int update)33{34unsigned offset = f->offset;35if (offset) {36SHA1_Update(&f->ctx, f->buffer, offset);37sha1flush(f, offset);38}39SHA1_Final(f->buffer, &f->ctx);40if (result)41memcpy(result, f->buffer, 20);42if (update)43sha1flush(f, 20);44if (close(f->fd))45die("%s: sha1 file error on close (%s)", f->name, strerror(errno));46free(f);47return 0;48}4950int sha1write(struct sha1file *f, void *buf, unsigned int count)51{52while (count) {53unsigned offset = f->offset;54unsigned left = sizeof(f->buffer) - offset;55unsigned nr = count > left ? left : count;5657memcpy(f->buffer + offset, buf, nr);58count -= nr;59offset += nr;60buf = (char *) buf + nr;61left -= nr;62if (!left) {63SHA1_Update(&f->ctx, f->buffer, offset);64sha1flush(f, offset);65offset = 0;66}67f->offset = offset;68}69return 0;70}7172struct sha1file *sha1create(const char *fmt, ...)73{74struct sha1file *f;75unsigned len;76va_list arg;77int fd;7879f = xmalloc(sizeof(*f));8081va_start(arg, fmt);82len = vsnprintf(f->name, sizeof(f->name), fmt, arg);83va_end(arg);84if (len >= PATH_MAX)85die("you wascally wabbit, you");86f->namelen = len;8788fd = open(f->name, O_CREAT | O_EXCL | O_WRONLY, 0666);89if (fd < 0)90die("unable to open %s (%s)", f->name, strerror(errno));91f->fd = fd;92f->error = 0;93f->offset = 0;94SHA1_Init(&f->ctx);95return f;96}9798struct sha1file *sha1fd(int fd, const char *name)99{100struct sha1file *f;101unsigned len;102103f = xmalloc(sizeof(*f));104105len = strlen(name);106if (len >= PATH_MAX)107die("you wascally wabbit, you");108f->namelen = len;109memcpy(f->name, name, len+1);110111f->fd = fd;112f->error = 0;113f->offset = 0;114SHA1_Init(&f->ctx);115return f;116}117118int sha1write_compressed(struct sha1file *f, void *in, unsigned int size)119{120z_stream stream;121unsigned long maxsize;122void *out;123124memset(&stream, 0, sizeof(stream));125deflateInit(&stream, zlib_compression_level);126maxsize = deflateBound(&stream, size);127out = xmalloc(maxsize);128129/* Compress it */130stream.next_in = in;131stream.avail_in = size;132133stream.next_out = out;134stream.avail_out = maxsize;135136while (deflate(&stream, Z_FINISH) == Z_OK)137/* nothing */;138deflateEnd(&stream);139140size = stream.total_out;141sha1write(f, out, size);142free(out);143return size;144}145146