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