mirror of
				https://github.com/FreeRTOS/FreeRTOS-Kernel.git
				synced 2025-11-04 02:32:42 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			536 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			536 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
 | 
						|
 | 
						|
                   Copyright (c) 2014-2015 Datalight, Inc.
 | 
						|
                       All Rights Reserved Worldwide.
 | 
						|
 | 
						|
    This program is free software; you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU General Public License as published by
 | 
						|
    the Free Software Foundation; use version 2 of the License.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
 | 
						|
    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU General Public License along
 | 
						|
    with this program; if not, write to the Free Software Foundation, Inc.,
 | 
						|
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
						|
*/
 | 
						|
/*  Businesses and individuals that for commercial or other reasons cannot
 | 
						|
    comply with the terms of the GPLv2 license may obtain a commercial license
 | 
						|
    before incorporating Reliance Edge into proprietary software for
 | 
						|
    distribution in any form.  Visit http://www.datalight.com/reliance-edge for
 | 
						|
    more information.
 | 
						|
*/
 | 
						|
/** @file
 | 
						|
    @brief Implements core volume operations.
 | 
						|
*/
 | 
						|
#include <redfs.h>
 | 
						|
#include <redcore.h>
 | 
						|
 | 
						|
 | 
						|
static bool MetarootIsValid(METAROOT *pMR, bool *pfSectorCRCIsValid);
 | 
						|
#ifdef REDCONF_ENDIAN_SWAP
 | 
						|
static void MetaRootEndianSwap(METAROOT *pMetaRoot);
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/** @brief Mount a file system volume.
 | 
						|
 | 
						|
    @return A negated ::REDSTATUS code indicating the operation result.
 | 
						|
 | 
						|
    @retval 0           Operation was successful.
 | 
						|
    @retval -RED_EIO    Volume not formatted, improperly formatted, or corrupt.
 | 
						|
*/
 | 
						|
REDSTATUS RedVolMount(void)
 | 
						|
{
 | 
						|
    REDSTATUS ret;
 | 
						|
 | 
						|
  #if REDCONF_READ_ONLY == 0
 | 
						|
    ret = RedOsBDevOpen(gbRedVolNum, BDEV_O_RDWR);
 | 
						|
  #else
 | 
						|
    ret = RedOsBDevOpen(gbRedVolNum, BDEV_O_RDONLY);
 | 
						|
  #endif
 | 
						|
 | 
						|
    if(ret == 0)
 | 
						|
    {
 | 
						|
        ret = RedVolMountMaster();
 | 
						|
 | 
						|
        if(ret == 0)
 | 
						|
        {
 | 
						|
            ret = RedVolMountMetaroot();
 | 
						|
        }
 | 
						|
 | 
						|
        if(ret != 0)
 | 
						|
        {
 | 
						|
            (void)RedOsBDevClose(gbRedVolNum);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** @brief Mount the master block.
 | 
						|
 | 
						|
    @return A negated ::REDSTATUS code indicating the operation result.
 | 
						|
 | 
						|
    @retval 0           Operation was successful.
 | 
						|
    @retval -RED_EIO    Master block missing, corrupt, or inconsistent with the
 | 
						|
                        compile-time driver settings.
 | 
						|
*/
 | 
						|
REDSTATUS RedVolMountMaster(void)
 | 
						|
{
 | 
						|
    REDSTATUS       ret;
 | 
						|
    MASTERBLOCK    *pMB;
 | 
						|
 | 
						|
    /*  Read the master block, to ensure that the disk was formatted with
 | 
						|
        Reliance Edge.
 | 
						|
    */
 | 
						|
    ret = RedBufferGet(BLOCK_NUM_MASTER, BFLAG_META_MASTER, CAST_VOID_PTR_PTR(&pMB));
 | 
						|
 | 
						|
    if(ret == 0)
 | 
						|
    {
 | 
						|
        /*  Verify that the driver was compiled with the same settings that
 | 
						|
            the disk was formatted with.  If not, the user has made a
 | 
						|
            mistake: either the driver settings are wrong, or the disk needs
 | 
						|
            to be reformatted.
 | 
						|
        */
 | 
						|
        if(    (pMB->ulVersion != RED_DISK_LAYOUT_VERSION)
 | 
						|
            || (pMB->ulInodeCount != gpRedVolConf->ulInodeCount)
 | 
						|
            || (pMB->ulBlockCount != gpRedVolume->ulBlockCount)
 | 
						|
            || (pMB->uMaxNameLen != REDCONF_NAME_MAX)
 | 
						|
            || (pMB->uDirectPointers != REDCONF_DIRECT_POINTERS)
 | 
						|
            || (pMB->uIndirectPointers != REDCONF_INDIRECT_POINTERS)
 | 
						|
            || (pMB->bBlockSizeP2 != BLOCK_SIZE_P2)
 | 
						|
            || (((pMB->bFlags & MBFLAG_API_POSIX) != 0U) != (REDCONF_API_POSIX == 1))
 | 
						|
            || (((pMB->bFlags & MBFLAG_INODE_TIMESTAMPS) != 0U) != (REDCONF_INODE_TIMESTAMPS == 1))
 | 
						|
            || (((pMB->bFlags & MBFLAG_INODE_BLOCKS) != 0U) != (REDCONF_INODE_BLOCKS == 1)))
 | 
						|
        {
 | 
						|
            ret = -RED_EIO;
 | 
						|
        }
 | 
						|
      #if REDCONF_API_POSIX == 1
 | 
						|
        else if(((pMB->bFlags & MBFLAG_INODE_NLINK) != 0U) != (REDCONF_API_POSIX_LINK == 1))
 | 
						|
        {
 | 
						|
            ret = -RED_EIO;
 | 
						|
        }
 | 
						|
      #else
 | 
						|
        else if((pMB->bFlags & MBFLAG_INODE_NLINK) != 0U)
 | 
						|
        {
 | 
						|
            ret = -RED_EIO;
 | 
						|
        }
 | 
						|
      #endif
 | 
						|
        else
 | 
						|
        {
 | 
						|
            /*  Master block configuration is valid.
 | 
						|
 | 
						|
                Save the sequence number of the master block in the volume,
 | 
						|
                since we need it later (see RedVolMountMetaroot()) and we do
 | 
						|
                not want to re-buffer the master block.
 | 
						|
            */
 | 
						|
            gpRedVolume->ullSequence = pMB->hdr.ullSequence;
 | 
						|
        }
 | 
						|
 | 
						|
        RedBufferPut(pMB);
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** @brief Mount the latest metaroot.
 | 
						|
 | 
						|
    This function also populates the volume contexts.
 | 
						|
 | 
						|
    @return A negated ::REDSTATUS code indicating the operation result.
 | 
						|
 | 
						|
    @retval 0           Operation was successful.
 | 
						|
    @retval -RED_EIO    Both metaroots are missing or corrupt.
 | 
						|
*/
 | 
						|
REDSTATUS RedVolMountMetaroot(void)
 | 
						|
{
 | 
						|
    REDSTATUS ret;
 | 
						|
 | 
						|
    ret = RedIoRead(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT, 1U, &gpRedCoreVol->aMR[0U]);
 | 
						|
 | 
						|
    if(ret == 0)
 | 
						|
    {
 | 
						|
        ret = RedIoRead(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT + 1U, 1U, &gpRedCoreVol->aMR[1U]);
 | 
						|
    }
 | 
						|
 | 
						|
    /*  Determine which metaroot is the most recent copy that was written
 | 
						|
        completely.
 | 
						|
    */
 | 
						|
    if(ret == 0)
 | 
						|
    {
 | 
						|
        uint8_t bMR = UINT8_MAX;
 | 
						|
        bool    fSectorCRCIsValid;
 | 
						|
 | 
						|
        if(MetarootIsValid(&gpRedCoreVol->aMR[0U], &fSectorCRCIsValid))
 | 
						|
        {
 | 
						|
            bMR = 0U;
 | 
						|
 | 
						|
          #ifdef REDCONF_ENDIAN_SWAP
 | 
						|
            MetaRootEndianSwap(&gpRedCoreVol->aMR[0U]);
 | 
						|
          #endif
 | 
						|
        }
 | 
						|
        else if(gpRedVolConf->fAtomicSectorWrite && !fSectorCRCIsValid)
 | 
						|
        {
 | 
						|
            ret = -RED_EIO;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            /*  Metaroot is not valid, so it is ignored and there's nothing
 | 
						|
                to do here.
 | 
						|
            */
 | 
						|
        }
 | 
						|
 | 
						|
        if(ret == 0)
 | 
						|
        {
 | 
						|
            if(MetarootIsValid(&gpRedCoreVol->aMR[1U], &fSectorCRCIsValid))
 | 
						|
            {
 | 
						|
              #ifdef REDCONF_ENDIAN_SWAP
 | 
						|
                MetaRootEndianSwap(&gpRedCoreVol->aMR[1U]);
 | 
						|
              #endif
 | 
						|
 | 
						|
                if((bMR != 0U) || (gpRedCoreVol->aMR[1U].hdr.ullSequence > gpRedCoreVol->aMR[0U].hdr.ullSequence))
 | 
						|
                {
 | 
						|
                    bMR = 1U;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else if(gpRedVolConf->fAtomicSectorWrite && !fSectorCRCIsValid)
 | 
						|
            {
 | 
						|
                ret = -RED_EIO;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                /*  Metaroot is not valid, so it is ignored and there's nothing
 | 
						|
                    to do here.
 | 
						|
                */
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if(ret == 0)
 | 
						|
        {
 | 
						|
            if(bMR == UINT8_MAX)
 | 
						|
            {
 | 
						|
                /*  Neither metaroot was valid.
 | 
						|
                */
 | 
						|
                ret = -RED_EIO;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                gpRedCoreVol->bCurMR = bMR;
 | 
						|
                gpRedMR = &gpRedCoreVol->aMR[bMR];
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if(ret == 0)
 | 
						|
    {
 | 
						|
        /*  Normally the metaroot contains the highest sequence number, but the
 | 
						|
            master block is the last block written during format, so on a
 | 
						|
            freshly formatted volume the master block sequence number (stored in
 | 
						|
            gpRedVolume->ullSequence) will be higher than that in the metaroot.
 | 
						|
        */
 | 
						|
        if(gpRedMR->hdr.ullSequence > gpRedVolume->ullSequence)
 | 
						|
        {
 | 
						|
            gpRedVolume->ullSequence = gpRedMR->hdr.ullSequence;
 | 
						|
        }
 | 
						|
 | 
						|
        /*  gpRedVolume->ullSequence stores the *next* sequence number; to avoid
 | 
						|
            giving the next node written to disk the same sequence number as the
 | 
						|
            metaroot, increment it here.
 | 
						|
        */
 | 
						|
        ret = RedVolSeqNumIncrement();
 | 
						|
    }
 | 
						|
 | 
						|
    if(ret == 0)
 | 
						|
    {
 | 
						|
        gpRedVolume->fMounted = true;
 | 
						|
      #if REDCONF_READ_ONLY == 0
 | 
						|
        gpRedVolume->fReadOnly = false;
 | 
						|
      #endif
 | 
						|
 | 
						|
      #if RESERVED_BLOCKS > 0U
 | 
						|
        gpRedCoreVol->fUseReservedBlocks = false;
 | 
						|
      #endif
 | 
						|
        gpRedCoreVol->ulAlmostFreeBlocks = 0U;
 | 
						|
 | 
						|
        gpRedCoreVol->aMR[1U - gpRedCoreVol->bCurMR] = *gpRedMR;
 | 
						|
        gpRedCoreVol->bCurMR = 1U - gpRedCoreVol->bCurMR;
 | 
						|
        gpRedMR = &gpRedCoreVol->aMR[gpRedCoreVol->bCurMR];
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** @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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#if REDCONF_READ_ONLY == 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;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#ifdef REDCONF_ENDIAN_SWAP
 | 
						|
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);
 | 
						|
    }
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/** @brief Process a critical file system error.
 | 
						|
 | 
						|
    @param pszFileName  The file in which the error occurred.
 | 
						|
    @param ulLineNum    The line number at which the error occurred.
 | 
						|
*/
 | 
						|
void RedVolCriticalError(
 | 
						|
    const char *pszFileName,
 | 
						|
    uint32_t    ulLineNum)
 | 
						|
{
 | 
						|
  #if REDCONF_OUTPUT == 1
 | 
						|
  #if REDCONF_READ_ONLY == 0
 | 
						|
    if(!gpRedVolume->fReadOnly)
 | 
						|
    {
 | 
						|
        RedOsOutputString("Critical file system error in Reliance Edge, setting volume to READONLY\n");
 | 
						|
    }
 | 
						|
    else
 | 
						|
  #endif
 | 
						|
    {
 | 
						|
        RedOsOutputString("Critical file system error in Reliance Edge (volume already READONLY)\n");
 | 
						|
    }
 | 
						|
  #endif
 | 
						|
 | 
						|
  #if REDCONF_READ_ONLY == 0
 | 
						|
    gpRedVolume->fReadOnly = true;
 | 
						|
  #endif
 | 
						|
 | 
						|
  #if REDCONF_ASSERTS == 1
 | 
						|
    RedOsAssertFail(pszFileName, ulLineNum);
 | 
						|
  #else
 | 
						|
    (void)pszFileName;
 | 
						|
    (void)ulLineNum;
 | 
						|
  #endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/** @brief Increment the sequence number.
 | 
						|
 | 
						|
    @return A negated ::REDSTATUS code indicating the operation result.
 | 
						|
 | 
						|
    @retval 0           Operation was successful.
 | 
						|
    @retval -RED_EINVAL Cannot increment sequence number: maximum value reached.
 | 
						|
                        This should not ever happen.
 | 
						|
*/
 | 
						|
REDSTATUS RedVolSeqNumIncrement(void)
 | 
						|
{
 | 
						|
    REDSTATUS ret;
 | 
						|
 | 
						|
    if(gpRedVolume->ullSequence == UINT64_MAX)
 | 
						|
    {
 | 
						|
        /*  In practice this should never, ever happen; to get here, there would
 | 
						|
            need to be UINT64_MAX disk writes, which would take eons: longer
 | 
						|
            than the lifetime of any product or storage media.  If this assert
 | 
						|
            fires and the current year is still written with four digits,
 | 
						|
            suspect memory corruption.
 | 
						|
        */
 | 
						|
        CRITICAL_ERROR();
 | 
						|
        ret = -RED_EFUBAR;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        gpRedVolume->ullSequence++;
 | 
						|
        ret = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 |