xref: /haiku/src/add-ons/kernel/file_systems/xfs/Inode.h (revision 6a1f97581ff62985b348d1e375a91927dfbd7efb)
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 			xfs_fsize_t			Size() const;
214 			xfs_rfsblock_t		BlockCount() const;
215 			uint32				NLink() const;
216 			uint16				Flags() const;
217 			uint32				UserId() const;
218 			uint32				GroupId() const;
219 			xfs_extnum_t		DataExtentsCount() const;
220 			uint8				ForkOffset() const;
221 			uint16				di_magic;
222 			uint16				di_mode;
223 				// uses standard S_Ixxx
224 			int8				di_version;
225 				//This either would be 1 or 2
226 			int8				di_format;
227 			uint16				di_onlink;
228 			uint32				di_uid;
229 			uint32				di_gid;
230 			uint32				di_nlink;
231 			uint16				di_projid;
232 			uint8				di_pad[8];
233 			uint16				di_flushiter;
234 			xfs_timestamp_t		di_atime;
235 			xfs_timestamp_t		di_mtime;
236 			xfs_timestamp_t		di_ctime;
237 			xfs_fsize_t			di_size;
238 				// size in bytes or length if link
239 			xfs_rfsblock_t		di_nblocks;
240 				// blocks used including metadata
241 				// extended attributes not included
242 			xfs_extlen_t		di_extsize;
243 				// extent size
244 			xfs_extnum_t		di_nextents;
245 				// number of data extents
246 			xfs_aextnum_t		di_anextents;
247 				// number of EA extents
248 			uint8				di_forkoff;
249 				// decides where di_a starts
250 			int8				di_aformat;
251 				// similar to di_format
252 			uint32				di_dmevmask;
253 			uint16				di_dmstate;
254 			uint16				di_flags;
255 			uint32				di_gen;
256 			uint32				di_next_unlinked;
257 
258 			// XFS Version 5
259 
260 			uint32				di_crc;
261 			uint64				di_changecount;
262 			uint64				di_lsn;
263 			uint64				di_flags2;
264 			uint32				di_cowextsize;
265 			uint8				di_pad2[12];
266 
267 			// fields only written to during inode creation
268 
269 			xfs_timestamp_t		di_crtime;
270 			uint64				di_ino;
271 			uuid_t				di_uuid;
272 };
273 
274 
275 // Values for di_flags
276 #define XFS_DIFLAG_REALTIME_BIT  0	// file's blocks come from rt area
277 #define XFS_DIFLAG_PREALLOC_BIT  1	// file space has been preallocated
278 #define XFS_DIFLAG_NEWRTBM_BIT   2	// for rtbitmap inode, new format
279 #define XFS_DIFLAG_IMMUTABLE_BIT 3	// inode is immutable
280 #define XFS_DIFLAG_APPEND_BIT    4	// inode is append-only
281 #define XFS_DIFLAG_SYNC_BIT      5	// inode is written synchronously
282 #define XFS_DIFLAG_NOATIME_BIT   6	// do not update atime
283 #define XFS_DIFLAG_NODUMP_BIT    7	// do not dump
284 #define XFS_DIFLAG_RTINHERIT_BIT 8	// create with realtime bit set
285 #define XFS_DIFLAG_PROJINHERIT_BIT   9	// create with parents projid
286 #define XFS_DIFLAG_NOSYMLINKS_BIT   10	// disallow symlink creation
287 #define XFS_DIFLAG_EXTSIZE_BIT      11	// inode extent size allocator hint
288 #define XFS_DIFLAG_EXTSZINHERIT_BIT 12	// inherit inode extent size
289 #define XFS_DIFLAG_NODEFRAG_BIT     13	// do not reorganize/defragment
290 #define XFS_DIFLAG_FILESTREAM_BIT   14  // use filestream allocator
291 
292 #define XFS_DIFLAG_REALTIME      (1 << XFS_DIFLAG_REALTIME_BIT)
293 #define XFS_DIFLAG_PREALLOC      (1 << XFS_DIFLAG_PREALLOC_BIT)
294 #define XFS_DIFLAG_NEWRTBM       (1 << XFS_DIFLAG_NEWRTBM_BIT)
295 #define XFS_DIFLAG_IMMUTABLE     (1 << XFS_DIFLAG_IMMUTABLE_BIT)
296 #define XFS_DIFLAG_APPEND        (1 << XFS_DIFLAG_APPEND_BIT)
297 #define XFS_DIFLAG_SYNC          (1 << XFS_DIFLAG_SYNC_BIT)
298 #define XFS_DIFLAG_NOATIME       (1 << XFS_DIFLAG_NOATIME_BIT)
299 #define XFS_DIFLAG_NODUMP        (1 << XFS_DIFLAG_NODUMP_BIT)
300 #define XFS_DIFLAG_RTINHERIT     (1 << XFS_DIFLAG_RTINHERIT_BIT)
301 #define XFS_DIFLAG_PROJINHERIT   (1 << XFS_DIFLAG_PROJINHERIT_BIT)
302 #define XFS_DIFLAG_NOSYMLINKS    (1 << XFS_DIFLAG_NOSYMLINKS_BIT)
303 #define XFS_DIFLAG_EXTSIZE       (1 << XFS_DIFLAG_EXTSIZE_BIT)
304 #define XFS_DIFLAG_EXTSZINHERIT  (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
305 #define XFS_DIFLAG_NODEFRAG      (1 << XFS_DIFLAG_NODEFRAG_BIT)
306 #define XFS_DIFLAG_FILESTREAM    (1 << XFS_DIFLAG_FILESTREAM_BIT)
307 
308 #define XFS_DIFLAG_ANY \
309 	(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
310 	 XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
311 	 XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
312 	 XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
313 	 XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM)
314 
315 /*
316 	Values for di_flags2 These start by being exposed to userspace in the upper
317 	16 bits of the XFS_XFLAG_S range.
318 */
319 #define XFS_DIFLAG2_DAX_BIT	0	// use DAX for this inode
320 #define XFS_DIFLAG2_REFLINK_BIT	1	// file's blocks may be shared
321 #define XFS_DIFLAG2_COWEXTSIZE_BIT 2  // copy on write extent size hint
322 #define XFS_DIFLAG2_BIGTIME_BIT	3	// big timestamps
323 
324 #define XFS_DIFLAG2_DAX		(1 << XFS_DIFLAG2_DAX_BIT)
325 #define XFS_DIFLAG2_REFLINK     (1 << XFS_DIFLAG2_REFLINK_BIT)
326 #define XFS_DIFLAG2_COWEXTSIZE  (1 << XFS_DIFLAG2_COWEXTSIZE_BIT)
327 #define XFS_DIFLAG2_BIGTIME	(1 << XFS_DIFLAG2_BIGTIME_BIT)
328 
329 #define XFS_DIFLAG2_ANY \
330 	(XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE | \
331 	 XFS_DIFLAG2_BIGTIME)
332 
333 class Inode {
334 public:
335 								Inode(Volume* volume, xfs_ino_t id);
336 								~Inode();
337 
338 			status_t			Init();
339 
340 			xfs_ino_t			ID() const { return fId; }
341 
342 			bool				VerifyInode() const;
343 
344 			bool				VerifyForkoff() const;
345 
346 			bool				VerifyFork(int WhichFork) const;
347 
348 			bool				IsDirectory() const
349 									{ return S_ISDIR(Mode()); }
350 
351 			bool				IsFile() const
352 									{ return S_ISREG(Mode()); }
353 
354 			bool				IsSymLink() const
355 									{ return S_ISLNK(Mode()); }
356 
357 			mode_t				Mode() const { return fNode->Mode(); }
358 
359 			Volume*				GetVolume() { return fVolume;}
360 
361 			int8				Format() const { return fNode->Format(); }
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 			uint64				FileSystemBlockToAddr(uint64 block);
409 			uint8				ForkOffset() const
410 									{ return fNode->ForkOffset(); }
411 			status_t			ReadExtents();
412 			status_t			ReadAt(off_t pos, uint8* buffer, size_t* length);
413 			status_t			GetNodefromTree(uint16& levelsInTree,
414 									Volume* volume, ssize_t& len,
415 									size_t DirBlockSize, char* block);
416 			int					SearchMapInAllExtent(uint64 blockNo);
417 			void				UnWrapExtentFromWrappedEntry(
418 									uint64 wrappedExtent[2],
419 									ExtentMapEntry* entry);
420 			status_t			ReadExtentsFromExtentBasedInode();
421 			status_t			ReadExtentsFromTreeInode();
422 			size_t				MaxRecordsPossibleInTreeRoot();
423 			size_t				MaxRecordsPossibleNode();
424 			TreePointer*		GetPtrFromRoot(int pos);
425 			TreePointer*		GetPtrFromNode(int pos, void* buffer);
426 			size_t				GetPtrOffsetIntoRoot(int pos);
427 			size_t				GetPtrOffsetIntoNode(int pos);
428 			bool				VerifyBlockHeader(LongBlock* header,
429 									char* buffer);
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 #endif
442