Changeset 76292 in vbox for trunk/src/VBox/Runtime/common/fs
- Timestamp:
- Dec 19, 2018 1:49:08 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fs/extvfs.cpp
r76256 r76292 32 32 #include <iprt/fsvfs.h> 33 33 34 #include <iprt/asm.h> 34 35 #include <iprt/assert.h> 36 #include <iprt/avl.h> 35 37 #include <iprt/file.h> 38 #include <iprt/list.h> 36 39 #include <iprt/log.h> 37 40 #include <iprt/mem.h> … … 43 46 44 47 /********************************************************************************************************************************* 48 * Defined Constants And Macros * 49 *********************************************************************************************************************************/ 50 /** The maximum block group cache size (in bytes). */ 51 #if ARCH_BITS >= 64 52 # define RTFSEXT_MAX_BLOCK_GROUP_CACHE_SIZE _512K 53 #else 54 # define RTFSEXT_MAX_BLOCK_GROUP_CACHE_SIZE _128K 55 #endif 56 /** The maximum inode cache size (in bytes). */ 57 #if ARCH_BITS >= 64 58 # define RTFSEXT_MAX_INODE_CACHE_SIZE _512K 59 #else 60 # define RTFSEXT_MAX_INODE_CACHE_SIZE _128K 61 #endif 62 63 64 /********************************************************************************************************************************* 45 65 * Structures and Typedefs * 46 66 *********************************************************************************************************************************/ 67 /** Pointer to the ext filesystem data. */ 68 typedef struct RTFSEXTVOL *PRTFSEXTVOL; 69 70 47 71 /** 48 72 * Cached block group descriptor data. … … 50 74 typedef struct RTFSEXTBLKGRP 51 75 { 52 /** Start offset (in bytes and from the start of the disk). */ 53 uint64_t offStart; 54 /** Last offset in the block group (inclusive). */ 55 uint64_t offLast; 76 /** AVL tree node, indexed by the block group number. */ 77 AVLU32NODECORE Core; 78 /** List node for the LRU list used for eviction. */ 79 RTLISTNODE NdLru; 80 /** Reference counter. */ 81 volatile uint32_t cRefs; 82 /** Block number where the inode table is store. */ 83 uint64_t iBlockInodeTbl; 84 /** Pointer to the inode bitmap. */ 85 uint8_t *pabInodeBitmap; 56 86 /** Block bitmap - variable in size (depends on the block size 57 87 * and number of blocks per group). */ 58 uint8_t abBlockBitmap[1];88 uint8_t abBlockBitmap[1]; 59 89 } RTFSEXTBLKGRP; 60 90 /** Pointer to block group descriptor data. */ 61 91 typedef RTFSEXTBLKGRP *PRTFSEXTBLKGRP; 92 93 94 /** 95 * In-memory inode. 96 */ 97 typedef struct RTFSEXTINODE 98 { 99 /** AVL tree node, indexed by the inode number. */ 100 AVLU32NODECORE Core; 101 /** List node for the inode LRU list used for eviction. */ 102 RTLISTNODE NdLru; 103 /** Reference counter. */ 104 volatile uint32_t cRefs; 105 /** Block number where the inode is stored. */ 106 uint64_t iBlockInode; 107 /** Offset in bytes into block where the inode is stored. */ 108 uint32_t offInode; 109 /** Inode data size. */ 110 uint64_t cbData; 111 } RTFSEXTINODE; 112 /** Pointer to an in-memory inode. */ 113 typedef RTFSEXTINODE *PRTFSEXTINODE; 114 115 116 /** 117 * Open directory instance. 118 */ 119 typedef struct RTFSEXTDIR 120 { 121 /** Volume this directory belongs to. */ 122 PRTFSEXTVOL pVol; 123 /** Set if we've reached the end of the directory enumeration. */ 124 bool fNoMoreFiles; 125 } RTFSEXTDIR; 126 /** Pointer to an open directory instance. */ 127 typedef RTFSEXTDIR *PRTFSEXTDIR; 128 62 129 63 130 /** … … 72 139 /** The size of the backing thingy. */ 73 140 uint64_t cbBacking; 74 /** The formatted size of the volume. */75 uint64_t cbVolume;76 /** cbVolume expressed as a cluster count. */77 uint64_t cClusters;78 141 79 142 /** RTVFSMNT_F_XXX. */ … … 82 145 uint32_t fExtFlags; 83 146 84 /** The (logical) sector size. */ 85 uint32_t cbSector; 86 87 /** The (logical) cluster size. */ 88 uint32_t cbCluster; 89 90 /** Block number of the superblock. */ 91 uint32_t iSbBlock; 147 /** Flag whether the filesystem is 64bit. */ 148 bool f64Bit; 92 149 /** Size of one block. */ 93 150 size_t cbBlock; 151 /** Number of bits to shift left for fast conversion of block numbers to offsets. */ 152 uint32_t cBlockShift; 94 153 /** Number of blocks in one group. */ 95 unsigned cBlocksPerGroup; 154 uint32_t cBlocksPerGroup; 155 /** Number of inodes in each block group. */ 156 uint32_t cInodesPerGroup; 96 157 /** Number of blocks groups in the volume. */ 97 unsigned cBlockGroups; 98 /** Cached block group descriptor data. */ 99 PRTFSEXTBLKGRP pBlkGrpDesc; 158 uint32_t cBlockGroups; 159 /** Size of the block bitmap. */ 160 size_t cbBlockBitmap; 161 /** Size of the inode bitmap. */ 162 size_t cbInodeBitmap; 163 /** Size of block group descriptor. */ 164 size_t cbBlkGrpDesc; 165 /** Size of an inode. */ 166 size_t cbInode; 167 168 /** @name Block group cache. 169 * @{ */ 170 /** LRU list anchor. */ 171 RTLISTANCHOR LstBlockGroupLru; 172 /** Root of the cached block group tree. */ 173 AVLU32TREE BlockGroupRoot; 174 /** Size of the cached block groups. */ 175 size_t cbBlockGroups; 176 /** @} */ 177 178 /** @name Inode cache. 179 * @{ */ 180 /** LRU list anchor for the inode cache. */ 181 RTLISTANCHOR LstInodeLru; 182 /** Root of the cached inode tree. */ 183 AVLU32TREE InodeRoot; 184 /** Size of the cached inodes. */ 185 size_t cbInodes; 186 /** @} */ 100 187 } RTFSEXTVOL; 101 /** Pointer to the ext filesystem data. */ 102 typedef RTFSEXTVOL *PRTFSEXTVOL; 103 104 105 106 /** 107 * Loads the block descriptor of the given block group from the medium. 188 189 190 191 /********************************************************************************************************************************* 192 * Internal Functions * 193 *********************************************************************************************************************************/ 194 195 #ifdef LOG_ENABLED 196 /** 197 * Logs the ext filesystem superblock. 198 * 199 * @returns nothing. 200 * @param pSb Pointer to the superblock. 201 */ 202 static void rtFsExtSb_Log(PCEXTSUPERBLOCK pSb) 203 { 204 if (LogIs2Enabled()) 205 { 206 RTTIMESPEC Spec; 207 char sz[80]; 208 209 Log2(("EXT: Superblock:\n")); 210 Log2(("EXT: cInodesTotal %RU32\n", RT_LE2H_U32(pSb->cInodesTotal))); 211 Log2(("EXT: cBlocksTotalLow %RU32\n", RT_LE2H_U32(pSb->cBlocksTotalLow))); 212 Log2(("EXT: cBlocksRsvdForSuperUserLow %RU32\n", RT_LE2H_U32(pSb->cBlocksRsvdForSuperUserLow))); 213 Log2(("EXT: cBlocksFreeLow %RU32\n", RT_LE2H_U32(pSb->cBlocksFreeLow))); 214 Log2(("EXT: cInodesFree %RU32\n", RT_LE2H_U32(pSb->cInodesFree))); 215 Log2(("EXT: iBlockOfSuperblock %RU32\n", RT_LE2H_U32(pSb->iBlockOfSuperblock))); 216 Log2(("EXT: cLogBlockSize %RU32\n", RT_LE2H_U32(pSb->cLogBlockSize))); 217 Log2(("EXT: cLogClusterSize %RU32\n", RT_LE2H_U32(pSb->cLogClusterSize))); 218 Log2(("EXT: cBlocksPerGroup %RU32\n", RT_LE2H_U32(pSb->cBlocksPerGroup))); 219 Log2(("EXT: cClustersPerBlockGroup %RU32\n", RT_LE2H_U32(pSb->cClustersPerBlockGroup))); 220 Log2(("EXT: cInodesPerBlockGroup %RU32\n", RT_LE2H_U32(pSb->cInodesPerBlockGroup))); 221 Log2(("EXT: u32LastMountTime %#RX32 %s\n", RT_LE2H_U32(pSb->u32LastMountTime), 222 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pSb->u32LastMountTime)), sz, sizeof(sz)))); 223 Log2(("EXT: u32LastWrittenTime %#RX32 %s\n", RT_LE2H_U32(pSb->u32LastWrittenTime), 224 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pSb->u32LastWrittenTime)), sz, sizeof(sz)))); 225 Log2(("EXT: cMountsSinceLastCheck %RU16\n", RT_LE2H_U32(pSb->cMountsSinceLastCheck))); 226 Log2(("EXT: cMaxMountsUntilCheck %RU16\n", RT_LE2H_U32(pSb->cMaxMountsUntilCheck))); 227 Log2(("EXT: u16Signature %#RX16\n", RT_LE2H_U32(pSb->u16Signature))); 228 Log2(("EXT: u16FilesystemState %#RX16\n", RT_LE2H_U32(pSb->u16FilesystemState))); 229 Log2(("EXT: u16ActionOnError %#RX16\n", RT_LE2H_U32(pSb->u16ActionOnError))); 230 Log2(("EXT: u16RevLvlMinor %#RX16\n", RT_LE2H_U32(pSb->u16RevLvlMinor))); 231 Log2(("EXT: u32LastCheckTime %#RX32 %s\n", RT_LE2H_U32(pSb->u32LastCheckTime), 232 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pSb->u32LastCheckTime)), sz, sizeof(sz)))); 233 Log2(("EXT: u32CheckInterval %RU32\n", RT_LE2H_U32(pSb->u32CheckInterval))); 234 Log2(("EXT: u32OsIdCreator %#RX32\n", RT_LE2H_U32(pSb->u32OsIdCreator))); 235 Log2(("EXT: u32RevLvl %#RX32\n", RT_LE2H_U32(pSb->u32RevLvl))); 236 Log2(("EXT: u16UidReservedBlocks %#RX16\n", RT_LE2H_U32(pSb->u16UidReservedBlocks))); 237 Log2(("EXT: u16GidReservedBlocks %#RX16\n", RT_LE2H_U32(pSb->u16GidReservedBlocks))); 238 if (RT_LE2H_U32(pSb->u32RevLvl) == EXT_SB_REV_V2_DYN_INODE_SZ) 239 { 240 Log2(("EXT: iFirstInodeNonRsvd %#RX32\n", RT_LE2H_U32(pSb->iFirstInodeNonRsvd))); 241 Log2(("EXT: cbInode %#RX16\n", RT_LE2H_U32(pSb->cbInode))); 242 Log2(("EXT: iBlkGrpSb %#RX16\n", RT_LE2H_U32(pSb->iBlkGrpSb))); 243 Log2(("EXT: fFeaturesCompat %#RX32%s%s%s%s%s%s%s%s%s%s\n", RT_LE2H_U32(pSb->fFeaturesCompat), 244 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_DIR_PREALLOC ? " dir-prealloc" : "", 245 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_IMAGIC_INODES ? " imagic-inode" : "", 246 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_HAS_JOURNAL ? " has-journal" : "", 247 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_EXT_ATTR ? " ext-attrs" : "", 248 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_RESIZE_INODE ? " resize-inode" : "", 249 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_DIR_INDEX ? " dir-index" : "", 250 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_LAZY_BG ? " lazy-bg" : "", 251 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_EXCLUDE_INODE ? " excl-inode" : "", 252 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_EXCLUDE_BITMAP ? " excl-bitmap" : "", 253 RT_LE2H_U32(pSb->fFeaturesCompat) & EXT_SB_FEAT_COMPAT_SPARSE_SUPER2 ? " sparse-super2" : "")); 254 Log2(("EXT: fFeaturesIncompat %#RX32%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", RT_LE2H_U32(pSb->fFeaturesIncompat), 255 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_COMPRESSION ? " compression" : "", 256 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_DIR_FILETYPE ? " dir-filetype" : "", 257 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_RECOVER ? " recovery" : "", 258 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_JOURNAL_DEV ? " journal-dev" : "", 259 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_META_BG ? " meta-bg" : "", 260 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_EXTENTS ? " extents" : "", 261 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_64BIT ? " 64bit" : "", 262 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_MMP ? " mmp" : "", 263 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_FLEX_BG ? " flex-bg" : "", 264 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_EXT_ATTR_INODE ? " extattr-inode" : "", 265 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_DIRDATA ? " dir-data" : "", 266 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_CSUM_SEED ? " csum-seed" : "", 267 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_LARGE_DIR ? " large-dir" : "", 268 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_INLINE_DATA ? " inline-data" : "", 269 RT_LE2H_U32(pSb->fFeaturesIncompat) & EXT_SB_FEAT_INCOMPAT_ENCRYPT ? " encrypt" : "")); 270 Log2(("EXT: fFeaturesCompatRo %#RX32%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", RT_LE2H_U32(pSb->fFeaturesCompatRo), 271 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_SPARSE_SUPER ? " sparse-super" : "", 272 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_LARGE_FILE ? " large-file" : "", 273 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_BTREE_DIR ? " btree-dir" : "", 274 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_HUGE_FILE ? " huge-file" : "", 275 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_GDT_CHSKUM ? " gdt-chksum" : "", 276 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_DIR_NLINK ? " dir-nlink" : "", 277 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_EXTRA_INODE_SZ ? " extra-inode" : "", 278 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_HAS_SNAPSHOTS ? " snapshots" : "", 279 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_QUOTA ? " quota" : "", 280 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_BIGALLOC ? " big-alloc" : "", 281 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_METADATA_CHKSUM ? " meta-chksum" : "", 282 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_REPLICA ? " replica" : "", 283 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_READONLY ? " ro" : "", 284 RT_LE2H_U32(pSb->fFeaturesCompatRo) & EXT_SB_FEAT_COMPAT_RO_PROJECT ? " project" : "")); 285 Log2(("EXT: au8Uuid <todo>\n")); 286 Log2(("EXT: achVolumeName %16s\n", &pSb->achVolumeName[0])); 287 Log2(("EXT: achLastMounted %64s\n", &pSb->achLastMounted[0])); 288 Log2(("EXT: u32AlgoUsageBitmap %#RX32\n", RT_LE2H_U32(pSb->u32AlgoUsageBitmap))); 289 Log2(("EXT: cBlocksPrealloc %RU8\n", pSb->cBlocksPrealloc)); 290 Log2(("EXT: cBlocksPreallocDirectory %RU8\n", pSb->cBlocksPreallocDirectory)); 291 Log2(("EXT: cGdtEntriesRsvd %RU16\n", pSb->cGdtEntriesRsvd)); 292 Log2(("EXT: au8JournalUuid <todo>\n")); 293 Log2(("EXT: iJournalInode %#RX32\n", RT_LE2H_U32(pSb->iJournalInode))); 294 Log2(("EXT: u32JournalDev %#RX32\n", RT_LE2H_U32(pSb->u32JournalDev))); 295 Log2(("EXT: u32LastOrphan %#RX32\n", RT_LE2H_U32(pSb->u32LastOrphan))); 296 Log2(("EXT: au32HashSeedHtree[0] %#RX32\n", RT_LE2H_U32(pSb->au32HashSeedHtree[0]))); 297 Log2(("EXT: au32HashSeedHtree[1] %#RX32\n", RT_LE2H_U32(pSb->au32HashSeedHtree[1]))); 298 Log2(("EXT: au32HashSeedHtree[2] %#RX32\n", RT_LE2H_U32(pSb->au32HashSeedHtree[2]))); 299 Log2(("EXT: au32HashSeedHtree[3] %#RX32\n", RT_LE2H_U32(pSb->au32HashSeedHtree[3]))); 300 Log2(("EXT: u8HashVersionDef %#RX8\n", pSb->u8HashVersionDef)); 301 Log2(("EXT: u8JnlBackupType %#RX8\n", pSb->u8JnlBackupType)); 302 Log2(("EXT: cbGroupDesc %RU16\n", RT_LE2H_U16(pSb->cbGroupDesc))); 303 Log2(("EXT: fMntOptsDef %#RX32\n", RT_LE2H_U32(pSb->fMntOptsDef))); 304 Log2(("EXT: iFirstMetaBg %#RX32\n", RT_LE2H_U32(pSb->iFirstMetaBg))); 305 Log2(("EXT: u32TimeFsCreation %#RX32 %s\n", RT_LE2H_U32(pSb->u32TimeFsCreation), 306 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pSb->u32TimeFsCreation)), sz, sizeof(sz)))); 307 for (unsigned i = 0; i < RT_ELEMENTS(pSb->au32JnlBlocks); i++) 308 Log2(("EXT: au32JnlBlocks[%u] %#RX32\n", i, RT_LE2H_U32(pSb->au32JnlBlocks[i]))); 309 Log2(("EXT: cBlocksTotalHigh %#RX32\n", RT_LE2H_U32(pSb->cBlocksTotalHigh))); 310 Log2(("EXT: cBlocksRsvdForSuperUserHigh %#RX32\n", RT_LE2H_U32(pSb->cBlocksRsvdForSuperUserHigh))); 311 Log2(("EXT: cBlocksFreeHigh %#RX32\n", RT_LE2H_U32(pSb->cBlocksFreeHigh))); 312 Log2(("EXT: cbInodesExtraMin %#RX16\n", RT_LE2H_U16(pSb->cbInodesExtraMin))); 313 Log2(("EXT: cbNewInodesRsv %#RX16\n", RT_LE2H_U16(pSb->cbInodesExtraMin))); 314 Log2(("EXT: fFlags %#RX32\n", RT_LE2H_U32(pSb->fFlags))); 315 Log2(("EXT: cRaidStride %RU16\n", RT_LE2H_U16(pSb->cRaidStride))); 316 Log2(("EXT: cSecMmpInterval %RU16\n", RT_LE2H_U16(pSb->cSecMmpInterval))); 317 Log2(("EXT: iMmpBlock %#RX64\n", RT_LE2H_U64(pSb->iMmpBlock))); 318 Log2(("EXT: cRaidStrideWidth %#RX32\n", RT_LE2H_U32(pSb->cRaidStrideWidth))); 319 Log2(("EXT: cLogGroupsPerFlex %RU8\n", pSb->cLogGroupsPerFlex)); 320 Log2(("EXT: u8ChksumType %RX8\n", pSb->u8ChksumType)); 321 Log2(("EXT: cKbWritten %#RX64\n", RT_LE2H_U64(pSb->cKbWritten))); 322 Log2(("EXT: iSnapshotInode %#RX32\n", RT_LE2H_U32(pSb->iSnapshotInode))); 323 Log2(("EXT: iSnapshotId %#RX32\n", RT_LE2H_U32(pSb->iSnapshotId))); 324 Log2(("EXT: cSnapshotRsvdBlocks %#RX64\n", RT_LE2H_U64(pSb->cSnapshotRsvdBlocks))); 325 Log2(("EXT: iSnapshotListInode %#RX32\n", RT_LE2H_U32(pSb->iSnapshotListInode))); 326 Log2(("EXT: cErrorsSeen %#RX32\n", RT_LE2H_U32(pSb->cErrorsSeen))); 327 Log2(("EXT: [...]\n")); /** @todo: Missing fields if becoming interesting. */ 328 Log2(("EXT: iInodeLostFound %#RX32\n", RT_LE2H_U32(pSb->iInodeLostFound))); 329 Log2(("EXT: iInodeProjQuota %#RX32\n", RT_LE2H_U32(pSb->iInodeProjQuota))); 330 Log2(("EXT: u32ChksumSeed %#RX32\n", RT_LE2H_U32(pSb->u32ChksumSeed))); 331 Log2(("EXT: [...]\n")); /** @todo: Missing fields if becoming interesting. */ 332 Log2(("EXT: u32Chksum %#RX32\n", RT_LE2H_U32(pSb->u32Chksum))); 333 } 334 } 335 } 336 337 338 /** 339 * Logs a ext filesystem block group descriptor. 340 * 341 * @returns nothing. 342 * @param pThis The ext volume instance. 343 * @param iBlockGroup Block group number. 344 * @param pBlockGroup Pointer to the block group. 345 */ 346 static void rtFsExtBlockGroup_Log(PRTFSEXTVOL pThis, uint32_t iBlockGroup, PCEXTBLOCKGROUPDESC pBlockGroup) 347 { 348 if (LogIs2Enabled()) 349 { 350 uint64_t iBlockStart = (uint64_t)iBlockGroup * pThis->cBlocksPerGroup; 351 Log2(("EXT: Block group %#RX32 (blocks %#RX64 to %#RX64):\n", 352 iBlockGroup, iBlockStart, iBlockStart + pThis->cBlocksPerGroup - 1)); 353 Log2(("EXT: offBlockBitmapLow %#RX32\n", RT_LE2H_U32(pBlockGroup->v32.offBlockBitmapLow))); 354 Log2(("EXT: offInodeBitmapLow %#RX32\n", RT_LE2H_U32(pBlockGroup->v32.offInodeBitmapLow))); 355 Log2(("EXT: offInodeTableLow %#RX32\n", RT_LE2H_U32(pBlockGroup->v32.offInodeTableLow))); 356 Log2(("EXT: cBlocksFreeLow %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.cBlocksFreeLow))); 357 Log2(("EXT: cInodesFreeLow %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.cInodesFreeLow))); 358 Log2(("EXT: cDirectoriesLow %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.cDirectoriesLow))); 359 Log2(("EXT: fFlags %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.fFlags))); 360 Log2(("EXT: offSnapshotExclBitmapLow %#RX32\n", RT_LE2H_U32(pBlockGroup->v32.offSnapshotExclBitmapLow))); 361 Log2(("EXT: u16ChksumBlockBitmapLow %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.u16ChksumBlockBitmapLow))); 362 Log2(("EXT: u16ChksumInodeBitmapLow %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.u16ChksumInodeBitmapLow))); 363 Log2(("EXT: cInodeTblUnusedLow %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.cInodeTblUnusedLow))); 364 Log2(("EXT: u16Chksum %#RX16\n", RT_LE2H_U16(pBlockGroup->v32.u16Chksum))); 365 if (pThis->cbBlkGrpDesc == sizeof(EXTBLOCKGROUPDESC64)) 366 { 367 Log2(("EXT: offBlockBitmapHigh %#RX32\n", RT_LE2H_U32(pBlockGroup->v64.offBlockBitmapHigh))); 368 Log2(("EXT: offInodeBitmapHigh %#RX32\n", RT_LE2H_U32(pBlockGroup->v64.offInodeBitmapHigh))); 369 Log2(("EXT: offInodeTableHigh %#RX32\n", RT_LE2H_U32(pBlockGroup->v64.offInodeTableHigh))); 370 Log2(("EXT: cBlocksFreeHigh %#RX16\n", RT_LE2H_U16(pBlockGroup->v64.cBlocksFreeHigh))); 371 Log2(("EXT: cInodesFreeHigh %#RX16\n", RT_LE2H_U16(pBlockGroup->v64.cInodesFreeHigh))); 372 Log2(("EXT: cDirectoriesHigh %#RX16\n", RT_LE2H_U16(pBlockGroup->v64.cDirectoriesHigh))); 373 Log2(("EXT: cInodeTblUnusedHigh %#RX16\n", RT_LE2H_U16(pBlockGroup->v64.cInodeTblUnusedHigh))); 374 Log2(("EXT: offSnapshotExclBitmapHigh %#RX32\n", RT_LE2H_U32(pBlockGroup->v64.offSnapshotExclBitmapHigh))); 375 Log2(("EXT: u16ChksumBlockBitmapHigh %#RX16\n", RT_LE2H_U16(pBlockGroup->v64.u16ChksumBlockBitmapHigh))); 376 Log2(("EXT: u16ChksumInodeBitmapHigh %#RX16\n", RT_LE2H_U16(pBlockGroup->v64.u16ChksumInodeBitmapHigh))); 377 } 378 } 379 } 380 381 382 /** 383 * Logs a ext filesystem inode. 384 * 385 * @returns nothing. 386 * @param pThis The ext volume instance. 387 * @param iInode Inode number. 388 * @param pInode Pointer to the inode. 389 */ 390 static void rtFsExtInode_Log(PRTFSEXTVOL pThis, uint32_t iInode, PCEXTINODECOMB pInode) 391 { 392 if (LogIs2Enabled()) 393 { 394 RTTIMESPEC Spec; 395 char sz[80]; 396 397 Log2(("EXT: Inode %#RX32:\n", iInode)); 398 Log2(("EXT: fMode %#RX16\n", RT_LE2H_U16(pInode->Core.fMode))); 399 Log2(("EXT: uUidLow %#RX16\n", RT_LE2H_U16(pInode->Core.uUidLow))); 400 Log2(("EXT: cbSizeLow %#RX32\n", RT_LE2H_U32(pInode->Core.cbSizeLow))); 401 Log2(("EXT: u32TimeLastAccess %#RX32 %s\n", RT_LE2H_U32(pInode->Core.u32TimeLastAccess), 402 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pInode->Core.u32TimeLastAccess)), sz, sizeof(sz)))); 403 Log2(("EXT: u32TimeLastChange %#RX32 %s\n", RT_LE2H_U32(pInode->Core.u32TimeLastChange), 404 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pInode->Core.u32TimeLastChange)), sz, sizeof(sz)))); 405 Log2(("EXT: u32TimeLastModification %#RX32 %s\n", RT_LE2H_U32(pInode->Core.u32TimeLastModification), 406 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pInode->Core.u32TimeLastModification)), sz, sizeof(sz)))); 407 Log2(("EXT: u32TimeDeletion %#RX32 %s\n", RT_LE2H_U32(pInode->Core.u32TimeDeletion), 408 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pInode->Core.u32TimeDeletion)), sz, sizeof(sz)))); 409 Log2(("EXT: uGidLow %#RX16\n", RT_LE2H_U16(pInode->Core.uGidLow))); 410 Log2(("EXT: cHardLinks %#RU16\n", RT_LE2H_U16(pInode->Core.cHardLinks))); 411 Log2(("EXT: cBlocksLow %#RX32\n", RT_LE2H_U32(pInode->Core.cBlocksLow))); 412 Log2(("EXT: fFlags %#RX32\n", RT_LE2H_U32(pInode->Core.fFlags))); 413 Log2(("EXT: Osd1.u32LnxVersion %#RX32\n", RT_LE2H_U32(pInode->Core.Osd1.u32LnxVersion))); 414 for (unsigned i = 0; i < RT_ELEMENTS(pInode->Core.au32Block); i++) 415 Log2(("EXT: au32Block[%u] %#RX32\n", i, RT_LE2H_U32(pInode->Core.au32Block[i]))); 416 Log2(("EXT: u32Version %#RX32\n", RT_LE2H_U32(pInode->Core.u32Version))); 417 Log2(("EXT: offExtAttrLow %#RX32\n", RT_LE2H_U32(pInode->Core.offExtAttrLow))); 418 Log2(("EXT: cbSizeHigh %#RX32\n", RT_LE2H_U32(pInode->Core.cbSizeHigh))); 419 Log2(("EXT: u32FragmentAddrObs %#RX32\n", RT_LE2H_U32(pInode->Core.u32FragmentAddrObs))); 420 Log2(("EXT: Osd2.Lnx.cBlocksHigh %#RX32\n", RT_LE2H_U32(pInode->Core.Osd2.Lnx.cBlocksHigh))); 421 Log2(("EXT: Osd2.Lnx.offExtAttrHigh %#RX32\n", RT_LE2H_U32(pInode->Core.Osd2.Lnx.offExtAttrHigh))); 422 Log2(("EXT: Osd2.Lnx.uUidHigh %#RX16\n", RT_LE2H_U16(pInode->Core.Osd2.Lnx.uUidHigh))); 423 Log2(("EXT: Osd2.Lnx.uGidHigh %#RX16\n", RT_LE2H_U16(pInode->Core.Osd2.Lnx.uGidHigh))); 424 Log2(("EXT: Osd2.Lnx.u16ChksumLow %#RX16\n", RT_LE2H_U16(pInode->Core.Osd2.Lnx.u16ChksumLow))); 425 426 if (pThis->cbInode >= sizeof(EXTINODECOMB)) 427 { 428 Log2(("EXT: cbInodeExtra %#RU16\n", RT_LE2H_U16(pInode->Extra.cbInodeExtra))); 429 Log2(("EXT: u16ChksumHigh %#RX16\n", RT_LE2H_U16(pInode->Extra.u16ChksumHigh))); 430 Log2(("EXT: u32ExtraTimeLastChange %#RX32\n", RT_LE2H_U16(pInode->Extra.u32ExtraTimeLastChange))); 431 Log2(("EXT: u32ExtraTimeLastModification %#RX32\n", RT_LE2H_U16(pInode->Extra.u32ExtraTimeLastModification))); 432 Log2(("EXT: u32ExtraTimeLastAccess %#RX32\n", RT_LE2H_U16(pInode->Extra.u32ExtraTimeLastAccess))); 433 Log2(("EXT: u32TimeCreation %#RX32 %s\n", RT_LE2H_U32(pInode->Extra.u32TimeCreation), 434 RTTimeSpecToString(RTTimeSpecSetSeconds(&Spec, RT_LE2H_U32(pInode->Extra.u32TimeCreation)), sz, sizeof(sz)))); 435 Log2(("EXT: u32ExtraTimeCreation %#RX32\n", RT_LE2H_U16(pInode->Extra.u32ExtraTimeCreation))); 436 Log2(("EXT: u32VersionHigh %#RX32\n", RT_LE2H_U16(pInode->Extra.u32VersionHigh))); 437 Log2(("EXT: u32ProjectId %#RX32\n", RT_LE2H_U16(pInode->Extra.u32ProjectId))); 438 } 439 } 440 } 441 #endif 442 443 444 /** 445 * Converts a block number to a byte offset. 446 * 447 * @returns Offset in bytes for the given block number. 448 * @param pThis The ext volume instance. 449 * @param iBlock The block number to convert. 450 */ 451 DECLINLINE(uint64_t) rtFsExtBlockIdxToDiskOffset(PRTFSEXTVOL pThis, uint64_t iBlock) 452 { 453 return iBlock << pThis->cBlockShift; 454 } 455 456 457 /** 458 * Converts a byte offset to a block number. 459 * 460 * @returns Block number. 461 * @param pThis The ext volume instance. 462 * @param iBlock The offset to convert. 463 */ 464 DECLINLINE(uint64_t) rtFsExtDiskOffsetToBlockIdx(PRTFSEXTVOL pThis, uint64_t off) 465 { 466 return off >> pThis->cBlockShift; 467 } 468 469 470 /** 471 * Creates the proper block number from the given low and high parts in case a 64bit 472 * filesystem is used. 473 * 474 * @returns 64bit block number. 475 * @param pThis The ext volume instance. 476 * @param uLow The lower 32bit part. 477 * @param uHigh The upper 32bit part. 478 */ 479 DECLINLINE(uint64_t) rtFsExtBlockFromLowHigh(PRTFSEXTVOL pThis, uint32_t uLow, uint32_t uHigh) 480 { 481 return pThis->f64Bit ? RT_MAKE_U64(uLow, uHigh): uLow; 482 } 483 484 485 /** 486 * Converts the given high and low parts of the block number to a byte offset. 487 * 488 * @returns Offset in bytes for the given block number. 489 * @param uLow The lower 32bit part of the block number. 490 * @param uHigh The upper 32bit part of the block number. 491 */ 492 DECLINLINE(uint64_t) rtFsExtBlockIdxLowHighToDiskOffset(PRTFSEXTVOL pThis, uint32_t uLow, uint32_t uHigh) 493 { 494 uint64_t iBlock = rtFsExtBlockFromLowHigh(pThis, uLow, uHigh); 495 return rtFsExtBlockIdxToDiskOffset(pThis, iBlock); 496 } 497 498 499 /** 500 * Allocates a new block group. 501 * 502 * @returns Pointer to the new block group descriptor or NULL if out of memory. 503 * @param pThis The ext volume instance. 504 * @param cbAlloc How much to allocate. 505 * @param iBlockGroup Block group number. 506 */ 507 static PRTFSEXTBLKGRP rtFsExtBlockGroupAlloc(PRTFSEXTVOL pThis, size_t cbAlloc, uint32_t iBlockGroup) 508 { 509 PRTFSEXTBLKGRP pBlockGroup = (PRTFSEXTBLKGRP)RTMemAllocZ(cbAlloc); 510 if (RT_LIKELY(pBlockGroup)) 511 { 512 pBlockGroup->Core.Key = iBlockGroup; 513 pBlockGroup->cRefs = 0; 514 pBlockGroup->pabInodeBitmap = &pBlockGroup->abBlockBitmap[pThis->cbBlockBitmap]; 515 pThis->cbBlockGroups += cbAlloc; 516 } 517 518 return pBlockGroup; 519 } 520 521 522 /** 523 * Frees the given block group. 524 * 525 * @returns nothing. 526 * @param pThis The ext volume instance. 527 * @param pBlockGroup The block group to free. 528 */ 529 static void rtFsExtBlockGroupFree(PRTFSEXTVOL pThis, PRTFSEXTBLKGRP pBlockGroup) 530 { 531 Assert(!pBlockGroup->cRefs); 532 533 /* 534 * Put it into the cache if the limit wasn't exceeded, otherwise the block group 535 * is freed right away. 536 */ 537 if (pThis->cbBlockGroups <= RTFSEXT_MAX_BLOCK_GROUP_CACHE_SIZE) 538 { 539 /* Put onto the LRU list. */ 540 RTListPrepend(&pThis->LstBlockGroupLru, &pBlockGroup->NdLru); 541 } 542 else 543 { 544 /* Remove from the tree and free memory. */ 545 PAVLU32NODECORE pCore = RTAvlU32Remove(&pThis->BlockGroupRoot, pBlockGroup->Core.Key); 546 Assert(pCore == &pBlockGroup->Core); RT_NOREF(pCore); 547 RTMemFree(pBlockGroup); 548 pThis->cbBlockGroups -= sizeof(RTFSEXTBLKGRP) + pThis->cbBlockBitmap + pThis->cbInodeBitmap; 549 } 550 } 551 552 553 /** 554 * Returns a new block group utilizing the cache if possible. 555 * 556 * @returns Pointer to the new block group descriptor or NULL if out of memory. 557 * @param pThis The ext volume instance. 558 * @param iBlockGroup Block group number. 559 */ 560 static PRTFSEXTBLKGRP rtFsExtBlockGroupGetNew(PRTFSEXTVOL pThis, uint32_t iBlockGroup) 561 { 562 PRTFSEXTBLKGRP pBlockGroup = NULL; 563 size_t cbAlloc = sizeof(RTFSEXTBLKGRP) + pThis->cbBlockBitmap + pThis->cbInodeBitmap; 564 if (pThis->cbBlockGroups + cbAlloc <= RTFSEXT_MAX_BLOCK_GROUP_CACHE_SIZE) 565 pBlockGroup = rtFsExtBlockGroupAlloc(pThis, cbAlloc, iBlockGroup); 566 else 567 { 568 pBlockGroup = RTListRemoveLast(&pThis->LstBlockGroupLru, RTFSEXTBLKGRP, NdLru); 569 if (!pBlockGroup) 570 pBlockGroup = rtFsExtBlockGroupAlloc(pThis, cbAlloc, iBlockGroup); 571 else 572 { 573 /* Remove the block group from the tree because it gets a new key. */ 574 PAVLU32NODECORE pCore = RTAvlU32Remove(&pThis->BlockGroupRoot, pBlockGroup->Core.Key); 575 Assert(pCore == &pBlockGroup->Core); RT_NOREF(pCore); 576 } 577 } 578 579 Assert(!pBlockGroup->cRefs); 580 pBlockGroup->Core.Key = iBlockGroup; 581 pBlockGroup->cRefs = 1; 582 583 return pBlockGroup; 584 } 585 586 587 /** 588 * Loads the given block group number and returns it on success. 108 589 * 109 590 * @returns IPRT status code. 110 * @param pThis EXT filesystem instance data. 111 * @param iBlkGrp Block group number to load. 112 */ 113 static int rtFsExtLoadBlkGrpDesc(PRTFSEXTVOL pThis, uint32_t iBlkGrp) 114 { 115 size_t cbBlockBitmap = pThis->cBlocksPerGroup / 8; 116 if (pThis->cBlocksPerGroup % 8) 117 cbBlockBitmap++; 118 119 PRTFSEXTBLKGRP pBlkGrpDesc = pThis->pBlkGrpDesc; 120 if (!pBlkGrpDesc) 121 { 122 size_t cbBlkDesc = RT_UOFFSETOF_DYN(RTFSEXTBLKGRP, abBlockBitmap[cbBlockBitmap]); 123 pBlkGrpDesc = (PRTFSEXTBLKGRP)RTMemAllocZ(cbBlkDesc); 124 if (!pBlkGrpDesc) 125 return VERR_NO_MEMORY; 126 } 127 128 uint64_t offRead = (pThis->iSbBlock + 1) * pThis->cbBlock; 129 EXTBLOCKGROUPDESC32 BlkDesc; 130 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &BlkDesc, sizeof(BlkDesc), NULL); 591 * @param pThis The ext volume instance. 592 * @param iBlockGroup The block group to load. 593 * @param ppBlockGroup Where to store the block group on success. 594 */ 595 static int rtFsExtBlockGroupLoad(PRTFSEXTVOL pThis, uint32_t iBlockGroup, PRTFSEXTBLKGRP *ppBlockGroup) 596 { 597 int rc = VINF_SUCCESS; 598 599 /* Try to fetch the block group from the cache first. */ 600 PRTFSEXTBLKGRP pBlockGroup = (PRTFSEXTBLKGRP)RTAvlU32Get(&pThis->BlockGroupRoot, iBlockGroup); 601 if (!pBlockGroup) 602 { 603 /* Slow path, load from disk. */ 604 pBlockGroup = rtFsExtBlockGroupGetNew(pThis, iBlockGroup); 605 if (RT_LIKELY(pBlockGroup)) 606 { 607 uint64_t offRead = rtFsExtBlockIdxToDiskOffset(pThis, pThis->cbBlock == _1K ? 2 : 1) 608 + (uint64_t)iBlockGroup * pThis->cbBlkGrpDesc; 609 EXTBLOCKGROUPDESC BlockGroupDesc; 610 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &BlockGroupDesc, pThis->cbBlkGrpDesc, NULL); 611 if (RT_SUCCESS(rc)) 612 { 613 #ifdef LOG_ENABLED 614 rtFsExtBlockGroup_Log(pThis, iBlockGroup, &BlockGroupDesc); 615 #endif 616 pBlockGroup->iBlockInodeTbl = RT_LE2H_U32(BlockGroupDesc.v32.offInodeTableLow) 617 | ((pThis->cbBlkGrpDesc == sizeof(EXTBLOCKGROUPDESC64)) 618 ? (uint64_t)RT_LE2H_U32(BlockGroupDesc.v64.offInodeTableHigh) << 32 619 : 0); 620 621 offRead = rtFsExtBlockIdxLowHighToDiskOffset(pThis, RT_LE2H_U32(BlockGroupDesc.v32.offBlockBitmapLow), 622 RT_LE2H_U32(BlockGroupDesc.v64.offBlockBitmapHigh)); 623 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &pBlockGroup->abBlockBitmap[0], pThis->cbBlockBitmap, NULL); 624 if (RT_SUCCESS(rc)) 625 { 626 offRead = rtFsExtBlockIdxLowHighToDiskOffset(pThis, RT_LE2H_U32(BlockGroupDesc.v32.offInodeBitmapLow), 627 RT_LE2H_U32(BlockGroupDesc.v64.offInodeBitmapHigh)); 628 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &pBlockGroup->pabInodeBitmap[0], pThis->cbInodeBitmap, NULL); 629 if (RT_SUCCESS(rc)) 630 { 631 bool fIns = RTAvlU32Insert(&pThis->BlockGroupRoot, &pBlockGroup->Core); 632 Assert(fIns); RT_NOREF(fIns); 633 } 634 } 635 } 636 } 637 else 638 rc = VERR_NO_MEMORY; 639 } 640 else 641 { 642 /* Remove from current LRU list position and add to the beginning. */ 643 uint32_t cRefs = ASMAtomicIncU32(&pBlockGroup->cRefs); 644 if (cRefs == 1) /* Block groups get removed from the LRU list if they are referenced. */ 645 RTListNodeRemove(&pBlockGroup->NdLru); 646 } 647 131 648 if (RT_SUCCESS(rc)) 132 { 133 pBlkGrpDesc->offStart = pThis->iSbBlock + (uint64_t)iBlkGrp * pThis->cBlocksPerGroup * pThis->cbBlock; 134 pBlkGrpDesc->offLast = pBlkGrpDesc->offStart + pThis->cBlocksPerGroup * pThis->cbBlock; 135 rc = RTVfsFileReadAt(pThis->hVfsBacking, BlkDesc.offBlockBitmapLow * pThis->cbBlock, 136 &pBlkGrpDesc->abBlockBitmap[0], cbBlockBitmap, NULL); 137 } 138 139 pThis->pBlkGrpDesc = pBlkGrpDesc; 649 *ppBlockGroup = pBlockGroup; 650 else if (pBlockGroup) 651 { 652 ASMAtomicDecU32(&pBlockGroup->cRefs); 653 rtFsExtBlockGroupFree(pThis, pBlockGroup); /* Free the block group. */ 654 } 655 140 656 return rc; 141 657 } 142 658 143 659 144 static bool rtFsExtIsBlockRangeInUse(PRTFSEXTBLKGRP pBlkGrpDesc, uint32_t offBlockStart, size_t cBlocks) 145 { 660 /** 661 * Releases a reference of the given block group. 662 * 663 * @returns nothing. 664 * @param pThis The ext volume instance. 665 * @param pBlockGroup The block group to release. 666 */ 667 static void rtFsExtBlockGroupRelease(PRTFSEXTVOL pThis, PRTFSEXTBLKGRP pBlockGroup) 668 { 669 uint32_t cRefs = ASMAtomicDecU32(&pBlockGroup->cRefs); 670 if (!cRefs) 671 rtFsExtBlockGroupFree(pThis, pBlockGroup); 672 } 673 674 675 /** 676 * Allocates a new inode. 677 * 678 * @returns Pointer to the new inode or NULL if out of memory. 679 * @param pThis The ext volume instance. 680 * @param iInode Inode number. 681 */ 682 static PRTFSEXTINODE rtFsExtInodeAlloc(PRTFSEXTVOL pThis, uint32_t iInode) 683 { 684 PRTFSEXTINODE pInode = (PRTFSEXTINODE)RTMemAllocZ(sizeof(RTFSEXTINODE)); 685 if (RT_LIKELY(pInode)) 686 { 687 pInode->Core.Key = iInode; 688 pInode->cRefs = 0; 689 pThis->cbInodes += sizeof(RTFSEXTINODE); 690 } 691 692 return pInode; 693 } 694 695 696 /** 697 * Frees the given inode. 698 * 699 * @returns nothing. 700 * @param pThis The ext volume instance. 701 * @param pInode The inode to free. 702 */ 703 static void rtFsExtInodeFree(PRTFSEXTVOL pThis, PRTFSEXTINODE pInode) 704 { 705 Assert(!pInode->cRefs); 706 707 /* 708 * Put it into the cache if the limit wasn't exceeded, otherwise the inode 709 * is freed right away. 710 */ 711 if (pThis->cbInodes <= RTFSEXT_MAX_INODE_CACHE_SIZE) 712 { 713 /* Put onto the LRU list. */ 714 RTListPrepend(&pThis->LstInodeLru, &pInode->NdLru); 715 } 716 else 717 { 718 /* Remove from the tree and free memory. */ 719 PAVLU32NODECORE pCore = RTAvlU32Remove(&pThis->InodeRoot, pInode->Core.Key); 720 Assert(pCore == &pInode->Core); RT_NOREF(pCore); 721 RTMemFree(pInode); 722 pThis->cbInodes -= sizeof(RTFSEXTINODE); 723 } 724 } 725 726 727 /** 728 * Returns a new inodep utilizing the cache if possible. 729 * 730 * @returns Pointer to the new inode or NULL if out of memory. 731 * @param pThis The ext volume instance. 732 * @param iInode Inode number. 733 */ 734 static PRTFSEXTINODE rtFsExtInodeGetNew(PRTFSEXTVOL pThis, uint32_t iInode) 735 { 736 PRTFSEXTINODE pInode = NULL; 737 if (pThis->cbInodes + sizeof(RTFSEXTINODE) <= RTFSEXT_MAX_INODE_CACHE_SIZE) 738 pInode = rtFsExtInodeAlloc(pThis, iInode); 739 else 740 { 741 pInode = RTListRemoveLast(&pThis->LstInodeLru, RTFSEXTINODE, NdLru); 742 if (!pInode) 743 pInode = rtFsExtInodeAlloc(pThis, iInode); 744 else 745 { 746 /* Remove the block group from the tree because it gets a new key. */ 747 PAVLU32NODECORE pCore = RTAvlU32Remove(&pThis->InodeRoot, pInode->Core.Key); 748 Assert(pCore == &pInode->Core); RT_NOREF(pCore); 749 } 750 } 751 752 Assert(!pInode->cRefs); 753 pInode->Core.Key = iInode; 754 pInode->cRefs = 1; 755 756 return pInode; 757 } 758 759 760 /** 761 * Loads the given inode number and returns it on success. 762 * 763 * @returns IPRT status code. 764 * @param pThis The ext volume instance. 765 * @param iInode The inode to load. 766 * @param ppInode Where to store the inode on success. 767 */ 768 static int rtFsExtInodeLoad(PRTFSEXTVOL pThis, uint32_t iInode, PRTFSEXTINODE *ppInode) 769 { 770 int rc = VINF_SUCCESS; 771 772 /* Try to fetch the inode from the cache first. */ 773 PRTFSEXTINODE pInode = (PRTFSEXTINODE)RTAvlU32Get(&pThis->InodeRoot, iInode); 774 if (!pInode) 775 { 776 /* Slow path, load from disk. */ 777 pInode = rtFsExtInodeGetNew(pThis, iInode); 778 if (RT_LIKELY(pInode)) 779 { 780 /* Calculate the block group and load that one first to get at the inode table location. */ 781 PRTFSEXTBLKGRP pBlockGroup = NULL; 782 rc = rtFsExtBlockGroupLoad(pThis, (iInode - 1) / pThis->cInodesPerGroup, &pBlockGroup); 783 if (RT_SUCCESS(rc)) 784 { 785 uint32_t idxInodeInTbl = (iInode - 1) % pThis->cInodesPerGroup; 786 uint64_t offRead = rtFsExtBlockIdxToDiskOffset(pThis, pBlockGroup->iBlockInodeTbl) 787 + idxInodeInTbl * pThis->cbInode; 788 789 /* Release block group here already as it is not required. */ 790 rtFsExtBlockGroupRelease(pThis, pBlockGroup); 791 792 EXTINODECOMB Inode; 793 rc = RTVfsFileReadAt(pThis->hVfsBacking, offRead, &Inode, RT_MIN(sizeof(Inode), pThis->cbInode), NULL); 794 if (RT_SUCCESS(rc)) 795 { 796 #ifdef LOG_ENABLED 797 rtFsExtInode_Log(pThis, iInode, &Inode); 798 #endif 799 /** @todo Fill in data. */ 800 } 801 } 802 } 803 else 804 rc = VERR_NO_MEMORY; 805 } 806 else 807 { 808 /* Remove from current LRU list position and add to the beginning. */ 809 uint32_t cRefs = ASMAtomicIncU32(&pInode->cRefs); 810 if (cRefs == 1) /* Inodes get removed from the LRU list if they are referenced. */ 811 RTListNodeRemove(&pInode->NdLru); 812 } 813 814 if (RT_SUCCESS(rc)) 815 *ppInode = pInode; 816 else if (pInode) 817 { 818 ASMAtomicDecU32(&pInode->cRefs); 819 rtFsExtInodeFree(pThis, pInode); /* Free the inode. */ 820 } 821 822 return rc; 823 } 824 825 826 /** 827 * Releases a reference of the given inode. 828 * 829 * @returns nothing. 830 * @param pThis The ext volume instance. 831 * @param pInode The inode to release. 832 */ 833 static void rtFsExtInodeRelease(PRTFSEXTVOL pThis, PRTFSEXTINODE pInode) 834 { 835 uint32_t cRefs = ASMAtomicDecU32(&pInode->cRefs); 836 if (!cRefs) 837 rtFsExtInodeFree(pThis, pInode); 838 } 839 840 841 /* 842 * 843 * Directory instance methods 844 * Directory instance methods 845 * Directory instance methods 846 * 847 */ 848 849 /** 850 * @interface_method_impl{RTVFSOBJOPS,pfnClose} 851 */ 852 static DECLCALLBACK(int) rtFsExtDir_Close(void *pvThis) 853 { 854 PRTFSEXTDIR pThis = (PRTFSEXTDIR)pvThis; 855 LogFlowFunc(("pThis=%p\n", pThis)); 856 857 return VINF_SUCCESS; 858 } 859 860 861 /** 862 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo} 863 */ 864 static DECLCALLBACK(int) rtFsExtDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr) 865 { 866 PRTFSEXTDIR pThis = (PRTFSEXTDIR)pvThis; 867 LogFlowFunc(("\n")); 868 RT_NOREF(pThis, pObjInfo, enmAddAttr); 869 return VERR_NOT_IMPLEMENTED; 870 } 871 872 873 /** 874 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode} 875 */ 876 static DECLCALLBACK(int) rtFsExtDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask) 877 { 878 LogFlowFunc(("\n")); 879 RT_NOREF(pvThis, fMode, fMask); 880 return VERR_WRITE_PROTECT; 881 } 882 883 884 /** 885 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes} 886 */ 887 static DECLCALLBACK(int) rtFsExtDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime, 888 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime) 889 { 890 LogFlowFunc(("\n")); 891 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime); 892 return VERR_WRITE_PROTECT; 893 } 894 895 896 /** 897 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner} 898 */ 899 static DECLCALLBACK(int) rtFsExtDir_SetOwner(void *pvThis, RTUID uid, RTGID gid) 900 { 901 LogFlowFunc(("\n")); 902 RT_NOREF(pvThis, uid, gid); 903 return VERR_WRITE_PROTECT; 904 } 905 906 907 /** 908 * @interface_method_impl{RTVFSDIROPS,pfnOpen} 909 */ 910 static DECLCALLBACK(int) rtFsExtDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen, 911 uint32_t fFlags, PRTVFSOBJ phVfsObj) 912 { 913 LogFlowFunc(("pszEntry='%s' fOpen=%#RX64 fFlags=%#x\n", pszEntry, fOpen, fFlags)); 914 PRTFSEXTDIR pThis = (PRTFSEXTDIR)pvThis; 915 PRTFSEXTVOL pVol = pThis->pVol; 916 int rc = VINF_SUCCESS; 917 918 RT_NOREF(pThis, pVol, phVfsObj); 919 920 /* 921 * We cannot create or replace anything, just open stuff. 922 */ 923 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN 924 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE) 925 { /* likely */ } 926 else 927 return VERR_WRITE_PROTECT; 928 929 LogFlow(("rtFsExtDir_Open(%s): returns %Rrc\n", pszEntry, rc)); 930 return rc; 931 } 932 933 934 /** 935 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir} 936 */ 937 static DECLCALLBACK(int) rtFsExtDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir) 938 { 939 RT_NOREF(pvThis, pszSubDir, fMode, phVfsDir); 940 LogFlowFunc(("\n")); 941 return VERR_WRITE_PROTECT; 942 } 943 944 945 /** 946 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink} 947 */ 948 static DECLCALLBACK(int) rtFsExtDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink) 949 { 950 RT_NOREF(pvThis, pszSymlink, phVfsSymlink); 951 LogFlowFunc(("\n")); 952 return VERR_NOT_SUPPORTED; 953 } 954 955 956 /** 957 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink} 958 */ 959 static DECLCALLBACK(int) rtFsExtDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget, 960 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink) 961 { 962 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink); 963 LogFlowFunc(("\n")); 964 return VERR_WRITE_PROTECT; 965 } 966 967 968 /** 969 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry} 970 */ 971 static DECLCALLBACK(int) rtFsExtDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType) 972 { 973 RT_NOREF(pvThis, pszEntry, fType); 974 LogFlowFunc(("\n")); 975 return VERR_WRITE_PROTECT; 976 } 977 978 979 /** 980 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry} 981 */ 982 static DECLCALLBACK(int) rtFsExtDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName) 983 { 984 RT_NOREF(pvThis, pszEntry, fType, pszNewName); 985 LogFlowFunc(("\n")); 986 return VERR_WRITE_PROTECT; 987 } 988 989 990 /** 991 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir} 992 */ 993 static DECLCALLBACK(int) rtFsExtDir_RewindDir(void *pvThis) 994 { 995 PRTFSEXTDIR pThis = (PRTFSEXTDIR)pvThis; 996 LogFlowFunc(("\n")); 997 998 pThis->fNoMoreFiles = false; 999 return VINF_SUCCESS; 1000 } 1001 1002 1003 /** 1004 * @interface_method_impl{RTVFSDIROPS,pfnReadDir} 1005 */ 1006 static DECLCALLBACK(int) rtFsExtDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, 1007 RTFSOBJATTRADD enmAddAttr) 1008 { 1009 PRTFSEXTDIR pThis = (PRTFSEXTDIR)pvThis; 1010 int rc = VINF_SUCCESS; 1011 LogFlowFunc(("\n")); 1012 1013 RT_NOREF(pThis, rc, pDirEntry, pcbDirEntry, enmAddAttr); 1014 1015 /* 1016 * The End. 1017 */ 1018 LogFlowFunc(("no more files\n")); 1019 pThis->fNoMoreFiles = true; 1020 return VERR_NO_MORE_FILES; 1021 } 1022 1023 1024 /** 1025 * EXT directory operations. 1026 */ 1027 static const RTVFSDIROPS g_rtFsExtDirOps = 1028 { 1029 { /* Obj */ 1030 RTVFSOBJOPS_VERSION, 1031 RTVFSOBJTYPE_DIR, 1032 "EXT Dir", 1033 rtFsExtDir_Close, 1034 rtFsExtDir_QueryInfo, 1035 RTVFSOBJOPS_VERSION 1036 }, 1037 RTVFSDIROPS_VERSION, 1038 0, 1039 { /* ObjSet */ 1040 RTVFSOBJSETOPS_VERSION, 1041 RT_UOFFSETOF(RTVFSDIROPS, ObjSet) - RT_UOFFSETOF(RTVFSDIROPS, Obj), 1042 rtFsExtDir_SetMode, 1043 rtFsExtDir_SetTimes, 1044 rtFsExtDir_SetOwner, 1045 RTVFSOBJSETOPS_VERSION 1046 }, 1047 rtFsExtDir_Open, 1048 NULL /* pfnFollowAbsoluteSymlink */, 1049 NULL /* pfnOpenFile */, 1050 NULL /* pfnOpenDir */, 1051 rtFsExtDir_CreateDir, 1052 rtFsExtDir_OpenSymlink, 1053 rtFsExtDir_CreateSymlink, 1054 NULL /* pfnQueryEntryInfo */, 1055 rtFsExtDir_UnlinkEntry, 1056 rtFsExtDir_RenameEntry, 1057 rtFsExtDir_RewindDir, 1058 rtFsExtDir_ReadDir, 1059 RTVFSDIROPS_VERSION, 1060 }; 1061 1062 1063 /** 1064 * Opens a directory by the given inode. 1065 * 1066 * @returns IPRT status code. 1067 * @param pThis The ext volume instance. 1068 * @param iInode The inode to open. 1069 * @param phVfsDir Where to store the handle to the VFS directory on success. 1070 */ 1071 static int rtFsExtVol_OpenDirByInode(PRTFSEXTVOL pThis, uint32_t iInode, PRTVFSDIR phVfsDir) 1072 { 1073 PRTFSEXTINODE pInode = NULL; 1074 int rc = rtFsExtInodeLoad(pThis, iInode, &pInode); 1075 if (RT_SUCCESS(rc)) 1076 rtFsExtInodeRelease(pThis, pInode); 1077 RT_NOREF(phVfsDir, g_rtFsExtDirOps); 1078 return rc; 1079 } 1080 1081 1082 /* 1083 * 1084 * Volume level code. 1085 * Volume level code. 1086 * Volume level code. 1087 * 1088 */ 1089 1090 1091 /** 1092 * Checks whether the block range in the given block group is in use by checking the 1093 * block bitmap. 1094 * 1095 * @returns Flag whether the range is in use. 1096 * @param pBlkGrpDesc The block group to check for. 1097 * @param iBlockStart The starting block to check relative from the beginning of the block group. 1098 * @param cBlocks How many blocks to check. 1099 */ 1100 static bool rtFsExtIsBlockRangeInUse(PRTFSEXTBLKGRP pBlkGrpDesc, uint64_t iBlockStart, size_t cBlocks) 1101 { 1102 /** @todo: Optimize with ASMBitFirstSet(). */ 146 1103 while (cBlocks) 147 1104 { 148 uint32_t idxByte = offBlockStart / 8;149 uint32_t iBit = offBlockStart % 8;1105 uint32_t idxByte = iBlockStart / 8; 1106 uint32_t iBit = iBlockStart % 8; 150 1107 151 1108 if (pBlkGrpDesc->abBlockBitmap[idxByte] & RT_BIT(iBit)) … … 153 1110 154 1111 cBlocks--; 155 offBlockStart++;1112 iBlockStart++; 156 1113 } 157 1114 … … 160 1117 161 1118 1119 static DECLCALLBACK(int) rtFsExtVolBlockGroupTreeDestroy(PAVLU32NODECORE pCore, void *pvUser) 1120 { 1121 RT_NOREF(pvUser); 1122 1123 PRTFSEXTBLKGRP pBlockGroup = (PRTFSEXTBLKGRP)pCore; 1124 Assert(!pBlockGroup->cRefs); 1125 RTMemFree(pBlockGroup); 1126 return VINF_SUCCESS; 1127 } 1128 1129 162 1130 /** 163 1131 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose} … … 167 1135 PRTFSEXTVOL pThis = (PRTFSEXTVOL)pvThis; 168 1136 169 if (pThis->pBlkGrpDesc) 170 RTMemFree(pThis->pBlkGrpDesc); 1137 /* Destroy the block group tree. */ 1138 RTAvlU32Destroy(&pThis->BlockGroupRoot, rtFsExtVolBlockGroupTreeDestroy, pThis); 1139 pThis->BlockGroupRoot = NULL; 1140 RTListInit(&pThis->LstBlockGroupLru); 1141 1142 /* 1143 * Backing file and handles. 1144 */ 1145 RTVfsFileRelease(pThis->hVfsBacking); 1146 pThis->hVfsBacking = NIL_RTVFSFILE; 1147 pThis->hVfsSelf = NIL_RTVFS; 171 1148 172 1149 return VINF_SUCCESS; … … 189 1166 static DECLCALLBACK(int) rtFsExtVol_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir) 190 1167 { 191 NOREF(pvThis); 192 NOREF(phVfsDir); 193 return VERR_NOT_IMPLEMENTED; 1168 PRTFSEXTVOL pThis = (PRTFSEXTVOL)pvThis; 1169 int rc = rtFsExtVol_OpenDirByInode(pThis, EXT_INODE_NR_ROOT_DIR, phVfsDir); 1170 LogFlowFunc(("returns %Rrc\n", rc)); 1171 return rc; 194 1172 } 195 1173 … … 205 1183 *pfUsed = false; 206 1184 207 while (cb > 0) 208 { 209 uint32_t const offBlockStart = (uint32_t)(off / pThis->cbBlock); 210 uint32_t const iBlockGroup = (offBlockStart - pThis->iSbBlock) / pThis->cBlocksPerGroup; 211 uint32_t const offBlockRelStart = offBlockStart - iBlockGroup * pThis->cBlocksPerGroup; 212 213 if ( off < pThis->pBlkGrpDesc->offStart 214 || off > pThis->pBlkGrpDesc->offLast) 215 { 216 /* Load new block descriptor. */ 217 rc = rtFsExtLoadBlkGrpDesc(pThis, iBlockGroup); 218 if (RT_FAILURE(rc)) 219 break; 220 } 221 222 size_t cbThis = RT_MIN(cb, pThis->pBlkGrpDesc->offLast - off + 1); 223 if (rtFsExtIsBlockRangeInUse(pThis->pBlkGrpDesc, 224 offBlockRelStart, 225 cbThis / pThis->cbBlock + (cbThis % pThis->cbBlock ? 1 : 0)) ) 1185 uint64_t iBlock = rtFsExtDiskOffsetToBlockIdx(pThis, off); 1186 uint64_t cBlocks = rtFsExtDiskOffsetToBlockIdx(pThis, cb) + (cb % pThis->cbBlock ? 1 : 0); 1187 while (cBlocks > 0) 1188 { 1189 uint32_t const iBlockGroup = iBlock / pThis->cBlocksPerGroup; 1190 uint32_t const iBlockRelStart = iBlock - iBlockGroup * pThis->cBlocksPerGroup; 1191 PRTFSEXTBLKGRP pBlockGroup = NULL; 1192 1193 rc = rtFsExtBlockGroupLoad(pThis, iBlockGroup, &pBlockGroup); 1194 if (RT_FAILURE(rc)) 1195 break; 1196 1197 uint64_t cBlocksThis = RT_MIN(cBlocks, iBlockRelStart - pThis->cBlocksPerGroup); 1198 if (rtFsExtIsBlockRangeInUse(pBlockGroup, iBlockRelStart, cBlocksThis)) 226 1199 { 227 1200 *pfUsed = true; … … 229 1202 } 230 1203 231 cb -= cbThis; 232 off += cbThis; 1204 rtFsExtBlockGroupRelease(pThis, pBlockGroup); 1205 cBlocks -= cBlocksThis; 1206 iBlock += cBlocksThis; 233 1207 } 234 1208 … … 256 1230 257 1231 1232 1233 /** 1234 * Loads the parameters from the given original ext2 format superblock (EXT_SB_REV_ORIG). 1235 * 1236 * @returns IPRT status code. 1237 * @param pThis The ext volume instance. 1238 * @param pSb The superblock to load. 1239 * @param pErrInfo Where to return additional error info. 1240 */ 1241 static int rtFsExtVolLoadAndParseSuperBlockV0(PRTFSEXTVOL pThis, PCEXTSUPERBLOCK pSb, PRTERRINFO pErrInfo) 1242 { 1243 RT_NOREF(pErrInfo); 1244 1245 /* 1246 * Linux never supported a differing cluster (also called fragment) size for 1247 * the original ext2 layout so we reject such filesystems as it is not clear what 1248 * the purpose is really. 1249 */ 1250 if (RT_LE2H_U32(pSb->cLogBlockSize) != RT_LE2H_U32(pSb->cLogClusterSize)) 1251 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "EXT filesystem cluster and block size differ"); 1252 1253 pThis->f64Bit = false; 1254 pThis->cBlockShift = 10 + RT_LE2H_U32(pSb->cLogBlockSize); 1255 pThis->cbBlock = 1 << pThis->cBlockShift; 1256 pThis->cbInode = sizeof(EXTINODE); 1257 pThis->cbBlkGrpDesc = sizeof(EXTBLOCKGROUPDESC32); 1258 pThis->cBlocksPerGroup = RT_LE2H_U32(pSb->cBlocksPerGroup); 1259 pThis->cInodesPerGroup = RT_LE2H_U32(pSb->cInodesPerBlockGroup); 1260 pThis->cBlockGroups = RT_LE2H_U32(pSb->cBlocksTotalLow) / pThis->cBlocksPerGroup; 1261 pThis->cbBlockBitmap = pThis->cBlocksPerGroup / 8; 1262 if (pThis->cBlocksPerGroup % 8) 1263 pThis->cbBlockBitmap++; 1264 pThis->cbInodeBitmap = pThis->cInodesPerGroup / 8; 1265 if (pThis->cInodesPerGroup % 8) 1266 pThis->cbInodeBitmap++; 1267 1268 return VINF_SUCCESS; 1269 } 1270 1271 1272 /** 1273 * Loads the parameters from the given ext superblock (EXT_SB_REV_V2_DYN_INODE_SZ). 1274 * 1275 * @returns IPRT status code. 1276 * @param pThis The ext volume instance. 1277 * @param pSb The superblock to load. 1278 * @param pErrInfo Where to return additional error info. 1279 */ 1280 static int rtFsExtVolLoadAndParseSuperBlockV1(PRTFSEXTVOL pThis, PCEXTSUPERBLOCK pSb, PRTERRINFO pErrInfo) 1281 { 1282 if (RT_LE2H_U32(pSb->fFeaturesIncompat) != 0) 1283 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "EXT filesystem contains unsupported incompatible features: %RX32", 1284 RT_LE2H_U32(pSb->fFeaturesIncompat)); 1285 if ( RT_LE2H_U32(pSb->fFeaturesCompatRo) != 0 1286 && !(pThis->fMntFlags & RTVFSMNT_F_READ_ONLY)) 1287 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "EXT filesystem contains unsupported readonly features: %RX32", 1288 RT_LE2H_U32(pSb->fFeaturesCompatRo)); 1289 1290 return VINF_SUCCESS; 1291 } 1292 1293 1294 /** 1295 * Loads and parses the superblock of the filesystem. 1296 * 1297 * @returns IPRT status code. 1298 * @param pThis The ext volume instance. 1299 * @param pErrInfo Where to return additional error info. 1300 */ 1301 static int rtFsExtVolLoadAndParseSuperblock(PRTFSEXTVOL pThis, PRTERRINFO pErrInfo) 1302 { 1303 int rc = VINF_SUCCESS; 1304 EXTSUPERBLOCK Sb; 1305 rc = RTVfsFileReadAt(pThis->hVfsBacking, EXT_SB_OFFSET, &Sb, sizeof(EXTSUPERBLOCK), NULL); 1306 if (RT_FAILURE(rc)) 1307 return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading super block"); 1308 1309 /* Validate the superblock. */ 1310 if (RT_LE2H_U16(Sb.u16Signature) != EXT_SB_SIGNATURE) 1311 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, "Not EXT - Signature mismatch: %RX16", RT_LE2H_U16(Sb.u16Signature)); 1312 1313 #ifdef LOG_ENABLED 1314 rtFsExtSb_Log(&Sb); 1315 #endif 1316 1317 if (RT_LE2H_U16(Sb.u16FilesystemState) == EXT_SB_STATE_ERRORS) 1318 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "EXT filesystem contains errors"); 1319 1320 if (RT_LE2H_U32(Sb.u32RevLvl) == EXT_SB_REV_ORIG) 1321 rc = rtFsExtVolLoadAndParseSuperBlockV0(pThis, &Sb, pErrInfo); 1322 else 1323 rc = rtFsExtVolLoadAndParseSuperBlockV1(pThis, &Sb, pErrInfo); 1324 1325 return rc; 1326 } 1327 1328 258 1329 RTDECL(int) RTFsExtVolOpen(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fExtFlags, PRTVFS phVfs, PRTERRINFO pErrInfo) 259 1330 { … … 265 1336 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE); 266 1337 1338 /* 1339 * Create a VFS instance and initialize the data so rtFsExtVol_Close works. 1340 */ 1341 RTVFS hVfs; 267 1342 PRTFSEXTVOL pThis; 268 int rc = RTVfsNew(&g_rtFsExtVolOps, sizeof(*pThis), NIL_RTVFS, RTVFSLOCK_CREATE_RW, phVfs, (void **)&pThis);1343 int rc = RTVfsNew(&g_rtFsExtVolOps, sizeof(*pThis), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, (void **)&pThis); 269 1344 if (RT_SUCCESS(rc)) 270 1345 { 271 pThis->hVfsBacking = hVfsFileIn; 272 pThis->pBlkGrpDesc = NULL; 273 274 EXTSUPERBLOCK SuperBlock; 275 rc = RTVfsFileReadAt(hVfsFileIn, 1024, &SuperBlock, sizeof(EXTSUPERBLOCK), NULL); 1346 pThis->hVfsBacking = hVfsFileIn; 1347 pThis->hVfsSelf = hVfs; 1348 pThis->fMntFlags = fMntFlags; 1349 pThis->fExtFlags = fExtFlags; 1350 pThis->BlockGroupRoot = NULL; 1351 pThis->InodeRoot = NULL; 1352 pThis->cbBlockGroups = 0; 1353 pThis->cbInodes = 0; 1354 RTListInit(&pThis->LstBlockGroupLru); 1355 RTListInit(&pThis->LstInodeLru); 1356 1357 rc = RTVfsFileGetSize(pThis->hVfsBacking, &pThis->cbBacking); 276 1358 if (RT_SUCCESS(rc)) 277 1359 { 278 #if defined(RT_BIGENDIAN) 279 /** @todo Convert to host endianess. */ 280 #endif 281 if (SuperBlock.u16FilesystemState == EXT_SB_STATE_ERRORS) 282 rc = RTERRINFO_LOG_SET(pErrInfo, VERR_FILESYSTEM_CORRUPT, "EXT_STATE_ERRORS"); 283 else 284 { 285 pThis->iSbBlock = SuperBlock.iBlockOfSuperblock; 286 pThis->cbBlock = 1024 << SuperBlock.cLogBlockSize; 287 pThis->cBlocksPerGroup = SuperBlock.cBlocksPerGroup; 288 pThis->cBlockGroups = SuperBlock.cBlocksTotalLow / pThis->cBlocksPerGroup; 289 290 /* Load first block group descriptor. */ 291 rc = rtFsExtLoadBlkGrpDesc(pThis, 0); 292 } 1360 rc = rtFsExtVolLoadAndParseSuperblock(pThis, pErrInfo); 293 1361 if (RT_SUCCESS(rc)) 294 1362 { 1363 *phVfs = hVfs; 295 1364 return VINF_SUCCESS; 296 1365 } 297 1366 } 298 else 299 rc = RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading super block"); 300 301 RTVfsRelease(*phVfs); 1367 1368 RTVfsRelease(hVfs); 302 1369 *phVfs = NIL_RTVFS; 303 1370 }
Note:
See TracChangeset
for help on using the changeset viewer.