📄 dir.c
字号:
/* * dir.c * * Copyright (C) 1995, 1996 by Volker Lendecke * Modified for big endian by J.F. Chadima and David S. Miller * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache * Modified 1998, 1999 Wolfram Pienkoss for NLS * Modified 1999 Wolfram Pienkoss for directory caching * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info * */#include <linux/time.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/mm.h>#include <asm/uaccess.h>#include <asm/byteorder.h>#include <linux/smp_lock.h>#include <linux/ncp_fs.h>#include "ncplib_kernel.h"static void ncp_read_volume_list(struct file *, void *, filldir_t, struct ncp_cache_control *);static void ncp_do_readdir(struct file *, void *, filldir_t, struct ncp_cache_control *);static int ncp_readdir(struct file *, void *, filldir_t);static int ncp_create(struct inode *, struct dentry *, int, struct nameidata *);static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *);static int ncp_unlink(struct inode *, struct dentry *);static int ncp_mkdir(struct inode *, struct dentry *, int);static int ncp_rmdir(struct inode *, struct dentry *);static int ncp_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);static int ncp_mknod(struct inode * dir, struct dentry *dentry, int mode, dev_t rdev);#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)extern int ncp_symlink(struct inode *, struct dentry *, const char *);#else#define ncp_symlink NULL#endif const struct file_operations ncp_dir_operations ={ .read = generic_read_dir, .readdir = ncp_readdir, .ioctl = ncp_ioctl,#ifdef CONFIG_COMPAT .compat_ioctl = ncp_compat_ioctl,#endif};const struct inode_operations ncp_dir_inode_operations ={ .create = ncp_create, .lookup = ncp_lookup, .unlink = ncp_unlink, .symlink = ncp_symlink, .mkdir = ncp_mkdir, .rmdir = ncp_rmdir, .mknod = ncp_mknod, .rename = ncp_rename, .setattr = ncp_notify_change,};/* * Dentry operations routines */static int ncp_lookup_validate(struct dentry *, struct nameidata *);static int ncp_hash_dentry(struct dentry *, struct qstr *);static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);static int ncp_delete_dentry(struct dentry *);static struct dentry_operations ncp_dentry_operations ={ .d_revalidate = ncp_lookup_validate, .d_hash = ncp_hash_dentry, .d_compare = ncp_compare_dentry, .d_delete = ncp_delete_dentry,};struct dentry_operations ncp_root_dentry_operations ={ .d_hash = ncp_hash_dentry, .d_compare = ncp_compare_dentry, .d_delete = ncp_delete_dentry,};/* * Note: leave the hash unchanged if the directory * is case-sensitive. */static int ncp_hash_dentry(struct dentry *dentry, struct qstr *this){ struct nls_table *t; unsigned long hash; int i; t = NCP_IO_TABLE(dentry); if (!ncp_case_sensitive(dentry->d_inode)) { hash = init_name_hash(); for (i=0; i<this->len ; i++) hash = partial_name_hash(ncp_tolower(t, this->name[i]), hash); this->hash = end_name_hash(hash); } return 0;}static intncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b){ if (a->len != b->len) return 1; if (ncp_case_sensitive(dentry->d_inode)) return strncmp(a->name, b->name, a->len); return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len);}/* * This is the callback from dput() when d_count is going to 0. * We use this to unhash dentries with bad inodes. * Closing files can be safely postponed until iput() - it's done there anyway. */static intncp_delete_dentry(struct dentry * dentry){ struct inode *inode = dentry->d_inode; if (inode) { if (is_bad_inode(inode)) return 1; } else { /* N.B. Unhash negative dentries? */ } return 0;}static inline intncp_single_volume(struct ncp_server *server){ return (server->m.mounted_vol[0] != '\0');}static inline int ncp_is_server_root(struct inode *inode){ return (!ncp_single_volume(NCP_SERVER(inode)) && inode == inode->i_sb->s_root->d_inode);}/* * This is the callback when the dcache has a lookup hit. */#ifdef CONFIG_NCPFS_STRONG/* try to delete a readonly file (NW R bit set) */static intncp_force_unlink(struct inode *dir, struct dentry* dentry){ int res=0x9c,res2; struct nw_modify_dos_info info; __le32 old_nwattr; struct inode *inode; memset(&info, 0, sizeof(info)); /* remove the Read-Only flag on the NW server */ inode = dentry->d_inode; old_nwattr = NCP_FINFO(inode)->nwattr; info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT); res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); if (res2) goto leave_me; /* now try again the delete operation */ res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry); if (res) /* delete failed, set R bit again */ { info.attributes = old_nwattr; res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); if (res2) goto leave_me; }leave_me: return(res);}#endif /* CONFIG_NCPFS_STRONG */#ifdef CONFIG_NCPFS_STRONGstatic intncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name, struct inode *new_dir, struct dentry* new_dentry, char *_new_name){ struct nw_modify_dos_info info; int res=0x90,res2; struct inode *old_inode = old_dentry->d_inode; __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr; __le32 new_nwattr = 0; /* shut compiler warning */ int old_nwattr_changed = 0; int new_nwattr_changed = 0; memset(&info, 0, sizeof(info)); /* remove the Read-Only flag on the NW server */ info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); if (!res2) old_nwattr_changed = 1; if (new_dentry && new_dentry->d_inode) { new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr; info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); if (!res2) new_nwattr_changed = 1; } /* now try again the rename operation */ /* but only if something really happened */ if (new_nwattr_changed || old_nwattr_changed) { res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), old_dir, _old_name, new_dir, _new_name); } if (res) goto leave_me; /* file was successfully renamed, so: do not set attributes on old file - it no longer exists copy attributes from old file to new */ new_nwattr_changed = old_nwattr_changed; new_nwattr = old_nwattr; old_nwattr_changed = 0; leave_me:; if (old_nwattr_changed) { info.attributes = old_nwattr; res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); /* ignore errors */ } if (new_nwattr_changed) { info.attributes = new_nwattr; res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); /* ignore errors */ } return(res);}#endif /* CONFIG_NCPFS_STRONG */static int__ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd){ struct ncp_server *server; struct dentry *parent; struct inode *dir; struct ncp_entry_info finfo; int res, val = 0, len; __u8 __name[NCP_MAXPATHLEN + 1]; parent = dget_parent(dentry); dir = parent->d_inode; if (!dentry->d_inode) goto finished; server = NCP_SERVER(dir); if (!ncp_conn_valid(server)) goto finished; /* * Inspired by smbfs: * The default validation is based on dentry age: * We set the max age at mount time. (But each * successful server lookup renews the timestamp.) */ val = NCP_TEST_AGE(server, dentry); if (val) goto finished; DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n", dentry->d_parent->d_name.name, dentry->d_name.name, NCP_GET_AGE(dentry)); len = sizeof(__name); if (ncp_is_server_root(dir)) { res = ncp_io2vol(server, __name, &len, dentry->d_name.name, dentry->d_name.len, 1); if (!res) res = ncp_lookup_volume(server, __name, &(finfo.i)); } else { res = ncp_io2vol(server, __name, &len, dentry->d_name.name, dentry->d_name.len, !ncp_preserve_case(dir)); if (!res) res = ncp_obtain_info(server, dir, __name, &(finfo.i)); } finfo.volume = finfo.i.volNumber; DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n", dentry->d_parent->d_name.name, __name, res); /* * If we didn't find it, or if it has a different dirEntNum to * what we remember, it's not valid any more. */ if (!res) { if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) { ncp_new_dentry(dentry); val=1; } else DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n"); ncp_update_inode2(dentry->d_inode, &finfo); }finished: DDPRINTK("ncp_lookup_validate: result=%d\n", val); dput(parent); return val;}static intncp_lookup_validate(struct dentry * dentry, struct nameidata *nd){ int res; lock_kernel(); res = __ncp_lookup_validate(dentry, nd); unlock_kernel(); return res;}static struct dentry *ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos){ struct dentry *dent = dentry; struct list_head *next; if (d_validate(dent, parent)) { if (dent->d_name.len <= NCP_MAXPATHLEN && (unsigned long)dent->d_fsdata == fpos) { if (!dent->d_inode) { dput(dent); dent = NULL; } return dent; } dput(dent); } /* If a pointer is invalid, we search the dentry. */ spin_lock(&dcache_lock); next = parent->d_subdirs.next; while (next != &parent->d_subdirs) { dent = list_entry(next, struct dentry, d_u.d_child); if ((unsigned long)dent->d_fsdata == fpos) { if (dent->d_inode) dget_locked(dent); else dent = NULL; spin_unlock(&dcache_lock); goto out; } next = next->next; } spin_unlock(&dcache_lock); return NULL;out: return dent;}static time_t ncp_obtain_mtime(struct dentry *dentry){ struct inode *inode = dentry->d_inode; struct ncp_server *server = NCP_SERVER(inode); struct nw_info_struct i; if (!ncp_conn_valid(server) || ncp_is_server_root(inode)) return 0; if (ncp_obtain_info(server, inode, NULL, &i)) return 0; return ncp_date_dos2unix(i.modifyTime, i.modifyDate);}static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir){ struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct page *page = NULL; struct ncp_server *server = NCP_SERVER(inode); union ncp_dir_cache *cache = NULL; struct ncp_cache_control ctl; int result, mtime_valid = 0; time_t mtime = 0; lock_kernel(); ctl.page = NULL; ctl.cache = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -