xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2  * Copyright 2022, Raghav Sharma, raghavself28@gmail.com
3  * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
4  * All rights reserved. Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "Inode.h"
9 
10 #include "BPlusTree.h"
11 #include "VerifyHeader.h"
12 
13 
14 void
15 xfs_inode_t::SwapEndian()
16 {
17 	di_magic			=	B_BENDIAN_TO_HOST_INT16(di_magic);
18 	di_mode				=	B_BENDIAN_TO_HOST_INT16(di_mode);
19 	di_onlink			=	B_BENDIAN_TO_HOST_INT16(di_onlink);
20 	di_uid				=	B_BENDIAN_TO_HOST_INT32(di_uid);
21 	di_gid				=	B_BENDIAN_TO_HOST_INT32(di_gid);
22 	di_nlink			=	B_BENDIAN_TO_HOST_INT32(di_nlink);
23 	di_projid			=	B_BENDIAN_TO_HOST_INT16(di_projid);
24 	di_flushiter		=	B_BENDIAN_TO_HOST_INT16(di_flushiter);
25 	di_atime.t_sec		=	B_BENDIAN_TO_HOST_INT32(di_atime.t_sec);
26 	di_atime.t_nsec		=	B_BENDIAN_TO_HOST_INT32(di_atime.t_nsec);
27 	di_mtime.t_sec		=	B_BENDIAN_TO_HOST_INT32(di_mtime.t_sec);
28 	di_mtime.t_nsec		=	B_BENDIAN_TO_HOST_INT32(di_mtime.t_nsec);
29 	di_ctime.t_sec		=	B_BENDIAN_TO_HOST_INT32(di_ctime.t_sec);
30 	di_ctime.t_nsec		=	B_BENDIAN_TO_HOST_INT32(di_ctime.t_nsec);
31 	di_size				=	B_BENDIAN_TO_HOST_INT64(di_size);
32 	di_nblocks			=	B_BENDIAN_TO_HOST_INT64(di_nblocks);
33 	di_extsize			=	B_BENDIAN_TO_HOST_INT32(di_extsize);
34 	di_nextents			=	B_BENDIAN_TO_HOST_INT32(di_nextents);
35 	di_naextents		=	B_BENDIAN_TO_HOST_INT16(di_naextents);
36 	di_dmevmask			=	B_BENDIAN_TO_HOST_INT32(di_dmevmask);
37 	di_dmstate			=	B_BENDIAN_TO_HOST_INT16(di_dmstate);
38 	di_flags			=	B_BENDIAN_TO_HOST_INT16(di_flags);
39 	di_gen				=	B_BENDIAN_TO_HOST_INT32(di_gen);
40 	di_next_unlinked	=	B_BENDIAN_TO_HOST_INT32(di_next_unlinked);
41 	di_changecount		=	B_BENDIAN_TO_HOST_INT64(di_changecount);
42 	di_lsn				=	B_BENDIAN_TO_HOST_INT64(di_lsn);
43 	di_flags2			=	B_BENDIAN_TO_HOST_INT64(di_flags2);
44 	di_cowextsize		=	B_BENDIAN_TO_HOST_INT64(di_cowextsize);
45 	di_crtime.t_sec		=	B_BENDIAN_TO_HOST_INT32(di_crtime.t_sec);
46 	di_crtime.t_nsec	=	B_BENDIAN_TO_HOST_INT32(di_crtime.t_nsec);
47 	di_ino				=	B_BENDIAN_TO_HOST_INT64(di_ino);
48 }
49 
50 
51 uint8
52 xfs_inode_t::ForkOffset() const
53 {
54 	return di_forkoff;
55 }
56 
57 
58 xfs_rfsblock_t
59 xfs_inode_t::BlockCount() const
60 {
61 	return di_nblocks;
62 }
63 
64 
65 xfs_fsize_t
66 xfs_inode_t::Size() const
67 {
68 	return di_size;
69 }
70 
71 
72 mode_t
73 xfs_inode_t::Mode() const
74 {
75 	return di_mode;
76 }
77 
78 
79 uint32
80 xfs_inode_t::UserId() const
81 {
82 	return di_uid;
83 }
84 
85 
86 uint32
87 xfs_inode_t::GroupId() const
88 {
89 	return di_gid;
90 }
91 
92 
93 void
94 xfs_inode_t::GetModificationTime(struct timespec& stamp)
95 {
96 	stamp.tv_sec = di_mtime.t_sec;
97 	stamp.tv_nsec = di_mtime.t_nsec;
98 }
99 
100 
101 void
102 xfs_inode_t::GetAccessTime(struct timespec& stamp)
103 {
104 	stamp.tv_sec = di_atime.t_sec;
105 	stamp.tv_nsec = di_atime.t_nsec;
106 }
107 
108 
109 void
110 xfs_inode_t::GetChangeTime(struct timespec& stamp)
111 {
112 	stamp.tv_sec = di_ctime.t_sec;
113 	stamp.tv_nsec = di_ctime.t_nsec;
114 }
115 
116 
117 void
118 xfs_inode_t::GetCreationTime(struct timespec& stamp)
119 {
120 	stamp.tv_sec = di_crtime.t_sec;
121 	stamp.tv_nsec = di_crtime.t_nsec;
122 }
123 
124 
125 uint32
126 xfs_inode_t::NLink() const
127 {
128 	return di_nlink;
129 }
130 
131 
132 int8
133 xfs_inode_t::Version() const
134 {
135 	return di_version;
136 }
137 
138 
139 uint16
140 xfs_inode_t::Flags() const
141 {
142 	return di_flags;
143 }
144 
145 
146 int8
147 xfs_inode_t::Format() const
148 {
149 	return di_format;
150 }
151 
152 
153 int8
154 xfs_inode_t::AttrFormat() const
155 {
156 	return di_aformat;
157 }
158 
159 
160 xfs_extnum_t
161 xfs_inode_t::DataExtentsCount() const
162 {
163 	return di_nextents;
164 }
165 
166 
167 xfs_extnum_t
168 xfs_inode_t::AttrExtentsCount() const
169 {
170 	return di_naextents;
171 }
172 
173 
174 Inode::Inode(Volume* volume, xfs_ino_t id)
175 	:
176 	fId(id),
177 	fVolume(volume),
178 	fBuffer(NULL),
179 	fExtents(NULL)
180 {
181 }
182 
183 
184 //Convert inode mode to directory entry filetype
185 unsigned char
186 Inode::XfsModeToFtype() const
187 {
188 	switch (Mode() & S_IFMT) {
189 	case S_IFREG:
190 		return XFS_DIR3_FT_REG_FILE;
191 	case S_IFDIR:
192 		return XFS_DIR3_FT_DIR;
193 	case S_IFCHR:
194 		return XFS_DIR3_FT_CHRDEV;
195 	case S_IFBLK:
196 		return XFS_DIR3_FT_BLKDEV;
197 	case S_IFIFO:
198 		return XFS_DIR3_FT_FIFO;
199 	case S_IFSOCK:
200 		return XFS_DIR3_FT_SOCK;
201 	case S_IFLNK:
202 		return XFS_DIR3_FT_SYMLINK;
203 	default:
204 		return XFS_DIR3_FT_UNKNOWN;
205 	}
206 }
207 
208 bool
209 Inode::VerifyFork(int whichFork) const
210 {
211 	uint32 di_nextents = XFS_DFORK_NEXTENTS(fNode, whichFork);
212 
213 	switch (XFS_DFORK_FORMAT(fNode, whichFork)) {
214 	case XFS_DINODE_FMT_LOCAL:
215 		if (whichFork == XFS_DATA_FORK) {
216 			if (S_ISREG(Mode()))
217 				return false;
218 			if (Size() > (xfs_fsize_t) DFORK_SIZE(fNode, fVolume, whichFork))
219 				return false;
220 		}
221 		if (di_nextents)
222 			return false;
223 		break;
224 	case XFS_DINODE_FMT_EXTENTS:
225 		if (di_nextents > DFORK_MAXEXT(fNode, fVolume, whichFork))
226 			return false;
227 		break;
228 	case XFS_DINODE_FMT_BTREE:
229 		if (whichFork == XFS_ATTR_FORK) {
230 			if (di_nextents > MAXAEXTNUM)
231 				return false;
232 		} else if (di_nextents > MAXEXTNUM) {
233 			return false;
234 		}
235 		break;
236 	default:
237 		return false;
238 	}
239 
240 	return true;
241 }
242 
243 bool
244 Inode::VerifyForkoff() const
245 {
246 	switch(Format()) {
247 		case XFS_DINODE_FMT_DEV:
248 			if (fNode->di_forkoff != (ROUNDUP(sizeof(uint32), 8) >> 3))
249 			return false;
250 		break;
251 		case XFS_DINODE_FMT_LOCAL:
252 		case XFS_DINODE_FMT_EXTENTS:
253 		case XFS_DINODE_FMT_BTREE:
254 			if (fNode->di_forkoff >= (LITINO(fVolume) >> 3))
255 				return false;
256 		break;
257 	default:
258 		return false;
259 	}
260 
261 	return true;
262 }
263 
264 
265 bool
266 Inode::VerifyInode() const
267 {
268 	if(fNode->di_magic != INODE_MAGIC) {
269 		ERROR("Bad inode magic number");
270 		return false;
271 	}
272 
273 	// check if inode version is valid
274 	if(fNode->Version() < 1 || fNode->Version() > 3) {
275 		ERROR("Bad inode version");
276 		return false;
277 	}
278 
279 	// verify version 3 inodes first
280 	if(fNode->Version() == 3) {
281 
282 		if(!HAS_V3INODES(fVolume)) {
283 			ERROR("xfs v4 doesn't have v3 inodes");
284 			return false;
285 		}
286 
287 		if(!xfs_verify_cksum(fBuffer, fVolume->InodeSize(), INODE_CRC_OFF)) {
288 			ERROR("Inode is corrupted");
289 			return false;
290 		}
291 
292 		if(fNode->di_ino != fId) {
293 			ERROR("Incorrect inode number");
294 			return false;
295 		}
296 
297 		if(!fVolume->UuidEquals(&fNode->di_uuid)) {
298 			ERROR("UUID is incorrect");
299 			return false;
300 		}
301 	}
302 
303 	if(fNode->di_size & (1ULL << 63)) {
304 		ERROR("Invalid EOF of inode");
305 		return false;
306 	}
307 
308 	if (Mode() && XfsModeToFtype() == XFS_DIR3_FT_UNKNOWN) {
309 		 ERROR("Entry points to an unknown inode type");
310 		 return false;
311 	}
312 
313 	if(!VerifyForkoff()) {
314 		ERROR("Invalid inode fork offset");
315 		return false;
316 	}
317 
318 	// Check for appropriate data fork formats for the mode
319 	switch (Mode() & S_IFMT) {
320 	case S_IFIFO:
321 	case S_IFCHR:
322 	case S_IFBLK:
323 	case S_IFSOCK:
324 		if (fNode->di_format != XFS_DINODE_FMT_DEV)
325 			return false;
326 		break;
327 	case S_IFREG:
328 	case S_IFLNK:
329 	case S_IFDIR:
330 		if (!VerifyFork(XFS_DATA_FORK)) {
331 			ERROR("Invalid data fork in inode");
332 			return false;
333 		}
334 		break;
335 	case 0:
336 		// Uninitialized inode is fine
337 		break;
338 	default:
339 		return false;
340 	}
341 
342 	if (fNode->di_forkoff) {
343 		if (!VerifyFork(XFS_ATTR_FORK)) {
344 			ERROR("Invalid attribute fork in inode");
345 			return false;
346 		}
347 	} else {
348 		/*
349 			If there is no fork offset, this may be a freshly-made inode
350 			in a new disk cluster, in which case di_aformat is zeroed.
351 			Otherwise, such an inode must be in EXTENTS format; this goes
352 			for freed inodes as well.
353 		 */
354 		switch (fNode->di_aformat) {
355 		case 0:
356 		case XFS_DINODE_FMT_EXTENTS:
357 			break;
358 		default:
359 			return false;
360 		}
361 
362 		if (fNode->di_naextents)
363 			return false;
364 	}
365 
366 	// TODO : Add reflink and big-timestamps check using di_flags2
367 
368 	return true;
369 }
370 
371 
372 uint32
373 Inode::CoreInodeSize() const
374 {
375 	if (Version() == 3)
376 		return sizeof(struct xfs_inode_t);
377 
378 	return offsetof(struct xfs_inode_t, di_crc);
379 }
380 
381 
382 status_t
383 Inode::Init()
384 {
385 	fNode = new(std::nothrow) xfs_inode_t;
386 	if (fNode == NULL)
387 		return B_NO_MEMORY;
388 
389 	uint16 inodeSize = fVolume->InodeSize();
390 	fBuffer = new(std::nothrow) char[inodeSize];
391 	if (fBuffer == NULL)
392 		return B_NO_MEMORY;
393 
394 	status_t status = GetFromDisk();
395 	if (status == B_OK) {
396 		if (VerifyInode()) {
397 			TRACE("Init(): Inode successfully read.\n");
398 			status = B_OK;
399 		} else {
400 			TRACE("Init(): Inode wasn't read successfully!\n");
401 			status = B_BAD_VALUE;
402 		}
403 	}
404 
405 	return status;
406 }
407 
408 
409 Inode::~Inode()
410 {
411 	delete fNode;
412 	delete[] fBuffer;
413 	delete[] fExtents;
414 }
415 
416 
417 bool
418 Inode::HasFileTypeField() const
419 {
420 	if((fNode->Version() == 3 && fVolume->XfsHasIncompatFeature())
421 			|| (fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE))
422 		return true;
423 
424 	return false;
425 }
426 
427 
428 status_t
429 Inode::CheckPermissions(int accessMode) const
430 {
431 	// you never have write access to a read-only volume
432 	if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
433 		return B_READ_ONLY_DEVICE;
434 
435 	return check_access_permissions(accessMode, Mode(),
436 		(uint32)fNode->GroupId(), (uint32)fNode->UserId());
437 }
438 
439 
440 uint32
441 Inode::SizeOfLongBlock()
442 {
443 	if (Version() == 3)
444 		return sizeof(LongBlock);
445 	else
446 		return offsetof(struct LongBlock, bb_blkno);
447 }
448 
449 
450 void
451 Inode::UnWrapExtentFromWrappedEntry(uint64 wrappedExtent[2],
452 	ExtentMapEntry* entry)
453 {
454 		uint64 first = B_BENDIAN_TO_HOST_INT64(wrappedExtent[0]);
455 		uint64 second = B_BENDIAN_TO_HOST_INT64(wrappedExtent[1]);
456 		entry->br_state = first >> 63;
457 		entry->br_startoff = (first & MASK(63)) >> 9;
458 		entry->br_startblock = ((first & MASK(9)) << 43) | (second >> 21);
459 		entry->br_blockcount = second & MASK(21);
460 }
461 
462 
463 status_t
464 Inode::ReadExtentsFromExtentBasedInode()
465 {
466 	fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()];
467 	char* dataStart = (char*) DIR_DFORK_PTR(Buffer(), CoreInodeSize());
468 	uint64 wrappedExtent[2];
469 	for (int i = 0; i < DataExtentsCount(); i++) {
470 		wrappedExtent[0] = *(uint64*)(dataStart);
471 		wrappedExtent[1] = *(uint64*)(dataStart + sizeof(uint64));
472 		dataStart += 2 * sizeof(uint64);
473 		UnWrapExtentFromWrappedEntry(wrappedExtent, &fExtents[i]);
474 	}
475 	return B_OK;
476 }
477 
478 
479 size_t
480 Inode::MaxRecordsPossibleInTreeRoot()
481 {
482 	size_t lengthOfDataFork;
483 	if (ForkOffset() != 0)
484 		lengthOfDataFork = ForkOffset() << 3;
485 	else if(ForkOffset() == 0) {
486 		lengthOfDataFork = GetVolume()->InodeSize()
487 			- CoreInodeSize();
488 	}
489 
490 	lengthOfDataFork -= sizeof(BlockInDataFork);
491 	return lengthOfDataFork / (XFS_KEY_SIZE + XFS_PTR_SIZE);
492 }
493 
494 
495 size_t
496 Inode::GetPtrOffsetIntoRoot(int pos)
497 {
498 	size_t maxRecords = MaxRecordsPossibleInTreeRoot();
499 	return (sizeof(BlockInDataFork)
500 		+ maxRecords * XFS_KEY_SIZE + (pos - 1) * XFS_PTR_SIZE);
501 }
502 
503 
504 TreePointer*
505 Inode::GetPtrFromRoot(int pos)
506 {
507 	return (TreePointer*)
508 		((char*)DIR_DFORK_PTR(Buffer(), CoreInodeSize()) + GetPtrOffsetIntoRoot(pos));
509 }
510 
511 
512 size_t
513 Inode::MaxRecordsPossibleNode()
514 {
515 	size_t availableSpace = GetVolume()->BlockSize();
516 	return availableSpace / (XFS_KEY_SIZE + XFS_PTR_SIZE);
517 }
518 
519 
520 size_t
521 Inode::GetPtrOffsetIntoNode(int pos)
522 {
523 	size_t maxRecords = MaxRecordsPossibleNode();
524 
525 	return SizeOfLongBlock() + maxRecords * XFS_KEY_SIZE
526 		+ (pos - 1) * XFS_PTR_SIZE;
527 }
528 
529 
530 TreePointer*
531 Inode::GetPtrFromNode(int pos, void* buffer)
532 {
533 	size_t offsetIntoNode = GetPtrOffsetIntoNode(pos);
534 	return (TreePointer*)((char*)buffer + offsetIntoNode);
535 }
536 
537 
538 status_t
539 Inode::GetNodefromTree(uint16& levelsInTree, Volume* volume,
540 	ssize_t& len, size_t DirBlockSize, char* block) {
541 
542 	char* node = new(std::nothrow) char[len];
543 	if (node == NULL)
544 		return B_NO_MEMORY;
545 		// This isn't for a directory block but for one of the tree nodes
546 
547 	ArrayDeleter<char> nodeDeleter(node);
548 
549 	TRACE("levels:(%" B_PRIu16 ")\n", levelsInTree);
550 
551 	TreePointer* ptrToNode = GetPtrFromRoot(1);
552 	uint64 fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode);
553 	uint64 readPos = FileSystemBlockToAddr(fileSystemBlockNo);
554 		// Go down the tree by taking the leftmost pointer to the first leaf
555 	while (levelsInTree != 1) {
556 		fileSystemBlockNo = B_BENDIAN_TO_HOST_INT64(*ptrToNode);
557 			// The fs block that contains node at next lower level. Now read.
558 		readPos = FileSystemBlockToAddr(fileSystemBlockNo);
559 		if (read_pos(volume->Device(), readPos, node, len) != len) {
560 			ERROR("Extent::FillBlockBuffer(): IO Error");
561 			return B_IO_ERROR;
562 		}
563 		LongBlock* curLongBlock = (LongBlock*)node;
564 		if (!VerifyHeader<LongBlock>(curLongBlock, node, this,
565 				0, NULL, XFS_BTREE)) {
566 			TRACE("Invalid Long Block");
567 			return B_BAD_VALUE;
568 		}
569 		ptrToNode = GetPtrFromNode(1, (void*)curLongBlock);
570 			// Get's the first pointer. This points to next node.
571 		levelsInTree--;
572 	}
573 	// Next level wil contain leaf nodes. Now Read Directory Buffer
574 	len = DirBlockSize;
575 	if (read_pos(volume->Device(), readPos, block, len)
576 		!= len) {
577 		ERROR("Extent::FillBlockBuffer(): IO Error");
578 		return B_IO_ERROR;
579 	}
580 	levelsInTree--;
581 	if (levelsInTree != 0)
582 		return B_BAD_VALUE;
583 	return B_OK;
584 }
585 
586 
587 status_t
588 Inode::ReadExtentsFromTreeInode()
589 {
590 	fExtents = new(std::nothrow) ExtentMapEntry[DataExtentsCount()];
591 	BlockInDataFork* root = new(std::nothrow) BlockInDataFork;
592 	if (root == NULL)
593 		return B_NO_MEMORY;
594 	memcpy((void*)root,
595 		DIR_DFORK_PTR(Buffer(), CoreInodeSize()), sizeof(BlockInDataFork));
596 
597 	uint16 levelsInTree = root->Levels();
598 	delete root;
599 
600 	Volume* volume = GetVolume();
601 	ssize_t len = volume->BlockSize();
602 
603 	len = DirBlockSize();
604 	char* block = new(std::nothrow) char[len];
605 	if (block == NULL)
606 		return B_NO_MEMORY;
607 
608 	ArrayDeleter<char> blockDeleter(block);
609 
610 	GetNodefromTree(levelsInTree, volume, len, DirBlockSize(), block);
611 
612 	uint64 fileSystemBlockNo;
613 	uint64 wrappedExtent[2];
614 	int indexIntoExtents = 0;
615 	// We should be at the left most leaf node.
616 	// This could be a multilevel node type directory
617 	while (1) {
618 		// Run till you have leaf blocks to checkout
619 		char* leafBuffer = block;
620 		if (!VerifyHeader<LongBlock>((LongBlock*)leafBuffer, leafBuffer, this,
621 				0, NULL, XFS_BTREE)) {
622 			TRACE("Invalid Long Block");
623 			return B_BAD_VALUE;
624 		}
625 
626 		uint32 offset = SizeOfLongBlock();
627 		int numRecs = ((LongBlock*)leafBuffer)->NumRecs();
628 
629 		for (int i = 0; i < numRecs; i++) {
630 			wrappedExtent[0] = *(uint64*)(leafBuffer + offset);
631 			wrappedExtent[1]
632 				= *(uint64*)(leafBuffer + offset + sizeof(uint64));
633 			offset += sizeof(ExtentMapUnwrap);
634 			UnWrapExtentFromWrappedEntry(wrappedExtent,
635 				&fExtents[indexIntoExtents]);
636 			indexIntoExtents++;
637 		}
638 
639 		fileSystemBlockNo = ((LongBlock*)leafBuffer)->Right();
640 		TRACE("Next leaf is at: (%" B_PRIu64 ")\n", fileSystemBlockNo);
641 		if (fileSystemBlockNo == (uint64) -1)
642 			break;
643 		uint64 readPos = FileSystemBlockToAddr(fileSystemBlockNo);
644 		if (read_pos(volume->Device(), readPos, block, len)
645 				!= len) {
646 				ERROR("Extent::FillBlockBuffer(): IO Error");
647 				return B_IO_ERROR;
648 		}
649 	}
650 	TRACE("Total covered: (%" B_PRId32 ")\n", indexIntoExtents);
651 	return B_OK;
652 }
653 
654 
655 status_t
656 Inode::ReadExtents()
657 {
658 	if (fExtents != NULL)
659 		return B_OK;
660 	if (Format() == XFS_DINODE_FMT_BTREE)
661 		return ReadExtentsFromTreeInode();
662 	if (Format() == XFS_DINODE_FMT_EXTENTS)
663 		return ReadExtentsFromExtentBasedInode();
664 	return B_BAD_VALUE;
665 }
666 
667 
668 int
669 Inode::SearchMapInAllExtent(uint64 blockNo)
670 {
671 	for (int i = 0; i < DataExtentsCount(); i++) {
672 		if (fExtents[i].br_startoff <= blockNo
673 			&& (blockNo <= fExtents[i].br_startoff
674 				+ fExtents[i].br_blockcount - 1)) {
675 			// Map found
676 			return i;
677 		}
678 	}
679 	return -1;
680 }
681 
682 
683 status_t
684 Inode::ReadAt(off_t pos, uint8* buffer, size_t* length)
685 {
686 	TRACE("Inode::ReadAt: pos:(%" B_PRIdOFF "), *length:(%" B_PRIuSIZE ")\n", pos, *length);
687 	status_t status;
688 	if (fExtents == NULL) {
689 		status = ReadExtents();
690 		if (status != B_OK)
691 			return status;
692 	}
693 
694 	// set/check boundaries for pos/length
695 	if (pos < 0) {
696 		ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFF
697 			", length %lu)\n", ID(), pos, *length);
698 		return B_BAD_VALUE;
699 	}
700 
701 	if (pos >= Size() || length == 0) {
702 		TRACE("inode %" B_PRIdINO ": ReadAt 0 (pos %" B_PRIdOFF
703 			", length %" B_PRIuSIZE ")\n", ID(), pos, *length);
704 		*length = 0;
705 		return B_NO_ERROR;
706 	}
707 
708 	uint32 blockNo = BLOCKNO_FROM_POSITION(pos, GetVolume());
709 	uint32 offsetIntoBlock = BLOCKOFFSET_FROM_POSITION(pos, this);
710 
711 	ssize_t lengthOfBlock = BlockSize();
712 	char* block = new(std::nothrow) char[lengthOfBlock];
713 	if (block == NULL)
714 		return B_NO_MEMORY;
715 
716 	ArrayDeleter<char> blockDeleter(block);
717 
718 	size_t lengthRead = 0;
719 	size_t lengthLeftInFile;
720 	size_t lengthLeftInBlock;
721 	size_t lengthToRead;
722 	TRACE("What is blockLen:(%" B_PRId64 ")\n", lengthOfBlock);
723 	while (*length > 0) {
724 		TRACE("Inode::ReadAt: pos:(%" B_PRIdOFF "), *length:(%" B_PRIuSIZE ")\n", pos, *length);
725 		// As long as you can read full blocks, read.
726 		lengthLeftInFile = Size() - pos;
727 		lengthLeftInBlock = lengthOfBlock - offsetIntoBlock;
728 
729 		/*
730 			We will read file in blocks of size 4096 bytes, if that
731 			is not possible we will read file of remaining bytes.
732 			This meathod will change when we will add file cache for xfs.
733 		*/
734 		if(lengthLeftInFile >= 4096) {
735 			*length = 4096;
736 		} else {
737 			*length = lengthLeftInFile;
738 		}
739 
740 		// We could be almost at the end of the file
741 		if (lengthLeftInFile <= lengthLeftInBlock)
742 			lengthToRead = lengthLeftInFile;
743 		else lengthToRead = lengthLeftInBlock;
744 
745 		// But we might not be able to read all of the
746 		// data because of less buffer length
747 		if (lengthToRead > *length)
748 			lengthToRead = *length;
749 
750 		int indexForMap = SearchMapInAllExtent(blockNo);
751 		if (indexForMap == -1)
752 			return B_BAD_VALUE;
753 
754 		xfs_daddr_t readPos
755 			= FileSystemBlockToAddr(fExtents[indexForMap].br_startblock
756 				+ blockNo - fExtents[indexForMap].br_startoff);
757 
758 		if (read_pos(GetVolume()->Device(), readPos, block, lengthOfBlock)
759 			!= lengthOfBlock) {
760 			ERROR("TreeDirectory::FillBlockBuffer(): IO Error");
761 			return B_IO_ERROR;
762 		}
763 
764 
765 		memcpy((void*) (buffer + lengthRead),
766 			(void*)(block + offsetIntoBlock), lengthToRead);
767 
768 		pos += lengthToRead;
769 		*length -= lengthToRead;
770 		lengthRead += lengthToRead;
771 		blockNo = BLOCKNO_FROM_POSITION(pos, GetVolume());
772 		offsetIntoBlock = BLOCKOFFSET_FROM_POSITION(pos, this);
773 	}
774 
775 	TRACE("lengthRead:(%" B_PRIuSIZE ")\n", lengthRead);
776 	*length = lengthRead;
777 	return B_OK;
778 }
779 
780 
781 status_t
782 Inode::GetFromDisk()
783 {
784 	xfs_agnumber_t agNo = INO_TO_AGNO(fId, fVolume);
785 		// Get the AG number from the inode
786 	uint32 agRelativeInodeNo = INO_TO_AGINO(fId, fVolume->AgInodeBits());
787 		// AG relative ino #
788 	xfs_agblock_t agBlock = INO_TO_AGBLOCK(agRelativeInodeNo, fVolume);
789 		// AG relative block number
790 	xfs_off_t offset = INO_TO_BLOCKOFFSET(fId, fVolume);
791 		// Offset into the block1
792 	uint32 len = fVolume->InodeSize();
793 		// Inode len to read (size of inode)
794 
795 	TRACE("AgNumber: (%" B_PRIu32 "), AgRelativeIno: (%" B_PRIu32 "),"
796 		"AgRelativeBlockNum: (%" B_PRIu32 "),Offset: (%" B_PRId64 "),"
797 		"len: (%" B_PRIu32 ")\n", agNo,agRelativeInodeNo, agBlock, offset, len);
798 
799 	if (agNo > fVolume->AgCount()) {
800 		ERROR("Inode::GetFromDisk : AG Number more than number of AGs");
801 		return B_ENTRY_NOT_FOUND;
802 	}
803 
804 	xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks();
805 
806 	xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
807 		((uint64)(agNo * numberOfBlocksInAg) + agBlock));
808 
809 	xfs_daddr_t readPos = blockToRead * XFS_MIN_BLOCKSIZE + offset * len;
810 
811 	if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) {
812 		ERROR("Inode::Inode(): IO Error");
813 		return B_IO_ERROR;
814 	}
815 
816 	if(fVolume->IsVersion5())
817 		memcpy(fNode, fBuffer, sizeof(xfs_inode_t));
818 	else
819 		memcpy(fNode, fBuffer, INODE_CRC_OFF);
820 
821 	fNode->SwapEndian();
822 
823 	return B_OK;
824 }
825 
826 
827 uint64
828 Inode::FileSystemBlockToAddr(uint64 block)
829 {
830 	xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks();
831 
832 	uint64 agNo = FSBLOCKS_TO_AGNO(block, fVolume);
833 	uint64 agBlockNo = FSBLOCKS_TO_AGBLOCKNO(block, fVolume);
834 
835 	xfs_fsblock_t actualBlockToRead =
836 		FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
837 			((uint64)(agNo * numberOfBlocksInAg) + agBlockNo));
838 	TRACE("blockToRead:(%" B_PRIu64 ")\n", actualBlockToRead);
839 
840 	uint64 readPos = actualBlockToRead * (XFS_MIN_BLOCKSIZE);
841 	return readPos;
842 }
843 
844 
845 /*
846  * Basically take 4 characters at a time as long as you can, and xor with
847  * previous hashVal after rotating 4 bits of hashVal. Likewise, continue
848  * xor and rotating. This is quite a generic hash function.
849 */
850 uint32
851 hashfunction(const char* name, int length)
852 {
853 	uint32 hashVal = 0;
854 	int lengthCovered = 0;
855 	int index = 0;
856 	if (length >= 4) {
857 		for (; index < length && (length - index) >= 4; index += 4)
858 		{
859 			lengthCovered += 4;
860 			hashVal = (name[index] << 21) ^ (name[index + 1] << 14)
861 				^ (name[index + 2] << 7) ^ (name[index + 3] << 0)
862 				^ ((hashVal << 28) | (hashVal >> 4));
863 		}
864 	}
865 
866 	int leftToCover = length - lengthCovered;
867 	if (leftToCover == 3) {
868 		hashVal = (name[index] << 14) ^ (name[index + 1] << 7)
869 			^ (name[index + 2] << 0) ^ ((hashVal << 21) | (hashVal >> 11));
870 	}
871 	if (leftToCover == 2) {
872 		hashVal = (name[index] << 7) ^ (name[index + 1] << 0)
873 			^ ((hashVal << 14) | (hashVal >> (32 - 14)));
874 	}
875 	if (leftToCover == 1) {
876 		hashVal = (name[index] << 0)
877 			^ ((hashVal << 7) | (hashVal >> (32 - 7)));
878 	}
879 
880 	return hashVal;
881 }