1 // SPDX-License-Identifier: GPL-2.0
5 * (c) 1996 Hans-Joachim Widmaier - Rewritten
7 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
9 * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
11 * (C) 1991 Linus Torvalds - minix filesystem
13 * affs directory handling functions
17 #include <linux/iversion.h>
20 static int affs_readdir(struct file
*, struct dir_context
*);
22 const struct file_operations affs_dir_operations
= {
23 .read
= generic_read_dir
,
24 .llseek
= generic_file_llseek
,
25 .iterate_shared
= affs_readdir
,
26 .fsync
= affs_file_fsync
,
30 * directories can handle most operations...
32 const struct inode_operations affs_dir_inode_operations
= {
33 .create
= affs_create
,
34 .lookup
= affs_lookup
,
36 .unlink
= affs_unlink
,
37 .symlink
= affs_symlink
,
40 .rename
= affs_rename2
,
41 .setattr
= affs_notify_change
,
45 affs_readdir(struct file
*file
, struct dir_context
*ctx
)
47 struct inode
*inode
= file_inode(file
);
48 struct super_block
*sb
= inode
->i_sb
;
49 struct buffer_head
*dir_bh
= NULL
;
50 struct buffer_head
*fh_bh
= NULL
;
59 pr_debug("%s(ino=%lu,f_pos=%llx)\n", __func__
, inode
->i_ino
, ctx
->pos
);
62 file
->private_data
= (void *)0;
63 if (!dir_emit_dots(file
, ctx
))
68 chain_pos
= (ctx
->pos
- 2) & 0xffff;
69 hash_pos
= (ctx
->pos
- 2) >> 16;
70 if (chain_pos
== 0xffff) {
71 affs_warning(sb
, "readdir", "More than 65535 entries in chain");
74 ctx
->pos
= ((hash_pos
<< 16) | chain_pos
) + 2;
76 dir_bh
= affs_bread(sb
, inode
->i_ino
);
80 /* If the directory hasn't changed since the last call to readdir(),
81 * we can jump directly to where we left off.
83 ino
= (u32
)(long)file
->private_data
;
84 if (ino
&& inode_eq_iversion(inode
, file
->f_version
)) {
85 pr_debug("readdir() left off=%d\n", ino
);
89 ino
= be32_to_cpu(AFFS_HEAD(dir_bh
)->table
[hash_pos
]);
90 for (i
= 0; ino
&& i
< chain_pos
; i
++) {
91 fh_bh
= affs_bread(sb
, ino
);
93 affs_error(sb
, "readdir","Cannot read block %d", i
);
97 ino
= be32_to_cpu(AFFS_TAIL(sb
, fh_bh
)->hash_chain
);
105 for (; hash_pos
< AFFS_SB(sb
)->s_hashsize
; hash_pos
++) {
106 ino
= be32_to_cpu(AFFS_HEAD(dir_bh
)->table
[hash_pos
]);
109 ctx
->pos
= (hash_pos
<< 16) + 2;
112 fh_bh
= affs_bread(sb
, ino
);
114 affs_error(sb
, "readdir",
115 "Cannot read block %d", ino
);
119 namelen
= min(AFFS_TAIL(sb
, fh_bh
)->name
[0],
121 name
= AFFS_TAIL(sb
, fh_bh
)->name
+ 1;
122 pr_debug("readdir(): dir_emit(\"%.*s\", ino=%u), hash=%d, f_pos=%llx\n",
123 namelen
, name
, ino
, hash_pos
, ctx
->pos
);
125 if (!dir_emit(ctx
, name
, namelen
, ino
, DT_UNKNOWN
))
128 ino
= be32_to_cpu(AFFS_TAIL(sb
, fh_bh
)->hash_chain
);
134 file
->f_version
= inode_query_iversion(inode
);
135 file
->private_data
= (void *)(long)ino
;
142 affs_unlock_dir(inode
);