📄 dir.c
字号:
/* * Directory operations for Coda filesystem * Original version: (C) 1996 P. Braam and M. Callahan * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University * * Carnegie Mellon encourages users to contribute improvements to * the Coda project. Contact Peter Braam (coda@cs.cmu.edu). */#include <linux/types.h>#include <linux/kernel.h>#include <linux/time.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/smp_lock.h>#include <asm/uaccess.h>#include <linux/coda.h>#include <linux/coda_linux.h>#include <linux/coda_psdev.h>#include <linux/coda_fs_i.h>#include <linux/coda_cache.h>#include "coda_int.h"/* dir inode-ops */static int coda_create(struct inode *dir, struct dentry *new, int mode, struct nameidata *nd);static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd);static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, struct dentry *entry);static int coda_unlink(struct inode *dir_inode, struct dentry *entry);static int coda_symlink(struct inode *dir_inode, struct dentry *entry, const char *symname);static int coda_mkdir(struct inode *dir_inode, struct dentry *entry, int mode);static int coda_rmdir(struct inode *dir_inode, struct dentry *entry);static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry);/* dir file-ops */static int coda_readdir(struct file *file, void *buf, filldir_t filldir);/* dentry ops */static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);static int coda_dentry_delete(struct dentry *);/* support routines */static int coda_venus_readdir(struct file *coda_file, void *buf, filldir_t filldir);/* same as fs/bad_inode.c */static int coda_return_EIO(void){ return -EIO;}#define CODA_EIO_ERROR ((void *) (coda_return_EIO))static struct dentry_operations coda_dentry_operations ={ .d_revalidate = coda_dentry_revalidate, .d_delete = coda_dentry_delete,};const struct inode_operations coda_dir_inode_operations ={ .create = coda_create, .lookup = coda_lookup, .link = coda_link, .unlink = coda_unlink, .symlink = coda_symlink, .mkdir = coda_mkdir, .rmdir = coda_rmdir, .mknod = CODA_EIO_ERROR, .rename = coda_rename, .permission = coda_permission, .getattr = coda_getattr, .setattr = coda_setattr,};const struct file_operations coda_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = coda_readdir, .open = coda_open, .release = coda_release, .fsync = coda_fsync,};/* inode operations for directories *//* access routines: lookup, readlink, permission */static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd){ struct inode *inode = NULL; struct CodaFid resfid = { { 0, } }; int type = 0; int error = 0; const char *name = entry->d_name.name; size_t length = entry->d_name.len; if (length > CODA_MAXNAMLEN) { printk(KERN_ERR "name too long: lookup, %s (%*s)\n", coda_i2s(dir), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { error = coda_cnode_makectl(&inode, dir->i_sb); type = CODA_NOCACHE; goto exit; } lock_kernel(); error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length, &type, &resfid); if (!error) error = coda_cnode_make(&inode, &resfid, dir->i_sb); unlock_kernel(); if (error && error != -ENOENT) return ERR_PTR(error);exit: entry->d_op = &coda_dentry_operations; if (inode && (type & CODA_NOCACHE)) coda_flag_inode(inode, C_VATTR | C_PURGE); return d_splice_alias(inode, entry);}int coda_permission(struct inode *inode, int mask, struct nameidata *nd){ int error = 0; if (!mask) return 0; lock_kernel(); if (coda_cache_check(inode, mask)) goto out; error = venus_access(inode->i_sb, coda_i2f(inode), mask); if (!error) coda_cache_enter(inode, mask); out: unlock_kernel(); return error;}static inline void coda_dir_update_mtime(struct inode *dir){#ifdef REQUERY_VENUS_FOR_MTIME /* invalidate the directory cnode's attributes so we refetch the * attributes from venus next time the inode is referenced */ coda_flag_inode(dir, C_VATTR);#else /* optimistically we can also act as if our nose bleeds. The * granularity of the mtime is coarse anyways so we might actually be * right most of the time. Note: we only do this for directories. */ dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;#endif}/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a * trick to fool GNU find's optimizations. If we can't be sure of the link * (because of volume mount points) we set i_nlink to 1 which forces find * to consider every child as a possible directory. We should also never * see an increment or decrement for deleted directories where i_nlink == 0 */static inline void coda_dir_inc_nlink(struct inode *dir){ if (dir->i_nlink >= 2) inc_nlink(dir);}static inline void coda_dir_drop_nlink(struct inode *dir){ if (dir->i_nlink > 2) drop_nlink(dir);}/* creation routines: create, mknod, mkdir, link, symlink */static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd){ int error=0; const char *name=de->d_name.name; int length=de->d_name.len; struct inode *inode; struct CodaFid newfid; struct coda_vattr attrs; lock_kernel(); if (coda_isroot(dir) && coda_iscontrol(name, length)) { unlock_kernel(); return -EPERM; } error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 0, mode, &newfid, &attrs); if ( error ) { unlock_kernel(); d_drop(de); return error; } inode = coda_iget(dir->i_sb, &newfid, &attrs); if ( IS_ERR(inode) ) { unlock_kernel(); d_drop(de); return PTR_ERR(inode); } /* invalidate the directory cnode's attributes */ coda_dir_update_mtime(dir); unlock_kernel(); d_instantiate(de, inode); return 0;}static int coda_mkdir(struct inode *dir, struct dentry *de, int mode){ struct inode *inode; struct coda_vattr attrs; const char *name = de->d_name.name; int len = de->d_name.len; int error; struct CodaFid newfid; lock_kernel(); if (coda_isroot(dir) && coda_iscontrol(name, len)) { unlock_kernel(); return -EPERM; } attrs.va_mode = mode; error = venus_mkdir(dir->i_sb, coda_i2f(dir), name, len, &newfid, &attrs); if ( error ) { unlock_kernel(); d_drop(de); return error; } inode = coda_iget(dir->i_sb, &newfid, &attrs); if ( IS_ERR(inode) ) { unlock_kernel(); d_drop(de); return PTR_ERR(inode); } /* invalidate the directory cnode's attributes */ coda_dir_inc_nlink(dir); coda_dir_update_mtime(dir); unlock_kernel(); d_instantiate(de, inode); return 0;}/* try to make de an entry in dir_inodde linked to source_de */ static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de){ struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; int error; lock_kernel(); if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) { unlock_kernel(); return -EPERM; } error = venus_link(dir_inode->i_sb, coda_i2f(inode), coda_i2f(dir_inode), (const char *)name, len); if (error) { d_drop(de); goto out; } coda_dir_update_mtime(dir_inode); atomic_inc(&inode->i_count); d_instantiate(de, inode); inc_nlink(inode);out: unlock_kernel(); return(error);}static int coda_symlink(struct inode *dir_inode, struct dentry *de, const char *symname){ const char *name = de->d_name.name; int len = de->d_name.len; int symlen; int error = 0; lock_kernel(); if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) { unlock_kernel(); return -EPERM; } symlen = strlen(symname); if ( symlen > CODA_MAXPATHLEN ) { unlock_kernel(); return -ENAMETOOLONG; } /* * This entry is now negative. Since we do not create * an inode for the entry we have to drop it. */ d_drop(de); error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, symname, symlen); /* mtime is no good anymore */ if ( !error ) coda_dir_update_mtime(dir_inode); unlock_kernel(); return error;}/* destruction routines: unlink, rmdir */int coda_unlink(struct inode *dir, struct dentry *de){ int error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -