xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.cpp (revision 46c7a1d9de8313e26c12405513abd31e5dd3ce06)
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 xfs_rfsblock_t
41 xfs_inode_t::BlockCount() const
42 {
43 	return di_nblocks;
44 }
45 
46 
47 xfs_fsize_t
48 xfs_inode_t::Size() const
49 {
50 	return di_size;
51 }
52 
53 
54 mode_t
55 xfs_inode_t::Mode() const
56 {
57 	return di_mode;
58 }
59 
60 
61 uint32
62 xfs_inode_t::UserId() const
63 {
64 	return di_uid;
65 }
66 
67 
68 uint32
69 xfs_inode_t::GroupId() const
70 {
71 	return di_gid;
72 }
73 
74 
75 void
76 xfs_inode_t::GetModificationTime(struct timespec& stamp)
77 {
78 	stamp.tv_sec = di_mtime.t_sec;
79 	stamp.tv_nsec = di_mtime.t_nsec;
80 }
81 
82 
83 void
84 xfs_inode_t::GetAccessTime(struct timespec& stamp)
85 {
86 	stamp.tv_sec = di_atime.t_sec;
87 	stamp.tv_nsec = di_atime.t_nsec;
88 }
89 
90 
91 void
92 xfs_inode_t::GetChangeTime(struct timespec& stamp)
93 {
94 	stamp.tv_sec = di_ctime.t_sec;
95 	stamp.tv_nsec = di_ctime.t_nsec;
96 }
97 
98 
99 uint32
100 xfs_inode_t::NLink() const
101 {
102 	return di_nlink;
103 }
104 
105 
106 int8
107 xfs_inode_t::Version() const
108 {
109 	return di_version;
110 }
111 
112 
113 uint16
114 xfs_inode_t::Flags() const
115 {
116 	return di_flags;
117 }
118 
119 
120 int8
121 xfs_inode_t::Format() const
122 {
123 	return di_format;
124 }
125 
126 
127 xfs_extnum_t
128 xfs_inode_t::DataExtentsCount() const
129 {
130 	return di_nextents;
131 }
132 
133 
134 Inode::Inode(Volume* volume, xfs_ino_t id)
135 	:
136 	fVolume(volume),
137 	fId(id)
138 {
139 
140 }
141 
142 
143 status_t
144 Inode::Init()
145 {
146 	fNode = new(std::nothrow) xfs_inode_t;
147 	if (fNode == NULL)
148 		return B_NO_MEMORY;
149 
150 	uint16 inodeSize = fVolume->InodeSize();
151 	fBuffer = new(std::nothrow) char[inodeSize];
152 	if (fBuffer == NULL)
153 		return B_NO_MEMORY;
154 
155 	status_t status = GetFromDisk();
156 	if (status == B_OK) {
157 		if (fNode->di_magic == INODE_MAGIC) {
158 			TRACE("Init(): Inode successfully read.\n");
159 			status = B_OK;
160 		} else {
161 			TRACE("Init(): Inode wasn't read successfully!\n");
162 			status = B_BAD_VALUE;
163 		}
164 	}
165 
166 	return status;
167 }
168 
169 
170 bool
171 Inode::HasFileTypeField() const
172 {
173 	return fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE;
174 }
175 
176 
177 status_t
178 Inode::GetFromDisk()
179 {
180 	xfs_agnumber_t agNo = INO_TO_AGNO(fId, fVolume);
181 		// Get the AG number from the inode
182 	uint32 agRelativeInodeNo = INO_TO_AGINO(fId, fVolume->AgInodeBits());
183 		// AG relative ino #
184 	xfs_agblock_t agBlock = INO_TO_AGBLOCK(agRelativeInodeNo, fVolume);
185 		// AG relative block number
186 	xfs_off_t offset = INO_TO_BLOCKOFFSET(fId, fVolume);
187 		// Offset into the block1
188 	uint32 len = fVolume->InodeSize();
189 		// Inode len to read (size of inode)
190 
191 	TRACE("AgNumber: (%d), AgRelativeIno: (%d), AgRelativeBlockNum: (%d),"
192 		"Offset: (%d), len: (%d)\n", agNo,
193 		agRelativeInodeNo, agBlock, offset, len);
194 
195 	if (agNo > fVolume->AgCount()) {
196 		ERROR("Inode::GetFromDisk : AG Number more than number of AGs");
197 		return B_ENTRY_NOT_FOUND;
198 	}
199 
200 	xfs_agblock_t numberOfBlocksInAg = fVolume->AgBlocks();
201 
202 	xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(),
203 		((uint64)(agNo * numberOfBlocksInAg) + agBlock));
204 
205 	xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE + offset * len;
206 
207 	if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) {
208 		ERROR("Inode::Inode(): IO Error");
209 		return B_IO_ERROR;
210 	}
211 
212 	memcpy(fNode, fBuffer, INODE_CORE_UNLINKED_SIZE);
213 	fNode->SwapEndian();
214 
215 	return B_OK;
216 }
217 
218 
219 Inode::~Inode()
220 {
221 	delete fBuffer;
222 	delete fNode;
223 }
224 
225 
226 /*
227  * Basically take 4 characters at a time as long as you can, and xor with
228  * previous hashVal after rotating 4 bits of hashVal. Likewise, continue
229  * xor and rotating. This is quite a generic hash function.
230 */
231 uint32
232 hashfunction(const char* name, int length)
233 {
234 	uint32 hashVal = 0;
235 	int lengthCovered = 0;
236 	int index = 0;
237 	if (length >= 4) {
238 		for (;index < length && (length - index) >= 4; index += 4)
239 		{
240 			lengthCovered += 4;
241 			hashVal = (name[index] << 21) ^ (name[index+1] << 14)
242 				^ (name[index+2] << 7) ^ (name[index+3] << 0)
243 				^ ((hashVal << 28) | (hashVal >> (4)));
244 		}
245 	}
246 
247 	int leftToCover = length - lengthCovered;
248 	if (leftToCover == 3) {
249 		hashVal = (name[index] << 14) ^ (name[index+1] << 7)
250 			^ (name[index+2] << 0) ^ ((hashVal << 21) | (hashVal >> (11)));
251 	}
252 	if (leftToCover == 2) {
253 		hashVal = (name[index] << 7) ^ (name[index+1] << 0)
254 			^ ((hashVal << 14) | (hashVal >> (32 - 14)));
255 	}
256 	if (leftToCover == 1) {
257 		hashVal = (name[index] << 0)
258 			^ ((hashVal << 7) | (hashVal >> (32 - 7)));
259 	}
260 
261 	return hashVal;
262 }
263