VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fs/xfsvfs.cpp@ 76881

Last change on this file since 76881 was 76642, checked in by vboxsync, 6 years ago

Runtime/fs/xfsvfs: Updates, working on inode parsing [scm]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.2 KB
Line 
1/* $Id: xfsvfs.cpp 76642 2019-01-04 21:20:09Z vboxsync $ */
2/** @file
3 * IPRT - XFS Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2018-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_FS
32#include <iprt/fsvfs.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/file.h>
38#include <iprt/err.h>
39#include <iprt/list.h>
40#include <iprt/log.h>
41#include <iprt/mem.h>
42#include <iprt/string.h>
43#include <iprt/vfs.h>
44#include <iprt/vfslowlevel.h>
45#include <iprt/formats/xfs.h>
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/** The maximum allocation group cache size (in bytes). */
52#if ARCH_BITS >= 64
53# define RTFSXFS_MAX_AG_CACHE_SIZE _512K
54#else
55# define RTFSXFS_MAX_AG_CACHE_SIZE _128K
56#endif
57/** The maximum inode cache size (in bytes). */
58#if ARCH_BITS >= 64
59# define RTFSXFS_MAX_INODE_CACHE_SIZE _512K
60#else
61# define RTFSXFS_MAX_INODE_CACHE_SIZE _128K
62#endif
63/** The maximum extent tree cache size (in bytes). */
64#if ARCH_BITS >= 64
65# define RTFSXFS_MAX_BLOCK_CACHE_SIZE _512K
66#else
67# define RTFSXFS_MAX_BLOCK_CACHE_SIZE _128K
68#endif
69
70
71/*********************************************************************************************************************************
72* Structures and Typedefs *
73*********************************************************************************************************************************/
74/** Pointer to the XFS filesystem data. */
75typedef struct RTFSXFSVOL *PRTFSXFSVOL;
76
77
78/**
79 * Cached allocation group descriptor data.
80 */
81typedef struct RTFSXFSAG
82{
83 /** AVL tree node, indexed by the allocation group number. */
84 AVLU32NODECORE Core;
85 /** List node for the LRU list used for eviction. */
86 RTLISTNODE NdLru;
87 /** Reference counter. */
88 volatile uint32_t cRefs;
89 /** @todo */
90} RTFSXFSAG;
91/** Pointer to allocation group descriptor data. */
92typedef RTFSXFSAG *PRTFSXFSAG;
93
94
95/**
96 * In-memory inode.
97 */
98typedef struct RTFSXFSINODE
99{
100 /** AVL tree node, indexed by the inode number. */
101 AVLU64NODECORE Core;
102 /** List node for the inode LRU list used for eviction. */
103 RTLISTNODE NdLru;
104 /** Reference counter. */
105 volatile uint32_t cRefs;
106 /** Byte offset in the backing file where the inode is stored.. */
107 uint64_t offInode;
108 /** Inode data. */
109 RTFSOBJINFO ObjInfo;
110 /** Inode data fork format. */
111 uint8_t enmFormat;
112 /** Inode flags. */
113 uint16_t fFlags;
114} RTFSXFSINODE;
115/** Pointer to an in-memory inode. */
116typedef RTFSXFSINODE *PRTFSXFSINODE;
117
118
119/**
120 * Block cache entry.
121 */
122typedef struct RTFSXFSBLOCKENTRY
123{
124 /** AVL tree node, indexed by the filesystem block number. */
125 AVLU64NODECORE Core;
126 /** List node for the inode LRU list used for eviction. */
127 RTLISTNODE NdLru;
128 /** Reference counter. */
129 volatile uint32_t cRefs;
130 /** The block data. */
131 uint8_t abData[1];
132} RTFSXFSBLOCKENTRY;
133/** Pointer to a block cache entry. */
134typedef RTFSXFSBLOCKENTRY *PRTFSXFSBLOCKENTRY;
135
136
137/**
138 * Open directory instance.
139 */
140typedef struct RTFSXFSDIR
141{
142 /** Volume this directory belongs to. */
143 PRTFSXFSVOL pVol;
144 /** The underlying inode structure. */
145 PRTFSXFSINODE pInode;
146 /** Set if we've reached the end of the directory enumeration. */
147 bool fNoMoreFiles;
148 /** Current offset into the directory where the next entry should be read. */
149 uint64_t offEntry;
150 /** Next entry index (for logging purposes). */
151 uint32_t idxEntry;
152} RTFSXFSDIR;
153/** Pointer to an open directory instance. */
154typedef RTFSXFSDIR *PRTFSXFSDIR;
155
156
157/**
158 * Open file instance.
159 */
160typedef struct RTFSXFSFILE
161{
162 /** Volume this directory belongs to. */
163 PRTFSXFSVOL pVol;
164 /** The underlying inode structure. */
165 PRTFSXFSINODE pInode;
166 /** Current offset into the file for I/O. */
167 RTFOFF offFile;
168} RTFSXFSFILE;
169/** Pointer to an open file instance. */
170typedef RTFSXFSFILE *PRTFSXFSFILE;
171
172
173/**
174 * XFS filesystem volume.
175 */
176typedef struct RTFSXFSVOL
177{
178 /** Handle to itself. */
179 RTVFS hVfsSelf;
180 /** The file, partition, or whatever backing the ext volume. */
181 RTVFSFILE hVfsBacking;
182 /** The size of the backing thingy. */
183 uint64_t cbBacking;
184
185 /** RTVFSMNT_F_XXX. */
186 uint32_t fMntFlags;
187 /** RTFSXFSVFS_F_XXX (currently none defined). */
188 uint32_t fXfsFlags;
189
190 /** Size of one sector. */
191 size_t cbSector;
192 /** Size of one block. */
193 size_t cbBlock;
194 /** Number of bits to shift for converting a block number to byte offset. */
195 uint32_t cBlockShift;
196 /** Number of blocks per allocation group. */
197 XFSAGNUMBER cBlocksPerAg;
198 /** Number of blocks per allocation group as log2. */
199 uint32_t cAgBlocksLog;
200 /** Number of allocation groups for this volume. */
201 uint32_t cAgs;
202 /** inode of the root directory. */
203 XFSINO uInodeRoot;
204 /** Inode size in bytes. */
205 size_t cbInode;
206 /** Number of inodes per block. */
207 uint32_t cInodesPerBlock;
208 /** Number of inodes per block as log2. */
209 uint32_t cInodesPerBlockLog;
210
211 /** @name Allocation group cache.
212 * @{ */
213 /** LRU list anchor. */
214 RTLISTANCHOR LstAgLru;
215 /** Root of the cached allocation group tree. */
216 AVLU32TREE AgRoot;
217 /** Size of the cached allocation groups. */
218 size_t cbAgs;
219 /** @} */
220
221 /** @name Inode cache.
222 * @{ */
223 /** LRU list anchor for the inode cache. */
224 RTLISTANCHOR LstInodeLru;
225 /** Root of the cached inode tree. */
226 AVLU64TREE InodeRoot;
227 /** Size of the cached inodes. */
228 size_t cbInodes;
229 /** @} */
230
231 /** @name Block cache.
232 * @{ */
233 /** LRU list anchor for the block cache. */
234 RTLISTANCHOR LstBlockLru;
235 /** Root of the cached block tree. */
236 AVLU64TREE BlockRoot;
237 /** Size of cached blocks. */
238 size_t cbBlocks;
239 /** @} */
240} RTFSXFSVOL;
241
242
243
244/*********************************************************************************************************************************
245* Internal Functions *
246*********************************************************************************************************************************/
247static int rtFsXfsVol_OpenDirByInode(PRTFSXFSVOL pThis, uint32_t iInode, PRTVFSDIR phVfsDir);
248
249#ifdef LOG_ENABLED
250/**
251 * Logs the XFS filesystem superblock.
252 *
253 * @returns nothing.
254 * @param iAg The allocation group number for the given super block.
255 * @param pSb Pointer to the superblock.
256 */
257static void rtFsXfsSb_Log(uint32_t iAg, PCXFSSUPERBLOCK pSb)
258{
259 if (LogIs2Enabled())
260 {
261 Log2(("XFS: Superblock %#RX32:\n", iAg));
262 Log2(("XFS: u32Magic %#RX32\n", RT_BE2H_U32(pSb->u32Magic)));
263 Log2(("XFS: cbBlock %RU32\n", RT_BE2H_U32(pSb->cbBlock)));
264 Log2(("XFS: cBlocks %RU64\n", RT_BE2H_U64(pSb->cBlocks)));
265 Log2(("XFS: cBlocksRtDev %RU64\n", RT_BE2H_U64(pSb->cBlocksRtDev)));
266 Log2(("XFS: cExtentsRtDev %RU64\n", RT_BE2H_U64(pSb->cExtentsRtDev)));
267 Log2(("XFS: abUuid <todo>\n"));
268 Log2(("XFS: uBlockJournal %#RX64\n", RT_BE2H_U64(pSb->uBlockJournal)));
269 Log2(("XFS: uInodeRoot %#RX64\n", RT_BE2H_U64(pSb->uInodeRoot)));
270 Log2(("XFS: uInodeBitmapRtExt %#RX64\n", RT_BE2H_U64(pSb->uInodeBitmapRtExt)));
271 Log2(("XFS: uInodeBitmapSummary %#RX64\n", RT_BE2H_U64(pSb->uInodeBitmapSummary)));
272 Log2(("XFS: cRtExtent %RU32\n", RT_BE2H_U32(pSb->cRtExtent)));
273 Log2(("XFS: cAgBlocks %RU32\n", RT_BE2H_U32(pSb->cAgBlocks)));
274 Log2(("XFS: cAg %RU32\n", RT_BE2H_U32(pSb->cAg)));
275 Log2(("XFS: cRtBitmapBlocks %RU32\n", RT_BE2H_U32(pSb->cRtBitmapBlocks)));
276 Log2(("XFS: cJournalBlocks %RU32\n", RT_BE2H_U32(pSb->cJournalBlocks)));
277 Log2(("XFS: fVersion %#RX16%s%s%s%s%s%s%s%s%s%s%s\n", RT_BE2H_U16(pSb->fVersion),
278 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_ATTR ? " attr" : "",
279 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_NLINK ? " nlink" : "",
280 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_QUOTA ? " quota" : "",
281 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_ALIGN ? " align" : "",
282 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_DALIGN ? " dalign" : "",
283 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_SHARED ? " shared" : "",
284 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_LOGV2 ? " logv2" : "",
285 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_SECTOR ? " sector" : "",
286 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_EXTFLG ? " extflg" : "",
287 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_DIRV2 ? " dirv2" : "",
288 RT_BE2H_U16(pSb->fVersion) & XFS_SB_VERSION_F_FEAT2 ? " feat2" : ""));
289 Log2(("XFS: cbSector %RU16\n", RT_BE2H_U16(pSb->cbSector)));
290 Log2(("XFS: cbInode %RU16\n", RT_BE2H_U16(pSb->cbInode)));
291 Log2(("XFS: cIndoesPerBlock %RU16\n", RT_BE2H_U16(pSb->cInodesPerBlock)));
292 Log2(("XFS: achFsName %12s\n", &pSb->achFsName[0]));
293 Log2(("XFS: cBlockSzLog %RU8\n", pSb->cBlockSzLog));
294 Log2(("XFS: cSectorSzLog %RU8\n", pSb->cSectorSzLog));
295 Log2(("XFS: cInodeSzLog %RU8\n", pSb->cInodeSzLog));
296 Log2(("XFS: cInodesPerBlockLog %RU8\n", pSb->cInodesPerBlockLog));
297 Log2(("XFS: cAgBlocksLog %RU8\n", pSb->cAgBlocksLog));
298 Log2(("XFS: cExtentsRtDevLog %RU8\n", pSb->cExtentsRtDevLog));
299 Log2(("XFS: fInProgress %RU8\n", pSb->fInProgress));
300 Log2(("XFS: cInodeMaxPct %RU8\n", pSb->cInodeMaxPct));
301 Log2(("XFS: cInodesGlobal %#RX64\n", RT_BE2H_U64(pSb->cInodesGlobal)));
302 Log2(("XFS: cInodesGlobalFree %#RX64\n", RT_BE2H_U64(pSb->cInodesGlobalFree)));
303 Log2(("XFS: cBlocksFree %#RX64\n", RT_BE2H_U64(pSb->cBlocksFree)));
304 Log2(("XFS: cExtentsRtFree %#RX64\n", RT_BE2H_U64(pSb->cExtentsRtFree)));
305 Log2(("XFS: uInodeQuotaUsr %#RX64\n", RT_BE2H_U64(pSb->uInodeQuotaUsr)));
306 Log2(("XFS: uInodeQuotaGrp %#RX64\n", RT_BE2H_U64(pSb->uInodeQuotaGrp)));
307 Log2(("XFS: fQuotaFlags %#RX16\n", RT_BE2H_U16(pSb->fQuotaFlags)));
308 Log2(("XFS: fFlagsMisc %#RX8\n", pSb->fFlagsMisc));
309 Log2(("XFS: uSharedVn %#RX8\n", pSb->uSharedVn));
310 Log2(("XFS: cBlocksInodeAlignment %#RX32\n", RT_BE2H_U32(pSb->cBlocksInodeAlignment)));
311 Log2(("XFS: cBlocksRaidStripe %#RX32\n", RT_BE2H_U32(pSb->cBlocksRaidStripe)));
312 Log2(("XFS: cBlocksRaidWidth %#RX32\n", RT_BE2H_U32(pSb->cBlocksRaidWidth)));
313 Log2(("XFS: cDirBlockAllocLog %RU8\n", pSb->cDirBlockAllocLog));
314 Log2(("XFS: cLogDevSubVolSectorSzLog %RU8\n", pSb->cLogDevSubVolSectorSzLog));
315 Log2(("XFS: cLogDevSectorSzLog %RU16\n", RT_BE2H_U16(pSb->cLogDevSectorSzLog)));
316 Log2(("XFS: cLogDevRaidStripe %RU32\n", RT_BE2H_U32(pSb->cLogDevRaidStripe)));
317 Log2(("XFS: fFeatures2 %#RX32\n", RT_BE2H_U32(pSb->fFeatures2)));
318 Log2(("XFS: fFeaturesRw %#RX32\n", RT_BE2H_U32(pSb->fFeaturesRw)));
319 Log2(("XFS: fFeaturesRo %#RX32\n", RT_BE2H_U32(pSb->fFeaturesRo)));
320 Log2(("XFS: fFeaturesIncompatRw %#RX32\n", RT_BE2H_U32(pSb->fFeaturesIncompatRw)));
321 Log2(("XFS: fFeaturesJrnlIncompatRw %#RX32\n", RT_BE2H_U32(pSb->fFeaturesJrnlIncompatRw)));
322 Log2(("XFS: u32Chksum %#RX32\n", RT_BE2H_U32(pSb->u32Chksum)));
323 Log2(("XFS: u32SparseInodeAlignment %#RX32\n", RT_BE2H_U32(pSb->u32SparseInodeAlignment)));
324 Log2(("XFS: uInodeProjectQuota %#RX64\n", RT_BE2H_U64(pSb->uInodeProjectQuota)));
325 Log2(("XFS: uJrnlSeqSbUpdate %#RX64\n", RT_BE2H_U64(pSb->uJrnlSeqSbUpdate)));
326 Log2(("XFS: abUuidMeta <todo>\n"));
327 Log2(("XFS: uInodeRm %#RX64\n", RT_BE2H_U64(pSb->uInodeRm)));
328 }
329}
330
331
332/**
333 * Logs a AG free space block.
334 *
335 * @returns nothing.
336 * @param iAg The allocation group number for the given free space block.
337 * @param pAgf The AG free space block.
338 */
339static void rtFsXfsAgf_Log(uint32_t iAg, PCXFSAGF pAgf)
340{
341 if (LogIs2Enabled())
342 {
343 Log2(("XFS: AGF %#RX32:\n", iAg));
344 Log2(("XFS: u32Magic %#RX32\n", RT_BE2H_U32(pAgf->u32Magic)));
345 Log2(("XFS: uVersion %#RX32\n", RT_BE2H_U32(pAgf->uVersion)));
346 Log2(("XFS: uSeqNo %#RX32\n", RT_BE2H_U32(pAgf->uSeqNo)));
347 Log2(("XFS: cLengthBlocks %#RX32\n", RT_BE2H_U32(pAgf->cLengthBlocks)));
348 Log2(("XFS: auRoots[0] %#RX32\n", RT_BE2H_U32(pAgf->auRoots[0])));
349 Log2(("XFS: auRoots[1] %#RX32\n", RT_BE2H_U32(pAgf->auRoots[1])));
350 Log2(("XFS: auRoots[2] %#RX32\n", RT_BE2H_U32(pAgf->auRoots[2])));
351 Log2(("XFS: acLvls[0] %RU32\n", RT_BE2H_U32(pAgf->acLvls[0])));
352 Log2(("XFS: acLvls[1] %RU32\n", RT_BE2H_U32(pAgf->acLvls[1])));
353 Log2(("XFS: acLvls[2] %RU32\n", RT_BE2H_U32(pAgf->acLvls[2])));
354 Log2(("XFS: idxFreeListFirst %RU32\n", RT_BE2H_U32(pAgf->idxFreeListFirst)));
355 Log2(("XFS: idxFreeListLast %RU32\n", RT_BE2H_U32(pAgf->idxFreeListLast)));
356 Log2(("XFS: cFreeListBlocks %RU32\n", RT_BE2H_U32(pAgf->cFreeListBlocks)));
357 Log2(("XFS: cFreeBlocks %RU32\n", RT_BE2H_U32(pAgf->cFreeBlocks)));
358 Log2(("XFS: cFreeBlocksLongest %RU32\n", RT_BE2H_U32(pAgf->cFreeBlocksLongest)));
359 Log2(("XFS: cBlocksBTrees %RU32\n", RT_BE2H_U32(pAgf->cBlocksBTrees)));
360 Log2(("XFS: abUuid <todo>\n"));
361 Log2(("XFS: cBlocksRevMap %RU32\n", RT_BE2H_U32(pAgf->cBlocksRevMap)));
362 Log2(("XFS: cBlocksRefcountBTree %RU32\n", RT_BE2H_U32(pAgf->cBlocksRefcountBTree)));
363 Log2(("XFS: uRootRefcount %#RX32\n", RT_BE2H_U32(pAgf->uRootRefcount)));
364 Log2(("XFS: cLvlRefcount %RU32\n", RT_BE2H_U32(pAgf->cLvlRefcount)));
365 Log2(("XFS: uSeqNoLastWrite %#RX64\n", RT_BE2H_U64(pAgf->uSeqNoLastWrite)));
366 Log2(("XFS: uChkSum %#RX32\n", RT_BE2H_U32(pAgf->uChkSum)));
367 }
368}
369
370
371/**
372 * Loads an AG inode information block.
373 *
374 * @returns nothing.
375 * @param iAg The allocation group number for the given inode information block.
376 * @param pAgi The AG inode information block.
377 */
378static void rtFsXfsAgi_Log(uint32_t iAg, PCXFSAGI pAgi)
379{
380 if (LogIs2Enabled())
381 {
382 Log2(("XFS: AGI %#RX32:\n", iAg));
383 Log2(("XFS: u32Magic %#RX32\n", RT_BE2H_U32(pAgi->u32Magic)));
384 Log2(("XFS: uVersion %#RX32\n", RT_BE2H_U32(pAgi->uVersion)));
385 Log2(("XFS: uSeqNo %#RX32\n", RT_BE2H_U32(pAgi->uSeqNo)));
386 Log2(("XFS: cLengthBlocks %#RX32\n", RT_BE2H_U32(pAgi->cLengthBlocks)));
387 Log2(("XFS: cInodesAlloc %#RX32\n", RT_BE2H_U32(pAgi->cInodesAlloc)));
388 Log2(("XFS: uRootInode %#RX32\n", RT_BE2H_U32(pAgi->uRootInode)));
389 Log2(("XFS: cLvlsInode %RU32\n", RT_BE2H_U32(pAgi->cLvlsInode)));
390 Log2(("XFS: uInodeNew %#RX32\n", RT_BE2H_U32(pAgi->uInodeNew)));
391 Log2(("XFS: uInodeDir %#RX32\n", RT_BE2H_U32(pAgi->uInodeDir)));
392 Log2(("XFS: au32HashUnlinked[0..63] <todo>\n"));
393 Log2(("XFS: abUuid <todo>\n"));
394 Log2(("XFS: uChkSum %#RX32\n", RT_BE2H_U32(pAgi->uChkSum)));
395 Log2(("XFS: uSeqNoLastWrite %#RX64\n", RT_BE2H_U64(pAgi->uSeqNoLastWrite)));
396 Log2(("XFS: uRootFreeInode %#RX32\n", RT_BE2H_U32(pAgi->uRootFreeInode)));
397 Log2(("XFS: cLvlsFreeInode %RU32\n", RT_BE2H_U32(pAgi->cLvlsFreeInode)));
398 }
399}
400
401
402/**
403 * Logs a XFS filesystem inode.
404 *
405 * @returns nothing.
406 * @param pThis The XFS volume instance.
407 * @param iInode Inode number.
408 * @param pInode Pointer to the inode.
409 */
410static void rtFsXfsInode_Log(PRTFSXFSVOL pThis, XFSINO iInode, PCXFSINODECORE pInode)
411{
412 RT_NOREF(pThis);
413
414 if (LogIs2Enabled())
415 {
416 RTTIMESPEC Spec;
417 char sz[80];
418
419 Log2(("XFS: Inode %#RX64:\n", iInode));
420 Log2(("XFS: u16Magic %#RX16\n", RT_BE2H_U16(pInode->u16Magic)));
421 Log2(("XFS: fMode %#RX16\n", RT_BE2H_U16(pInode->fMode)));
422 Log2(("XFS: iVersion %#RX8\n", pInode->iVersion));
423 Log2(("XFS: enmFormat %#RX8\n", pInode->enmFormat));
424 Log2(("XFS: cOnLinks %RU16\n", RT_BE2H_U16(pInode->cOnLinks)));
425 Log2(("XFS: uUid %#RX32\n", RT_BE2H_U32(pInode->uUid)));
426 Log2(("XFS: uGid %#RX32\n", RT_BE2H_U32(pInode->uGid)));
427 Log2(("XFS: cLinks %#RX32\n", RT_BE2H_U32(pInode->cLinks)));
428 Log2(("XFS: uProjIdLow %#RX16\n", RT_BE2H_U16(pInode->uProjIdLow)));
429 Log2(("XFS: uProjIdHigh %#RX16\n", RT_BE2H_U16(pInode->uProjIdHigh)));
430 Log2(("XFS: cFlush %RU16\n", RT_BE2H_U16(pInode->cFlush)));
431 Log2(("XFS: TsLastAccessed %#RX32:%#RX32 %s\n", RT_BE2H_U32(pInode->TsLastAccessed.cSecEpoch),
432 RT_BE2H_U32(pInode->TsLastAccessed.cNanoSec),
433 RTTimeSpecToString(RTTimeSpecAddNano(RTTimeSpecSetSeconds(&Spec, RT_BE2H_U32(pInode->TsLastAccessed.cSecEpoch)),
434 RT_BE2H_U32(pInode->TsLastAccessed.cNanoSec)),
435 sz, sizeof(sz))));
436 Log2(("XFS: TsLastModified %#RX32:%#RX32 %s\n", RT_BE2H_U32(pInode->TsLastModified.cSecEpoch),
437 RT_BE2H_U32(pInode->TsLastModified.cNanoSec),
438 RTTimeSpecToString(RTTimeSpecAddNano(RTTimeSpecSetSeconds(&Spec, RT_BE2H_U32(pInode->TsLastModified.cSecEpoch)),
439 RT_BE2H_U32(pInode->TsLastModified.cNanoSec)),
440 sz, sizeof(sz))));
441 Log2(("XFS: TsCreatedModified %#RX32:%#RX32 %s\n", RT_BE2H_U32(pInode->TsCreatedModified.cSecEpoch),
442 RT_BE2H_U32(pInode->TsCreatedModified.cNanoSec),
443 RTTimeSpecToString(RTTimeSpecAddNano(RTTimeSpecSetSeconds(&Spec, RT_BE2H_U32(pInode->TsCreatedModified.cSecEpoch)),
444 RT_BE2H_U32(pInode->TsCreatedModified.cNanoSec)),
445 sz, sizeof(sz))));
446 Log2(("XFS: cbInode %#RX64\n", RT_BE2H_U64(pInode->cbInode)));
447 Log2(("XFS: cBlocks %#RX64\n", RT_BE2H_U64(pInode->cBlocks)));
448 Log2(("XFS: cExtentBlocksMin %#RX32\n", RT_BE2H_U32(pInode->cExtentBlocksMin)));
449 Log2(("XFS: cExtentsData %#RX32\n", RT_BE2H_U32(pInode->cExtentsData)));
450 Log2(("XFS: cExtentsAttr %#RX16\n", RT_BE2H_U16(pInode->cExtentsAttr)));
451 Log2(("XFS: offAttrFork %#RX8\n", pInode->offAttrFork));
452 Log2(("XFS: enmFormatAttr %#RX8\n", pInode->enmFormatAttr));
453 Log2(("XFS: fEvtMaskDmig %#RX32\n", RT_BE2H_U32(pInode->fEvtMaskDmig)));
454 Log2(("XFS: uStateDmig %#RX16\n", RT_BE2H_U16(pInode->uStateDmig)));
455 Log2(("XFS: fFlags %#RX16\n", RT_BE2H_U16(pInode->fFlags)));
456 Log2(("XFS: cGeneration %#RX32\n", RT_BE2H_U32(pInode->cGeneration)));
457 Log2(("XFS: offBlockUnlinkedNext %#RX32\n", RT_BE2H_U32(pInode->offBlockUnlinkedNext)));
458 Log2(("XFS: uChkSum %#RX32\n", RT_BE2H_U32(pInode->uChkSum)));
459 Log2(("XFS: cAttrChanges %#RX64\n", RT_BE2H_U64(pInode->cAttrChanges)));
460 Log2(("XFS: uFlushSeqNo %#RX64\n", RT_BE2H_U64(pInode->uFlushSeqNo)));
461 Log2(("XFS: fFlags2 %#RX64\n", RT_BE2H_U64(pInode->fFlags2)));
462 Log2(("XFS: cExtentCowMin %#RX32\n", RT_BE2H_U32(pInode->cExtentCowMin)));
463 Log2(("XFS: TsCreation %#RX32:%#RX32 %s\n", RT_BE2H_U32(pInode->TsCreation.cSecEpoch),
464 RT_BE2H_U32(pInode->TsCreation.cNanoSec),
465 RTTimeSpecToString(RTTimeSpecAddNano(RTTimeSpecSetSeconds(&Spec, RT_BE2H_U32(pInode->TsCreation.cSecEpoch)),
466 RT_BE2H_U32(pInode->TsCreation.cNanoSec)),
467 sz, sizeof(sz))));
468 Log2(("XFS: uInode %#RX64\n", RT_BE2H_U64(pInode->uInode)));
469 Log2(("XFS: abUuid <todo>\n"));
470 }
471}
472
473
474#if 0
475/**
476 * Logs a XFS filesystem directory entry.
477 *
478 * @returns nothing.
479 * @param pThis The XFS volume instance.
480 * @param idxDirEntry Directory entry index number.
481 * @param pDirEntry The directory entry.
482 */
483static void rtFsXfsDirEntry_Log(PRTFSXFSVOL pThis, uint32_t idxDirEntry, PCXFSDIRENTRYEX pDirEntry)
484{
485 if (LogIs2Enabled())
486 {
487 }
488}
489#endif
490#endif
491
492
493/**
494 * Converts a block number to a byte offset.
495 *
496 * @returns Offset in bytes for the given block number.
497 * @param pThis The XFS volume instance.
498 * @param iBlock The block number to convert.
499 */
500DECLINLINE(uint64_t) rtFsXfsBlockIdxToDiskOffset(PRTFSXFSVOL pThis, uint64_t iBlock)
501{
502 return iBlock << pThis->cBlockShift;
503}
504
505
506/**
507 * Converts a byte offset to a block number.
508 *
509 * @returns Block number.
510 * @param pThis The XFS volume instance.
511 * @param iBlock The offset to convert.
512 */
513DECLINLINE(uint64_t) rtFsXfsDiskOffsetToBlockIdx(PRTFSXFSVOL pThis, uint64_t off)
514{
515 return off >> pThis->cBlockShift;
516}
517
518
519/**
520 * Splits the given absolute inode number into the AG number, block inside the AG
521 * and the offset into the block where to find the inode structure.
522 *
523 * @returns nothing.
524 * @param pThis The XFS volume instance.
525 * @param iInode The inode to split.
526 * @param piAg Where to store the AG number.
527 * @param puBlock Where to store the block number inside the AG.
528 * @param poffBlock Where to store the offset into the block.
529 */
530DECLINLINE(void) rtFsXfsInodeSplitAbs(PRTFSXFSVOL pThis, XFSINO iInode,
531 uint32_t *piAg, uint32_t *puBlock,
532 uint32_t *poffBlock)
533{
534 *poffBlock = iInode & (pThis->cInodesPerBlock - 1);
535 iInode >>= pThis->cInodesPerBlockLog;
536 *puBlock = iInode & (RT_BIT_32(pThis->cAgBlocksLog) - 1); /* Using the log2 value here as it is rounded. */
537 iInode >>= RT_BIT_32(pThis->cAgBlocksLog) - 1;
538 *piAg = (uint32_t)iInode;
539}
540
541
542/**
543 * Allocates a new block group.
544 *
545 * @returns Pointer to the new block group descriptor or NULL if out of memory.
546 * @param pThis The XFS volume instance.
547 * @param cbAlloc How much to allocate.
548 * @param iBlockGroup Block group number.
549 */
550static PRTFSXFSBLOCKENTRY rtFsXfsVol_BlockAlloc(PRTFSXFSVOL pThis, size_t cbAlloc, uint64_t iBlock)
551{
552 PRTFSXFSBLOCKENTRY pBlock = (PRTFSXFSBLOCKENTRY)RTMemAllocZ(cbAlloc);
553 if (RT_LIKELY(pBlock))
554 {
555 pBlock->Core.Key = iBlock;
556 pBlock->cRefs = 0;
557 pThis->cbBlocks += cbAlloc;
558 }
559
560 return pBlock;
561}
562
563
564/**
565 * Returns a new block entry utilizing the cache if possible.
566 *
567 * @returns Pointer to the new block entry or NULL if out of memory.
568 * @param pThis The XFS volume instance.
569 * @param iBlock Block number.
570 */
571static PRTFSXFSBLOCKENTRY rtFsXfsVol_BlockGetNew(PRTFSXFSVOL pThis, uint64_t iBlock)
572{
573 PRTFSXFSBLOCKENTRY pBlock = NULL;
574 size_t cbAlloc = RT_UOFFSETOF_DYN(RTFSXFSBLOCKENTRY, abData[pThis->cbBlock]);
575 if (pThis->cbBlocks + cbAlloc <= RTFSXFS_MAX_BLOCK_CACHE_SIZE)
576 pBlock = rtFsXfsVol_BlockAlloc(pThis, cbAlloc, iBlock);
577 else
578 {
579 pBlock = RTListRemoveLast(&pThis->LstBlockLru, RTFSXFSBLOCKENTRY, NdLru);
580 if (!pBlock)
581 pBlock = rtFsXfsVol_BlockAlloc(pThis, cbAlloc, iBlock);
582 else
583 {
584 /* Remove the block group from the tree because it gets a new key. */
585 PAVLU64NODECORE pCore = RTAvlU64Remove(&pThis->BlockRoot, pBlock->Core.Key);
586 Assert(pCore == &pBlock->Core); RT_NOREF(pCore);
587 }
588 }
589
590 Assert(!pBlock->cRefs);
591 pBlock->Core.Key = iBlock;
592 pBlock->cRefs = 1;
593
594 return pBlock;
595}
596
597
598/**
599 * Frees the given block.
600 *
601 * @returns nothing.
602 * @param pThis The XFS volume instance.
603 * @param pBlock The block to free.
604 */
605static void rtFsXfsVol_BlockFree(PRTFSXFSVOL pThis, PRTFSXFSBLOCKENTRY pBlock)
606{
607 Assert(!pBlock->cRefs);
608
609 /*
610 * Put it into the cache if the limit wasn't exceeded, otherwise the block group
611 * is freed right away.
612 */
613 if (pThis->cbBlocks <= RTFSXFS_MAX_BLOCK_CACHE_SIZE)
614 {
615 /* Put onto the LRU list. */
616 RTListPrepend(&pThis->LstBlockLru, &pBlock->NdLru);
617 }
618 else
619 {
620 /* Remove from the tree and free memory. */
621 PAVLU64NODECORE pCore = RTAvlU64Remove(&pThis->BlockRoot, pBlock->Core.Key);
622 Assert(pCore == &pBlock->Core); RT_NOREF(pCore);
623 RTMemFree(pBlock);
624 pThis->cbBlocks -= RT_UOFFSETOF_DYN(RTFSXFSBLOCKENTRY, abData[pThis->cbBlock]);
625 }
626}
627
628
629/**
630 * Gets the specified block data from the volume.
631 *
632 * @returns IPRT status code.
633 * @param pThis The XFS volume instance.
634 * @param iBlock The filesystem block to load.
635 * @param ppBlock Where to return the pointer to the block entry on success.
636 * @param ppvData Where to return the pointer to the block data on success.
637 */
638static int rtFsXfsVol_BlockLoad(PRTFSXFSVOL pThis, uint64_t iBlock, PRTFSXFSBLOCKENTRY *ppBlock, void **ppvData)
639{
640 int rc = VINF_SUCCESS;
641
642 /* Try to fetch the block group from the cache first. */
643 PRTFSXFSBLOCKENTRY pBlock = (PRTFSXFSBLOCKENTRY)RTAvlU64Get(&pThis->BlockRoot, iBlock);
644 if (!pBlock)
645 {
646 /* Slow path, load from disk. */
647 pBlock = rtFsXfsVol_BlockGetNew(pThis, iBlock);
648 if (RT_LIKELY(pBlock))
649 {
650 uint64_t offRead = rtFsXfsBlockIdxToDiskOffset(pThis, iBlock);
651 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &pBlock->abData[0], pThis->cbBlock, NULL);
652 if (RT_SUCCESS(rc))
653 {
654 bool fIns = RTAvlU64Insert(&pThis->BlockRoot, &pBlock->Core);
655 Assert(fIns); RT_NOREF(fIns);
656 }
657 }
658 else
659 rc = VERR_NO_MEMORY;
660 }
661 else
662 {
663 /* Remove from current LRU list position and add to the beginning. */
664 uint32_t cRefs = ASMAtomicIncU32(&pBlock->cRefs);
665 if (cRefs == 1) /* Blocks get removed from the LRU list if they are referenced. */
666 RTListNodeRemove(&pBlock->NdLru);
667 }
668
669 if (RT_SUCCESS(rc))
670 {
671 *ppBlock = pBlock;
672 *ppvData = &pBlock->abData[0];
673 }
674 else if (pBlock)
675 {
676 ASMAtomicDecU32(&pBlock->cRefs);
677 rtFsXfsVol_BlockFree(pThis, pBlock); /* Free the block. */
678 }
679
680 return rc;
681}
682
683
684/**
685 * Releases a reference of the given block.
686 *
687 * @returns nothing.
688 * @param pThis The XFS volume instance.
689 * @param pBlock The block to release.
690 */
691static void rtFsXfsVol_BlockRelease(PRTFSXFSVOL pThis, PRTFSXFSBLOCKENTRY pBlock)
692{
693 uint32_t cRefs = ASMAtomicDecU32(&pBlock->cRefs);
694 if (!cRefs)
695 rtFsXfsVol_BlockFree(pThis, pBlock);
696}
697
698
699/**
700 * Allocates a new alloction group.
701 *
702 * @returns Pointer to the new allocation group descriptor or NULL if out of memory.
703 * @param pThis The XFS volume instance.
704 * @param iAG Allocation group number.
705 */
706static PRTFSXFSAG rtFsXfsAg_Alloc(PRTFSXFSVOL pThis, uint32_t iAg)
707{
708 PRTFSXFSAG pAg = (PRTFSXFSAG)RTMemAllocZ(sizeof(RTFSXFSAG));
709 if (RT_LIKELY(pAg))
710 {
711 pAg->Core.Key = iAg;
712 pAg->cRefs = 0;
713 pThis->cbAgs += sizeof(RTFSXFSAG);
714 }
715
716 return pAg;
717}
718
719
720/**
721 * Frees the given allocation group.
722 *
723 * @returns nothing.
724 * @param pThis The XFS volume instance.
725 * @param pAg The allocation group to free.
726 */
727static void rtFsXfsAg_Free(PRTFSXFSVOL pThis, PRTFSXFSAG pAg)
728{
729 Assert(!pAg->cRefs);
730
731 /*
732 * Put it into the cache if the limit wasn't exceeded, otherwise the allocation group
733 * is freed right away.
734 */
735 if (pThis->cbAgs <= RTFSXFS_MAX_AG_CACHE_SIZE)
736 {
737 /* Put onto the LRU list. */
738 RTListPrepend(&pThis->LstAgLru, &pAg->NdLru);
739 }
740 else
741 {
742 /* Remove from the tree and free memory. */
743 PAVLU32NODECORE pCore = RTAvlU32Remove(&pThis->AgRoot, pAg->Core.Key);
744 Assert(pCore == &pAg->Core); RT_NOREF(pCore);
745 RTMemFree(pAg);
746 pThis->cbAgs -= sizeof(RTFSXFSAG);
747 }
748}
749
750
751/**
752 * Returns a new block group utilizing the cache if possible.
753 *
754 * @returns Pointer to the new block group descriptor or NULL if out of memory.
755 * @param pThis The XFS volume instance.
756 * @param iAg Allocation group number.
757 */
758static PRTFSXFSAG rtFsXfsAg_GetNew(PRTFSXFSVOL pThis, uint32_t iAg)
759{
760 PRTFSXFSAG pAg = NULL;
761 if (pThis->cbAgs + sizeof(RTFSXFSAG) <= RTFSXFS_MAX_AG_CACHE_SIZE)
762 pAg = rtFsXfsAg_Alloc(pThis, iAg);
763 else
764 {
765 pAg = RTListRemoveLast(&pThis->LstAgLru, RTFSXFSAG, NdLru);
766 if (!pAg)
767 pAg = rtFsXfsAg_Alloc(pThis, iAg);
768 else
769 {
770 /* Remove the block group from the tree because it gets a new key. */
771 PAVLU32NODECORE pCore = RTAvlU32Remove(&pThis->AgRoot, pAg->Core.Key);
772 Assert(pCore == &pAg->Core); RT_NOREF(pCore);
773 }
774 }
775
776 Assert(!pAg->cRefs);
777 pAg->Core.Key = iAg;
778 pAg->cRefs = 1;
779
780 return pAg;
781}
782
783
784/**
785 * Loads the given allocation group number and returns it on success.
786 *
787 * @returns IPRT status code.
788 * @param pThis The XFS volume instance.
789 * @param iAg The allocation group to load.
790 * @param ppAg Where to store the allocation group on success.
791 */
792static int rtFsXfsAg_Load(PRTFSXFSVOL pThis, uint32_t iAg, PRTFSXFSAG *ppAg)
793{
794 int rc = VINF_SUCCESS;
795
796 AssertReturn(iAg < pThis->cAgs, VERR_VFS_BOGUS_FORMAT);
797
798 /* Try to fetch the allocation group from the cache first. */
799 PRTFSXFSAG pAg = (PRTFSXFSAG)RTAvlU32Get(&pThis->AgRoot, iAg);
800 if (!pAg)
801 {
802 /* Slow path, load from disk. */
803 pAg = rtFsXfsAg_GetNew(pThis, iAg);
804 if (RT_LIKELY(pAg))
805 {
806 uint64_t offRead = rtFsXfsBlockIdxToDiskOffset(pThis, iAg * pThis->cBlocksPerAg);
807 XFSSUPERBLOCK Sb;
808 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &Sb, sizeof(Sb), NULL);
809 if (RT_SUCCESS(rc))
810 {
811#ifdef LOG_ENABLED
812 rtFsXfsSb_Log(iAg, &Sb);
813#endif
814 }
815 }
816 else
817 rc = VERR_NO_MEMORY;
818 }
819 else
820 {
821 /* Remove from current LRU list position and add to the beginning. */
822 uint32_t cRefs = ASMAtomicIncU32(&pAg->cRefs);
823 if (cRefs == 1) /* Block groups get removed from the LRU list if they are referenced. */
824 RTListNodeRemove(&pAg->NdLru);
825 }
826
827 if (RT_SUCCESS(rc))
828 *ppAg = pAg;
829 else if (pAg)
830 {
831 ASMAtomicDecU32(&pAg->cRefs);
832 rtFsXfsAg_Free(pThis, pAg); /* Free the allocation group. */
833 }
834
835 return rc;
836}
837
838
839/**
840 * Releases a reference of the given allocation group.
841 *
842 * @returns nothing.
843 * @param pThis The XFS volume instance.
844 * @param pAg The allocation group to release.
845 */
846static void rtFsXfsAg_Release(PRTFSXFSVOL pThis, PRTFSXFSAG pAg)
847{
848 uint32_t cRefs = ASMAtomicDecU32(&pAg->cRefs);
849 if (!cRefs)
850 rtFsXfsAg_Free(pThis, pAg);
851}
852
853
854/**
855 * Allocates a new inode.
856 *
857 * @returns Pointer to the new inode or NULL if out of memory.
858 * @param pThis The XFS volume instance.
859 * @param iInode Inode number.
860 */
861static PRTFSXFSINODE rtFsXfsInode_Alloc(PRTFSXFSVOL pThis, uint32_t iInode)
862{
863 PRTFSXFSINODE pInode = (PRTFSXFSINODE)RTMemAllocZ(sizeof(RTFSXFSINODE));
864 if (RT_LIKELY(pInode))
865 {
866 pInode->Core.Key = iInode;
867 pInode->cRefs = 0;
868 pThis->cbInodes += sizeof(RTFSXFSINODE);
869 }
870
871 return pInode;
872}
873
874
875/**
876 * Frees the given inode.
877 *
878 * @returns nothing.
879 * @param pThis The XFS volume instance.
880 * @param pInode The inode to free.
881 */
882static void rtFsXfsInode_Free(PRTFSXFSVOL pThis, PRTFSXFSINODE pInode)
883{
884 Assert(!pInode->cRefs);
885
886 /*
887 * Put it into the cache if the limit wasn't exceeded, otherwise the inode
888 * is freed right away.
889 */
890 if (pThis->cbInodes <= RTFSXFS_MAX_INODE_CACHE_SIZE)
891 {
892 /* Put onto the LRU list. */
893 RTListPrepend(&pThis->LstInodeLru, &pInode->NdLru);
894 }
895 else
896 {
897 /* Remove from the tree and free memory. */
898 PAVLU64NODECORE pCore = RTAvlU64Remove(&pThis->InodeRoot, pInode->Core.Key);
899 Assert(pCore == &pInode->Core); RT_NOREF(pCore);
900 RTMemFree(pInode);
901 pThis->cbInodes -= sizeof(RTFSXFSINODE);
902 }
903}
904
905
906/**
907 * Returns a new inodep utilizing the cache if possible.
908 *
909 * @returns Pointer to the new inode or NULL if out of memory.
910 * @param pThis The XFS volume instance.
911 * @param iInode Inode number.
912 */
913static PRTFSXFSINODE rtFsXfsInode_GetNew(PRTFSXFSVOL pThis, XFSINO iInode)
914{
915 PRTFSXFSINODE pInode = NULL;
916 if (pThis->cbInodes + sizeof(RTFSXFSINODE) <= RTFSXFS_MAX_INODE_CACHE_SIZE)
917 pInode = rtFsXfsInode_Alloc(pThis, iInode);
918 else
919 {
920 pInode = RTListRemoveLast(&pThis->LstInodeLru, RTFSXFSINODE, NdLru);
921 if (!pInode)
922 pInode = rtFsXfsInode_Alloc(pThis, iInode);
923 else
924 {
925 /* Remove the block group from the tree because it gets a new key. */
926 PAVLU64NODECORE pCore = RTAvlU64Remove(&pThis->InodeRoot, pInode->Core.Key);
927 Assert(pCore == &pInode->Core); RT_NOREF(pCore);
928 }
929 }
930
931 Assert(!pInode->cRefs);
932 pInode->Core.Key = iInode;
933 pInode->cRefs = 1;
934
935 return pInode;
936}
937
938
939/**
940 * Loads the given inode number and returns it on success.
941 *
942 * @returns IPRT status code.
943 * @param pThis The XFS volume instance.
944 * @param iInode The inode to load.
945 * @param ppInode Where to store the inode on success.
946 */
947static int rtFsXfsInode_Load(PRTFSXFSVOL pThis, XFSINO iInode, PRTFSXFSINODE *ppInode)
948{
949 int rc = VINF_SUCCESS;
950
951 /* Try to fetch the inode from the cache first. */
952 PRTFSXFSINODE pInode = (PRTFSXFSINODE)RTAvlU64Get(&pThis->InodeRoot, iInode);
953 if (!pInode)
954 {
955 /* Slow path, load from disk. */
956 pInode = rtFsXfsInode_GetNew(pThis, iInode);
957 if (RT_LIKELY(pInode))
958 {
959 uint32_t iAg;
960 uint32_t uBlock;
961 uint32_t offBlock;
962
963 rtFsXfsInodeSplitAbs(pThis, iInode, &iAg, &uBlock, &offBlock);
964
965 uint64_t offRead = (iAg * pThis->cBlocksPerAg + uBlock) * pThis->cbBlock + offBlock;
966 XFSINODECORE Inode;
967 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &Inode, RT_MIN(sizeof(Inode), pThis->cbInode), NULL);
968 if (RT_SUCCESS(rc))
969 {
970#ifdef LOG_ENABLED
971 rtFsXfsInode_Log(pThis, iInode, &Inode);
972#endif
973
974 pInode->offInode = offRead;
975 pInode->fFlags = RT_BE2H_U16(Inode.fFlags);
976 pInode->enmFormat = Inode.enmFormat;
977 pInode->ObjInfo.cbObject = RT_BE2H_U64(Inode.cbInode);
978 pInode->ObjInfo.cbAllocated = RT_BE2H_U64(Inode.cBlocks) * pThis->cbBlock;
979 RTTimeSpecSetSeconds(&pInode->ObjInfo.AccessTime, RT_BE2H_U32(Inode.TsLastAccessed.cSecEpoch));
980 RTTimeSpecAddNano(&pInode->ObjInfo.AccessTime, RT_BE2H_U32(Inode.TsLastAccessed.cNanoSec));
981 RTTimeSpecSetSeconds(&pInode->ObjInfo.ModificationTime, RT_BE2H_U32(Inode.TsLastModified.cSecEpoch));
982 RTTimeSpecAddNano(&pInode->ObjInfo.ModificationTime, RT_BE2H_U32(Inode.TsLastModified.cNanoSec));
983 RTTimeSpecSetSeconds(&pInode->ObjInfo.ChangeTime, RT_BE2H_U32(Inode.TsCreatedModified.cSecEpoch));
984 RTTimeSpecAddNano(&pInode->ObjInfo.ChangeTime, RT_BE2H_U32(Inode.TsCreatedModified.cNanoSec));
985 pInode->ObjInfo.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
986 pInode->ObjInfo.Attr.u.Unix.uid = RT_BE2H_U32(Inode.uUid);
987 pInode->ObjInfo.Attr.u.Unix.gid = RT_BE2H_U32(Inode.uGid);
988 pInode->ObjInfo.Attr.u.Unix.cHardlinks = RT_BE2H_U16(Inode.cOnLinks); /** @todo v2 inodes. */
989 pInode->ObjInfo.Attr.u.Unix.INodeIdDevice = 0;
990 pInode->ObjInfo.Attr.u.Unix.INodeId = iInode;
991 pInode->ObjInfo.Attr.u.Unix.fFlags = 0;
992 pInode->ObjInfo.Attr.u.Unix.GenerationId = RT_BE2H_U32(Inode.cGeneration);
993 pInode->ObjInfo.Attr.u.Unix.Device = 0;
994 if (Inode.iVersion >= 3)
995 {
996 RTTimeSpecSetSeconds(&pInode->ObjInfo.BirthTime, RT_BE2H_U32(Inode.TsCreation.cSecEpoch));
997 RTTimeSpecAddNano(&pInode->ObjInfo.BirthTime, RT_BE2H_U32(Inode.TsCreation.cNanoSec));
998 }
999 else
1000 pInode->ObjInfo.BirthTime = pInode->ObjInfo.ChangeTime;
1001
1002 /* Fill in the mode. */
1003 pInode->ObjInfo.Attr.fMode = 0;
1004 uint16_t fInodeMode = RT_BE2H_U16(Inode.fMode);
1005 switch (XFS_INODE_MODE_TYPE_GET_TYPE(fInodeMode))
1006 {
1007 case XFS_INODE_MODE_TYPE_FIFO:
1008 pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_FIFO;
1009 break;
1010 case XFS_INODE_MODE_TYPE_CHAR:
1011 pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_DEV_CHAR;
1012 break;
1013 case XFS_INODE_MODE_TYPE_DIR:
1014 pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_DIRECTORY;
1015 break;
1016 case XFS_INODE_MODE_TYPE_BLOCK:
1017 pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_DEV_BLOCK;
1018 break;
1019 case XFS_INODE_MODE_TYPE_REGULAR:
1020 pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_FILE;
1021 break;
1022 case XFS_INODE_MODE_TYPE_SYMLINK:
1023 pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_SYMLINK;
1024 break;
1025 case XFS_INODE_MODE_TYPE_SOCKET:
1026 pInode->ObjInfo.Attr.fMode |= RTFS_TYPE_SOCKET;
1027 break;
1028 default:
1029 rc = VERR_VFS_BOGUS_FORMAT;
1030 }
1031 if (fInodeMode & XFS_INODE_MODE_EXEC_OTHER)
1032 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IXOTH;
1033 if (fInodeMode & XFS_INODE_MODE_WRITE_OTHER)
1034 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IWOTH;
1035 if (fInodeMode & XFS_INODE_MODE_READ_OTHER)
1036 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IROTH;
1037 if (fInodeMode & XFS_INODE_MODE_EXEC_GROUP)
1038 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IXGRP;
1039 if (fInodeMode & XFS_INODE_MODE_WRITE_GROUP)
1040 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IWGRP;
1041 if (fInodeMode & XFS_INODE_MODE_READ_GROUP)
1042 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IRGRP;
1043 if (fInodeMode & XFS_INODE_MODE_EXEC_OWNER)
1044 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IXUSR;
1045 if (fInodeMode & XFS_INODE_MODE_WRITE_OWNER)
1046 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IWUSR;
1047 if (fInodeMode & XFS_INODE_MODE_READ_OWNER)
1048 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_IRUSR;
1049 if (fInodeMode & XFS_INODE_MODE_STICKY)
1050 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_ISTXT;
1051 if (fInodeMode & XFS_INODE_MODE_SET_GROUP_ID)
1052 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_ISGID;
1053 if (fInodeMode & XFS_INODE_MODE_SET_USER_ID)
1054 pInode->ObjInfo.Attr.fMode |= RTFS_UNIX_ISUID;
1055 }
1056 }
1057 else
1058 rc = VERR_NO_MEMORY;
1059 }
1060 else
1061 {
1062 /* Remove from current LRU list position and add to the beginning. */
1063 uint32_t cRefs = ASMAtomicIncU32(&pInode->cRefs);
1064 if (cRefs == 1) /* Inodes get removed from the LRU list if they are referenced. */
1065 RTListNodeRemove(&pInode->NdLru);
1066 }
1067
1068 if (RT_SUCCESS(rc))
1069 *ppInode = pInode;
1070 else if (pInode)
1071 {
1072 ASMAtomicDecU32(&pInode->cRefs);
1073 rtFsXfsInode_Free(pThis, pInode); /* Free the inode. */
1074 }
1075
1076 return rc;
1077}
1078
1079
1080/**
1081 * Releases a reference of the given inode.
1082 *
1083 * @returns nothing.
1084 * @param pThis The XFS volume instance.
1085 * @param pInode The inode to release.
1086 */
1087static void rtFsXfsInode_Release(PRTFSXFSVOL pThis, PRTFSXFSINODE pInode)
1088{
1089 uint32_t cRefs = ASMAtomicDecU32(&pInode->cRefs);
1090 if (!cRefs)
1091 rtFsXfsInode_Free(pThis, pInode);
1092}
1093
1094
1095/**
1096 * Worker for various QueryInfo methods.
1097 *
1098 * @returns IPRT status code.
1099 * @param pInode The inode structure to return info for.
1100 * @param pObjInfo Where to return object info.
1101 * @param enmAddAttr What additional info to return.
1102 */
1103static int rtFsXfsInode_QueryInfo(PRTFSXFSINODE pInode, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1104{
1105 RT_ZERO(*pObjInfo);
1106
1107 pObjInfo->cbObject = pInode->ObjInfo.cbObject;
1108 pObjInfo->cbAllocated = pInode->ObjInfo.cbAllocated;
1109 pObjInfo->AccessTime = pInode->ObjInfo.AccessTime;
1110 pObjInfo->ModificationTime = pInode->ObjInfo.ModificationTime;
1111 pObjInfo->ChangeTime = pInode->ObjInfo.ChangeTime;
1112 pObjInfo->BirthTime = pInode->ObjInfo.BirthTime;
1113 pObjInfo->Attr.fMode = pInode->ObjInfo.Attr.fMode;
1114 pObjInfo->Attr.enmAdditional = enmAddAttr;
1115 switch (enmAddAttr)
1116 {
1117 case RTFSOBJATTRADD_UNIX:
1118 memcpy(&pObjInfo->Attr.u.Unix, &pInode->ObjInfo.Attr.u.Unix, sizeof(pInode->ObjInfo.Attr.u.Unix));
1119 break;
1120
1121 case RTFSOBJATTRADD_UNIX_OWNER:
1122 pObjInfo->Attr.u.UnixOwner.uid = pInode->ObjInfo.Attr.u.Unix.uid;
1123 break;
1124
1125 case RTFSOBJATTRADD_UNIX_GROUP:
1126 pObjInfo->Attr.u.UnixGroup.gid = pInode->ObjInfo.Attr.u.Unix.gid;
1127 break;
1128
1129 default:
1130 break;
1131 }
1132
1133 return VINF_SUCCESS;
1134}
1135
1136
1137/**
1138 * Maps the given inode block to the destination filesystem block.
1139 *
1140 * @returns IPRT status code.
1141 * @param pThis The XFS volume instance.
1142 * @param pInode The inode structure to read from.
1143 * @param iBlock The inode block to map.
1144 * @param cBlocks Number of blocks requested.
1145 * @param piBlockFs Where to store the filesystem block on success.
1146 * @param pcBlocks Where to store the number of contiguous blocks on success.
1147 * @param pfSparse Where to store the sparse flag on success.
1148 *
1149 * @todo Optimize
1150 */
1151static int rtFsXfsInode_MapBlockToFs(PRTFSXFSVOL pThis, PRTFSXFSINODE pInode, uint64_t iBlock, size_t cBlocks,
1152 uint64_t *piBlockFs, size_t *pcBlocks, bool *pfSparse)
1153{
1154 RT_NOREF(pThis, pInode, iBlock, cBlocks, piBlockFs, pcBlocks, pfSparse);
1155 return VERR_NOT_IMPLEMENTED;
1156}
1157
1158
1159/**
1160 * Reads data from the given inode at the given byte offset.
1161 *
1162 * @returns IPRT status code.
1163 * @param pThis The XFS volume instance.
1164 * @param pInode The inode structure to read from.
1165 * @param off The byte offset to start reading from.
1166 * @param pvBuf Where to store the read data to.
1167 * @param pcbRead Where to return the amount of data read.
1168 */
1169static int rtFsXfsInode_Read(PRTFSXFSVOL pThis, PRTFSXFSINODE pInode, uint64_t off, void *pvBuf, size_t cbRead, size_t *pcbRead)
1170{
1171 int rc = VINF_SUCCESS;
1172 uint8_t *pbBuf = (uint8_t *)pvBuf;
1173
1174 if (((uint64_t)pInode->ObjInfo.cbObject < off + cbRead))
1175 {
1176 if (!pcbRead)
1177 return VERR_EOF;
1178 else
1179 cbRead = (uint64_t)pInode->ObjInfo.cbObject - off;
1180 }
1181
1182 while ( cbRead
1183 && RT_SUCCESS(rc))
1184 {
1185 uint64_t iBlockStart = rtFsXfsDiskOffsetToBlockIdx(pThis, off);
1186 uint32_t offBlockStart = off % pThis->cbBlock;
1187
1188 /* Resolve the inode block to the proper filesystem block. */
1189 uint64_t iBlockFs = 0;
1190 size_t cBlocks = 0;
1191 bool fSparse = false;
1192 rc = rtFsXfsInode_MapBlockToFs(pThis, pInode, iBlockStart, 1, &iBlockFs, &cBlocks, &fSparse);
1193 if (RT_SUCCESS(rc))
1194 {
1195 Assert(cBlocks == 1);
1196
1197 size_t cbThisRead = RT_MIN(cbRead, pThis->cbBlock - offBlockStart);
1198
1199 if (!fSparse)
1200 {
1201 uint64_t offRead = rtFsXfsBlockIdxToDiskOffset(pThis, iBlockFs);
1202 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead + offBlockStart, pbBuf, cbThisRead, NULL);
1203 }
1204 else
1205 memset(pbBuf, 0, cbThisRead);
1206
1207 if (RT_SUCCESS(rc))
1208 {
1209 pbBuf += cbThisRead;
1210 cbRead -= cbThisRead;
1211 off += cbThisRead;
1212 if (pcbRead)
1213 *pcbRead += cbThisRead;
1214 }
1215 }
1216 }
1217
1218 return rc;
1219}
1220
1221
1222
1223/*
1224 *
1225 * File operations.
1226 * File operations.
1227 * File operations.
1228 *
1229 */
1230
1231/**
1232 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
1233 */
1234static DECLCALLBACK(int) rtFsXfsFile_Close(void *pvThis)
1235{
1236 PRTFSXFSFILE pThis = (PRTFSXFSFILE)pvThis;
1237 LogFlow(("rtFsXfsFile_Close(%p/%p)\n", pThis, pThis->pInode));
1238
1239 rtFsXfsInode_Release(pThis->pVol, pThis->pInode);
1240 pThis->pInode = NULL;
1241 pThis->pVol = NULL;
1242 return VINF_SUCCESS;
1243}
1244
1245
1246/**
1247 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
1248 */
1249static DECLCALLBACK(int) rtFsXfsFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1250{
1251 PRTFSXFSFILE pThis = (PRTFSXFSFILE)pvThis;
1252 return rtFsXfsInode_QueryInfo(pThis->pInode, pObjInfo, enmAddAttr);
1253}
1254
1255
1256/**
1257 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
1258 */
1259static DECLCALLBACK(int) rtFsXfsFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
1260{
1261 PRTFSXFSFILE pThis = (PRTFSXFSFILE)pvThis;
1262 AssertReturn(pSgBuf->cSegs == 1, VERR_INTERNAL_ERROR_3);
1263 RT_NOREF(fBlocking);
1264
1265 if (off == -1)
1266 off = pThis->offFile;
1267 else
1268 AssertReturn(off >= 0, VERR_INTERNAL_ERROR_3);
1269
1270 int rc;
1271 size_t cbRead = pSgBuf->paSegs[0].cbSeg;
1272 if (!pcbRead)
1273 {
1274 rc = rtFsXfsInode_Read(pThis->pVol, pThis->pInode, (uint64_t)off, pSgBuf->paSegs[0].pvSeg, cbRead, NULL);
1275 if (RT_SUCCESS(rc))
1276 pThis->offFile = off + cbRead;
1277 Log6(("rtFsXfsFile_Read: off=%#RX64 cbSeg=%#x -> %Rrc\n", off, pSgBuf->paSegs[0].cbSeg, rc));
1278 }
1279 else
1280 {
1281 PRTFSXFSINODE pInode = pThis->pInode;
1282 if (off >= pInode->ObjInfo.cbObject)
1283 {
1284 *pcbRead = 0;
1285 rc = VINF_EOF;
1286 }
1287 else
1288 {
1289 if ((uint64_t)off + cbRead <= (uint64_t)pInode->ObjInfo.cbObject)
1290 rc = rtFsXfsInode_Read(pThis->pVol, pThis->pInode, (uint64_t)off, pSgBuf->paSegs[0].pvSeg, cbRead, NULL);
1291 else
1292 {
1293 /* Return VINF_EOF if beyond end-of-file. */
1294 cbRead = (size_t)(pInode->ObjInfo.cbObject - off);
1295 rc = rtFsXfsInode_Read(pThis->pVol, pThis->pInode, off, pSgBuf->paSegs[0].pvSeg, cbRead, NULL);
1296 if (RT_SUCCESS(rc))
1297 rc = VINF_EOF;
1298 }
1299 if (RT_SUCCESS(rc))
1300 {
1301 pThis->offFile = off + cbRead;
1302 *pcbRead = cbRead;
1303 }
1304 else
1305 *pcbRead = 0;
1306 }
1307 Log6(("rtFsXfsFile_Read: off=%#RX64 cbSeg=%#x -> %Rrc *pcbRead=%#x\n", off, pSgBuf->paSegs[0].cbSeg, rc, *pcbRead));
1308 }
1309
1310 return rc;
1311}
1312
1313
1314/**
1315 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
1316 */
1317static DECLCALLBACK(int) rtFsXfsFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
1318{
1319 RT_NOREF(pvThis, off, pSgBuf, fBlocking, pcbWritten);
1320 return VERR_WRITE_PROTECT;
1321}
1322
1323
1324/**
1325 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
1326 */
1327static DECLCALLBACK(int) rtFsXfsFile_Flush(void *pvThis)
1328{
1329 RT_NOREF(pvThis);
1330 return VINF_SUCCESS;
1331}
1332
1333
1334/**
1335 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
1336 */
1337static DECLCALLBACK(int) rtFsXfsFile_Tell(void *pvThis, PRTFOFF poffActual)
1338{
1339 PRTFSXFSFILE pThis = (PRTFSXFSFILE)pvThis;
1340 *poffActual = pThis->offFile;
1341 return VINF_SUCCESS;
1342}
1343
1344
1345/**
1346 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
1347 */
1348static DECLCALLBACK(int) rtFsXfsFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
1349{
1350 RT_NOREF(pvThis, fMode, fMask);
1351 return VERR_WRITE_PROTECT;
1352}
1353
1354
1355/**
1356 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
1357 */
1358static DECLCALLBACK(int) rtFsXfsFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1359 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1360{
1361 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1362 return VERR_WRITE_PROTECT;
1363}
1364
1365
1366/**
1367 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
1368 */
1369static DECLCALLBACK(int) rtFsXfsFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
1370{
1371 RT_NOREF(pvThis, uid, gid);
1372 return VERR_WRITE_PROTECT;
1373}
1374
1375
1376/**
1377 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
1378 */
1379static DECLCALLBACK(int) rtFsXfsFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
1380{
1381 PRTFSXFSFILE pThis = (PRTFSXFSFILE)pvThis;
1382 RTFOFF offNew;
1383 switch (uMethod)
1384 {
1385 case RTFILE_SEEK_BEGIN:
1386 offNew = offSeek;
1387 break;
1388 case RTFILE_SEEK_END:
1389 offNew = pThis->pInode->ObjInfo.cbObject + offSeek;
1390 break;
1391 case RTFILE_SEEK_CURRENT:
1392 offNew = (RTFOFF)pThis->offFile + offSeek;
1393 break;
1394 default:
1395 return VERR_INVALID_PARAMETER;
1396 }
1397 if (offNew >= 0)
1398 {
1399 pThis->offFile = offNew;
1400 *poffActual = offNew;
1401 return VINF_SUCCESS;
1402 }
1403 return VERR_NEGATIVE_SEEK;
1404}
1405
1406
1407/**
1408 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
1409 */
1410static DECLCALLBACK(int) rtFsXfsFile_QuerySize(void *pvThis, uint64_t *pcbFile)
1411{
1412 PRTFSXFSFILE pThis = (PRTFSXFSFILE)pvThis;
1413 *pcbFile = (uint64_t)pThis->pInode->ObjInfo.cbObject;
1414 return VINF_SUCCESS;
1415}
1416
1417
1418/**
1419 * @interface_method_impl{RTVFSFILEOPS,pfnSetSize}
1420 */
1421static DECLCALLBACK(int) rtFsXfsFile_SetSize(void *pvThis, uint64_t cbFile, uint32_t fFlags)
1422{
1423 RT_NOREF(pvThis, cbFile, fFlags);
1424 return VERR_WRITE_PROTECT;
1425}
1426
1427
1428/**
1429 * @interface_method_impl{RTVFSFILEOPS,pfnQueryMaxSize}
1430 */
1431static DECLCALLBACK(int) rtFsXfsFile_QueryMaxSize(void *pvThis, uint64_t *pcbMax)
1432{
1433 RT_NOREF(pvThis);
1434 *pcbMax = INT64_MAX; /** @todo */
1435 return VINF_SUCCESS;
1436}
1437
1438
1439/**
1440 * XFS file operations.
1441 */
1442static const RTVFSFILEOPS g_rtFsXfsFileOps =
1443{
1444 { /* Stream */
1445 { /* Obj */
1446 RTVFSOBJOPS_VERSION,
1447 RTVFSOBJTYPE_FILE,
1448 "XFS File",
1449 rtFsXfsFile_Close,
1450 rtFsXfsFile_QueryInfo,
1451 RTVFSOBJOPS_VERSION
1452 },
1453 RTVFSIOSTREAMOPS_VERSION,
1454 RTVFSIOSTREAMOPS_FEAT_NO_SG,
1455 rtFsXfsFile_Read,
1456 rtFsXfsFile_Write,
1457 rtFsXfsFile_Flush,
1458 NULL /*PollOne*/,
1459 rtFsXfsFile_Tell,
1460 NULL /*pfnSkip*/,
1461 NULL /*pfnZeroFill*/,
1462 RTVFSIOSTREAMOPS_VERSION,
1463 },
1464 RTVFSFILEOPS_VERSION,
1465 0,
1466 { /* ObjSet */
1467 RTVFSOBJSETOPS_VERSION,
1468 RT_UOFFSETOF(RTVFSFILEOPS, ObjSet) - RT_UOFFSETOF(RTVFSFILEOPS, Stream.Obj),
1469 rtFsXfsFile_SetMode,
1470 rtFsXfsFile_SetTimes,
1471 rtFsXfsFile_SetOwner,
1472 RTVFSOBJSETOPS_VERSION
1473 },
1474 rtFsXfsFile_Seek,
1475 rtFsXfsFile_QuerySize,
1476 rtFsXfsFile_SetSize,
1477 rtFsXfsFile_QueryMaxSize,
1478 RTVFSFILEOPS_VERSION
1479};
1480
1481
1482/**
1483 * Creates a new VFS file from the given regular file inode.
1484 *
1485 * @returns IPRT status code.
1486 * @param pThis The XFS volume instance.
1487 * @param fOpen Open flags passed.
1488 * @param iInode The inode for the file.
1489 * @param phVfsFile Where to store the VFS file handle on success.
1490 * @param pErrInfo Where to record additional error information on error, optional.
1491 * @param pszWhat Logging prefix.
1492 */
1493static int rtFsXfsVol_NewFile(PRTFSXFSVOL pThis, uint64_t fOpen, uint32_t iInode,
1494 PRTVFSFILE phVfsFile, PRTERRINFO pErrInfo, const char *pszWhat)
1495{
1496 /*
1497 * Load the inode and check that it really is a file.
1498 */
1499 PRTFSXFSINODE pInode = NULL;
1500 int rc = rtFsXfsInode_Load(pThis, iInode, &pInode);
1501 if (RT_SUCCESS(rc))
1502 {
1503 if (RTFS_IS_FILE(pInode->ObjInfo.Attr.fMode))
1504 {
1505 PRTFSXFSFILE pNewFile;
1506 rc = RTVfsNewFile(&g_rtFsXfsFileOps, sizeof(*pNewFile), fOpen, pThis->hVfsSelf, NIL_RTVFSLOCK,
1507 phVfsFile, (void **)&pNewFile);
1508 if (RT_SUCCESS(rc))
1509 {
1510 pNewFile->pVol = pThis;
1511 pNewFile->pInode = pInode;
1512 pNewFile->offFile = 0;
1513 }
1514 }
1515 else
1516 rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_NOT_A_FILE, "%s: fMode=%#RX32", pszWhat, pInode->ObjInfo.Attr.fMode);
1517
1518 if (RT_FAILURE(rc))
1519 rtFsXfsInode_Release(pThis, pInode);
1520 }
1521
1522 return rc;
1523}
1524
1525
1526
1527/*
1528 *
1529 * XFS directory code.
1530 * XFS directory code.
1531 * XFS directory code.
1532 *
1533 */
1534
1535/**
1536 * Looks up an entry in the given directory inode.
1537 *
1538 * @returns IPRT status code.
1539 * @param pThis The XFS volume instance.
1540 * @param pInode The directory inode structure to.
1541 * @param pszEntry The entry to lookup.
1542 * @param piInode Where to store the inode number if the entry was found.
1543 */
1544static int rtFsXfsDir_Lookup(PRTFSXFSVOL pThis, PRTFSXFSINODE pInode, const char *pszEntry, uint32_t *piInode)
1545{
1546 uint64_t offEntry = 0;
1547 int rc = VERR_FILE_NOT_FOUND;
1548 uint32_t idxDirEntry = 0;
1549 size_t cchEntry = strlen(pszEntry);
1550
1551 if (cchEntry > 255)
1552 return VERR_FILENAME_TOO_LONG;
1553
1554 RT_NOREF(pThis, idxDirEntry, offEntry, pInode, piInode);
1555
1556#if 0 /** @todo */
1557 while (offEntry < (uint64_t)pInode->ObjInfo.cbObject)
1558 {
1559 EXTDIRENTRYEX DirEntry;
1560 size_t cbThis = RT_MIN(sizeof(DirEntry), (uint64_t)pInode->ObjInfo.cbObject - offEntry);
1561 int rc2 = rtFsXfsInode_Read(pThis, pInode, offEntry, &DirEntry, cbThis, NULL);
1562 if (RT_SUCCESS(rc2))
1563 {
1564#ifdef LOG_ENABLED
1565 rtFsExtDirEntry_Log(pThis, idxDirEntry, &DirEntry);
1566#endif
1567
1568 uint16_t cbName = pThis->fFeaturesIncompat & EXT_SB_FEAT_INCOMPAT_DIR_FILETYPE
1569 ? DirEntry.Core.u.v2.cbName
1570 : RT_LE2H_U16(DirEntry.Core.u.v1.cbName);
1571 if ( cchEntry == cbName
1572 && !memcmp(pszEntry, &DirEntry.Core.achName[0], cchEntry))
1573 {
1574 *piInode = RT_LE2H_U32(DirEntry.Core.iInodeRef);
1575 rc = VINF_SUCCESS;
1576 break;
1577 }
1578
1579 offEntry += RT_LE2H_U16(DirEntry.Core.cbRecord);
1580 idxDirEntry++;
1581 }
1582 else
1583 {
1584 rc = rc2;
1585 break;
1586 }
1587 }
1588#endif
1589 return rc;
1590}
1591
1592
1593
1594/*
1595 *
1596 * Directory instance methods
1597 * Directory instance methods
1598 * Directory instance methods
1599 *
1600 */
1601
1602/**
1603 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
1604 */
1605static DECLCALLBACK(int) rtFsXfsDir_Close(void *pvThis)
1606{
1607 PRTFSXFSDIR pThis = (PRTFSXFSDIR)pvThis;
1608 LogFlowFunc(("pThis=%p\n", pThis));
1609 rtFsXfsInode_Release(pThis->pVol, pThis->pInode);
1610 pThis->pInode = NULL;
1611 return VINF_SUCCESS;
1612}
1613
1614
1615/**
1616 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
1617 */
1618static DECLCALLBACK(int) rtFsXfsDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1619{
1620 PRTFSXFSDIR pThis = (PRTFSXFSDIR)pvThis;
1621 LogFlowFunc(("\n"));
1622 return rtFsXfsInode_QueryInfo(pThis->pInode, pObjInfo, enmAddAttr);
1623}
1624
1625
1626/**
1627 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
1628 */
1629static DECLCALLBACK(int) rtFsXfsDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
1630{
1631 LogFlowFunc(("\n"));
1632 RT_NOREF(pvThis, fMode, fMask);
1633 return VERR_WRITE_PROTECT;
1634}
1635
1636
1637/**
1638 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
1639 */
1640static DECLCALLBACK(int) rtFsXfsDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1641 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1642{
1643 LogFlowFunc(("\n"));
1644 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1645 return VERR_WRITE_PROTECT;
1646}
1647
1648
1649/**
1650 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
1651 */
1652static DECLCALLBACK(int) rtFsXfsDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
1653{
1654 LogFlowFunc(("\n"));
1655 RT_NOREF(pvThis, uid, gid);
1656 return VERR_WRITE_PROTECT;
1657}
1658
1659
1660/**
1661 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
1662 */
1663static DECLCALLBACK(int) rtFsXfsDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen,
1664 uint32_t fFlags, PRTVFSOBJ phVfsObj)
1665{
1666 LogFlowFunc(("pszEntry='%s' fOpen=%#RX64 fFlags=%#x\n", pszEntry, fOpen, fFlags));
1667 PRTFSXFSDIR pThis = (PRTFSXFSDIR)pvThis;
1668 PRTFSXFSVOL pVol = pThis->pVol;
1669 int rc = VINF_SUCCESS;
1670
1671 RT_NOREF(pThis, pVol, phVfsObj, pszEntry, fFlags);
1672
1673 /*
1674 * We cannot create or replace anything, just open stuff.
1675 */
1676 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
1677 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE)
1678 { /* likely */ }
1679 else
1680 return VERR_WRITE_PROTECT;
1681
1682 /*
1683 * Lookup the entry.
1684 */
1685 uint32_t iInode = 0;
1686 rc = rtFsXfsDir_Lookup(pVol, pThis->pInode, pszEntry, &iInode);
1687 if (RT_SUCCESS(rc))
1688 {
1689 PRTFSXFSINODE pInode = NULL;
1690 rc = rtFsXfsInode_Load(pVol, iInode, &pInode);
1691 if (RT_SUCCESS(rc))
1692 {
1693 if (RTFS_IS_DIRECTORY(pInode->ObjInfo.Attr.fMode))
1694 {
1695 RTVFSDIR hVfsDir;
1696 rc = rtFsXfsVol_OpenDirByInode(pVol, iInode, &hVfsDir);
1697 if (RT_SUCCESS(rc))
1698 {
1699 *phVfsObj = RTVfsObjFromDir(hVfsDir);
1700 RTVfsDirRelease(hVfsDir);
1701 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
1702 }
1703 }
1704 else if (RTFS_IS_FILE(pInode->ObjInfo.Attr.fMode))
1705 {
1706 RTVFSFILE hVfsFile;
1707 rc = rtFsXfsVol_NewFile(pVol, fOpen, iInode, &hVfsFile, NULL, pszEntry);
1708 if (RT_SUCCESS(rc))
1709 {
1710 *phVfsObj = RTVfsObjFromFile(hVfsFile);
1711 RTVfsFileRelease(hVfsFile);
1712 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
1713 }
1714 }
1715 else
1716 rc = VERR_NOT_SUPPORTED;
1717 }
1718 }
1719
1720 LogFlow(("rtFsXfsDir_Open(%s): returns %Rrc\n", pszEntry, rc));
1721 return rc;
1722}
1723
1724
1725/**
1726 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
1727 */
1728static DECLCALLBACK(int) rtFsXfsDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
1729{
1730 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir);
1731 LogFlowFunc(("\n"));
1732 return VERR_WRITE_PROTECT;
1733}
1734
1735
1736/**
1737 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
1738 */
1739static DECLCALLBACK(int) rtFsXfsDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
1740{
1741 RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
1742 LogFlowFunc(("\n"));
1743 return VERR_NOT_SUPPORTED;
1744}
1745
1746
1747/**
1748 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
1749 */
1750static DECLCALLBACK(int) rtFsXfsDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
1751 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
1752{
1753 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
1754 LogFlowFunc(("\n"));
1755 return VERR_WRITE_PROTECT;
1756}
1757
1758
1759/**
1760 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
1761 */
1762static DECLCALLBACK(int) rtFsXfsDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
1763{
1764 RT_NOREF(pvThis, pszEntry, fType);
1765 LogFlowFunc(("\n"));
1766 return VERR_WRITE_PROTECT;
1767}
1768
1769
1770/**
1771 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
1772 */
1773static DECLCALLBACK(int) rtFsXfsDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
1774{
1775 RT_NOREF(pvThis, pszEntry, fType, pszNewName);
1776 LogFlowFunc(("\n"));
1777 return VERR_WRITE_PROTECT;
1778}
1779
1780
1781/**
1782 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
1783 */
1784static DECLCALLBACK(int) rtFsXfsDir_RewindDir(void *pvThis)
1785{
1786 PRTFSXFSDIR pThis = (PRTFSXFSDIR)pvThis;
1787 LogFlowFunc(("\n"));
1788
1789 pThis->fNoMoreFiles = false;
1790 pThis->offEntry = 0;
1791 pThis->idxEntry = 0;
1792 return VINF_SUCCESS;
1793}
1794
1795
1796/**
1797 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
1798 */
1799static DECLCALLBACK(int) rtFsXfsDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
1800 RTFSOBJATTRADD enmAddAttr)
1801{
1802 PRTFSXFSDIR pThis = (PRTFSXFSDIR)pvThis;
1803 PRTFSXFSINODE pInode = pThis->pInode;
1804 LogFlowFunc(("\n"));
1805
1806 if (pThis->fNoMoreFiles)
1807 return VERR_NO_MORE_FILES;
1808
1809 RT_NOREF(pInode, pDirEntry, pcbDirEntry, enmAddAttr);
1810 return VERR_NOT_IMPLEMENTED;
1811}
1812
1813
1814/**
1815 * XFS directory operations.
1816 */
1817static const RTVFSDIROPS g_rtFsXfsDirOps =
1818{
1819 { /* Obj */
1820 RTVFSOBJOPS_VERSION,
1821 RTVFSOBJTYPE_DIR,
1822 "XFS Dir",
1823 rtFsXfsDir_Close,
1824 rtFsXfsDir_QueryInfo,
1825 RTVFSOBJOPS_VERSION
1826 },
1827 RTVFSDIROPS_VERSION,
1828 0,
1829 { /* ObjSet */
1830 RTVFSOBJSETOPS_VERSION,
1831 RT_UOFFSETOF(RTVFSDIROPS, ObjSet) - RT_UOFFSETOF(RTVFSDIROPS, Obj),
1832 rtFsXfsDir_SetMode,
1833 rtFsXfsDir_SetTimes,
1834 rtFsXfsDir_SetOwner,
1835 RTVFSOBJSETOPS_VERSION
1836 },
1837 rtFsXfsDir_Open,
1838 NULL /* pfnFollowAbsoluteSymlink */,
1839 NULL /* pfnOpenFile */,
1840 NULL /* pfnOpenDir */,
1841 rtFsXfsDir_CreateDir,
1842 rtFsXfsDir_OpenSymlink,
1843 rtFsXfsDir_CreateSymlink,
1844 NULL /* pfnQueryEntryInfo */,
1845 rtFsXfsDir_UnlinkEntry,
1846 rtFsXfsDir_RenameEntry,
1847 rtFsXfsDir_RewindDir,
1848 rtFsXfsDir_ReadDir,
1849 RTVFSDIROPS_VERSION,
1850};
1851
1852
1853/**
1854 * Opens a directory by the given inode.
1855 *
1856 * @returns IPRT status code.
1857 * @param pThis The XFS volume instance.
1858 * @param iInode The inode to open.
1859 * @param phVfsDir Where to store the handle to the VFS directory on success.
1860 */
1861static int rtFsXfsVol_OpenDirByInode(PRTFSXFSVOL pThis, uint32_t iInode, PRTVFSDIR phVfsDir)
1862{
1863 PRTFSXFSINODE pInode = NULL;
1864 int rc = rtFsXfsInode_Load(pThis, iInode, &pInode);
1865 if (RT_SUCCESS(rc))
1866 {
1867 if (RTFS_IS_DIRECTORY(pInode->ObjInfo.Attr.fMode))
1868 {
1869 PRTFSXFSDIR pNewDir;
1870 rc = RTVfsNewDir(&g_rtFsXfsDirOps, sizeof(*pNewDir), 0 /*fFlags*/, pThis->hVfsSelf, NIL_RTVFSLOCK,
1871 phVfsDir, (void **)&pNewDir);
1872 if (RT_SUCCESS(rc))
1873 {
1874 pNewDir->fNoMoreFiles = false;
1875 pNewDir->pVol = pThis;
1876 pNewDir->pInode = pInode;
1877 }
1878 }
1879 else
1880 rc = VERR_VFS_BOGUS_FORMAT;
1881
1882 if (RT_FAILURE(rc))
1883 rtFsXfsInode_Release(pThis, pInode);
1884 }
1885
1886 return rc;
1887}
1888
1889
1890
1891/*
1892 *
1893 * Volume level code.
1894 * Volume level code.
1895 * Volume level code.
1896 *
1897 */
1898
1899static DECLCALLBACK(int) rtFsXfsVolAgTreeDestroy(PAVLU32NODECORE pCore, void *pvUser)
1900{
1901 RT_NOREF(pvUser);
1902
1903 PRTFSXFSAG pAg = (PRTFSXFSAG)pCore;
1904 Assert(!pAg->cRefs);
1905 RTMemFree(pAg);
1906 return VINF_SUCCESS;
1907}
1908
1909
1910static DECLCALLBACK(int) rtFsXfsVolInodeTreeDestroy(PAVLU64NODECORE pCore, void *pvUser)
1911{
1912 RT_NOREF(pvUser);
1913
1914 PRTFSXFSINODE pInode = (PRTFSXFSINODE)pCore;
1915 Assert(!pInode->cRefs);
1916 RTMemFree(pInode);
1917 return VINF_SUCCESS;
1918}
1919
1920
1921static DECLCALLBACK(int) rtFsXfsVolBlockTreeDestroy(PAVLU64NODECORE pCore, void *pvUser)
1922{
1923 RT_NOREF(pvUser);
1924
1925 PRTFSXFSBLOCKENTRY pBlock = (PRTFSXFSBLOCKENTRY)pCore;
1926 Assert(!pBlock->cRefs);
1927 RTMemFree(pBlock);
1928 return VINF_SUCCESS;
1929}
1930
1931
1932/**
1933 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
1934 */
1935static DECLCALLBACK(int) rtFsXfsVol_Close(void *pvThis)
1936{
1937 PRTFSXFSVOL pThis = (PRTFSXFSVOL)pvThis;
1938
1939 /* Destroy the block group tree. */
1940 RTAvlU32Destroy(&pThis->AgRoot, rtFsXfsVolAgTreeDestroy, pThis);
1941 pThis->AgRoot = NULL;
1942 RTListInit(&pThis->LstAgLru);
1943
1944 /* Destroy the inode tree. */
1945 RTAvlU64Destroy(&pThis->InodeRoot, rtFsXfsVolInodeTreeDestroy, pThis);
1946 pThis->InodeRoot = NULL;
1947 RTListInit(&pThis->LstInodeLru);
1948
1949 /* Destroy the block cache tree. */
1950 RTAvlU64Destroy(&pThis->BlockRoot, rtFsXfsVolBlockTreeDestroy, pThis);
1951 pThis->BlockRoot = NULL;
1952 RTListInit(&pThis->LstBlockLru);
1953
1954 /*
1955 * Backing file and handles.
1956 */
1957 RTVfsFileRelease(pThis->hVfsBacking);
1958 pThis->hVfsBacking = NIL_RTVFSFILE;
1959 pThis->hVfsSelf = NIL_RTVFS;
1960
1961 return VINF_SUCCESS;
1962}
1963
1964
1965/**
1966 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo}
1967 */
1968static DECLCALLBACK(int) rtFsXfsVol_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1969{
1970 RT_NOREF(pvThis, pObjInfo, enmAddAttr);
1971 return VERR_WRONG_TYPE;
1972}
1973
1974
1975/**
1976 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnOpenRoot}
1977 */
1978static DECLCALLBACK(int) rtFsXfsVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
1979{
1980 PRTFSXFSVOL pThis = (PRTFSXFSVOL)pvThis;
1981 int rc = rtFsXfsVol_OpenDirByInode(pThis, pThis->uInodeRoot, phVfsDir);
1982 LogFlowFunc(("returns %Rrc\n", rc));
1983 return rc;
1984}
1985
1986
1987/**
1988 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryRangeState}
1989 */
1990static DECLCALLBACK(int) rtFsXfsVol_QueryRangeState(void *pvThis, uint64_t off, size_t cb, bool *pfUsed)
1991{
1992 RT_NOREF(pvThis, off, cb, pfUsed);
1993 return VERR_NOT_IMPLEMENTED;
1994}
1995
1996
1997DECL_HIDDEN_CONST(const RTVFSOPS) g_rtFsXfsVolOps =
1998{
1999 /* .Obj = */
2000 {
2001 /* .uVersion = */ RTVFSOBJOPS_VERSION,
2002 /* .enmType = */ RTVFSOBJTYPE_VFS,
2003 /* .pszName = */ "XfsVol",
2004 /* .pfnClose = */ rtFsXfsVol_Close,
2005 /* .pfnQueryInfo = */ rtFsXfsVol_QueryInfo,
2006 /* .uEndMarker = */ RTVFSOBJOPS_VERSION
2007 },
2008 /* .uVersion = */ RTVFSOPS_VERSION,
2009 /* .fFeatures = */ 0,
2010 /* .pfnOpenRoot = */ rtFsXfsVol_OpenRoot,
2011 /* .pfnQueryRangeState = */ rtFsXfsVol_QueryRangeState,
2012 /* .uEndMarker = */ RTVFSOPS_VERSION
2013};
2014
2015
2016/**
2017 * Loads and parses the AGI block.
2018 *
2019 * @returns IPRT status code.
2020 * @param pThis The XFS volume instance.
2021 * @param pErrInfo Where to return additional error info.
2022 */
2023static int rtFsXfsVolLoadAgi(PRTFSXFSVOL pThis, PRTERRINFO pErrInfo)
2024{
2025 XFSAGI Agi;
2026 int rc = RTVfsFileReadAt(pThis->hVfsBacking, 2 * pThis->cbSector, &Agi, sizeof(&Agi), NULL);
2027 if (RT_SUCCESS(rc))
2028 {
2029#ifdef LOG_ENABLED
2030 rtFsXfsAgi_Log(0, &Agi);
2031#endif
2032
2033 /** @todo Verification */
2034 RT_NOREF(pErrInfo);
2035 }
2036
2037 return rc;
2038}
2039
2040
2041/**
2042 * Loads and parses the superblock of the filesystem.
2043 *
2044 * @returns IPRT status code.
2045 * @param pThis The XFS volume instance.
2046 * @param pErrInfo Where to return additional error info.
2047 */
2048static int rtFsXfsVolLoadAndParseSuperblock(PRTFSXFSVOL pThis, PRTERRINFO pErrInfo)
2049{
2050 int rc = VINF_SUCCESS;
2051 XFSSUPERBLOCK Sb;
2052 rc = RTVfsFileReadAt(pThis->hVfsBacking, XFS_SB_OFFSET, &Sb, sizeof(XFSSUPERBLOCK), NULL);
2053 if (RT_FAILURE(rc))
2054 return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading super block");
2055
2056 /* Validate the superblock. */
2057 if (RT_BE2H_U32(Sb.u32Magic) != XFS_SB_MAGIC)
2058 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, "Not XFS - Signature mismatch: %RX32", RT_BE2H_U32(Sb.u32Magic));
2059
2060#ifdef LOG_ENABLED
2061 rtFsXfsSb_Log(0, &Sb);
2062#endif
2063
2064 /** @todo More verification */
2065 pThis->cbSector = RT_BE2H_U32(Sb.cbSector);
2066 pThis->cbBlock = RT_BE2H_U32(Sb.cbBlock);
2067 pThis->cBlockShift = Sb.cBlockSzLog;
2068 pThis->cBlocksPerAg = RT_BE2H_U32(Sb.cAgBlocks);
2069 pThis->cAgs = RT_BE2H_U32(Sb.cAg);
2070 pThis->uInodeRoot = RT_BE2H_U64(Sb.uInodeRoot);
2071 pThis->cbInode = RT_BE2H_U16(Sb.cbInode);
2072 pThis->cInodesPerBlock = RT_BE2H_U16(Sb.cInodesPerBlock);
2073 pThis->cAgBlocksLog = Sb.cAgBlocksLog;
2074 pThis->cInodesPerBlockLog = Sb.cInodesPerBlockLog;
2075 return rc;
2076}
2077
2078
2079RTDECL(int) RTFsXfsVolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fXfsFlags, PRTVFS phVfs, PRTERRINFO pErrInfo)
2080{
2081 AssertPtrReturn(phVfs, VERR_INVALID_POINTER);
2082 AssertReturn(!(fMntFlags & ~RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
2083 AssertReturn(!fXfsFlags, VERR_INVALID_FLAGS);
2084
2085 uint32_t cRefs = RTVfsFileRetain(hVfsFileIn);
2086 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
2087
2088 /*
2089 * Create a VFS instance and initialize the data so rtFsXfsVol_Close works.
2090 */
2091 RTVFS hVfs;
2092 PRTFSXFSVOL pThis;
2093 int rc = RTVfsNew(&g_rtFsXfsVolOps, sizeof(*pThis), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, (void **)&pThis);
2094 if (RT_SUCCESS(rc))
2095 {
2096 pThis->hVfsBacking = hVfsFileIn;
2097 pThis->hVfsSelf = hVfs;
2098 pThis->fMntFlags = fMntFlags;
2099 pThis->fXfsFlags = fXfsFlags;
2100 pThis->AgRoot = NULL;
2101 pThis->InodeRoot = NULL;
2102 pThis->BlockRoot = NULL;
2103 pThis->cbAgs = 0;
2104 pThis->cbInodes = 0;
2105 pThis->cbBlocks = 0;
2106 RTListInit(&pThis->LstAgLru);
2107 RTListInit(&pThis->LstInodeLru);
2108 RTListInit(&pThis->LstBlockLru);
2109
2110 rc = RTVfsFileGetSize(pThis->hVfsBacking, &pThis->cbBacking);
2111 if (RT_SUCCESS(rc))
2112 {
2113 rc = rtFsXfsVolLoadAndParseSuperblock(pThis, pErrInfo);
2114 if (RT_SUCCESS(rc))
2115 rc = rtFsXfsVolLoadAgi(pThis, pErrInfo);
2116 if (RT_SUCCESS(rc))
2117 {
2118 *phVfs = hVfs;
2119 return VINF_SUCCESS;
2120 }
2121 }
2122
2123 RTVfsRelease(hVfs);
2124 *phVfs = NIL_RTVFS;
2125 }
2126 else
2127 RTVfsFileRelease(hVfsFileIn);
2128
2129 return rc;
2130}
2131
2132
2133/**
2134 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
2135 */
2136static DECLCALLBACK(int) rtVfsChainXfsVol_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
2137 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
2138{
2139 RT_NOREF(pProviderReg);
2140
2141 /*
2142 * Basic checks.
2143 */
2144 if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
2145 return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
2146 if ( pElement->enmType != RTVFSOBJTYPE_VFS
2147 && pElement->enmType != RTVFSOBJTYPE_DIR)
2148 return VERR_VFS_CHAIN_ONLY_DIR_OR_VFS;
2149 if (pElement->cArgs > 1)
2150 return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
2151
2152 /*
2153 * Parse the flag if present, save in pElement->uProvider.
2154 */
2155 bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
2156 if (pElement->cArgs > 0)
2157 {
2158 const char *psz = pElement->paArgs[0].psz;
2159 if (*psz)
2160 {
2161 if (!strcmp(psz, "ro"))
2162 fReadOnly = true;
2163 else if (!strcmp(psz, "rw"))
2164 fReadOnly = false;
2165 else
2166 {
2167 *poffError = pElement->paArgs[0].offSpec;
2168 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
2169 }
2170 }
2171 }
2172
2173 pElement->uProvider = fReadOnly ? RTVFSMNT_F_READ_ONLY : 0;
2174 return VINF_SUCCESS;
2175}
2176
2177
2178/**
2179 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
2180 */
2181static DECLCALLBACK(int) rtVfsChainXfsVol_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
2182 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
2183 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
2184{
2185 RT_NOREF(pProviderReg, pSpec, poffError);
2186
2187 int rc;
2188 RTVFSFILE hVfsFileIn = RTVfsObjToFile(hPrevVfsObj);
2189 if (hVfsFileIn != NIL_RTVFSFILE)
2190 {
2191 RTVFS hVfs;
2192 rc = RTFsXfsVolOpen(hVfsFileIn, (uint32_t)pElement->uProvider, (uint32_t)(pElement->uProvider >> 32), &hVfs, pErrInfo);
2193 RTVfsFileRelease(hVfsFileIn);
2194 if (RT_SUCCESS(rc))
2195 {
2196 *phVfsObj = RTVfsObjFromVfs(hVfs);
2197 RTVfsRelease(hVfs);
2198 if (*phVfsObj != NIL_RTVFSOBJ)
2199 return VINF_SUCCESS;
2200 rc = VERR_VFS_CHAIN_CAST_FAILED;
2201 }
2202 }
2203 else
2204 rc = VERR_VFS_CHAIN_CAST_FAILED;
2205 return rc;
2206}
2207
2208
2209/**
2210 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
2211 */
2212static DECLCALLBACK(bool) rtVfsChainXfsVol_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
2213 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
2214 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
2215{
2216 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
2217 if ( pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider
2218 || !pReuseElement->paArgs[0].uProvider)
2219 return true;
2220 return false;
2221}
2222
2223
2224/** VFS chain element 'xfs'. */
2225static RTVFSCHAINELEMENTREG g_rtVfsChainXfsVolReg =
2226{
2227 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
2228 /* fReserved = */ 0,
2229 /* pszName = */ "xfs",
2230 /* ListEntry = */ { NULL, NULL },
2231 /* pszHelp = */ "Open a XFS file system, requires a file object on the left side.\n"
2232 "First argument is an optional 'ro' (read-only) or 'rw' (read-write) flag.\n",
2233 /* pfnValidate = */ rtVfsChainXfsVol_Validate,
2234 /* pfnInstantiate = */ rtVfsChainXfsVol_Instantiate,
2235 /* pfnCanReuseElement = */ rtVfsChainXfsVol_CanReuseElement,
2236 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
2237};
2238
2239RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainXfsVolReg, rtVfsChainXfsVolReg);
2240
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette