xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.h (revision 388d91a7b829b91b95abd2505437d431c468ce7d)
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_anextents)
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 uint32
148 hashfunction(const char* name, int length);
149 
150 
151 struct xfs_timestamp_t {
152 		int32				t_sec;
153 		int32				t_nsec;
154 };
155 
156 
157 enum xfs_dinode_fmt_t {
158 		XFS_DINODE_FMT_DEV,
159 			// For devices
160 		XFS_DINODE_FMT_LOCAL,
161 			// For Directories and links
162 		XFS_DINODE_FMT_EXTENTS,
163 			// For large number of extents
164 		XFS_DINODE_FMT_BTREE,
165 			// Extents and Directories
166 		XFS_DINODE_FMT_UUID,
167 			// Not used
168 };
169 
170 
171 #define XFS_INODE_FORMAT_STR \
172 	{ XFS_DINODE_FMT_DEV,		"dev" }, \
173 	{ XFS_DINODE_FMT_LOCAL,		"local" }, \
174 	{ XFS_DINODE_FMT_EXTENTS,	"extent" }, \
175 	{ XFS_DINODE_FMT_BTREE,		"btree" }, \
176 	{ XFS_DINODE_FMT_UUID,		"uuid" }
177 
178 
179 /*
180 	Dirents in version 3 directories have a file type field. Additions to this
181 	list are an on-disk format change, requiring feature bits. Valid values
182 	are as follows:
183 */
184 #define XFS_DIR3_FT_UNKNOWN		0
185 #define XFS_DIR3_FT_REG_FILE	1
186 #define XFS_DIR3_FT_DIR			2
187 #define XFS_DIR3_FT_CHRDEV		3
188 #define XFS_DIR3_FT_BLKDEV		4
189 #define XFS_DIR3_FT_FIFO		5
190 #define XFS_DIR3_FT_SOCK		6
191 #define XFS_DIR3_FT_SYMLINK		7
192 #define XFS_DIR3_FT_WHT			8
193 
194 #define XFS_DIR3_FT_MAX			9
195 
196 
197 /*
198  * The xfs_ino_t is the same for all types of inodes, the data and attribute
199  * fork might be different and that is to be handled accordingly.
200  */
201 struct xfs_inode_t {
202 			void				SwapEndian();
203 			int8				Version() const;
204 			mode_t				Mode() const;
205 			void				GetModificationTime(struct timespec&
206 									timestamp);
207 			void				GetChangeTime(struct timespec& timestamp);
208 			void				GetAccessTime(struct timespec& timestamp);
209 			void				GetCreationTime(struct timespec& timestamp);
210 
211 			int8				Format() const;
212 				// The format of the inode
213 			int8				AttrFormat() const;
214 			xfs_fsize_t			Size() const;
215 			xfs_rfsblock_t		BlockCount() const;
216 			uint32				NLink() const;
217 			uint16				Flags() const;
218 			uint32				UserId() const;
219 			uint32				GroupId() const;
220 			xfs_extnum_t		DataExtentsCount() const;
221 			uint8				ForkOffset() const;
222 			uint16				di_magic;
223 			uint16				di_mode;
224 				// uses standard S_Ixxx
225 			int8				di_version;
226 				//This either would be 1 or 2
227 			int8				di_format;
228 			uint16				di_onlink;
229 			uint32				di_uid;
230 			uint32				di_gid;
231 			uint32				di_nlink;
232 			uint16				di_projid;
233 			uint8				di_pad[8];
234 			uint16				di_flushiter;
235 			xfs_timestamp_t		di_atime;
236 			xfs_timestamp_t		di_mtime;
237 			xfs_timestamp_t		di_ctime;
238 			xfs_fsize_t			di_size;
239 				// size in bytes or length if link
240 			xfs_rfsblock_t		di_nblocks;
241 				// blocks used including metadata
242 				// extended attributes not included
243 			xfs_extlen_t		di_extsize;
244 				// extent size
245 			xfs_extnum_t		di_nextents;
246 				// number of data extents
247 			xfs_aextnum_t		di_anextents;
248 				// number of EA extents
249 			uint8				di_forkoff;
250 				// decides where di_a starts
251 			int8				di_aformat;
252 				// similar to di_format
253 			uint32				di_dmevmask;
254 			uint16				di_dmstate;
255 			uint16				di_flags;
256 			uint32				di_gen;
257 			uint32				di_next_unlinked;
258 
259 			// XFS Version 5
260 
261 			uint32				di_crc;
262 			uint64				di_changecount;
263 			uint64				di_lsn;
264 			uint64				di_flags2;
265 			uint32				di_cowextsize;
266 			uint8				di_pad2[12];
267 
268 			// fields only written to during inode creation
269 
270 			xfs_timestamp_t		di_crtime;
271 			uint64				di_ino;
272 			uuid_t				di_uuid;
273 };
274 
275 
276 // Values for di_flags
277 #define XFS_DIFLAG_REALTIME_BIT  0	// file's blocks come from rt area
278 #define XFS_DIFLAG_PREALLOC_BIT  1	// file space has been preallocated
279 #define XFS_DIFLAG_NEWRTBM_BIT   2	// for rtbitmap inode, new format
280 #define XFS_DIFLAG_IMMUTABLE_BIT 3	// inode is immutable
281 #define XFS_DIFLAG_APPEND_BIT    4	// inode is append-only
282 #define XFS_DIFLAG_SYNC_BIT      5	// inode is written synchronously
283 #define XFS_DIFLAG_NOATIME_BIT   6	// do not update atime
284 #define XFS_DIFLAG_NODUMP_BIT    7	// do not dump
285 #define XFS_DIFLAG_RTINHERIT_BIT 8	// create with realtime bit set
286 #define XFS_DIFLAG_PROJINHERIT_BIT   9	// create with parents projid
287 #define XFS_DIFLAG_NOSYMLINKS_BIT   10	// disallow symlink creation
288 #define XFS_DIFLAG_EXTSIZE_BIT      11	// inode extent size allocator hint
289 #define XFS_DIFLAG_EXTSZINHERIT_BIT 12	// inherit inode extent size
290 #define XFS_DIFLAG_NODEFRAG_BIT     13	// do not reorganize/defragment
291 #define XFS_DIFLAG_FILESTREAM_BIT   14  // use filestream allocator
292 
293 #define XFS_DIFLAG_REALTIME      (1 << XFS_DIFLAG_REALTIME_BIT)
294 #define XFS_DIFLAG_PREALLOC      (1 << XFS_DIFLAG_PREALLOC_BIT)
295 #define XFS_DIFLAG_NEWRTBM       (1 << XFS_DIFLAG_NEWRTBM_BIT)
296 #define XFS_DIFLAG_IMMUTABLE     (1 << XFS_DIFLAG_IMMUTABLE_BIT)
297 #define XFS_DIFLAG_APPEND        (1 << XFS_DIFLAG_APPEND_BIT)
298 #define XFS_DIFLAG_SYNC          (1 << XFS_DIFLAG_SYNC_BIT)
299 #define XFS_DIFLAG_NOATIME       (1 << XFS_DIFLAG_NOATIME_BIT)
300 #define XFS_DIFLAG_NODUMP        (1 << XFS_DIFLAG_NODUMP_BIT)
301 #define XFS_DIFLAG_RTINHERIT     (1 << XFS_DIFLAG_RTINHERIT_BIT)
302 #define XFS_DIFLAG_PROJINHERIT   (1 << XFS_DIFLAG_PROJINHERIT_BIT)
303 #define XFS_DIFLAG_NOSYMLINKS    (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
304 #define XFS_DIFLAG_EXTSIZE       (1 << XFS_DIFLAG_EXTSIZE_BIT)
305 #define XFS_DIFLAG_EXTSZINHERIT  (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
306 #define XFS_DIFLAG_NODEFRAG      (1 << XFS_DIFLAG_NODEFRAG_BIT)
307 #define XFS_DIFLAG_FILESTREAM    (1 << XFS_DIFLAG_FILESTREAM_BIT)
308 
309 #define XFS_DIFLAG_ANY \
310 	(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
311 	 XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
312 	 XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
313 	 XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
314 	 XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM)
315 
316 /*
317 	Values for di_flags2 These start by being exposed to userspace in the upper
318 	16 bits of the XFS_XFLAG_S range.
319 */
320 #define XFS_DIFLAG2_DAX_BIT	0	// use DAX for this inode
321 #define XFS_DIFLAG2_REFLINK_BIT	1	// file's blocks may be shared
322 #define XFS_DIFLAG2_COWEXTSIZE_BIT 2  // copy on write extent size hint
323 #define XFS_DIFLAG2_BIGTIME_BIT	3	// big timestamps
324 
325 #define XFS_DIFLAG2_DAX		(1 << XFS_DIFLAG2_DAX_BIT)
326 #define XFS_DIFLAG2_REFLINK     (1 << XFS_DIFLAG2_REFLINK_BIT)
327 #define XFS_DIFLAG2_COWEXTSIZE  (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
328 #define XFS_DIFLAG2_BIGTIME	(1 << XFS_DIFLAG2_BIGTIME_BIT)
329 
330 #define XFS_DIFLAG2_ANY \
331 	(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
332 	 XFS_DIFLAG2_BIGTIME)
333 
334 class Inode {
335 public:
336 								Inode(Volume* volume, xfs_ino_t id);
337 								~Inode();
338 
339 			status_t			Init();
340 
341 			xfs_ino_t			ID() const { return fId; }
342 
343 			bool				VerifyInode() const;
344 
345 			bool				VerifyForkoff() const;
346 
347 			bool				VerifyFork(int WhichFork) const;
348 
349 			bool				IsDirectory() const
350 									{ return S_ISDIR(Mode()); }
351 
352 			bool				IsFile() const
353 									{ return S_ISREG(Mode()); }
354 
355 			bool				IsSymLink() const
356 									{ return S_ISLNK(Mode()); }
357 
358 			mode_t				Mode() const { return fNode->Mode(); }
359 
360 			Volume*				GetVolume() { return fVolume;}
361 
362 			int8				Format() const { return fNode->Format(); }
363 
364 			int8				AttrFormat() const { return fNode->AttrFormat(); }
365 
366 			bool				IsLocal() const
367 									{ return
368 										Format() == XFS_DINODE_FMT_LOCAL; }
369 
370 			uint32				NLink() const { return fNode->NLink(); }
371 
372 			int8				Version() const { return fNode->Version(); }
373 
374 			xfs_rfsblock_t		BlockCount() const
375 									{ return fNode->BlockCount(); }
376 
377 			char*				Buffer() { return fBuffer; }
378 
379 			int16				Flags() const { return fNode->Flags(); }
380 
381 			xfs_fsize_t			Size() const { return fNode->Size(); }
382 
383 			uint32				DirBlockSize() const
384 									{ return fVolume->DirBlockSize(); }
385 
386 			uint32				BlockSize() const
387 									{ return fVolume->BlockSize(); }
388 
389 			uint32				CoreInodeSize() const;
390 
391 			void				GetChangeTime(struct timespec& timestamp) const
392 								{ fNode->GetChangeTime(timestamp); }
393 
394 			void				GetModificationTime(struct timespec& timestamp)
395 									const
396 								{ fNode->GetModificationTime(timestamp); }
397 
398 			void				GetAccessTime(struct timespec& timestamp) const
399 								{ fNode->GetAccessTime(timestamp); }
400 
401 			void				GetCreationTime(struct timespec& timestamp) const
402 								{ fNode->GetCreationTime(timestamp); }
403 
404 			unsigned char		XfsModeToFtype() const;
405 			status_t			CheckPermissions(int accessMode) const;
406 			uint32				UserId() const { return fNode->UserId(); }
407 			uint32				GroupId() const { return fNode->GroupId(); }
408 			bool				HasFileTypeField() const;
409 			xfs_extnum_t		DataExtentsCount() const
410 									{ return fNode->DataExtentsCount(); }
411 			uint64				FileSystemBlockToAddr(uint64 block);
412 			uint8				ForkOffset() const
413 									{ return fNode->ForkOffset(); }
414 			status_t			ReadExtents();
415 			status_t			ReadAt(off_t pos, uint8* buffer, size_t* length);
416 			status_t			GetNodefromTree(uint16& levelsInTree,
417 									Volume* volume, ssize_t& len,
418 									size_t DirBlockSize, char* block);
419 			int					SearchMapInAllExtent(uint64 blockNo);
420 			void				UnWrapExtentFromWrappedEntry(
421 									uint64 wrappedExtent[2],
422 									ExtentMapEntry* entry);
423 			status_t			ReadExtentsFromExtentBasedInode();
424 			status_t			ReadExtentsFromTreeInode();
425 			size_t				MaxRecordsPossibleInTreeRoot();
426 			size_t				MaxRecordsPossibleNode();
427 			TreePointer*		GetPtrFromRoot(int pos);
428 			TreePointer*		GetPtrFromNode(int pos, void* buffer);
429 			size_t				GetPtrOffsetIntoRoot(int pos);
430 			size_t				GetPtrOffsetIntoNode(int pos);
431 			uint32				SizeOfLongBlock();
432 private:
433 			status_t			GetFromDisk();
434 			xfs_inode_t*		fNode;
435 			xfs_ino_t			fId;
436 			Volume*				fVolume;
437 			char*				fBuffer;
438 				// Contains the disk inode in BE format
439 			ExtentMapEntry*		fExtents;
440 };
441 
442 #endif
443