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