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
87 struct LongBlock; // Forward declaration to remove cyclic dependency
88
89
90 // xfs_bmdr_block
91 struct BlockInDataFork {
LevelsBlockInDataFork92 uint16 Levels()
93 { return
94 B_BENDIAN_TO_HOST_INT16(bb_level); }
NumRecordsBlockInDataFork95 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
104 struct BlockInfo {
105 uint32 forw;
106 uint32 back;
107 uint16 magic;
108 uint16 pad;
109 };
110
111
112 // xfs_da3_blkinfo_t
113 struct 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
131 struct 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
143 struct xfs_timestamp_t {
144 int32 t_sec;
145 int32 t_nsec;
146 };
147
148
149 enum 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 */
185 class Inode {
186 public:
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
ID()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
IsDirectory()255 bool IsDirectory() const
256 { return S_ISDIR(Mode()); }
257
IsFile()258 bool IsFile() const
259 { return S_ISREG(Mode()); }
260
IsSymLink()261 bool IsSymLink() const
262 { return S_ISLNK(Mode()); }
263
Mode()264 mode_t Mode() const { return fNode->di_mode; }
265
GetVolume()266 Volume* GetVolume() { return fVolume;}
267
Format()268 int8 Format() const { return fNode->di_format; }
269
AttrFormat()270 int8 AttrFormat() const { return fNode->di_aformat; }
271
IsLocal()272 bool IsLocal() const
273 { return Format() == XFS_DINODE_FMT_LOCAL; }
274
NLink()275 uint32 NLink() const { return fNode->di_nlink; }
276
Version()277 int8 Version() const { return fNode->di_version; }
278
BlockCount()279 xfs_rfsblock_t BlockCount() const
280 { return fNode->di_nblocks; }
281
Buffer()282 char* Buffer() { return fBuffer; }
283
Flags()284 int16 Flags() const { return fNode->di_flags; }
285
Size()286 xfs_fsize_t Size() const { return fNode->di_size; }
287
DirBlockSize()288 uint32 DirBlockSize() const
289 { return fVolume->DirBlockSize(); }
290
BlockSize()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;
UserId()306 uint32 UserId() const { return fNode->di_uid; }
GroupId()307 uint32 GroupId() const { return fNode->di_gid; }
308 bool HasFileTypeField() const;
DataExtentsCount()309 xfs_extnum_t DataExtentsCount() const
310 { return fNode->di_nextents; }
AttrExtentsCount()311 xfs_extnum_t AttrExtentsCount() const
312 { return fNode->di_naextents; }
313 uint64 FileSystemBlockToAddr(uint64 block);
ForkOffset()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();
334 private:
335 void SwapEndian();
336 private:
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
347 uint32 hashfunction(const char* name, int length);
348
349
350 // A common function to return given hash lowerbound
351 template<class T> void
hashLowerBound(T * entry,int & left,int & right,uint32 hashValueOfRequest)352 hashLowerBound(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