Пример #1
0
/** @brief Put the cached inode structure.

    This puts all of the buffers in the ::CINODE structure.  Also updates inode
    timestamp fields if requested.

    @param pInode       The cached inode structure.
    @param bTimeFields  The inode timestamp fields to update.
*/
void RedInodePut(
    CINODE  *pInode,
    uint8_t  bTimeFields)
{
    if(pInode == NULL)
    {
        REDERROR();
    }
    else
    {
        RedInodePutCoord(pInode);

        if(pInode->pInodeBuf != NULL)
        {
          #if (REDCONF_READ_ONLY == 0) && (REDCONF_INODE_TIMESTAMPS == 1)
            if((bTimeFields & IPUT_UPDATE_MASK) != 0U)
            {
                if(!pInode->fBranched || !pInode->fDirty)
                {
                    REDERROR();
                }
                else
                {
                    uint32_t ulNow = RedOsClockGetTime();

                  #if REDCONF_ATIME == 1
                    if((bTimeFields & IPUT_UPDATE_ATIME) != 0U)
                    {
                        pInode->pInodeBuf->ulATime = ulNow;
                    }
                  #endif

                    if((bTimeFields & IPUT_UPDATE_MTIME) != 0U)
                    {
                        pInode->pInodeBuf->ulMTime = ulNow;
                    }

                    if((bTimeFields & IPUT_UPDATE_CTIME) != 0U)
                    {
                        pInode->pInodeBuf->ulCTime = ulNow;
                    }
                }
            }
          #else
            (void)bTimeFields;
          #endif

            RedBufferPut(pInode->pInodeBuf);
            pInode->pInodeBuf = NULL;
        }
    }
}
Пример #2
0
/** @brief Create an inode.

    @param pInode   Pointer to the cached inode structure.  If pInode->ulInode
                    is #INODE_INVALID, a free inode will be found; otherwise,
                    pInode->ulInode will be the inode number (an error will be
                    returned if it is not free).
    @param ulPInode The parent inode number.
    @param uMode    The inode mode.

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

    @retval 0           Operation was successful.
    @retval -RED_EBADF  pInode->ulInode is an invalid inode number other than
                        #INODE_INVALID.
    @retval -RED_EINVAL Invalid parameters.
    @retval -RED_EEXIST Tried to create an inode with an inode number that is
                        already in use.
    @retval -RED_ENFILE All inode slots are already in use.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedInodeCreate(
    CINODE     *pInode,
    uint32_t    ulPInode,
    uint16_t    uMode)
{
    REDSTATUS   ret;

  #if REDCONF_API_POSIX == 1
    /*  ulPInode must be a valid inode number, unless we are creating the root
        directory, in which case ulPInode must be INODE_INVALID (the root
        directory has no parent).
    */
    if(    (pInode == NULL)
        || (!INODE_IS_VALID(ulPInode) && ((ulPInode != INODE_INVALID) || (pInode->ulInode != INODE_ROOTDIR))))
  #else
    if(pInode == NULL)
  #endif
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        uint32_t ulInode = pInode->ulInode;

        RedMemSet(pInode, 0U, sizeof(*pInode));

      #if REDCONF_API_POSIX == 1
        if(ulInode == INODE_INVALID)
        {
            /*  Caller requested that an inode number be allocated.  Search for
                an unused inode number, error if there isn't one.
            */
            ret = InodeFindFree(&pInode->ulInode);
        }
        else
      #endif
        {
            /*  Caller requested creation of a specific inode number.  Make sure
                it's valid and doesn't already exist.
            */
            if(INODE_IS_VALID(ulInode))
            {
                bool fFree;

                ret = RedInodeIsFree(ulInode, &fFree);
                if(ret == 0)
                {
                    if(fFree)
                    {
                        pInode->ulInode = ulInode;
                    }
                    else
                    {
                        ret = -RED_EEXIST;
                    }
                }
            }
            else
            {
                ret = -RED_EBADF;
            }
        }

        if(ret == 0)
        {
            uint8_t bWriteableWhich;

            ret = InodeGetWriteableCopy(pInode->ulInode, &bWriteableWhich);

            if(ret == 0)
            {
                ret = RedBufferGet(InodeBlock(pInode->ulInode, bWriteableWhich),
                    (uint16_t)((uint32_t)BFLAG_META_INODE | BFLAG_DIRTY | BFLAG_NEW), CAST_VOID_PTR_PTR(&pInode->pInodeBuf));

                if(ret == 0)
                {
                    /*  Mark the inode block as allocated.
                    */
                    ret = InodeBitSet(pInode->ulInode, bWriteableWhich, true);

                    if(ret != 0)
                    {
                        RedBufferPut(pInode->pInodeBuf);
                    }
                }
            }
        }

        if(ret == 0)
        {
          #if REDCONF_INODE_TIMESTAMPS == 1
            uint32_t ulNow = RedOsClockGetTime();

            pInode->pInodeBuf->ulATime = ulNow;
            pInode->pInodeBuf->ulMTime = ulNow;
            pInode->pInodeBuf->ulCTime = ulNow;
          #endif

            pInode->pInodeBuf->uMode = uMode;

          #if REDCONF_API_POSIX == 1
          #if REDCONF_API_POSIX_LINK == 1
            pInode->pInodeBuf->uNLink = 1U;
          #endif
            pInode->pInodeBuf->ulPInode = ulPInode;
          #else
            (void)ulPInode;
          #endif

            pInode->fBranched = true;
            pInode->fDirty = true;

          #if REDCONF_API_POSIX == 1
            gpRedMR->ulFreeInodes--;
          #endif
        }
    }

    return ret;
}
Пример #3
0
/** @brief Format a file system volume.

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

    @retval 0           Operation was successful.
    @retval -RED_EBUSY  Volume is mounted.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedVolFormat(void)
{
    REDSTATUS   ret;

    if(gpRedVolume->fMounted)
    {
        ret = -RED_EBUSY;
    }
    else
    {
        ret = RedOsBDevOpen(gbRedVolNum, BDEV_O_RDWR);
    }

    if(ret == 0)
    {
        MASTERBLOCK    *pMB;
        REDSTATUS       ret2;

        /*  Overwrite the master block with zeroes, so that if formatting is
            interrupted, the volume will not be mountable.
        */
        ret = RedBufferGet(BLOCK_NUM_MASTER, BFLAG_NEW | BFLAG_DIRTY, CAST_VOID_PTR_PTR(&pMB));

        if(ret == 0)
        {
            ret = RedBufferFlush(BLOCK_NUM_MASTER, 1U);

            RedBufferDiscard(pMB);
        }

        if(ret == 0)
        {
            ret = RedIoFlush(gbRedVolNum);
        }

      #if REDCONF_IMAP_EXTERNAL == 1
        if((ret == 0) && !gpRedCoreVol->fImapInline)
        {
            uint32_t ulImapBlock;
            uint32_t ulImapBlockLimit = gpRedCoreVol->ulImapStartBN + (gpRedCoreVol->ulImapNodeCount * 2U);
            uint16_t uImapFlags = (uint16_t)((uint32_t)BFLAG_META_IMAP | BFLAG_NEW | BFLAG_DIRTY);

            /*  Technically it is only necessary to create one copy of each imap
                node (the copy the metaroot points at), but creating them both
                avoids headaches during disk image analysis from stale imaps
                left over from previous formats.
            */
            for(ulImapBlock = gpRedCoreVol->ulImapStartBN; ulImapBlock < ulImapBlockLimit; ulImapBlock++)
            {
                IMAPNODE   *pImap;

                ret = RedBufferGet(ulImapBlock, uImapFlags, CAST_VOID_PTR_PTR(&pImap));
                if(ret != 0)
                {
                    break;
                }

                RedBufferPut(pImap);
            }
        }
      #endif

        /*  Write the first metaroot.
        */
        if(ret == 0)
        {
            RedMemSet(gpRedMR, 0U, sizeof(*gpRedMR));

            gpRedMR->ulFreeBlocks = gpRedVolume->ulBlocksAllocable;
          #if REDCONF_API_POSIX == 1
            gpRedMR->ulFreeInodes = gpRedVolConf->ulInodeCount;
          #endif
            gpRedMR->ulAllocNextBlock = gpRedCoreVol->ulFirstAllocableBN;

            /*  The branched flag is typically set automatically when bits in
                the imap change.  It is set here explicitly because the imap has
                only been initialized, not changed.
            */
            gpRedCoreVol->fBranched = true;

            ret = RedVolTransact();
        }

      #if REDCONF_API_POSIX == 1
        /*  Create the root directory.
        */
        if(ret == 0)
        {
            CINODE rootdir;

            rootdir.ulInode = INODE_ROOTDIR;
            ret = RedInodeCreate(&rootdir, INODE_INVALID, RED_S_IFDIR);

            if(ret == 0)
            {
                RedInodePut(&rootdir, 0U);
            }
        }
      #endif

      #if REDCONF_API_FSE == 1
        /*  The FSE API does not support creating or deletes files, so all the
            inodes are created during setup.
        */
        if(ret == 0)
        {
            uint32_t ulInodeIdx;

            for(ulInodeIdx = 0U; ulInodeIdx < gpRedVolConf->ulInodeCount; ulInodeIdx++)
            {
                CINODE ino;

                ino.ulInode = INODE_FIRST_FREE + ulInodeIdx;
                ret = RedInodeCreate(&ino, INODE_INVALID, RED_S_IFREG);

                if(ret == 0)
                {
                    RedInodePut(&ino, 0U);
                }
            }
        }
      #endif

        /*  Write the second metaroot.
        */
        if(ret == 0)
        {
            ret = RedVolTransact();
        }

        /*  Populate and write out the master block.
        */
        if(ret == 0)
        {
            ret = RedBufferGet(BLOCK_NUM_MASTER, (uint16_t)((uint32_t)BFLAG_META_MASTER | BFLAG_NEW | BFLAG_DIRTY), CAST_VOID_PTR_PTR(&pMB));
        }

        if(ret == 0)
        {
            pMB->ulVersion = RED_DISK_LAYOUT_VERSION;
            RedStrNCpy(pMB->acBuildNum, RED_BUILD_NUMBER, sizeof(pMB->acBuildNum));
            pMB->ulFormatTime = RedOsClockGetTime();
            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;

          #if REDCONF_API_POSIX == 1
            pMB->bFlags |= MBFLAG_API_POSIX;
          #endif
          #if REDCONF_INODE_TIMESTAMPS == 1
            pMB->bFlags |= MBFLAG_INODE_TIMESTAMPS;
          #endif
          #if REDCONF_INODE_BLOCKS == 1
            pMB->bFlags |= MBFLAG_INODE_BLOCKS;
          #endif
          #if (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1)
            pMB->bFlags |= MBFLAG_INODE_NLINK;
          #endif

            ret = RedBufferFlush(BLOCK_NUM_MASTER, 1U);

            RedBufferPut(pMB);
        }

        if(ret == 0)
        {
            ret = RedIoFlush(gbRedVolNum);
        }

        ret2 = RedOsBDevClose(gbRedVolNum);
        if(ret == 0)
        {
            ret = ret2;
        }
    }

    /*  Discard the buffers so a subsequent format will not run into blocks it
        does not expect.
    */
    if(ret == 0)
    {
        ret = RedBufferDiscardRange(0U, gpRedVolume->ulBlockCount);
    }

    return ret;
}