⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 testfs.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
        nd->refcnt++;

        // Pass it out
        *dir_out = (cyg_dir)nd;
    }
    else
    {
        // If no output dir is required, this means that the mte and
        // dir arguments are the current cdir setting and we should
        // forget this fact.

        testfs_node *nd = (testfs_node *)dir;

        // Just decrement reference count.
        nd->refcnt--;
    }
        
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
                          struct stat *buf)
{
    testfs_node *nd, *parent;
    int err;
    char name[TESTFS_NAMESIZE];
    cyg_bool lastp;
    
    err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );

    if( err != ENOERR ) return err;

    *buf = nd->status;
    
    return err;
}

// -------------------------------------------------------------------------

static int testfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
                          int key, void *buf, int len )
{
    return ENOSYS;
}

// -------------------------------------------------------------------------

static int testfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
                          int key, void *buf, int len )
{
    return ENOSYS;
}


//==========================================================================
// File operations


// -------------------------------------------------------------------------

static int testfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
    testfs_node *nd = (testfs_node *)fp->f_data;
    int i;
    off_t pos = fp->f_offset;

    for( i = 0; i < uio->uio_iovcnt; i++ )
    {
        cyg_iovec *iov = &uio->uio_iov[i];
        char *buf = (char *)iov->iov_base;
        off_t len = iov->iov_len;

        while( len > 0 && pos < nd->status.st_size )
        {
            testfs_block *b = nd->u.file.data[pos/TESTFS_BLOCKSIZE];
            off_t l = len;
            off_t bpos = pos%TESTFS_BLOCKSIZE;
            
            // If there is no block in that pos, we have reached
            // the end of the file.
            if( b == NULL ) return ENOERR;

            // adjust size to this block
            if( l > (b->size-bpos) )
                l = (b->size-bpos);

            // copy data out
            memcpy( buf, &b->data[bpos], l );

            uio->uio_resid -= l;
            len -= l;
            buf += l;
            pos += l;

            // keep offset up to date incase of errors
            fp->f_offset = pos;
        }
    }
    
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
    testfs_node *nd = (testfs_node *)fp->f_data;
    int i;
    off_t pos = fp->f_offset;
    
    // Check we are not at end of allowed max file size
    if( pos >= TESTFS_FILESIZE_MAX )
        return EFBIG;

    // Check that pos is within current file size, or at the very end.
    if( pos < 0 || pos > nd->status.st_size )
        return EINVAL;

    // Now loop over the iovecs until they are all done, or
    // we get an error.
    for( i = 0; i < uio->uio_iovcnt; i++ )
    {
        cyg_iovec *iov = &uio->uio_iov[i];
        char *buf = (char *)iov->iov_base;
        off_t len = iov->iov_len;

        while( len > 0 )
        {
            testfs_block *b = nd->u.file.data[pos/TESTFS_BLOCKSIZE];
            off_t l = len;
            off_t bpos = pos%TESTFS_BLOCKSIZE;
            
            // If there is no block in that pos, allocate one
            // and initialize it
            if( b == NULL )
            {
                b = free_block;
                if( b == NULL ) return ENOSPC;
                free_block = b->u.next;
                nd->u.file.data[pos/TESTFS_BLOCKSIZE] = b;
                b->u.file = nd;
                b->pos = pos;
                b->size = 0;
            }

            // adjust size to this block
            if( l > (TESTFS_BLOCKSIZE-bpos) )
                l = (TESTFS_BLOCKSIZE-bpos);

            // copy data in
            memcpy( &b->data[bpos], buf, l );

            // adjust buffer info
            if( b->size < bpos+l )
                b->size = bpos+l;
            
            uio->uio_resid -= l;
            len -= l;
            buf += l;
            pos += l;

            // keep node size and file offset up to date
            //in case of an error.
            if( pos > nd->status.st_size )
                nd->status.st_size = pos;
            fp->f_offset = pos;

            if( pos >= TESTFS_FILESIZE_MAX )
                return EFBIG;
        }
    }
    
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
{
    testfs_node *nd = (testfs_node *)fp->f_data;
    off_t pos = *apos;

    switch( whence )
    {
    case SEEK_SET:
        // we are already where we want to be.
        break;

    case SEEK_CUR:
        pos += fp->f_offset;
        break;

    case SEEK_END:
        pos += nd->status.st_size;
        break;

    default:
        return EINVAL;
    }
    
    // Check that pos is within current file size, or at the very end.
    if( pos < 0 || pos > nd->status.st_size )
        return EINVAL;

    // All OK, set fp offset.
    *apos = fp->f_offset = pos;
    
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
                             CYG_ADDRWORD data)
{
    return ENOSYS;
}

// -------------------------------------------------------------------------

static int testfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode )
{
    // Nothing to do
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_close     (struct CYG_FILE_TAG *fp)
{
    testfs_node *nd = (testfs_node *)fp->f_data;

    nd->refcnt--;       // remove open count

    fp->f_data = 0;     // clear data pointer
    
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf )
{
    testfs_node *nd = (testfs_node *)fp->f_data;

    *buf = nd->status;    
    
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
{
    return ENOERR;
}


//==========================================================================
// Directory operations

static int testfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
    testfs_node *nd = (testfs_node *)fp->f_data;
    off_t pos = fp->f_offset;
    cyg_iovec *iov = &uio->uio_iov[0];
    char *buf = (char *)iov->iov_base;
    off_t len = iov->iov_len;

    // End of directory
    if( pos >= TESTFS_FILEBLOCKS )
        return ENOERR;

    if( len < sizeof(struct dirent) )
        return EINVAL;
    
    for( ; pos < TESTFS_FILEBLOCKS; pos++ )
        if( nd->u.dir.nodes[pos] != NULL )
        {
            struct dirent *ent = (struct dirent *)buf;
            strcpy( ent->d_name, nd->u.dir.nodes[pos]->name );
            uio->uio_resid -= sizeof(struct dirent);
            break;
        }

    fp->f_offset = pos+1;
    
    return ENOERR;
}

// -------------------------------------------------------------------------

static int testfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
{
    if( whence != SEEK_SET || *pos != 0)
        return EINVAL;

    *pos = fp->f_offset = 0;
    
    return ENOERR;
}

//==========================================================================
// Filesystem dump
// Dumps out the node and block arrays in a readable format, and does
// a little consistency checking as it goes.

void testfs_dump(void)
{
    int errors = 0;
    int i;
    char *indent = "\n                      |";

    diag_printf("Nodes:\n");
    for( i = 0; i < TESTFS_NFILE; i++ )
    {
        testfs_node *nd = &node[i];

        diag_printf("%3d : ",i);
        if( nd->refcnt < 0 )
            diag_printf("<free>");
        else if( !S_ISDIR(nd->status.st_mode) )
        {
            // Regular file
            int j;
            diag_printf("f %8s %4d |",nd->name,nd->status.st_size);
            for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
            {
                testfs_block *b = nd->u.file.data[j];
                if( b != NULL )
                {
                    if( j > 0 && (j%4) == 0 )
                        diag_printf(indent);
                    diag_printf(" %3d[%3d,%3d]",b-block,b->pos,b->size);
                    if( b->u.file != nd )
                    {
                        errors++;
                        diag_printf("!");
                    }
                }
            }
        }
        else
        {
            // Directory
            int j;
            int rc = 1;
            diag_printf("d %8s      |",nd->name);

            for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
            {
                testfs_node *n = nd->u.dir.nodes[j];
                if( n != NULL )
                {
                    if( j > 0 && (j%4) == 0 )
                        diag_printf(indent);
                    diag_printf(" %3d[%7s]",n-node,n->name);
                    rc++;
                }
            }

            if( nd->refcnt != rc )
            {
                diag_printf("%s refcount is %d should be %d",indent,nd->refcnt,rc);
                if( nd->refcnt == rc+1 )
                    diag_printf(" (but may be current dir)");
            }
        }

        diag_printf("\n");
    }

    diag_printf("Blocks:\n");

    for( i = 0; i < TESTFS_NBLOCK; i++ )
    {
        testfs_block *b = &block[i];

        diag_printf("%3d :",i);
        if( b->pos == -1 )
            diag_printf(" <free>");
        else
        {
            int j;
            testfs_node *nd = b->u.file;
            diag_printf(" %3d %3d %d[%7s]",b->pos,b->size,nd-node,nd->name);
            for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
            {
                if( nd->u.file.data[j] == b )
                    break;
            }
            if( j == TESTFS_FILEBLOCKS )
            {
                errors++;
                diag_printf(" block not in file!");
            }
        }
        diag_printf("\n");
    }

    if( errors != 0 )
        diag_printf("%d errors detected\n",errors);
}

// -------------------------------------------------------------------------
// EOF testfs.c

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -