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 _EXTENT_H_
7#define _EXTENT_H_
8
9
10#include "Directory.h"
11#include "Inode.h"
12#include "system_dependencies.h"
13
14
15#define DIR2_BLOCK_HEADER_MAGIC 0x58443242
16	// for v4 system
17#define DIR3_BLOCK_HEADER_MAGIC 0x58444233
18	// for v5 system
19#define DIR2_FREE_TAG 0xffff
20#define XFS_DIR2_DATA_FD_COUNT 3
21#define EXTENT_SIZE 16
22#define BLOCKNO_FROM_ADDRESS(n, volume) \
23	((n) >> (volume->BlockLog() + volume->DirBlockLog()))
24#define BLOCKOFFSET_FROM_ADDRESS(n, inode) ((n) & (inode->DirBlockSize() - 1))
25#define LEAF_STARTOFFSET(n) 1UL << (35 - (n))
26
27
28// Enum values to check which directory we are reading
29enum DirectoryType {
30	XFS_BLOCK,
31	XFS_LEAF,
32	XFS_NODE,
33	XFS_BTREE,
34};
35
36
37// xfs_dir2_data_free_t
38struct FreeRegion {
39			uint16				offset;
40			uint16				length;
41};
42
43
44// This class will act as interface for V4 and V5 data header
45class ExtentDataHeader
46{
47public:
48			virtual						~ExtentDataHeader()			=	0;
49			virtual	uint32				Magic()						=	0;
50			virtual	uint64				Blockno()					=	0;
51			virtual	uint64				Lsn()						=	0;
52			virtual	uint64				Owner()						=	0;
53			virtual	const uuid_t&		Uuid()						=	0;
54
55			static	uint32				ExpectedMagic(int8 WhichDirectory,
56										Inode* inode);
57			static	uint32				CRCOffset();
58			static	ExtentDataHeader*	Create(Inode* inode, const char* buffer);
59			static	uint32				Size(Inode* inode);
60};
61
62
63// xfs_dir_data_hdr_t
64class ExtentDataHeaderV4 : public ExtentDataHeader
65{
66public :
67			struct	OnDiskData {
68			public:
69					uint32				magic;
70					FreeRegion			bestfree[XFS_DIR2_DATA_FD_COUNT];
71			};
72
73								ExtentDataHeaderV4(const char* buffer);
74								~ExtentDataHeaderV4();
75			uint32				Magic();
76			uint64				Blockno();
77			uint64				Lsn();
78			uint64				Owner();
79			const uuid_t&		Uuid();
80
81private:
82			void				_SwapEndian();
83
84private:
85			OnDiskData			fData;
86};
87
88
89// xfs_dir3_data_hdr_t
90class ExtentDataHeaderV5 : public ExtentDataHeader
91{
92public:
93			struct OnDiskData {
94			public:
95				uint32				magic;
96				uint32				crc;
97				uint64				blkno;
98				uint64				lsn;
99				uuid_t				uuid;
100				uint64				owner;
101				FreeRegion			bestfree[XFS_DIR2_DATA_FD_COUNT];
102				uint32				pad;
103			};
104
105								ExtentDataHeaderV5(const char* buffer);
106								~ExtentDataHeaderV5();
107			uint32				Magic();
108			uint64				Blockno();
109			uint64				Lsn();
110			uint64				Owner();
111			const uuid_t&		Uuid();
112
113private:
114			void				_SwapEndian();
115
116private:
117			OnDiskData 			fData;
118};
119
120
121// xfs_dir2_data_entry_t
122struct ExtentDataEntry {
123			xfs_ino_t			inumber;
124			uint8				namelen;
125			uint8				name[];
126
127// Followed by a file type (8bit) if applicable and a 16bit tag
128// tag is the offset from start of the block
129};
130
131
132// xfs_dir2_data_unused_t
133struct ExtentUnusedEntry {
134			uint16				freetag;
135				// takes the value 0xffff
136			uint16				length;
137				// freetag + length overrides the inumber of an entry
138			uint16				tag;
139};
140
141
142// xfs_dir2_leaf_entry_t
143struct ExtentLeafEntry {
144			uint32				hashval;
145			uint32				address;
146				// offset into block after >> 3
147};
148
149
150// xfs_dir2_block_tail_t
151struct ExtentBlockTail {
152			uint32				count;
153				// # of entries in leaf
154			uint32				stale;
155				// # of free leaf entries
156};
157
158
159class Extent : public DirectoryIterator {
160public:
161								Extent(Inode* inode);
162								~Extent();
163			status_t			Init();
164			bool				IsBlockType();
165			void				FillMapEntry(void* pointerToMap);
166			status_t			FillBlockBuffer();
167			ExtentBlockTail*	BlockTail();
168			ExtentLeafEntry*	BlockFirstLeaf(ExtentBlockTail* tail);
169			xfs_ino_t			GetIno();
170			uint32				GetOffsetFromAddress(uint32 address);
171			int					EntrySize(int len) const;
172			status_t			GetNext(char* name, size_t* length,
173									xfs_ino_t* ino);
174			status_t			Lookup(const char* name, size_t length,
175									xfs_ino_t* id);
176private:
177			Inode*				fInode;
178			ExtentMapEntry*		fMap;
179			uint32				fOffset;
180			char*				fBlockBuffer;
181				// This isn't inode data. It holds the directory block.
182};
183
184#endif
185