static REDSTATUS Shrink()

in FreeRTOS-Plus/Source/Reliance-Edge/core/driver/inodedata.c [420:518]


static REDSTATUS Shrink(
    CINODE     *pInode,
    uint64_t    ullSize)
{
    REDSTATUS   ret = 0;

    /*  pInode->fDirty is checked explicitly here, instead of using the
        CINODE_IS_DIRTY() macro, to avoid a duplicate mount check.
    */
    if(!CINODE_IS_MOUNTED(pInode) || ((ullSize > 0U) && !pInode->fDirty))
    {
        REDERROR();
        ret = -RED_EINVAL;
    }
    else
    {
        uint32_t ulTruncBlock = (uint32_t)((ullSize + REDCONF_BLOCK_SIZE - 1U) >> BLOCK_SIZE_P2);

        RedInodePutData(pInode);

      #if REDCONF_DIRECT_POINTERS > 0U
        while(ulTruncBlock < REDCONF_DIRECT_POINTERS)
        {
            ret = TruncDataBlock(pInode, &pInode->pInodeBuf->aulEntries[ulTruncBlock], true);

            if(ret != 0)
            {
                break;
            }

            ulTruncBlock++;
        }
      #endif

      #if REDCONF_INDIRECT_POINTERS > 0U
        while((ret == 0) && (ulTruncBlock < (REDCONF_DIRECT_POINTERS + INODE_INDIR_BLOCKS)))
        {
            ret = RedInodeDataSeek(pInode, ulTruncBlock);

            if((ret == 0) || (ret == -RED_ENODATA))
            {
                bool fFreed;

                ret = TruncIndir(pInode, &fFreed);

                if(ret == 0)
                {
                    if(fFreed)
                    {
                        pInode->pInodeBuf->aulEntries[pInode->uInodeEntry] = BLOCK_SPARSE;
                    }

                    /*  The next seek will go to the beginning of the next
                        indirect.
                    */
                    ulTruncBlock += (INDIR_ENTRIES - pInode->uIndirEntry);
                }
            }
        }
      #endif

      #if DINDIR_POINTERS > 0U
        while((ret == 0) && (ulTruncBlock < INODE_DATA_BLOCKS))
        {
            ret = RedInodeDataSeek(pInode, ulTruncBlock);

            if((ret == 0) || (ret == -RED_ENODATA))
            {
                bool fFreed;

                /*  TruncDindir() invokes seek as it goes along, which will
                    update the entry values (possibly all three of these);
                    make a copy so we can compute things correctly after.
                */
                uint16_t uOrigInodeEntry = pInode->uInodeEntry;
                uint16_t uOrigDindirEntry = pInode->uDindirEntry;
                uint16_t uOrigIndirEntry = pInode->uIndirEntry;

                ret = TruncDindir(pInode, &fFreed);

                if(ret == 0)
                {
                    if(fFreed)
                    {
                        pInode->pInodeBuf->aulEntries[uOrigInodeEntry] = BLOCK_SPARSE;
                    }

                    /*  The next seek will go to the beginning of the next
                        double indirect.
                    */
                    ulTruncBlock += (DINDIR_DATA_BLOCKS - (uOrigDindirEntry * INDIR_ENTRIES)) - uOrigIndirEntry;
                }
            }
        }
      #endif
    }

    return ret;
}