1 /* 2 * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Inode.h" 8 9 10 void 11 xfs_inode_t::SwapEndian() 12 { 13 di_magic = B_BENDIAN_TO_HOST_INT16(di_magic); 14 di_mode = B_BENDIAN_TO_HOST_INT16(di_mode); 15 di_onlink = B_BENDIAN_TO_HOST_INT16(di_onlink); 16 di_uid = B_BENDIAN_TO_HOST_INT32(di_uid); 17 di_gid = B_BENDIAN_TO_HOST_INT32(di_gid); 18 di_nlink = B_BENDIAN_TO_HOST_INT32(di_nlink); 19 di_projid = B_BENDIAN_TO_HOST_INT16(di_projid); 20 di_flushiter = B_BENDIAN_TO_HOST_INT16(di_flushiter); 21 di_atime.t_sec = B_BENDIAN_TO_HOST_INT32(di_atime.t_sec); 22 di_atime.t_nsec = B_BENDIAN_TO_HOST_INT32(di_atime.t_nsec); 23 di_mtime.t_sec = B_BENDIAN_TO_HOST_INT32(di_mtime.t_sec); 24 di_mtime.t_nsec = B_BENDIAN_TO_HOST_INT32(di_mtime.t_nsec); 25 di_ctime.t_sec = B_BENDIAN_TO_HOST_INT32(di_ctime.t_sec); 26 di_ctime.t_nsec = B_BENDIAN_TO_HOST_INT32(di_ctime.t_nsec); 27 di_size = B_BENDIAN_TO_HOST_INT64(di_size); 28 di_nblocks = B_BENDIAN_TO_HOST_INT64(di_nblocks); 29 di_extsize = B_BENDIAN_TO_HOST_INT32(di_extsize); 30 di_nextents = B_BENDIAN_TO_HOST_INT32(di_nextents); 31 di_anextents = B_BENDIAN_TO_HOST_INT16(di_anextents); 32 di_dmevmask = B_BENDIAN_TO_HOST_INT32(di_dmevmask); 33 di_dmstate = B_BENDIAN_TO_HOST_INT16(di_dmstate); 34 di_flags = B_BENDIAN_TO_HOST_INT16(di_flags); 35 di_gen = B_BENDIAN_TO_HOST_INT32(di_gen); 36 di_next_unlinked = B_BENDIAN_TO_HOST_INT32(di_next_unlinked); 37 } 38 39 40 uint8 41 xfs_inode_t::ForkOffset() const 42 { 43 return di_forkoff; 44 } 45 46 47 xfs_rfsblock_t 48 xfs_inode_t::BlockCount() const 49 { 50 return di_nblocks; 51 } 52 53 54 xfs_fsize_t 55 xfs_inode_t::Size() const 56 { 57 return di_size; 58 } 59 60 61 mode_t 62 xfs_inode_t::Mode() const 63 { 64 return di_mode; 65 } 66 67 68 uint32 69 xfs_inode_t::UserId() const 70 { 71 return di_uid; 72 } 73 74 75 uint32 76 xfs_inode_t::GroupId() const 77 { 78 return di_gid; 79 } 80 81 82 void 83 xfs_inode_t::GetModificationTime(struct timespec& stamp) 84 { 85 stamp.tv_sec = di_mtime.t_sec; 86 stamp.tv_nsec = di_mtime.t_nsec; 87 } 88 89 90 void 91 xfs_inode_t::GetAccessTime(struct timespec& stamp) 92 { 93 stamp.tv_sec = di_atime.t_sec; 94 stamp.tv_nsec = di_atime.t_nsec; 95 } 96 97 98 void 99 xfs_inode_t::GetChangeTime(struct timespec& stamp) 100 { 101 stamp.tv_sec = di_ctime.t_sec; 102 stamp.tv_nsec = di_ctime.t_nsec; 103 } 104 105 106 uint32 107 xfs_inode_t::NLink() const 108 { 109 return di_nlink; 110 } 111 112 113 int8 114 xfs_inode_t::Version() const 115 { 116 return di_version; 117 } 118 119 120 uint16 121 xfs_inode_t::Flags() const 122 { 123 return di_flags; 124 } 125 126 127 int8 128 xfs_inode_t::Format() const 129 { 130 return di_format; 131 } 132 133 134 xfs_extnum_t 135 xfs_inode_t::DataExtentsCount() const 136 { 137 return di_nextents; 138 } 139 140 141 Inode::Inode(Volume* volume, xfs_ino_t id) 142 : 143 fVolume(volume), 144 fId(id) 145 { 146 147 } 148 149 150 status_t 151 Inode::Init() 152 { 153 fNode = new(std::nothrow) xfs_inode_t; 154 if (fNode == NULL) 155 return B_NO_MEMORY; 156 157 uint16 inodeSize = fVolume->InodeSize(); 158 fBuffer = new(std::nothrow) char[inodeSize]; 159 if (fBuffer == NULL) 160 return B_NO_MEMORY; 161 162 status_t status = GetFromDisk(); 163 if (status == B_OK) { 164 if (fNode->di_magic == INODE_MAGIC) { 165 TRACE("Init(): Inode successfully read.\n"); 166 status = B_OK; 167 } else { 168 TRACE("Init(): Inode wasn't read successfully!\n"); 169 status = B_BAD_VALUE; 170 } 171 } 172 173 return status; 174 } 175 176 177 bool 178 Inode::HasFileTypeField() const 179 { 180 return fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE; 181 } 182 183 184 status_t 185 Inode::CheckPermissions(int accessMode) const 186 { 187 // you never have write access to a read-only volume 188 if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly()) 189 return B_READ_ONLY_DEVICE; 190 191 return check_access_permissions(accessMode, Mode(), 192 (uint32)fNode->GroupId(), (uint32)fNode->UserId()); 193 } 194 195 196 status_t 197 Inode::GetFromDisk() 198 { 199 xfs_agnumber_t agNo = INO_TO_AGNO(fId, fVolume); 200 // Get the AG number from the inode 201 uint32 agRelativeInodeNo = INO_TO_AGINO(fId, fVolume->AgInodeBits()); 202 // AG relative ino # 203 xfs_agblock_t agBlock = INO_TO_AGBLOCK(agRelativeInodeNo, fVolume); 204 // AG relative block number 205 xfs_off_t offset = INO_TO_BLOCKOFFSET(fId, fVolume); 206 // Offset into the block1 207 uint32 len = fVolume->InodeSize(); 208 // Inode len to read (size of inode) 209 210 TRACE("AgNumber: (%d), AgRelativeIno: (%d), AgRelativeBlockNum: (%d)," 211 "Offset: (%d), len: (%d)\n", agNo, 212 agRelativeInodeNo, agBlock, offset, len); 213 214 if (agNo > fVolume->AgCount()) { 215 ERROR("Inode::GetFromDisk : AG Number more than number of AGs"); 216 return B_ENTRY_NOT_FOUND; 217 } 218 219 xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks(); 220 221 xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(), 222 ((uint64)(agNo * numberOfBlocksInAg) + agBlock)); 223 224 xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE + offset * len; 225 226 if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) { 227 ERROR("Inode::Inode(): IO Error"); 228 return B_IO_ERROR; 229 } 230 231 memcpy(fNode, fBuffer, INODE_CORE_UNLINKED_SIZE); 232 fNode->SwapEndian(); 233 234 return B_OK; 235 } 236 237 238 uint64 239 Inode::FileSystemBlockToAddr(uint64 block) 240 { 241 xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks(); 242 243 uint64 agNo = FSBLOCKS_TO_AGNO(block, fVolume); 244 uint64 agBlockNo = FSBLOCKS_TO_AGBLOCKNO(block, fVolume); 245 246 xfs_fsblock_t actualBlockToRead = 247 FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(), 248 ((uint64)(agNo * numberOfBlocksInAg) + agBlockNo)); 249 TRACE("blockToRead:(%d)\n", actualBlockToRead); 250 251 uint64 readPos = actualBlockToRead * (BASICBLOCKSIZE); 252 return readPos; 253 } 254 255 256 Inode::~Inode() 257 { 258 delete fBuffer; 259 delete fNode; 260 } 261 262 263 /* 264 * Basically take 4 characters at a time as long as you can, and xor with 265 * previous hashVal after rotating 4 bits of hashVal. Likewise, continue 266 * xor and rotating. This is quite a generic hash function. 267 */ 268 uint32 269 hashfunction(const char* name, int length) 270 { 271 uint32 hashVal = 0; 272 int lengthCovered = 0; 273 int index = 0; 274 if (length >= 4) { 275 for (;index < length && (length - index) >= 4; index += 4) 276 { 277 lengthCovered += 4; 278 hashVal = (name[index] << 21) ^ (name[index+1] << 14) 279 ^ (name[index+2] << 7) ^ (name[index+3] << 0) 280 ^ ((hashVal << 28) | (hashVal >> (4))); 281 } 282 } 283 284 int leftToCover = length - lengthCovered; 285 if (leftToCover == 3) { 286 hashVal = (name[index] << 14) ^ (name[index+1] << 7) 287 ^ (name[index+2] << 0) ^ ((hashVal << 21) | (hashVal >> (11))); 288 } 289 if (leftToCover == 2) { 290 hashVal = (name[index] << 7) ^ (name[index+1] << 0) 291 ^ ((hashVal << 14) | (hashVal >> (32 - 14))); 292 } 293 if (leftToCover == 1) { 294 hashVal = (name[index] << 0) 295 ^ ((hashVal << 7) | (hashVal >> (32 - 7))); 296 } 297 298 return hashVal; 299 } 300