REDSTATUS RedDirEntryRename()

in FreeRTOS-Plus/Source/Reliance-Edge/core/driver/dir.c [619:762]


REDSTATUS RedDirEntryRename(
    CINODE     *pSrcPInode,
    const char *pszSrcName,
    CINODE     *pSrcInode,
    CINODE     *pDstPInode,
    const char *pszDstName,
    CINODE     *pDstInode)
{
    REDSTATUS   ret;

    if(    !CINODE_IS_DIRTY(pSrcPInode)
        || (pszSrcName == NULL)
        || (pSrcInode == NULL)
        || !CINODE_IS_DIRTY(pDstPInode)
        || (pszDstName == NULL)
        || (pDstInode == NULL))
    {
        ret = -RED_EINVAL;
    }
    else if(!pSrcPInode->fDirectory || !pDstPInode->fDirectory)
    {
        ret = -RED_ENOTDIR;
    }
    else
    {
        uint32_t ulDstIdx = 0U; /* Init'd to quiet warnings. */
        uint32_t ulSrcIdx;

        /*  Look up the source and destination names.
        */
        ret = RedDirEntryLookup(pSrcPInode, pszSrcName, &ulSrcIdx, &pSrcInode->ulInode);

        if(ret == 0)
        {
            ret = RedDirEntryLookup(pDstPInode, pszDstName, &ulDstIdx, &pDstInode->ulInode);

            if(ret == -RED_ENOENT)
            {
                if(ulDstIdx == DIR_INDEX_INVALID)
                {
                    ret = -RED_ENOSPC;
                }
                else
                {
                  #if REDCONF_RENAME_ATOMIC == 1
                    pDstInode->ulInode = INODE_INVALID;
                  #endif
                    ret = 0;
                }
            }
          #if REDCONF_RENAME_ATOMIC == 0
            else if(ret == 0)
            {
                ret = -RED_EEXIST;
            }
            else
            {
                /*  Nothing to do here, just propagate the error.
                */
            }
          #endif
        }

      #if REDCONF_RENAME_ATOMIC == 1
        /*  If both names point to the same inode, POSIX says to do nothing to
            either name.
        */
        if((ret == 0) && (pSrcInode->ulInode != pDstInode->ulInode))
      #else
        if(ret == 0)
      #endif
        {
            ret = RedInodeMount(pSrcInode, FTYPE_EITHER, true);

          #if REDCONF_RENAME_ATOMIC == 1
            if((ret == 0) && (pDstInode->ulInode != INODE_INVALID))
            {
                /*  Source and destination must be the same type (file/dir).
                */
                ret = RedInodeMount(pDstInode, pSrcInode->fDirectory ? FTYPE_DIR : FTYPE_FILE, true);

                /*  If renaming directories, the destination must be empty.
                */
                if((ret == 0) && pDstInode->fDirectory && (pDstInode->pInodeBuf->ullSize > 0U))
                {
                    ret = -RED_ENOTEMPTY;
                }
            }
          #endif

            /*  If we are renaming a directory, make sure the rename isn't
                cyclic (e.g., renaming "foo" into "foo/bar").
            */
            if((ret == 0) && pSrcInode->fDirectory)
            {
                ret = DirCyclicRenameCheck(pSrcInode->ulInode, pDstPInode);
            }

            if(ret == 0)
            {
                ret = DirEntryWrite(pDstPInode, ulDstIdx, pSrcInode->ulInode, pszDstName, RedNameLen(pszDstName));
            }

            if(ret == 0)
            {
                ret = RedDirEntryDelete(pSrcPInode, ulSrcIdx);

                if(ret == -RED_ENOSPC)
                {
                    REDSTATUS ret2;

                    /*  If there was not enough space to branch the parent
                        directory inode and data block containin the source
                        entry, revert destination directory entry to its
                        previous state.
                    */
                  #if REDCONF_RENAME_ATOMIC == 1
                    if(pDstInode->ulInode != INODE_INVALID)
                    {
                        ret2 = DirEntryWrite(pDstPInode, ulDstIdx, pDstInode->ulInode, pszDstName, RedNameLen(pszDstName));
                    }
                    else
                  #endif
                    {
                        ret2 = RedDirEntryDelete(pDstPInode, ulDstIdx);
                    }

                    if(ret2 != 0)
                    {
                        ret = ret2;
                        CRITICAL_ERROR();
                    }
                }
            }

            if(ret == 0)
            {
                pSrcInode->pInodeBuf->ulPInode = pDstPInode->ulInode;
            }
        }
    }

    return ret;
}