1/*
2** Copyright 2003, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3** Distributed under the terms of the OpenBeOS License.
4*/
5
6
7#include "amiga_ffs.h"
8
9#include <boot/partitions.h>
10#include <boot/platform.h>
11#include <util/kernel_cpp.h>
12
13#include <string.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18
19
20using namespace FFS;
21
22
23class BCPLString {
24	public:
25		uint8 Length() { return fLength; }
26		const char *String() { return (const char *)(&fLength + 1); }
27		int32 CopyTo(char *name, size_t size);
28
29	private:
30		uint8	fLength;
31};
32
33
34int32
35BCPLString::CopyTo(char *name, size_t size)
36{
37	int32 length = size - 1 > Length() ? Length() : size - 1;
38
39	memcpy(name, String(), length);
40	name[length] = '\0';
41
42	return length;
43}
44
45
46//	#pragma mark -
47
48
49status_t
50BaseBlock::GetNameBackOffset(int32 offset, char *name, size_t size) const
51{
52	BCPLString *string = (BCPLString *)&fData[fSize - offset];
53	string->CopyTo(name, size);
54
55	return B_OK;
56}
57
58
59status_t
60BaseBlock::ValidateCheckSum() const
61{
62	if (fData == NULL)
63		return B_NO_INIT;
64
65	int32 sum = 0;
66	for (int32 index = 0; index < fSize; index++) {
67		sum += Offset(index);
68	}
69
70	return sum == 0 ? B_OK : B_BAD_DATA;
71}
72
73
74//	#pragma mark -
75
76
77char
78DirectoryBlock::ToUpperChar(int32 type, char c) const
79{
80	// Taken from Ralph Babel's "The Amiga Guru Book" (1993), section 15.3.4.3
81
82	if (type == DT_AMIGA_OFS || type == DT_AMIGA_FFS)
83		return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
84
85	return (c >= '\340' && c <= '\376' && c != '\367')
86		|| (c >= 'a' && c <= 'z') ? c + ('A' - 'a') : c;
87}
88
89
90int32
91DirectoryBlock::HashIndexFor(int32 type, const char *name) const
92{
93	int32 hash = strlen(name);
94
95	while (name[0]) {
96		hash = (hash * 13 + ToUpperChar(type, name[0])) & 0x7ff;
97		name++;
98	}
99
100	return hash % HashSize();
101}
102
103
104int32
105DirectoryBlock::HashValueAt(int32 index) const
106{
107	return index >= HashSize() ? -1 : (int32)B_BENDIAN_TO_HOST_INT32(HashTable()[index]);
108}
109
110
111int32
112DirectoryBlock::FirstHashValue(int32 &index) const
113{
114	index = -1;
115	return NextHashValue(index);
116}
117
118
119int32
120DirectoryBlock::NextHashValue(int32 &index) const
121{
122	index++;
123
124	int32 value;
125	while ((value = HashValueAt(index)) == 0) {
126		if (++index >= HashSize())
127			return -1;
128	}
129
130	return value;
131}
132
133
134//	#pragma mark -
135
136
137HashIterator::HashIterator(int32 device, DirectoryBlock &directory)
138	:
139	fDirectory(directory),
140	fDevice(device),
141	fCurrent(0),
142	fBlock(-1)
143{
144	fData = (int32 *)malloc(directory.BlockSize());
145	fNode.SetTo(directory.BlockData(), directory.BlockSize());
146}
147
148
149HashIterator::~HashIterator()
150{
151	free(fData);
152}
153
154
155status_t
156HashIterator::InitCheck()
157{
158	return fData != NULL ? B_OK : B_NO_MEMORY;
159}
160
161
162void
163HashIterator::Goto(int32 index)
164{
165	fCurrent = index;
166	fBlock = fDirectory.HashValueAt(index);
167}
168
169
170NodeBlock *
171HashIterator::GetNext(int32 &block)
172{
173	if (fBlock == -1) {
174		// first entry
175		fBlock = fDirectory.FirstHashValue(fCurrent);
176	} else if (fBlock == 0) {
177		fBlock = fDirectory.NextHashValue(fCurrent);
178	}
179
180	if (fBlock == -1)
181		return NULL;
182
183	block = fBlock;
184
185	if (read_pos(fDevice, fBlock * fNode.BlockSize(), fData, fNode.BlockSize()) < B_OK)
186		return NULL;
187
188	fNode.SetTo(fData);
189	if (fNode.ValidateCheckSum() != B_OK) {
190		dprintf("block at %ld bad checksum.\n", fBlock);
191		return NULL;
192	}
193
194	fBlock = fNode.HashChain();
195
196	return &fNode;
197}
198
199
200void
201HashIterator::Rewind()
202{
203	fCurrent = 0;
204	fBlock = -1;
205}
206
207
208//	#pragma mark -
209
210
211status_t
212FFS::get_root_block(int fDevice, char *buffer, int32 blockSize, off_t partitionSize)
213{
214	// calculate root block position (it depends on the block size)
215
216	// ToDo: get the number of reserved blocks out of the disk_environment structure??
217	//		(from the amiga_rdb module)
218	int32 reservedBlocks = 2;
219	off_t offset = (((partitionSize / blockSize) - 1 - reservedBlocks) / 2) + reservedBlocks;
220		// ToDo: this calculation might be incorrect for certain cases.
221
222	if (read_pos(fDevice, offset * blockSize, buffer, blockSize) < B_OK)
223		return B_ERROR;
224
225	RootBlock root(buffer, blockSize);
226	if (root.ValidateCheckSum() < B_OK)
227		return B_BAD_DATA;
228
229	//printf("primary = %ld, secondary = %ld\n", root.PrimaryType(), root.SecondaryType());
230	if (!root.IsRootBlock())
231		return B_BAD_TYPE;
232
233	return B_OK;
234}
235
236