📄 testfs.c
字号:
//==========================================================================
//
// 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 + -