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