static int sfs_create_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name, bool excl, struct inode **node_store) { int ret, slot; uint32_t ino; struct inode *link_node; if ((ret = sfs_dirent_search_nolock(sfs, sin, name, &ino, NULL, &slot)) != -E_NOENT) { if (ret != 0) { return ret; } if (!excl) { if ((ret = sfs_load_inode(sfs, &link_node, ino)) != 0) { return ret; } if (vop_info(link_node, sfs_inode)->din->type == SFS_TYPE_FILE) { goto out; } vop_ref_dec(link_node); } return -E_EXISTS; } else { if ((ret = sfs_dirent_create_inode(sfs, SFS_TYPE_FILE, &link_node)) != 0) { return ret; } if ((ret = sfs_dirent_link_nolock(sfs, sin, slot, vop_info(link_node, sfs_inode), name)) != 0) { vop_ref_dec(link_node); return ret; } } out: *node_store = link_node; return 0; }
static int sfs_namefile(struct inode *node, struct iobuf *iob) { struct sfs_disk_entry *entry; if (iob->io_resid <= 2 || (entry = kmalloc(sizeof(struct sfs_disk_entry))) == NULL) { return -E_NO_MEM; } struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); struct sfs_inode *sin = vop_info(node, sfs_inode); int ret; uint32_t ino; char *ptr = iob->io_base + iob->io_resid; size_t alen, resid = iob->io_resid - 2; vop_ref_inc(node); while ((ino = sin->ino) != SFS_BLKN_ROOT) { struct inode *parent; if ((ret = sfs_load_parent(sfs, sin, &parent)) != 0) { goto failed; } vop_ref_dec(node); node = parent, sin = vop_info(node, sfs_inode); assert(ino != sin->ino && sin->din->type == SFS_TYPE_DIR); if ((ret = trylock_sin(sin)) != 0) { goto failed; } ret = sfs_dirent_findino_nolock(sfs, sin, ino, entry); unlock_sin(sin); if (ret != 0) { goto failed; } if ((alen = strlen(entry->name) + 1) > resid) { goto failed_nomem; } resid -= alen, ptr -= alen; memcpy(ptr, entry->name, alen - 1); ptr[alen - 1] = '/'; } vop_ref_dec(node); alen = iob->io_resid - resid - 2; ptr = memmove(iob->io_base + 1, ptr, alen); ptr[-1] = '/', ptr[alen] = '\0'; iobuf_skip(iob, alen); kfree(entry); return 0; failed_nomem: ret = -E_NO_MEM; failed: vop_ref_dec(node); kfree(entry); return ret; }
static int pipe_root_create(struct inode *__node, const char *name, bool excl, struct inode **node_store) { assert((name[0] == 'r' || name[0] == 'w') && name[1] == '_'); int ret = 0; bool readonly = (name[0] == 'r'); name += 2; struct inode *node[2]; struct fs *fs = vop_fs(__node); struct pipe_fs *pipe = fsop_info(fs, pipe); lock_pipe(pipe); lookup_pipe_nolock(pipe, name, &node[0], &node[1]); if (!readonly) { struct inode *tmp = node[0]; node[0] = node[1], node[1] = tmp; } if (node[0] != NULL) { if (excl) { ret = -E_EXISTS, vop_ref_dec(node[0]); goto out; } *node_store = node[0]; goto out; } ret = -E_NO_MEM; struct pipe_state *state; if (node[1] == NULL) { if ((state = pipe_state_create()) == NULL) { goto out; } } else { state = vop_info(node[1], pipe_inode)->state; pipe_state_acquire(state); } struct inode *new_node; if ((new_node = pipe_create_inode(fs, name, state, readonly)) == NULL) { pipe_state_release(state); goto out; } list_add(&(pipe->pipe_list), &(vop_info(new_node, pipe_inode)->pipe_link)); ret = 0, *node_store = new_node; out: unlock_pipe(pipe); if (node[1] != NULL) { vop_ref_dec(node[1]); } return ret; }
int vfs_open(char *path, uint32_t open_flags, struct inode **node_store) { bool can_write = 0; switch (open_flags & O_ACCMODE) { case O_RDONLY: break; case O_WRONLY: case O_RDWR: can_write = 1; break; default: return -E_INVAL; } if (open_flags & O_TRUNC) { if (!can_write) { return -E_INVAL; } } int ret; struct inode *dir, *node; if (open_flags & O_CREAT) { char *name; bool excl = (open_flags & O_EXCL) != 0; if ((ret = vfs_lookup_parent(path, &dir, &name)) != 0) { return ret; } ret = vop_create(dir, name, excl, &node); vop_ref_dec(dir); } else { ret = vfs_lookup(path, &node); } if (ret != 0) { return ret; } assert(node != NULL); if ((ret = vop_open(node, open_flags)) != 0) { vop_ref_dec(node); return ret; } vop_open_inc(node); if (open_flags & O_TRUNC) { if ((ret = vop_truncate(node, 0)) != 0) { vop_open_dec(node); vop_ref_dec(node); return ret; } } *node_store = node; return 0; }
int sfs_getpath(struct inode *node, char *path, int maxlen){ int ret, namelen; int pos = maxlen - 2; uint inum; char *ptr = path + maxlen; char namebuf[DIRSIZ]; struct sfs_inode *sin = vop_info(node, sfs_inode); vop_ref_inc(node); while(1){ struct inode *parent; if((parent = sfs_dirlookup(node, "..", 0)) == 0){ goto failed; } inum = sin->inum; vop_ref_dec(node); if(node == parent){ vop_ref_dec(node); break; } node = parent; sin = vop_info(node, sfs_inode); ret = sfs_inumtoname(node, inum, namebuf); if(ret != 0){ goto failed; } if((namelen = strlen(namebuf) + 1) > pos){ return -1; } pos -= namelen; ptr -= namelen; memcpy(ptr, namebuf, namelen -1); ptr[namelen -1] = '/'; } namelen = maxlen - pos - 2; ptr = memmove(path + 5, ptr, namelen); ptr[-1] = '/'; ptr[-2] = ':'; ptr[-3] = 's'; ptr[-4] = 'f'; ptr[-5] = 's'; ptr[namelen] = '\0'; return 0; failed: vop_ref_dec(node); return -1; }
static int sfs_mkdir_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name) { int ret, slot; if ((ret = sfs_dirent_search_nolock(sfs, sin, name, NULL, NULL, &slot)) != -E_NOENT) { return (ret != 0) ? ret : -E_EXISTS; } struct inode *link_node; if ((ret = sfs_dirent_create_inode(sfs, SFS_TYPE_DIR, &link_node)) != 0) { return ret; } struct sfs_inode *lnksin = vop_info(link_node, sfs_inode); if ((ret = sfs_dirent_link_nolock(sfs, sin, slot, lnksin, name)) != 0) { assert(lnksin->din->nlinks == 0); assert(inode_ref_count(link_node) == 1 && inode_open_count(link_node) == 0); goto out; } /* set parent */ sfs_dirinfo_set_parent(lnksin, sin); /* add '.' link to itself */ sfs_nlinks_inc_nolock(lnksin); /* add '..' link to parent */ sfs_nlinks_inc_nolock(sin); out: vop_ref_dec(link_node); return ret; }
static int pipe_root_lookup(struct inode *__node, char *path, struct inode **node_store) { assert((path[0] == 'r' || path[0] == 'w') && path[1] == '_'); struct inode *node[2]; struct pipe_fs *pipe = fsop_info(vop_fs(__node), pipe); lock_pipe(pipe); { lookup_pipe_nolock(pipe, path + 2, &node[0], &node[1]); } unlock_pipe(pipe); if (path[0] != 'r') { struct inode *tmp = node[0]; node[0] = node[1], node[1] = tmp; } if (node[1] != NULL) { vop_ref_dec(node[1]); } if (node[0] == NULL) { return -E_NOENT; } *node_store = node[0]; return 0; }
// 设置当前的目录 int vfs_set_curdir(struct inode *dir) { int ret = 0; lock_cfs(); struct inode *old_dir; if ((old_dir = get_cwd_nolock()) != dir) { // 得到当前的工作目录的inode if (dir != NULL) { uint32_t type; if ((ret = vop_gettype(dir, &type)) != 0) { goto out; } if (!S_ISDIR(type)) { ret = -E_NOTDIR; goto out; } vop_ref_inc(dir); } set_cwd_nolock(dir); if (old_dir != NULL) { vop_ref_dec(old_dir); } } out: unlock_cfs(); return ret; }
/* * Get current directory, as a pathname. * Use vop_namefile to get the pathname. */ int vfs_getcwd(struct iobuf *iob) { int ret; struct inode *node; if ((ret = vfs_get_curdir(&node)) != 0) { return ret; } /* The current dir must be a directory, and thus it is not a device. */ assert(node->in_fs != NULL); const char *devname = vfs_get_devname(node->in_fs); if ((ret = iobuf_move(iob, (char *)devname, strlen(devname), 1, NULL)) != 0) { goto out; } char colon = ':'; if ((ret = iobuf_move(iob, &colon, sizeof(colon), 1, NULL)) != 0) { goto out; } ret = vop_namefile(node, iob); out: vop_ref_dec(node); return ret; }
/* * Common code to pull the device name, if any, off the front of a * path and choose the inode to begin the name lookup relative to. */ static int get_device(char *path, char **subpath, struct inode **node_store) { int i, slash = -1, colon = -1; /* * Locate the first colon or slash. */ for (i = 0; path[i] != '\0'; i ++) { if (path[i] == ':') { colon = i; break; } if (path[i] == '/') { slash = i; break; } } if (colon < 0 && slash != 0) { /* * * No colon before a slash, so no device name specified, and the slash isn't leading * or is also absent, so this is a relative path or just a bare filename. Start from * the current directory, and use the whole thing as the subpath. * */ *subpath = path; return vfs_get_curdir(node_store); } if (colon > 0) { /* device:path - get root of device's filesystem */ path[colon] = '\0'; /* device:/path - skip slash, treat as device:path */ while (path[++ colon] == '/'); *subpath = path + colon; return vfs_get_root(path, node_store); } /* * * we have either /path or :path * /path is a path relative to the root of the "boot filesystem" * :path is a path relative to the root of the current filesystem * */ int ret; if (*path == '/') { if ((ret = vfs_get_bootfs(node_store)) != 0) { return ret; } } else { assert(*path == ':'); struct inode *node; if ((ret = vfs_get_curdir(&node)) != 0) { return ret; } /* The current directory may not be a device, so it must have a fs. */ assert(node->in_fs != NULL); *node_store = fsop_get_root(node->in_fs); vop_ref_dec(node); } /* ///... or :/... */ while (*(++ path) == '/'); *subpath = path; return 0; }
static int sfs_lookup(struct inode *node, char *path, struct inode **node_store) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); assert(*path != '\0' && *path != '/'); vop_ref_inc(node); do { struct sfs_inode *sin = vop_info(node, sfs_inode); if (sin->din->type != SFS_TYPE_DIR) { vop_ref_dec(node); return -E_NOTDIR; } char *subpath; next: subpath = sfs_lookup_subpath(path); if (strcmp(path, ".") == 0) { if ((path = subpath) != NULL) { goto next; } break; } int ret; struct inode *subnode; if (strcmp(path, "..") == 0) { ret = sfs_load_parent(sfs, sin, &subnode); } else { if (strlen(path) > SFS_MAX_FNAME_LEN) { vop_ref_dec(node); return -E_TOO_BIG; } ret = sfs_lookup_once(sfs, sin, path, &subnode, NULL); } vop_ref_dec(node); if (ret != 0) { return ret; } node = subnode, path = subpath; } while (path != NULL); *node_store = node; return 0; }
/* * vfs_chdir - Set current directory, as a pathname. Use vfs_lookup to translate * it to a inode. */ int vfs_chdir(char *path) { // 改变当前的路径- int ret; struct inode *node; if ((ret = vfs_lookup(path, &node)) == 0) { ret = vfs_set_curdir(node); // 设置当前的目录 vop_ref_dec(node); } return ret; }
int vfs_readlink(char *path, struct iobuf *iob) { int ret; struct inode *node; if ((ret = vfs_lookup(path, &node)) != 0) { return ret; } ret = vop_readlink(node, iob); vop_ref_dec(node); return ret; }
int vfs_lookup_parent(char *path, struct inode **node_store, char **endp) { int ret; struct inode *node; if ((ret = get_device(path, &path, &node)) != 0) { return ret; } ret = (*path != '\0') ? vop_lookup_parent(node, path, node_store, endp) : -E_INVAL; vop_ref_dec(node); return ret; }
/* * sfs_lookup - Parse path relative to the passed directory * DIR, and hand back the inode for the file it * refers to. */ static int sfs_lookup(struct inode *node, char *path, struct inode **node_store) { struct sfs_fs *sfs = fsop_info(vop_fs(node), sfs); assert(*path != '\0' && *path != '/'); vop_ref_inc(node); struct sfs_inode *sin = vop_info(node, sfs_inode); if (sin->din->type != SFS_TYPE_DIR) { vop_ref_dec(node); return -E_NOTDIR; } struct inode *subnode; int ret = sfs_lookup_once(sfs, sin, path, &subnode, NULL); vop_ref_dec(node); if (ret != 0) { return ret; } *node_store = subnode; return 0; }
int pipe_open(struct inode **rnode_store, struct inode **wnode_store) { int ret; struct inode *root; if ((ret = vfs_get_root("pipe", &root)) != 0) { return ret; } ret = -E_NO_MEM; struct pipe_state *state; if ((state = pipe_state_create()) == NULL) { goto out; } struct fs *fs = vop_fs(root); struct inode *node[2] = { NULL, NULL }; if ((node[0] = pipe_create_inode(fs, NULL, state, 1)) == NULL) { goto failed_cleanup_state; } pipe_state_acquire(state); if ((node[1] = pipe_create_inode(fs, NULL, state, 0)) == NULL) { goto failed_cleanup_node0; } vop_open_inc(node[0]), vop_open_inc(node[1]); *rnode_store = node[0]; *wnode_store = node[1]; ret = 0; out: vop_ref_dec(root); return ret; failed_cleanup_node0: vop_ref_dec(node[0]); failed_cleanup_state: pipe_state_release(state); goto out; }
static void change_bootfs(struct inode *node) { struct inode *old; lock_bootfs(); { old = bootfs_node, bootfs_node = node; } unlock_bootfs(); if (old != NULL) { vop_ref_dec(old); } }
int vfs_unlink(char *path) { int ret; char *name; struct inode *dir; if ((ret = vfs_lookup_parent(path, &dir, &name)) != 0) { return ret; } ret = vop_unlink(dir, name); vop_ref_dec(dir); return ret; }
int vfs_symlink(char *old_path, char *new_path) { int ret; char *new_name; struct inode *new_dir; if ((ret = vfs_lookup_parent(new_path, &new_dir, &new_name)) != 0) { return ret; } ret = vop_symlink(new_dir, new_name, old_path); vop_ref_dec(new_dir); return ret; }
int vfs_rename(char *old_path, char *new_path) { int ret; char *old_name, *new_name; struct inode *old_dir, *new_dir; if ((ret = vfs_lookup_parent(old_path, &old_dir, &old_name)) != 0) { return ret; } if ((ret = vfs_lookup_parent(new_path, &new_dir, &new_name)) != 0) { vop_ref_dec(old_dir); return ret; } if (old_dir->in_fs == NULL || old_dir->in_fs != new_dir->in_fs) { ret = -E_XDEV; } else { ret = vop_rename(old_dir, old_name, new_dir, new_name); } vop_ref_dec(old_dir); vop_ref_dec(new_dir); return ret; }
static int sfs_rename2_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name, struct sfs_inode *newsin, const char *new_name) { uint32_t ino; int ret, slot1, slot2; if ((ret = sfs_dirent_search_nolock(sfs, sin, name, &ino, &slot1, NULL)) != 0) { return ret; } if ((ret = sfs_dirent_search_nolock(sfs, newsin, new_name, NULL, NULL, &slot2)) != -E_NOENT) { return (ret != 0) ? ret : -E_EXISTS; } struct inode *link_node; if ((ret = sfs_load_inode(sfs, &link_node, ino)) != 0) { return ret; } struct sfs_inode *lnksin = vop_info(link_node, sfs_inode); if ((ret = sfs_dirent_unlink_nolock(sfs, sin, slot1, lnksin)) != 0) { goto out; } int isdir = (lnksin->din->type == SFS_TYPE_DIR); /* remove '..' link from old parent */ if (isdir) { sfs_nlinks_dec_nolock(sin); } /* if link fails try to recover its old link */ if ((ret = sfs_dirent_link_nolock(sfs, newsin, slot2, lnksin, new_name)) != 0) { if (sfs_dirent_link_nolock_check(sfs, sin, slot1, lnksin, name) == 0) { if (isdir) { sfs_nlinks_inc_nolock(sin); } } goto out; } if (isdir) { /* set '..' link to new directory */ sfs_nlinks_inc_nolock(newsin); /* update parent relationship */ sfs_dirinfo_set_parent(lnksin, newsin); } out: vop_ref_dec(link_node); return ret; }
/* * vfs_lookup - get the inode according to the path filename */ int vfs_lookup(char *path, struct inode **node_store) { int ret; struct inode *node; if ((ret = get_device(path, &path, &node)) != 0) { return ret; } if (*path != '\0') { ret = vop_lookup(node, path, node_store); vop_ref_dec(node); return ret; } *node_store = node; return 0; }
void dev_init(void) { init_device(null); init_device(stdin); init_device(stdout); init_device(disk0); /* for Nand flash */ init_device(disk1); init_device(tty); //init_device(ashmem); // link such as stdout int ret; char *new_name; struct inode *old_node, *new_dir; if ((ret = vfs_lookup("stdout:", &old_node)) != 0) { kprintf("erho"); return;// ret; } if ((ret = vfs_lookup_parent("/dev", &new_dir, &new_name)) != 0) { vop_ref_dec(old_node); return;// ret; } // if (old_node->in_fs == NULL || old_node->in_fs != new_dir->in_fs) { // ret = -E_XDEV; // } // else { ret = vop_link(new_dir, new_name, old_node); kprintf("odife%d\n", ret); // } vop_ref_dec(old_node); vop_ref_dec(new_dir); }
void fs_destroy(struct fs_struct *fs_struct) { assert(fs_struct != NULL && fs_count(fs_struct) == 0); if (fs_struct->pwd != NULL) { vop_ref_dec(fs_struct->pwd); } int i; struct file *file = fs_struct->filemap; for (i = 0; i < FS_STRUCT_NENTRY; i ++, file ++) { if (file->status == FD_OPENED) { filemap_close(file); } assert(file->status == FD_NONE); } kfree(fs_struct); }
//Called when a proc exit void files_destroy(struct files_struct *filesp) { // 用于销毁文件 // cprintf("[files_destroy]\n"); assert(filesp != NULL && files_count(filesp) == 0); if (filesp->pwd != NULL) { // 如果当前目录不为空 vop_ref_dec(filesp->pwd); } int i; struct file *file = filesp->fd_array; for (i = 0; i < FILES_STRUCT_NENTRY; i ++, file ++) { if (file->status == FD_OPENED) { fd_array_close(file); // 关闭每一个文件 } assert(file->status == FD_NONE); } kfree(filesp); }
static int sfs_unlink_nolock(struct sfs_fs *sfs, struct sfs_inode *sin, const char *name) { int ret, slot; uint32_t ino; if ((ret = sfs_dirent_search_nolock(sfs, sin, name, &ino, &slot, NULL)) != 0) { return ret; } struct inode *link_node; if ((ret = sfs_load_inode(sfs, &link_node, ino)) != 0) { return ret; } struct sfs_inode *lnksin = vop_info(link_node, sfs_inode); if (lnksin->din->type != SFS_TYPE_DIR) { ret = sfs_dirent_unlink_nolock(sfs, sin, slot, lnksin); } else { if ((ret = trylock_sin(lnksin)) == 0) { if (lnksin->din->dirinfo.slots != 0) { ret = -E_NOTEMPTY; } else if ((ret = sfs_dirent_unlink_nolock(sfs, sin, slot, lnksin)) == 0) { /* lnksin must be empty, so set SFS_removed bit to invalidate further trylock opts */ SetSFSInodeRemoved(lnksin); /* remove '.' link */ sfs_nlinks_dec_nolock(lnksin); /* remove '..' link */ sfs_nlinks_dec_nolock(sin); } unlock_sin(lnksin); } } vop_ref_dec(link_node); return ret; }
int vfs_close(struct inode *node) { vop_open_dec(node); vop_ref_dec(node); return 0; }