18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2000-2001 Christoph Hellwig. 38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Krzysztof Blaszkowski 48c2ecf20Sopenharmony_ci * All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 78c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 88c2ecf20Sopenharmony_ci * are met: 98c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 108c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 118c2ecf20Sopenharmony_ci * without modification. 128c2ecf20Sopenharmony_ci * 2. The name of the author may not be used to endorse or promote products 138c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 168c2ecf20Sopenharmony_ci * GNU General Public License ("GPL"). 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 198c2ecf20Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 208c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 218c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 228c2ecf20Sopenharmony_ci * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 238c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 248c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 258c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 268c2ecf20Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 278c2ecf20Sopenharmony_ci * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 288c2ecf20Sopenharmony_ci * SUCH DAMAGE. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Veritas filesystem driver - lookup and other directory related code. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci#include <linux/fs.h> 358c2ecf20Sopenharmony_ci#include <linux/time.h> 368c2ecf20Sopenharmony_ci#include <linux/mm.h> 378c2ecf20Sopenharmony_ci#include <linux/highmem.h> 388c2ecf20Sopenharmony_ci#include <linux/kernel.h> 398c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "vxfs.h" 428c2ecf20Sopenharmony_ci#include "vxfs_dir.h" 438c2ecf20Sopenharmony_ci#include "vxfs_inode.h" 448c2ecf20Sopenharmony_ci#include "vxfs_extern.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * Number of VxFS blocks per page. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci#define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_SIZE / (sbp)->s_blocksize)) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int); 538c2ecf20Sopenharmony_cistatic int vxfs_readdir(struct file *, struct dir_context *); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciconst struct inode_operations vxfs_dir_inode_ops = { 568c2ecf20Sopenharmony_ci .lookup = vxfs_lookup, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciconst struct file_operations vxfs_dir_operations = { 608c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 618c2ecf20Sopenharmony_ci .read = generic_read_dir, 628c2ecf20Sopenharmony_ci .iterate_shared = vxfs_readdir, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * vxfs_find_entry - find a mathing directory entry for a dentry 688c2ecf20Sopenharmony_ci * @ip: directory inode 698c2ecf20Sopenharmony_ci * @dp: dentry for which we want to find a direct 708c2ecf20Sopenharmony_ci * @ppp: gets filled with the page the return value sits in 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * Description: 738c2ecf20Sopenharmony_ci * vxfs_find_entry finds a &struct vxfs_direct for the VFS directory 748c2ecf20Sopenharmony_ci * cache entry @dp. @ppp will be filled with the page the return 758c2ecf20Sopenharmony_ci * value resides in. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * Returns: 788c2ecf20Sopenharmony_ci * The wanted direct on success, else a NULL pointer. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_cistatic struct vxfs_direct * 818c2ecf20Sopenharmony_civxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci u_long bsize = ip->i_sb->s_blocksize; 848c2ecf20Sopenharmony_ci const char *name = dp->d_name.name; 858c2ecf20Sopenharmony_ci int namelen = dp->d_name.len; 868c2ecf20Sopenharmony_ci loff_t limit = VXFS_DIRROUND(ip->i_size); 878c2ecf20Sopenharmony_ci struct vxfs_direct *de_exit = NULL; 888c2ecf20Sopenharmony_ci loff_t pos = 0; 898c2ecf20Sopenharmony_ci struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci while (pos < limit) { 928c2ecf20Sopenharmony_ci struct page *pp; 938c2ecf20Sopenharmony_ci char *kaddr; 948c2ecf20Sopenharmony_ci int pg_ofs = pos & ~PAGE_MASK; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT); 978c2ecf20Sopenharmony_ci if (IS_ERR(pp)) 988c2ecf20Sopenharmony_ci return NULL; 998c2ecf20Sopenharmony_ci kaddr = (char *)page_address(pp); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci while (pg_ofs < PAGE_SIZE && pos < limit) { 1028c2ecf20Sopenharmony_ci struct vxfs_direct *de; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if ((pos & (bsize - 1)) < 4) { 1058c2ecf20Sopenharmony_ci struct vxfs_dirblk *dbp = 1068c2ecf20Sopenharmony_ci (struct vxfs_dirblk *) 1078c2ecf20Sopenharmony_ci (kaddr + (pos & ~PAGE_MASK)); 1088c2ecf20Sopenharmony_ci int overhead = VXFS_DIRBLKOV(sbi, dbp); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci pos += overhead; 1118c2ecf20Sopenharmony_ci pg_ofs += overhead; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci de = (struct vxfs_direct *)(kaddr + pg_ofs); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (!de->d_reclen) { 1168c2ecf20Sopenharmony_ci pos += bsize - 1; 1178c2ecf20Sopenharmony_ci pos &= ~(bsize - 1); 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci pg_ofs += fs16_to_cpu(sbi, de->d_reclen); 1228c2ecf20Sopenharmony_ci pos += fs16_to_cpu(sbi, de->d_reclen); 1238c2ecf20Sopenharmony_ci if (!de->d_ino) 1248c2ecf20Sopenharmony_ci continue; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (namelen != fs16_to_cpu(sbi, de->d_namelen)) 1278c2ecf20Sopenharmony_ci continue; 1288c2ecf20Sopenharmony_ci if (!memcmp(name, de->d_name, namelen)) { 1298c2ecf20Sopenharmony_ci *ppp = pp; 1308c2ecf20Sopenharmony_ci de_exit = de; 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci if (!de_exit) 1358c2ecf20Sopenharmony_ci vxfs_put_page(pp); 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return de_exit; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/** 1448c2ecf20Sopenharmony_ci * vxfs_inode_by_name - find inode number for dentry 1458c2ecf20Sopenharmony_ci * @dip: directory to search in 1468c2ecf20Sopenharmony_ci * @dp: dentry we search for 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * Description: 1498c2ecf20Sopenharmony_ci * vxfs_inode_by_name finds out the inode number of 1508c2ecf20Sopenharmony_ci * the path component described by @dp in @dip. 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * Returns: 1538c2ecf20Sopenharmony_ci * The wanted inode number on success, else Zero. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_cistatic ino_t 1568c2ecf20Sopenharmony_civxfs_inode_by_name(struct inode *dip, struct dentry *dp) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct vxfs_direct *de; 1598c2ecf20Sopenharmony_ci struct page *pp; 1608c2ecf20Sopenharmony_ci ino_t ino = 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci de = vxfs_find_entry(dip, dp, &pp); 1638c2ecf20Sopenharmony_ci if (de) { 1648c2ecf20Sopenharmony_ci ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino); 1658c2ecf20Sopenharmony_ci kunmap(pp); 1668c2ecf20Sopenharmony_ci put_page(pp); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return (ino); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/** 1738c2ecf20Sopenharmony_ci * vxfs_lookup - lookup pathname component 1748c2ecf20Sopenharmony_ci * @dip: dir in which we lookup 1758c2ecf20Sopenharmony_ci * @dp: dentry we lookup 1768c2ecf20Sopenharmony_ci * @flags: lookup flags 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * Description: 1798c2ecf20Sopenharmony_ci * vxfs_lookup tries to lookup the pathname component described 1808c2ecf20Sopenharmony_ci * by @dp in @dip. 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * Returns: 1838c2ecf20Sopenharmony_ci * A NULL-pointer on success, else a negative error code encoded 1848c2ecf20Sopenharmony_ci * in the return pointer. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic struct dentry * 1878c2ecf20Sopenharmony_civxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct inode *ip = NULL; 1908c2ecf20Sopenharmony_ci ino_t ino; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (dp->d_name.len > VXFS_NAMELEN) 1938c2ecf20Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci ino = vxfs_inode_by_name(dip, dp); 1968c2ecf20Sopenharmony_ci if (ino) 1978c2ecf20Sopenharmony_ci ip = vxfs_iget(dip->i_sb, ino); 1988c2ecf20Sopenharmony_ci return d_splice_alias(ip, dp); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * vxfs_readdir - read a directory 2038c2ecf20Sopenharmony_ci * @fp: the directory to read 2048c2ecf20Sopenharmony_ci * @retp: return buffer 2058c2ecf20Sopenharmony_ci * @filler: filldir callback 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Description: 2088c2ecf20Sopenharmony_ci * vxfs_readdir fills @retp with directory entries from @fp 2098c2ecf20Sopenharmony_ci * using the VFS supplied callback @filler. 2108c2ecf20Sopenharmony_ci * 2118c2ecf20Sopenharmony_ci * Returns: 2128c2ecf20Sopenharmony_ci * Zero. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistatic int 2158c2ecf20Sopenharmony_civxfs_readdir(struct file *fp, struct dir_context *ctx) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct inode *ip = file_inode(fp); 2188c2ecf20Sopenharmony_ci struct super_block *sbp = ip->i_sb; 2198c2ecf20Sopenharmony_ci u_long bsize = sbp->s_blocksize; 2208c2ecf20Sopenharmony_ci loff_t pos, limit; 2218c2ecf20Sopenharmony_ci struct vxfs_sb_info *sbi = VXFS_SBI(sbp); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (ctx->pos == 0) { 2248c2ecf20Sopenharmony_ci if (!dir_emit_dot(fp, ctx)) 2258c2ecf20Sopenharmony_ci goto out; 2268c2ecf20Sopenharmony_ci ctx->pos++; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci if (ctx->pos == 1) { 2298c2ecf20Sopenharmony_ci if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR)) 2308c2ecf20Sopenharmony_ci goto out; 2318c2ecf20Sopenharmony_ci ctx->pos++; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci limit = VXFS_DIRROUND(ip->i_size); 2358c2ecf20Sopenharmony_ci if (ctx->pos > limit) 2368c2ecf20Sopenharmony_ci goto out; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci pos = ctx->pos & ~3L; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci while (pos < limit) { 2418c2ecf20Sopenharmony_ci struct page *pp; 2428c2ecf20Sopenharmony_ci char *kaddr; 2438c2ecf20Sopenharmony_ci int pg_ofs = pos & ~PAGE_MASK; 2448c2ecf20Sopenharmony_ci int rc = 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT); 2478c2ecf20Sopenharmony_ci if (IS_ERR(pp)) 2488c2ecf20Sopenharmony_ci return -ENOMEM; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci kaddr = (char *)page_address(pp); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci while (pg_ofs < PAGE_SIZE && pos < limit) { 2538c2ecf20Sopenharmony_ci struct vxfs_direct *de; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if ((pos & (bsize - 1)) < 4) { 2568c2ecf20Sopenharmony_ci struct vxfs_dirblk *dbp = 2578c2ecf20Sopenharmony_ci (struct vxfs_dirblk *) 2588c2ecf20Sopenharmony_ci (kaddr + (pos & ~PAGE_MASK)); 2598c2ecf20Sopenharmony_ci int overhead = VXFS_DIRBLKOV(sbi, dbp); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci pos += overhead; 2628c2ecf20Sopenharmony_ci pg_ofs += overhead; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci de = (struct vxfs_direct *)(kaddr + pg_ofs); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!de->d_reclen) { 2678c2ecf20Sopenharmony_ci pos += bsize - 1; 2688c2ecf20Sopenharmony_ci pos &= ~(bsize - 1); 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci pg_ofs += fs16_to_cpu(sbi, de->d_reclen); 2738c2ecf20Sopenharmony_ci pos += fs16_to_cpu(sbi, de->d_reclen); 2748c2ecf20Sopenharmony_ci if (!de->d_ino) 2758c2ecf20Sopenharmony_ci continue; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci rc = dir_emit(ctx, de->d_name, 2788c2ecf20Sopenharmony_ci fs16_to_cpu(sbi, de->d_namelen), 2798c2ecf20Sopenharmony_ci fs32_to_cpu(sbi, de->d_ino), 2808c2ecf20Sopenharmony_ci DT_UNKNOWN); 2818c2ecf20Sopenharmony_ci if (!rc) { 2828c2ecf20Sopenharmony_ci /* the dir entry was not read, fix pos. */ 2838c2ecf20Sopenharmony_ci pos -= fs16_to_cpu(sbi, de->d_reclen); 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci vxfs_put_page(pp); 2888c2ecf20Sopenharmony_ci if (!rc) 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci ctx->pos = pos | 2; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciout: 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 297