]> asedeno.scripts.mit.edu Git - linux.git/blob - fs/freevxfs/vxfs_lookup.c
freevxfs: handle big endian HP-UX file systems
[linux.git] / fs / freevxfs / vxfs_lookup.c
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_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_shared =       vxfs_readdir,
62 };
63
64 static inline u_long
65 dir_blocks(struct inode *ip)
66 {
67         u_long                  bsize = ip->i_sb->s_blocksize;
68         return (ip->i_size + bsize - 1) & ~(bsize - 1);
69 }
70
71 /*
72  * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
73  *
74  * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
75  */
76 static inline int
77 vxfs_match(struct vxfs_sb_info *sbi, int len, const char *const name,
78                 struct vxfs_direct *de)
79 {
80         if (len != fs16_to_cpu(sbi, de->d_namelen))
81                 return 0;
82         if (!de->d_ino)
83                 return 0;
84         return !memcmp(name, de->d_name, len);
85 }
86
87 static inline struct vxfs_direct *
88 vxfs_next_entry(struct vxfs_sb_info *sbi, struct vxfs_direct *de)
89 {
90         return ((struct vxfs_direct *)
91                 ((char *)de + fs16_to_cpu(sbi, de->d_reclen)));
92 }
93
94 /**
95  * vxfs_find_entry - find a mathing directory entry for a dentry
96  * @ip:         directory inode
97  * @dp:         dentry for which we want to find a direct
98  * @ppp:        gets filled with the page the return value sits in
99  *
100  * Description:
101  *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
102  *   cache entry @dp.  @ppp will be filled with the page the return
103  *   value resides in.
104  *
105  * Returns:
106  *   The wanted direct on success, else a NULL pointer.
107  */
108 static struct vxfs_direct *
109 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
110 {
111         struct vxfs_sb_info             *sbi = VXFS_SBI(ip->i_sb);
112         u_long                          npages, page, nblocks, pblocks, block;
113         u_long                          bsize = ip->i_sb->s_blocksize;
114         const char                      *name = dp->d_name.name;
115         int                             namelen = dp->d_name.len;
116
117         npages = dir_pages(ip);
118         nblocks = dir_blocks(ip);
119         pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
120         
121         for (page = 0; page < npages; page++) {
122                 caddr_t                 kaddr;
123                 struct page             *pp;
124
125                 pp = vxfs_get_page(ip->i_mapping, page);
126                 if (IS_ERR(pp))
127                         continue;
128                 kaddr = (caddr_t)page_address(pp);
129
130                 for (block = 0; block <= nblocks && block <= pblocks; block++) {
131                         caddr_t                 baddr, limit;
132                         struct vxfs_dirblk      *dbp;
133                         struct vxfs_direct      *de;
134
135                         baddr = kaddr + (block * bsize);
136                         limit = baddr + bsize - VXFS_DIRLEN(1);
137                         
138                         dbp = (struct vxfs_dirblk *)baddr;
139                         de = (struct vxfs_direct *)
140                                 (baddr + VXFS_DIRBLKOV(sbi, dbp));
141
142                         for (; (caddr_t)de <= limit;
143                                         de = vxfs_next_entry(sbi, de)) {
144                                 if (!de->d_reclen)
145                                         break;
146                                 if (!de->d_ino)
147                                         continue;
148                                 if (vxfs_match(sbi, namelen, name, de)) {
149                                         *ppp = pp;
150                                         return (de);
151                                 }
152                         }
153                 }
154                 vxfs_put_page(pp);
155         }
156
157         return NULL;
158 }
159
160 /**
161  * vxfs_inode_by_name - find inode number for dentry
162  * @dip:        directory to search in
163  * @dp:         dentry we search for
164  *
165  * Description:
166  *   vxfs_inode_by_name finds out the inode number of
167  *   the path component described by @dp in @dip.
168  *
169  * Returns:
170  *   The wanted inode number on success, else Zero.
171  */
172 static ino_t
173 vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
174 {
175         struct vxfs_direct              *de;
176         struct page                     *pp;
177         ino_t                           ino = 0;
178
179         de = vxfs_find_entry(dip, dp, &pp);
180         if (de) {
181                 ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
182                 kunmap(pp);
183                 put_page(pp);
184         }
185         
186         return (ino);
187 }
188
189 /**
190  * vxfs_lookup - lookup pathname component
191  * @dip:        dir in which we lookup
192  * @dp:         dentry we lookup
193  * @flags:      lookup flags
194  *
195  * Description:
196  *   vxfs_lookup tries to lookup the pathname component described
197  *   by @dp in @dip.
198  *
199  * Returns:
200  *   A NULL-pointer on success, else a negative error code encoded
201  *   in the return pointer.
202  */
203 static struct dentry *
204 vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
205 {
206         struct inode            *ip = NULL;
207         ino_t                   ino;
208                          
209         if (dp->d_name.len > VXFS_NAMELEN)
210                 return ERR_PTR(-ENAMETOOLONG);
211                                  
212         ino = vxfs_inode_by_name(dip, dp);
213         if (ino) {
214                 ip = vxfs_iget(dip->i_sb, ino);
215                 if (IS_ERR(ip))
216                         return ERR_CAST(ip);
217         }
218         d_add(dp, ip);
219         return NULL;
220 }
221
222 /**
223  * vxfs_readdir - read a directory
224  * @fp:         the directory to read
225  * @retp:       return buffer
226  * @filler:     filldir callback
227  *
228  * Description:
229  *   vxfs_readdir fills @retp with directory entries from @fp
230  *   using the VFS supplied callback @filler.
231  *
232  * Returns:
233  *   Zero.
234  */
235 static int
236 vxfs_readdir(struct file *fp, struct dir_context *ctx)
237 {
238         struct inode            *ip = file_inode(fp);
239         struct super_block      *sbp = ip->i_sb;
240         struct vxfs_sb_info     *sbi = VXFS_SBI(sbp);
241         u_long                  bsize = sbp->s_blocksize;
242         u_long                  page, npages, block, pblocks, nblocks, offset;
243         loff_t                  pos;
244
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_SHIFT;
266         offset = pos & ~PAGE_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(sbi, dbp)));
291
292                         for (; (char *)de <= limit;
293                                         de = vxfs_next_entry(sbi, de)) {
294                                 if (!de->d_reclen)
295                                         break;
296                                 if (!de->d_ino)
297                                         continue;
298
299                                 offset = (char *)de - kaddr;
300                                 ctx->pos = ((page << PAGE_SHIFT) | offset) + 2;
301                                 if (!dir_emit(ctx, de->d_name,
302                                                 fs16_to_cpu(sbi, de->d_namelen),
303                                                 fs32_to_cpu(sbi, de->d_ino),
304                                                 DT_UNKNOWN)) {
305                                         vxfs_put_page(pp);
306                                         return 0;
307                                 }
308                         }
309                         offset = 0;
310                 }
311                 vxfs_put_page(pp);
312                 offset = 0;
313         }
314         ctx->pos = ((page << PAGE_SHIFT) | offset) + 2;
315         return 0;
316 }