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