xref: /haiku/src/kits/package/ChecksumAccessors.cpp (revision 1c09002cbee8e797a0f8bbfc5678dfadd39ee1a7)
1 /*
2  * Copyright 2011, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Oliver Tappe <zooey@hirschkaefer.de>
7  */
8 
9 
10 #include <File.h>
11 
12 #include <AutoDeleter.h>
13 #include <SHA256.h>
14 
15 #include <package/ChecksumAccessors.h>
16 
17 
18 namespace BPackageKit {
19 
20 namespace BPrivate {
21 
22 
23 #define NIBBLE_AS_HEX(nibble) \
24 	(nibble >= 10 ? 'a' + nibble - 10 : '0' + nibble)
25 
26 
27 ChecksumAccessor::~ChecksumAccessor()
28 {
29 }
30 
31 
32 ChecksumFileChecksumAccessor::ChecksumFileChecksumAccessor(
33 	const BEntry& checksumFileEntry)
34 	:
35 	fChecksumFileEntry(checksumFileEntry)
36 {
37 }
38 
39 
40 status_t
41 ChecksumFileChecksumAccessor::GetChecksum(BString& checksum) const
42 {
43 	BFile checksumFile(&fChecksumFileEntry, B_READ_ONLY);
44 	status_t result = checksumFile.InitCheck();
45 	if (result != B_OK)
46 		return result;
47 
48 	const int kSHA256ChecksumHexDumpSize = 64;
49 	char* buffer = checksum.LockBuffer(kSHA256ChecksumHexDumpSize);
50 	if (buffer == NULL)
51 		return B_NO_MEMORY;
52 
53 	ssize_t bytesRead = checksumFile.Read(buffer, kSHA256ChecksumHexDumpSize);
54 	buffer[kSHA256ChecksumHexDumpSize] = '\0';
55 	checksum.UnlockBuffer(kSHA256ChecksumHexDumpSize);
56 	if (bytesRead < 0)
57 		return bytesRead;
58 	if (bytesRead != kSHA256ChecksumHexDumpSize)
59 		return B_IO_ERROR;
60 
61 	return B_OK;
62 }
63 
64 
65 GeneralFileChecksumAccessor::GeneralFileChecksumAccessor(
66 	const BEntry& fileEntry, bool skipMissingFile)
67 	:
68 	fFileEntry(fileEntry),
69 	fSkipMissingFile(skipMissingFile)
70 {
71 }
72 
73 
74 status_t
75 GeneralFileChecksumAccessor::GetChecksum(BString& checksum) const
76 {
77 	SHA256 sha;
78 
79 	checksum.Truncate(0);
80 
81 	{
82 		BFile file(&fFileEntry, B_READ_ONLY);
83 		status_t result = file.InitCheck();
84 		if (result != B_OK) {
85 			if (result == B_ENTRY_NOT_FOUND && fSkipMissingFile)
86 				return B_OK;
87 			return result;
88 		}
89 
90 		off_t fileSize;
91 		if ((result = file.GetSize(&fileSize)) != B_OK)
92 			return result;
93 
94 		const int kBlockSize = 64 * 1024;
95 		void* buffer = malloc(kBlockSize);
96 		if (buffer == NULL)
97 			return B_NO_MEMORY;
98 		MemoryDeleter memoryDeleter(buffer);
99 
100 		off_t handledSize = 0;
101 		while (handledSize < fileSize) {
102 			ssize_t bytesRead = file.Read(buffer, kBlockSize);
103 			if (bytesRead < 0)
104 				return bytesRead;
105 
106 			sha.Update(buffer, bytesRead);
107 
108 			handledSize += bytesRead;
109 		}
110 	}
111 
112 	const int kSHA256ChecksumSize = sha.DigestLength();
113 	char* buffer = checksum.LockBuffer(2 * kSHA256ChecksumSize);
114 	if (buffer == NULL)
115 		return B_NO_MEMORY;
116 	const uint8* digest = sha.Digest();
117 	for (int i = 0; i < kSHA256ChecksumSize; ++i) {
118 		uint8 highNibble = (digest[i] & 0xF0) >> 4;
119 		buffer[i * 2] = NIBBLE_AS_HEX(highNibble);
120 		uint8 lowNibble = digest[i] & 0x0F;
121 		buffer[1 + i * 2] = NIBBLE_AS_HEX(lowNibble);
122 	}
123 	buffer[2 * kSHA256ChecksumSize] = '\0';
124 	checksum.UnlockBuffer(2 * kSHA256ChecksumSize);
125 
126 	return B_OK;
127 }
128 
129 
130 }	// namespace BPrivate
131 
132 }	// namespace BPackageKit
133