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