Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 LT |
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 | ||
1da177e4 | 15 | #include <linux/buffer_head.h> |
964f5369 | 16 | #include "qnx4.h" |
1da177e4 | 17 | |
b7213ffa LT |
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. | |
d5f65459 LT |
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. | |
b7213ffa LT |
44 | */ |
45 | union qnx4_directory_entry { | |
46 | struct { | |
d5f65459 LT |
47 | const char de_name[48]; |
48 | u8 de_pad[15]; | |
49 | u8 de_status; | |
b7213ffa LT |
50 | }; |
51 | struct qnx4_inode_entry inode; | |
52 | struct qnx4_link_info link; | |
53 | }; | |
54 | ||
663f4dec | 55 | static int qnx4_readdir(struct file *file, struct dir_context *ctx) |
1da177e4 | 56 | { |
663f4dec | 57 | struct inode *inode = file_inode(file); |
1da177e4 LT |
58 | unsigned int offset; |
59 | struct buffer_head *bh; | |
1da177e4 LT |
60 | unsigned long blknum; |
61 | int ix, ino; | |
62 | int size; | |
63 | ||
891ddb95 | 64 | QNX4DEBUG((KERN_INFO "qnx4_readdir:i_size = %ld\n", (long) inode->i_size)); |
663f4dec | 65 | QNX4DEBUG((KERN_INFO "pos = %ld\n", (long) ctx->pos)); |
1da177e4 | 66 | |
663f4dec AV |
67 | while (ctx->pos < inode->i_size) { |
68 | blknum = qnx4_block_map(inode, ctx->pos >> QNX4_BLOCK_SIZE_BITS); | |
1da177e4 | 69 | bh = sb_bread(inode->i_sb, blknum); |
663f4dec | 70 | if (bh == NULL) { |
1da177e4 | 71 | printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum); |
663f4dec | 72 | return 0; |
1da177e4 | 73 | } |
663f4dec AV |
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) { | |
b7213ffa | 76 | union qnx4_directory_entry *de; |
b7213ffa | 77 | |
1da177e4 | 78 | offset = ix * QNX4_DIR_ENTRY_SIZE; |
b7213ffa LT |
79 | de = (union qnx4_directory_entry *) (bh->b_data + offset); |
80 | ||
d5f65459 | 81 | if (!de->de_name[0]) |
663f4dec | 82 | continue; |
b7213ffa | 83 | if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) |
663f4dec | 84 | continue; |
b7213ffa LT |
85 | if (!(de->de_status & QNX4_FILE_LINK)) { |
86 | size = sizeof(de->inode.di_fname); | |
663f4dec | 87 | ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1; |
b7213ffa LT |
88 | } else { |
89 | size = sizeof(de->link.dl_fname); | |
b7213ffa | 90 | ino = ( le32_to_cpu(de->link.dl_inode_blk) - 1 ) * |
663f4dec | 91 | QNX4_INODES_PER_BLOCK + |
b7213ffa | 92 | de->link.dl_inode_ndx; |
663f4dec | 93 | } |
d5f65459 | 94 | size = strnlen(de->de_name, size); |
b7213ffa | 95 | QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, name)); |
d5f65459 | 96 | if (!dir_emit(ctx, de->de_name, size, ino, DT_UNKNOWN)) { |
663f4dec AV |
97 | brelse(bh); |
98 | return 0; | |
1da177e4 | 99 | } |
1da177e4 LT |
100 | } |
101 | brelse(bh); | |
102 | } | |
1da177e4 LT |
103 | return 0; |
104 | } | |
105 | ||
4b6f5d20 | 106 | const struct file_operations qnx4_dir_operations = |
1da177e4 | 107 | { |
ca572727 | 108 | .llseek = generic_file_llseek, |
1da177e4 | 109 | .read = generic_read_dir, |
c51da20c | 110 | .iterate_shared = qnx4_readdir, |
1b061d92 | 111 | .fsync = generic_file_fsync, |
1da177e4 LT |
112 | }; |
113 | ||
c5ef1c42 | 114 | const struct inode_operations qnx4_dir_inode_operations = |
1da177e4 LT |
115 | { |
116 | .lookup = qnx4_lookup, | |
1da177e4 | 117 | }; |