📄 ramfs.c
字号:
// the pathname, so we can create it here.
int doterr, dotdoterr, direrr;
node = alloc_node( __stat_mode_DIR | S_IRWXU|S_IRWXG|S_IRWXO);
if( node == NULL )
return ENOSPC;
// Add "." and ".." entries.
doterr = add_direntry( node, ".", 1, node );
dotdoterr = add_direntry( node, "..", 2, ds.dir );
// And add to parent directory.
direrr = add_direntry( ds.dir, ds.name, ds.namelen, node );
// check for any errors in that...
if( doterr+dotdoterr+direrr != ENOERR )
{
// For each of the add_direntry() calls that succeeded,
// we must now undo it.
if( doterr == ENOERR )
del_direntry( node, ".", 1 );
else err = doterr;
if( dotdoterr == ENOERR )
del_direntry( node, "..", 2 );
else err = dotdoterr;
if( direrr == ENOERR )
del_direntry( ds.dir, ds.name, ds.namelen );
else err = direrr;
// Free the data and the node itself.
freebuffer_node( node );
free_node( node );
}
else err = ENOERR;
}
// If this was not the last element, then and intermediate
// directory does not exist.
}
else
{
// If there we no error, something already exists with that
// name, so we cannot create another one.
if( err == ENOERR )
err = EEXIST;
}
return err;
}
// -------------------------------------------------------------------------
// ramfs_rmdir()
// Remove a directory.
static int ramfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
{
ramfs_dirsearch ds;
int err;
init_dirsearch( &ds, (ramfs_node *)dir, name );
err = ramfs_find( &ds );
if( err != ENOERR ) return err;
// Check that this is actually a directory.
if( !S_ISDIR(ds.node->mode) )
return EPERM;
// Delete the entry. This will adjust the link values
// accordingly and if the directory is now unreferenced,
// will cause it to be deleted.
err = del_direntry( ds.dir, ds.name, ds.namelen );
return err;
}
// -------------------------------------------------------------------------
// ramfs_rename()
// Rename a file/dir.
static int ramfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 )
{
ramfs_dirsearch ds1, ds2;
int err;
init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
err = ramfs_find( &ds1 );
if( err != ENOERR ) return err;
init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
err = ramfs_find( &ds2 );
// Allow through renames to non-existent objects.
if( ds2.last && err == ENOENT )
ds2.node = NULL, err = ENOERR;
if( err != ENOERR ) return err;
// Null rename, just return
if( ds1.node == ds2.node )
return ENOERR;
// First deal with any entry that is at the destination
if( ds2.node )
{
// Check that we are renaming like-for-like
if( !S_ISDIR(ds1.node->mode) && S_ISDIR(ds2.node->mode) )
return EISDIR;
if( S_ISDIR(ds1.node->mode) && !S_ISDIR(ds2.node->mode) )
return ENOTDIR;
// Now delete the destination directory entry
err = del_direntry( ds2.dir, ds2.name, ds2.namelen );
if( err != ENOERR ) return err;
}
// Now we know that there is no clashing node at the destination,
// make a new direntry at the destination and delete the old entry
// at the source.
err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
if( err == ENOERR )
err = del_direntry( ds1.dir, ds1.name, ds1.namelen );
// Update directory times
if( err == ENOERR )
ds1.dir->ctime =
ds1.dir->mtime =
ds2.dir->ctime =
ds2.dir->mtime = cyg_timestamp();
return err;
}
// -------------------------------------------------------------------------
// ramfs_link()
// Make a new directory entry for a file.
static int ramfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type )
{
ramfs_dirsearch ds1, ds2;
int err;
// Only do hard links for now in this filesystem
if( type != CYG_FSLINK_HARD )
return EINVAL;
init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
err = ramfs_find( &ds1 );
if( err != ENOERR ) return err;
init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
err = ramfs_find( &ds2 );
// Don't allow links to existing objects
if( err == ENOERR ) return EEXIST;
// Allow through links to non-existing terminal objects
if( ds2.last && err == ENOENT )
ds2.node = NULL, err = ENOERR;
if( err != ENOERR ) return err;
// Now we know that there is no existing node at the destination,
// make a new direntry at the destination.
err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
if( err == ENOERR )
ds1.node->ctime =
ds2.dir->ctime =
ds2.dir->mtime = cyg_timestamp();
return err;
}
// -------------------------------------------------------------------------
// ramfs_opendir()
// Open a directory for reading.
static int ramfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *file )
{
ramfs_dirsearch ds;
int err;
init_dirsearch( &ds, (ramfs_node *)dir, name );
err = ramfs_find( &ds );
if( err != ENOERR ) return err;
// check it is really a directory.
if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
ds.node->refcnt++; // Count successful open
// Initialize the file object, setting the f_ops field to a
// special set of file ops.
file->f_type = CYG_FILE_TYPE_FILE;
file->f_ops = &ramfs_dirops;
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)ds.node;
file->f_xops = 0;
return ENOERR;
}
// -------------------------------------------------------------------------
// ramfs_chdir()
// Change directory support.
static int ramfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out )
{
if( dir_out != NULL )
{
// This is a request to get a new directory pointer in
// *dir_out.
ramfs_dirsearch ds;
int err;
init_dirsearch( &ds, (ramfs_node *)dir, name );
err = ramfs_find( &ds );
if( err != ENOERR ) return err;
// check it is a directory
if( !S_ISDIR(ds.node->mode) )
return ENOTDIR;
// Increment ref count to keep this directory in existent
// while it is the current cdir.
ds.node->refcnt++;
// Pass it out
*dir_out = (cyg_dir)ds.node;
}
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.
ramfs_node *node = (ramfs_node *)dir;
// Just decrement directory reference count.
dec_refcnt( node );
}
return ENOERR;
}
// -------------------------------------------------------------------------
// ramfs_stat()
// Get struct stat info for named object.
static int ramfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf)
{
ramfs_dirsearch ds;
int err;
init_dirsearch( &ds, (ramfs_node *)dir, name );
err = ramfs_find( &ds );
if( err != ENOERR ) return err;
// Fill in the status
buf->st_mode = ds.node->mode;
buf->st_ino = (ino_t)ds.node;
buf->st_dev = 0;
buf->st_nlink = ds.node->nlink;
buf->st_uid = 0;
buf->st_gid = 0;
buf->st_size = ds.node->size;
buf->st_atime = ds.node->atime;
buf->st_mtime = ds.node->mtime;
buf->st_ctime = ds.node->ctime;
return err;
}
// -------------------------------------------------------------------------
// ramfs_getinfo()
// Getinfo. Currently only support pathconf() and filesystem usage.
static int ramfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len )
{
ramfs_dirsearch ds;
int err;
init_dirsearch( &ds, (ramfs_node *)dir, name );
err = ramfs_find( &ds );
if( err != ENOERR ) return err;
switch( key )
{
case FS_INFO_CONF:
err = ramfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
break;
#if defined(CYGSEM_FILEIO_BLOCK_USAGE) && defined(CYGPKG_FS_RAM_BLOCKS_ARRAY)
// When using malloc for storage this does not make much
// sense, so only implement this when using pre-allocated
// blocks
case FS_INFO_BLOCK_USAGE: {
struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
ramfs_block *b;
usage->total_blocks = CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE;
usage->free_blocks = 0;
// Iterate over the free list to count its size
b = block_free_list;
while(b) {
usage->free_blocks++;
b=*(ramfs_block **)b;
}
usage->block_size = CYGNUM_RAMFS_BLOCK_SIZE;
return ENOERR;
}
#endif
default:
err = EINVAL;
}
return err;
}
// -------------------------------------------------------------------------
// ramfs_setinfo()
// Setinfo. Nothing to support here at present.
static int ramfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len )
{
// No setinfo keys supported at present
return EINVAL;
}
//==========================================================================
// File operations
// -------------------------------------------------------------------------
// ramfs_fo_read()
// Read data from the file.
static int ramfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
ramfs_node *node = (ramfs_node *)fp->f_data;
int i;
off_t pos = fp->f_offset;
ssize_t resid = uio->uio_resid;
// Loop over the io vectors until there are none left
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;
// Loop over each vector filling it with data from the file.
while( len > 0 && pos < node->size )
{
cyg_uint8 *fbuf;
size_t bsize;
off_t l = len;
int err;
// Get a pointer to the data at offset _pos_.
err = findbuffer_node( node, pos, &fbuf, &bsize, false );
if( err != ENOERR )
return err;
// adjust size to end of file if necessary
if( l > node->size-pos )
l = node->size-pos;
// adjust size to the amount of contiguous data we can see
// at present.
if( l > bsize )
l = bsize;
if (fbuf) {
// copy data out
memcpy( buf, fbuf, l );
} else { // hole, so return zeros here.
memset( buf, 0, l )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -