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/efs_fs.h> 12 #include <linux/smp_lock.h> 13 14 static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) { 15 struct buffer_head *bh; 16 17 int slot, namelen; 18 char *nameptr; 19 struct efs_dir *dirblock; 20 struct efs_dentry *dirslot; 21 efs_ino_t inodenum; 22 efs_block_t block; 23 24 if (inode->i_size & (EFS_DIRBSIZE-1)) 25 printk(KERN_WARNING "EFS: WARNING: find_entry(): directory size not a multiple of EFS_DIRBSIZE\n"); 26 27 for(block = 0; block < inode->i_blocks; block++) { 28 29 bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 30 if (!bh) { 31 printk(KERN_ERR "EFS: find_entry(): failed to read dir block %d\n", block); 32 return 0; 33 } 34 35 dirblock = (struct efs_dir *) bh->b_data; 36 37 if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 38 printk(KERN_ERR "EFS: find_entry(): invalid directory block\n"); 39 brelse(bh); 40 return(0); 41 } 42 43 for(slot = 0; slot < dirblock->slots; slot++) { 44 dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 45 46 namelen = dirslot->namelen; 47 nameptr = dirslot->name; 48 49 if ((namelen == len) && (!memcmp(name, nameptr, len))) { 50 inodenum = be32_to_cpu(dirslot->inode); 51 brelse(bh); 52 return(inodenum); 53 } 54 } 55 brelse(bh); 56 } 57 return(0); 58 } 59 60 struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { 61 efs_ino_t inodenum; 62 struct inode * inode = NULL; 63 64 lock_kernel(); 65 inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); 66 if (inodenum) { 67 if (!(inode = iget(dir->i_sb, inodenum))) { 68 unlock_kernel(); 69 return ERR_PTR(-EACCES); 70 } 71 } 72 unlock_kernel(); 73 74 d_add(dentry, inode); 75 return NULL; 76 } 77 78 struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp) 79 { 80 __u32 *objp = vobjp; 81 unsigned long ino = objp[0]; 82 __u32 generation = objp[1]; 83 struct inode *inode; 84 struct dentry *result; 85 86 if (ino == 0) 87 return ERR_PTR(-ESTALE); 88 inode = iget(sb, ino); 89 if (inode == NULL) 90 return ERR_PTR(-ENOMEM); 91 92 if (is_bad_inode(inode) || 93 (generation && inode->i_generation != generation)) { 94 result = ERR_PTR(-ESTALE); 95 goto out_iput; 96 } 97 98 result = d_alloc_anon(inode); 99 if (!result) { 100 result = ERR_PTR(-ENOMEM); 101 goto out_iput; 102 } 103 return result; 104 105 out_iput: 106 iput(inode); 107 return result; 108 } 109 110 struct dentry *efs_get_parent(struct dentry *child) 111 { 112 struct dentry *parent; 113 struct inode *inode; 114 efs_ino_t ino; 115 int error; 116 117 lock_kernel(); 118 119 error = -ENOENT; 120 ino = efs_find_entry(child->d_inode, "..", 2); 121 if (!ino) 122 goto fail; 123 124 error = -EACCES; 125 inode = iget(child->d_inode->i_sb, ino); 126 if (!inode) 127 goto fail; 128 129 error = -ENOMEM; 130 parent = d_alloc_anon(inode); 131 if (!parent) 132 goto fail_iput; 133 134 unlock_kernel(); 135 return parent; 136 137 fail_iput: 138 iput(inode); 139 fail: 140 unlock_kernel(); 141 return ERR_PTR(error); 142 } 143