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

📄 testfs.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      testfs.c
//
//      Test file system
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):           nickg
// Contributors:        nickg
// Date:                2000-05-25
// Purpose:             Test file system
// Description:         This is a very simple implementation of a RAM file system.
//                      This implementation is not "industrial strength" or suitable
//                      for production use, it is too wasteful of both memory and time.
//                      Its primary purpose is to support testing of the fileio
//                      infrastructure and API. It can, however, serve as a model
//                      and source of code fragments for the implementation
//                      of further filesystems.
//              
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/hal.h>
#include <pkgconf/io_fileio.h>

#include <cyg/infra/cyg_trac.h>        // tracing macros
#include <cyg/infra/cyg_ass.h>         // assertion macros

#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>

#include <cyg/fileio/fileio.h>

#include <cyg/infra/diag.h>

//==========================================================================
// Configuration  parameters

#define TESTFS_NFILE            10      // Max number of files/directories
#define TESTFS_NBLOCK           20      // Number of data blocks available
#define TESTFS_BLOCKSIZE        128     // Bytes stored per block
#define TESTFS_FILEBLOCKS       8       // Max blocks per file
#define TESTFS_NAMESIZE         32      // Length of file names in bytes


// Maximum file size is blocksize*blocks
#define TESTFS_FILESIZE_MAX     (TESTFS_BLOCKSIZE*TESTFS_FILEBLOCKS)

//==========================================================================
// Data structures

struct testfs_node;
typedef struct testfs_node testfs_node;

struct testfs_block;
typedef struct testfs_block testfs_block;


struct testfs_node
{
    testfs_node         *next;          // next node in list
    testfs_node         *parent;        // Back pointer to parent
    int                 refcnt;         // reference count
    char                name[TESTFS_NAMESIZE]; // file name
    struct stat         status;         // status data
    union
    {
        struct
        {
            testfs_block        *data[TESTFS_FILEBLOCKS];  // array of blocks
        } file;

        struct
        {
            testfs_node         *nodes[TESTFS_FILEBLOCKS]; // array of nodes
        } dir;
    } u;
};

struct testfs_block
{
    union
    {
        testfs_block    *next;          // next block in free list
        testfs_node     *file;          // back pointer to file
    } u;
    off_t               pos;            // position in file of first byte
    size_t              size;           // number of bytes in buffer
    char                data[TESTFS_BLOCKSIZE]; // the data
};

//==========================================================================
// Local data

// Array of nodes
static testfs_node node[TESTFS_NFILE];

// node free list.
static testfs_node *free_node = NULL;

// Array of data blocks
static testfs_block block[TESTFS_NBLOCK];

// block free list.
static testfs_block *free_block = NULL;

// Init flag
cyg_bool testfs_initialized = false;

//==========================================================================
// Forward definitions

// Filesystem operations
static int testfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
static int testfs_umount   ( cyg_mtab_entry *mte );
static int testfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                             int mode,  cyg_file *fte );
static int testfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int testfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int testfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int testfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
                             cyg_dir dir2, const char *name2 );
static int testfs_link     ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
                             cyg_dir dir2, const char *name2, int type );
static int testfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                             cyg_file *fte );
static int testfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                             cyg_dir *dir_out );
static int testfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                             struct stat *buf);
static int testfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                             int key, void *buf, int len );
static int testfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                             int key, void *buf, int len );

// File operations
static int testfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int testfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int testfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
static int testfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
                                CYG_ADDRWORD data);
//static int testfs_fo_select    (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
static int testfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode );        
static int testfs_fo_close     (struct CYG_FILE_TAG *fp);
static int testfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf );
static int testfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
static int testfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );

// Directory operations
static int testfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int testfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );

//==========================================================================
// Filesystem table entries

FSTAB_ENTRY( testfs_fste, "testfs", 0,
             CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
             testfs_mount,
             testfs_umount,
             testfs_open,
             testfs_unlink,
             testfs_mkdir,
             testfs_rmdir,
             testfs_rename,
             testfs_link,
             testfs_opendir,
             testfs_chdir,
             testfs_stat,
             testfs_getinfo,
             testfs_setinfo);

MTAB_ENTRY( testfs_mte1,
                   "/",
                   "testfs",
                   "",
                   0);

#if 0
MTAB_ENTRY( testfs_mte2,
                   "/ram",
                   "testfs",
                   "",
                   0);
#endif

static cyg_fileops testfs_fileops =
{
    testfs_fo_read,
    testfs_fo_write,
    testfs_fo_lseek,
    testfs_fo_ioctl,
    cyg_fileio_seltrue,
    testfs_fo_fsync,
    testfs_fo_close,
    testfs_fo_fstat,
    testfs_fo_getinfo,
    testfs_fo_setinfo
};

static cyg_fileops testfs_dirops =
{
    testfs_fo_dirread,
    (cyg_fileop_write *)cyg_fileio_enosys,
    testfs_fo_dirlseek,
    (cyg_fileop_ioctl *)cyg_fileio_enosys,
    cyg_fileio_seltrue,
    (cyg_fileop_fsync *)cyg_fileio_enosys,
    testfs_fo_close,
    (cyg_fileop_fstat *)cyg_fileio_enosys,
    (cyg_fileop_getinfo *)cyg_fileio_enosys,
    (cyg_fileop_setinfo *)cyg_fileio_enosys
};

//==========================================================================
// Support routines

// -------------------------------------------------------------------------
// Local strcmp() and strcpy()

static int mystrcmp( const char *s1, const char *s2 )
{
    while( *s1 == *s2 && *s1 != '\0' && *s2 != '\0' )
        s1++, s2++;

    return (*s2)-(*s1);
}

static char *mystrcpy( char *s1, const char *s2 )
{
    char *s = s1;
    while( (*s1++ = *s2++) != 0);
    return s;
}

// -------------------------------------------------------------------------
// Follow a path through the directory structure

static int testfs_find( testfs_node *dir,       // dir to start search in
                        const char *path,       // path to follow
                        testfs_node **found,    // return node found
                        testfs_node **parent,   // return last dir searched
                        char *name,             // name fragment buffer
                        cyg_bool *lastp)        // last name in path ?
{
    testfs_node *nd = dir;

    *lastp = false;
    *found = NULL;
    
    while( *path != '\0' )
    {
        const char *p = path;
        char *n = name;
        testfs_node *nd1;
        int i;

        // check nd is a directory
        if( !S_ISDIR(nd->status.st_mode) ) return ENOTDIR;        

        // Isolate the next element of the path name. 
        while( *p != '\0' && *p != '/' && (n-&name[0]) < TESTFS_NAMESIZE)
            *n++ = *p++;

        if( (n-&name[0]) >= TESTFS_NAMESIZE )
            return ENAMETOOLONG;

        // Step path on past the separator
        // If this is the last name element in the path,
        // set *lastp to indicate this.
        if( *(path=p) == '/' ) path++;
        else *lastp = true;

        // teminate name
        *n = '\0';

        // name now contains the next path element, search the node
        // in nd for it.

        *parent = nd;
        nd1 = NULL;
        
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
        {
            testfs_node *n = nd->u.dir.nodes[i];
            if( n == NULL )
                continue;

            if( mystrcmp( name, n->name ) == 0 )
            {
                nd1 = n;
                break;
            }
        }
        
        if( nd1 == NULL ) return ENOENT;

        nd = nd1;
    }

    // Return what we have found
    *found = nd;
    
    return ENOERR;
}

// -------------------------------------------------------------------------
// Get current time since epoch

static time_t testfs_time(void)
{
#ifdef CYGPKG_KERNEL
    return cyg_current_time();
#else
    return 0;
#endif
}

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

static int testfs_delnode( testfs_node *nd )
{

    testfs_node *parent;
    int i;

    // Non-unitary ref count means this node is either open    
    // or is a dir with entries in it.
    if( nd->refcnt > 1 )
        return EBUSY;

    // Remove from parent's node list.
    
    parent = nd->parent;

    for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
        if( parent->u.dir.nodes[i] == nd )
        {
            parent->u.dir.nodes[i] = NULL;
            break;
        }

    parent->refcnt--;

    if( S_ISREG(nd->status.st_mode) )
    {
        // for a file, return blocks to free list
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
        {
            testfs_block *b = nd->u.file.data[i];
            if( b != NULL )
            {
                b->u.next = free_block;
                b->pos = -1;
                free_block = b;
            }
        }
    }

    // and finally return nd to free node list

    nd->next = free_node;
    nd->refcnt = -1;
    free_node = nd;

    return ENOERR;
}

//==========================================================================
// Filesystem operations

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

static int testfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
{
    testfs_node *root;
    int i;
    
    if( !testfs_initialized )

⌨️ 快捷键说明

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