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