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
Symlink(Inode * inode)12 Symlink::Symlink(Inode* inode)
13 :
14 fInode(inode),
15 fSymlinkBuffer(NULL)
16 {
17 }
18
19
~Symlink()20 Symlink::~Symlink()
21 {
22 delete fSymlinkBuffer;
23 }
24
25
26 status_t
_FillMapEntry()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
_FillBuffer()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
_ReadLocalLink(off_t pos,char * buffer,size_t * _length)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
_ReadExtentLink(off_t pos,char * buffer,size_t * _length)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
ReadLink(off_t pos,char * buffer,size_t * _length)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 }