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 *, struct dir_context *); 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 .iterate = 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 * @flags: lookup flags 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, struct dir_context *ctx) 239 { 240 struct inode *ip = file_inode(fp); 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 if (ctx->pos == 0) { 247 if (!dir_emit_dot(fp, ctx)) 248 return 0; 249 ctx->pos = 1; 250 } 251 if (ctx->pos == 1) { 252 if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR)) 253 return 0; 254 ctx->pos = 2; 255 } 256 pos = ctx->pos - 2; 257 258 if (pos > VXFS_DIRROUND(ip->i_size)) 259 return 0; 260 261 npages = dir_pages(ip); 262 nblocks = dir_blocks(ip); 263 pblocks = VXFS_BLOCK_PER_PAGE(sbp); 264 265 page = pos >> PAGE_CACHE_SHIFT; 266 offset = pos & ~PAGE_CACHE_MASK; 267 block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks; 268 269 for (; page < npages; page++, block = 0) { 270 char *kaddr; 271 struct page *pp; 272 273 pp = vxfs_get_page(ip->i_mapping, page); 274 if (IS_ERR(pp)) 275 continue; 276 kaddr = (char *)page_address(pp); 277 278 for (; block <= nblocks && block <= pblocks; block++) { 279 char *baddr, *limit; 280 struct vxfs_dirblk *dbp; 281 struct vxfs_direct *de; 282 283 baddr = kaddr + (block * bsize); 284 limit = baddr + bsize - VXFS_DIRLEN(1); 285 286 dbp = (struct vxfs_dirblk *)baddr; 287 de = (struct vxfs_direct *) 288 (offset ? 289 (kaddr + offset) : 290 (baddr + VXFS_DIRBLKOV(dbp))); 291 292 for (; (char *)de <= limit; de = vxfs_next_entry(de)) { 293 if (!de->d_reclen) 294 break; 295 if (!de->d_ino) 296 continue; 297 298 offset = (char *)de - kaddr; 299 ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2; 300 if (!dir_emit(ctx, de->d_name, de->d_namelen, 301 de->d_ino, DT_UNKNOWN)) { 302 vxfs_put_page(pp); 303 return 0; 304 } 305 } 306 offset = 0; 307 } 308 vxfs_put_page(pp); 309 offset = 0; 310 } 311 ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2; 312 return 0; 313 } 314