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