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;
}