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 ATTR_LEAF_CRC_OFF - ATTR_LEAF_V5_VPTR_OFF; 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) - ATTR_LEAF_V4_VPTR_OFF; 385 else 386 return sizeof(AttrLeafHeaderV5) - ATTR_LEAF_V5_VPTR_OFF; 387 } 388 389 390 void 391 AttrLeafHeaderV4::SwapEndian() 392 { 393 info.forw = B_BENDIAN_TO_HOST_INT32(info.forw); 394 info.back = B_BENDIAN_TO_HOST_INT32(info.back); 395 info.magic = B_BENDIAN_TO_HOST_INT16(info.magic); 396 info.pad = B_BENDIAN_TO_HOST_INT16(info.pad); 397 count = B_BENDIAN_TO_HOST_INT16(count); 398 usedbytes = B_BENDIAN_TO_HOST_INT16(usedbytes); 399 firstused = B_BENDIAN_TO_HOST_INT16(firstused); 400 } 401 402 403 AttrLeafHeaderV4::AttrLeafHeaderV4(const char* buffer) 404 { 405 uint32 offset = 0; 406 407 info = *(BlockInfo*)(buffer + offset); 408 offset += sizeof(BlockInfo); 409 410 count = *(uint16*)(buffer + offset); 411 offset += sizeof(uint16); 412 413 usedbytes = *(uint16*)(buffer + offset); 414 offset += sizeof(uint16); 415 416 firstused = *(uint16*)(buffer + offset); 417 offset += sizeof(uint16); 418 419 holes = *(uint8*)(buffer + offset); 420 offset += sizeof(uint8); 421 422 pad1 = *(uint8*)(buffer + offset); 423 offset += sizeof(uint8); 424 425 memcpy(freemap, buffer + offset, XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap)); 426 427 SwapEndian(); 428 } 429 430 431 AttrLeafHeaderV4::~AttrLeafHeaderV4() 432 { 433 } 434 435 436 uint16 437 AttrLeafHeaderV4::Magic() 438 { 439 return info.magic; 440 } 441 442 443 uint64 444 AttrLeafHeaderV4::Blockno() 445 { 446 return B_BAD_VALUE; 447 } 448 449 450 uint64 451 AttrLeafHeaderV4::Owner() 452 { 453 return B_BAD_VALUE; 454 } 455 456 457 uuid_t* 458 AttrLeafHeaderV4::Uuid() 459 { 460 return NULL; 461 } 462 463 464 uint16 465 AttrLeafHeaderV4::Count() 466 { 467 return count; 468 } 469 470 471 void 472 AttrLeafHeaderV5::SwapEndian() 473 { 474 info.forw = B_BENDIAN_TO_HOST_INT32(info.forw); 475 info.back = B_BENDIAN_TO_HOST_INT32(info.back); 476 info.magic = B_BENDIAN_TO_HOST_INT16(info.magic); 477 info.pad = B_BENDIAN_TO_HOST_INT16(info.pad); 478 info.blkno = B_BENDIAN_TO_HOST_INT64(info.blkno); 479 info.lsn = B_BENDIAN_TO_HOST_INT64(info.lsn); 480 info.owner = B_BENDIAN_TO_HOST_INT64(info.owner); 481 count = B_BENDIAN_TO_HOST_INT16(count); 482 usedbytes = B_BENDIAN_TO_HOST_INT16(usedbytes); 483 firstused = B_BENDIAN_TO_HOST_INT16(firstused); 484 pad2 = B_BENDIAN_TO_HOST_INT32(pad2); 485 } 486 487 488 AttrLeafHeaderV5::AttrLeafHeaderV5(const char* buffer) 489 { 490 uint32 offset = 0; 491 492 info = *(BlockInfoV5*)(buffer + offset); 493 offset += sizeof(BlockInfoV5); 494 495 count = *(uint16*)(buffer + offset); 496 offset += sizeof(uint16); 497 498 usedbytes = *(uint16*)(buffer + offset); 499 offset += sizeof(uint16); 500 501 firstused = *(uint16*)(buffer + offset); 502 offset += sizeof(uint16); 503 504 holes = *(uint8*)(buffer + offset); 505 offset += sizeof(uint8); 506 507 pad1 = *(uint8*)(buffer + offset); 508 offset += sizeof(uint8); 509 510 memcpy(freemap, buffer + offset, XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap)); 511 offset += XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap); 512 513 pad2 = *(uint32*)(buffer + offset); 514 offset += sizeof(uint32); 515 516 SwapEndian(); 517 } 518 519 520 AttrLeafHeaderV5::~AttrLeafHeaderV5() 521 { 522 } 523 524 525 uint16 526 AttrLeafHeaderV5::Magic() 527 { 528 return info.magic; 529 } 530 531 532 uint64 533 AttrLeafHeaderV5::Blockno() 534 { 535 return info.blkno; 536 } 537 538 539 uint64 540 AttrLeafHeaderV5::Owner() 541 { 542 return info.owner; 543 } 544 545 546 uuid_t* 547 AttrLeafHeaderV5::Uuid() 548 { 549 return &info.uuid; 550 } 551 552 553 uint16 554 AttrLeafHeaderV5::Count() 555 { 556 return count; 557 }