xref: /haiku/src/add-ons/kernel/file_systems/ufs2/Inode.cpp (revision 553f3f2309e87d95345220463fa865d5fd8cf28d)
1 /*
2  * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com
3  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
4  * All rights reserved. Distributed under the terms of the MIT License.
5  */
6 
7 #include "Inode.h"
8 #include <string.h>
9 
10 
11 #define TRACE_UFS2
12 #ifdef TRACE_UFS2
13 #define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x)
14 #else
15 #define TRACE(x...) ;
16 #endif
17 #define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x)
18 
19 
20 Inode::Inode(Volume* volume, ino_t id)
21 	:
22 	fVolume(volume),
23 	fID(id),
24 	fCache(NULL),
25 	fMap(NULL)
26 {
27 	rw_lock_init(&fLock, "ufs2 inode");
28 
29 	fInitStatus = B_OK;//UpdateNodeFromDisk();
30 	if (fInitStatus == B_OK) {
31 		if (!IsDirectory() && !IsSymLink()) {
32 			fCache = file_cache_create(fVolume->ID(), ID(), Size());
33 			fMap = file_map_create(fVolume->ID(), ID(), Size());
34 		}
35 	}
36 	int fd = fVolume->Device();
37 	ufs2_super_block* superblock = (ufs2_super_block* )&fVolume->SuperBlock();
38 	int64_t fs_block = ino_to_fsba(superblock, id);
39 	int64_t offset_in_block = ino_to_fsbo(superblock, id);
40 	int64_t offset = fs_block * MINBSIZE + offset_in_block * sizeof(fNode);
41 
42 	if (read_pos(fd, offset, (void*)&fNode, sizeof(fNode)) != sizeof(fNode))
43 		ERROR("Inode::Inode(): IO Error\n");
44 
45 
46 }
47 
48 
49 Inode::Inode(Volume* volume, ino_t id, const ufs2_inode& item)
50 	:
51 	fVolume(volume),
52 	fID(id),
53 	fCache(NULL),
54 	fMap(NULL),
55 	fInitStatus(B_OK),
56 	fNode(item)
57 {
58 	if (!IsDirectory() && !IsSymLink()) {
59 		fCache = file_cache_create(fVolume->ID(), ID(), Size());
60 		fMap = file_map_create(fVolume->ID(), ID(), Size());
61 	}
62 }
63 
64 
65 Inode::Inode(Volume* volume)
66 	:
67 	fVolume(volume),
68 	fID(0),
69 	fCache(NULL),
70 	fMap(NULL),
71 	fInitStatus(B_NO_INIT)
72 {
73 	rw_lock_init(&fLock, "ufs2 inode");
74 }
75 
76 
77 Inode::~Inode()
78 {
79 	TRACE("Inode destructor\n");
80 	file_cache_delete(FileCache());
81 	file_map_delete(Map());
82 	TRACE("Inode destructor: Done\n");
83 }
84 
85 
86 status_t
87 Inode::InitCheck()
88 {
89 	return fInitStatus;
90 }
91 
92 
93 status_t
94 Inode::ReadAt(off_t file_offset, uint8* buffer, size_t* _length)
95 {
96 	int fd = fVolume->Device();
97 	ufs2_super_block super_block = fVolume->SuperBlock();
98 	int32_t blockSize = super_block.fs_bsize;
99 	off_t pos;
100 	int64_t size = Size();
101 	off_t startBlockNumber = file_offset / blockSize;
102 	off_t endBlockNumber = (file_offset + *_length) / blockSize;
103 	off_t blockOffset = file_offset % blockSize;
104 	ssize_t length = 0;
105 	if (startBlockNumber != endBlockNumber) {
106 		ssize_t remainingLength = blockSize - blockOffset;
107 		for (; startBlockNumber <= endBlockNumber; startBlockNumber++) {
108 			//code for reading multiple blocks
109 			pos = FindBlock(startBlockNumber, blockOffset);
110 			length += read_pos(fd, pos, buffer, remainingLength);
111 			blockOffset = 0;
112 			remainingLength = *_length - length;
113 			if (remainingLength > blockSize)
114 				remainingLength = blockSize;
115 		}
116 		*_length = length;
117 		return B_OK;
118 	}
119 	pos = FindBlock(startBlockNumber, blockOffset);
120 	length = read_pos(fd, pos, buffer, *_length);
121 	*_length = length;
122 	return B_OK;
123 
124 }
125 
126 
127 off_t
128 Inode::FindBlock(off_t blockNumber, off_t blockOffset)
129 {
130 	int fd = fVolume->Device();
131 	ufs2_super_block super_block = fVolume->SuperBlock();
132 	int32_t blockSize = super_block.fs_bsize;
133 	int32_t fragmentSize = super_block.fs_fsize;
134 	off_t indirectOffset;
135 	int64_t directBlock;
136 	off_t numberOfBlockPointers = blockSize / 8;
137 	const off_t numberOfIndirectBlocks = numberOfBlockPointers;
138 	const off_t numberOfDoubleIndirectBlocks = numberOfBlockPointers
139 		* numberOfBlockPointers;
140 	if (blockNumber < 12) {
141 		// read from direct block
142 		return GetBlockPointer(blockNumber) * fragmentSize + blockOffset;
143 
144 	} else if (blockNumber < numberOfIndirectBlocks + 12) {
145 		//read from indirect block
146 		blockNumber = blockNumber - 12;
147 		indirectOffset = GetIndirectBlockPointer() *
148 			fragmentSize + (8 * blockNumber);
149 		read_pos(fd, indirectOffset,
150 			(void*)&directBlock, sizeof(directBlock));
151 
152 		return directBlock * fragmentSize + blockOffset;
153 
154 	} else if (blockNumber < numberOfDoubleIndirectBlocks
155 			+ numberOfIndirectBlocks + 12) {
156 		// Data is in double indirect block
157 		// Subract the already read blocks
158 		blockNumber = blockNumber - numberOfBlockPointers - 12;
159 		// Calculate indirect block inside double indirect block
160 		off_t indirectBlockNumber = blockNumber / numberOfBlockPointers;
161 		indirectOffset = GetDoubleIndirectBlockPtr() *
162 			fragmentSize + (8 * indirectBlockNumber);
163 
164 		int64_t indirectPointer;
165 		read_pos(fd, indirectOffset,
166 			(void*)&indirectPointer, sizeof(directBlock));
167 
168 		indirectOffset = indirectPointer * fragmentSize
169 			+ (8 * (blockNumber % numberOfBlockPointers));
170 
171 		read_pos(fd, indirectOffset,
172 			(void*)&directBlock, sizeof(directBlock));
173 
174 		return directBlock * fragmentSize + blockOffset;
175 
176 	} else if (blockNumber < (numberOfIndirectBlocks
177 				* numberOfDoubleIndirectBlocks)
178 				+ (numberOfDoubleIndirectBlocks + numberOfBlockPointers + 12)) {
179 		// Reading from triple indirect block
180 		blockNumber = blockNumber - numberOfDoubleIndirectBlocks
181 			- numberOfBlockPointers - 12;
182 
183 		// Get double indirect block
184 		// Double indirect block no
185 		off_t indirectBlockNumber = blockNumber / numberOfDoubleIndirectBlocks;
186 
187 		// offset to double indirect block ptr
188 		indirectOffset = GetTripleIndirectBlockPtr() *
189 			fragmentSize + (8 * indirectBlockNumber);
190 
191 		int64_t indirectPointer;
192 		// Get the double indirect block ptr
193 		read_pos(fd, indirectOffset,
194 			(void*)&indirectPointer, sizeof(directBlock));
195 
196 		// Get the indirect block
197 		// number of indirect block ptr
198 		indirectBlockNumber = blockNumber / numberOfBlockPointers;
199 		// Indirect block ptr offset
200 		indirectOffset = indirectPointer * fragmentSize
201 			+ (8 * indirectBlockNumber);
202 
203 		read_pos(fd, indirectOffset,
204 			(void*)&indirectPointer, sizeof(directBlock));
205 
206 		// Get direct block pointer
207 		indirectOffset = indirectPointer * fragmentSize
208 			+ (8 * (blockNumber % numberOfBlockPointers));
209 
210 		read_pos(fd, indirectOffset,
211 			(void*)&directBlock, sizeof(directBlock));
212 
213 		return directBlock * fragmentSize + blockOffset;
214 	}
215 
216 	return B_BAD_VALUE;
217 }
218 
219 
220 status_t
221 Inode::ReadLink(char* buffer, size_t *_bufferSize)
222 {
223 	strlcpy(buffer, fNode.symlinkpath, *_bufferSize);
224 	return B_OK;
225 }
226