xref: /haiku/src/add-ons/kernel/file_systems/xfs/LeafAttribute.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 ATTR_LEAF_CRC_OFF - ATTR_LEAF_V5_VPTR_OFF;
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) - ATTR_LEAF_V4_VPTR_OFF;
385 	else
386 		return sizeof(AttrLeafHeaderV5) - ATTR_LEAF_V5_VPTR_OFF;
387 }
388 
389 
390 void
391 AttrLeafHeaderV4::SwapEndian()
392 {
393 	info.forw	=	B_BENDIAN_TO_HOST_INT32(info.forw);
394 	info.back	=	B_BENDIAN_TO_HOST_INT32(info.back);
395 	info.magic	=	B_BENDIAN_TO_HOST_INT16(info.magic);
396 	info.pad	=	B_BENDIAN_TO_HOST_INT16(info.pad);
397 	count		=	B_BENDIAN_TO_HOST_INT16(count);
398 	usedbytes	=	B_BENDIAN_TO_HOST_INT16(usedbytes);
399 	firstused	=	B_BENDIAN_TO_HOST_INT16(firstused);
400 }
401 
402 
403 AttrLeafHeaderV4::AttrLeafHeaderV4(const char* buffer)
404 {
405 	uint32 offset = 0;
406 
407 	info = *(BlockInfo*)(buffer + offset);
408 	offset += sizeof(BlockInfo);
409 
410 	count = *(uint16*)(buffer + offset);
411 	offset += sizeof(uint16);
412 
413 	usedbytes = *(uint16*)(buffer + offset);
414 	offset += sizeof(uint16);
415 
416 	firstused = *(uint16*)(buffer + offset);
417 	offset += sizeof(uint16);
418 
419 	holes = *(uint8*)(buffer + offset);
420 	offset += sizeof(uint8);
421 
422 	pad1 = *(uint8*)(buffer + offset);
423 	offset += sizeof(uint8);
424 
425 	memcpy(freemap, buffer + offset, XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap));
426 
427 	SwapEndian();
428 }
429 
430 
431 AttrLeafHeaderV4::~AttrLeafHeaderV4()
432 {
433 }
434 
435 
436 uint16
437 AttrLeafHeaderV4::Magic()
438 {
439 	return info.magic;
440 }
441 
442 
443 uint64
444 AttrLeafHeaderV4::Blockno()
445 {
446 	return B_BAD_VALUE;
447 }
448 
449 
450 uint64
451 AttrLeafHeaderV4::Owner()
452 {
453 	return B_BAD_VALUE;
454 }
455 
456 
457 uuid_t*
458 AttrLeafHeaderV4::Uuid()
459 {
460 	return NULL;
461 }
462 
463 
464 uint16
465 AttrLeafHeaderV4::Count()
466 {
467 	return count;
468 }
469 
470 
471 void
472 AttrLeafHeaderV5::SwapEndian()
473 {
474 	info.forw	=	B_BENDIAN_TO_HOST_INT32(info.forw);
475 	info.back	=	B_BENDIAN_TO_HOST_INT32(info.back);
476 	info.magic	=	B_BENDIAN_TO_HOST_INT16(info.magic);
477 	info.pad	=	B_BENDIAN_TO_HOST_INT16(info.pad);
478 	info.blkno	=	B_BENDIAN_TO_HOST_INT64(info.blkno);
479 	info.lsn	=	B_BENDIAN_TO_HOST_INT64(info.lsn);
480 	info.owner	=	B_BENDIAN_TO_HOST_INT64(info.owner);
481 	count		=	B_BENDIAN_TO_HOST_INT16(count);
482 	usedbytes	=	B_BENDIAN_TO_HOST_INT16(usedbytes);
483 	firstused	=	B_BENDIAN_TO_HOST_INT16(firstused);
484 	pad2		=	B_BENDIAN_TO_HOST_INT32(pad2);
485 }
486 
487 
488 AttrLeafHeaderV5::AttrLeafHeaderV5(const char* buffer)
489 {
490 	uint32 offset = 0;
491 
492 	info = *(BlockInfoV5*)(buffer + offset);
493 	offset += sizeof(BlockInfoV5);
494 
495 	count = *(uint16*)(buffer + offset);
496 	offset += sizeof(uint16);
497 
498 	usedbytes = *(uint16*)(buffer + offset);
499 	offset += sizeof(uint16);
500 
501 	firstused = *(uint16*)(buffer + offset);
502 	offset += sizeof(uint16);
503 
504 	holes = *(uint8*)(buffer + offset);
505 	offset += sizeof(uint8);
506 
507 	pad1 = *(uint8*)(buffer + offset);
508 	offset += sizeof(uint8);
509 
510 	memcpy(freemap, buffer + offset, XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap));
511 	offset += XFS_ATTR_LEAF_MAPSIZE * sizeof(AttrLeafMap);
512 
513 	pad2 = *(uint32*)(buffer + offset);
514 	offset += sizeof(uint32);
515 
516 	SwapEndian();
517 }
518 
519 
520 AttrLeafHeaderV5::~AttrLeafHeaderV5()
521 {
522 }
523 
524 
525 uint16
526 AttrLeafHeaderV5::Magic()
527 {
528 	return info.magic;
529 }
530 
531 
532 uint64
533 AttrLeafHeaderV5::Blockno()
534 {
535 	return info.blkno;
536 }
537 
538 
539 uint64
540 AttrLeafHeaderV5::Owner()
541 {
542 	return info.owner;
543 }
544 
545 
546 uuid_t*
547 AttrLeafHeaderV5::Uuid()
548 {
549 	return &info.uuid;
550 }
551 
552 
553 uint16
554 AttrLeafHeaderV5::Count()
555 {
556 	return count;
557 }