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