Beispiel #1
0
/** @brief Mount an existing inode.

    Will populate all fields of the cached inode structure, except those which
    are populated during seek.

    @param pInode   A pointer to the cached inode structure.  The
                    pInode->ulInode field must already be initialized with the
                    inode number to mount.  All other fields will be discarded.
    @param type     The expected inode type.
    @param fBranch  Whether to branch the inode.

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

    @retval 0               Operation was successful.
    @retval -RED_EINVAL     Invalid parameters.
    @retval -RED_EROFS      @p fBranch is true but the driver is read-only.
    @retval -RED_EIO        A disk I/O error occurred.
    @retval -RED_EBADF      The inode number is free; or the inode number is not
                            valid.
    @retval -RED_EISDIR     @p type is ::FTYPE_FILE and the inode is a directory.
    @retval -RED_ENOTDIR    @p type is ::FTYPE_DIR and the inode is a file.
*/
REDSTATUS RedInodeMount(
    CINODE     *pInode,
    FTYPE       type,
    bool        fBranch)
{
    REDSTATUS   ret = 0;

    if(pInode == NULL)
    {
        ret = -RED_EINVAL;
    }
    else if(!INODE_IS_VALID(pInode->ulInode))
    {
        ret = -RED_EBADF;
    }
  #if REDCONF_API_FSE == 1
    else if(type == FTYPE_DIR)
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
  #endif
  #if REDCONF_READ_ONLY == 1
    else if(fBranch)
    {
        REDERROR();
        ret = -RED_EROFS;
    }
  #endif
    else
    {
        uint32_t ulInode = pInode->ulInode;
        uint8_t  bWhich = 0U; /* Init'd to quiet warnings. */

        RedMemSet(pInode, 0U, sizeof(*pInode));
        pInode->ulInode = ulInode;

        ret = InodeGetCurrentCopy(pInode->ulInode, &bWhich);

        if(ret == 0)
        {
            ret = RedBufferGet(InodeBlock(pInode->ulInode, bWhich), BFLAG_META_INODE, CAST_VOID_PTR_PTR(&pInode->pInodeBuf));
        }

      #if REDCONF_READ_ONLY == 0
        if(ret == 0)
        {
            ret = InodeIsBranched(pInode->ulInode, &pInode->fBranched);
        }
      #endif

        if(ret == 0)
        {
            if(RED_S_ISREG(pInode->pInodeBuf->uMode))
            {
              #if REDCONF_API_POSIX == 1
                pInode->fDirectory = false;

                if(type == FTYPE_DIR)
                {
                    ret = -RED_ENOTDIR;
                }
              #endif
            }
          #if REDCONF_API_POSIX == 1
            else if(RED_S_ISDIR(pInode->pInodeBuf->uMode))
            {
                pInode->fDirectory = true;

                if(type == FTYPE_FILE)
                {
                    ret = -RED_EISDIR;
                }
            }
          #endif
            else
            {
                /*  Missing or unsupported inode type.
                */
                CRITICAL_ERROR();
                ret = -RED_EFUBAR;
            }
        }

      #if REDCONF_READ_ONLY == 0
        if((ret == 0) && fBranch)
        {
            ret = RedInodeBranch(pInode);
        }
      #endif

        if(ret != 0)
        {
            RedInodePut(pInode, 0U);
        }
    }

    return ret;
}
Beispiel #2
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;
}