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