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