summaryrefslogtreecommitdiffstats
path: root/crypto/digest.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/digest.c')
-rw-r--r--crypto/digest.c131
1 files changed, 74 insertions, 57 deletions
diff --git a/crypto/digest.c b/crypto/digest.c
index bc6de0b98f..2c4de2e4f1 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -211,15 +211,76 @@ void digest_free(struct digest *d)
}
EXPORT_SYMBOL_GPL(digest_free);
+static int digest_update_interruptible(struct digest *d, const void *data,
+ unsigned long len)
+{
+ if (ctrlc())
+ return -EINTR;
+
+ return digest_update(d, data, len);
+}
+
+static int digest_update_from_fd(struct digest *d, int fd,
+ loff_t start, loff_t size)
+{
+ unsigned char *buf = xmalloc(PAGE_SIZE);
+ int ret = 0;
+
+ if (lseek(fd, start, SEEK_SET) != start) {
+ perror("lseek");
+ ret = -errno;
+ goto out_free;
+ }
+
+ while (size) {
+ const ssize_t now = read(fd, buf, PAGE_SIZE);
+ if (now < 0) {
+ ret = now;
+ perror("read");
+ goto out_free;
+ }
+
+ if (!now)
+ break;
+
+ ret = digest_update_interruptible(d, buf, now);
+ if (ret)
+ goto out_free;
+
+ size -= now;
+ }
+
+out_free:
+ free(buf);
+ return ret;
+}
+
+static int digest_update_from_memory(struct digest *d,
+ const unsigned char *buf,
+ loff_t size)
+{
+ while (size) {
+ unsigned long now = min_t(typeof(size), PAGE_SIZE, size);
+ int ret;
+
+ ret = digest_update_interruptible(d, buf, now);
+ if (ret)
+ return ret;
+
+ size -= now;
+ buf += now;
+ }
+
+ return 0;
+}
+
int digest_file_window(struct digest *d, const char *filename,
unsigned char *hash,
const unsigned char *sig,
- ulong start, ulong size)
+ loff_t start, loff_t size)
{
- ulong len = 0;
- int fd, now, ret = 0;
+ int fd, ret;
unsigned char *buf;
- int flags = 0;
ret = digest_init(d);
if (ret)
@@ -228,63 +289,22 @@ int digest_file_window(struct digest *d, const char *filename,
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror(filename);
- return fd;
+ return -errno;
}
buf = memmap(fd, PROT_READ);
- if (buf == (void *)-1) {
- buf = xmalloc(4096);
- flags = 1;
- }
-
- if (start > 0) {
- if (flags) {
- ret = lseek(fd, start, SEEK_SET);
- if (ret == -1) {
- perror("lseek");
- goto out;
- }
- } else {
- buf += start;
- }
- }
-
- while (size) {
- now = min((ulong)4096, size);
- if (flags) {
- now = read(fd, buf, now);
- if (now < 0) {
- ret = now;
- perror("read");
- goto out_free;
- }
- if (!now)
- break;
- }
-
- if (ctrlc()) {
- ret = -EINTR;
- goto out_free;
- }
-
- ret = digest_update(d, buf, now);
- if (ret)
- goto out_free;
- size -= now;
- len += now;
+ if (buf == MAP_FAILED)
+ ret = digest_update_from_fd(d, fd, start, size);
+ else
+ ret = digest_update_from_memory(d, buf + start, size);
- if (!flags)
- buf += now;
- }
+ if (ret)
+ goto out;
if (sig)
ret = digest_verify(d, sig);
else
ret = digest_final(d, hash);
-
-out_free:
- if (flags)
- free(buf);
out:
close(fd);
@@ -297,12 +317,9 @@ int digest_file(struct digest *d, const char *filename,
const unsigned char *sig)
{
struct stat st;
- int ret;
-
- ret = stat(filename, &st);
- if (ret < 0)
- return ret;
+ if (stat(filename, &st))
+ return -errno;
return digest_file_window(d, filename, hash, sig, 0, st.st_size);
}