1 /* 2 * Copyright 2022, Raghav Sharma, raghavself28@gmail.com 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "LeafAttribute.h" 8 9 #include "VerifyHeader.h" 10 11 12 LeafAttribute::LeafAttribute(Inode* inode) 13 : 14 fInode(inode), 15 fName(NULL), 16 fMap(NULL), 17 fLeafBuffer(NULL) 18 { 19 fLastEntryOffset = 0; 20 } 21 22 23 LeafAttribute::~LeafAttribute() 24 { 25 delete fMap; 26 delete[] fLeafBuffer; 27 } 28 29 30 status_t 31 LeafAttribute::Init() 32 { 33 status_t status = _FillMapEntry(); 34 35 if (status != B_OK) 36 return status; 37 38 status = _FillLeafBuffer(); 39 40 if (status != B_OK) 41 return status; 42 43 AttrLeafHeader* header = AttrLeafHeader::Create(fInode, fLeafBuffer); 44 if (header == NULL) 45 return B_NO_MEMORY; 46 47 if (!VerifyHeader<AttrLeafHeader>(header, fLeafBuffer, fInode, 0, fMap, ATTR_LEAF)) { 48 ERROR("Invalid data header"); 49 delete header; 50 return B_BAD_VALUE; 51 } 52 delete header; 53 54 return B_OK; 55 } 56 57 58 status_t 59 LeafAttribute::_FillMapEntry() 60 { 61 fMap = new(std::nothrow) ExtentMapEntry; 62 if (fMap == NULL) 63 return B_NO_MEMORY; 64 65 void* attributeFork = DIR_AFORK_PTR(fInode->Buffer(), 66 fInode->CoreInodeSize(), fInode->ForkOffset()); 67 68 uint64* pointerToMap = (uint64*)((char*)attributeFork); 69 uint64 firstHalf = pointerToMap[0]; 70 uint64 secondHalf = pointerToMap[1]; 71 //dividing the 128 bits into 2 parts. 72 73 firstHalf = B_BENDIAN_TO_HOST_INT64(firstHalf); 74 secondHalf = B_BENDIAN_TO_HOST_INT64(secondHalf); 75 fMap->br_state = firstHalf >> 63; 76 fMap->br_startoff = (firstHalf & MASK(63)) >> 9; 77 fMap->br_startblock = ((firstHalf & MASK(9)) << 43) | (secondHalf >> 21); 78 fMap->br_blockcount = secondHalf & MASK(21); 79 TRACE("Extent::Init: startoff:(%" B_PRIu64 "), startblock:(%" B_PRIu64 ")," 80 "blockcount:(%" B_PRIu64 "),state:(%" B_PRIu8 ")\n", fMap->br_startoff, fMap->br_startblock, 81 fMap->br_blockcount, fMap->br_state); 82 83 return B_OK; 84 } 85 86 87 status_t 88 LeafAttribute::_FillLeafBuffer() 89 { 90 if (fMap->br_state != 0) 91 return B_BAD_VALUE; 92 93 int len = fInode->DirBlockSize(); 94 fLeafBuffer = new(std::nothrow) char[len]; 95 if (fLeafBuffer == NULL) 96 return B_NO_MEMORY; 97 98 xfs_daddr_t readPos = fInode->FileSystemBlockToAddr(fMap->br_startblock); 99 100 if (read_pos(fInode->GetVolume()->Device(), readPos, fLeafBuffer, len) != len) { 101 ERROR("Extent::FillBlockBuffer(): IO Error"); 102 return B_IO_ERROR; 103 } 104 105 return B_OK; 106 } 107 108 109 status_t 110 LeafAttribute::Open(const char* name, int openMode, attr_cookie** _cookie) 111 { 112 TRACE("LeafAttribute::Open\n"); 113 114 size_t length = strlen(name); 115 status_t status = Lookup(name, &length); 116 if (status < B_OK) 117 return status; 118 119 attr_cookie* cookie = new(std::nothrow) attr_cookie; 120 if (cookie == NULL) 121 return B_NO_MEMORY; 122 123 fName = name; 124 125 // initialize the cookie 126 strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH); 127 cookie->open_mode = openMode; 128 cookie->create = false; 129 130 *_cookie = cookie; 131 return B_OK; 132 } 133 134 135 status_t 136 LeafAttribute::Stat(attr_cookie* cookie, struct stat& stat) 137 { 138 TRACE("LeafAttribute::Stat\n"); 139 140 fName = cookie->name; 141 142 size_t namelength = strlen(fName); 143 144 status_t status; 145 146 // check if this attribute exists 147 status = Lookup(fName, &namelength); 148 149 if(status != B_OK) 150 return status; 151 152 // We have valid attribute entry to stat 153 if (fLocalEntry != NULL) { 154 uint16 valuelen = B_BENDIAN_TO_HOST_INT16(fLocalEntry->valuelen); 155 stat.st_type = B_XATTR_TYPE; 156 stat.st_size = valuelen + fLocalEntry->namelen; 157 } else { 158 uint32 valuelen = B_BENDIAN_TO_HOST_INT32(fRemoteEntry->valuelen); 159 stat.st_type = B_XATTR_TYPE; 160 stat.st_size = valuelen + fRemoteEntry->namelen; 161 } 162 163 return B_OK; 164 } 165 166 167 status_t 168 LeafAttribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* length) 169 { 170 TRACE("LeafAttribute::Read\n"); 171 172 if(pos < 0) 173 return B_BAD_VALUE; 174 175 fName = cookie->name; 176 177 size_t namelength = strlen(fName); 178 179 status_t status; 180 181 status = Lookup(fName, &namelength); 182 183 if (status != B_OK) 184 return status; 185 186 uint32 lengthToRead = 0; 187 188 if (fLocalEntry != NULL) { 189 uint16 valuelen = B_BENDIAN_TO_HOST_INT16(fLocalEntry->valuelen); 190 if (pos + *length > valuelen) 191 lengthToRead = valuelen - pos; 192 else 193 lengthToRead = *length; 194 195 char* ptrToOffset = (char*) fLocalEntry + sizeof(uint16) 196 + sizeof(uint8) + fLocalEntry->namelen; 197 198 memcpy(buffer, ptrToOffset, lengthToRead); 199 200 *length = lengthToRead; 201 202 return B_OK; 203 } else { 204 uint32 valuelen = B_BENDIAN_TO_HOST_INT32(fRemoteEntry->valuelen); 205 if (pos + *length > valuelen) 206 lengthToRead = valuelen - pos; 207 else 208 lengthToRead = *length; 209 210 // For remote value blocks, value is stored in seperate file system block 211 uint32 blkno = B_BENDIAN_TO_HOST_INT32(fRemoteEntry->valueblk); 212 213 xfs_daddr_t readPos = fInode->FileSystemBlockToAddr(blkno); 214 215 if (fInode->Version() == 3) 216 pos += sizeof(AttrRemoteHeader); 217 218 readPos += pos; 219 220 // TODO : Implement remote header checks for V5 file system 221 if (read_pos(fInode->GetVolume()->Device(), readPos, buffer, lengthToRead) 222 != lengthToRead) { 223 ERROR("Extent::FillBlockBuffer(): IO Error"); 224 return B_IO_ERROR; 225 } 226 227 *length = lengthToRead; 228 229 return B_OK; 230 } 231 } 232 233 234 status_t 235 LeafAttribute::GetNext(char* name, size_t* nameLength) 236 { 237 TRACE("LeafAttribute::GetNext\n"); 238 239 AttrLeafHeader* header = AttrLeafHeader::Create(fInode,fLeafBuffer); 240 AttrLeafEntry* firstEntry = (AttrLeafEntry*)(fLeafBuffer + AttrLeafHeader::Size(fInode)); 241 242 int totalEntries = header->Count(); 243 244 delete header; 245 246 for (int i = fLastEntryOffset; i < totalEntries; i++) { 247 248 AttrLeafEntry* entry = 249 (AttrLeafEntry*)((char*)firstEntry + i * sizeof(AttrLeafEntry)); 250 251 uint32 offset = B_BENDIAN_TO_HOST_INT16(entry->nameidx); 252 TRACE("offset:(%" B_PRIu16 ")\n", offset); 253 fLastEntryOffset = i + 1; 254 255 // First check if its local or remote value 256 if (entry->flags & XFS_ATTR_LOCAL) { 257 AttrLeafNameLocal* local = (AttrLeafNameLocal*)(fLeafBuffer + offset); 258 memcpy(name, local->nameval, local->namelen); 259 name[local->namelen] = '\0'; 260 *nameLength = local->namelen + 1; 261 TRACE("Entry found name : %s, namelength : %ld", name, *nameLength); 262 return B_OK; 263 } else { 264 AttrLeafNameRemote* remote = (AttrLeafNameRemote*)(fLeafBuffer + offset); 265 memcpy(name, remote->name, remote->namelen); 266 name[remote->namelen] = '\0'; 267 *nameLength = remote->namelen + 1; 268 TRACE("Entry found name : %s, namelength : %ld", name, *nameLength); 269 return B_OK; 270 } 271 } 272 273 return B_ENTRY_NOT_FOUND; 274 275 } 276 277 278 status_t 279 LeafAttribute::Lookup(const char* name, size_t* nameLength) 280 { 281 TRACE("LeafAttribute::Lookup\n"); 282 uint32 hashValueOfRequest = hashfunction(name, *nameLength); 283 TRACE("Hashval:(%" B_PRIu32 ")\n", hashValueOfRequest); 284 285 AttrLeafHeader* header = AttrLeafHeader::Create(fInode,fLeafBuffer); 286 AttrLeafEntry* entry = (AttrLeafEntry*)(fLeafBuffer + AttrLeafHeader::Size(fInode)); 287 288 int numberOfLeafEntries = header->Count(); 289 int left = 0; 290 int right = numberOfLeafEntries - 1; 291 292 delete header; 293 294 hashLowerBound<AttrLeafEntry>(entry, left, right, hashValueOfRequest); 295 296 while (B_BENDIAN_TO_HOST_INT32(entry[left].hashval) == hashValueOfRequest) { 297 298 uint32 offset = B_BENDIAN_TO_HOST_INT16(entry[left].nameidx); 299 TRACE("offset:(%" B_PRIu16 ")\n", offset); 300 int status; 301 302 // First check if its local or remote value 303 if (entry[left].flags & XFS_ATTR_LOCAL) { 304 AttrLeafNameLocal* local = (AttrLeafNameLocal*)(fLeafBuffer + offset); 305 char* ptrToOffset = (char*)local + sizeof(uint8) + sizeof(uint16); 306 status = strncmp(name, ptrToOffset, *nameLength); 307 if (status == 0) { 308 fLocalEntry = local; 309 fRemoteEntry = NULL; 310 return B_OK; 311 } 312 } else { 313 AttrLeafNameRemote* remote = (AttrLeafNameRemote*)(fLeafBuffer + offset); 314 char* ptrToOffset = (char*)remote + sizeof(uint8) + 2 * sizeof(uint32); 315 status = strncmp(name, ptrToOffset, *nameLength); 316 if (status == 0) { 317 fRemoteEntry = remote; 318 fLocalEntry = NULL; 319 return B_OK; 320 } 321 } 322 left++; 323 } 324 325 return B_ENTRY_NOT_FOUND; 326 } 327 328 329 AttrLeafHeader::~AttrLeafHeader() 330 { 331 } 332 333 334 /* 335 First see which type of directory we reading then 336 return magic number as per Inode Version. 337 */ 338 uint32 339 AttrLeafHeader::ExpectedMagic(int8 WhichDirectory, Inode* inode) 340 { 341 if (WhichDirectory == ATTR_LEAF) { 342 if (inode->Version() == 1 || inode->Version() == 2) 343 return XFS_ATTR_LEAF_MAGIC; 344 else 345 return XFS_ATTR3_LEAF_MAGIC; 346 } else { 347 // currently we don't support other directories; 348 return B_BAD_VALUE; 349 } 350 } 351 352 353 uint32 354 AttrLeafHeader::CRCOffset() 355 { 356 return offsetof(AttrLeafHeaderV5::OnDiskData, info.crc); 357 } 358 359 360 //Function to get V4 or V5 Attr leaf header instance 361 AttrLeafHeader* 362 AttrLeafHeader::Create(Inode* inode, const char* buffer) 363 { 364 if (inode->Version() == 1 || inode->Version() == 2) { 365 AttrLeafHeaderV4* header = new (std::nothrow) AttrLeafHeaderV4(buffer); 366 return header; 367 } else { 368 AttrLeafHeaderV5* header = new (std::nothrow) AttrLeafHeaderV5(buffer); 369 return header; 370 } 371 } 372 373 374 /* 375 This Function returns Actual size of leaf header 376 in all forms of directory. 377 Never use sizeof() operator because we now have 378 vtable as well and it will give wrong results 379 */ 380 uint32 381 AttrLeafHeader::Size(Inode* inode) 382 { 383 if (inode->Version() == 1 || inode->Version() == 2) 384 return sizeof(AttrLeafHeaderV4::OnDiskData); 385 else 386 return sizeof(AttrLeafHeaderV5::OnDiskData); 387 } 388 389 390 void 391 AttrLeafHeaderV4::SwapEndian() 392 { 393 fData.info.forw = B_BENDIAN_TO_HOST_INT32(fData.info.forw); 394 fData.info.back = B_BENDIAN_TO_HOST_INT32(fData.info.back); 395 fData.info.magic = B_BENDIAN_TO_HOST_INT16(fData.info.magic); 396 fData.info.pad = B_BENDIAN_TO_HOST_INT16(fData.info.pad); 397 fData.count = B_BENDIAN_TO_HOST_INT16(fData.count); 398 fData.usedbytes = B_BENDIAN_TO_HOST_INT16(fData.usedbytes); 399 fData.firstused = B_BENDIAN_TO_HOST_INT16(fData.firstused); 400 } 401 402 403 AttrLeafHeaderV4::AttrLeafHeaderV4(const char* buffer) 404 { 405 memcpy(&fData, buffer, sizeof(fData)); 406 SwapEndian(); 407 } 408 409 410 AttrLeafHeaderV4::~AttrLeafHeaderV4() 411 { 412 } 413 414 415 uint16 416 AttrLeafHeaderV4::Magic() 417 { 418 return fData.info.magic; 419 } 420 421 422 uint64 423 AttrLeafHeaderV4::Blockno() 424 { 425 return B_BAD_VALUE; 426 } 427 428 429 uint64 430 AttrLeafHeaderV4::Owner() 431 { 432 return B_BAD_VALUE; 433 } 434 435 436 const uuid_t& 437 AttrLeafHeaderV4::Uuid() 438 { 439 static uuid_t nullUuid = {0}; 440 return nullUuid; 441 } 442 443 444 uint16 445 AttrLeafHeaderV4::Count() 446 { 447 return fData.count; 448 } 449 450 451 void 452 AttrLeafHeaderV5::SwapEndian() 453 { 454 fData.info.forw = B_BENDIAN_TO_HOST_INT32(fData.info.forw); 455 fData.info.back = B_BENDIAN_TO_HOST_INT32(fData.info.back); 456 fData.info.magic = B_BENDIAN_TO_HOST_INT16(fData.info.magic); 457 fData.info.pad = B_BENDIAN_TO_HOST_INT16(fData.info.pad); 458 fData.info.blkno = B_BENDIAN_TO_HOST_INT64(fData.info.blkno); 459 fData.info.lsn = B_BENDIAN_TO_HOST_INT64(fData.info.lsn); 460 fData.info.owner = B_BENDIAN_TO_HOST_INT64(fData.info.owner); 461 fData.count = B_BENDIAN_TO_HOST_INT16(fData.count); 462 fData.usedbytes = B_BENDIAN_TO_HOST_INT16(fData.usedbytes); 463 fData.firstused = B_BENDIAN_TO_HOST_INT16(fData.firstused); 464 fData.pad2 = B_BENDIAN_TO_HOST_INT32(fData.pad2); 465 } 466 467 468 AttrLeafHeaderV5::AttrLeafHeaderV5(const char* buffer) 469 { 470 memcpy(&fData, buffer, sizeof(fData)); 471 SwapEndian(); 472 } 473 474 475 AttrLeafHeaderV5::~AttrLeafHeaderV5() 476 { 477 } 478 479 480 uint16 481 AttrLeafHeaderV5::Magic() 482 { 483 return fData.info.magic; 484 } 485 486 487 uint64 488 AttrLeafHeaderV5::Blockno() 489 { 490 return fData.info.blkno; 491 } 492 493 494 uint64 495 AttrLeafHeaderV5::Owner() 496 { 497 return fData.info.owner; 498 } 499 500 501 const uuid_t& 502 AttrLeafHeaderV5::Uuid() 503 { 504 return fData.info.uuid; 505 } 506 507 508 uint16 509 AttrLeafHeaderV5::Count() 510 { 511 return fData.count; 512 } 513