diff --git a/commands/digest.c b/commands/digest.c index 2a699e625..1fbffb6ec 100644 --- a/commands/digest.c +++ b/commands/digest.c @@ -29,71 +29,12 @@ #include #include -static int file_digest(struct digest *d, char *filename, - ulong start, ulong size) -{ - ulong len = 0; - int fd, now, i, ret = 0; - unsigned char *buf; - - d->init(d); - - fd = open(filename, O_RDONLY); - if (fd < 0) { - perror(filename); - return fd; - } - - if (start > 0) { - ret = lseek(fd, start, SEEK_SET); - if (ret == -1) { - perror("lseek"); - goto out; - } - } - - buf = xmalloc(4096); - - while (size) { - now = min((ulong)4096, size); - 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; - } - - d->update(d, buf, now); - size -= now; - len += now; - } - - d->final(d, buf); - - for (i = 0; i < d->length; i++) - printf("%02x", buf[i]); - - printf(" %s\t0x%08lx ... 0x%08lx\n", filename, start, start + len); - -out_free: - free(buf); -out: - close(fd); - - return ret; -} - static int do_digest(char *algorithm, int argc, char *argv[]) { struct digest *d; int ret = 0; + int i; + unsigned char *hash; d = digest_get_by_name(algorithm); BUG_ON(!d); @@ -101,6 +42,12 @@ static int do_digest(char *algorithm, int argc, char *argv[]) if (argc < 2) return COMMAND_ERROR_USAGE; + hash = calloc(d->length, sizeof(unsigned char)); + if (!hash) { + perror("calloc"); + return COMMAND_ERROR_USAGE; + } + argv++; while (*argv) { char *filename = "/dev/mem"; @@ -113,12 +60,19 @@ static int do_digest(char *algorithm, int argc, char *argv[]) argv++; } - if (file_digest(d, filename, start, size) < 0) + if (digest_file_window(d, filename, hash, start, size) < 0) ret = 1; + for (i = 0; i < d->length; i++) + printf("%02x", hash[i]); + + printf(" %s\t0x%08lx ... 0x%08lx\n", filename, start, start + size); + argv++; } + free(hash); + return ret; } diff --git a/common/digest.c b/common/digest.c index 10ad06005..a32739580 100644 --- a/common/digest.c +++ b/common/digest.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -75,3 +78,101 @@ struct digest* digest_get_by_name(char* name) return NULL; } EXPORT_SYMBOL_GPL(digest_get_by_name); + +int digest_file_window(struct digest *d, char *filename, + unsigned char *hash, + ulong start, ulong size) +{ + ulong len = 0; + int fd, now, ret = 0; + unsigned char *buf; + int flags; + + d->init(d); + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + return fd; + } + + 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; + } + + d->update(d, buf, now); + size -= now; + len += now; + } + + d->final(d, hash); + +out_free: + if (flags) + free(buf); +out: + close(fd); + + return ret; +} +EXPORT_SYMBOL_GPL(digest_file_window); + +int digest_file(struct digest *d, char *filename, + unsigned char *hash) +{ + struct stat st; + int ret; + + ret = stat(filename, &st); + + if (ret < 0) + return ret; + + return digest_file_window(d, filename, hash, 0, st.st_size); +} +EXPORT_SYMBOL_GPL(digest_file); + +int digest_file_by_name(char *algo, char *filename, + unsigned char *hash) +{ + struct digest *d; + + d = digest_get_by_name(algo); + if (!d) + return -EIO; + + return digest_file(d, filename, hash); +} +EXPORT_SYMBOL_GPL(digest_file_by_name); diff --git a/include/digest.h b/include/digest.h index 1dcfd9d86..36a8e37fd 100644 --- a/include/digest.h +++ b/include/digest.h @@ -46,4 +46,12 @@ void digest_unregister(struct digest *d); struct digest* digest_get_by_name(char* name); +int digest_file_window(struct digest *d, char *filename, + unsigned char *hash, + ulong start, ulong size); +int digest_file(struct digest *d, char *filename, + unsigned char *hash); +int digest_file_by_name(char *algo, char *filename, + unsigned char *hash); + #endif /* __SH_ST_DEVICES_H__ */