REDSTATUS RedDirEntryLookup()

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


REDSTATUS RedDirEntryLookup(
    CINODE     *pPInode,
    const char *pszName,
    uint32_t   *pulEntryIdx,
    uint32_t   *pulInode)
{
    REDSTATUS   ret = 0;

    if(!CINODE_IS_MOUNTED(pPInode) || (pszName == NULL))
    {
        ret = -RED_EINVAL;
    }
    else if(!pPInode->fDirectory)
    {
        ret = -RED_ENOTDIR;
    }
    else
    {
        uint32_t ulNameLen = RedNameLen(pszName);

        if(ulNameLen == 0U)
        {
            ret = -RED_EINVAL;
        }
        else if(ulNameLen > REDCONF_NAME_MAX)
        {
            ret = -RED_ENAMETOOLONG;
        }
        else
        {
            uint32_t    ulIdx = 0U;
            uint32_t    ulDirentCount = DirOffsetToEntryIndex(pPInode->pInodeBuf->ullSize);
            uint32_t    ulFreeIdx = DIR_INDEX_INVALID;  /* Index of first free dirent. */

            /*  Loop over the directory blocks, searching each block for a
                dirent that matches the given name.
            */
            while((ret == 0) && (ulIdx < ulDirentCount))
            {
                ret = RedInodeDataSeekAndRead(pPInode, ulIdx / DIRENTS_PER_BLOCK);

                if(ret == 0)
                {
                    const DIRENT *pDirents = CAST_CONST_DIRENT_PTR(pPInode->pbData);
                    uint32_t      ulBlockLastIdx = REDMIN(DIRENTS_PER_BLOCK, ulDirentCount - ulIdx);
                    uint32_t      ulBlockIdx;

                    for(ulBlockIdx = 0U; ulBlockIdx < ulBlockLastIdx; ulBlockIdx++)
                    {
                        const DIRENT *pDirent = &pDirents[ulBlockIdx];

                        if(pDirent->ulInode != INODE_INVALID)
                        {
                            /*  The name in the dirent will not be null
                                terminated if it is of the maximum length, so
                                use a bounded string compare and then make sure
                                there is nothing more to the name.
                            */
                            if(    (RedStrNCmp(pDirent->acName, pszName, ulNameLen) == 0)
                                && ((ulNameLen == REDCONF_NAME_MAX) || (pDirent->acName[ulNameLen] == '\0')))
                            {
                                /*  Found a matching dirent, stop and return its
                                    information.
                                */
                                if(pulInode != NULL)
                                {
                                    *pulInode = pDirent->ulInode;

                                  #ifdef REDCONF_ENDIAN_SWAP
                                    *pulInode = RedRev32(*pulInode);
                                  #endif
                                }

                                ulIdx += ulBlockIdx;
                                break;
                            }
                        }
                        else if(ulFreeIdx == DIR_INDEX_INVALID)
                        {
                            ulFreeIdx = ulIdx + ulBlockIdx;
                        }
                        else
                        {
                            /*  The directory entry is free, but we already found a free one, so there's
                                nothing to do here.
                            */
                        }
                    }

                    if(ulBlockIdx < ulBlockLastIdx)
                    {
                        /*  If we broke out of the for loop, we found a matching
                            dirent and can stop the search.
                        */
                        break;
                    }

                    ulIdx += ulBlockLastIdx;
                }
                else if(ret == -RED_ENODATA)
                {
                    if(ulFreeIdx == DIR_INDEX_INVALID)
                    {
                        ulFreeIdx = ulIdx;
                    }

                    ret = 0;
                    ulIdx += DIRENTS_PER_BLOCK;
                }
                else
                {
                    /*  Unexpected error, let the loop terminate, no action
                        here.
                    */
                }
            }

            if(ret == 0)
            {
                /*  If we made it all the way to the end of the directory
                    without stopping, then the given name does not exist in the
                    directory.
                */
                if(ulIdx == ulDirentCount)
                {
                    /*  If the directory had no sparse dirents, then the first
                        free dirent is beyond the end of the directory.  If the
                        directory is already the maximum size, then there is no
                        free dirent.
                    */
                    if((ulFreeIdx == DIR_INDEX_INVALID) && (ulDirentCount < DIRENTS_MAX))
                    {
                        ulFreeIdx = ulDirentCount;
                    }

                    ulIdx = ulFreeIdx;

                    ret = -RED_ENOENT;
                }

                if(pulEntryIdx != NULL)
                {
                    *pulEntryIdx = ulIdx;
                }
            }
        }
    }

    return ret;
}