xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.h (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
1 /*
2  * Copyright 2022, Raghav Sharma, raghavself28@gmail.com
3  * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
4  * All rights reserved. Distributed under the terms of the MIT License.
5  */
6 #ifndef _INODE_H_
7 #define _INODE_H_
8 
9 
10 #include "system_dependencies.h"
11 #include "Volume.h"
12 #include "xfs_types.h"
13 
14 
15 #define INODE_MAGIC	0x494e
16 #define INODE_MINSIZE_LOG	8
17 #define INODE_MAXSIZE_LOG	11
18 #define INODE_MIN_SIZE	(1 << INODE_MINSIZE_LOG)
19 #define INODE_MAX_SIZE	(1 << INODE_MAXSIZE_LOG)
20 #define INODE_CRC_OFF	offsetof(struct xfs_inode_t, di_crc)
21 #define MAXAEXTNUM	((xfs_aextnum_t) 0x7fff)
22 #define MAXEXTNUM	((xfs_extnum_t) 0x7fffffff)
23 
24 // Does fs volume has v3 inodes?
25 #define HAS_V3INODES(volume)	(volume->IsVersion5() ? 1 : 0 )
26 
27 // Inode size for given fs
28 #define DINODE_SIZE(volume) \
29 	(HAS_V3INODES(volume) ? \
30 		sizeof(struct xfs_inode_t) : offsetof(struct xfs_inode_t, di_crc))
31 #define LITINO(volume) \
32 	((volume)->InodeSize() - DINODE_SIZE(volume))
33 
34 // inode data and attribute fork sizes
35 #define DFORK_BOFF(ino)	((int)((ino)->di_forkoff << 3))
36 
37 #define DFORK_DSIZE(ino, volume) \
38 	((ino)->di_forkoff ? DFORK_BOFF(ino) : LITINO(volume))
39 #define DFORK_ASIZE(ino, volume) \
40 	((ino)->di_forkoff ? LITINO(volume) - DFORK_BOFF(ino) : 0)
41 #define DFORK_SIZE(ino, volume, w) \
42 	((w) == XFS_DATA_FORK ? \
43 		DFORK_DSIZE(ino, volume) : DFORK_ASIZE(ino, volume))
44 
45 
46 #define INO_MASK(x)	((1ULL << (x)) - 1)
47 	// Gets 2^x - 1
48 #define INO_TO_AGNO(id, volume)	((xfs_agnumber_t)id >> (volume->AgInodeBits()))
49 	// Gets AG number from inode number
50 #define INO_TO_AGINO(id, bits)	((uint32) id & INO_MASK(bits))
51 	// Gets the AG relative inode number
52 #define INO_TO_AGBLOCK(id, volume) \
53 		(id >> (volume->InodesPerBlkLog())) \
54 		& (INO_MASK(volume->AgBlocksLog()))
55 	// Gets the AG relative block number that contains inode
56 #define INO_TO_BLOCKOFFSET(id, volume)	(id & INO_MASK(volume->InodesPerBlkLog()))
57 	// Gets the offset into the block from the inode number
58 
59 // Data and attribute fork pointers
60 #define DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) (void*) \
61 		((char*) dir_ino_ptr + DATA_FORK_OFFSET)
62 #define DIR_AFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET, forkoff) \
63 					(void*)((char*)DIR_DFORK_PTR(dir_ino_ptr, DATA_FORK_OFFSET) + \
64 					(((uint32)forkoff)<<3))
65 
66 #define MASK(n)	((1UL << n) - 1)
67 #define FSBLOCKS_TO_AGNO(n, volume)	((n) >> volume->AgBlocksLog())
68 #define FSBLOCKS_TO_AGBLOCKNO(n, volume)	((n) & MASK(volume->AgBlocksLog()))
69 #define BLOCKNO_FROM_POSITION(n, volume) \
70 	((n) >> (volume->BlockLog()))
71 #define BLOCKOFFSET_FROM_POSITION(n, inode)	((n) & (inode->BlockSize() - 1))
72 
73 
74 // Inode fork identifiers
75 #define XFS_DATA_FORK	0
76 #define XFS_ATTR_FORK	1
77 
78 #define XFS_DFORK_FORMAT(ino, w) \
79 	((w) == XFS_DATA_FORK ? (ino)->di_format : (ino)->di_aformat)
80 
81 #define XFS_DFORK_NEXTENTS(ino, w) \
82 	((w) == XFS_DATA_FORK ? (ino)->di_nextents : (ino)->di_naextents)
83 
84 #define DFORK_MAXEXT(ino, volume, w) \
85 	(DFORK_SIZE(ino, volume, w) / (2 * sizeof(uint64)))
86 
87 
88 struct LongBlock;  // Forward declaration to remove cyclic dependency
89 
90 
91 // xfs_bmdr_block
92 struct BlockInDataFork {
93 			uint16				Levels()
94 									{ return
95 										B_BENDIAN_TO_HOST_INT16(bb_level); }
96 			uint16				NumRecords()
97 									{ return
98 										B_BENDIAN_TO_HOST_INT16(bb_numrecs); }
99 			uint16				bb_level;
100 			uint16				bb_numrecs;
101 };
102 
103 
104 //xfs_da_blkinfo_t
105 struct BlockInfo {
106 			uint32				forw;
107 			uint32				back;
108 			uint16				magic;
109 			uint16				pad;
110 };
111 
112 
113 // xfs_da3_blkinfo_t
114 struct BlockInfoV5 {
115 			uint32				forw;
116 			uint32				back;
117 			uint16				magic;
118 			uint16				pad;
119 
120 			// version 5
121 
122 			uint32				crc;
123 			uint64				blkno;
124 			uint64				lsn;
125 			uuid_t				uuid;
126 			uint64				owner;
127 };
128 
129 #define XFS_BLOCK_CRC_OFF offsetof(struct BlockInfo, crc)
130 
131 
132 struct ExtentMapEntry {
133 			xfs_fileoff_t		br_startoff;
134 				// logical file block offset
135 			xfs_fsblock_t		br_startblock;
136 				// absolute block number
137 			xfs_filblks_t		br_blockcount;
138 				// # of blocks
139 			uint8				br_state;
140 				// state of the extent
141 };
142 
143 
144 struct xfs_timestamp_t {
145 		int32				t_sec;
146 		int32				t_nsec;
147 };
148 
149 
150 enum xfs_dinode_fmt_t {
151 		XFS_DINODE_FMT_DEV,
152 			// For devices
153 		XFS_DINODE_FMT_LOCAL,
154 			// For Directories and links
155 		XFS_DINODE_FMT_EXTENTS,
156 			// For large number of extents
157 		XFS_DINODE_FMT_BTREE,
158 			// Extents and Directories
159 		XFS_DINODE_FMT_UUID,
160 			// Not used
161 };
162 
163 
164 /*
165 	Dirents in version 3 directories have a file type field. Additions to this
166 	list are an on-disk format change, requiring feature bits. Valid values
167 	are as follows:
168 */
169 #define XFS_DIR3_FT_UNKNOWN		0
170 #define XFS_DIR3_FT_REG_FILE	1
171 #define XFS_DIR3_FT_DIR			2
172 #define XFS_DIR3_FT_CHRDEV		3
173 #define XFS_DIR3_FT_BLKDEV		4
174 #define XFS_DIR3_FT_FIFO		5
175 #define XFS_DIR3_FT_SOCK		6
176 #define XFS_DIR3_FT_SYMLINK		7
177 #define XFS_DIR3_FT_WHT			8
178 
179 #define XFS_DIR3_FT_MAX			9
180 
181 
182 /*
183  * The xfs_ino_t is the same for all types of inodes, the data and attribute
184  * fork might be different and that is to be handled accordingly.
185  */
186 struct xfs_inode_t {
187 			void				SwapEndian();
188 			int8				Version() const;
189 			mode_t				Mode() const;
190 			void				GetModificationTime(struct timespec&
191 									timestamp);
192 			void				GetChangeTime(struct timespec& timestamp);
193 			void				GetAccessTime(struct timespec& timestamp);
194 			void				GetCreationTime(struct timespec& timestamp);
195 
196 			int8				Format() const;
197 				// The format of the inode
198 			int8				AttrFormat() const;
199 			xfs_fsize_t			Size() const;
200 			xfs_rfsblock_t		BlockCount() const;
201 			uint32				NLink() const;
202 			uint16				Flags() const;
203 			uint32				UserId() const;
204 			uint32				GroupId() const;
205 			xfs_extnum_t		DataExtentsCount() const;
206 			xfs_extnum_t		AttrExtentsCount() const;
207 			uint8				ForkOffset() const;
208 			uint16				di_magic;
209 			uint16				di_mode;
210 				// uses standard S_Ixxx
211 			int8				di_version;
212 				//This either would be 1 or 2
213 			int8				di_format;
214 			uint16				di_onlink;
215 			uint32				di_uid;
216 			uint32				di_gid;
217 			uint32				di_nlink;
218 			uint16				di_projid;
219 			uint8				di_pad[8];
220 			uint16				di_flushiter;
221 			xfs_timestamp_t		di_atime;
222 			xfs_timestamp_t		di_mtime;
223 			xfs_timestamp_t		di_ctime;
224 			xfs_fsize_t			di_size;
225 				// size in bytes or length if link
226 			xfs_rfsblock_t		di_nblocks;
227 				// blocks used including metadata
228 				// extended attributes not included
229 			xfs_extlen_t		di_extsize;
230 				// extent size
231 			xfs_extnum_t		di_nextents;
232 				// number of data extents
233 			xfs_aextnum_t		di_naextents;
234 				// number of EA extents
235 			uint8				di_forkoff;
236 				// decides where di_a starts
237 			int8				di_aformat;
238 				// similar to di_format
239 			uint32				di_dmevmask;
240 			uint16				di_dmstate;
241 			uint16				di_flags;
242 			uint32				di_gen;
243 			uint32				di_next_unlinked;
244 
245 			// XFS Version 5
246 
247 			uint32				di_crc;
248 			uint64				di_changecount;
249 			uint64				di_lsn;
250 			uint64				di_flags2;
251 			uint32				di_cowextsize;
252 			uint8				di_pad2[12];
253 
254 			// fields only written to during inode creation
255 
256 			xfs_timestamp_t		di_crtime;
257 			uint64				di_ino;
258 			uuid_t				di_uuid;
259 };
260 
261 
262 class Inode {
263 public:
264 								Inode(Volume* volume, xfs_ino_t id);
265 								~Inode();
266 
267 			status_t			Init();
268 
269 			xfs_ino_t			ID() const { return fId; }
270 
271 			bool				VerifyInode() const;
272 
273 			bool				VerifyForkoff() const;
274 
275 			bool				VerifyFork(int WhichFork) const;
276 
277 			bool				IsDirectory() const
278 									{ return S_ISDIR(Mode()); }
279 
280 			bool				IsFile() const
281 									{ return S_ISREG(Mode()); }
282 
283 			bool				IsSymLink() const
284 									{ return S_ISLNK(Mode()); }
285 
286 			mode_t				Mode() const { return fNode->Mode(); }
287 
288 			Volume*				GetVolume() { return fVolume;}
289 
290 			int8				Format() const { return fNode->Format(); }
291 
292 			int8				AttrFormat() const { return fNode->AttrFormat(); }
293 
294 			bool				IsLocal() const
295 									{ return
296 										Format() == XFS_DINODE_FMT_LOCAL; }
297 
298 			uint32				NLink() const { return fNode->NLink(); }
299 
300 			int8				Version() const { return fNode->Version(); }
301 
302 			xfs_rfsblock_t		BlockCount() const
303 									{ return fNode->BlockCount(); }
304 
305 			char*				Buffer() { return fBuffer; }
306 
307 			int16				Flags() const { return fNode->Flags(); }
308 
309 			xfs_fsize_t			Size() const { return fNode->Size(); }
310 
311 			uint32				DirBlockSize() const
312 									{ return fVolume->DirBlockSize(); }
313 
314 			uint32				BlockSize() const
315 									{ return fVolume->BlockSize(); }
316 
317 			uint32				CoreInodeSize() const;
318 
319 			void				GetChangeTime(struct timespec& timestamp) const
320 								{ fNode->GetChangeTime(timestamp); }
321 
322 			void				GetModificationTime(struct timespec& timestamp)
323 									const
324 								{ fNode->GetModificationTime(timestamp); }
325 
326 			void				GetAccessTime(struct timespec& timestamp) const
327 								{ fNode->GetAccessTime(timestamp); }
328 
329 			void				GetCreationTime(struct timespec& timestamp) const
330 								{ fNode->GetCreationTime(timestamp); }
331 
332 			unsigned char		XfsModeToFtype() const;
333 			status_t			CheckPermissions(int accessMode) const;
334 			uint32				UserId() const { return fNode->UserId(); }
335 			uint32				GroupId() const { return fNode->GroupId(); }
336 			bool				HasFileTypeField() const;
337 			xfs_extnum_t		DataExtentsCount() const
338 									{ return fNode->DataExtentsCount(); }
339 			xfs_extnum_t		AttrExtentsCount() const
340 									{ return fNode->AttrExtentsCount(); }
341 			uint64				FileSystemBlockToAddr(uint64 block);
342 			uint8				ForkOffset() const
343 									{ return fNode->ForkOffset(); }
344 			status_t			ReadExtents();
345 			status_t			ReadAt(off_t pos, uint8* buffer, size_t* length);
346 			status_t			GetNodefromTree(uint16& levelsInTree,
347 									Volume* volume, ssize_t& len,
348 									size_t DirBlockSize, char* block);
349 			int					SearchMapInAllExtent(uint64 blockNo);
350 			void				UnWrapExtentFromWrappedEntry(
351 									uint64 wrappedExtent[2],
352 									ExtentMapEntry* entry);
353 			status_t			ReadExtentsFromExtentBasedInode();
354 			status_t			ReadExtentsFromTreeInode();
355 			size_t				MaxRecordsPossibleInTreeRoot();
356 			size_t				MaxRecordsPossibleNode();
357 			TreePointer*		GetPtrFromRoot(int pos);
358 			TreePointer*		GetPtrFromNode(int pos, void* buffer);
359 			size_t				GetPtrOffsetIntoRoot(int pos);
360 			size_t				GetPtrOffsetIntoNode(int pos);
361 			uint32				SizeOfLongBlock();
362 private:
363 			status_t			GetFromDisk();
364 			xfs_inode_t*		fNode;
365 			xfs_ino_t			fId;
366 			Volume*				fVolume;
367 			char*				fBuffer;
368 				// Contains the disk inode in BE format
369 			ExtentMapEntry*		fExtents;
370 };
371 
372 
373 uint32 hashfunction(const char* name, int length);
374 
375 
376 // A common function to return given hash lowerbound
377 template<class T> void
378 hashLowerBound(T* entry, int& left, int& right, uint32 hashValueOfRequest)
379 {
380 	int mid;
381 
382 	/*
383 	* Trying to find the lowerbound of hashValueOfRequest
384 	* This is slightly different from bsearch(), as we want the first
385 	* instance of hashValueOfRequest and not any instance.
386 	*/
387 	while (left < right) {
388 		mid = (left + right) / 2;
389 		uint32 hashval = B_BENDIAN_TO_HOST_INT32(entry[mid].hashval);
390 		if (hashval >= hashValueOfRequest) {
391 			right = mid;
392 			continue;
393 		}
394 		if (hashval < hashValueOfRequest)
395 			left = mid+1;
396 	}
397 	TRACE("left:(%" B_PRId32 "), right:(%" B_PRId32 ")\n", left, right);
398 }
399 
400 #endif
401