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: 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 33 int32 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 49 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 59 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 77 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 90 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 104 DirectoryBlock::HashValueAt(int32 index) const 105 { 106 return index >= HashSize() ? -1 : (int32)B_BENDIAN_TO_HOST_INT32(HashTable()[index]); 107 } 108 109 110 int32 111 DirectoryBlock::FirstHashValue(int32 &index) const 112 { 113 index = -1; 114 return NextHashValue(index); 115 } 116 117 118 int32 119 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 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 148 HashIterator::~HashIterator() 149 { 150 free(fData); 151 } 152 153 154 status_t 155 HashIterator::InitCheck() 156 { 157 return fData != NULL ? B_OK : B_NO_MEMORY; 158 } 159 160 161 void 162 HashIterator::Goto(int32 index) 163 { 164 fCurrent = index; 165 fBlock = fDirectory.HashValueAt(index); 166 } 167 168 169 NodeBlock * 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 %ld bad checksum.\n", fBlock); 190 return NULL; 191 } 192 193 fBlock = fNode.HashChain(); 194 195 return &fNode; 196 } 197 198 199 void 200 HashIterator::Rewind() 201 { 202 fCurrent = 0; 203 fBlock = -1; 204 } 205 206 207 // #pragma mark - 208 209 210 status_t 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