xref: /haiku/src/add-ons/kernel/file_systems/ufs2/Inode.cpp (revision c9afad22682e9f15753db4e9ca8684e2d4a643a9)
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 	int fd = fVolume->Device();
30 	ufs2_super_block* superblock = (ufs2_super_block* )&fVolume->SuperBlock();
31 	int64_t fs_block = ino_to_fsba(superblock, id);
32 	int64_t offset_in_block = ino_to_fsbo(superblock, id);
33 	int64_t offset = fs_block * superblock->fs_fsize + offset_in_block * sizeof(fNode);
34 
35 	if (read_pos(fd, offset, (void*)&fNode, sizeof(fNode)) != sizeof(fNode)) {
36 		ERROR("Inode::Inode(): IO Error\n");
37 		fInitStatus = B_IO_ERROR;
38 		return;
39 	}
40 	fInitStatus = B_OK;
41 
42 	if (fInitStatus == B_OK) {
43 		if (!IsDirectory() && !IsSymLink()) {
44 			fCache = file_cache_create(fVolume->ID(), ID(), Size());
45 			fMap = file_map_create(fVolume->ID(), ID(), Size());
46 		}
47 	}
48 }
49 
50 
51 Inode::Inode(Volume* volume, ino_t id, const ufs2_inode& item)
52 	:
53 	fVolume(volume),
54 	fID(id),
55 	fCache(NULL),
56 	fMap(NULL),
57 	fInitStatus(B_OK),
58 	fNode(item)
59 {
60 	if (!IsDirectory() && !IsSymLink()) {
61 		fCache = file_cache_create(fVolume->ID(), ID(), Size());
62 		fMap = file_map_create(fVolume->ID(), ID(), Size());
63 	}
64 }
65 
66 
67 Inode::Inode(Volume* volume)
68 	:
69 	fVolume(volume),
70 	fID(0),
71 	fCache(NULL),
72 	fMap(NULL),
73 	fInitStatus(B_NO_INIT)
74 {
75 	rw_lock_init(&fLock, "ufs2 inode");
76 }
77 
78 
79 Inode::~Inode()
80 {
81 	TRACE("Inode destructor\n");
82 	file_cache_delete(FileCache());
83 	file_map_delete(Map());
84 	TRACE("Inode destructor: Done\n");
85 }
86 
87 
88 status_t
89 Inode::InitCheck()
90 {
91 	return fInitStatus;
92 }
93 
94 
95 status_t
96 Inode::ReadAt(off_t file_offset, uint8* buffer, size_t* _length)
97 {
98 	int fd = fVolume->Device();
99 	ufs2_super_block super_block = fVolume->SuperBlock();
100 	int32_t blockSize = super_block.fs_bsize;
101 	off_t pos;
102 	int64_t size = Size();
103 	off_t startBlockNumber = file_offset / blockSize;
104 	off_t endBlockNumber = (file_offset + *_length) / blockSize;
105 	off_t blockOffset = file_offset % blockSize;
106 	ssize_t length = 0;
107 	if (size <= file_offset || size < 0 || file_offset < 0) {
108 		*_length = 0;
109 		return B_OK;
110 	}
111 	if ((int64_t) *_length > size - file_offset)
112 		*_length = size - file_offset;
113 	if (startBlockNumber != endBlockNumber) {
114 		ssize_t remainingLength = blockSize - blockOffset;
115 		for (; startBlockNumber <= endBlockNumber; startBlockNumber++) {
116 			//code for reading multiple blocks
117 			pos = FindBlock(startBlockNumber, blockOffset);
118 			if (remainingLength > (int64_t) *_length - length)
119 				remainingLength = *_length - length;
120 			length += read_pos(fd, pos, buffer + length, remainingLength);
121 			blockOffset = 0;
122 			remainingLength = *_length - length;
123 			remainingLength = blockSize;
124 		}
125 		*_length = length;
126 		return B_OK;
127 	}
128 	pos = FindBlock(startBlockNumber, blockOffset);
129 	length = read_pos(fd, pos, buffer, *_length);
130 	*_length = length;
131 	return B_OK;
132 
133 }
134 
135 
136 off_t
137 Inode::FindBlock(off_t blockNumber, off_t blockOffset)
138 {
139 	int fd = fVolume->Device();
140 	ufs2_super_block super_block = fVolume->SuperBlock();
141 	int32_t blockSize = super_block.fs_bsize;
142 	int32_t fragmentSize = super_block.fs_fsize;
143 	off_t indirectOffset;
144 	int64_t directBlock;
145 	off_t numberOfBlockPointers = blockSize / 8;
146 	const off_t numberOfIndirectBlocks = numberOfBlockPointers;
147 	const off_t numberOfDoubleIndirectBlocks = numberOfBlockPointers
148 		* numberOfBlockPointers;
149 	if (blockNumber < 12) {
150 		// read from direct block
151 		return GetBlockPointer(blockNumber) * fragmentSize + blockOffset;
152 
153 	} else if (blockNumber < numberOfIndirectBlocks + 12) {
154 		//read from indirect block
155 		blockNumber = blockNumber - 12;
156 		indirectOffset = GetIndirectBlockPointer() *
157 			fragmentSize + (8 * blockNumber);
158 		read_pos(fd, indirectOffset,
159 			(void*)&directBlock, sizeof(directBlock));
160 
161 		return directBlock * fragmentSize + blockOffset;
162 
163 	} else if (blockNumber < numberOfDoubleIndirectBlocks
164 			+ numberOfIndirectBlocks + 12) {
165 		// Data is in double indirect block
166 		// Subract the already read blocks
167 		blockNumber = blockNumber - numberOfBlockPointers - 12;
168 		// Calculate indirect block inside double indirect block
169 		off_t indirectBlockNumber = blockNumber / numberOfBlockPointers;
170 		indirectOffset = GetDoubleIndirectBlockPtr() *
171 			fragmentSize + (8 * indirectBlockNumber);
172 
173 		int64_t indirectPointer;
174 		read_pos(fd, indirectOffset,
175 			(void*)&indirectPointer, sizeof(directBlock));
176 
177 		indirectOffset = indirectPointer * fragmentSize
178 			+ (8 * (blockNumber % numberOfBlockPointers));
179 
180 		read_pos(fd, indirectOffset,
181 			(void*)&directBlock, sizeof(directBlock));
182 
183 		return directBlock * fragmentSize + blockOffset;
184 
185 	} else if (blockNumber < (numberOfIndirectBlocks
186 				* numberOfDoubleIndirectBlocks)
187 				+ (numberOfDoubleIndirectBlocks + numberOfBlockPointers + 12)) {
188 		// Reading from triple indirect block
189 		blockNumber = blockNumber - numberOfDoubleIndirectBlocks
190 			- numberOfBlockPointers - 12;
191 
192 		// Get double indirect block
193 		// Double indirect block no
194 		off_t indirectBlockNumber = blockNumber / numberOfDoubleIndirectBlocks;
195 
196 		// offset to double indirect block ptr
197 		indirectOffset = GetTripleIndirectBlockPtr() *
198 			fragmentSize + (8 * indirectBlockNumber);
199 
200 		int64_t indirectPointer;
201 		// Get the double indirect block ptr
202 		read_pos(fd, indirectOffset,
203 			(void*)&indirectPointer, sizeof(directBlock));
204 
205 		// Get the indirect block
206 		// number of indirect block ptr
207 		indirectBlockNumber = blockNumber / numberOfBlockPointers;
208 		// Indirect block ptr offset
209 		indirectOffset = indirectPointer * fragmentSize
210 			+ (8 * indirectBlockNumber);
211 
212 		read_pos(fd, indirectOffset,
213 			(void*)&indirectPointer, sizeof(directBlock));
214 
215 		// Get direct block pointer
216 		indirectOffset = indirectPointer * fragmentSize
217 			+ (8 * (blockNumber % numberOfBlockPointers));
218 
219 		read_pos(fd, indirectOffset,
220 			(void*)&directBlock, sizeof(directBlock));
221 
222 		return directBlock * fragmentSize + blockOffset;
223 	}
224 
225 	return B_BAD_VALUE;
226 }
227 
228 
229 status_t
230 Inode::ReadLink(char* buffer, size_t *_bufferSize)
231 {
232 	strlcpy(buffer, fNode.symlinkpath, *_bufferSize);
233 	return B_OK;
234 }
235 
236 
237 status_t
238 Inode::CheckPermissions(int accessMode) const
239 {
240 	// you never have write access to a read-only volume
241 	if ((accessMode & W_OK) != 0/* && fVolume->IsReadOnly()*/)
242 		return B_READ_ONLY_DEVICE;
243 
244 	return check_access_permissions(accessMode, Mode(), (gid_t)GroupID(),
245 		(uid_t)UserID());
246 }
247