xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.cpp (revision 641b9f704b0152d363dc7c81e0971185677bce43)
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
SwapEndian()15 Inode::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 
51 void
GetModificationTime(struct timespec & stamp) const52 Inode::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 
59 void
GetAccessTime(struct timespec & stamp) const60 Inode::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 
67 void
GetChangeTime(struct timespec & stamp) const68 Inode::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 
75 void
GetCreationTime(struct timespec & stamp) const76 Inode::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 
Inode(Volume * volume,xfs_ino_t id)83 Inode::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
94 unsigned char
XfsModeToFtype() const95 Inode::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 
118 bool
VerifyFork(int whichFork) const119 Inode::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 
154 bool
VerifyForkoff() const155 Inode::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 
176 bool
VerifyInode() const177 Inode::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 
283 uint32
CoreInodeSize() const284 Inode::CoreInodeSize() const
285 {
286 	if (Version() == 3)
287 		return sizeof(Dinode);
288 
289 	return offsetof(Dinode, di_crc);
290 }
291 
292 
293 status_t
Init()294 Inode::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 
~Inode()320 Inode::~Inode()
321 {
322 	delete fNode;
323 	delete[] fBuffer;
324 	delete[] fExtents;
325 }
326 
327 
328 bool
HasFileTypeField() const329 Inode::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 
339 status_t
CheckPermissions(int accessMode) const340 Inode::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 
350 uint32
SizeOfLongBlock()351 Inode::SizeOfLongBlock()
352 {
353 	if (Version() == 3)
354 		return sizeof(LongBlock);
355 	else
356 		return LongBlock::Offset_v5();
357 }
358 
359 
360 void
UnWrapExtentFromWrappedEntry(uint64 wrappedExtent[2],ExtentMapEntry * entry)361 Inode::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 
373 status_t
ReadExtentsFromExtentBasedInode()374 Inode::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 
389 size_t
MaxRecordsPossibleInTreeRoot()390 Inode::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 
405 size_t
GetPtrOffsetIntoRoot(int pos)406 Inode::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 
414 TreePointer*
GetPtrFromRoot(int pos)415 Inode::GetPtrFromRoot(int pos)
416 {
417 	return (TreePointer*)
418 		((char*)DIR_DFORK_PTR(Buffer(), CoreInodeSize()) + GetPtrOffsetIntoRoot(pos));
419 }
420 
421 
422 size_t
MaxRecordsPossibleNode()423 Inode::MaxRecordsPossibleNode()
424 {
425 	size_t availableSpace = GetVolume()->BlockSize();
426 	return availableSpace / (XFS_KEY_SIZE + XFS_PTR_SIZE);
427 }
428 
429 
430 size_t
GetPtrOffsetIntoNode(int pos)431 Inode::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 
440 TreePointer*
GetPtrFromNode(int pos,void * buffer)441 Inode::GetPtrFromNode(int pos, void* buffer)
442 {
443 	size_t offsetIntoNode = GetPtrOffsetIntoNode(pos);
444 	return (TreePointer*)((char*)buffer + offsetIntoNode);
445 }
446 
447 
448 status_t
GetNodefromTree(uint16 & levelsInTree,Volume * volume,ssize_t & len,size_t DirBlockSize,char * block)449 Inode::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 
497 status_t
ReadExtentsFromTreeInode()498 Inode::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 
565 status_t
ReadExtents()566 Inode::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 
578 int
SearchMapInAllExtent(uint64 blockNo)579 Inode::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 
593 status_t
ReadAt(off_t pos,uint8 * buffer,size_t * length)594 Inode::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 
691 status_t
GetFromDisk()692 Inode::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 
737 uint64
FileSystemBlockToAddr(uint64 block)738 Inode::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 */
760 uint32
hashfunction(const char * name,int length)761 hashfunction(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