Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2000-2001 Christoph Hellwig.
0004  * Copyright (c) 2016 Krzysztof Blaszkowski
0005  */
0006 
0007 /*
0008  * Veritas filesystem driver - lookup and other directory related code.
0009  */
0010 #include <linux/fs.h>
0011 #include <linux/time.h>
0012 #include <linux/mm.h>
0013 #include <linux/highmem.h>
0014 #include <linux/kernel.h>
0015 #include <linux/pagemap.h>
0016 
0017 #include "vxfs.h"
0018 #include "vxfs_dir.h"
0019 #include "vxfs_inode.h"
0020 #include "vxfs_extern.h"
0021 
0022 /*
0023  * Number of VxFS blocks per page.
0024  */
0025 #define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_SIZE / (sbp)->s_blocksize))
0026 
0027 
0028 static struct dentry *  vxfs_lookup(struct inode *, struct dentry *, unsigned int);
0029 static int      vxfs_readdir(struct file *, struct dir_context *);
0030 
0031 const struct inode_operations vxfs_dir_inode_ops = {
0032     .lookup =       vxfs_lookup,
0033 };
0034 
0035 const struct file_operations vxfs_dir_operations = {
0036     .llseek =       generic_file_llseek,
0037     .read =         generic_read_dir,
0038     .iterate_shared =   vxfs_readdir,
0039 };
0040 
0041 
0042 /**
0043  * vxfs_find_entry - find a mathing directory entry for a dentry
0044  * @ip:     directory inode
0045  * @dp:     dentry for which we want to find a direct
0046  * @ppp:    gets filled with the page the return value sits in
0047  *
0048  * Description:
0049  *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
0050  *   cache entry @dp.  @ppp will be filled with the page the return
0051  *   value resides in.
0052  *
0053  * Returns:
0054  *   The wanted direct on success, else a NULL pointer.
0055  */
0056 static struct vxfs_direct *
0057 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
0058 {
0059     u_long bsize = ip->i_sb->s_blocksize;
0060     const char *name = dp->d_name.name;
0061     int namelen = dp->d_name.len;
0062     loff_t limit = VXFS_DIRROUND(ip->i_size);
0063     struct vxfs_direct *de_exit = NULL;
0064     loff_t pos = 0;
0065     struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
0066 
0067     while (pos < limit) {
0068         struct page *pp;
0069         char *kaddr;
0070         int pg_ofs = pos & ~PAGE_MASK;
0071 
0072         pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
0073         if (IS_ERR(pp))
0074             return NULL;
0075         kaddr = (char *)page_address(pp);
0076 
0077         while (pg_ofs < PAGE_SIZE && pos < limit) {
0078             struct vxfs_direct *de;
0079 
0080             if ((pos & (bsize - 1)) < 4) {
0081                 struct vxfs_dirblk *dbp =
0082                     (struct vxfs_dirblk *)
0083                      (kaddr + (pos & ~PAGE_MASK));
0084                 int overhead = VXFS_DIRBLKOV(sbi, dbp);
0085 
0086                 pos += overhead;
0087                 pg_ofs += overhead;
0088             }
0089             de = (struct vxfs_direct *)(kaddr + pg_ofs);
0090 
0091             if (!de->d_reclen) {
0092                 pos += bsize - 1;
0093                 pos &= ~(bsize - 1);
0094                 break;
0095             }
0096 
0097             pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
0098             pos += fs16_to_cpu(sbi, de->d_reclen);
0099             if (!de->d_ino)
0100                 continue;
0101 
0102             if (namelen != fs16_to_cpu(sbi, de->d_namelen))
0103                 continue;
0104             if (!memcmp(name, de->d_name, namelen)) {
0105                 *ppp = pp;
0106                 de_exit = de;
0107                 break;
0108             }
0109         }
0110         if (!de_exit)
0111             vxfs_put_page(pp);
0112         else
0113             break;
0114     }
0115 
0116     return de_exit;
0117 }
0118 
0119 /**
0120  * vxfs_inode_by_name - find inode number for dentry
0121  * @dip:    directory to search in
0122  * @dp:     dentry we search for
0123  *
0124  * Description:
0125  *   vxfs_inode_by_name finds out the inode number of
0126  *   the path component described by @dp in @dip.
0127  *
0128  * Returns:
0129  *   The wanted inode number on success, else Zero.
0130  */
0131 static ino_t
0132 vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
0133 {
0134     struct vxfs_direct      *de;
0135     struct page         *pp;
0136     ino_t               ino = 0;
0137 
0138     de = vxfs_find_entry(dip, dp, &pp);
0139     if (de) {
0140         ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
0141         kunmap(pp);
0142         put_page(pp);
0143     }
0144     
0145     return (ino);
0146 }
0147 
0148 /**
0149  * vxfs_lookup - lookup pathname component
0150  * @dip:    dir in which we lookup
0151  * @dp:     dentry we lookup
0152  * @flags:  lookup flags
0153  *
0154  * Description:
0155  *   vxfs_lookup tries to lookup the pathname component described
0156  *   by @dp in @dip.
0157  *
0158  * Returns:
0159  *   A NULL-pointer on success, else a negative error code encoded
0160  *   in the return pointer.
0161  */
0162 static struct dentry *
0163 vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
0164 {
0165     struct inode        *ip = NULL;
0166     ino_t           ino;
0167              
0168     if (dp->d_name.len > VXFS_NAMELEN)
0169         return ERR_PTR(-ENAMETOOLONG);
0170                  
0171     ino = vxfs_inode_by_name(dip, dp);
0172     if (ino)
0173         ip = vxfs_iget(dip->i_sb, ino);
0174     return d_splice_alias(ip, dp);
0175 }
0176 
0177 /**
0178  * vxfs_readdir - read a directory
0179  * @fp:     the directory to read
0180  * @retp:   return buffer
0181  * @filler: filldir callback
0182  *
0183  * Description:
0184  *   vxfs_readdir fills @retp with directory entries from @fp
0185  *   using the VFS supplied callback @filler.
0186  *
0187  * Returns:
0188  *   Zero.
0189  */
0190 static int
0191 vxfs_readdir(struct file *fp, struct dir_context *ctx)
0192 {
0193     struct inode        *ip = file_inode(fp);
0194     struct super_block  *sbp = ip->i_sb;
0195     u_long          bsize = sbp->s_blocksize;
0196     loff_t          pos, limit;
0197     struct vxfs_sb_info *sbi = VXFS_SBI(sbp);
0198 
0199     if (ctx->pos == 0) {
0200         if (!dir_emit_dot(fp, ctx))
0201             goto out;
0202         ctx->pos++;
0203     }
0204     if (ctx->pos == 1) {
0205         if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
0206             goto out;
0207         ctx->pos++;
0208     }
0209 
0210     limit = VXFS_DIRROUND(ip->i_size);
0211     if (ctx->pos > limit)
0212         goto out;
0213 
0214     pos = ctx->pos & ~3L;
0215 
0216     while (pos < limit) {
0217         struct page *pp;
0218         char *kaddr;
0219         int pg_ofs = pos & ~PAGE_MASK;
0220         int rc = 0;
0221 
0222         pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
0223         if (IS_ERR(pp))
0224             return -ENOMEM;
0225 
0226         kaddr = (char *)page_address(pp);
0227 
0228         while (pg_ofs < PAGE_SIZE && pos < limit) {
0229             struct vxfs_direct *de;
0230 
0231             if ((pos & (bsize - 1)) < 4) {
0232                 struct vxfs_dirblk *dbp =
0233                     (struct vxfs_dirblk *)
0234                      (kaddr + (pos & ~PAGE_MASK));
0235                 int overhead = VXFS_DIRBLKOV(sbi, dbp);
0236 
0237                 pos += overhead;
0238                 pg_ofs += overhead;
0239             }
0240             de = (struct vxfs_direct *)(kaddr + pg_ofs);
0241 
0242             if (!de->d_reclen) {
0243                 pos += bsize - 1;
0244                 pos &= ~(bsize - 1);
0245                 break;
0246             }
0247 
0248             pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
0249             pos += fs16_to_cpu(sbi, de->d_reclen);
0250             if (!de->d_ino)
0251                 continue;
0252 
0253             rc = dir_emit(ctx, de->d_name,
0254                     fs16_to_cpu(sbi, de->d_namelen),
0255                     fs32_to_cpu(sbi, de->d_ino),
0256                     DT_UNKNOWN);
0257             if (!rc) {
0258                 /* the dir entry was not read, fix pos. */
0259                 pos -= fs16_to_cpu(sbi, de->d_reclen);
0260                 break;
0261             }
0262         }
0263         vxfs_put_page(pp);
0264         if (!rc)
0265             break;
0266     }
0267 
0268     ctx->pos = pos | 2;
0269 
0270 out:
0271     return 0;
0272 }