root/fs/freevxfs/vxfs_lookup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vxfs_find_entry
  2. vxfs_inode_by_name
  3. vxfs_lookup
  4. vxfs_readdir

   1 /*
   2  * Copyright (c) 2000-2001 Christoph Hellwig.
   3  * Copyright (c) 2016 Krzysztof Blaszkowski
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  * 1. Redistributions of source code must retain the above copyright
  10  *    notice, this list of conditions, and the following disclaimer,
  11  *    without modification.
  12  * 2. The name of the author may not be used to endorse or promote products
  13  *    derived from this software without specific prior written permission.
  14  *
  15  * Alternatively, this software may be distributed under the terms of the
  16  * GNU General Public License ("GPL").
  17  *
  18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28  * SUCH DAMAGE.
  29  */
  30 
  31 /*
  32  * Veritas filesystem driver - lookup and other directory related code.
  33  */
  34 #include <linux/fs.h>
  35 #include <linux/time.h>
  36 #include <linux/mm.h>
  37 #include <linux/highmem.h>
  38 #include <linux/kernel.h>
  39 #include <linux/pagemap.h>
  40 
  41 #include "vxfs.h"
  42 #include "vxfs_dir.h"
  43 #include "vxfs_inode.h"
  44 #include "vxfs_extern.h"
  45 
  46 /*
  47  * Number of VxFS blocks per page.
  48  */
  49 #define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_SIZE / (sbp)->s_blocksize))
  50 
  51 
  52 static struct dentry *  vxfs_lookup(struct inode *, struct dentry *, unsigned int);
  53 static int              vxfs_readdir(struct file *, struct dir_context *);
  54 
  55 const struct inode_operations vxfs_dir_inode_ops = {
  56         .lookup =               vxfs_lookup,
  57 };
  58 
  59 const struct file_operations vxfs_dir_operations = {
  60         .llseek =               generic_file_llseek,
  61         .read =                 generic_read_dir,
  62         .iterate_shared =       vxfs_readdir,
  63 };
  64 
  65 
  66 /**
  67  * vxfs_find_entry - find a mathing directory entry for a dentry
  68  * @ip:         directory inode
  69  * @dp:         dentry for which we want to find a direct
  70  * @ppp:        gets filled with the page the return value sits in
  71  *
  72  * Description:
  73  *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
  74  *   cache entry @dp.  @ppp will be filled with the page the return
  75  *   value resides in.
  76  *
  77  * Returns:
  78  *   The wanted direct on success, else a NULL pointer.
  79  */
  80 static struct vxfs_direct *
  81 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
  82 {
  83         u_long bsize = ip->i_sb->s_blocksize;
  84         const char *name = dp->d_name.name;
  85         int namelen = dp->d_name.len;
  86         loff_t limit = VXFS_DIRROUND(ip->i_size);
  87         struct vxfs_direct *de_exit = NULL;
  88         loff_t pos = 0;
  89         struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
  90 
  91         while (pos < limit) {
  92                 struct page *pp;
  93                 char *kaddr;
  94                 int pg_ofs = pos & ~PAGE_MASK;
  95 
  96                 pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
  97                 if (IS_ERR(pp))
  98                         return NULL;
  99                 kaddr = (char *)page_address(pp);
 100 
 101                 while (pg_ofs < PAGE_SIZE && pos < limit) {
 102                         struct vxfs_direct *de;
 103 
 104                         if ((pos & (bsize - 1)) < 4) {
 105                                 struct vxfs_dirblk *dbp =
 106                                         (struct vxfs_dirblk *)
 107                                          (kaddr + (pos & ~PAGE_MASK));
 108                                 int overhead = VXFS_DIRBLKOV(sbi, dbp);
 109 
 110                                 pos += overhead;
 111                                 pg_ofs += overhead;
 112                         }
 113                         de = (struct vxfs_direct *)(kaddr + pg_ofs);
 114 
 115                         if (!de->d_reclen) {
 116                                 pos += bsize - 1;
 117                                 pos &= ~(bsize - 1);
 118                                 break;
 119                         }
 120 
 121                         pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
 122                         pos += fs16_to_cpu(sbi, de->d_reclen);
 123                         if (!de->d_ino)
 124                                 continue;
 125 
 126                         if (namelen != fs16_to_cpu(sbi, de->d_namelen))
 127                                 continue;
 128                         if (!memcmp(name, de->d_name, namelen)) {
 129                                 *ppp = pp;
 130                                 de_exit = de;
 131                                 break;
 132                         }
 133                 }
 134                 if (!de_exit)
 135                         vxfs_put_page(pp);
 136                 else
 137                         break;
 138         }
 139 
 140         return de_exit;
 141 }
 142 
 143 /**
 144  * vxfs_inode_by_name - find inode number for dentry
 145  * @dip:        directory to search in
 146  * @dp:         dentry we search for
 147  *
 148  * Description:
 149  *   vxfs_inode_by_name finds out the inode number of
 150  *   the path component described by @dp in @dip.
 151  *
 152  * Returns:
 153  *   The wanted inode number on success, else Zero.
 154  */
 155 static ino_t
 156 vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
 157 {
 158         struct vxfs_direct              *de;
 159         struct page                     *pp;
 160         ino_t                           ino = 0;
 161 
 162         de = vxfs_find_entry(dip, dp, &pp);
 163         if (de) {
 164                 ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
 165                 kunmap(pp);
 166                 put_page(pp);
 167         }
 168         
 169         return (ino);
 170 }
 171 
 172 /**
 173  * vxfs_lookup - lookup pathname component
 174  * @dip:        dir in which we lookup
 175  * @dp:         dentry we lookup
 176  * @flags:      lookup flags
 177  *
 178  * Description:
 179  *   vxfs_lookup tries to lookup the pathname component described
 180  *   by @dp in @dip.
 181  *
 182  * Returns:
 183  *   A NULL-pointer on success, else a negative error code encoded
 184  *   in the return pointer.
 185  */
 186 static struct dentry *
 187 vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
 188 {
 189         struct inode            *ip = NULL;
 190         ino_t                   ino;
 191                          
 192         if (dp->d_name.len > VXFS_NAMELEN)
 193                 return ERR_PTR(-ENAMETOOLONG);
 194                                  
 195         ino = vxfs_inode_by_name(dip, dp);
 196         if (ino)
 197                 ip = vxfs_iget(dip->i_sb, ino);
 198         return d_splice_alias(ip, dp);
 199 }
 200 
 201 /**
 202  * vxfs_readdir - read a directory
 203  * @fp:         the directory to read
 204  * @retp:       return buffer
 205  * @filler:     filldir callback
 206  *
 207  * Description:
 208  *   vxfs_readdir fills @retp with directory entries from @fp
 209  *   using the VFS supplied callback @filler.
 210  *
 211  * Returns:
 212  *   Zero.
 213  */
 214 static int
 215 vxfs_readdir(struct file *fp, struct dir_context *ctx)
 216 {
 217         struct inode            *ip = file_inode(fp);
 218         struct super_block      *sbp = ip->i_sb;
 219         u_long                  bsize = sbp->s_blocksize;
 220         loff_t                  pos, limit;
 221         struct vxfs_sb_info     *sbi = VXFS_SBI(sbp);
 222 
 223         if (ctx->pos == 0) {
 224                 if (!dir_emit_dot(fp, ctx))
 225                         goto out;
 226                 ctx->pos++;
 227         }
 228         if (ctx->pos == 1) {
 229                 if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
 230                         goto out;
 231                 ctx->pos++;
 232         }
 233 
 234         limit = VXFS_DIRROUND(ip->i_size);
 235         if (ctx->pos > limit)
 236                 goto out;
 237 
 238         pos = ctx->pos & ~3L;
 239 
 240         while (pos < limit) {
 241                 struct page *pp;
 242                 char *kaddr;
 243                 int pg_ofs = pos & ~PAGE_MASK;
 244                 int rc = 0;
 245 
 246                 pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
 247                 if (IS_ERR(pp))
 248                         return -ENOMEM;
 249 
 250                 kaddr = (char *)page_address(pp);
 251 
 252                 while (pg_ofs < PAGE_SIZE && pos < limit) {
 253                         struct vxfs_direct *de;
 254 
 255                         if ((pos & (bsize - 1)) < 4) {
 256                                 struct vxfs_dirblk *dbp =
 257                                         (struct vxfs_dirblk *)
 258                                          (kaddr + (pos & ~PAGE_MASK));
 259                                 int overhead = VXFS_DIRBLKOV(sbi, dbp);
 260 
 261                                 pos += overhead;
 262                                 pg_ofs += overhead;
 263                         }
 264                         de = (struct vxfs_direct *)(kaddr + pg_ofs);
 265 
 266                         if (!de->d_reclen) {
 267                                 pos += bsize - 1;
 268                                 pos &= ~(bsize - 1);
 269                                 break;
 270                         }
 271 
 272                         pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
 273                         pos += fs16_to_cpu(sbi, de->d_reclen);
 274                         if (!de->d_ino)
 275                                 continue;
 276 
 277                         rc = dir_emit(ctx, de->d_name,
 278                                         fs16_to_cpu(sbi, de->d_namelen),
 279                                         fs32_to_cpu(sbi, de->d_ino),
 280                                         DT_UNKNOWN);
 281                         if (!rc) {
 282                                 /* the dir entry was not read, fix pos. */
 283                                 pos -= fs16_to_cpu(sbi, de->d_reclen);
 284                                 break;
 285                         }
 286                 }
 287                 vxfs_put_page(pp);
 288                 if (!rc)
 289                         break;
 290         }
 291 
 292         ctx->pos = pos | 2;
 293 
 294 out:
 295         return 0;
 296 }

/* [<][>][^][v][top][bottom][index][help] */