xref: /haiku/src/system/boot/loader/file_systems/amiga_ffs/amiga_ffs.cpp (revision 99d027cd0238c1d86da86d7c3f4200509ccc61a6)
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 
20 using namespace FFS;
21 
22 
23 class 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 
34 int32
35 BCPLString::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 
49 status_t
50 BaseBlock::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 
59 status_t
60 BaseBlock::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 
77 char
78 DirectoryBlock::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 
90 int32
91 DirectoryBlock::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 
104 int32
105 DirectoryBlock::HashValueAt(int32 index) const
106 {
107 	return index >= HashSize() ? -1 : (int32)B_BENDIAN_TO_HOST_INT32(HashTable()[index]);
108 }
109 
110 
111 int32
112 DirectoryBlock::FirstHashValue(int32 &index) const
113 {
114 	index = -1;
115 	return NextHashValue(index);
116 }
117 
118 
119 int32
120 DirectoryBlock::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 
137 HashIterator::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 
149 HashIterator::~HashIterator()
150 {
151 	free(fData);
152 }
153 
154 
155 status_t
156 HashIterator::InitCheck()
157 {
158 	return fData != NULL ? B_OK : B_NO_MEMORY;
159 }
160 
161 
162 void
163 HashIterator::Goto(int32 index)
164 {
165 	fCurrent = index;
166 	fBlock = fDirectory.HashValueAt(index);
167 }
168 
169 
170 NodeBlock *
171 HashIterator::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 
200 void
201 HashIterator::Rewind()
202 {
203 	fCurrent = 0;
204 	fBlock = -1;
205 }
206 
207 
208 //	#pragma mark -
209 
210 
211 status_t
212 FFS::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