📄 testfs.c
字号:
if( !testfs_initialized )
{
int i;
for( i = 0; i < TESTFS_NFILE; i++ )
{
node[i].next = free_node;
node[i].refcnt = -1;
free_node = &node[i];
}
for( i = 0; i < TESTFS_NBLOCK; i++ )
{
block[i].u.next = free_block;
block[i].pos = -1;
free_block = &block[i];
}
testfs_initialized = true;
}
// Allocate a node to be the root of this filesystem and
// initialize it.
root = free_node;
if( root == NULL ) return ENOSPC;
free_node = root->next;
root->next = root; // form circular list
root->parent = root; // I'm my own parent!
root->refcnt = 1; // don't want to ever lose root
strcpy( root->name, "root");
root->status.st_mode = __stat_mode_DIR;
root->status.st_ino = root-&node[0];
root->status.st_dev = 0;
root->status.st_nlink = 1;
root->status.st_uid = 0;
root->status.st_gid = 0;
root->status.st_size = 0;
root->status.st_atime = testfs_time();
root->status.st_mtime = testfs_time();
root->status.st_ctime = testfs_time();
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
root->u.dir.nodes[i] = NULL;
mte->root = (cyg_dir)root;
return 0;
}
// -------------------------------------------------------------------------
static int testfs_umount ( cyg_mtab_entry *mte )
{
testfs_node *root = (testfs_node *)mte->root;
// Non-empty filesystem, do not unmount
if( root->refcnt != 1 )
return EBUSY;
// Otherwise just return it to the free pool
root->next = free_node;
root->refcnt = -1;
free_node = root;
// Clear root pointer
mte->root = CYG_DIR_NULL;
// That's all folks.
return ENOERR;
}
// -------------------------------------------------------------------------
static int testfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
int mode, cyg_file *file )
{
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( lastp && err == ENOENT && (mode & O_CREAT) )
{
int i;
// No node there, if the O_CREAT bit is set then we must
// create a new one. The parent and name results will have been filled
// in, so we know where to put it.
// first check that there is space for it
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
if( parent->u.dir.nodes[i] == NULL )
break;
if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
// Allocate a new node
nd = free_node;
if( nd == NULL ) return ENOSPC;
free_node = nd->next;
// Add to directory list
parent->u.dir.nodes[i] = nd;
parent->refcnt++;
// Fill in details
nd->parent = parent;
nd->refcnt = 1; // 1 for directory reference
strcpy( nd->name, name);
nd->status.st_mode = __stat_mode_REG;
nd->status.st_ino = nd-&node[0];
nd->status.st_dev = 0;
nd->status.st_nlink = 1;
nd->status.st_uid = 0;
nd->status.st_gid = 0;
nd->status.st_size = 0;
nd->status.st_atime = testfs_time();
nd->status.st_mtime = testfs_time();
nd->status.st_ctime = testfs_time();
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
nd->u.file.data[i] = NULL;
err = ENOERR;
}
if( err == ENOERR && (mode & O_TRUNC ) )
{
// Clean out any blocks in the file...
int i;
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;
nd->u.file.data[i] = NULL;
}
}
nd->status.st_size = 0;
}
if( err != ENOERR ) return err;
if( S_ISDIR(nd->status.st_mode) ) return EISDIR;
nd->refcnt++; // Count successful open as a ref
// Initialize the file object
file->f_flag |= mode & CYG_FILE_MODE_MASK;
file->f_type = CYG_FILE_TYPE_FILE;
file->f_ops = &testfs_fileops;
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)nd;
file->f_xops = 0;
return ENOERR;
}
// -------------------------------------------------------------------------
static int testfs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
{
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;
// Cannot unlink directories, use rmdir() instead
if( S_ISDIR(nd->status.st_mode) )
return EPERM;
err = testfs_delnode( nd );
return err;
}
// -------------------------------------------------------------------------
static int testfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
{
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( lastp && err == ENOENT )
{
int i;
// No node there, create a new one. The parent and name
// results will have been filled in, so we know where to put
// it.
// first check that there is space for it
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
if( parent->u.dir.nodes[i] == NULL )
break;
if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
// Allocate a new node
nd = free_node;
if( nd == NULL ) return ENOSPC;
free_node = nd->next;
// Add to directory list
parent->u.dir.nodes[i] = nd;
parent->refcnt++;
// Fill in details
nd->parent = parent;
nd->refcnt = 1; // 1 for directory reference
strcpy( nd->name, name);
nd->status.st_mode = __stat_mode_DIR;
nd->status.st_ino = nd-&node[0];
nd->status.st_dev = 0;
nd->status.st_nlink = 1;
nd->status.st_uid = 0;
nd->status.st_gid = 0;
nd->status.st_size = 0;
nd->status.st_atime = testfs_time();
nd->status.st_mtime = testfs_time();
nd->status.st_ctime = testfs_time();
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
nd->u.dir.nodes[i] = NULL;
err = ENOERR;
}
return err;
}
// -------------------------------------------------------------------------
static int testfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
{
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;
// Check that it is a directory
if( !S_ISDIR(nd->status.st_mode) )
return EPERM;
err = testfs_delnode( nd );
return err;
}
// -------------------------------------------------------------------------
static int testfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *path1,
cyg_dir dir2, const char *path2 )
{
testfs_node *nd1, *parent1;
testfs_node *nd2, *parent2;
int err;
char name1[TESTFS_NAMESIZE];
char name2[TESTFS_NAMESIZE];
cyg_bool lastp;
int i,j;
err = testfs_find( (testfs_node *)dir1, path1, &nd1, &parent1, name1, &lastp );
if( err != ENOERR ) return err;
err = testfs_find( (testfs_node *)dir2, path2, &nd2, &parent2, name2, &lastp );
// Allow through renames to non-existent objects.
if( lastp && err == ENOENT )
err = ENOERR;
if( err != ENOERR ) return err;
// Null rename, just return
if( nd1 == nd2 )
return ENOERR;
// First deal with any node that is at the destination
if( nd2 )
{
// Check that we are renaming like-for-like
if( !S_ISDIR(nd1->status.st_mode) && S_ISDIR(nd2->status.st_mode) )
return EISDIR;
if( S_ISDIR(nd1->status.st_mode) && !S_ISDIR(nd2->status.st_mode) )
return ENOTDIR;
// Now delete the destination node.
err = testfs_delnode( nd2 );
if( err != ENOERR ) return err;
}
// Now we know that there is no clashing node at the destination.
// Move the node over and change its name.
// first check that there is space for it
for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
if( parent2->u.dir.nodes[i] == NULL )
break;
if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
// Now remove node from old parent.
for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
if( parent1->u.dir.nodes[j] == nd1 )
{
parent1->u.dir.nodes[j] = NULL;
break;
}
parent1->refcnt--;
// Add to directory list
parent2->u.dir.nodes[i] = nd1;
parent2->refcnt++;
nd1->parent = parent2;
// And give it a new name.
strcpy( nd1->name, name2 );
return err;
}
// -------------------------------------------------------------------------
static int testfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *path1,
cyg_dir dir2, const char *path2, int type )
{
// The data structures of this file system do not support the
// creation of links.
return ENOSYS;
}
// -------------------------------------------------------------------------
static int testfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
cyg_file *file )
{
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;
if( !S_ISDIR(nd->status.st_mode) )
return ENOTDIR;
nd->refcnt++; // Count successful open as a ref
// Initialize the file object
file->f_type = CYG_FILE_TYPE_FILE;
file->f_ops = &testfs_dirops;
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)nd;
file->f_xops = 0;
return ENOERR;
}
// -------------------------------------------------------------------------
static int testfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
cyg_dir *dir_out )
{
if( dir_out != NULL )
{
// This is a request to get a new directory pointer in
// *dir_out.
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;
if( !S_ISDIR(nd->status.st_mode) )
return ENOTDIR;
// Increment ref count to keep this directory in existent
// while it is the current cdir.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -