blob: 2ddb12a0b70da87afe6fa8a33dce08c6c8ae7f71 [file] [log] [blame]
Linus Torvaldsc38138c2005-06-26 20:27:56 -07001/*
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"
Nicolas Pitre2a128d62007-10-30 17:06:21 -040011#include "progress.h"
Linus Torvaldsc38138c2005-06-26 20:27:56 -070012#include "csum-file.h"
13
Shawn O. Pearcee782e122008-10-10 08:39:20 -070014static void flush(struct sha1file *f, void * buf, unsigned int count)
Linus Torvaldsc38138c2005-06-26 20:27:56 -070015{
Linus Torvaldsc38138c2005-06-26 20:27:56 -070016 for (;;) {
Junio C Hamano1c15afb2005-12-19 16:18:28 -080017 int ret = xwrite(f->fd, buf, count);
Linus Torvaldsc38138c2005-06-26 20:27:56 -070018 if (ret > 0) {
Nicolas Pitre218558a2007-11-04 22:15:41 -050019 f->total += ret;
20 display_throughput(f->tp, f->total);
Florian Forster1d7f1712006-06-18 17:18:09 +020021 buf = (char *) buf + ret;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070022 count -= ret;
23 if (count)
24 continue;
David Rientjes78b713a2006-08-14 13:32:01 -070025 return;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070026 }
27 if (!ret)
Linus Torvaldse1808842005-06-26 22:01:46 -070028 die("sha1 file '%s' write error. Out of diskspace", f->name);
Linus Torvaldse1808842005-06-26 22:01:46 -070029 die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
Linus Torvaldsc38138c2005-06-26 20:27:56 -070030 }
31}
32
Nicolas Pitre838cd342008-10-09 22:08:51 -040033void sha1flush(struct sha1file *f)
Linus Torvaldsc38138c2005-06-26 20:27:56 -070034{
35 unsigned offset = f->offset;
Linus Torvalds4c81b032008-05-30 08:42:16 -070036
Linus Torvaldsc38138c2005-06-26 20:27:56 -070037 if (offset) {
Nicolas Pitre9126f002008-10-01 14:05:20 -040038 git_SHA1_Update(&f->ctx, f->buffer, offset);
Shawn O. Pearcee782e122008-10-10 08:39:20 -070039 flush(f, f->buffer, offset);
Dana L. Howf0215362007-05-13 11:28:19 -070040 f->offset = 0;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070041 }
Nicolas Pitre838cd342008-10-09 22:08:51 -040042}
43
44int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags)
45{
46 int fd;
47
48 sha1flush(f);
Nicolas Pitre9126f002008-10-01 14:05:20 -040049 git_SHA1_Final(f->buffer, &f->ctx);
Nicolas Pitreac0463e2008-08-29 16:08:00 -040050 if (result)
51 hashcpy(result, f->buffer);
Linus Torvalds4c81b032008-05-30 08:42:16 -070052 if (flags & (CSUM_CLOSE | CSUM_FSYNC)) {
Nicolas Pitre7ba502c2007-10-16 21:55:48 -040053 /* write checksum and close fd */
Shawn O. Pearcee782e122008-10-10 08:39:20 -070054 flush(f, f->buffer, 20);
Linus Torvalds4c81b032008-05-30 08:42:16 -070055 if (flags & CSUM_FSYNC)
56 fsync_or_die(f->fd, f->name);
Nicolas Pitre7ba502c2007-10-16 21:55:48 -040057 if (close(f->fd))
58 die("%s: sha1 file error on close (%s)",
59 f->name, strerror(errno));
60 fd = 0;
61 } else
62 fd = f->fd;
Sergey Vlasov7bf058f2005-08-08 22:46:13 +040063 free(f);
Nicolas Pitre7ba502c2007-10-16 21:55:48 -040064 return fd;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070065}
66
67int sha1write(struct sha1file *f, void *buf, unsigned int count)
68{
69 while (count) {
70 unsigned offset = f->offset;
71 unsigned left = sizeof(f->buffer) - offset;
72 unsigned nr = count > left ? left : count;
Nicolas Pitrea8032d12008-09-02 10:22:20 -040073 void *data;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070074
Nicolas Pitrea8032d12008-09-02 10:22:20 -040075 if (f->do_crc)
76 f->crc32 = crc32(f->crc32, buf, nr);
77
78 if (nr == sizeof(f->buffer)) {
79 /* process full buffer directly without copy */
80 data = buf;
81 } else {
82 memcpy(f->buffer + offset, buf, nr);
83 data = f->buffer;
84 }
85
Linus Torvaldsc38138c2005-06-26 20:27:56 -070086 count -= nr;
87 offset += nr;
Florian Forster1d7f1712006-06-18 17:18:09 +020088 buf = (char *) buf + nr;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070089 left -= nr;
90 if (!left) {
Nicolas Pitre9126f002008-10-01 14:05:20 -040091 git_SHA1_Update(&f->ctx, data, offset);
Shawn O. Pearcee782e122008-10-10 08:39:20 -070092 flush(f, data, offset);
Linus Torvaldsc38138c2005-06-26 20:27:56 -070093 offset = 0;
94 }
95 f->offset = offset;
96 }
97 return 0;
98}
99
Linus Torvalds4397f012005-06-28 11:10:06 -0700100struct sha1file *sha1fd(int fd, const char *name)
101{
Nicolas Pitre2a128d62007-10-30 17:06:21 -0400102 return sha1fd_throughput(fd, name, NULL);
103}
104
105struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
106{
Nicolas Pitreec640ed2007-11-04 22:54:50 -0500107 struct sha1file *f = xmalloc(sizeof(*f));
Linus Torvalds4397f012005-06-28 11:10:06 -0700108 f->fd = fd;
Linus Torvalds4397f012005-06-28 11:10:06 -0700109 f->offset = 0;
Nicolas Pitre218558a2007-11-04 22:15:41 -0500110 f->total = 0;
Nicolas Pitre2a128d62007-10-30 17:06:21 -0400111 f->tp = tp;
Nicolas Pitreec640ed2007-11-04 22:54:50 -0500112 f->name = name;
Nicolas Pitre78d1e842007-04-09 01:06:31 -0400113 f->do_crc = 0;
Nicolas Pitre9126f002008-10-01 14:05:20 -0400114 git_SHA1_Init(&f->ctx);
Linus Torvalds4397f012005-06-28 11:10:06 -0700115 return f;
116}
117
Nicolas Pitre78d1e842007-04-09 01:06:31 -0400118void crc32_begin(struct sha1file *f)
119{
120 f->crc32 = crc32(0, Z_NULL, 0);
121 f->do_crc = 1;
122}
Linus Torvaldsc38138c2005-06-26 20:27:56 -0700123
Nicolas Pitre78d1e842007-04-09 01:06:31 -0400124uint32_t crc32_end(struct sha1file *f)
125{
126 f->do_crc = 0;
127 return f->crc32;
128}