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 "File.h" 8 9#include <errno.h> 10#include <sys/stat.h> 11#include <unistd.h> 12 13#include <util/kernel_cpp.h> 14 15 16namespace FFS { 17 18class Stream { 19 public: 20 Stream(int device, FileBlock &node); 21 ~Stream(); 22 23 status_t InitCheck(); 24 ssize_t ReadAt(off_t offset, uint8 *buffer, size_t size); 25 26 private: 27 int32 BlockOffset(off_t offset) const; 28 int32 BlockIndex(off_t offset) const; 29 int32 ExtensionBlockOffset(off_t offset) const; 30 status_t ReadNextExtension(); 31 32 int fDevice; 33 FileBlock &fNode; 34 FileBlock fBlock; 35 int32 fExtensionBlockOffset; 36}; 37 38 39Stream::Stream(int device, FileBlock &node) 40 : 41 fDevice(device), 42 fNode(node) 43{ 44 void *buffer = malloc(fNode.BlockSize()); 45 if (buffer == NULL) 46 return; 47 48 fExtensionBlockOffset = 0; 49 fBlock.SetTo(buffer, fNode.BlockSize()); 50} 51 52 53Stream::~Stream() 54{ 55 free(fBlock.BlockData()); 56} 57 58 59status_t 60Stream::InitCheck() 61{ 62 return fBlock.BlockData() != NULL ? B_OK : B_NO_MEMORY; 63} 64 65 66int32 67Stream::BlockOffset(off_t offset) const 68{ 69 return offset % fNode.BlockSize(); 70} 71 72 73int32 74Stream::BlockIndex(off_t offset) const 75{ 76 return (offset % (fNode.BlockSize() * fNode.NumDataBlocks())) / fNode.BlockSize(); 77} 78 79 80int32 81Stream::ExtensionBlockOffset(off_t offset) const 82{ 83 return offset / (fNode.BlockSize() * fNode.NumDataBlocks()); 84} 85 86 87status_t 88Stream::ReadNextExtension() 89{ 90 int32 next; 91 if (fExtensionBlockOffset == 0) 92 next = fNode.NextExtension(); 93 else 94 next = fBlock.NextExtension(); 95 96 if (read_pos(fDevice, next * fNode.BlockSize(), fBlock.BlockData(), fNode.BlockSize()) < B_OK) 97 return B_ERROR; 98 99 return fBlock.ValidateCheckSum(); 100} 101 102 103ssize_t 104Stream::ReadAt(off_t offset, uint8 *buffer, size_t size) 105{ 106 if (offset < 0) 107 return B_BAD_VALUE; 108 if (offset + size > fNode.Size()) 109 size = fNode.Size() - offset; 110 111 ssize_t bytesLeft = (ssize_t)size; 112 113 while (bytesLeft != 0) { 114 int32 extensionBlock = ExtensionBlockOffset(offset); 115 116 // get the right extension block 117 118 if (extensionBlock < fExtensionBlockOffset) 119 fExtensionBlockOffset = 1; 120 121 while (fExtensionBlockOffset < extensionBlock) { 122 if (ReadNextExtension() != B_OK) 123 return B_ERROR; 124 125 fExtensionBlockOffset++; 126 } 127 128 // read the data block into memory 129 130 int32 block; 131 if (extensionBlock == 0) 132 block = fNode.DataBlock(BlockIndex(offset)); 133 else 134 block = fBlock.DataBlock(BlockIndex(offset)); 135 136 int32 blockOffset = BlockOffset(offset); 137 int32 toRead = fNode.BlockSize() - blockOffset; 138 if (toRead > bytesLeft) 139 toRead = bytesLeft; 140 141 ssize_t bytesRead = read_pos(fDevice, block * fNode.BlockSize() + blockOffset, 142 buffer, toRead); 143 if (bytesRead < 0) 144 return errno; 145 146 bytesLeft -= bytesRead; 147 buffer += bytesRead; 148 offset += fNode.BlockSize() - blockOffset; 149 } 150 151 return size; 152} 153 154 155// #pragma mark - 156 157 158File::File(Volume &volume, int32 block) 159 : 160 fVolume(volume) 161{ 162 void *data = malloc(volume.BlockSize()); 163 if (data == NULL) 164 return; 165 166 if (read_pos(volume.Device(), block * volume.BlockSize(), data, volume.BlockSize()) == volume.BlockSize()) 167 fNode.SetTo(data, volume.BlockSize()); 168} 169 170 171File::~File() 172{ 173} 174 175 176status_t 177File::InitCheck() 178{ 179 if (!fNode.IsFile()) 180 return B_BAD_TYPE; 181 182 return fNode.ValidateCheckSum(); 183} 184 185 186status_t 187File::Open(void **_cookie, int mode) 188{ 189 Stream *stream = new(nothrow) Stream(fVolume.Device(), fNode); 190 if (stream == NULL) 191 return B_NO_MEMORY; 192 193 if (stream->InitCheck() != B_OK) { 194 delete stream; 195 return B_NO_MEMORY; 196 } 197 198 *_cookie = (void *)stream; 199 return B_OK; 200} 201 202 203status_t 204File::Close(void *cookie) 205{ 206 Stream *stream = (Stream *)cookie; 207 208 delete stream; 209 return B_OK; 210} 211 212 213ssize_t 214File::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) 215{ 216 Stream *stream = (Stream *)cookie; 217 if (stream == NULL) 218 return B_BAD_VALUE; 219 220 return stream->ReadAt(pos, (uint8 *)buffer, bufferSize); 221} 222 223 224ssize_t 225File::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 226{ 227 return EROFS; 228} 229 230 231status_t 232File::GetName(char *nameBuffer, size_t bufferSize) const 233{ 234 return fNode.GetName(nameBuffer, bufferSize); 235} 236 237 238int32 239File::Type() const 240{ 241 return S_IFREG; 242} 243 244 245off_t 246File::Size() const 247{ 248 return fNode.Size(); 249} 250 251 252ino_t 253File::Inode() const 254{ 255 return fNode.HeaderKey(); 256} 257 258} // namespace FFS 259