0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/iversion.h>
0018 #include "affs.h"
0019
0020 static int affs_readdir(struct file *, struct dir_context *);
0021
0022 const struct file_operations affs_dir_operations = {
0023 .read = generic_read_dir,
0024 .llseek = generic_file_llseek,
0025 .iterate_shared = affs_readdir,
0026 .fsync = affs_file_fsync,
0027 };
0028
0029
0030
0031
0032 const struct inode_operations affs_dir_inode_operations = {
0033 .create = affs_create,
0034 .lookup = affs_lookup,
0035 .link = affs_link,
0036 .unlink = affs_unlink,
0037 .symlink = affs_symlink,
0038 .mkdir = affs_mkdir,
0039 .rmdir = affs_rmdir,
0040 .rename = affs_rename2,
0041 .setattr = affs_notify_change,
0042 };
0043
0044 static int
0045 affs_readdir(struct file *file, struct dir_context *ctx)
0046 {
0047 struct inode *inode = file_inode(file);
0048 struct super_block *sb = inode->i_sb;
0049 struct buffer_head *dir_bh = NULL;
0050 struct buffer_head *fh_bh = NULL;
0051 unsigned char *name;
0052 int namelen;
0053 u32 i;
0054 int hash_pos;
0055 int chain_pos;
0056 u32 ino;
0057 int error = 0;
0058
0059 pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos);
0060
0061 if (ctx->pos < 2) {
0062 file->private_data = (void *)0;
0063 if (!dir_emit_dots(file, ctx))
0064 return 0;
0065 }
0066
0067 affs_lock_dir(inode);
0068 chain_pos = (ctx->pos - 2) & 0xffff;
0069 hash_pos = (ctx->pos - 2) >> 16;
0070 if (chain_pos == 0xffff) {
0071 affs_warning(sb, "readdir", "More than 65535 entries in chain");
0072 chain_pos = 0;
0073 hash_pos++;
0074 ctx->pos = ((hash_pos << 16) | chain_pos) + 2;
0075 }
0076 dir_bh = affs_bread(sb, inode->i_ino);
0077 if (!dir_bh)
0078 goto out_unlock_dir;
0079
0080
0081
0082
0083 ino = (u32)(long)file->private_data;
0084 if (ino && inode_eq_iversion(inode, file->f_version)) {
0085 pr_debug("readdir() left off=%d\n", ino);
0086 goto inside;
0087 }
0088
0089 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
0090 for (i = 0; ino && i < chain_pos; i++) {
0091 fh_bh = affs_bread(sb, ino);
0092 if (!fh_bh) {
0093 affs_error(sb, "readdir","Cannot read block %d", i);
0094 error = -EIO;
0095 goto out_brelse_dir;
0096 }
0097 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
0098 affs_brelse(fh_bh);
0099 fh_bh = NULL;
0100 }
0101 if (ino)
0102 goto inside;
0103 hash_pos++;
0104
0105 for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) {
0106 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
0107 if (!ino)
0108 continue;
0109 ctx->pos = (hash_pos << 16) + 2;
0110 inside:
0111 do {
0112 fh_bh = affs_bread(sb, ino);
0113 if (!fh_bh) {
0114 affs_error(sb, "readdir",
0115 "Cannot read block %d", ino);
0116 break;
0117 }
0118
0119 namelen = min(AFFS_TAIL(sb, fh_bh)->name[0],
0120 (u8)AFFSNAMEMAX);
0121 name = AFFS_TAIL(sb, fh_bh)->name + 1;
0122 pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n",
0123 namelen, name, ino, hash_pos, ctx->pos);
0124
0125 if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
0126 goto done;
0127 ctx->pos++;
0128 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
0129 affs_brelse(fh_bh);
0130 fh_bh = NULL;
0131 } while (ino);
0132 }
0133 done:
0134 file->f_version = inode_query_iversion(inode);
0135 file->private_data = (void *)(long)ino;
0136 affs_brelse(fh_bh);
0137
0138 out_brelse_dir:
0139 affs_brelse(dir_bh);
0140
0141 out_unlock_dir:
0142 affs_unlock_dir(inode);
0143 return error;
0144 }