xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.cpp (revision 20308ad6a7acd17d4a5c93c2b4248497468b2044)
1 /*
2  * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Inode.h"
8 
9 
10 void
11 xfs_inode_t::SwapEndian()
12 {
13 	di_magic = B_BENDIAN_TO_HOST_INT16(di_magic);
14 	di_mode = B_BENDIAN_TO_HOST_INT16(di_mode);
15 	di_onlink = B_BENDIAN_TO_HOST_INT16(di_onlink);
16 	di_uid = B_BENDIAN_TO_HOST_INT32(di_uid);
17 	di_gid = B_BENDIAN_TO_HOST_INT32(di_gid);
18 	di_nlink = B_BENDIAN_TO_HOST_INT32(di_nlink);
19 	di_projid = B_BENDIAN_TO_HOST_INT16(di_projid);
20 	di_flushiter = B_BENDIAN_TO_HOST_INT16(di_flushiter);
21 	di_atime.t_sec = B_BENDIAN_TO_HOST_INT32(di_atime.t_sec);
22 	di_atime.t_nsec = B_BENDIAN_TO_HOST_INT32(di_atime.t_nsec);
23 	di_mtime.t_sec = B_BENDIAN_TO_HOST_INT32(di_mtime.t_sec);
24 	di_mtime.t_nsec = B_BENDIAN_TO_HOST_INT32(di_mtime.t_nsec);
25 	di_ctime.t_sec = B_BENDIAN_TO_HOST_INT32(di_ctime.t_sec);
26 	di_ctime.t_nsec = B_BENDIAN_TO_HOST_INT32(di_ctime.t_nsec);
27 	di_size = B_BENDIAN_TO_HOST_INT64(di_size);
28 	di_nblocks =  B_BENDIAN_TO_HOST_INT64(di_nblocks);
29 	di_extsize = B_BENDIAN_TO_HOST_INT32(di_extsize);
30 	di_nextents = B_BENDIAN_TO_HOST_INT32(di_nextents);
31 	di_anextents = B_BENDIAN_TO_HOST_INT16(di_anextents);
32 	di_dmevmask = B_BENDIAN_TO_HOST_INT32(di_dmevmask);
33 	di_dmstate = B_BENDIAN_TO_HOST_INT16(di_dmstate);
34 	di_flags = B_BENDIAN_TO_HOST_INT16(di_flags);
35 	di_gen = B_BENDIAN_TO_HOST_INT32(di_gen);
36 	di_next_unlinked = B_BENDIAN_TO_HOST_INT32(di_next_unlinked);
37 }
38 
39 
40 uint8
41 xfs_inode_t::ForkOffset() const
42 {
43 	return di_forkoff;
44 }
45 
46 
47 xfs_rfsblock_t
48 xfs_inode_t::BlockCount() const
49 {
50 	return di_nblocks;
51 }
52 
53 
54 xfs_fsize_t
55 xfs_inode_t::Size() const
56 {
57 	return di_size;
58 }
59 
60 
61 mode_t
62 xfs_inode_t::Mode() const
63 {
64 	return di_mode;
65 }
66 
67 
68 uint32
69 xfs_inode_t::UserId() const
70 {
71 	return di_uid;
72 }
73 
74 
75 uint32
76 xfs_inode_t::GroupId() const
77 {
78 	return di_gid;
79 }
80 
81 
82 void
83 xfs_inode_t::GetModificationTime(struct timespec& stamp)
84 {
85 	stamp.tv_sec = di_mtime.t_sec;
86 	stamp.tv_nsec = di_mtime.t_nsec;
87 }
88 
89 
90 void
91 xfs_inode_t::GetAccessTime(struct timespec& stamp)
92 {
93 	stamp.tv_sec = di_atime.t_sec;
94 	stamp.tv_nsec = di_atime.t_nsec;
95 }
96 
97 
98 void
99 xfs_inode_t::GetChangeTime(struct timespec& stamp)
100 {
101 	stamp.tv_sec = di_ctime.t_sec;
102 	stamp.tv_nsec = di_ctime.t_nsec;
103 }
104 
105 
106 uint32
107 xfs_inode_t::NLink() const
108 {
109 	return di_nlink;
110 }
111 
112 
113 int8
114 xfs_inode_t::Version() const
115 {
116 	return di_version;
117 }
118 
119 
120 uint16
121 xfs_inode_t::Flags() const
122 {
123 	return di_flags;
124 }
125 
126 
127 int8
128 xfs_inode_t::Format() const
129 {
130 	return di_format;
131 }
132 
133 
134 xfs_extnum_t
135 xfs_inode_t::DataExtentsCount() const
136 {
137 	return di_nextents;
138 }
139 
140 
141 Inode::Inode(Volume* volume, xfs_ino_t id)
142 	:
143 	fVolume(volume),
144 	fId(id)
145 {
146 
147 }
148 
149 
150 status_t
151 Inode::Init()
152 {
153 	fNode = new(std::nothrow) xfs_inode_t;
154 	if (fNode == NULL)
155 		return B_NO_MEMORY;
156 
157 	uint16 inodeSize = fVolume->InodeSize();
158 	fBuffer = new(std::nothrow) char[inodeSize];
159 	if (fBuffer == NULL)
160 		return B_NO_MEMORY;
161 
162 	status_t status = GetFromDisk();
163 	if (status == B_OK) {
164 		if (fNode->di_magic == INODE_MAGIC) {
165 			TRACE("Init(): Inode successfully read.\n");
166 			status = B_OK;
167 		} else {
168 			TRACE("Init(): Inode wasn't read successfully!\n");
169 			status = B_BAD_VALUE;
170 		}
171 	}
172 
173 	return status;
174 }
175 
176 
177 bool
178 Inode::HasFileTypeField() const
179 {
180 	return fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE;
181 }
182 
183 
184 status_t
185 Inode::CheckPermissions(int accessMode) const
186 {
187 	// you never have write access to a read-only volume
188 	if ((accessMode & W_OK) != 0 && fVolume->IsReadOnly())
189 		return B_READ_ONLY_DEVICE;
190 
191 	return check_access_permissions(accessMode, Mode(),
192 		(uint32)fNode->GroupId(), (uint32)fNode->UserId());
193 }
194 
195 
196 status_t
197 Inode::GetFromDisk()
198 {
199 	xfs_agnumber_t agNo = INO_TO_AGNO(fId, fVolume);
200 		// Get the AG number from the inode
201 	uint32 agRelativeInodeNo = INO_TO_AGINO(fId, fVolume->AgInodeBits());
202 		// AG relative ino #
203 	xfs_agblock_t agBlock = INO_TO_AGBLOCK(agRelativeInodeNo, fVolume);
204 		// AG relative block number
205 	xfs_off_t offset = INO_TO_BLOCKOFFSET(fId, fVolume);
206 		// Offset into the block1
207 	uint32 len = fVolume->InodeSize();
208 		// Inode len to read (size of inode)
209 
210 	TRACE("AgNumber: (%d), AgRelativeIno: (%d), AgRelativeBlockNum: (%d),"
211 		"Offset: (%d), len: (%d)\n", agNo,
212 		agRelativeInodeNo, agBlock, offset, len);
213 
214 	if (agNo > fVolume->AgCount()) {
215 		ERROR("Inode::GetFromDisk : AG Number more than number of AGs");
216 		return B_ENTRY_NOT_FOUND;
217 	}
218 
219 	xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks();
220 
221 	xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
222 		((uint64)(agNo * numberOfBlocksInAg) + agBlock));
223 
224 	xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE + offset * len;
225 
226 	if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) {
227 		ERROR("Inode::Inode(): IO Error");
228 		return B_IO_ERROR;
229 	}
230 
231 	memcpy(fNode, fBuffer, INODE_CORE_UNLINKED_SIZE);
232 	fNode->SwapEndian();
233 
234 	return B_OK;
235 }
236 
237 
238 uint64
239 Inode::FileSystemBlockToAddr(uint64 block)
240 {
241 	xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks();
242 
243 	uint64 agNo = FSBLOCKS_TO_AGNO(block, fVolume);
244 	uint64 agBlockNo = FSBLOCKS_TO_AGBLOCKNO(block, fVolume);
245 
246 	xfs_fsblock_t actualBlockToRead =
247 		FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
248 			((uint64)(agNo * numberOfBlocksInAg) + agBlockNo));
249 	TRACE("blockToRead:(%d)\n", actualBlockToRead);
250 
251 	uint64 readPos = actualBlockToRead * (BASICBLOCKSIZE);
252 	return readPos;
253 }
254 
255 
256 Inode::~Inode()
257 {
258 	delete fBuffer;
259 	delete fNode;
260 }
261 
262 
263 /*
264  * Basically take 4 characters at a time as long as you can, and xor with
265  * previous hashVal after rotating 4 bits of hashVal. Likewise, continue
266  * xor and rotating. This is quite a generic hash function.
267 */
268 uint32
269 hashfunction(const char* name, int length)
270 {
271 	uint32 hashVal = 0;
272 	int lengthCovered = 0;
273 	int index = 0;
274 	if (length >= 4) {
275 		for (;index < length && (length - index) >= 4; index += 4)
276 		{
277 			lengthCovered += 4;
278 			hashVal = (name[index] << 21) ^ (name[index+1] << 14)
279 				^ (name[index+2] << 7) ^ (name[index+3] << 0)
280 				^ ((hashVal << 28) | (hashVal >> (4)));
281 		}
282 	}
283 
284 	int leftToCover = length - lengthCovered;
285 	if (leftToCover == 3) {
286 		hashVal = (name[index] << 14) ^ (name[index+1] << 7)
287 			^ (name[index+2] << 0) ^ ((hashVal << 21) | (hashVal >> (11)));
288 	}
289 	if (leftToCover == 2) {
290 		hashVal = (name[index] << 7) ^ (name[index+1] << 0)
291 			^ ((hashVal << 14) | (hashVal >> (32 - 14)));
292 	}
293 	if (leftToCover == 1) {
294 		hashVal = (name[index] << 0)
295 			^ ((hashVal << 7) | (hashVal >> (32 - 7)));
296 	}
297 
298 	return hashVal;
299 }
300