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
20Inode::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
51Inode::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
67Inode::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
79Inode::~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
88status_t
89Inode::InitCheck()
90{
91	return fInitStatus;
92}
93
94
95status_t
96Inode::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
136off_t
137Inode::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
229status_t
230Inode::ReadLink(char* buffer, size_t *_bufferSize)
231{
232	strlcpy(buffer, fNode.symlinkpath, *_bufferSize);
233	return B_OK;
234}
235
236
237status_t
238Inode::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