vxfs_lookup.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  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. #ident "$Id: vxfs_lookup.c,v 1.21 2002/01/02 22:00:13 hch Exp hch $"
  30. /*
  31.  * Veritas filesystem driver - lookup and other directory related code.
  32.  */
  33. #include <linux/fs.h>
  34. #include <linux/sched.h>
  35. #include <linux/mm.h>
  36. #include <linux/highmem.h>
  37. #include <linux/kernel.h>
  38. #include <linux/pagemap.h>
  39. #include "vxfs.h"
  40. #include "vxfs_dir.h"
  41. #include "vxfs_inode.h"
  42. #include "vxfs_extern.h"
  43. /*
  44.  * Number of VxFS blocks per page.
  45.  */
  46. #define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
  47. static struct dentry * vxfs_lookup(struct inode *, struct dentry *);
  48. static int vxfs_readdir(struct file *, void *, filldir_t);
  49. struct inode_operations vxfs_dir_inode_ops = {
  50. .lookup = vxfs_lookup,
  51. };
  52. struct file_operations vxfs_dir_operations = {
  53. .readdir = vxfs_readdir,
  54. };
  55.  
  56. static __inline__ u_long
  57. dir_pages(struct inode *inode)
  58. {
  59. return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  60. }
  61.  
  62. static __inline__ u_long
  63. dir_blocks(struct inode *ip)
  64. {
  65. u_long bsize = ip->i_sb->s_blocksize;
  66. return (ip->i_size + bsize - 1) & ~(bsize - 1);
  67. }
  68. /*
  69.  * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
  70.  *
  71.  * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
  72.  */
  73. static __inline__ int
  74. vxfs_match(int len, const char * const name, struct vxfs_direct *de)
  75. {
  76. if (len != de->d_namelen)
  77. return 0;
  78. if (!de->d_ino)
  79. return 0;
  80. return !memcmp(name, de->d_name, len);
  81. }
  82. static __inline__ struct vxfs_direct *
  83. vxfs_next_entry(struct vxfs_direct *de)
  84. {
  85. return ((struct vxfs_direct *)((char*)de + de->d_reclen));
  86. }
  87. /**
  88.  * vxfs_find_entry - find a mathing directory entry for a dentry
  89.  * @ip: directory inode
  90.  * @dp: dentry for which we want to find a direct
  91.  * @ppp: gets filled with the page the return value sits in
  92.  *
  93.  * Description:
  94.  *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
  95.  *   cache entry @dp.  @ppp will be filled with the page the return
  96.  *   value resides in.
  97.  *
  98.  * Returns:
  99.  *   The wanted direct on success, else a NULL pointer.
  100.  */
  101. static struct vxfs_direct *
  102. vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
  103. {
  104. u_long npages, page, nblocks, pblocks, block;
  105. u_long bsize = ip->i_sb->s_blocksize;
  106. const char *name = dp->d_name.name;
  107. int namelen = dp->d_name.len;
  108. npages = dir_pages(ip);
  109. nblocks = dir_blocks(ip);
  110. pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
  111. for (page = 0; page < npages; page++) {
  112. caddr_t kaddr;
  113. struct page *pp;
  114. pp = vxfs_get_page(ip->i_mapping, page);
  115. if (IS_ERR(pp))
  116. continue;
  117. kaddr = (caddr_t)page_address(pp);
  118. for (block = 0; block <= nblocks && block <= pblocks; block++) {
  119. caddr_t baddr, limit;
  120. struct vxfs_dirblk *dbp;
  121. struct vxfs_direct *de;
  122. baddr = kaddr + (block * bsize);
  123. limit = baddr + bsize - VXFS_DIRLEN(1);
  124. dbp = (struct vxfs_dirblk *)baddr;
  125. de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
  126. for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
  127. if (!de->d_reclen)
  128. break;
  129. if (!de->d_ino)
  130. continue;
  131. if (vxfs_match(namelen, name, de)) {
  132. *ppp = pp;
  133. return (de);
  134. }
  135. }
  136. }
  137. vxfs_put_page(pp);
  138. }
  139. return NULL;
  140. }
  141. /**
  142.  * vxfs_inode_by_name - find inode number for dentry
  143.  * @dip: directory to search in
  144.  * @dp: dentry we seach for
  145.  *
  146.  * Description:
  147.  *   vxfs_inode_by_name finds out the inode number of
  148.  *   the path component described by @dp in @dip.
  149.  *
  150.  * Returns:
  151.  *   The wanted inode number on success, else Zero.
  152.  */
  153. static ino_t
  154. vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
  155. {
  156. struct vxfs_direct *de;
  157. struct page *pp;
  158. ino_t ino = 0;
  159. de = vxfs_find_entry(dip, dp, &pp);
  160. if (de) {
  161. ino = de->d_ino;
  162. kunmap(pp);
  163. page_cache_release(pp);
  164. }
  165. return (ino);
  166. }
  167. /**
  168.  * vxfs_lookup - lookup pathname component
  169.  * @dip: dir in which we lookup
  170.  * @dp: dentry we lookup
  171.  *
  172.  * Description:
  173.  *   vxfs_lookup tries to lookup the pathname component described
  174.  *   by @dp in @dip.
  175.  *
  176.  * Returns:
  177.  *   A NULL-pointer on success, else an negative error code encoded
  178.  *   in the return pointer.
  179.  */
  180. static struct dentry *
  181. vxfs_lookup(struct inode *dip, struct dentry *dp)
  182. {
  183. struct inode *ip = NULL;
  184. ino_t ino;
  185.  
  186. if (dp->d_name.len > VXFS_NAMELEN)
  187. return ERR_PTR(-ENAMETOOLONG);
  188.  
  189. ino = vxfs_inode_by_name(dip, dp);
  190. if (ino == 0)
  191. return NULL;
  192. ip = iget(dip->i_sb, ino);
  193. if (!ip)
  194. return ERR_PTR(-EACCES);
  195. d_add(dp, ip);
  196. return NULL;
  197. }
  198. /**
  199.  * vxfs_readdir - read a directory
  200.  * @fp: the directory to read
  201.  * @retp: return buffer
  202.  * @filler: filldir callback
  203.  *
  204.  * Description:
  205.  *   vxfs_readdir fills @retp with directory entries from @fp
  206.  *   using the VFS supplied callback @filler.
  207.  *
  208.  * Returns:
  209.  *   Zero.
  210.  */
  211. static int
  212. vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
  213. {
  214. struct inode *ip = fp->f_dentry->d_inode;
  215. struct super_block *sbp = ip->i_sb;
  216. u_long bsize = sbp->s_blocksize;
  217. u_long page, npages, block, pblocks, nblocks, offset;
  218. loff_t pos;
  219. switch ((long)fp->f_pos) {
  220. case 0:
  221. if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
  222. goto out;
  223. fp->f_pos++;
  224. /* fallthrough */
  225. case 1:
  226. if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0)
  227. goto out;
  228. fp->f_pos++;
  229. /* fallthrough */
  230. }
  231. pos = fp->f_pos - 2;
  232. if (pos > VXFS_DIRROUND(ip->i_size))
  233. return 0;
  234. npages = dir_pages(ip);
  235. nblocks = dir_blocks(ip);
  236. pblocks = VXFS_BLOCK_PER_PAGE(sbp);
  237. page = pos >> PAGE_CACHE_SHIFT;
  238. offset = pos & ~PAGE_CACHE_MASK;
  239. block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
  240. for (; page < npages; page++, block = 0) {
  241. caddr_t kaddr;
  242. struct page *pp;
  243. pp = vxfs_get_page(ip->i_mapping, page);
  244. if (IS_ERR(pp))
  245. continue;
  246. kaddr = (caddr_t)page_address(pp);
  247. for (; block <= nblocks && block <= pblocks; block++) {
  248. caddr_t baddr, limit;
  249. struct vxfs_dirblk *dbp;
  250. struct vxfs_direct *de;
  251. baddr = kaddr + (block * bsize);
  252. limit = baddr + bsize - VXFS_DIRLEN(1);
  253. dbp = (struct vxfs_dirblk *)baddr;
  254. de = (struct vxfs_direct *)
  255. (offset ?
  256.  (kaddr + offset) :
  257.  (baddr + VXFS_DIRBLKOV(dbp)));
  258. for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
  259. int over;
  260. if (!de->d_reclen)
  261. break;
  262. if (!de->d_ino)
  263. continue;
  264. offset = (caddr_t)de - kaddr;
  265. over = filler(retp, de->d_name, de->d_namelen,
  266. ((page << PAGE_CACHE_SHIFT) | offset) + 2,
  267. de->d_ino, DT_UNKNOWN);
  268. if (over) {
  269. vxfs_put_page(pp);
  270. goto done;
  271. }
  272. }
  273. offset = 0;
  274. }
  275. vxfs_put_page(pp);
  276. offset = 0;
  277. }
  278. done:
  279. fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
  280. out:
  281. return 0;
  282. }