xref: /openbmc/linux/fs/efs/namei.c (revision 298384cd)
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>
111da177e4SLinus Torvalds #include <linux/efs_fs.h>
121da177e4SLinus Torvalds #include <linux/smp_lock.h>
1305da0804SChristoph Hellwig #include <linux/exportfs.h>
1405da0804SChristoph Hellwig 
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) {
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))
271da177e4SLinus Torvalds 		printk(KERN_WARNING "EFS: WARNING: find_entry(): directory size not a multiple of EFS_DIRBSIZE\n");
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds 	for(block = 0; block < inode->i_blocks; block++) {
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds 		bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
321da177e4SLinus Torvalds 		if (!bh) {
331da177e4SLinus Torvalds 			printk(KERN_ERR "EFS: find_entry(): failed to read dir block %d\n", block);
341da177e4SLinus Torvalds 			return 0;
351da177e4SLinus Torvalds 		}
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 		dirblock = (struct efs_dir *) bh->b_data;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds 		if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
401da177e4SLinus Torvalds 			printk(KERN_ERR "EFS: find_entry(): invalid directory block\n");
411da177e4SLinus Torvalds 			brelse(bh);
421da177e4SLinus Torvalds 			return(0);
431da177e4SLinus Torvalds 		}
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 		for(slot = 0; slot < dirblock->slots; slot++) {
461da177e4SLinus Torvalds 			dirslot  = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 			namelen  = dirslot->namelen;
491da177e4SLinus Torvalds 			nameptr  = dirslot->name;
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds 			if ((namelen == len) && (!memcmp(name, nameptr, len))) {
521da177e4SLinus Torvalds 				inodenum = be32_to_cpu(dirslot->inode);
531da177e4SLinus Torvalds 				brelse(bh);
541da177e4SLinus Torvalds 				return(inodenum);
551da177e4SLinus Torvalds 			}
561da177e4SLinus Torvalds 		}
571da177e4SLinus Torvalds 		brelse(bh);
581da177e4SLinus Torvalds 	}
591da177e4SLinus Torvalds 	return(0);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) {
631da177e4SLinus Torvalds 	efs_ino_t inodenum;
641da177e4SLinus Torvalds 	struct inode * inode = NULL;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	lock_kernel();
671da177e4SLinus Torvalds 	inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
681da177e4SLinus Torvalds 	if (inodenum) {
69298384cdSDavid Howells 		inode = efs_iget(dir->i_sb, inodenum);
70298384cdSDavid Howells 		if (IS_ERR(inode)) {
711da177e4SLinus Torvalds 			unlock_kernel();
72298384cdSDavid Howells 			return ERR_CAST(inode);
731da177e4SLinus Torvalds 		}
741da177e4SLinus Torvalds 	}
751da177e4SLinus Torvalds 	unlock_kernel();
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	d_add(dentry, inode);
781da177e4SLinus Torvalds 	return NULL;
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds 
8105da0804SChristoph Hellwig static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino,
8205da0804SChristoph Hellwig 		u32 generation)
835ca29607SChristoph Hellwig {
845ca29607SChristoph Hellwig 	struct inode *inode;
855ca29607SChristoph Hellwig 
865ca29607SChristoph Hellwig 	if (ino == 0)
875ca29607SChristoph Hellwig 		return ERR_PTR(-ESTALE);
88298384cdSDavid Howells 	inode = efs_iget(sb, ino);
89298384cdSDavid Howells 	if (IS_ERR(inode))
90298384cdSDavid Howells 		return ERR_CAST(inode);
915ca29607SChristoph Hellwig 
92298384cdSDavid Howells 	if (generation && inode->i_generation != generation) {
935ca29607SChristoph Hellwig 		iput(inode);
9405da0804SChristoph Hellwig 		return ERR_PTR(-ESTALE);
9505da0804SChristoph Hellwig 	}
9605da0804SChristoph Hellwig 
9705da0804SChristoph Hellwig 	return inode;
9805da0804SChristoph Hellwig }
9905da0804SChristoph Hellwig 
10005da0804SChristoph Hellwig struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
10105da0804SChristoph Hellwig 		int fh_len, int fh_type)
10205da0804SChristoph Hellwig {
10305da0804SChristoph Hellwig 	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
10405da0804SChristoph Hellwig 				    efs_nfs_get_inode);
10505da0804SChristoph Hellwig }
10605da0804SChristoph Hellwig 
10705da0804SChristoph Hellwig struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
10805da0804SChristoph Hellwig 		int fh_len, int fh_type)
10905da0804SChristoph Hellwig {
11005da0804SChristoph Hellwig 	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
11105da0804SChristoph Hellwig 				    efs_nfs_get_inode);
1125ca29607SChristoph Hellwig }
1135ca29607SChristoph Hellwig 
1141da177e4SLinus Torvalds struct dentry *efs_get_parent(struct dentry *child)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds 	struct dentry *parent;
1171da177e4SLinus Torvalds 	struct inode *inode;
1181da177e4SLinus Torvalds 	efs_ino_t ino;
119298384cdSDavid Howells 	long error;
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	lock_kernel();
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 	error = -ENOENT;
1241da177e4SLinus Torvalds 	ino = efs_find_entry(child->d_inode, "..", 2);
1251da177e4SLinus Torvalds 	if (!ino)
1261da177e4SLinus Torvalds 		goto fail;
1271da177e4SLinus Torvalds 
128298384cdSDavid Howells 	inode = efs_iget(child->d_inode->i_sb, ino);
129298384cdSDavid Howells 	if (IS_ERR(inode)) {
130298384cdSDavid Howells 		error = PTR_ERR(inode);
1311da177e4SLinus Torvalds 		goto fail;
132298384cdSDavid Howells 	}
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	error = -ENOMEM;
1351da177e4SLinus Torvalds 	parent = d_alloc_anon(inode);
1361da177e4SLinus Torvalds 	if (!parent)
1371da177e4SLinus Torvalds 		goto fail_iput;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	unlock_kernel();
1401da177e4SLinus Torvalds 	return parent;
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds  fail_iput:
1431da177e4SLinus Torvalds 	iput(inode);
1441da177e4SLinus Torvalds  fail:
1451da177e4SLinus Torvalds 	unlock_kernel();
1461da177e4SLinus Torvalds 	return ERR_PTR(error);
1471da177e4SLinus Torvalds }
148