1 /* 2 * namei.c 3 * 4 * Copyright (c) 1999 Al Smith 5 * 6 * Portions derived from work (c) 1995,1996 Christian Vogelgsang. 7 */ 8 9 #include <linux/buffer_head.h> 10 #include <linux/string.h> 11 #include <linux/exportfs.h> 12 #include "efs.h" 13 14 15 static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) 16 { 17 struct buffer_head *bh; 18 19 int slot, namelen; 20 char *nameptr; 21 struct efs_dir *dirblock; 22 struct efs_dentry *dirslot; 23 efs_ino_t inodenum; 24 efs_block_t block; 25 26 if (inode->i_size & (EFS_DIRBSIZE-1)) 27 pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n", 28 __func__); 29 30 for(block = 0; block < inode->i_blocks; block++) { 31 32 bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 33 if (!bh) { 34 pr_err("%s(): failed to read dir block %d\n", 35 __func__, block); 36 return 0; 37 } 38 39 dirblock = (struct efs_dir *) bh->b_data; 40 41 if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 42 pr_err("%s(): invalid directory block\n", __func__); 43 brelse(bh); 44 return 0; 45 } 46 47 for (slot = 0; slot < dirblock->slots; slot++) { 48 dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 49 50 namelen = dirslot->namelen; 51 nameptr = dirslot->name; 52 53 if ((namelen == len) && (!memcmp(name, nameptr, len))) { 54 inodenum = be32_to_cpu(dirslot->inode); 55 brelse(bh); 56 return inodenum; 57 } 58 } 59 brelse(bh); 60 } 61 return 0; 62 } 63 64 struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 65 { 66 efs_ino_t inodenum; 67 struct inode *inode = NULL; 68 69 inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); 70 if (inodenum) 71 inode = efs_iget(dir->i_sb, inodenum); 72 73 return d_splice_alias(inode, dentry); 74 } 75 76 static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino, 77 u32 generation) 78 { 79 struct inode *inode; 80 81 if (ino == 0) 82 return ERR_PTR(-ESTALE); 83 inode = efs_iget(sb, ino); 84 if (IS_ERR(inode)) 85 return ERR_CAST(inode); 86 87 if (generation && inode->i_generation != generation) { 88 iput(inode); 89 return ERR_PTR(-ESTALE); 90 } 91 92 return inode; 93 } 94 95 struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid, 96 int fh_len, int fh_type) 97 { 98 return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 99 efs_nfs_get_inode); 100 } 101 102 struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid, 103 int fh_len, int fh_type) 104 { 105 return generic_fh_to_parent(sb, fid, fh_len, fh_type, 106 efs_nfs_get_inode); 107 } 108 109 struct dentry *efs_get_parent(struct dentry *child) 110 { 111 struct dentry *parent = ERR_PTR(-ENOENT); 112 efs_ino_t ino; 113 114 ino = efs_find_entry(child->d_inode, "..", 2); 115 if (ino) 116 parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino)); 117 118 return parent; 119 } 120