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