11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * namei.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 1999 Al Smith 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Portions derived from work (c) 1995,1996 Christian Vogelgsang. 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/buffer_head.h> 101da177e4SLinus Torvalds #include <linux/string.h> 1105da0804SChristoph Hellwig #include <linux/exportfs.h> 1245254b4fSChristoph Hellwig #include "efs.h" 1305da0804SChristoph Hellwig 141da177e4SLinus Torvalds 15ca356640SFabian Frederick static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) 16ca356640SFabian Frederick { 171da177e4SLinus Torvalds struct buffer_head *bh; 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds int slot, namelen; 201da177e4SLinus Torvalds char *nameptr; 211da177e4SLinus Torvalds struct efs_dir *dirblock; 221da177e4SLinus Torvalds struct efs_dentry *dirslot; 231da177e4SLinus Torvalds efs_ino_t inodenum; 241da177e4SLinus Torvalds efs_block_t block; 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds if (inode->i_size & (EFS_DIRBSIZE-1)) 27f403d1dbSFabian Frederick pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n", 28f403d1dbSFabian Frederick __func__); 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds for(block = 0; block < inode->i_blocks; block++) { 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 331da177e4SLinus Torvalds if (!bh) { 34f403d1dbSFabian Frederick pr_err("%s(): failed to read dir block %d\n", 35f403d1dbSFabian Frederick __func__, block); 361da177e4SLinus Torvalds return 0; 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds dirblock = (struct efs_dir *) bh->b_data; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 42f403d1dbSFabian Frederick pr_err("%s(): invalid directory block\n", __func__); 431da177e4SLinus Torvalds brelse(bh); 44ca356640SFabian Frederick return 0; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds for (slot = 0; slot < dirblock->slots; slot++) { 481da177e4SLinus Torvalds dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds namelen = dirslot->namelen; 511da177e4SLinus Torvalds nameptr = dirslot->name; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds if ((namelen == len) && (!memcmp(name, nameptr, len))) { 541da177e4SLinus Torvalds inodenum = be32_to_cpu(dirslot->inode); 551da177e4SLinus Torvalds brelse(bh); 56ca356640SFabian Frederick return inodenum; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds brelse(bh); 601da177e4SLinus Torvalds } 61ca356640SFabian Frederick return 0; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 6400cd8dd3SAl Viro struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 6500cd8dd3SAl Viro { 661da177e4SLinus Torvalds efs_ino_t inodenum; 671da177e4SLinus Torvalds struct inode *inode = NULL; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); 70a9049376SAl Viro if (inodenum) 71298384cdSDavid Howells inode = efs_iget(dir->i_sb, inodenum); 721da177e4SLinus Torvalds 732d8a10cdSAl Viro return d_splice_alias(inode, dentry); 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 7605da0804SChristoph Hellwig static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino, 7705da0804SChristoph Hellwig u32 generation) 785ca29607SChristoph Hellwig { 795ca29607SChristoph Hellwig struct inode *inode; 805ca29607SChristoph Hellwig 815ca29607SChristoph Hellwig if (ino == 0) 825ca29607SChristoph Hellwig return ERR_PTR(-ESTALE); 83298384cdSDavid Howells inode = efs_iget(sb, ino); 84298384cdSDavid Howells if (IS_ERR(inode)) 85298384cdSDavid Howells return ERR_CAST(inode); 865ca29607SChristoph Hellwig 87298384cdSDavid Howells if (generation && inode->i_generation != generation) { 885ca29607SChristoph Hellwig iput(inode); 8905da0804SChristoph Hellwig return ERR_PTR(-ESTALE); 9005da0804SChristoph Hellwig } 9105da0804SChristoph Hellwig 9205da0804SChristoph Hellwig return inode; 9305da0804SChristoph Hellwig } 9405da0804SChristoph Hellwig 9505da0804SChristoph Hellwig struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid, 9605da0804SChristoph Hellwig int fh_len, int fh_type) 9705da0804SChristoph Hellwig { 9805da0804SChristoph Hellwig return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 9905da0804SChristoph Hellwig efs_nfs_get_inode); 10005da0804SChristoph Hellwig } 10105da0804SChristoph Hellwig 10205da0804SChristoph Hellwig struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid, 10305da0804SChristoph Hellwig int fh_len, int fh_type) 10405da0804SChristoph Hellwig { 10505da0804SChristoph Hellwig return generic_fh_to_parent(sb, fid, fh_len, fh_type, 10605da0804SChristoph Hellwig efs_nfs_get_inode); 1075ca29607SChristoph Hellwig } 1085ca29607SChristoph Hellwig 1091da177e4SLinus Torvalds struct dentry *efs_get_parent(struct dentry *child) 1101da177e4SLinus Torvalds { 11144003728SChristoph Hellwig struct dentry *parent = ERR_PTR(-ENOENT); 1121da177e4SLinus Torvalds efs_ino_t ino; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds ino = efs_find_entry(child->d_inode, "..", 2); 11544003728SChristoph Hellwig if (ino) 11644003728SChristoph Hellwig parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino)); 11744003728SChristoph Hellwig 1181da177e4SLinus Torvalds return parent; 1191da177e4SLinus Torvalds } 120