📄 ramfs.c
字号:
break;
}
frag += fraglen;
// If we are at the last fragment, then the whole name string
// has matched and we have a successful search.
if( d->last )
return first;
// Otherwise move on to next entry in chain
err = findbuffer_node( dir, d->next, &buf, &size, false );
if( err != ENOERR )
return NULL;
d = (ramfs_dirent *)buf;
}
}
pos += sizeof(ramfs_dirent);
}
return NULL;
}
// -------------------------------------------------------------------------
// del_direntry()
// Delete a named directory entry. Find it and then follow the chain
// deleting the fragments as we go.
static int del_direntry( ramfs_node *dir, const char *name, int namelen )
{
ramfs_dirent *d = find_direntry( dir, name, namelen );
if( d == NULL )
return ENOENT;
for(;;)
{
int err;
cyg_uint8 *buf;
size_t size;
d->inuse = 0;
if( d->last ) break;
err = findbuffer_node( dir, d->next, &buf, &size, false );
if( err != ENOERR )
return ENOENT;
d = (ramfs_dirent *)buf;
}
dec_nlink( d->node );
return ENOERR;
}
//==========================================================================
// Directory search
// -------------------------------------------------------------------------
// init_dirsearch()
// Initialize a dirsearch object to start a search
static void init_dirsearch( ramfs_dirsearch *ds,
ramfs_node *dir,
const char *name)
{
ds->dir = dir;
ds->path = name;
ds->node = dir;
ds->name = name;
ds->namelen = 0;
ds->last = false;
}
// -------------------------------------------------------------------------
// find_entry()
// Search a single directory for the next name in a path and update the
// dirsearch object appropriately.
static int find_entry( ramfs_dirsearch *ds )
{
ramfs_node *dir = ds->dir;
const char *name = ds->path;
const char *n = name;
char namelen = 0;
ramfs_dirent *d;
// check that we really have a directory
if( !S_ISDIR(dir->mode) )
return ENOTDIR;
// Isolate the next element of the path name.
while( *n != '\0' && *n != '/' )
n++, namelen++;
// Check if this is the last path element.
while( *n == '/') n++;
if( *n == '\0' )
ds->last = true;
// update name in dirsearch object
ds->name = name;
ds->namelen = namelen;
// Here we have the name and its length set up.
// Search the directory for a matching entry
d = find_direntry( dir, name, namelen );
if( d == NULL )
return ENOENT;
// pass back the node we have found
ds->node = d->node;
return ENOERR;
}
// -------------------------------------------------------------------------
// ramfs_find()
// Main interface to directory search code. This is used in all file
// level operations to locate the object named by the pathname.
static int ramfs_find( ramfs_dirsearch *d )
{
int err;
// Short circuit empty paths
if( *(d->path) == '\0' )
return ENOERR;
// iterate down directory tree until we find the object
// we want.
for(;;)
{
err = find_entry( d );
if( err != ENOERR )
return err;
if( d->last )
return ENOERR;
// Update dirsearch object to search next directory.
d->dir = d->node;
d->path += d->namelen;
while( *(d->path) == '/' ) d->path++; // skip dirname separators
}
}
//==========================================================================
// Pathconf support
// This function provides support for pathconf() and fpathconf().
static int ramfs_pathconf( ramfs_node *node, struct cyg_pathconf_info *info )
{
int err = ENOERR;
switch( info->name )
{
case _PC_LINK_MAX:
info->value = LINK_MAX;
break;
case _PC_MAX_CANON:
info->value = -1; // not supported
err = EINVAL;
break;
case _PC_MAX_INPUT:
info->value = -1; // not supported
err = EINVAL;
break;
case _PC_NAME_MAX:
info->value = NAME_MAX;
break;
case _PC_PATH_MAX:
info->value = PATH_MAX;
break;
case _PC_PIPE_BUF:
info->value = -1; // not supported
err = EINVAL;
break;
case _PC_ASYNC_IO:
info->value = -1; // not supported
err = EINVAL;
break;
case _PC_CHOWN_RESTRICTED:
info->value = -1; // not supported
err = EINVAL;
break;
case _PC_NO_TRUNC:
info->value = 0;
break;
case _PC_PRIO_IO:
info->value = 0;
break;
case _PC_SYNC_IO:
info->value = 0;
break;
case _PC_VDISABLE:
info->value = -1; // not supported
err = EINVAL;
break;
default:
err = EINVAL;
break;
}
return err;
}
//==========================================================================
// Filesystem operations
// -------------------------------------------------------------------------
// ramfs_mount()
// Process a mount request. This mainly creates a root for the
// filesystem.
static int ramfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
{
ramfs_node *root;
int err;
// Allocate a node to be the root of this filesystem and initialize it.
root = alloc_node(__stat_mode_DIR|S_IRWXU|S_IRWXG|S_IRWXO);
if( root == NULL )
return ENOSPC;
// Add . and .. entries back to self.
err = add_direntry( root, ".", 1, root );
if( err == ENOERR )
err = add_direntry( root, "..", 2, root );
if( err != ENOERR )
{
free_node( root );
return err;
}
mte->root = (cyg_dir)root;
return ENOERR;
}
// -------------------------------------------------------------------------
// ramfs_umount()
// Unmount the filesystem. This will currently only succeed if the
// filesystem is empty.
static int ramfs_umount ( cyg_mtab_entry *mte )
{
ramfs_node *root = (ramfs_node *)mte->root;
// Check for open/inuse root
if( root->refcnt != 0 )
return EBUSY;
// Check that root directory is clear of extra links.
if( root->nlink != 2 )
return EBUSY;
// Just return it to free pool
free_node( root );
// Clear root pointer
mte->root = CYG_DIR_NULL;
// That's all folks.
return ENOERR;
}
// -------------------------------------------------------------------------
// ramfs_open()
// Open a file for reading or writing.
static int ramfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *file )
{
ramfs_dirsearch ds;
ramfs_node *node = NULL;
int err;
init_dirsearch( &ds, (ramfs_node *)dir, name );
err = ramfs_find( &ds );
if( err == ENOENT )
{
if( ds.last && (mode & O_CREAT) )
{
// No node there, if the O_CREAT bit is set then we must
// create a new one. The dir and name fields of the dirsearch
// object will have been updated so we know where to put it.
node = alloc_node( __stat_mode_REG|S_IRWXU|S_IRWXG|S_IRWXO);
if( node == NULL )
return ENOSPC;
err = add_direntry( ds.dir, ds.name, ds.namelen, node );
if( err != ENOERR )
{
free_node( node );
return err;
}
err = ENOERR;
}
}
else if( err == ENOERR )
{
// The node exists. If the O_CREAT and O_EXCL bits are set, we
// must fail the open.
if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
err = EEXIST;
else node = ds.node;
}
if( err == ENOERR && (mode & O_TRUNC ) )
{
// If the O_TRUNC bit is set we must clean out the file data.
err = freebuffer_node( node );
node->size = 0;
// Update file times
node->ctime =
node->mtime = cyg_timestamp();
}
if( err != ENOERR ) return err;
// Check that we actually have a file here
if( S_ISDIR(node->mode) ) return EISDIR;
node->refcnt++; // Count successful open
// Initialize the file object
file->f_flag |= mode & CYG_FILE_MODE_MASK;
file->f_type = CYG_FILE_TYPE_FILE;
file->f_ops = &ramfs_fileops;
file->f_offset = (mode&O_APPEND) ? node->size : 0;
file->f_data = (CYG_ADDRWORD)node;
file->f_xops = 0;
return ENOERR;
}
// -------------------------------------------------------------------------
// ramfs_unlink()
// Remove a file link from its directory.
static int ramfs_unlink ( 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;
// Cannot unlink directories, use rmdir() instead
if( S_ISDIR(ds.node->mode) )
return EPERM;
// Delete it from its directory
err = del_direntry( ds.dir, ds.name, ds.namelen );
return err;
}
// -------------------------------------------------------------------------
// ramfs_mkdir()
// Create a new directory.
static int ramfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
{
ramfs_dirsearch ds;
ramfs_node *node = NULL;
int err;
init_dirsearch( &ds, (ramfs_node *)dir, name );
err = ramfs_find( &ds );
if( err == ENOENT )
{
if( ds.last )
{
// The entry does not exist, and it is the last element in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -