xref: /linux/fs/freevxfs/vxfs_lookup.c (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2000-2001 Christoph Hellwig.
4  * Copyright (c) 2016 Krzysztof Blaszkowski
5  */
6 
7 /*
8  * Veritas filesystem driver - lookup and other directory related code.
9  */
10 #include <linux/fs.h>
11 #include <linux/filelock.h>
12 #include <linux/time.h>
13 #include <linux/mm.h>
14 #include <linux/highmem.h>
15 #include <linux/kernel.h>
16 #include <linux/pagemap.h>
17 
18 #include "vxfs.h"
19 #include "vxfs_dir.h"
20 #include "vxfs_inode.h"
21 #include "vxfs_extern.h"
22 
23 /*
24  * Number of VxFS blocks per page.
25  */
26 #define VXFS_BLOCK_PER_PAGE(sbp)  ((PAGE_SIZE / (sbp)->s_blocksize))
27 
28 
29 static struct dentry *	vxfs_lookup(struct inode *, struct dentry *, unsigned int);
30 static int		vxfs_readdir(struct file *, struct dir_context *);
31 
32 const struct inode_operations vxfs_dir_inode_ops = {
33 	.lookup =		vxfs_lookup,
34 };
35 
36 const struct file_operations vxfs_dir_operations = {
37 	.llseek =		generic_file_llseek,
38 	.read =			generic_read_dir,
39 	.iterate_shared =	vxfs_readdir,
40 	.setlease =		generic_setlease,
41 };
42 
43 
44 /**
45  * vxfs_find_entry - find a mathing directory entry for a dentry
46  * @ip:		directory inode
47  * @dp:		dentry for which we want to find a direct
48  * @ppp:	gets filled with the page the return value sits in
49  *
50  * Description:
51  *   vxfs_find_entry finds a &struct vxfs_direct for the VFS directory
52  *   cache entry @dp.  @ppp will be filled with the page the return
53  *   value resides in.
54  *
55  * Returns:
56  *   The wanted direct on success, else a NULL pointer.
57  */
58 static struct vxfs_direct *
59 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
60 {
61 	u_long bsize = ip->i_sb->s_blocksize;
62 	const char *name = dp->d_name.name;
63 	int namelen = dp->d_name.len;
64 	loff_t limit = VXFS_DIRROUND(ip->i_size);
65 	struct vxfs_direct *de_exit = NULL;
66 	loff_t pos = 0;
67 	struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
68 
69 	while (pos < limit) {
70 		struct page *pp;
71 		char *kaddr;
72 		int pg_ofs = pos & ~PAGE_MASK;
73 
74 		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
75 		if (IS_ERR(pp))
76 			return NULL;
77 		kaddr = (char *)page_address(pp);
78 
79 		while (pg_ofs < PAGE_SIZE && pos < limit) {
80 			struct vxfs_direct *de;
81 
82 			if ((pos & (bsize - 1)) < 4) {
83 				struct vxfs_dirblk *dbp =
84 					(struct vxfs_dirblk *)
85 					 (kaddr + (pos & ~PAGE_MASK));
86 				int overhead = VXFS_DIRBLKOV(sbi, dbp);
87 
88 				pos += overhead;
89 				pg_ofs += overhead;
90 			}
91 			de = (struct vxfs_direct *)(kaddr + pg_ofs);
92 
93 			if (!de->d_reclen) {
94 				pos += bsize - 1;
95 				pos &= ~(bsize - 1);
96 				break;
97 			}
98 
99 			pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
100 			pos += fs16_to_cpu(sbi, de->d_reclen);
101 			if (!de->d_ino)
102 				continue;
103 
104 			if (namelen != fs16_to_cpu(sbi, de->d_namelen))
105 				continue;
106 			if (!memcmp(name, de->d_name, namelen)) {
107 				*ppp = pp;
108 				de_exit = de;
109 				break;
110 			}
111 		}
112 		if (!de_exit)
113 			vxfs_put_page(pp);
114 		else
115 			break;
116 	}
117 
118 	return de_exit;
119 }
120 
121 /**
122  * vxfs_inode_by_name - find inode number for dentry
123  * @dip:	directory to search in
124  * @dp:		dentry we search for
125  *
126  * Description:
127  *   vxfs_inode_by_name finds out the inode number of
128  *   the path component described by @dp in @dip.
129  *
130  * Returns:
131  *   The wanted inode number on success, else Zero.
132  */
133 static ino_t
134 vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
135 {
136 	struct vxfs_direct		*de;
137 	struct page			*pp;
138 	ino_t				ino = 0;
139 
140 	de = vxfs_find_entry(dip, dp, &pp);
141 	if (de) {
142 		ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
143 		kunmap(pp);
144 		put_page(pp);
145 	}
146 
147 	return (ino);
148 }
149 
150 /**
151  * vxfs_lookup - lookup pathname component
152  * @dip:	dir in which we lookup
153  * @dp:		dentry we lookup
154  * @flags:	lookup flags
155  *
156  * Description:
157  *   vxfs_lookup tries to lookup the pathname component described
158  *   by @dp in @dip.
159  *
160  * Returns:
161  *   A NULL-pointer on success, else a negative error code encoded
162  *   in the return pointer.
163  */
164 static struct dentry *
165 vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
166 {
167 	struct inode		*ip = NULL;
168 	ino_t			ino;
169 
170 	if (dp->d_name.len > VXFS_NAMELEN)
171 		return ERR_PTR(-ENAMETOOLONG);
172 
173 	ino = vxfs_inode_by_name(dip, dp);
174 	if (ino)
175 		ip = vxfs_iget(dip->i_sb, ino);
176 	return d_splice_alias(ip, dp);
177 }
178 
179 /**
180  * vxfs_readdir - read a directory
181  * @fp:		the directory to read
182  * @ctx:	dir_context for filldir/readdir
183  *
184  * Description:
185  *   vxfs_readdir fills @retp with directory entries from @fp
186  *   using the VFS supplied callback @filler.
187  *
188  * Returns:
189  *   Zero.
190  */
191 static int
192 vxfs_readdir(struct file *fp, struct dir_context *ctx)
193 {
194 	struct inode		*ip = file_inode(fp);
195 	struct super_block	*sbp = ip->i_sb;
196 	u_long			bsize = sbp->s_blocksize;
197 	loff_t			pos, limit;
198 	struct vxfs_sb_info	*sbi = VXFS_SBI(sbp);
199 
200 	if (ctx->pos == 0) {
201 		if (!dir_emit_dot(fp, ctx))
202 			goto out;
203 		ctx->pos++;
204 	}
205 	if (ctx->pos == 1) {
206 		if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
207 			goto out;
208 		ctx->pos++;
209 	}
210 
211 	limit = VXFS_DIRROUND(ip->i_size);
212 	if (ctx->pos > limit)
213 		goto out;
214 
215 	pos = ctx->pos & ~3L;
216 
217 	while (pos < limit) {
218 		struct page *pp;
219 		char *kaddr;
220 		int pg_ofs = pos & ~PAGE_MASK;
221 		int rc = 0;
222 
223 		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
224 		if (IS_ERR(pp))
225 			return -ENOMEM;
226 
227 		kaddr = (char *)page_address(pp);
228 
229 		while (pg_ofs < PAGE_SIZE && pos < limit) {
230 			struct vxfs_direct *de;
231 
232 			if ((pos & (bsize - 1)) < 4) {
233 				struct vxfs_dirblk *dbp =
234 					(struct vxfs_dirblk *)
235 					 (kaddr + (pos & ~PAGE_MASK));
236 				int overhead = VXFS_DIRBLKOV(sbi, dbp);
237 
238 				pos += overhead;
239 				pg_ofs += overhead;
240 			}
241 			de = (struct vxfs_direct *)(kaddr + pg_ofs);
242 
243 			if (!de->d_reclen) {
244 				pos += bsize - 1;
245 				pos &= ~(bsize - 1);
246 				break;
247 			}
248 
249 			pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
250 			pos += fs16_to_cpu(sbi, de->d_reclen);
251 			if (!de->d_ino)
252 				continue;
253 
254 			rc = dir_emit(ctx, de->d_name,
255 					fs16_to_cpu(sbi, de->d_namelen),
256 					fs32_to_cpu(sbi, de->d_ino),
257 					DT_UNKNOWN);
258 			if (!rc) {
259 				/* the dir entry was not read, fix pos. */
260 				pos -= fs16_to_cpu(sbi, de->d_reclen);
261 				break;
262 			}
263 		}
264 		vxfs_put_page(pp);
265 		if (!rc)
266 			break;
267 	}
268 
269 	ctx->pos = pos | 2;
270 
271 out:
272 	return 0;
273 }
274