0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/fs.h>
0011 #include <linux/time.h>
0012 #include <linux/mm.h>
0013 #include <linux/highmem.h>
0014 #include <linux/kernel.h>
0015 #include <linux/pagemap.h>
0016
0017 #include "vxfs.h"
0018 #include "vxfs_dir.h"
0019 #include "vxfs_inode.h"
0020 #include "vxfs_extern.h"
0021
0022
0023
0024
0025 #define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_SIZE / (sbp)->s_blocksize))
0026
0027
0028 static struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int);
0029 static int vxfs_readdir(struct file *, struct dir_context *);
0030
0031 const struct inode_operations vxfs_dir_inode_ops = {
0032 .lookup = vxfs_lookup,
0033 };
0034
0035 const struct file_operations vxfs_dir_operations = {
0036 .llseek = generic_file_llseek,
0037 .read = generic_read_dir,
0038 .iterate_shared = vxfs_readdir,
0039 };
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 static struct vxfs_direct *
0057 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
0058 {
0059 u_long bsize = ip->i_sb->s_blocksize;
0060 const char *name = dp->d_name.name;
0061 int namelen = dp->d_name.len;
0062 loff_t limit = VXFS_DIRROUND(ip->i_size);
0063 struct vxfs_direct *de_exit = NULL;
0064 loff_t pos = 0;
0065 struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
0066
0067 while (pos < limit) {
0068 struct page *pp;
0069 char *kaddr;
0070 int pg_ofs = pos & ~PAGE_MASK;
0071
0072 pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
0073 if (IS_ERR(pp))
0074 return NULL;
0075 kaddr = (char *)page_address(pp);
0076
0077 while (pg_ofs < PAGE_SIZE && pos < limit) {
0078 struct vxfs_direct *de;
0079
0080 if ((pos & (bsize - 1)) < 4) {
0081 struct vxfs_dirblk *dbp =
0082 (struct vxfs_dirblk *)
0083 (kaddr + (pos & ~PAGE_MASK));
0084 int overhead = VXFS_DIRBLKOV(sbi, dbp);
0085
0086 pos += overhead;
0087 pg_ofs += overhead;
0088 }
0089 de = (struct vxfs_direct *)(kaddr + pg_ofs);
0090
0091 if (!de->d_reclen) {
0092 pos += bsize - 1;
0093 pos &= ~(bsize - 1);
0094 break;
0095 }
0096
0097 pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
0098 pos += fs16_to_cpu(sbi, de->d_reclen);
0099 if (!de->d_ino)
0100 continue;
0101
0102 if (namelen != fs16_to_cpu(sbi, de->d_namelen))
0103 continue;
0104 if (!memcmp(name, de->d_name, namelen)) {
0105 *ppp = pp;
0106 de_exit = de;
0107 break;
0108 }
0109 }
0110 if (!de_exit)
0111 vxfs_put_page(pp);
0112 else
0113 break;
0114 }
0115
0116 return de_exit;
0117 }
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 static ino_t
0132 vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
0133 {
0134 struct vxfs_direct *de;
0135 struct page *pp;
0136 ino_t ino = 0;
0137
0138 de = vxfs_find_entry(dip, dp, &pp);
0139 if (de) {
0140 ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
0141 kunmap(pp);
0142 put_page(pp);
0143 }
0144
0145 return (ino);
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 static struct dentry *
0163 vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
0164 {
0165 struct inode *ip = NULL;
0166 ino_t ino;
0167
0168 if (dp->d_name.len > VXFS_NAMELEN)
0169 return ERR_PTR(-ENAMETOOLONG);
0170
0171 ino = vxfs_inode_by_name(dip, dp);
0172 if (ino)
0173 ip = vxfs_iget(dip->i_sb, ino);
0174 return d_splice_alias(ip, dp);
0175 }
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190 static int
0191 vxfs_readdir(struct file *fp, struct dir_context *ctx)
0192 {
0193 struct inode *ip = file_inode(fp);
0194 struct super_block *sbp = ip->i_sb;
0195 u_long bsize = sbp->s_blocksize;
0196 loff_t pos, limit;
0197 struct vxfs_sb_info *sbi = VXFS_SBI(sbp);
0198
0199 if (ctx->pos == 0) {
0200 if (!dir_emit_dot(fp, ctx))
0201 goto out;
0202 ctx->pos++;
0203 }
0204 if (ctx->pos == 1) {
0205 if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
0206 goto out;
0207 ctx->pos++;
0208 }
0209
0210 limit = VXFS_DIRROUND(ip->i_size);
0211 if (ctx->pos > limit)
0212 goto out;
0213
0214 pos = ctx->pos & ~3L;
0215
0216 while (pos < limit) {
0217 struct page *pp;
0218 char *kaddr;
0219 int pg_ofs = pos & ~PAGE_MASK;
0220 int rc = 0;
0221
0222 pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
0223 if (IS_ERR(pp))
0224 return -ENOMEM;
0225
0226 kaddr = (char *)page_address(pp);
0227
0228 while (pg_ofs < PAGE_SIZE && pos < limit) {
0229 struct vxfs_direct *de;
0230
0231 if ((pos & (bsize - 1)) < 4) {
0232 struct vxfs_dirblk *dbp =
0233 (struct vxfs_dirblk *)
0234 (kaddr + (pos & ~PAGE_MASK));
0235 int overhead = VXFS_DIRBLKOV(sbi, dbp);
0236
0237 pos += overhead;
0238 pg_ofs += overhead;
0239 }
0240 de = (struct vxfs_direct *)(kaddr + pg_ofs);
0241
0242 if (!de->d_reclen) {
0243 pos += bsize - 1;
0244 pos &= ~(bsize - 1);
0245 break;
0246 }
0247
0248 pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
0249 pos += fs16_to_cpu(sbi, de->d_reclen);
0250 if (!de->d_ino)
0251 continue;
0252
0253 rc = dir_emit(ctx, de->d_name,
0254 fs16_to_cpu(sbi, de->d_namelen),
0255 fs32_to_cpu(sbi, de->d_ino),
0256 DT_UNKNOWN);
0257 if (!rc) {
0258
0259 pos -= fs16_to_cpu(sbi, de->d_reclen);
0260 break;
0261 }
0262 }
0263 vxfs_put_page(pp);
0264 if (!rc)
0265 break;
0266 }
0267
0268 ctx->pos = pos | 2;
0269
0270 out:
0271 return 0;
0272 }