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