static REDSTATUS FildesOpen()

in FreeRTOS-Plus/Source/Reliance-Edge/posix/posix.c [2372:2556]


static REDSTATUS FildesOpen(
    const char *pszPath,
    uint32_t    ulOpenMode,
    FTYPE       type,
    int32_t    *piFildes)
{
    uint8_t     bVolNum;
    const char *pszLocalPath;
    REDSTATUS   ret;

    ret = RedPathSplit(pszPath, &bVolNum, &pszLocalPath);

    if(ret == 0)
    {
        if(piFildes == NULL)
        {
            ret = -RED_EINVAL;
        }
      #if REDCONF_READ_ONLY == 0
        else if(gaRedVolume[bVolNum].fReadOnly && (ulOpenMode != RED_O_RDONLY))
        {
            ret = -RED_EROFS;
        }
      #endif
        else
        {
            uint16_t    uHandleIdx;
            REDHANDLE  *pHandle = NULL;

            /*  Search for an unused handle.
            */
            for(uHandleIdx = 0U; uHandleIdx < REDCONF_HANDLE_COUNT; uHandleIdx++)
            {
                if(gaHandle[uHandleIdx].ulInode == INODE_INVALID)
                {
                    pHandle = &gaHandle[uHandleIdx];
                    break;
                }
            }

            /*  Error if all the handles are in use.
            */
            if(pHandle == NULL)
            {
                ret = -RED_EMFILE;
            }
            else
            {
                bool        fCreated = false;
                uint16_t    uMode = 0U;
                uint32_t    ulInode = 0U;       /* Init'd to quiet warnings. */

              #if REDCONF_VOLUME_COUNT > 1U
                ret = RedCoreVolSetCurrent(bVolNum);
                if(ret == 0)
              #endif
                {
                  #if REDCONF_READ_ONLY == 0
                    if((ulOpenMode & RED_O_CREAT) != 0U)
                    {
                        uint32_t    ulPInode;
                        const char *pszName;

                        ret = RedPathToName(pszLocalPath, &ulPInode, &pszName);
                        if(ret == 0)
                        {
                            ret = RedCoreCreate(ulPInode, pszName, false, &ulInode);
                            if(ret == 0)
                            {
                                fCreated = true;
                            }
                            else if((ret == -RED_EEXIST) && ((ulOpenMode & RED_O_EXCL) == 0U))
                            {
                                /*  If the path already exists and that's OK,
                                    lookup its inode number.
                                */
                                ret = RedCoreLookup(ulPInode, pszName, &ulInode);
                            }
                            else
                            {
                                /*  No action, just propagate the error.
                                */
                            }
                        }
                    }
                    else
                  #endif
                    {
                        ret = RedPathLookup(pszLocalPath, &ulInode);
                    }
                }

                /*  If we created the inode, none of the below stuff is
                    necessary.  This is important from an error handling
                    perspective -- we do not need code to delete the created
                    inode on error.
                */
                if(!fCreated)
                {
                    if(ret == 0)
                    {
                        REDSTAT s;

                        ret = RedCoreStat(ulInode, &s);
                        if(ret == 0)
                        {
                            uMode = s.st_mode;
                        }
                    }

                    /*  Error if the inode is not of the expected type.
                    */
                    if(ret == 0)
                    {
                        ret = ModeTypeCheck(uMode, type);
                    }

                    /*  Directories must always be opened with O_RDONLY.
                    */
                    if((ret == 0) && RED_S_ISDIR(uMode) && ((ulOpenMode & RED_O_RDONLY) == 0U))
                    {
                        ret = -RED_EISDIR;
                    }

                  #if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_FTRUNCATE == 1)
                    if((ret == 0) && ((ulOpenMode & RED_O_TRUNC) != 0U))
                    {
                        ret = RedCoreFileTruncate(ulInode, UINT64_SUFFIX(0));
                    }
                  #endif
                }

                if(ret == 0)
                {
                    int32_t iFildes;

                    RedMemSet(pHandle, 0U, sizeof(*pHandle));

                    /*  Populate this handle, marking it as in use.
                    */
                    pHandle->ulInode = ulInode;
                    pHandle->bVolNum = bVolNum;

                    if(RED_S_ISDIR(uMode))
                    {
                        pHandle->bFlags |= HFLAG_DIRECTORY;
                    }

                    if(((ulOpenMode & RED_O_RDONLY) != 0U) || ((ulOpenMode & RED_O_RDWR) != 0U))
                    {
                        pHandle->bFlags |= HFLAG_READABLE;
                    }

                  #if REDCONF_READ_ONLY == 0
                    if(((ulOpenMode & RED_O_WRONLY) != 0U) || ((ulOpenMode & RED_O_RDWR) != 0U))
                    {
                        pHandle->bFlags |= HFLAG_WRITEABLE;
                    }

                    if((ulOpenMode & RED_O_APPEND) != 0U)
                    {
                        pHandle->bFlags |= HFLAG_APPENDING;
                    }
                  #endif

                    iFildes = FildesPack(uHandleIdx, bVolNum);
                    if(iFildes == -1)
                    {
                        /*  It should be impossible to get here, unless there
                            is memory corruption.
                        */
                        REDERROR();
                        ret = -RED_EFUBAR;
                    }
                    else
                    {
                        *piFildes = iFildes;
                    }
                }
            }
        }
    }

    return ret;
}