xref: /haiku/src/bin/package/command_checksum.cpp (revision 71452e98334eaac603bf542d159e24788a46bebb)
1 /*
2  * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <getopt.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include <new>
16 
17 #include <File.h>
18 #include <String.h>
19 
20 #include <package/hpkg/HPKGDefs.h>
21 #include <package/hpkg/PackageWriter.h>
22 
23 #include <DataPositionIOWrapper.h>
24 #include <FdIO.h>
25 #include <SHA256.h>
26 
27 #include "package.h"
28 #include "PackageWriterListener.h"
29 
30 
31 using BPackageKit::BHPKG::BPackageWriter;
32 using BPackageKit::BHPKG::BPackageWriterListener;
33 using BPackageKit::BHPKG::BPackageWriterParameters;
34 
35 
36 struct ChecksumIO : BDataIO {
37 	ChecksumIO()
38 	{
39 		fChecksummer.Init();
40 	}
41 
42 	virtual ssize_t Write(const void* buffer, size_t size)
43 	{
44 		if (size > 0)
45 			fChecksummer.Update(buffer, size);
46 		return (ssize_t)size;
47 	}
48 
49 	BString Digest()
50 	{
51 		const uint8* digest = fChecksummer.Digest();
52 		BString hex;
53 		size_t length = fChecksummer.DigestLength();
54 		char* buffer = hex.LockBuffer(length * 2);
55 		if (buffer == NULL)
56 		{
57 			throw std::bad_alloc();
58 		}
59 
60 		for (size_t i = 0; i < length; i++)
61 			snprintf(buffer + 2 * i, 3, "%02x", digest[i]);
62 
63 		hex.UnlockBuffer();
64 		return hex;
65 	}
66 
67 private:
68 	SHA256	fChecksummer;
69 };
70 
71 
72 static BPositionIO*
73 create_stdio(bool isInput)
74 {
75 	BFdIO* dataIO = new BFdIO(isInput ? 0 : 1, false);
76 	return new BDataPositionIOWrapper(dataIO);
77 }
78 
79 
80 int
81 command_checksum(int argc, const char* const* argv)
82 {
83 	bool quiet = false;
84 	bool verbose = false;
85 
86 	while (true) {
87 		static struct option sLongOptions[] = {
88 			{ "help", no_argument, 0, 'h' },
89 			{ "quiet", no_argument, 0, 'q' },
90 			{ "verbose", no_argument, 0, 'v' },
91 			{ 0, 0, 0, 0 }
92 		};
93 
94 		opterr = 0; // don't print errors
95 		int c = getopt_long(argc, (char**)argv, "+hqv",
96 			sLongOptions, NULL);
97 		if (c == -1)
98 			break;
99 
100 		switch (c) {
101 			case 'h':
102 				print_usage_and_exit(false);
103 				break;
104 
105 			case 'q':
106 				quiet = true;
107 				break;
108 
109 			case 'v':
110 				verbose = true;
111 				break;
112 
113 			default:
114 				print_usage_and_exit(true);
115 				break;
116 		}
117 	}
118 
119 	// The optional remaining argument is the package file.
120 	if (argc - optind > 1)
121 		print_usage_and_exit(true);
122 
123 	const char* packageFileName = optind < argc ? argv[optind++] : NULL;
124 
125 	// open the input package
126 	status_t error = B_OK;
127 	BPositionIO* inputFile;
128 	if (packageFileName == NULL || strcmp(packageFileName, "-") == 0) {
129 		inputFile = create_stdio(true);
130 	} else {
131 		BFile* inputFileFile = new BFile;
132 		error = inputFileFile->SetTo(packageFileName, O_RDONLY);
133 		if (error != B_OK) {
134 			fprintf(stderr, "Error: Failed to open input file \"%s\": %s\n",
135 				packageFileName, strerror(error));
136 			return 1;
137 		}
138 		inputFile = inputFileFile;
139 	}
140 
141 	// write the output package to a BDataIO that computes the checksum
142 	BPackageWriterParameters writerParameters;
143 	writerParameters.SetCompressionLevel(0);
144 	writerParameters.SetCompression(
145 		BPackageKit::BHPKG::B_HPKG_COMPRESSION_NONE);
146 
147 	PackageWriterListener listener(verbose, quiet);
148 	BPackageWriter packageWriter(&listener);
149 	ChecksumIO outputFile;
150 	error = packageWriter.Init(new BDataPositionIOWrapper(&outputFile), true,
151 		&writerParameters);
152 	if (error != B_OK)
153 		return 1;
154 
155 	error = packageWriter.Recompress(inputFile);
156 	if (error != B_OK)
157 		return 1;
158 
159 	printf("%s\n", outputFile.Digest().String());
160 
161 	return 0;
162 }
163