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 19using namespace FFS; 20 21 22class BCPLString { 23 public: 24 uint8 Length() { return fLength; } 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 33int32 34BCPLString::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 48status_t 49BaseBlock::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 58status_t 59BaseBlock::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 76char 77DirectoryBlock::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 89int32 90DirectoryBlock::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 103int32 104DirectoryBlock::HashValueAt(int32 index) const 105{ 106 return index >= HashSize() ? -1 : (int32)B_BENDIAN_TO_HOST_INT32(HashTable()[index]); 107} 108 109 110int32 111DirectoryBlock::FirstHashValue(int32 &index) const 112{ 113 index = -1; 114 return NextHashValue(index); 115} 116 117 118int32 119DirectoryBlock::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 136HashIterator::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 148HashIterator::~HashIterator() 149{ 150 free(fData); 151} 152 153 154status_t 155HashIterator::InitCheck() 156{ 157 return fData != NULL ? B_OK : B_NO_MEMORY; 158} 159 160 161void 162HashIterator::Goto(int32 index) 163{ 164 fCurrent = index; 165 fBlock = fDirectory.HashValueAt(index); 166} 167 168 169NodeBlock * 170HashIterator::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 199void 200HashIterator::Rewind() 201{ 202 fCurrent = 0; 203 fBlock = -1; 204} 205 206 207// #pragma mark - 208 209 210status_t 211FFS::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