diff options
Diffstat (limited to 'crypto/digest.c')
-rw-r--r-- | crypto/digest.c | 131 |
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); } |