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