예제 #1
0
/** @brief Determine whether the metaroot is valid.

    @param pMR                  The metaroot buffer.
    @param pfSectorCRCIsValid   Populated with whether the first sector of the
                                metaroot buffer is valid.

    @return Whether the metaroot is valid.

    @retval true    The metaroot buffer is valid.
    @retval false   The metaroot buffer is invalid.
*/
static bool MetarootIsValid(
    METAROOT   *pMR,
    bool       *pfSectorCRCIsValid)
{
    bool        fRet = false;

    if(pfSectorCRCIsValid == NULL)
    {
        REDERROR();
    }
    else if(pMR == NULL)
    {
        REDERROR();
        *pfSectorCRCIsValid = false;
    }
  #ifdef REDCONF_ENDIAN_SWAP
    else if(RedRev32(pMR->hdr.ulSignature) != META_SIG_METAROOT)
  #else
    else if(pMR->hdr.ulSignature != META_SIG_METAROOT)
  #endif
    {
        *pfSectorCRCIsValid = false;
    }
    else
    {
        const uint8_t  *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMR);
        uint32_t        ulSectorCRC = pMR->ulSectorCRC;
        uint32_t        ulCRC;

      #ifdef REDCONF_ENDIAN_SWAP
        ulSectorCRC = RedRev32(ulSectorCRC);
      #endif

        /*  The sector CRC was zero when the CRC was computed during the
            transaction, so it must be zero here.
        */
        pMR->ulSectorCRC = 0U;

        ulCRC = RedCrc32Update(0U, &pbMR[8U], gpRedVolConf->ulSectorSize - 8U);

        fRet = ulCRC == ulSectorCRC;
        *pfSectorCRCIsValid = fRet;

        if(fRet)
        {
            if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
            {
                ulCRC = RedCrc32Update(ulCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
            }

          #ifdef REDCONF_ENDIAN_SWAP
            ulCRC = RedRev32(ulCRC);
          #endif

            fRet = ulCRC == pMR->hdr.ulCRC;
        }
    }

    return fRet;
}
예제 #2
0
/** @brief Swap the byte order of a metadata node header

    @param pHeader  Pointer to the metadata node header to swap
*/
static void BufferEndianSwapHeader(
    NODEHEADER *pHeader)
{
    if(pHeader == NULL)
    {
        REDERROR();
    }
    else
    {
        pHeader->ulSignature = RedRev32(pHeader->ulSignature);
        pHeader->ulCRC = RedRev32(pHeader->ulCRC);
        pHeader->ullSequence = RedRev64(pHeader->ullSequence);
    }
}
예제 #3
0
static void MetaRootEndianSwap(
    METAROOT *pMetaRoot)
{
    if(pMetaRoot == NULL)
    {
        REDERROR();
    }
    else
    {
        pMetaRoot->ulSectorCRC = RedRev32(pMetaRoot->ulSectorCRC);
        pMetaRoot->ulFreeBlocks = RedRev32(pMetaRoot->ulFreeBlocks);
      #if REDCONF_API_POSIX == 1
        pMetaRoot->ulFreeInodes = RedRev32(pMetaRoot->ulFreeInodes);
      #endif
        pMetaRoot->ulAllocNextBlock = RedRev32(pMetaRoot->ulAllocNextBlock);
    }
}
예제 #4
0
/** @brief Swap the byte order of a master block

    @param pMaster  Pointer to the master block to swap
*/
static void BufferEndianSwapMaster(
    MASTERBLOCK *pMaster)
{
    if(pMaster == NULL)
    {
        REDERROR();
    }
    else
    {
        pMaster->ulVersion = RedRev32(pMaster->ulVersion);
        pMaster->ulFormatTime = RedRev32(pMaster->ulFormatTime);
        pMaster->ulInodeCount = RedRev32(pMaster->ulInodeCount);
        pMaster->ulBlockCount = RedRev32(pMaster->ulBlockCount);
        pMaster->uMaxNameLen = RedRev16(pMaster->uMaxNameLen);
        pMaster->uDirectPointers = RedRev16(pMaster->uDirectPointers);
        pMaster->uIndirectPointers = RedRev16(pMaster->uIndirectPointers);
    }
}
예제 #5
0
/** @brief Swap the byte order of an indirect or double indirect node

    @param pIndir   Pointer to the node to swap
*/
static void BufferEndianSwapIndir(
    INDIR  *pIndir)
{
    if(pIndir == NULL)
    {
        REDERROR();
    }
    else
    {
        uint32_t ulIdx;

        pIndir->ulInode = RedRev32(pIndir->ulInode);

        for(ulIdx = 0; ulIdx < INDIR_ENTRIES; ulIdx++)
        {
            pIndir->aulEntries[ulIdx] = RedRev32(pIndir->aulEntries[ulIdx]);
        }
    }
}
예제 #6
0
/** @brief Swap the byte order of an inode

    @param pInode   Pointer to the inode to swap
*/
static void BufferEndianSwapInode(
    INODE  *pInode)
{
    if(pInode == NULL)
    {
        REDERROR();
    }
    else
    {
        uint32_t ulIdx;

        pInode->ullSize = RedRev64(pInode->ullSize);

      #if REDCONF_INODE_BLOCKS == 1
        pInode->ulBlocks = RedRev32(pInode->ulBlocks);
      #endif

      #if REDCONF_INODE_TIMESTAMPS == 1
        pInode->ulATime = RedRev32(pInode->ulATime);
        pInode->ulMTime = RedRev32(pInode->ulMTime);
        pInode->ulCTime = RedRev32(pInode->ulCTime);
      #endif

        pInode->uMode = RedRev16(pInode->uMode);

      #if (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1)
        pInode->uNLink = RedRev16(pInode->uNLink);
      #endif

      #if REDCONF_API_POSIX == 1
        pInode->ulPInode = RedRev32(pInode->ulPInode);
      #endif

        for(ulIdx = 0; ulIdx < INODE_ENTRIES; ulIdx++)
        {
            pInode->aulEntries[ulIdx] = RedRev32(pInode->aulEntries[ulIdx]);
        }
    }
}
예제 #7
0
/** @brief Finalize a metadata buffer.

    This updates the CRC and the sequence number.  It also sets the signature,
    though this is only truly needed if the buffer is new.

    @param pbBuffer Pointer to the metadata buffer to finalize.
    @param bVolNum  The volume number for the metadata buffer.
    @param uFlags   The associated buffer flags.  Used to determine the expected
                    signature.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0           Operation was successful.
    @retval -RED_EINVAL Invalid parameter; or maximum sequence number reached.
*/
static REDSTATUS BufferFinalize(
    uint8_t    *pbBuffer,
    uint8_t     bVolNum,
    uint16_t    uFlags)
{
    REDSTATUS   ret = 0;

    if((pbBuffer == NULL) || (bVolNum >= REDCONF_VOLUME_COUNT) || ((uFlags & BFLAG_MASK) != uFlags))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        uint32_t ulSignature;

        switch(uFlags & BFLAG_META_MASK)
        {
            case BFLAG_META_MASTER:
                ulSignature = META_SIG_MASTER;
                break;
          #if REDCONF_IMAP_EXTERNAL == 1
            case BFLAG_META_IMAP:
                ulSignature = META_SIG_IMAP;
                break;
          #endif
            case BFLAG_META_INODE:
                ulSignature = META_SIG_INODE;
                break;
          #if DINDIR_POINTERS > 0U
            case BFLAG_META_DINDIR:
                ulSignature = META_SIG_DINDIR;
                break;
          #endif
          #if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
            case BFLAG_META_INDIR:
                ulSignature = META_SIG_INDIR;
                break;
          #endif
            default:
                ulSignature = 0U;
                break;
        }

        if(ulSignature == 0U)
        {
            REDERROR();
            ret = -RED_EINVAL;
        }
        else
        {
            uint64_t ullSeqNum = gaRedVolume[bVolNum].ullSequence;

            ret = RedVolSeqNumIncrement(bVolNum);
            if(ret == 0)
            {
                uint32_t ulCrc;

                RedMemCpy(&pbBuffer[NODEHEADER_OFFSET_SIG], &ulSignature, sizeof(ulSignature));
                RedMemCpy(&pbBuffer[NODEHEADER_OFFSET_SEQ], &ullSeqNum, sizeof(ullSeqNum));

              #ifdef REDCONF_ENDIAN_SWAP
                BufferEndianSwap(pbBuffer, uFlags);
              #endif

                ulCrc = RedCrcNode(pbBuffer);
              #ifdef REDCONF_ENDIAN_SWAP
                ulCrc = RedRev32(ulCrc);
              #endif
                RedMemCpy(&pbBuffer[NODEHEADER_OFFSET_CRC], &ulCrc, sizeof(ulCrc));
            }
        }
    }

    return ret;
}
예제 #8
0
/** Determine whether a metadata buffer is valid.

    This includes checking its signature, CRC, and sequence number.

    @param pbBuffer Pointer to the metadata buffer to validate.
    @param uFlags   The buffer flags provided by the caller.  Used to determine
                    the expected signature.

    @return Whether the metadata buffer is valid.

    @retval true    The metadata buffer is valid.
    @retval false   The metadata buffer is invalid.
*/
static bool BufferIsValid(
    const uint8_t  *pbBuffer,
    uint16_t        uFlags)
{
    bool            fValid;

    if((pbBuffer == NULL) || ((uFlags & BFLAG_MASK) != uFlags))
    {
        REDERROR();
        fValid = false;
    }
    else
    {
        NODEHEADER  buf;
        uint16_t    uMetaFlags = uFlags & BFLAG_META_MASK;

        /*  Casting pbBuffer to (NODEHEADER *) would run afoul MISRA-C:2012
            R11.3, so instead copy the fields out.
        */
        RedMemCpy(&buf.ulSignature, &pbBuffer[NODEHEADER_OFFSET_SIG], sizeof(buf.ulSignature));
        RedMemCpy(&buf.ulCRC,       &pbBuffer[NODEHEADER_OFFSET_CRC], sizeof(buf.ulCRC));
        RedMemCpy(&buf.ullSequence, &pbBuffer[NODEHEADER_OFFSET_SEQ], sizeof(buf.ullSequence));

      #ifdef REDCONF_ENDIAN_SWAP
        buf.ulCRC = RedRev32(buf.ulCRC);
        buf.ulSignature = RedRev32(buf.ulSignature);
        buf.ullSequence = RedRev64(buf.ullSequence);
      #endif

        /*  Make sure the signature is correct for the type of metadata block
            requested by the caller.
        */
        switch(buf.ulSignature)
        {
            case META_SIG_MASTER:
                fValid = (uMetaFlags == BFLAG_META_MASTER);
                break;
          #if REDCONF_IMAP_EXTERNAL == 1
            case META_SIG_IMAP:
                fValid = (uMetaFlags == BFLAG_META_IMAP);
                break;
          #endif
            case META_SIG_INODE:
                fValid = (uMetaFlags == BFLAG_META_INODE);
                break;
          #if DINDIR_POINTERS > 0U
            case META_SIG_DINDIR:
                fValid = (uMetaFlags == BFLAG_META_DINDIR);
                break;
          #endif
          #if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
            case META_SIG_INDIR:
                fValid = (uMetaFlags == BFLAG_META_INDIR);
                break;
          #endif
            default:
                fValid = false;
                break;
        }

        if(fValid)
        {
            uint32_t ulComputedCrc;

            /*  Check for disk corruption by comparing the stored CRC with one
                computed from the data.

                Also check the sequence number: if it is greater than the
                current sequence number, the block is from a previous format
                or the disk is writing blocks out of order.  During mount,
                before the metaroots have been read, the sequence number will
                be unknown, and the check is skipped.
            */
            ulComputedCrc = RedCrcNode(pbBuffer);
            if(buf.ulCRC != ulComputedCrc)
            {
                fValid = false;
            }
            else if(gpRedVolume->fMounted && (buf.ullSequence >= gpRedVolume->ullSequence))
            {
                fValid = false;
            }
            else
            {
                /*  Buffer is valid.  No action, fValid is already true.
                */
            }
        }
    }

    return fValid;
}
예제 #9
0
/** @brief Commit a transaction point.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0           Operation was successful.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedVolTransact(void)
{
    REDSTATUS ret = 0;

    REDASSERT(!gpRedVolume->fReadOnly); /* Should be checked by caller. */

    if(gpRedCoreVol->fBranched)
    {
        gpRedMR->ulFreeBlocks += gpRedCoreVol->ulAlmostFreeBlocks;
        gpRedCoreVol->ulAlmostFreeBlocks = 0U;

        ret = RedBufferFlush(0U, gpRedVolume->ulBlockCount);

        if(ret == 0)
        {
            gpRedMR->hdr.ulSignature = META_SIG_METAROOT;
            gpRedMR->hdr.ullSequence = gpRedVolume->ullSequence;

            ret = RedVolSeqNumIncrement();
        }

        if(ret == 0)
        {
            const uint8_t  *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(gpRedMR);
            uint32_t        ulSectorCRC;

          #ifdef REDCONF_ENDIAN_SWAP
            MetaRootEndianSwap(gpRedMR);
          #endif

            gpRedMR->ulSectorCRC = 0U;

            ulSectorCRC = RedCrc32Update(0U, &pbMR[8U], gpRedVolConf->ulSectorSize - 8U);

            if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
            {
                gpRedMR->hdr.ulCRC = RedCrc32Update(ulSectorCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
            }
            else
            {
                gpRedMR->hdr.ulCRC = ulSectorCRC;
            }

            gpRedMR->ulSectorCRC = ulSectorCRC;

          #ifdef REDCONF_ENDIAN_SWAP
            gpRedMR->hdr.ulCRC = RedRev32(gpRedMR->hdr.ulCRC);
            gpRedMR->ulSectorCRC = RedRev32(gpRedMR->ulSectorCRC);
          #endif

            /*  Flush the block device before writing the metaroot, so that all
                previously written blocks are guaranteed to be on the media before
                the metaroot is written.  Otherwise, if the block device reorders
                the writes, the metaroot could reach the media before metadata it
                points at, creating a window for disk corruption if power is lost.
            */
            ret = RedIoFlush(gbRedVolNum);
        }

        if(ret == 0)
        {
            ret = RedIoWrite(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT + gpRedCoreVol->bCurMR, 1U, gpRedMR);

          #ifdef REDCONF_ENDIAN_SWAP
            MetaRootEndianSwap(gpRedMR);
          #endif
        }

        /*  Flush the block device to force the metaroot write to the media.  This
            guarantees the transaction point is really complete before we return.
        */
        if(ret == 0)
        {
            ret = RedIoFlush(gbRedVolNum);
        }

        /*  Toggle to the other metaroot buffer.  The working state and committed
            state metaroot buffers exchange places.
        */
        if(ret == 0)
        {
            uint8_t bNextMR = 1U - gpRedCoreVol->bCurMR;

            gpRedCoreVol->aMR[bNextMR] = *gpRedMR;
            gpRedCoreVol->bCurMR = bNextMR;

            gpRedMR = &gpRedCoreVol->aMR[gpRedCoreVol->bCurMR];

            gpRedCoreVol->fBranched = false;
        }

        CRITICAL_ASSERT(ret == 0);
    }

    return ret;
}