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