📄 fs.c
字号:
* disk... */ current_fsnode = sos_fs_nscache_get_fs_node(current_nsnode); retval = current_fsnode->ops_dir ->lookup(current_fsnode, current_component.contents, current_component.length, & storage_location); if (SOS_OK != retval) { /* Well, we cannot go further, stop here */ *result_nsnode = current_nsnode; return SOS_OK; } /* Now retrieve this node from disk or from the cache into memory */ retval = fs_fetch_node(current_fsnode->fs, storage_location, & next_fsnode); if (SOS_OK != retval) { sos_fs_nscache_unref_node(current_nsnode); return retval; } /* Integrate it in the nscache */ retval = sos_fs_nscache_add_new_child_node(current_nsnode, & current_component, next_fsnode, & next_nsnode); sos_fs_nscache_unref_node(current_nsnode); if (SOS_OK != retval) return retval; } else sos_fs_nscache_unref_node(current_nsnode); /* Reaching a symlink ? */ if (sos_fs_nscache_get_fs_node(next_nsnode)->type == SOS_FS_NODE_SYMLINK) { /* Expand the link only for non-terminal nodes, or for the terminal node only if follow_symlinks is TRUE */ if ( (remaining.length != 0) || follow_symlinks ) { struct sos_fs_nscache_node * symlink_target; retval = fs_resolve_symlink(root_nsnode, next_nsnode, & symlink_target, lookup_recursion_level); sos_fs_nscache_unref_node(next_nsnode); if (SOS_OK != retval) return retval; /* Dangling symlink */ next_nsnode = symlink_target; } } /* Make sure there was no slash after this component, unless this component is a directory */ if (slashes_after_first_component && ( sos_fs_nscache_get_fs_node(next_nsnode)->type != SOS_FS_NODE_DIRECTORY) ) { sos_fs_nscache_unref_node(next_nsnode); return -SOS_ENOTDIR; } /* Ok, fine, we got it, update the path we still have to explore */ memcpy(result_remaining_path, & remaining, sizeof(remaining)); current_nsnode = next_nsnode; } sos_display_fatal_error("Should not get there"); return -SOS_EFATAL;}/** * It is assumed that parent does not already have a child with the * given name. We make sure that the "path" is a single entity (ie * not "a/b") * @return Error if fsnode is not on the same FS as parent_nsnode */static sos_ret_tfs_register_child_node(const struct sos_process * creator, struct sos_fs_nscache_node * parent_nsnode, const struct sos_fs_pathname * name, struct sos_fs_node * fsnode, sos_ui32_t flags, struct sos_fs_nscache_node ** result_nsnode){ sos_ret_t retval; struct sos_fs_node * parent_fsnode; struct sos_fs_pathname first_component, remaining; sos_bool_t slashes_after_first_component = FALSE; parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode); if (parent_fsnode->type != SOS_FS_NODE_DIRECTORY) return -SOS_ENOTDIR; if (name->length <= 0) return -SOS_EINVAL; slashes_after_first_component = sos_fs_pathname_split_path(name, & first_component, & remaining); if (fsnode->type != SOS_FS_NODE_DIRECTORY) { /* Make sure the given name is exactly a single path component (ie no '/') */ if (slashes_after_first_component) return -SOS_EINVAL; } else { /* Make sure there aren't any other component behind the '/'s, if any */ if (remaining.length > 0) return -SOS_EINVAL; } /* Make sure the parent directory is writeable */ if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) ) return -SOS_EACCES; /* Make sure that the entries are located on the same FS */ if (fsnode->fs != parent_fsnode->fs) return -SOS_EXDEV; /* Make sure that the nsnode won't be destroyed */ sos_fs_nscache_ref_node(parent_nsnode); /* Allocate the node in directory */ retval = parent_fsnode->ops_dir->link(parent_fsnode, creator, first_component.contents, first_component.length, fsnode); if (SOS_OK != retval) { sos_fs_nscache_unref_node(parent_nsnode); return retval; } /* Success: Consider the directory as dirty */ mark_dirty_fsnode(parent_fsnode, FALSE); /* Allocate the node in nscache cache */ retval = sos_fs_nscache_add_new_child_node(parent_nsnode, & first_component, fsnode, result_nsnode); sos_fs_nscache_unref_node(parent_nsnode); return retval;}/** It is assumed that parent does not already have a child with the given name. We make sure that the "path" is a single entity (ie not "a/b"). Return a NEW reference to the newly-created NS node */static sos_ret_tfs_create_child_node(struct sos_fs_nscache_node * parent_nsnode, const struct sos_fs_pathname * name, sos_fs_node_type_t type, sos_ui32_t flags, const struct sos_process * creator, sos_ui32_t access_rights, struct sos_fs_nscache_node ** result_nsnode){ sos_ret_t retval; struct sos_fs_node * fsnode, * parent_fsnode; parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode); if (parent_fsnode->type != SOS_FS_NODE_DIRECTORY) return -SOS_ENOTDIR; /* Make sure that the nsnode won't be destroyed */ sos_fs_nscache_ref_node(parent_nsnode); retval = fs_allocate_node(parent_fsnode->fs, type, flags, creator, access_rights, & fsnode); if (SOS_OK != retval) { sos_fs_nscache_unref_node(parent_nsnode); return retval; } retval = fs_register_child_node(creator, parent_nsnode, name, fsnode, flags, result_nsnode); sos_fs_nscache_unref_node(parent_nsnode); /* The function does not need it anymore */ sos_fs_unref_fsnode(fsnode); return retval;}/** * It is assumed that parent does not already have a child with the * given name, and that the new child does not have a parent yet. We * make sure that the "path" is a single entity (ie not "a/b") @return * Error if fsnode is not on the same FS as parent_nsnode */static sos_ret_tfs_connect_existing_child_node(const struct sos_process * creator, struct sos_fs_nscache_node * parent_nsnode, const struct sos_fs_pathname * name, struct sos_fs_nscache_node * nsnode){ sos_ret_t retval; struct sos_fs_node * parent_fsnode, * fsnode; struct sos_fs_pathname first_component, remaining; sos_bool_t slashes_after_first_component = FALSE; fsnode = sos_fs_nscache_get_fs_node(nsnode); parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode); if (parent_fsnode->type != SOS_FS_NODE_DIRECTORY) return -SOS_ENOTDIR; if (name->length <= 0) return -SOS_EINVAL; slashes_after_first_component = sos_fs_pathname_split_path(name, & first_component, & remaining); if (fsnode->type != SOS_FS_NODE_DIRECTORY) { /* Make sure the given name is exactly a single path component (ie no '/') */ if (slashes_after_first_component) return -SOS_EINVAL; } else { /* Make sure there aren't any other component behind the '/'s, if any */ if (remaining.length > 0) return -SOS_EINVAL; } /* Make sure the parent directory is writeable */ if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) ) return -SOS_EACCES; /* Make sure that the entries are located on the same FS */ if (fsnode->fs != parent_fsnode->fs) return -SOS_EXDEV; /* Make sure that the nsnode won't be destroyed */ sos_fs_nscache_ref_node(parent_nsnode); /* Allocate the node in directory */ retval = parent_fsnode->ops_dir->link(parent_fsnode, creator, first_component.contents, first_component.length, fsnode); if (SOS_OK != retval) { sos_fs_nscache_unref_node(parent_nsnode); return retval; } /* Success: Consider the directory as dirty */ mark_dirty_fsnode(parent_fsnode, FALSE); /* Allocate the node in nscache cache */ retval = sos_fs_nscache_add_existing_child_node(parent_nsnode, & first_component, nsnode); sos_fs_nscache_unref_node(parent_nsnode); return retval;}/** Return a new reference to the new node inserted unless result_nsnode is NULL */static sos_ret_tfs_create_node(const struct sos_fs_pathname * _path, const struct sos_process * creator, sos_ui32_t access_rights, sos_fs_node_type_t type, struct sos_fs_nscache_node ** result_nsnode){ sos_ret_t retval; struct sos_fs_pathname path; struct sos_fs_nscache_node *nsnode, *new_nsnode; path.contents = _path->contents; path.length = _path->length; if (path.length <= 0) return -SOS_ENOENT; if (path.contents[0] == '/') nsnode = sos_process_get_root(creator)->direntry; else nsnode = sos_process_get_cwd(creator)->direntry; retval = fs_lookup_node(& path, TRUE, sos_process_get_root(creator)->direntry, nsnode, & nsnode, & path, 0); if (SOS_OK != retval) return retval; if (path.length <= 0) { /* Found the exact match ! */ sos_fs_nscache_unref_node(nsnode); return -SOS_EEXIST; } /* Create a new entry in the file system */ retval = fs_create_child_node(nsnode, & path, type, /* flags */0, creator, access_rights, & new_nsnode); sos_fs_nscache_unref_node(nsnode); /* node not needed by this function ? */ if (NULL == result_nsnode) sos_fs_nscache_unref_node(new_nsnode); else *result_nsnode = new_nsnode; return retval;}static sos_ret_tfs_remove_node(const struct sos_process * actor, struct sos_fs_nscache_node * nsnode){ sos_ret_t retval; struct sos_fs_nscache_node * parent_nsnode; struct sos_fs_node * parent_fsnode; struct sos_fs_pathname childname; /* Refuse to do anything if this is the root of a mounted FS */ if (nsnode == sos_fs_nscache_get_fs_node(nsnode)->fs->root) return -SOS_EBUSY; retval = sos_fs_nscache_get_parent(nsnode, & parent_nsnode); if (SOS_OK != retval) return retval; parent_fsnode = sos_fs_nscache_get_fs_node(parent_nsnode); /* Make sure FS is writable ! */ if (parent_fsnode->fs->flags & SOS_FS_MOUNT_READONLY) return -SOS_EPERM; /* Make sure the parent directory is writeable */ if (! (parent_fsnode->access_rights & SOS_FS_WRITABLE) ) return -SOS_EACCES; sos_fs_nscache_ref_node(parent_nsnode); sos_fs_nscache_get_name(nsnode, & childname); retval = parent_fsnode->ops_dir->unlink(parent_fsnode, actor, childname.contents, childname.length); if (SOS_OK == retval) sos_fs_nscache_disconnect_node(nsnode); /* Unallocate the node */ if (SOS_OK == retval) mark_dirty_fsnode(parent_fsnode, FALSE); sos_fs_nscache_unref_node(parent_nsnode); return retval;}/* ********************************************************** * Exported functions */sos_ret_t sos_fs_new_opened_file(const struct sos_process * owner, struct sos_fs_nscache_node * nsnode, sos_ui32_t open_flags, struct sos_fs_opened_file ** result_of){ sos_ret_t retval; struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(nsnode); retval = fsnode->new_opened_file(fsnode, owner, open_flags, result_of); if (SOS_OK != retval) { sos_fs_nscache_unref_node(nsnode); return retval; } (*result_of)->ref_cnt = 1; (*result_of)->generation = 1; retval = sos_fs_nscache_register_opened_file(nsnode, *result_of); if (SOS_OK != retval) { fsnode->close_opened_file(fsnode, *result_of); return retval; } (*result_of)->open_flags = open_flags; return SOS_OK;}sos_ret_tsos_fs_duplicate_opened_file(struct sos_fs_opened_file * src_of, const struct sos_process * dst_proc, struct sos_fs_opened_file ** result_of){ sos_ret_t retval = src_of->duplicate(src_of, dst_proc, result_of); if (SOS_OK != retval) return retval; (*result_of)->ref_cnt = 1; (*result_of)->generation = 1; retval = sos_fs_nscache_register_opened_file(src_of->direntry, *result_of); if (SOS_OK != retval) { struct sos_fs_node * fsnode = sos_fs_nscache_get_fs_node(src_of->direntry); fsnode->close_opened_file(fsnode, *result_of); return retval; } return retval;}sos_ret_t sos_fs_open(const struct sos_process *owner, const char *_path, sos_size_t _pathlen, sos_ui32_t open_flags, sos_ui32_t creat_access_rights, struct sos_fs_opened_file ** of){ sos_ret_t retval; struct sos_fs_nscache_node *nsnode; struct sos_fs_node * fsnode; struct sos_fs_pathname path; /* O_DIR | O_CREAT combination not supported */ if ((open_flags & SOS_FS_OPEN_DIRECTORY) && (open_flags & SOS_FS_OPEN_CREAT)) return -SOS_EINVAL; if (_pathlen <= 0) return -SOS_ENOENT; path.contents = _path; path.length = _pathlen; if (path.contents[0] == '/') nsnode = sos_process_get_root(owner)->direntry; else nsnode = sos_process_get_cwd(owner)->direntry; retval = fs_lookup_node(& path, ! (open_flags & SOS_FS_OPEN_NOFOLLOW), sos_process_get_root(owner)->direntry, nsnode, & nsnode, & path, 0); if (SOS_OK != retval) return retval; if (path.length <= 0) { /* Found the exact match ! */ if (open_flags & SOS_FS_OPEN_EXCL) { sos_fs_nscache_unref_node(nsnode); return -SOS_EEXIST; } fsnode = sos_fs_nscache_get_fs_node(nsnode); if ((open_flags & SOS_FS_OPEN_DIRECTORY) && (fsnode->type != SOS_FS_NODE_DIRECTORY)) { sos_fs_nscache_unref_node(nsnode); return -SOS_ENOTDIR; } } else { struct sos_fs_nscache_node * parent_nsnode = nsnode; /* Did not find an exact match. Should create the node ! */ if (! (open_flags & SOS_FS_OPEN_CREAT)) { sos_fs_nscache_unref_node(parent_nsnode); return -SOS_ENOENT; } /* Create a new entry in the file system */ retval = fs_create_child_node(parent_nsnode, & path, SOS_FS_NODE_REGULAR_FILE, open_flags, owner, creat_access_rights, & nsnode); sos_fs_nscache_unref_node(parent_nsnode); if (SOS_OK != retval) { return retval; } fsnode = sos_fs_nscache_get_fs_node(nsnode); } /* Recompute access rights */ open_flags &= ~(SOS_FS_OPEN_CREAT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -