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
87struct LongBlock;  // Forward declaration to remove cyclic dependency
88
89
90// xfs_bmdr_block
91struct 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
104struct BlockInfo {
105			uint32				forw;
106			uint32				back;
107			uint16				magic;
108			uint16				pad;
109};
110
111
112// xfs_da3_blkinfo_t
113struct 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
131struct 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
143struct xfs_timestamp_t {
144		int32				t_sec;
145		int32				t_nsec;
146};
147
148
149enum 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 */
185class Inode {
186public:
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();
334private:
335			void				SwapEndian();
336private:
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
347uint32 hashfunction(const char* name, int length);
348
349
350// A common function to return given hash lowerbound
351template<class T> void
352hashLowerBound(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