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* entry = (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 entry = (AttrLeafEntry*)((char*)entry + i * sizeof(AttrLeafEntry)); 249 250 uint32 offset = B_BENDIAN_TO_HOST_INT16(entry->nameidx); 251 TRACE("offset:(%" B_PRIu16 ")\n", offset); 252 fLastEntryOffset = i + 1; 253 254 // First check if its local or remote value 255 if (entry->flags & XFS_ATTR_LOCAL) { 256 AttrLeafNameLocal* local = (AttrLeafNameLocal*)(fLeafBuffer + offset); 257 memcpy(name, local->nameval, local->namelen); 258 name[local->namelen] = '\0'; 259 *nameLength = local->namelen + 1; 260 TRACE("Entry found name : %s, namelength : %ld", name, *nameLength); 261 return B_OK; 262 } else { 263 AttrLeafNameRemote* remote = (AttrLeafNameRemote*)(fLeafBuffer + offset); 264 memcpy(name, remote->name, remote->namelen); 265 name[remote->namelen] = '\0'; 266 *nameLength = remote->namelen + 1; 267 TRACE("Entry found name : %s, namelength : %ld", name, *nameLength); 268 return B_OK; 269 } 270 } 271 272 return B_ENTRY_NOT_FOUND; 273 274 } 275 276 277 status_t 278 LeafAttribute::Lookup(const char* name, size_t* nameLength) 279 { 280 TRACE("LeafAttribute::Lookup\n"); 281 uint32 hashValueOfRequest = hashfunction(name, *nameLength); 282 TRACE("Hashval:(%" B_PRIu32 ")\n", hashValueOfRequest); 283 284 AttrLeafHeader* header = AttrLeafHeader::Create(fInode,fLeafBuffer); 285 AttrLeafEntry* entry = (AttrLeafEntry*)(fLeafBuffer + AttrLeafHeader::Size(fInode)); 286 287 int numberOfLeafEntries = header->Count(); 288 int left = 0; 289 int right = numberOfLeafEntries - 1; 290 291 delete header; 292 293 hashLowerBound<AttrLeafEntry>(entry, left, right, hashValueOfRequest); 294 295 while (B_BENDIAN_TO_HOST_INT32(entry[left].hashval) == hashValueOfRequest) { 296 297 uint32 offset = B_BENDIAN_TO_HOST_INT16(entry[left].nameidx); 298 TRACE("offset:(%" B_PRIu16 ")\n", offset); 299 int status; 300 301 // First check if its local or remote value 302 if (entry[left].flags & XFS_ATTR_LOCAL) { 303 AttrLeafNameLocal* local = (AttrLeafNameLocal*)(fLeafBuffer + offset); 304 char* ptrToOffset = (char*)local + sizeof(uint8) + sizeof(uint16); 305 status = strncmp(name, ptrToOffset, *nameLength); 306 if (status == 0) { 307 fLocalEntry = local; 308 fRemoteEntry = NULL; 309 return B_OK; 310 } 311 } else { 312 AttrLeafNameRemote* remote = (AttrLeafNameRemote*)(fLeafBuffer + offset); 313 char* ptrToOffset = (char*)remote + sizeof(uint8) + 2 * sizeof(uint32); 314 status = strncmp(name, ptrToOffset, *nameLength); 315 if (status == 0) { 316 fRemoteEntry = remote; 317 fLocalEntry = NULL; 318 return B_OK; 319 } 320 } 321 left++; 322 } 323 324 return B_ENTRY_NOT_FOUND; 325 } 326 327 328 AttrLeafHeader::~AttrLeafHeader() 329 { 330 } 331 332 333 /* 334 First see which type of directory we reading then 335 return magic number as per Inode Version. 336 */ 337 uint32 338 AttrLeafHeader::ExpectedMagic(int8 WhichDirectory, Inode* inode) 339 { 340 if (WhichDirectory == ATTR_LEAF) { 341 if (inode->Version() == 1 || inode->Version() == 2) 342 return XFS_ATTR_LEAF_MAGIC; 343 else 344 return XFS_ATTR3_LEAF_MAGIC; 345 } else { 346 // currently we don't support other directories; 347 return B_BAD_VALUE; 348 } 349 } 350 351 352 uint32 353 AttrLeafHeader::CRCOffset() 354 { 355 return ATTR_LEAF_CRC_OFF - ATTR_LEAF_V5_VPTR_OFF; 356 } 357 358 359 //Function to get V4 or V5 Attr leaf header instance 360 AttrLeafHeader* 361 AttrLeafHeader::Create(Inode* inode, const char* buffer) 362 { 363 if (inode->Version() == 1 || inode->Version() == 2) { 364 AttrLeafHeaderV4* header = new (std::nothrow) AttrLeafHeaderV4(buffer); 365 return header; 366 } else { 367 AttrLeafHeaderV5* header = new (std::nothrow) AttrLeafHeaderV5(buffer); 368 return header; 369 } 370 } 371 372 373 /* 374 This Function returns Actual size of leaf header 375 in all forms of directory. 376 Never use sizeof() operator because we now have 377 vtable as well and it will give wrong results 378 */ 379 uint32 380 AttrLeafHeader::Size(Inode* inode) 381 { 382 if (inode->Version() == 1 || inode->Version() == 2) 383 return sizeof(AttrLeafHeaderV4) - ATTR_LEAF_V4_VPTR_OFF; 384 else 385 return sizeof(AttrLeafHeaderV5) - ATTR_LEAF_V5_VPTR_OFF; 386 } 387 388 389 void 390 AttrLeafHeaderV4::SwapEndian() 391 { 392 info.forw = B_BENDIAN_TO_HOST_INT32(info.forw); 393 info.back = B_BENDIAN_TO_HOST_INT32(info.back); 394 info.magic = B_BENDIAN_TO_HOST_INT16(info.magic); 395 info.pad = B_BENDIAN_TO_HOST_INT16(info.pad); 396 count = B_BENDIAN_TO_HOST_INT16(count); 397 usedbytes = B_BENDIAN_TO_HOST_INT16(usedbytes); 398 firstused = B_BENDIAN_TO_HOST_INT16(firstused); 399 } 400 401 402 AttrLeafHeaderV4::AttrLeafHeaderV4(const char* buffer) 403 { 404 uint32 offset = 0; 405 406 info = *(BlockInfo*)(buffer + offset); 407 offset += sizeof(BlockInfo); 408 409 count = *(uint16*)(buffer + offset); 410 offset += sizeof(uint16); 411 412 usedbytes = *(uint16*)(buffer + offset); 413 offset += sizeof(uint16); 414 415 firstused = *(uint16*)(buffer + offset); 416 offset += sizeof(uint16); 417 418 holes = *(uint8*)(buffer + offset); 419 offset += sizeof(uint8); 420 421 pad1 = *(uint8*)(buffer + offset); 422 offset += sizeof(uint8); 423 424 memcpy(freemap, buffer + offset, XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap)); 425 426 SwapEndian(); 427 } 428 429 430 AttrLeafHeaderV4::~AttrLeafHeaderV4() 431 { 432 } 433 434 435 uint16 436 AttrLeafHeaderV4::Magic() 437 { 438 return info.magic; 439 } 440 441 442 uint64 443 AttrLeafHeaderV4::Blockno() 444 { 445 return B_BAD_VALUE; 446 } 447 448 449 uint64 450 AttrLeafHeaderV4::Owner() 451 { 452 return B_BAD_VALUE; 453 } 454 455 456 uuid_t* 457 AttrLeafHeaderV4::Uuid() 458 { 459 return NULL; 460 } 461 462 463 uint16 464 AttrLeafHeaderV4::Count() 465 { 466 return count; 467 } 468 469 470 void 471 AttrLeafHeaderV5::SwapEndian() 472 { 473 info.forw = B_BENDIAN_TO_HOST_INT32(info.forw); 474 info.back = B_BENDIAN_TO_HOST_INT32(info.back); 475 info.magic = B_BENDIAN_TO_HOST_INT16(info.magic); 476 info.pad = B_BENDIAN_TO_HOST_INT16(info.pad); 477 info.blkno = B_BENDIAN_TO_HOST_INT64(info.blkno); 478 info.lsn = B_BENDIAN_TO_HOST_INT64(info.lsn); 479 info.owner = B_BENDIAN_TO_HOST_INT64(info.owner); 480 count = B_BENDIAN_TO_HOST_INT16(count); 481 usedbytes = B_BENDIAN_TO_HOST_INT16(usedbytes); 482 firstused = B_BENDIAN_TO_HOST_INT16(firstused); 483 pad2 = B_BENDIAN_TO_HOST_INT32(pad2); 484 } 485 486 487 AttrLeafHeaderV5::AttrLeafHeaderV5(const char* buffer) 488 { 489 uint32 offset = 0; 490 491 info = *(BlockInfoV5*)(buffer + offset); 492 offset += sizeof(BlockInfoV5); 493 494 count = *(uint16*)(buffer + offset); 495 offset += sizeof(uint16); 496 497 usedbytes = *(uint16*)(buffer + offset); 498 offset += sizeof(uint16); 499 500 firstused = *(uint16*)(buffer + offset); 501 offset += sizeof(uint16); 502 503 holes = *(uint8*)(buffer + offset); 504 offset += sizeof(uint8); 505 506 pad1 = *(uint8*)(buffer + offset); 507 offset += sizeof(uint8); 508 509 memcpy(freemap, buffer + offset, XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap)); 510 offset += XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap); 511 512 pad2 = *(uint32*)(buffer + offset); 513 offset += sizeof(uint32); 514 515 SwapEndian(); 516 } 517 518 519 AttrLeafHeaderV5::~AttrLeafHeaderV5() 520 { 521 } 522 523 524 uint16 525 AttrLeafHeaderV5::Magic() 526 { 527 return info.magic; 528 } 529 530 531 uint64 532 AttrLeafHeaderV5::Blockno() 533 { 534 return info.blkno; 535 } 536 537 538 uint64 539 AttrLeafHeaderV5::Owner() 540 { 541 return info.owner; 542 } 543 544 545 uuid_t* 546 AttrLeafHeaderV5::Uuid() 547 { 548 return &info.uuid; 549 } 550 551 552 uint16 553 AttrLeafHeaderV5::Count() 554 { 555 return count; 556 }