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