mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-28 21:54:40 +03:00
checksum: Support the '--check' option
This commit also updates 'checksum' to use the Core::Stream::File API.
This commit is contained in:
parent
340a2a96a4
commit
480e517f03
Notes:
sideshowbarker
2024-07-17 06:00:34 +09:00
Author: https://github.com/implicitfield Commit: https://github.com/SerenityOS/serenity/commit/480e517f03 Pull-request: https://github.com/SerenityOS/serenity/pull/15482 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/LucasChollet
@ -4,12 +4,18 @@ checksum - helper program for calculating checksums
|
||||
|
||||
## Synopsis
|
||||
|
||||
`$ md5sum <file>`
|
||||
`$ sha1sum <file>`
|
||||
`$ sha256sum <file>`
|
||||
`$ sha512sum <file>`
|
||||
`$ md5sum [options...] <file...>`
|
||||
`$ sha1sum [options...] <file...>`
|
||||
`$ sha256sum [options...] <file...>`
|
||||
`$ sha512sum [options...] <file...>`
|
||||
|
||||
## Description
|
||||
|
||||
This program calculates and print specified checksum of files. It cannot be run directly, only
|
||||
as `md5sum`, `sha1sum`, `sha256sum` or `sha512sum`.
|
||||
as `md5sum`, `sha1sum`, `sha256sum` or `sha512sum`. A non-zero exit code is returned if the
|
||||
input cannot be read. If the '--check' option is used, a non-zero exit code is also returned
|
||||
if the checksums cannot be verified.
|
||||
|
||||
## Options
|
||||
|
||||
* `-c`, `--check`: Verify checksums against `file` or stdin.
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/Stream.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibCrypto/Hash/HashManager.h>
|
||||
#include <LibMain/Main.h>
|
||||
@ -36,9 +36,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
auto hash_name = program_name.substring_view(0, program_name.length() - 3).to_string().to_uppercase();
|
||||
auto paths_help_string = String::formatted("File(s) to print {} checksum of", hash_name);
|
||||
|
||||
bool verify_from_paths = false;
|
||||
Vector<StringView> paths;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(verify_from_paths, "Verify checksums from file(s)", "check", 'c');
|
||||
args_parser.add_positional_argument(paths, paths_help_string.characters(), "path", Core::ArgsParser::Required::No);
|
||||
args_parser.parse(arguments);
|
||||
|
||||
@ -48,23 +50,79 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
Crypto::Hash::Manager hash;
|
||||
hash.initialize(hash_kind);
|
||||
|
||||
auto has_error = false;
|
||||
bool has_error = false;
|
||||
int read_fail_count = 0;
|
||||
int failed_verification_count = 0;
|
||||
|
||||
for (auto const& path : paths) {
|
||||
NonnullRefPtr<Core::File> file = Core::File::standard_input();
|
||||
if (path != "-"sv) {
|
||||
auto file_or_error = Core::File::open(path, Core::OpenMode::ReadOnly);
|
||||
if (file_or_error.is_error()) {
|
||||
warnln("{}: {}: {}", program_name, path, file->error_string());
|
||||
has_error = true;
|
||||
continue;
|
||||
auto file_or_error = Core::Stream::File::open_file_or_standard_stream(path, Core::Stream::OpenMode::Read);
|
||||
if (file_or_error.is_error()) {
|
||||
++read_fail_count;
|
||||
has_error = true;
|
||||
warnln("{}: {}", path, file_or_error.release_error());
|
||||
continue;
|
||||
}
|
||||
auto file = file_or_error.release_value();
|
||||
Array<u8, PAGE_SIZE> buffer;
|
||||
if (!verify_from_paths) {
|
||||
while (!file->is_eof())
|
||||
hash.update(TRY(file->read(buffer)));
|
||||
outln("{:hex-dump} {}", hash.digest().bytes(), path);
|
||||
} else {
|
||||
StringBuilder checksum_list_contents;
|
||||
Array<u8, 1> checksum_list_buffer;
|
||||
while (!file->is_eof())
|
||||
checksum_list_contents.append(TRY(file->read(checksum_list_buffer)).data()[0]);
|
||||
Vector<StringView> const lines = checksum_list_contents.string_view().split_view("\n"sv);
|
||||
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
Vector<StringView> const line = lines[i].split_view(" "sv);
|
||||
if (line.size() != 2) {
|
||||
++read_fail_count;
|
||||
// The real line number is greater than the iterator.
|
||||
warnln("{}: {}: Failed to parse line {}", program_name, path, i + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// line[0] = checksum
|
||||
// line[1] = filename
|
||||
StringView const filename = line[1];
|
||||
auto file_from_filename_or_error = Core::Stream::File::open_file_or_standard_stream(filename, Core::Stream::OpenMode::Read);
|
||||
if (file_from_filename_or_error.is_error()) {
|
||||
++read_fail_count;
|
||||
warnln("{}: {}", filename, file_from_filename_or_error.release_error());
|
||||
continue;
|
||||
}
|
||||
auto file_from_filename = file_from_filename_or_error.release_value();
|
||||
hash.reset();
|
||||
while (!file_from_filename->is_eof())
|
||||
hash.update(TRY(file_from_filename->read(buffer)));
|
||||
if (String::formatted("{:hex-dump}", hash.digest().bytes()) == line[0])
|
||||
outln("{}: OK", filename);
|
||||
else {
|
||||
++failed_verification_count;
|
||||
warnln("{}: FAILED", filename);
|
||||
}
|
||||
}
|
||||
file = file_or_error.release_value();
|
||||
}
|
||||
}
|
||||
// Print the warnings here in order to only print them once.
|
||||
if (verify_from_paths) {
|
||||
if (read_fail_count) {
|
||||
if (read_fail_count == 1)
|
||||
warnln("WARNING: 1 file could not be read");
|
||||
else
|
||||
warnln("WARNING: {} files could not be read", read_fail_count);
|
||||
has_error = true;
|
||||
}
|
||||
|
||||
while (!file->eof() && !file->has_error())
|
||||
hash.update(file->read(PAGE_SIZE));
|
||||
outln("{:hex-dump} {}", hash.digest().bytes(), path);
|
||||
if (failed_verification_count) {
|
||||
if (failed_verification_count == 1)
|
||||
warnln("WARNING: 1 checksum did NOT match");
|
||||
else
|
||||
warnln("WARNING: {} checksums did NOT match", failed_verification_count);
|
||||
has_error = true;
|
||||
}
|
||||
}
|
||||
return has_error ? 1 : 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user