1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/affs/dir.c 4 * 5 * (c) 1996 Hans-Joachim Widmaier - Rewritten 6 * 7 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. 8 * 9 * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem. 10 * 11 * (C) 1991 Linus Torvalds - minix filesystem 12 * 13 * affs directory handling functions 14 * 15 */ 16 17 #include <linux/iversion.h> 18 #include "affs.h" 19 20 struct affs_dir_data { 21 unsigned long ino; 22 u64 cookie; 23 }; 24 25 static int affs_readdir(struct file *, struct dir_context *); 26 27 static loff_t affs_dir_llseek(struct file *file, loff_t offset, int whence) 28 { 29 struct affs_dir_data *data = file->private_data; 30 31 return generic_llseek_cookie(file, offset, whence, &data->cookie); 32 } 33 34 static int affs_dir_open(struct inode *inode, struct file *file) 35 { 36 struct affs_dir_data *data; 37 38 data = kzalloc(sizeof(struct affs_dir_data), GFP_KERNEL); 39 if (!data) 40 return -ENOMEM; 41 file->private_data = data; 42 return 0; 43 } 44 45 static int affs_dir_release(struct inode *inode, struct file *file) 46 { 47 kfree(file->private_data); 48 return 0; 49 } 50 51 const struct file_operations affs_dir_operations = { 52 .open = affs_dir_open, 53 .read = generic_read_dir, 54 .llseek = affs_dir_llseek, 55 .iterate_shared = affs_readdir, 56 .fsync = affs_file_fsync, 57 .release = affs_dir_release, 58 }; 59 60 /* 61 * directories can handle most operations... 62 */ 63 const struct inode_operations affs_dir_inode_operations = { 64 .create = affs_create, 65 .lookup = affs_lookup, 66 .link = affs_link, 67 .unlink = affs_unlink, 68 .symlink = affs_symlink, 69 .mkdir = affs_mkdir, 70 .rmdir = affs_rmdir, 71 .rename = affs_rename2, 72 .setattr = affs_notify_change, 73 }; 74 75 static int 76 affs_readdir(struct file *file, struct dir_context *ctx) 77 { 78 struct inode *inode = file_inode(file); 79 struct affs_dir_data *data = file->private_data; 80 struct super_block *sb = inode->i_sb; 81 struct buffer_head *dir_bh = NULL; 82 struct buffer_head *fh_bh = NULL; 83 unsigned char *name; 84 int namelen; 85 u32 i; 86 int hash_pos; 87 int chain_pos; 88 u32 ino; 89 int error = 0; 90 91 pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos); 92 93 if (ctx->pos < 2) { 94 data->ino = 0; 95 if (!dir_emit_dots(file, ctx)) 96 return 0; 97 } 98 99 affs_lock_dir(inode); 100 chain_pos = (ctx->pos - 2) & 0xffff; 101 hash_pos = (ctx->pos - 2) >> 16; 102 if (chain_pos == 0xffff) { 103 affs_warning(sb, "readdir", "More than 65535 entries in chain"); 104 chain_pos = 0; 105 hash_pos++; 106 ctx->pos = ((hash_pos << 16) | chain_pos) + 2; 107 } 108 dir_bh = affs_bread(sb, inode->i_ino); 109 if (!dir_bh) 110 goto out_unlock_dir; 111 112 /* If the directory hasn't changed since the last call to readdir(), 113 * we can jump directly to where we left off. 114 */ 115 ino = data->ino; 116 if (ino && inode_eq_iversion(inode, data->cookie)) { 117 pr_debug("readdir() left off=%d\n", ino); 118 goto inside; 119 } 120 121 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); 122 for (i = 0; ino && i < chain_pos; i++) { 123 fh_bh = affs_bread(sb, ino); 124 if (!fh_bh) { 125 affs_error(sb, "readdir","Cannot read block %d", i); 126 error = -EIO; 127 goto out_brelse_dir; 128 } 129 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain); 130 affs_brelse(fh_bh); 131 fh_bh = NULL; 132 } 133 if (ino) 134 goto inside; 135 hash_pos++; 136 137 for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) { 138 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); 139 if (!ino) 140 continue; 141 ctx->pos = (hash_pos << 16) + 2; 142 inside: 143 do { 144 fh_bh = affs_bread(sb, ino); 145 if (!fh_bh) { 146 affs_error(sb, "readdir", 147 "Cannot read block %d", ino); 148 break; 149 } 150 151 namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], 152 (u8)AFFSNAMEMAX); 153 name = AFFS_TAIL(sb, fh_bh)->name + 1; 154 pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n", 155 namelen, name, ino, hash_pos, ctx->pos); 156 157 if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN)) 158 goto done; 159 ctx->pos++; 160 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain); 161 affs_brelse(fh_bh); 162 fh_bh = NULL; 163 } while (ino); 164 } 165 done: 166 data->cookie = inode_query_iversion(inode); 167 data->ino = ino; 168 affs_brelse(fh_bh); 169 170 out_brelse_dir: 171 affs_brelse(dir_bh); 172 173 out_unlock_dir: 174 affs_unlock_dir(inode); 175 return error; 176 } 177