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
Inode(Volume * volume,ino_t id)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
Inode(Volume * volume,ino_t id,const ufs2_inode & item)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
Inode(Volume * volume)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
~Inode()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
InitCheck()89 Inode::InitCheck()
90 {
91 return fInitStatus;
92 }
93
94
95 status_t
ReadAt(off_t file_offset,uint8 * buffer,size_t * _length)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
FindBlock(off_t blockNumber,off_t blockOffset)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
ReadLink(char * buffer,size_t * _bufferSize)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
CheckPermissions(int accessMode) const238 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