b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * linux/fs/affs/dir.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * (c) 1996 Hans-Joachim Widmaier - Rewritten
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11) * (C) 1991 Linus Torvalds - minix filesystem
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) * affs directory handling functions
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16)
9dffe569d942a (Jeff Layton 2017-12-11 06:35:10 -0500 17) #include <linux/iversion.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) #include "affs.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19)
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 20) static int affs_readdir(struct file *, struct dir_context *);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21)
4b6f5d20b04dc (Arjan van de Ven 2006-03-28 01:56:42 -0800 22) const struct file_operations affs_dir_operations = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) .read = generic_read_dir,
59af1584bf338 (Al Viro 2008-08-24 07:24:41 -0400 24) .llseek = generic_file_llseek,
3b0a3c1ac1598 (Al Viro 2016-04-20 23:42:46 -0400 25) .iterate_shared = affs_readdir,
c475879556a86 (Al Viro 2009-06-08 01:22:00 -0400 26) .fsync = affs_file_fsync,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) * directories can handle most operations...
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) */
754661f143e70 (Arjan van de Ven 2007-02-12 00:55:38 -0800 32) const struct inode_operations affs_dir_inode_operations = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33) .create = affs_create,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34) .lookup = affs_lookup,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) .link = affs_link,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36) .unlink = affs_unlink,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 37) .symlink = affs_symlink,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 38) .mkdir = affs_mkdir,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39) .rmdir = affs_rmdir,
c6184028a75cf (Fabian Frederick 2017-05-05 20:51:42 +0200 40) .rename = affs_rename2,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41) .setattr = affs_notify_change,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 42) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 43)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) static int
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 45) affs_readdir(struct file *file, struct dir_context *ctx)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46) {
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 47) struct inode *inode = file_inode(file);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 48) struct super_block *sb = inode->i_sb;
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 49) struct buffer_head *dir_bh = NULL;
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 50) struct buffer_head *fh_bh = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 51) unsigned char *name;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 52) int namelen;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53) u32 i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 54) int hash_pos;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) int chain_pos;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 56) u32 ino;
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 57) int error = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 58)
08fe100d91bc0 (Geert Uytterhoeven 2015-02-17 13:46:10 -0800 59) pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__, inode->i_ino, ctx->pos);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60)
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 61) if (ctx->pos < 2) {
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 62) file->private_data = (void *)0;
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 63) if (!dir_emit_dots(file, ctx))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 67) affs_lock_dir(inode);
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 68) chain_pos = (ctx->pos - 2) & 0xffff;
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 69) hash_pos = (ctx->pos - 2) >> 16;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) if (chain_pos == 0xffff) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) affs_warning(sb, "readdir", "More than 65535 entries in chain");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) chain_pos = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) hash_pos++;
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 74) ctx->pos = ((hash_pos << 16) | chain_pos) + 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76) dir_bh = affs_bread(sb, inode->i_ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77) if (!dir_bh)
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 78) goto out_unlock_dir;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 79)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 80) /* If the directory hasn't changed since the last call to readdir(),
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 81) * we can jump directly to where we left off.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 82) */
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 83) ino = (u32)(long)file->private_data;
c472c07bfed9c (Goffredo Baroncelli 2018-02-01 08:15:25 -0500 84) if (ino && inode_eq_iversion(inode, file->f_version)) {
9606d9aa858ae (Fabian Frederick 2014-06-06 14:37:25 -0700 85) pr_debug("readdir() left off=%d\n", ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) goto inside;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 88)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 89) ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) for (i = 0; ino && i < chain_pos; i++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 91) fh_bh = affs_bread(sb, ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) if (!fh_bh) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) affs_error(sb, "readdir","Cannot read block %d", i);
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 94) error = -EIO;
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 95) goto out_brelse_dir;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97) ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) affs_brelse(fh_bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) fh_bh = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 100) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 101) if (ino)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 102) goto inside;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) hash_pos++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 104)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 105) for (; hash_pos < AFFS_SB(sb)->s_hashsize; hash_pos++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 107) if (!ino)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108) continue;
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 109) ctx->pos = (hash_pos << 16) + 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110) inside:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 111) do {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 112) fh_bh = affs_bread(sb, ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 113) if (!fh_bh) {
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 114) affs_error(sb, "readdir",
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 115) "Cannot read block %d", ino);
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 116) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 117) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 118)
f157853e407c0 (Fabian Frederick 2015-02-17 13:46:23 -0800 119) namelen = min(AFFS_TAIL(sb, fh_bh)->name[0],
f157853e407c0 (Fabian Frederick 2015-02-17 13:46:23 -0800 120) (u8)AFFSNAMEMAX);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 121) name = AFFS_TAIL(sb, fh_bh)->name + 1;
08fe100d91bc0 (Geert Uytterhoeven 2015-02-17 13:46:10 -0800 122) pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n",
08fe100d91bc0 (Geert Uytterhoeven 2015-02-17 13:46:10 -0800 123) namelen, name, ino, hash_pos, ctx->pos);
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 124)
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 125) if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 126) goto done;
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 127) ctx->pos++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 128) ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 129) affs_brelse(fh_bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130) fh_bh = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) } while (ino);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 132) }
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 133) done:
9dffe569d942a (Jeff Layton 2017-12-11 06:35:10 -0500 134) file->f_version = inode_query_iversion(inode);
0edf977d2ae32 (Al Viro 2013-05-17 17:44:42 -0400 135) file->private_data = (void *)(long)ino;
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 136) affs_brelse(fh_bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 137)
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 138) out_brelse_dir:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 139) affs_brelse(dir_bh);
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 140)
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 141) out_unlock_dir:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142) affs_unlock_dir(inode);
d40c4d46eaa22 (Fabian Frederick 2014-04-07 15:39:00 -0700 143) return error;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 144) }