namei.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,434 行 · 第 1/3 页
C
1,434 行
/* * We try to drop the dentry early: we should have * a usage count of 2 if we're the only user of this * dentry, and if that is true (possibly after pruning * the dcache), then we drop the dentry now. * * A low-level filesystem can, if it choses, legally * do a * * if (!list_empty(&dentry->d_hash)) * return -EBUSY; * * if it cannot handle the case of removing a directory * that is still in use by something else.. */ switch (dentry->d_count) { default: shrink_dcache_parent(dentry); if (dentry->d_count != 2) break; case 2: d_drop(dentry); } error = dir->i_op->rmdir(dir, dentry); return error;}#ifdef OSKIT int do_rmdir(const char * name)#elsestatic inline int do_rmdir(const char * name)#endif{ int error; struct dentry *dir; struct dentry *dentry; dentry = lookup_dentry(name, NULL, 0); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit; error = -ENOENT; if (!dentry->d_inode) goto exit_dput; dir = dget(dentry->d_parent); /* * The dentry->d_count stuff confuses d_delete() enough to * not kill the inode from under us while it is locked. This * wouldn't be needed, except the dentry semaphore is really * in the inode, not in the dentry.. */ dentry->d_count++; double_lock(dir, dentry); error = -ENOENT; if (check_parent(dir, dentry)) error = vfs_rmdir(dir->d_inode, dentry); double_unlock(dentry, dir);exit_dput: dput(dentry);exit: return error;}asmlinkage int sys_rmdir(const char * pathname){ int error; char * tmp; lock_kernel(); tmp = getname(pathname); error = PTR_ERR(tmp); if (!IS_ERR(tmp)) { error = do_rmdir(tmp); putname(tmp); } unlock_kernel(); return error;}int vfs_unlink(struct inode *dir, struct dentry *dentry){ int error; error = may_delete(dir, dentry, 0); if (!error) { error = -EPERM; if (dir->i_op && dir->i_op->unlink) { DQUOT_INIT(dir); error = dir->i_op->unlink(dir, dentry); } } return error;}#ifdef OSKIT int do_unlink(const char * name)#elsestatic inline int do_unlink(const char * name)#endif{ int error; struct dentry *dir; struct dentry *dentry; dentry = lookup_dentry(name, NULL, 0); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit; dir = lock_parent(dentry); error = -ENOENT; if (check_parent(dir, dentry)) error = vfs_unlink(dir->d_inode, dentry); unlock_dir(dir); dput(dentry);exit: return error;}asmlinkage int sys_unlink(const char * pathname){ int error; char * tmp; lock_kernel(); tmp = getname(pathname); error = PTR_ERR(tmp); if (!IS_ERR(tmp)) { error = do_unlink(tmp); putname(tmp); } unlock_kernel(); return error;}#ifdef OSKIT int do_symlink(const char * oldname, const char * newname)#elsestatic inline int do_symlink(const char * oldname, const char * newname)#endif{ int error; struct dentry *dir; struct dentry *dentry; dentry = lookup_dentry(newname, NULL, 0); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit; dir = lock_parent(dentry); error = -ENOENT; if (!check_parent(dir, dentry)) goto exit_lock; error = may_create(dir->d_inode, dentry); if (error) goto exit_lock; error = -EPERM; if (!dir->d_inode->i_op || !dir->d_inode->i_op->symlink) goto exit_lock; DQUOT_INIT(dir->d_inode); error = dir->d_inode->i_op->symlink(dir->d_inode, dentry, oldname);exit_lock: unlock_dir(dir); dput(dentry);exit: return error;}asmlinkage int sys_symlink(const char * oldname, const char * newname){ int error; char * from; lock_kernel(); from = getname(oldname); error = PTR_ERR(from); if (!IS_ERR(from)) { char * to; to = getname(newname); error = PTR_ERR(to); if (!IS_ERR(to)) { error = do_symlink(from,to); putname(to); } putname(from); } unlock_kernel(); return error;}#ifdef OSKIT int do_link(struct dentry *dentry, const char * newname)#elsestatic inline int do_link(const char * oldname, const char * newname)#endif{ struct dentry *old_dentry, *new_dentry, *dir; struct inode *inode; int error; /* * Hardlinks are often used in delicate situations. We avoid * security-related surprises by not following symlinks on the * newname. --KAB * * We don't follow them on the oldname either to be compatible * with linux 2.0, and to avoid hard-linking to directories * and other special files. --ADM */#ifdef OSKIT dget(dentry); old_dentry = dentry;#else old_dentry = lookup_dentry(oldname, NULL, 0);#endif error = PTR_ERR(old_dentry); if (IS_ERR(old_dentry)) goto exit; new_dentry = lookup_dentry(newname, NULL, 0); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) goto exit_old; dir = lock_parent(new_dentry); error = -ENOENT; if (!check_parent(dir, new_dentry)) goto exit_lock; error = -ENOENT; inode = old_dentry->d_inode; if (!inode) goto exit_lock; error = may_create(dir->d_inode, new_dentry); if (error) goto exit_lock; error = -EXDEV; if (dir->d_inode->i_dev != inode->i_dev) goto exit_lock; /* * A link to an append-only or immutable file cannot be created. */ error = -EPERM; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) goto exit_lock; error = -EPERM; if (!dir->d_inode->i_op || !dir->d_inode->i_op->link) goto exit_lock; DQUOT_INIT(dir->d_inode); error = dir->d_inode->i_op->link(old_dentry, dir->d_inode, new_dentry);exit_lock: unlock_dir(dir); dput(new_dentry);exit_old: dput(old_dentry);exit: return error;}#ifndef OSKITasmlinkage int sys_link(const char * oldname, const char * newname){ int error; char * from; lock_kernel(); from = getname(oldname); error = PTR_ERR(from); if (!IS_ERR(from)) { char * to; to = getname(newname); error = PTR_ERR(to); if (!IS_ERR(to)) { error = do_link(from,to); putname(to); } putname(from); } unlock_kernel(); return error;}#endifint vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ int error; int need_rehash = 0; if (old_dentry->d_inode == new_dentry->d_inode) return 0; error = may_delete(old_dir, old_dentry, 1); if (error) return error; if (new_dir->i_dev != old_dir->i_dev) return -EXDEV; if (!new_dentry->d_inode) error = may_create(new_dir, new_dentry); else error = may_delete(new_dir, new_dentry, 1); if (error) return error; if (!old_dir->i_op || !old_dir->i_op->rename) return -EPERM; /* * If we are going to change the parent - check write permissions, * we'll need to flip '..'. */ if (new_dir != old_dir) { error = permission(old_dentry->d_inode, MAY_WRITE); } if (error) return error; DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); down(&old_dir->i_sb->s_vfs_rename_sem); error = -EINVAL; if (is_subdir(new_dentry, old_dentry)) goto out_unlock; if (new_dentry->d_inode) { error = -EBUSY; if (d_invalidate(new_dentry)<0) goto out_unlock; need_rehash = 1; } error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); if (need_rehash) d_rehash(new_dentry); if (!error) d_move(old_dentry,new_dentry);out_unlock: up(&old_dir->i_sb->s_vfs_rename_sem); return error;}int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ int error; if (old_dentry->d_inode == new_dentry->d_inode) return 0; error = may_delete(old_dir, old_dentry, 0); if (error) return error; if (new_dir->i_dev != old_dir->i_dev) return -EXDEV; if (!new_dentry->d_inode) error = may_create(new_dir, new_dentry); else error = may_delete(new_dir, new_dentry, 0); if (error) return error; if (!old_dir->i_op || !old_dir->i_op->rename) return -EPERM; DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); if (error) return error; /* The following d_move() should become unconditional */ if (!(old_dir->i_sb->s_flags & MS_ODD_RENAME)) { d_move(old_dentry, new_dentry); } return 0;}int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ if (S_ISDIR(old_dentry->d_inode->i_mode)) return vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); else return vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);}#ifdef OSKIT int do_rename(const char * oldname, const char * newname)#elsestatic inline int do_rename(const char * oldname, const char * newname)#endif{ int error; struct dentry * old_dir, * new_dir; struct dentry * old_dentry, *new_dentry; old_dentry = lookup_dentry(oldname, NULL, 0); error = PTR_ERR(old_dentry); if (IS_ERR(old_dentry)) goto exit; error = -ENOENT; if (!old_dentry->d_inode) goto exit_old; { unsigned int flags = 0; if (S_ISDIR(old_dentry->d_inode->i_mode)) flags = LOOKUP_SLASHOK; new_dentry = lookup_dentry(newname, NULL, flags); } error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) goto exit_old; new_dir = get_parent(new_dentry); old_dir = get_parent(old_dentry); double_lock(new_dir, old_dir); error = -ENOENT; if (check_parent(old_dir, old_dentry) && check_parent(new_dir, new_dentry)) error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); double_unlock(new_dir, old_dir); dput(new_dentry);exit_old: dput(old_dentry);exit: return error;}asmlinkage int sys_rename(const char * oldname, const char * newname){ int error; char * from; lock_kernel(); from = getname(oldname); error = PTR_ERR(from); if (!IS_ERR(from)) { char * to; to = getname(newname); error = PTR_ERR(to); if (!IS_ERR(to)) { error = do_rename(from,to); putname(to); } putname(from); } unlock_kernel(); return error;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?