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 {
ChecksumIOChecksumIO37 ChecksumIO()
38 {
39 fChecksummer.Init();
40 }
41
WriteChecksumIO42 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
DigestChecksumIO49 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*
create_stdio(bool isInput)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
command_checksum(int argc,const char * const * argv)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