Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * namei.c
0004  *
0005  * Copyright (c) 1999 Al Smith
0006  *
0007  * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
0008  */
0009 
0010 #include <linux/buffer_head.h>
0011 #include <linux/string.h>
0012 #include <linux/exportfs.h>
0013 #include "efs.h"
0014 
0015 
0016 static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len)
0017 {
0018     struct buffer_head *bh;
0019 
0020     int         slot, namelen;
0021     char            *nameptr;
0022     struct efs_dir      *dirblock;
0023     struct efs_dentry   *dirslot;
0024     efs_ino_t       inodenum;
0025     efs_block_t     block;
0026  
0027     if (inode->i_size & (EFS_DIRBSIZE-1))
0028         pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n",
0029             __func__);
0030 
0031     for(block = 0; block < inode->i_blocks; block++) {
0032 
0033         bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
0034         if (!bh) {
0035             pr_err("%s(): failed to read dir block %d\n",
0036                    __func__, block);
0037             return 0;
0038         }
0039     
0040         dirblock = (struct efs_dir *) bh->b_data;
0041 
0042         if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
0043             pr_err("%s(): invalid directory block\n", __func__);
0044             brelse(bh);
0045             return 0;
0046         }
0047 
0048         for (slot = 0; slot < dirblock->slots; slot++) {
0049             dirslot  = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
0050 
0051             namelen  = dirslot->namelen;
0052             nameptr  = dirslot->name;
0053 
0054             if ((namelen == len) && (!memcmp(name, nameptr, len))) {
0055                 inodenum = be32_to_cpu(dirslot->inode);
0056                 brelse(bh);
0057                 return inodenum;
0058             }
0059         }
0060         brelse(bh);
0061     }
0062     return 0;
0063 }
0064 
0065 struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
0066 {
0067     efs_ino_t inodenum;
0068     struct inode *inode = NULL;
0069 
0070     inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
0071     if (inodenum)
0072         inode = efs_iget(dir->i_sb, inodenum);
0073 
0074     return d_splice_alias(inode, dentry);
0075 }
0076 
0077 static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino,
0078         u32 generation)
0079 {
0080     struct inode *inode;
0081 
0082     if (ino == 0)
0083         return ERR_PTR(-ESTALE);
0084     inode = efs_iget(sb, ino);
0085     if (IS_ERR(inode))
0086         return ERR_CAST(inode);
0087 
0088     if (generation && inode->i_generation != generation) {
0089         iput(inode);
0090         return ERR_PTR(-ESTALE);
0091     }
0092 
0093     return inode;
0094 }
0095 
0096 struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
0097         int fh_len, int fh_type)
0098 {
0099     return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
0100                     efs_nfs_get_inode);
0101 }
0102 
0103 struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
0104         int fh_len, int fh_type)
0105 {
0106     return generic_fh_to_parent(sb, fid, fh_len, fh_type,
0107                     efs_nfs_get_inode);
0108 }
0109 
0110 struct dentry *efs_get_parent(struct dentry *child)
0111 {
0112     struct dentry *parent = ERR_PTR(-ENOENT);
0113     efs_ino_t ino;
0114 
0115     ino = efs_find_entry(d_inode(child), "..", 2);
0116     if (ino)
0117         parent = d_obtain_alias(efs_iget(child->d_sb, ino));
0118 
0119     return parent;
0120 }