1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * QNX4 file system, Linux implementation. |
4 | * |
5 | * Version : 0.2.1 |
6 | * |
7 | * Using parts of the xiafs filesystem. |
8 | * |
9 | * History : |
10 | * |
11 | * 28-05-1998 by Richard Frowijn : first release. |
12 | * 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support. |
13 | */ |
14 | |
15 | #include <linux/buffer_head.h> |
16 | #include "qnx4.h" |
17 | |
18 | /* |
19 | * A qnx4 directory entry is an inode entry or link info |
20 | * depending on the status field in the last byte. The |
21 | * first byte is where the name start either way, and a |
22 | * zero means it's empty. |
23 | * |
24 | * Also, due to a bug in gcc, we don't want to use the |
25 | * real (differently sized) name arrays in the inode and |
26 | * link entries, but always the 'de_name[]' one in the |
27 | * fake struct entry. |
28 | * |
29 | * See |
30 | * |
31 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6 |
32 | * |
33 | * for details, but basically gcc will take the size of the |
34 | * 'name' array from one of the used union entries randomly. |
35 | * |
36 | * This use of 'de_name[]' (48 bytes) avoids the false positive |
37 | * warnings that would happen if gcc decides to use 'inode.di_name' |
38 | * (16 bytes) even when the pointer and size were to come from |
39 | * 'link.dl_name' (48 bytes). |
40 | * |
41 | * In all cases the actual name pointer itself is the same, it's |
42 | * only the gcc internal 'what is the size of this field' logic |
43 | * that can get confused. |
44 | */ |
45 | union qnx4_directory_entry { |
46 | struct { |
47 | const char de_name[48]; |
48 | u8 de_pad[15]; |
49 | u8 de_status; |
50 | }; |
51 | struct qnx4_inode_entry inode; |
52 | struct qnx4_link_info link; |
53 | }; |
54 | |
55 | static int qnx4_readdir(struct file *file, struct dir_context *ctx) |
56 | { |
57 | struct inode *inode = file_inode(f: file); |
58 | unsigned int offset; |
59 | struct buffer_head *bh; |
60 | unsigned long blknum; |
61 | int ix, ino; |
62 | int size; |
63 | |
64 | QNX4DEBUG((KERN_INFO "qnx4_readdir:i_size = %ld\n" , (long) inode->i_size)); |
65 | QNX4DEBUG((KERN_INFO "pos = %ld\n" , (long) ctx->pos)); |
66 | |
67 | while (ctx->pos < inode->i_size) { |
68 | blknum = qnx4_block_map(inode, iblock: ctx->pos >> QNX4_BLOCK_SIZE_BITS); |
69 | bh = sb_bread(sb: inode->i_sb, block: blknum); |
70 | if (bh == NULL) { |
71 | printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n" , blknum); |
72 | return 0; |
73 | } |
74 | ix = (ctx->pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK; |
75 | for (; ix < QNX4_INODES_PER_BLOCK; ix++, ctx->pos += QNX4_DIR_ENTRY_SIZE) { |
76 | union qnx4_directory_entry *de; |
77 | |
78 | offset = ix * QNX4_DIR_ENTRY_SIZE; |
79 | de = (union qnx4_directory_entry *) (bh->b_data + offset); |
80 | |
81 | if (!de->de_name[0]) |
82 | continue; |
83 | if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) |
84 | continue; |
85 | if (!(de->de_status & QNX4_FILE_LINK)) { |
86 | size = sizeof(de->inode.di_fname); |
87 | ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; |
88 | } else { |
89 | size = sizeof(de->link.dl_fname); |
90 | ino = ( le32_to_cpu(de->link.dl_inode_blk) - 1 ) * |
91 | QNX4_INODES_PER_BLOCK + |
92 | de->link.dl_inode_ndx; |
93 | } |
94 | size = strnlen(p: de->de_name, maxlen: size); |
95 | QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n" , size, name)); |
96 | if (!dir_emit(ctx, name: de->de_name, namelen: size, ino, DT_UNKNOWN)) { |
97 | brelse(bh); |
98 | return 0; |
99 | } |
100 | } |
101 | brelse(bh); |
102 | } |
103 | return 0; |
104 | } |
105 | |
106 | const struct file_operations qnx4_dir_operations = |
107 | { |
108 | .llseek = generic_file_llseek, |
109 | .read = generic_read_dir, |
110 | .iterate_shared = qnx4_readdir, |
111 | .fsync = generic_file_fsync, |
112 | }; |
113 | |
114 | const struct inode_operations qnx4_dir_inode_operations = |
115 | { |
116 | .lookup = qnx4_lookup, |
117 | }; |
118 | |