xref: /haiku/src/add-ons/kernel/file_systems/xfs/LeafAttribute.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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 
12 LeafAttribute::LeafAttribute(Inode* inode)
13 	:
14 	fInode(inode),
15 	fName(NULL),
16 	fMap(NULL),
17 	fLeafBuffer(NULL)
18 {
19 	fLastEntryOffset = 0;
20 }
21 
22 
23 LeafAttribute::~LeafAttribute()
24 {
25 	delete fMap;
26 	delete[] fLeafBuffer;
27 }
28 
29 
30 status_t
31 LeafAttribute::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 
58 status_t
59 LeafAttribute::_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 
87 status_t
88 LeafAttribute::_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 
109 status_t
110 LeafAttribute::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 
135 status_t
136 LeafAttribute::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 
167 status_t
168 LeafAttribute::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 
234 status_t
235 LeafAttribute::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 
278 status_t
279 LeafAttribute::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 
329 AttrLeafHeader::~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 */
338 uint32
339 AttrLeafHeader::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 
353 uint32
354 AttrLeafHeader::CRCOffset()
355 {
356 	return offsetof(AttrLeafHeaderV5::OnDiskData, info.crc);
357 }
358 
359 
360 //Function to get V4 or V5 Attr leaf header instance
361 AttrLeafHeader*
362 AttrLeafHeader::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 */
380 uint32
381 AttrLeafHeader::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 
390 void
391 AttrLeafHeaderV4::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 
403 AttrLeafHeaderV4::AttrLeafHeaderV4(const char* buffer)
404 {
405 	memcpy(&fData, buffer, sizeof(fData));
406 	SwapEndian();
407 }
408 
409 
410 AttrLeafHeaderV4::~AttrLeafHeaderV4()
411 {
412 }
413 
414 
415 uint16
416 AttrLeafHeaderV4::Magic()
417 {
418 	return fData.info.magic;
419 }
420 
421 
422 uint64
423 AttrLeafHeaderV4::Blockno()
424 {
425 	return B_BAD_VALUE;
426 }
427 
428 
429 uint64
430 AttrLeafHeaderV4::Owner()
431 {
432 	return B_BAD_VALUE;
433 }
434 
435 
436 const uuid_t&
437 AttrLeafHeaderV4::Uuid()
438 {
439 	static uuid_t nullUuid = {0};
440 	return nullUuid;
441 }
442 
443 
444 uint16
445 AttrLeafHeaderV4::Count()
446 {
447 	return fData.count;
448 }
449 
450 
451 void
452 AttrLeafHeaderV5::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 
468 AttrLeafHeaderV5::AttrLeafHeaderV5(const char* buffer)
469 {
470 	memcpy(&fData, buffer, sizeof(fData));
471 	SwapEndian();
472 }
473 
474 
475 AttrLeafHeaderV5::~AttrLeafHeaderV5()
476 {
477 }
478 
479 
480 uint16
481 AttrLeafHeaderV5::Magic()
482 {
483 	return fData.info.magic;
484 }
485 
486 
487 uint64
488 AttrLeafHeaderV5::Blockno()
489 {
490 	return fData.info.blkno;
491 }
492 
493 
494 uint64
495 AttrLeafHeaderV5::Owner()
496 {
497 	return fData.info.owner;
498 }
499 
500 
501 const uuid_t&
502 AttrLeafHeaderV5::Uuid()
503 {
504 	return fData.info.uuid;
505 }
506 
507 
508 uint16
509 AttrLeafHeaderV5::Count()
510 {
511 	return fData.count;
512 }
513