1 /* 2 * Copyright 2022, Raghav Sharma, raghavself28@gmail.com 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Symlink.h" 8 9 #include "VerifyHeader.h" 10 11 12 Symlink::Symlink(Inode* inode) 13 : 14 fInode(inode), 15 fSymlinkBuffer(NULL) 16 { 17 } 18 19 20 Symlink::~Symlink() 21 { 22 delete fSymlinkBuffer; 23 } 24 25 26 status_t 27 Symlink::_FillMapEntry() 28 { 29 void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize()); 30 31 uint64 firstHalf = *((uint64*)pointerToMap); 32 uint64 secondHalf = *((uint64*)pointerToMap + 1); 33 //dividing the 128 bits into 2 parts. 34 firstHalf = B_BENDIAN_TO_HOST_INT64(firstHalf); 35 secondHalf = B_BENDIAN_TO_HOST_INT64(secondHalf); 36 fMap.br_state = firstHalf >> 63; 37 fMap.br_startoff = (firstHalf & MASK(63)) >> 9; 38 fMap.br_startblock = ((firstHalf & MASK(9)) << 43) | (secondHalf >> 21); 39 fMap.br_blockcount = secondHalf & MASK(21); 40 TRACE("Extent::Init: startoff:(%" B_PRIu64 "), startblock:(%" B_PRIu64 ")," 41 "blockcount:(%" B_PRIu64 "),state:(%" B_PRIu8 ")\n", fMap.br_startoff, fMap.br_startblock, 42 fMap.br_blockcount, fMap.br_state); 43 44 return B_OK; 45 } 46 47 48 status_t 49 Symlink::_FillBuffer() 50 { 51 if (fMap.br_state != 0) 52 return B_BAD_VALUE; 53 54 int len = fInode->DirBlockSize(); 55 fSymlinkBuffer = new(std::nothrow) char[len]; 56 if (fSymlinkBuffer == NULL) 57 return B_NO_MEMORY; 58 59 xfs_daddr_t readPos = 60 fInode->FileSystemBlockToAddr(fMap.br_startblock); 61 62 if (read_pos(fInode->GetVolume()->Device(), readPos, fSymlinkBuffer, len) 63 != len) { 64 ERROR("Extent::FillBlockBuffer(): IO Error"); 65 return B_IO_ERROR; 66 } 67 68 return B_OK; 69 } 70 71 72 status_t 73 Symlink::_ReadLocalLink(off_t pos, char* buffer, size_t* _length) 74 { 75 // All symlinks contents are inside inode itself 76 77 size_t lengthToRead = fInode->Size(); 78 79 if (*_length < lengthToRead) 80 lengthToRead = *_length; 81 82 char* offset = (char*)(DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize())); 83 84 memcpy(buffer, offset, lengthToRead); 85 86 *_length = lengthToRead; 87 88 return B_OK; 89 90 } 91 92 93 status_t 94 Symlink::_ReadExtentLink(off_t pos, char* buffer, size_t* _length) 95 { 96 status_t status; 97 // First fill up extent, then Symlink block buffer 98 status = _FillMapEntry(); 99 if (status != B_OK) 100 return status; 101 102 status = _FillBuffer(); 103 if (status != B_OK) 104 return status; 105 106 uint32 offset = 0; 107 // If it is Version 5 xfs then we have Symlink header 108 if (fInode->Version() == 3) { 109 SymlinkHeader* header = (SymlinkHeader*)fSymlinkBuffer; 110 if (!VerifyHeader<SymlinkHeader>(header, fSymlinkBuffer, fInode, 0, &fMap, 0)) { 111 ERROR("Invalid data header"); 112 return B_BAD_VALUE; 113 } 114 offset += sizeof(SymlinkHeader); 115 } 116 117 size_t lengthToRead = fInode->Size(); 118 119 if (*_length < lengthToRead) 120 lengthToRead = *_length; 121 122 memcpy(buffer, fSymlinkBuffer + offset, lengthToRead); 123 124 *_length = lengthToRead; 125 126 return B_OK; 127 } 128 129 130 status_t 131 Symlink::ReadLink(off_t pos, char* buffer, size_t* _length) 132 { 133 switch (fInode->Format()) { 134 case XFS_DINODE_FMT_LOCAL: 135 return _ReadLocalLink(pos, buffer, _length); 136 case XFS_DINODE_FMT_EXTENTS: 137 return _ReadExtentLink(pos, buffer, _length); 138 default: 139 return B_BAD_VALUE; 140 } 141 }