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