1 /* 2 * linux/fs/affs/dir.c 3 * 4 * (c) 1996 Hans-Joachim Widmaier - Rewritten 5 * 6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. 7 * 8 * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem. 9 * 10 * (C) 1991 Linus Torvalds - minix filesystem 11 * 12 * affs directory handling functions 13 * 14 */ 15 16 #include "affs.h" 17 18 static int affs_readdir(struct file *, void *, filldir_t); 19 20 const struct file_operations affs_dir_operations = { 21 .read = generic_read_dir, 22 .llseek = generic_file_llseek, 23 .readdir = affs_readdir, 24 .fsync = file_fsync, 25 }; 26 27 /* 28 * directories can handle most operations... 29 */ 30 const struct inode_operations affs_dir_inode_operations = { 31 .create = affs_create, 32 .lookup = affs_lookup, 33 .link = affs_link, 34 .unlink = affs_unlink, 35 .symlink = affs_symlink, 36 .mkdir = affs_mkdir, 37 .rmdir = affs_rmdir, 38 .rename = affs_rename, 39 .setattr = affs_notify_change, 40 }; 41 42 static int 43 affs_readdir(struct file *filp, void *dirent, filldir_t filldir) 44 { 45 struct inode *inode = filp->f_path.dentry->d_inode; 46 struct super_block *sb = inode->i_sb; 47 struct buffer_head *dir_bh; 48 struct buffer_head *fh_bh; 49 unsigned char *name; 50 int namelen; 51 u32 i; 52 int hash_pos; 53 int chain_pos; 54 u32 f_pos; 55 u32 ino; 56 int stored; 57 int res; 58 59 pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos); 60 61 stored = 0; 62 res = -EIO; 63 dir_bh = NULL; 64 fh_bh = NULL; 65 f_pos = filp->f_pos; 66 67 if (f_pos == 0) { 68 filp->private_data = (void *)0; 69 if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0) 70 return 0; 71 filp->f_pos = f_pos = 1; 72 stored++; 73 } 74 if (f_pos == 1) { 75 if (filldir(dirent, "..", 2, f_pos, parent_ino(filp->f_path.dentry), DT_DIR) < 0) 76 return stored; 77 filp->f_pos = f_pos = 2; 78 stored++; 79 } 80 81 affs_lock_dir(inode); 82 chain_pos = (f_pos - 2) & 0xffff; 83 hash_pos = (f_pos - 2) >> 16; 84 if (chain_pos == 0xffff) { 85 affs_warning(sb, "readdir", "More than 65535 entries in chain"); 86 chain_pos = 0; 87 hash_pos++; 88 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; 89 } 90 dir_bh = affs_bread(sb, inode->i_ino); 91 if (!dir_bh) 92 goto readdir_out; 93 94 /* If the directory hasn't changed since the last call to readdir(), 95 * we can jump directly to where we left off. 96 */ 97 ino = (u32)(long)filp->private_data; 98 if (ino && filp->f_version == inode->i_version) { 99 pr_debug("AFFS: readdir() left off=%d\n", ino); 100 goto inside; 101 } 102 103 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); 104 for (i = 0; ino && i < chain_pos; i++) { 105 fh_bh = affs_bread(sb, ino); 106 if (!fh_bh) { 107 affs_error(sb, "readdir","Cannot read block %d", i); 108 goto readdir_out; 109 } 110 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain); 111 affs_brelse(fh_bh); 112 fh_bh = NULL; 113 } 114 if (ino) 115 goto inside; 116 hash_pos++; 117 118 for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) { 119 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]); 120 if (!ino) 121 continue; 122 f_pos = (hash_pos << 16) + 2; 123 inside: 124 do { 125 fh_bh = affs_bread(sb, ino); 126 if (!fh_bh) { 127 affs_error(sb, "readdir","Cannot read block %d", ino); 128 goto readdir_done; 129 } 130 131 namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30); 132 name = AFFS_TAIL(sb, fh_bh)->name + 1; 133 pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n", 134 namelen, name, ino, hash_pos, f_pos); 135 if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0) 136 goto readdir_done; 137 stored++; 138 f_pos++; 139 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain); 140 affs_brelse(fh_bh); 141 fh_bh = NULL; 142 } while (ino); 143 } 144 readdir_done: 145 filp->f_pos = f_pos; 146 filp->f_version = inode->i_version; 147 filp->private_data = (void *)(long)ino; 148 res = stored; 149 150 readdir_out: 151 affs_brelse(dir_bh); 152 affs_brelse(fh_bh); 153 affs_unlock_dir(inode); 154 pr_debug("AFFS: readdir()=%d\n", stored); 155 return res; 156 } 157