
/**
@file shell_file.c
@brief Shell file process.
*/
/********************************************************************************************
Debug Switch Definition Section
********************************************************************************************/


/********************************************************************************************
Include File Section
********************************************************************************************/
#include "main.h"
#include "shell_char.h"
#include "shell_mem.h"
#include "shell_inode.h"
#include "shell_core.h"
#include "shell_file.h"

/********************************************************************************************
Macro Definition Section
********************************************************************************************/
#define MAX_FILE_COUNT              (64)
#define MAX_FILE_BTMAP_CNT          (MAX_FILE_COUNT/MEM_BIT_MAP_WIDTH)

/********************************************************************************************
Prototype Declaration Section
********************************************************************************************/
INODE_STATUS xShellFileMemCreate(void);
int32_t lShellFileMemAlloc(SHELL_INODE *inode, uint8_t mode);
SHELL_FILE * pxShellGetFileStruct(int32_t fd);
int32_t lShellOpen(const uint8_t *name, uint8_t mode, uint8_t counter);
uint32_t ulShellRead(int32_t fd, uint8_t *buffer, uint32_t size,uint8_t counter);
uint32_t ulShellWrite(int32_t fd, uint8_t *buffer, uint32_t size);
uint32_t ulShellLseek(int32_t fd, uint32_t offset, uint8_t whence);
int32_t lShellIoctl(int32_t fd, uint32_t cmd, uint32_t arg);
int32_t lShellClose(int32_t fd,uint8_t counter);
/********************************************************************************************
Const Global Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Global Variable Definition Section
********************************************************************************************/

/********************************************************************************************
Static Variable Definition Section
********************************************************************************************/
static uint8_t s_aucFileMemBlock[MAX_FILE_COUNT * sizeof(SHELL_FILE)];
static uint8_t s_aucFileMemBlockMap[MAX_FILE_BTMAP_CNT];
static SHELL_MEM_CB s_xFileMemCb;
/********************************************************************************************
Structure Type Definition Section
********************************************************************************************/

/********************************************************************************************
Function Definition Section
********************************************************************************************/
/**
 * xShellFileMemCreate
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
INODE_STATUS xShellFileMemCreate(void)
{
    INODE_STATUS ret = INODE_SUCESS;
    if(PROC_SUCESS != xShellMemInit(&s_xFileMemCb, &s_aucFileMemBlock[0], MAX_FILE_COUNT, sizeof(SHELL_FILE), \
                                      &s_aucFileMemBlockMap[0], MAX_FILE_BTMAP_CNT))
    {
        ret = INODE_MEM_ERR;
    }
    else
    {
        ;
    }
    return ret;
}

/**
 * xShellFileMemCreate
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
int32_t lShellFileMemAlloc(SHELL_INODE *inode, uint8_t mode)
{
	SHELL_FILE *fp = SAF_NULL;
    SHELL_STATUS rslt = PROC_SUCESS;
    int32_t fd = 0;

    fp = (SHELL_FILE *)pvShellMemGet(&s_xFileMemCb, &rslt);
    if(rslt == PROC_SUCESS)
    {
        fp->f_lofft = 0;
        fp->f_privatedata = SAF_NULL;
        fp->f_mode = mode;
        fp->f_ops = inode->f_ops;
        fp->f_flags = 0;
        fd = ((uint8_t *)fp -  s_xFileMemCb.pMem) / s_xFileMemCb.MemBlkSize;    /*calulate index*/
    }
    else
    {
        fd = FILE_GET_MEM_ERR;
    }

    return fd;
}

/**
 * pxShellGetFileStruct
 * Author qiuxf
 * @param *lock pointer to loexternck
 * @return status
 */
SHELL_FILE * pxShellGetFileStruct(int32_t fd)
{
    return (SHELL_FILE *)pucShellMemGetIndex(&s_xFileMemCb, fd);
}

/**
 * lShellOpen
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
int32_t lShellOpen(const uint8_t *name, uint8_t mode, uint8_t counter)
{
    INODE_STATUS rslt;
    int32_t fd = 0;
    SHELL_AUTHOR author = xShellGetAuthor();
    int32_t openret = 0;
    SHELL_INODE *inode = pxShellInodelookup(name, &rslt);

    if(INODE_SUCESS == rslt)
    {
        /*mode check*/
        uint8_t curmode = author == AUTHOR_USER ? inode->mode.i_mode_user : inode->mode.i_mode_root;

        if(((mode & F_READ_MASK) <= (curmode & F_READ_MASK)) &&\
            ((mode & F_WRITE_MASK) <= (curmode & F_WRITE_MASK))&&\
                ((mode & F_IOCTL_MASK) <= (curmode & F_IOCTL_MASK)))
        {
            /*create file struct*/
            fd = lShellFileMemAlloc(inode, mode);
            /*open file*/
            if(SAF_NULL != inode->f_ops->open)
            {
                openret = inode->f_ops->open(inode, (SHELL_FILE *)&s_xFileMemCb.pMem[fd * s_xFileMemCb.MemBlkSize],counter);
                if(FILE_OK != openret)
                {
                    fd =  FILE_OPEN_FAILD;
                    
                }
                else
                {
                    ; /*return fd*/
                }
            }
            else
            {
                fd = FILE_NO_OPEN;
            }
        }
        else
        {
            fd = FILE_MODE_ERROR; /*mode error*/            
        }
    }
    else
    {
        fd = FILE_NOT_ASSIST;      
    }
    return fd;
}

/**
 * ulShellRead
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
uint32_t ulShellRead(int32_t fd, uint8_t *buffer, uint32_t size,uint8_t counter)
{
	SHELL_FILE *filp = (SHELL_FILE *)&s_xFileMemCb.pMem[fd * s_xFileMemCb.MemBlkSize];
    uint32_t ret = 0;

    if(0 != (filp->f_mode & F_READ_MASK))
    {
		if(SAF_NULL != filp->f_ops->read)
		{
			ret = filp->f_ops->read(filp, buffer, size, &filp->f_lofft,counter);
		}
    }
    else
    {
    	printk("File Permission Error\r\n");
    }
    return ret;
}

/**
 * ulShellRead
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
uint32_t ulShellWrite(int32_t fd, uint8_t *buffer, uint32_t size)
{
	SHELL_FILE *filp = (SHELL_FILE *)&s_xFileMemCb.pMem[fd * s_xFileMemCb.MemBlkSize];
    uint32_t ret = 0;

    if(0 != (filp->f_mode & F_WRITE_MASK))
    {
		if(SAF_NULL != filp->f_ops->write)
		{
			ret = filp->f_ops->write(filp, (const uint8_t *)buffer, size, &filp->f_lofft);
		}
    }
    else
    {
    	printk("File Permission Error\r\n");;
    }

    return ret;
}

/**
 * ulShellRead
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
uint32_t ulShellLseek(int32_t fd, uint32_t offset, uint8_t whence)
{
	SHELL_FILE *filp = (SHELL_FILE *)&s_xFileMemCb.pMem[fd * s_xFileMemCb.MemBlkSize];
	uint32_t ret = 0;

	if(SAF_NULL != filp->f_ops->llseek)
	{
		ret = filp->f_ops->llseek(filp, offset, whence);
	}
	else
	{
		;
	}

	return ret;
}
/**
 * ulShellRead
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
int32_t lShellIoctl(int32_t fd, uint32_t cmd, uint32_t arg)
{
	SHELL_FILE *filp = (SHELL_FILE *)&s_xFileMemCb.pMem[fd * s_xFileMemCb.MemBlkSize];
    uint32_t ret = 0;

    if(0 != (filp->f_mode & F_IOCTL_MASK))
    {
		if(SAF_NULL != filp->f_ops->ioctl)
		{
			ret = filp->f_ops->ioctl(filp, cmd, arg);
		}
    }
    else
    {
    	printk("File Permission Error\r\n");
    }

    return ret;
}

/**
 * lShellClose
 * Author qiuxf
 * @param *lock pointer to lock
 * @return status
 */
int32_t lShellClose(int32_t fd,uint8_t counter)
{
	SHELL_FILE *filp = (SHELL_FILE *)&s_xFileMemCb.pMem[fd * s_xFileMemCb.MemBlkSize];
    uint32_t ret = 0;

    if(SAF_NULL != filp->f_ops->close)
    {
        filp->f_ops->close(filp,counter);
    }

    /*release mem*/
    (void)xShellMemPut(&s_xFileMemCb,  (void *)filp);
    return ret;
}
