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 16 namespace FFS { 17 18 class 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 39 Stream::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 53 Stream::~Stream() 54 { 55 free(fBlock.BlockData()); 56 } 57 58 59 status_t 60 Stream::InitCheck() 61 { 62 return fBlock.BlockData() != NULL ? B_OK : B_NO_MEMORY; 63 } 64 65 66 int32 67 Stream::BlockOffset(off_t offset) const 68 { 69 return offset % fNode.BlockSize(); 70 } 71 72 73 int32 74 Stream::BlockIndex(off_t offset) const 75 { 76 return (offset % (fNode.BlockSize() * fNode.NumDataBlocks())) / fNode.BlockSize(); 77 } 78 79 80 int32 81 Stream::ExtensionBlockOffset(off_t offset) const 82 { 83 return offset / (fNode.BlockSize() * fNode.NumDataBlocks()); 84 } 85 86 87 status_t 88 Stream::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 103 ssize_t 104 Stream::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 158 File::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 171 File::~File() 172 { 173 } 174 175 176 status_t 177 File::InitCheck() 178 { 179 if (!fNode.IsFile()) 180 return B_BAD_TYPE; 181 182 return fNode.ValidateCheckSum(); 183 } 184 185 186 status_t 187 File::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 203 status_t 204 File::Close(void *cookie) 205 { 206 Stream *stream = (Stream *)cookie; 207 208 delete stream; 209 return B_OK; 210 } 211 212 213 ssize_t 214 File::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 224 ssize_t 225 File::WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) 226 { 227 return EROFS; 228 } 229 230 231 status_t 232 File::GetName(char *nameBuffer, size_t bufferSize) const 233 { 234 return fNode.GetName(nameBuffer, bufferSize); 235 } 236 237 238 int32 239 File::Type() const 240 { 241 return S_IFREG; 242 } 243 244 245 off_t 246 File::Size() const 247 { 248 return fNode.Size(); 249 } 250 251 252 ino_t 253 File::Inode() const 254 { 255 return fNode.HeaderKey(); 256 } 257 258 } // namespace FFS 259