blob: 4d50cc5ce18c24a1dc853d3050062b864fe0b943 [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);
Thomas Rastd824cbb2009-06-27 17:58:46 +020029 die_errno("sha1 file '%s' write error", f->name);
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))
Thomas Rastd824cbb2009-06-27 17:58:46 +020058 die_errno("%s: sha1 file error on close", f->name);
Nicolas Pitre7ba502c2007-10-16 21:55:48 -040059 fd = 0;
60 } else
61 fd = f->fd;
Sergey Vlasov7bf058f2005-08-08 22:46:13 +040062 free(f);
Nicolas Pitre7ba502c2007-10-16 21:55:48 -040063 return fd;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070064}
65
66int sha1write(struct sha1file *f, void *buf, unsigned int count)
67{
68 while (count) {
69 unsigned offset = f->offset;
70 unsigned left = sizeof(f->buffer) - offset;
71 unsigned nr = count > left ? left : count;
Nicolas Pitrea8032d12008-09-02 10:22:20 -040072 void *data;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070073
Nicolas Pitrea8032d12008-09-02 10:22:20 -040074 if (f->do_crc)
75 f->crc32 = crc32(f->crc32, buf, nr);
76
77 if (nr == sizeof(f->buffer)) {
78 /* process full buffer directly without copy */
79 data = buf;
80 } else {
81 memcpy(f->buffer + offset, buf, nr);
82 data = f->buffer;
83 }
84
Linus Torvaldsc38138c2005-06-26 20:27:56 -070085 count -= nr;
86 offset += nr;
Florian Forster1d7f1712006-06-18 17:18:09 +020087 buf = (char *) buf + nr;
Linus Torvaldsc38138c2005-06-26 20:27:56 -070088 left -= nr;
89 if (!left) {
Nicolas Pitre9126f002008-10-01 14:05:20 -040090 git_SHA1_Update(&f->ctx, data, offset);
Shawn O. Pearcee782e122008-10-10 08:39:20 -070091 flush(f, data, offset);
Linus Torvaldsc38138c2005-06-26 20:27:56 -070092 offset = 0;
93 }
94 f->offset = offset;
95 }
96 return 0;
97}
98
Linus Torvalds4397f012005-06-28 11:10:06 -070099struct sha1file *sha1fd(int fd, const char *name)
100{
Nicolas Pitre2a128d62007-10-30 17:06:21 -0400101 return sha1fd_throughput(fd, name, NULL);
102}
103
104struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
105{
Nicolas Pitreec640ed2007-11-04 22:54:50 -0500106 struct sha1file *f = xmalloc(sizeof(*f));
Linus Torvalds4397f012005-06-28 11:10:06 -0700107 f->fd = fd;
Linus Torvalds4397f012005-06-28 11:10:06 -0700108 f->offset = 0;
Nicolas Pitre218558a2007-11-04 22:15:41 -0500109 f->total = 0;
Nicolas Pitre2a128d62007-10-30 17:06:21 -0400110 f->tp = tp;
Nicolas Pitreec640ed2007-11-04 22:54:50 -0500111 f->name = name;
Nicolas Pitre78d1e842007-04-09 01:06:31 -0400112 f->do_crc = 0;
Nicolas Pitre9126f002008-10-01 14:05:20 -0400113 git_SHA1_Init(&f->ctx);
Linus Torvalds4397f012005-06-28 11:10:06 -0700114 return f;
115}
116
Nicolas Pitre78d1e842007-04-09 01:06:31 -0400117void crc32_begin(struct sha1file *f)
118{
119 f->crc32 = crc32(0, Z_NULL, 0);
120 f->do_crc = 1;
121}
Linus Torvaldsc38138c2005-06-26 20:27:56 -0700122
Nicolas Pitre78d1e842007-04-09 01:06:31 -0400123uint32_t crc32_end(struct sha1file *f)
124{
125 f->do_crc = 0;
126 return f->crc32;
127}