xref: /haiku/src/add-ons/kernel/file_systems/xfs/Symlink.cpp (revision 2710b4f5d4251c5cf88c82b0114ea99b0ef46d22)
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 }