c1c9242f0046150566414e1f222cb667e03e605evboxsync/* $Id$ */
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** @file
c1c9242f0046150566414e1f222cb667e03e605evboxsync * IPRT Filesystem API (FileSys) - ext2/3 format.
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/*
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Copyright (C) 2012 Oracle Corporation
c1c9242f0046150566414e1f222cb667e03e605evboxsync *
c1c9242f0046150566414e1f222cb667e03e605evboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c1c9242f0046150566414e1f222cb667e03e605evboxsync * available from http://www.virtualbox.org. This file is free software;
c1c9242f0046150566414e1f222cb667e03e605evboxsync * you can redistribute it and/or modify it under the terms of the GNU
c1c9242f0046150566414e1f222cb667e03e605evboxsync * General Public License (GPL) as published by the Free Software
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c1c9242f0046150566414e1f222cb667e03e605evboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c1c9242f0046150566414e1f222cb667e03e605evboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c1c9242f0046150566414e1f222cb667e03e605evboxsync *
c1c9242f0046150566414e1f222cb667e03e605evboxsync * The contents of this file may alternatively be used under the terms
c1c9242f0046150566414e1f222cb667e03e605evboxsync * of the Common Development and Distribution License Version 1.0
c1c9242f0046150566414e1f222cb667e03e605evboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
c1c9242f0046150566414e1f222cb667e03e605evboxsync * VirtualBox OSE distribution, in which case the provisions of the
c1c9242f0046150566414e1f222cb667e03e605evboxsync * CDDL are applicable instead of those of the GPL.
c1c9242f0046150566414e1f222cb667e03e605evboxsync *
c1c9242f0046150566414e1f222cb667e03e605evboxsync * You may elect to license modified versions of this file under the
c1c9242f0046150566414e1f222cb667e03e605evboxsync * terms and conditions of either the GPL or the CDDL or both.
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/*******************************************************************************
c1c9242f0046150566414e1f222cb667e03e605evboxsync* Header Files *
c1c9242f0046150566414e1f222cb667e03e605evboxsync*******************************************************************************/
c1c9242f0046150566414e1f222cb667e03e605evboxsync#define LOG_GROUP LOG_GROUP_DEFAULT
c1c9242f0046150566414e1f222cb667e03e605evboxsync#include <iprt/types.h>
c1c9242f0046150566414e1f222cb667e03e605evboxsync#include <iprt/assert.h>
c1c9242f0046150566414e1f222cb667e03e605evboxsync#include <iprt/mem.h>
c1c9242f0046150566414e1f222cb667e03e605evboxsync#include <iprt/filesystem.h>
c1c9242f0046150566414e1f222cb667e03e605evboxsync#include <iprt/string.h>
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync#include <iprt/vfs.h>
c1c9242f0046150566414e1f222cb667e03e605evboxsync#include "internal/filesystem.h"
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/*******************************************************************************
c1c9242f0046150566414e1f222cb667e03e605evboxsync* Structures and Typedefs *
c1c9242f0046150566414e1f222cb667e03e605evboxsync*******************************************************************************/
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/*
c1c9242f0046150566414e1f222cb667e03e605evboxsync * The filesystem structures are from http://wiki.osdev.org/Ext2 and
c1c9242f0046150566414e1f222cb667e03e605evboxsync * http://www.nongnu.org/ext2-doc/ext2.html
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/**
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Ext superblock.
c1c9242f0046150566414e1f222cb667e03e605evboxsync *
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Everything is stored little endian on the disk.
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
c1c9242f0046150566414e1f222cb667e03e605evboxsync#pragma pack(1)
c1c9242f0046150566414e1f222cb667e03e605evboxsynctypedef struct ExtSuperBlock
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Total number of inodes in the filesystem. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cInodesTotal;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Total number of blocks in the filesystem. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cBlocksTotal;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of blocks reserved for the super user. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cBlocksRsvdForSuperUser;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Total number of unallocated blocks. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cBlocksUnallocated;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Total number of unallocated inodes. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cInodesUnallocated;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Block number of block containing the superblock. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t iBlockOfSuperblock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of bits to shift 1024 to the left to get the block size */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cBitsShiftLeftBlockSize;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of bits to shift 1024 to the left to get the fragment size */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cBitsShiftLeftFragmentSize;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of blocks in each block group. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cBlocksPerGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of fragments in each block group. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cFragmentsPerBlockGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of inodes in each block group. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t cInodesPerBlockGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Last mount time. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t u32LastMountTime;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Last written time. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t u32LastWrittenTime;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of times the volume was mounted since the last check. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t cMountsSinceLastCheck;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of mounts allowed before a consistency check. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t cMaxMountsUntilCheck;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Signature to identify a ext2 volume. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t u16Signature;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** State of the filesystem (clean/errors) */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t u16FilesystemState;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** What to do on an error. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t u16ActionOnError;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Minor version field. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t u16VersionMinor;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Time of last check. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t u32LastCheckTime;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Interval between consistency checks. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t u32CheckInterval;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Operating system ID of the filesystem creator. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t u32OsIdCreator;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Major version field. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t u32VersionMajor;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** User ID that is allowed to use reserved blocks. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t u16UidReservedBlocks;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Group ID that is allowed to use reserved blocks. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t u16GidReservedBlocks;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Reserved fields. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint8_t abReserved[940];
c1c9242f0046150566414e1f222cb667e03e605evboxsync} ExtSuperBlock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync#pragma pack()
c1c9242f0046150566414e1f222cb667e03e605evboxsyncAssertCompileSize(ExtSuperBlock, 1024);
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** Pointer to an ext super block. */
c1c9242f0046150566414e1f222cb667e03e605evboxsynctypedef ExtSuperBlock *PExtSuperBlock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** Ext2 signature. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync#define RTFILESYSTEM_EXT2_SIGNATURE (0xef53)
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** Clean filesystem state. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync#define RTFILESYSTEM_EXT2_STATE_CLEAN (0x0001)
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** Error filesystem state. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync#define RTFILESYSTEM_EXT2_STATE_ERRORS (0x0002)
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/**
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Block group descriptor.
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
c1c9242f0046150566414e1f222cb667e03e605evboxsync#pragma pack(1)
c1c9242f0046150566414e1f222cb667e03e605evboxsynctypedef struct BlockGroupDesc
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Block address of the block bitmap. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t offBlockBitmap;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Block address of the inode bitmap. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t offInodeBitmap;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Start block address of the inode table. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t offInodeTable;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of unallocated blocks in group. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t cBlocksUnallocated;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of unallocated inodes in group. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t cInodesUnallocated;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of directories in the group. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t cDirectories;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Padding. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint16_t u16Padding;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Reserved. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint8_t abReserved[12];
c1c9242f0046150566414e1f222cb667e03e605evboxsync} BlockGroupDesc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync#pragma pack()
c1c9242f0046150566414e1f222cb667e03e605evboxsyncAssertCompileSize(BlockGroupDesc, 32);
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** Pointer to an ext block group descriptor. */
c1c9242f0046150566414e1f222cb667e03e605evboxsynctypedef BlockGroupDesc *PBlockGroupDesc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/**
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Cached block group descriptor data.
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsynctypedef struct RTFILESYSTEMEXTBLKGRP
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Start offset (in bytes and from the start of the disk). */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint64_t offStart;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Last offset in the block group (inclusive). */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint64_t offLast;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Block bitmap - variable in size (depends on the block size
c1c9242f0046150566414e1f222cb667e03e605evboxsync * and number of blocks per group). */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint8_t abBlockBitmap[1];
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync} RTFILESYSTEMEXTBLKGRP;
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** Pointer to block group descriptor data. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsynctypedef RTFILESYSTEMEXTBLKGRP *PRTFILESYSTEMEXTBLKGRP;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/**
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Ext2/3 filesystem data.
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsynctypedef struct RTFILESYSTEMEXT
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** VFS file handle. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync RTVFSFILE hVfsFile;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Block number of the superblock. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t iSbBlock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Size of one block. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync size_t cbBlock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of blocks in one group. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync unsigned cBlocksPerGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Number of blocks groups in the volume. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync unsigned cBlockGroups;
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** Cached block group descriptor data. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync} RTFILESYSTEMEXT;
c1c9242f0046150566414e1f222cb667e03e605evboxsync/** Pointer to the ext filesystem data. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsynctypedef RTFILESYSTEMEXT *PRTFILESYSTEMEXT;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/*******************************************************************************
c1c9242f0046150566414e1f222cb667e03e605evboxsync* Methods *
c1c9242f0046150566414e1f222cb667e03e605evboxsync*******************************************************************************/
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync/**
c1c9242f0046150566414e1f222cb667e03e605evboxsync * Loads the block descriptor of the given block group from the medium.
c1c9242f0046150566414e1f222cb667e03e605evboxsync *
c1c9242f0046150566414e1f222cb667e03e605evboxsync * @returns IPRT status code.
c1c9242f0046150566414e1f222cb667e03e605evboxsync * @param pThis EXT filesystem instance data.
c1c9242f0046150566414e1f222cb667e03e605evboxsync * @param iBlkGrp Block group number to load.
c1c9242f0046150566414e1f222cb667e03e605evboxsync */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncstatic int rtFsExtLoadBlkGrpDesc(PRTFILESYSTEMEXT pThis, uint32_t iBlkGrp)
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
c1c9242f0046150566414e1f222cb667e03e605evboxsync int rc = VINF_SUCCESS;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc = pThis->pBlkGrpDesc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint64_t offRead = (pThis->iSbBlock + 1) * pThis->cbBlock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync BlockGroupDesc BlkDesc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync size_t cbBlockBitmap;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync cbBlockBitmap = pThis->cBlocksPerGroup / 8;
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (pThis->cBlocksPerGroup % 8)
c1c9242f0046150566414e1f222cb667e03e605evboxsync cbBlockBitmap++;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (!pBlkGrpDesc)
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync size_t cbBlkDesc = RT_OFFSETOF(RTFILESYSTEMEXTBLKGRP, abBlockBitmap[cbBlockBitmap]);
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync pBlkGrpDesc = (PRTFILESYSTEMEXTBLKGRP)RTMemAllocZ(cbBlkDesc);
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (!pBlkGrpDesc)
c1c9242f0046150566414e1f222cb667e03e605evboxsync return VERR_NO_MEMORY;
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = RTVfsFileReadAt(pThis->hVfsFile, offRead, &BlkDesc, sizeof(BlkDesc), NULL);
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (RT_SUCCESS(rc))
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
c1c9242f0046150566414e1f222cb667e03e605evboxsync pBlkGrpDesc->offStart = pThis->iSbBlock + (uint64_t)iBlkGrp * pThis->cBlocksPerGroup * pThis->cbBlock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync pBlkGrpDesc->offLast = pBlkGrpDesc->offStart + pThis->cBlocksPerGroup * pThis->cbBlock;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = RTVfsFileReadAt(pThis->hVfsFile, BlkDesc.offBlockBitmap * pThis->cbBlock,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync &pBlkGrpDesc->abBlockBitmap[0], cbBlockBitmap, NULL);
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync pThis->pBlkGrpDesc = pBlkGrpDesc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync return rc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync}
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncstatic bool rtFsExtIsBlockRangeInUse(PRTFILESYSTEMEXTBLKGRP pBlkGrpDesc,
854203c3afd42e567982d205e1046c8531d099a2vboxsync uint32_t offBlockStart, size_t cBlocks)
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync{
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync bool fUsed = false;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync while (cBlocks)
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync {
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync uint32_t idxByte = offBlockStart / 8;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync uint32_t iBit = offBlockStart % 8;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync if (pBlkGrpDesc->abBlockBitmap[idxByte] & RT_BIT(iBit))
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync {
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync fUsed = true;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync break;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync }
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync cBlocks--;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync offBlockStart++;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync }
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync return fUsed;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync}
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncstatic DECLCALLBACK(int) rtFsExtProbe(RTVFSFILE hVfsFile, uint32_t *puScore)
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
c1c9242f0046150566414e1f222cb667e03e605evboxsync int rc = VINF_SUCCESS;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync uint64_t cbMedium = 0;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync *puScore = RTFILESYSTEM_MATCH_SCORE_UNSUPPORTED;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = RTVfsFileGetSize(hVfsFile, &cbMedium);
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync if (RT_SUCCESS(rc))
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync if (cbMedium >= 2*sizeof(ExtSuperBlock))
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync ExtSuperBlock SuperBlock;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = RTVfsFileReadAt(hVfsFile, 1024, &SuperBlock, sizeof(ExtSuperBlock), NULL);
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync if (RT_SUCCESS(rc))
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync {
c1c9242f0046150566414e1f222cb667e03e605evboxsync#if defined(RT_BIGENDIAN)
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** @todo: Convert to host endianess. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync#endif
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync if (SuperBlock.u16Signature == RTFILESYSTEM_EXT2_SIGNATURE)
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync *puScore = RTFILESYSTEM_MATCH_SCORE_SUPPORTED;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync return rc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync}
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncstatic DECLCALLBACK(int) rtFsExtInit(void *pvThis, RTVFSFILE hVfsFile)
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
c1c9242f0046150566414e1f222cb667e03e605evboxsync int rc = VINF_SUCCESS;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
c1c9242f0046150566414e1f222cb667e03e605evboxsync ExtSuperBlock SuperBlock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync pThis->hVfsFile = hVfsFile;
c1c9242f0046150566414e1f222cb667e03e605evboxsync pThis->pBlkGrpDesc = NULL;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = RTVfsFileReadAt(hVfsFile, 1024, &SuperBlock, sizeof(ExtSuperBlock), NULL);
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (RT_SUCCESS(rc))
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
c1c9242f0046150566414e1f222cb667e03e605evboxsync#if defined(RT_BIGENDIAN)
c1c9242f0046150566414e1f222cb667e03e605evboxsync /** @todo: Convert to host endianess. */
c1c9242f0046150566414e1f222cb667e03e605evboxsync#endif
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (SuperBlock.u16FilesystemState == RTFILESYSTEM_EXT2_STATE_ERRORS)
c1c9242f0046150566414e1f222cb667e03e605evboxsync rc = VERR_FILESYSTEM_CORRUPT;
c1c9242f0046150566414e1f222cb667e03e605evboxsync else
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
c1c9242f0046150566414e1f222cb667e03e605evboxsync pThis->iSbBlock = SuperBlock.iBlockOfSuperblock;
c1c9242f0046150566414e1f222cb667e03e605evboxsync pThis->cbBlock = 1024 << SuperBlock.cBitsShiftLeftBlockSize;
c1c9242f0046150566414e1f222cb667e03e605evboxsync pThis->cBlocksPerGroup = SuperBlock.cBlocksPerGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync pThis->cBlockGroups = SuperBlock.cBlocksTotal / pThis->cBlocksPerGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync /* Load first block group descriptor. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = rtFsExtLoadBlkGrpDesc(pThis, 0);
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync return rc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync}
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncstatic DECLCALLBACK(void) rtFsExtDestroy(void *pvThis)
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (pThis->pBlkGrpDesc)
c1c9242f0046150566414e1f222cb667e03e605evboxsync RTMemFree(pThis->pBlkGrpDesc);
c1c9242f0046150566414e1f222cb667e03e605evboxsync}
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncstatic DECLCALLBACK(int) rtFsExtOpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
350953fa71e4942666d270cfac998be645fae487vboxsync NOREF(pvThis);
350953fa71e4942666d270cfac998be645fae487vboxsync NOREF(phVfsDir);
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync return VERR_NOT_IMPLEMENTED;
c1c9242f0046150566414e1f222cb667e03e605evboxsync}
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncstatic DECLCALLBACK(int) rtFsExtIsRangeInUse(void *pvThis, RTFOFF off, size_t cb,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync bool *pfUsed)
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
c1c9242f0046150566414e1f222cb667e03e605evboxsync int rc = VINF_SUCCESS;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync uint64_t offStart = (uint64_t)off;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync PRTFILESYSTEMEXT pThis = (PRTFILESYSTEMEXT)pvThis;
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync *pfUsed = false;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync while (cb > 0)
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
c1c9242f0046150566414e1f222cb667e03e605evboxsync bool fUsed;
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t offBlockStart = (uint32_t)(offStart / pThis->cbBlock);
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t iBlockGroup = (offBlockStart - pThis->iSbBlock) / pThis->cBlocksPerGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync uint32_t offBlockRelStart = offBlockStart - iBlockGroup * pThis->cBlocksPerGroup;
c1c9242f0046150566414e1f222cb667e03e605evboxsync size_t cbThis = 0;
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync if ( offStart < pThis->pBlkGrpDesc->offStart
c1c9242f0046150566414e1f222cb667e03e605evboxsync || offStart > pThis->pBlkGrpDesc->offLast)
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
c1c9242f0046150566414e1f222cb667e03e605evboxsync /* Load new block descriptor. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rc = rtFsExtLoadBlkGrpDesc(pThis, iBlockGroup);
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (RT_FAILURE(rc))
c1c9242f0046150566414e1f222cb667e03e605evboxsync break;
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync cbThis = RT_MIN(cb, pThis->pBlkGrpDesc->offLast - offStart + 1);
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync fUsed = rtFsExtIsBlockRangeInUse(pThis->pBlkGrpDesc, offBlockRelStart,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync cbThis / pThis->cbBlock +
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync (cbThis % pThis->cbBlock ? 1 : 0));
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync if (fUsed)
c1c9242f0046150566414e1f222cb667e03e605evboxsync {
c1c9242f0046150566414e1f222cb667e03e605evboxsync *pfUsed = true;
c1c9242f0046150566414e1f222cb667e03e605evboxsync break;
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync cb -= cbThis;
c1c9242f0046150566414e1f222cb667e03e605evboxsync offStart += cbThis;
c1c9242f0046150566414e1f222cb667e03e605evboxsync }
c1c9242f0046150566414e1f222cb667e03e605evboxsync
c1c9242f0046150566414e1f222cb667e03e605evboxsync return rc;
c1c9242f0046150566414e1f222cb667e03e605evboxsync}
c1c9242f0046150566414e1f222cb667e03e605evboxsync
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsyncDECL_HIDDEN_CONST(RTFILESYSTEMDESC) const g_rtFsExt =
c1c9242f0046150566414e1f222cb667e03e605evboxsync{
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** cbFs */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync sizeof(RTFILESYSTEMEXT),
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** VfsOps */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync {
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** uVersion. */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync RTVFSOPS_VERSION,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** fFeatures */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync 0,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** pszName */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync "ExtVfsOps",
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** pfnDestroy */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rtFsExtDestroy,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** pfnOpenRoot */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rtFsExtOpenRoot,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** pfnIsRangeInUse */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rtFsExtIsRangeInUse,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** uEndMarker */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync RTVFSOPS_VERSION
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync },
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** pfnProbe */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rtFsExtProbe,
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync /** pfnInit */
54d2d2606d7c83a456819cd038a73e0f9a600ca4vboxsync rtFsExtInit
c1c9242f0046150566414e1f222cb667e03e605evboxsync};
c1c9242f0046150566414e1f222cb667e03e605evboxsync