1 /* 2 * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com 3 * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 #include "Inode.h" 8 #include <string.h> 9 10 11 #define TRACE_UFS2 12 #ifdef TRACE_UFS2 13 #define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x) 14 #else 15 #define TRACE(x...) ; 16 #endif 17 #define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x) 18 19 20 Inode::Inode(Volume* volume, ino_t id) 21 : 22 fVolume(volume), 23 fID(id), 24 fCache(NULL), 25 fMap(NULL) 26 { 27 rw_lock_init(&fLock, "ufs2 inode"); 28 29 int fd = fVolume->Device(); 30 ufs2_super_block* superblock = (ufs2_super_block* )&fVolume->SuperBlock(); 31 int64_t fs_block = ino_to_fsba(superblock, id); 32 int64_t offset_in_block = ino_to_fsbo(superblock, id); 33 int64_t offset = fs_block * superblock->fs_fsize + offset_in_block * sizeof(fNode); 34 35 if (read_pos(fd, offset, (void*)&fNode, sizeof(fNode)) != sizeof(fNode)) { 36 ERROR("Inode::Inode(): IO Error\n"); 37 fInitStatus = B_IO_ERROR; 38 return; 39 } 40 fInitStatus = B_OK; 41 42 if (fInitStatus == B_OK) { 43 if (!IsDirectory() && !IsSymLink()) { 44 fCache = file_cache_create(fVolume->ID(), ID(), Size()); 45 fMap = file_map_create(fVolume->ID(), ID(), Size()); 46 } 47 } 48 } 49 50 51 Inode::Inode(Volume* volume, ino_t id, const ufs2_inode& item) 52 : 53 fVolume(volume), 54 fID(id), 55 fCache(NULL), 56 fMap(NULL), 57 fInitStatus(B_OK), 58 fNode(item) 59 { 60 if (!IsDirectory() && !IsSymLink()) { 61 fCache = file_cache_create(fVolume->ID(), ID(), Size()); 62 fMap = file_map_create(fVolume->ID(), ID(), Size()); 63 } 64 } 65 66 67 Inode::Inode(Volume* volume) 68 : 69 fVolume(volume), 70 fID(0), 71 fCache(NULL), 72 fMap(NULL), 73 fInitStatus(B_NO_INIT) 74 { 75 rw_lock_init(&fLock, "ufs2 inode"); 76 } 77 78 79 Inode::~Inode() 80 { 81 TRACE("Inode destructor\n"); 82 file_cache_delete(FileCache()); 83 file_map_delete(Map()); 84 TRACE("Inode destructor: Done\n"); 85 } 86 87 88 status_t 89 Inode::InitCheck() 90 { 91 return fInitStatus; 92 } 93 94 95 status_t 96 Inode::ReadAt(off_t file_offset, uint8* buffer, size_t* _length) 97 { 98 int fd = fVolume->Device(); 99 ufs2_super_block super_block = fVolume->SuperBlock(); 100 int32_t blockSize = super_block.fs_bsize; 101 off_t pos; 102 int64_t size = Size(); 103 off_t startBlockNumber = file_offset / blockSize; 104 off_t endBlockNumber = (file_offset + *_length) / blockSize; 105 off_t blockOffset = file_offset % blockSize; 106 ssize_t length = 0; 107 if (size <= file_offset || size < 0 || file_offset < 0) { 108 *_length = 0; 109 return B_OK; 110 } 111 if ((int64_t) *_length > size - file_offset) 112 *_length = size - file_offset; 113 if (startBlockNumber != endBlockNumber) { 114 ssize_t remainingLength = blockSize - blockOffset; 115 for (; startBlockNumber <= endBlockNumber; startBlockNumber++) { 116 //code for reading multiple blocks 117 pos = FindBlock(startBlockNumber, blockOffset); 118 if (remainingLength > (int64_t) *_length - length) 119 remainingLength = *_length - length; 120 length += read_pos(fd, pos, buffer + length, remainingLength); 121 blockOffset = 0; 122 remainingLength = *_length - length; 123 remainingLength = blockSize; 124 } 125 *_length = length; 126 return B_OK; 127 } 128 pos = FindBlock(startBlockNumber, blockOffset); 129 length = read_pos(fd, pos, buffer, *_length); 130 *_length = length; 131 return B_OK; 132 133 } 134 135 136 off_t 137 Inode::FindBlock(off_t blockNumber, off_t blockOffset) 138 { 139 int fd = fVolume->Device(); 140 ufs2_super_block super_block = fVolume->SuperBlock(); 141 int32_t blockSize = super_block.fs_bsize; 142 int32_t fragmentSize = super_block.fs_fsize; 143 off_t indirectOffset; 144 int64_t directBlock; 145 off_t numberOfBlockPointers = blockSize / 8; 146 const off_t numberOfIndirectBlocks = numberOfBlockPointers; 147 const off_t numberOfDoubleIndirectBlocks = numberOfBlockPointers 148 * numberOfBlockPointers; 149 if (blockNumber < 12) { 150 // read from direct block 151 return GetBlockPointer(blockNumber) * fragmentSize + blockOffset; 152 153 } else if (blockNumber < numberOfIndirectBlocks + 12) { 154 //read from indirect block 155 blockNumber = blockNumber - 12; 156 indirectOffset = GetIndirectBlockPointer() * 157 fragmentSize + (8 * blockNumber); 158 read_pos(fd, indirectOffset, 159 (void*)&directBlock, sizeof(directBlock)); 160 161 return directBlock * fragmentSize + blockOffset; 162 163 } else if (blockNumber < numberOfDoubleIndirectBlocks 164 + numberOfIndirectBlocks + 12) { 165 // Data is in double indirect block 166 // Subract the already read blocks 167 blockNumber = blockNumber - numberOfBlockPointers - 12; 168 // Calculate indirect block inside double indirect block 169 off_t indirectBlockNumber = blockNumber / numberOfBlockPointers; 170 indirectOffset = GetDoubleIndirectBlockPtr() * 171 fragmentSize + (8 * indirectBlockNumber); 172 173 int64_t indirectPointer; 174 read_pos(fd, indirectOffset, 175 (void*)&indirectPointer, sizeof(directBlock)); 176 177 indirectOffset = indirectPointer * fragmentSize 178 + (8 * (blockNumber % numberOfBlockPointers)); 179 180 read_pos(fd, indirectOffset, 181 (void*)&directBlock, sizeof(directBlock)); 182 183 return directBlock * fragmentSize + blockOffset; 184 185 } else if (blockNumber < (numberOfIndirectBlocks 186 * numberOfDoubleIndirectBlocks) 187 + (numberOfDoubleIndirectBlocks + numberOfBlockPointers + 12)) { 188 // Reading from triple indirect block 189 blockNumber = blockNumber - numberOfDoubleIndirectBlocks 190 - numberOfBlockPointers - 12; 191 192 // Get double indirect block 193 // Double indirect block no 194 off_t indirectBlockNumber = blockNumber / numberOfDoubleIndirectBlocks; 195 196 // offset to double indirect block ptr 197 indirectOffset = GetTripleIndirectBlockPtr() * 198 fragmentSize + (8 * indirectBlockNumber); 199 200 int64_t indirectPointer; 201 // Get the double indirect block ptr 202 read_pos(fd, indirectOffset, 203 (void*)&indirectPointer, sizeof(directBlock)); 204 205 // Get the indirect block 206 // number of indirect block ptr 207 indirectBlockNumber = blockNumber / numberOfBlockPointers; 208 // Indirect block ptr offset 209 indirectOffset = indirectPointer * fragmentSize 210 + (8 * indirectBlockNumber); 211 212 read_pos(fd, indirectOffset, 213 (void*)&indirectPointer, sizeof(directBlock)); 214 215 // Get direct block pointer 216 indirectOffset = indirectPointer * fragmentSize 217 + (8 * (blockNumber % numberOfBlockPointers)); 218 219 read_pos(fd, indirectOffset, 220 (void*)&directBlock, sizeof(directBlock)); 221 222 return directBlock * fragmentSize + blockOffset; 223 } 224 225 return B_BAD_VALUE; 226 } 227 228 229 status_t 230 Inode::ReadLink(char* buffer, size_t *_bufferSize) 231 { 232 strlcpy(buffer, fNode.symlinkpath, *_bufferSize); 233 return B_OK; 234 } 235 236 237 status_t 238 Inode::CheckPermissions(int accessMode) const 239 { 240 // you never have write access to a read-only volume 241 if ((accessMode & W_OK) != 0/* && fVolume->IsReadOnly()*/) 242 return B_READ_ONLY_DEVICE; 243 244 return check_access_permissions(accessMode, Mode(), (gid_t)GroupID(), 245 (uid_t)UserID()); 246 } 247