📄 ramfs.c
字号:
// -------------------------------------------------------------------------// init_dirsearch()// Initialize a dirsearch object to start a searchstatic 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); 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 ); 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 // the pathname, so we can create it here. int doterr, dotdoterr, direrr; node = alloc_node( __stat_mode_DIR ); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -