xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.h (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 DIR_AFORK_EXIST(dir_ino_ptr)	(dir_ino_ptr->di_forkoff != 0)
67 
68 #define MASK(n)	((1UL << n) - 1)
69 #define FSBLOCKS_TO_AGNO(n, volume)	((n) >> volume->AgBlocksLog())
70 #define FSBLOCKS_TO_AGBLOCKNO(n, volume)	((n) & MASK(volume->AgBlocksLog()))
71 #define BLOCKNO_FROM_POSITION(n, volume) \
72 	((n) >> (volume->BlockLog()))
73 #define BLOCKOFFSET_FROM_POSITION(n, inode)	((n) & (inode->BlockSize() - 1))
74 
75 #define MAXINUMBER	((xfs_ino_t)((1ULL << 56) - 1ULL))
76 
77 // Inode fork identifiers
78 #define XFS_DATA_FORK	0
79 #define XFS_ATTR_FORK	1
80 
81 #define XFS_DFORK_FORMAT(ino, w) \
82 	((w) == XFS_DATA_FORK ? (ino)->di_format : (ino)->di_aformat)
83 
84 #define XFS_DFORK_NEXTENTS(ino, w) \
85 	((w) == XFS_DATA_FORK ? (ino)->di_nextents : (ino)->di_naextents)
86 
87 #define DFORK_MAXEXT(ino, volume, w) \
88 	(DFORK_SIZE(ino, volume, w) / (2 * sizeof(uint64)))
89 
90 
91 struct LongBlock;  // Forward declaration to remove cyclic dependency
92 
93 
94 // xfs_bmdr_block
95 struct BlockInDataFork {
96 			uint16				Levels()
97 									{ return
98 										B_BENDIAN_TO_HOST_INT16(bb_level); }
99 			uint16				NumRecords()
100 									{ return
101 										B_BENDIAN_TO_HOST_INT16(bb_numrecs); }
102 			uint16				bb_level;
103 			uint16				bb_numrecs;
104 };
105 
106 
107 //xfs_da_blkinfo_t
108 struct BlockInfo {
109 			uint32				forw;
110 			uint32				back;
111 			uint16				magic;
112 			uint16				pad;
113 };
114 
115 
116 // xfs_da3_blkinfo_t
117 struct BlockInfoV5 {
118 			uint32				forw;
119 			uint32				back;
120 			uint16				magic;
121 			uint16				pad;
122 
123 			// version 5
124 
125 			uint32				crc;
126 			uint64				blkno;
127 			uint64				lsn;
128 			uuid_t				uuid;
129 			uint64				owner;
130 };
131 
132 #define XFS_BLOCK_CRC_OFF offsetof(struct BlockInfo, crc)
133 
134 
135 struct ExtentMapEntry {
136 			xfs_fileoff_t		br_startoff;
137 				// logical file block offset
138 			xfs_fsblock_t		br_startblock;
139 				// absolute block number
140 			xfs_filblks_t		br_blockcount;
141 				// # of blocks
142 			uint8				br_state;
143 				// state of the extent
144 };
145 
146 
147 struct xfs_timestamp_t {
148 		int32				t_sec;
149 		int32				t_nsec;
150 };
151 
152 
153 enum xfs_dinode_fmt_t {
154 		XFS_DINODE_FMT_DEV,
155 			// For devices
156 		XFS_DINODE_FMT_LOCAL,
157 			// For Directories and links
158 		XFS_DINODE_FMT_EXTENTS,
159 			// For large number of extents
160 		XFS_DINODE_FMT_BTREE,
161 			// Extents and Directories
162 		XFS_DINODE_FMT_UUID,
163 			// Not used
164 };
165 
166 
167 #define XFS_INODE_FORMAT_STR \
168 	{ XFS_DINODE_FMT_DEV,		"dev" }, \
169 	{ XFS_DINODE_FMT_LOCAL,		"local" }, \
170 	{ XFS_DINODE_FMT_EXTENTS,	"extent" }, \
171 	{ XFS_DINODE_FMT_BTREE,		"btree" }, \
172 	{ XFS_DINODE_FMT_UUID,		"uuid" }
173 
174 
175 /*
176 	Dirents in version 3 directories have a file type field. Additions to this
177 	list are an on-disk format change, requiring feature bits. Valid values
178 	are as follows:
179 */
180 #define XFS_DIR3_FT_UNKNOWN		0
181 #define XFS_DIR3_FT_REG_FILE	1
182 #define XFS_DIR3_FT_DIR			2
183 #define XFS_DIR3_FT_CHRDEV		3
184 #define XFS_DIR3_FT_BLKDEV		4
185 #define XFS_DIR3_FT_FIFO		5
186 #define XFS_DIR3_FT_SOCK		6
187 #define XFS_DIR3_FT_SYMLINK		7
188 #define XFS_DIR3_FT_WHT			8
189 
190 #define XFS_DIR3_FT_MAX			9
191 
192 
193 /*
194  * The xfs_ino_t is the same for all types of inodes, the data and attribute
195  * fork might be different and that is to be handled accordingly.
196  */
197 struct xfs_inode_t {
198 			void				SwapEndian();
199 			int8				Version() const;
200 			mode_t				Mode() const;
201 			void				GetModificationTime(struct timespec&
202 									timestamp);
203 			void				GetChangeTime(struct timespec& timestamp);
204 			void				GetAccessTime(struct timespec& timestamp);
205 			void				GetCreationTime(struct timespec& timestamp);
206 
207 			int8				Format() const;
208 				// The format of the inode
209 			int8				AttrFormat() const;
210 			xfs_fsize_t			Size() const;
211 			xfs_rfsblock_t		BlockCount() const;
212 			uint32				NLink() const;
213 			uint16				Flags() const;
214 			uint32				UserId() const;
215 			uint32				GroupId() const;
216 			xfs_extnum_t		DataExtentsCount() const;
217 			xfs_extnum_t		AttrExtentsCount() const;
218 			uint8				ForkOffset() const;
219 			uint16				di_magic;
220 			uint16				di_mode;
221 				// uses standard S_Ixxx
222 			int8				di_version;
223 				//This either would be 1 or 2
224 			int8				di_format;
225 			uint16				di_onlink;
226 			uint32				di_uid;
227 			uint32				di_gid;
228 			uint32				di_nlink;
229 			uint16				di_projid;
230 			uint8				di_pad[8];
231 			uint16				di_flushiter;
232 			xfs_timestamp_t		di_atime;
233 			xfs_timestamp_t		di_mtime;
234 			xfs_timestamp_t		di_ctime;
235 			xfs_fsize_t			di_size;
236 				// size in bytes or length if link
237 			xfs_rfsblock_t		di_nblocks;
238 				// blocks used including metadata
239 				// extended attributes not included
240 			xfs_extlen_t		di_extsize;
241 				// extent size
242 			xfs_extnum_t		di_nextents;
243 				// number of data extents
244 			xfs_aextnum_t		di_naextents;
245 				// number of EA extents
246 			uint8				di_forkoff;
247 				// decides where di_a starts
248 			int8				di_aformat;
249 				// similar to di_format
250 			uint32				di_dmevmask;
251 			uint16				di_dmstate;
252 			uint16				di_flags;
253 			uint32				di_gen;
254 			uint32				di_next_unlinked;
255 
256 			// XFS Version 5
257 
258 			uint32				di_crc;
259 			uint64				di_changecount;
260 			uint64				di_lsn;
261 			uint64				di_flags2;
262 			uint32				di_cowextsize;
263 			uint8				di_pad2[12];
264 
265 			// fields only written to during inode creation
266 
267 			xfs_timestamp_t		di_crtime;
268 			uint64				di_ino;
269 			uuid_t				di_uuid;
270 };
271 
272 
273 // Values for di_flags
274 #define XFS_DIFLAG_REALTIME_BIT  0	// file's blocks come from rt area
275 #define XFS_DIFLAG_PREALLOC_BIT  1	// file space has been preallocated
276 #define XFS_DIFLAG_NEWRTBM_BIT   2	// for rtbitmap inode, new format
277 #define XFS_DIFLAG_IMMUTABLE_BIT 3	// inode is immutable
278 #define XFS_DIFLAG_APPEND_BIT    4	// inode is append-only
279 #define XFS_DIFLAG_SYNC_BIT      5	// inode is written synchronously
280 #define XFS_DIFLAG_NOATIME_BIT   6	// do not update atime
281 #define XFS_DIFLAG_NODUMP_BIT    7	// do not dump
282 #define XFS_DIFLAG_RTINHERIT_BIT 8	// create with realtime bit set
283 #define XFS_DIFLAG_PROJINHERIT_BIT   9	// create with parents projid
284 #define XFS_DIFLAG_NOSYMLINKS_BIT   10	// disallow symlink creation
285 #define XFS_DIFLAG_EXTSIZE_BIT      11	// inode extent size allocator hint
286 #define XFS_DIFLAG_EXTSZINHERIT_BIT 12	// inherit inode extent size
287 #define XFS_DIFLAG_NODEFRAG_BIT     13	// do not reorganize/defragment
288 #define XFS_DIFLAG_FILESTREAM_BIT   14  // use filestream allocator
289 
290 #define XFS_DIFLAG_REALTIME      (1 << XFS_DIFLAG_REALTIME_BIT)
291 #define XFS_DIFLAG_PREALLOC      (1 << XFS_DIFLAG_PREALLOC_BIT)
292 #define XFS_DIFLAG_NEWRTBM       (1 << XFS_DIFLAG_NEWRTBM_BIT)
293 #define XFS_DIFLAG_IMMUTABLE     (1 << XFS_DIFLAG_IMMUTABLE_BIT)
294 #define XFS_DIFLAG_APPEND        (1 << XFS_DIFLAG_APPEND_BIT)
295 #define XFS_DIFLAG_SYNC          (1 << XFS_DIFLAG_SYNC_BIT)
296 #define XFS_DIFLAG_NOATIME       (1 << XFS_DIFLAG_NOATIME_BIT)
297 #define XFS_DIFLAG_NODUMP        (1 << XFS_DIFLAG_NODUMP_BIT)
298 #define XFS_DIFLAG_RTINHERIT     (1 << XFS_DIFLAG_RTINHERIT_BIT)
299 #define XFS_DIFLAG_PROJINHERIT   (1 << XFS_DIFLAG_PROJINHERIT_BIT)
300 #define XFS_DIFLAG_NOSYMLINKS    (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
301 #define XFS_DIFLAG_EXTSIZE       (1 << XFS_DIFLAG_EXTSIZE_BIT)
302 #define XFS_DIFLAG_EXTSZINHERIT  (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
303 #define XFS_DIFLAG_NODEFRAG      (1 << XFS_DIFLAG_NODEFRAG_BIT)
304 #define XFS_DIFLAG_FILESTREAM    (1 << XFS_DIFLAG_FILESTREAM_BIT)
305 
306 #define XFS_DIFLAG_ANY \
307 	(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
308 	 XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
309 	 XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
310 	 XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
311 	 XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM)
312 
313 /*
314 	Values for di_flags2 These start by being exposed to userspace in the upper
315 	16 bits of the XFS_XFLAG_S range.
316 */
317 #define XFS_DIFLAG2_DAX_BIT	0	// use DAX for this inode
318 #define XFS_DIFLAG2_REFLINK_BIT	1	// file's blocks may be shared
319 #define XFS_DIFLAG2_COWEXTSIZE_BIT 2  // copy on write extent size hint
320 #define XFS_DIFLAG2_BIGTIME_BIT	3	// big timestamps
321 
322 #define XFS_DIFLAG2_DAX		(1 << XFS_DIFLAG2_DAX_BIT)
323 #define XFS_DIFLAG2_REFLINK     (1 << XFS_DIFLAG2_REFLINK_BIT)
324 #define XFS_DIFLAG2_COWEXTSIZE  (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
325 #define XFS_DIFLAG2_BIGTIME	(1 << XFS_DIFLAG2_BIGTIME_BIT)
326 
327 #define XFS_DIFLAG2_ANY \
328 	(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
329 	 XFS_DIFLAG2_BIGTIME)
330 
331 class Inode {
332 public:
333 								Inode(Volume* volume, xfs_ino_t id);
334 								~Inode();
335 
336 			status_t			Init();
337 
338 			xfs_ino_t			ID() const { return fId; }
339 
340 			bool				VerifyInode() const;
341 
342 			bool				VerifyForkoff() const;
343 
344 			bool				VerifyFork(int WhichFork) const;
345 
346 			bool				IsDirectory() const
347 									{ return S_ISDIR(Mode()); }
348 
349 			bool				IsFile() const
350 									{ return S_ISREG(Mode()); }
351 
352 			bool				IsSymLink() const
353 									{ return S_ISLNK(Mode()); }
354 
355 			mode_t				Mode() const { return fNode->Mode(); }
356 
357 			Volume*				GetVolume() { return fVolume;}
358 
359 			int8				Format() const { return fNode->Format(); }
360 
361 			int8				AttrFormat() const { return fNode->AttrFormat(); }
362 
363 			bool				IsLocal() const
364 									{ return
365 										Format() == XFS_DINODE_FMT_LOCAL; }
366 
367 			uint32				NLink() const { return fNode->NLink(); }
368 
369 			int8				Version() const { return fNode->Version(); }
370 
371 			xfs_rfsblock_t		BlockCount() const
372 									{ return fNode->BlockCount(); }
373 
374 			char*				Buffer() { return fBuffer; }
375 
376 			int16				Flags() const { return fNode->Flags(); }
377 
378 			xfs_fsize_t			Size() const { return fNode->Size(); }
379 
380 			uint32				DirBlockSize() const
381 									{ return fVolume->DirBlockSize(); }
382 
383 			uint32				BlockSize() const
384 									{ return fVolume->BlockSize(); }
385 
386 			uint32				CoreInodeSize() const;
387 
388 			void				GetChangeTime(struct timespec& timestamp) const
389 								{ fNode->GetChangeTime(timestamp); }
390 
391 			void				GetModificationTime(struct timespec& timestamp)
392 									const
393 								{ fNode->GetModificationTime(timestamp); }
394 
395 			void				GetAccessTime(struct timespec& timestamp) const
396 								{ fNode->GetAccessTime(timestamp); }
397 
398 			void				GetCreationTime(struct timespec& timestamp) const
399 								{ fNode->GetCreationTime(timestamp); }
400 
401 			unsigned char		XfsModeToFtype() const;
402 			status_t			CheckPermissions(int accessMode) const;
403 			uint32				UserId() const { return fNode->UserId(); }
404 			uint32				GroupId() const { return fNode->GroupId(); }
405 			bool				HasFileTypeField() const;
406 			xfs_extnum_t		DataExtentsCount() const
407 									{ return fNode->DataExtentsCount(); }
408 			xfs_extnum_t		AttrExtentsCount() const
409 									{ return fNode->AttrExtentsCount(); }
410 			uint64				FileSystemBlockToAddr(uint64 block);
411 			uint8				ForkOffset() const
412 									{ return fNode->ForkOffset(); }
413 			status_t			ReadExtents();
414 			status_t			ReadAt(off_t pos, uint8* buffer, size_t* length);
415 			status_t			GetNodefromTree(uint16& levelsInTree,
416 									Volume* volume, ssize_t& len,
417 									size_t DirBlockSize, char* block);
418 			int					SearchMapInAllExtent(uint64 blockNo);
419 			void				UnWrapExtentFromWrappedEntry(
420 									uint64 wrappedExtent[2],
421 									ExtentMapEntry* entry);
422 			status_t			ReadExtentsFromExtentBasedInode();
423 			status_t			ReadExtentsFromTreeInode();
424 			size_t				MaxRecordsPossibleInTreeRoot();
425 			size_t				MaxRecordsPossibleNode();
426 			TreePointer*		GetPtrFromRoot(int pos);
427 			TreePointer*		GetPtrFromNode(int pos, void* buffer);
428 			size_t				GetPtrOffsetIntoRoot(int pos);
429 			size_t				GetPtrOffsetIntoNode(int pos);
430 			uint32				SizeOfLongBlock();
431 private:
432 			status_t			GetFromDisk();
433 			xfs_inode_t*		fNode;
434 			xfs_ino_t			fId;
435 			Volume*				fVolume;
436 			char*				fBuffer;
437 				// Contains the disk inode in BE format
438 			ExtentMapEntry*		fExtents;
439 };
440 
441 
442 uint32 hashfunction(const char* name, int length);
443 
444 
445 // A common function to return given hash lowerbound
446 template<class T> void
447 hashLowerBound(T* entry, int& left, int& right, uint32 hashValueOfRequest)
448 {
449 	int mid;
450 
451 	/*
452 	* Trying to find the lowerbound of hashValueOfRequest
453 	* This is slightly different from bsearch(), as we want the first
454 	* instance of hashValueOfRequest and not any instance.
455 	*/
456 	while (left < right) {
457 		mid = (left + right) / 2;
458 		uint32 hashval = B_BENDIAN_TO_HOST_INT32(entry[mid].hashval);
459 		if (hashval >= hashValueOfRequest) {
460 			right = mid;
461 			continue;
462 		}
463 		if (hashval < hashValueOfRequest)
464 			left = mid+1;
465 	}
466 	TRACE("left:(%" B_PRId32 "), right:(%" B_PRId32 ")\n", left, right);
467 }
468 
469 #endif
470