1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #include <linux/fs.h> |
3 | #include <linux/qnx4_fs.h> |
4 | |
5 | #define QNX4_DEBUG 0 |
6 | |
7 | #if QNX4_DEBUG |
8 | #define QNX4DEBUG(X) printk X |
9 | #else |
10 | #define QNX4DEBUG(X) (void) 0 |
11 | #endif |
12 | |
13 | struct qnx4_sb_info { |
14 | unsigned int Version; /* may be useful */ |
15 | struct qnx4_inode_entry *BitMap; /* useful */ |
16 | }; |
17 | |
18 | struct qnx4_inode_info { |
19 | struct qnx4_inode_entry raw; |
20 | loff_t mmu_private; |
21 | struct inode vfs_inode; |
22 | }; |
23 | |
24 | extern struct inode *qnx4_iget(struct super_block *, unsigned long); |
25 | extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); |
26 | extern unsigned long qnx4_count_free_blocks(struct super_block *sb); |
27 | extern unsigned long qnx4_block_map(struct inode *inode, long iblock); |
28 | |
29 | extern const struct inode_operations qnx4_dir_inode_operations; |
30 | extern const struct file_operations qnx4_dir_operations; |
31 | extern int qnx4_is_free(struct super_block *sb, long block); |
32 | |
33 | static inline struct qnx4_sb_info *qnx4_sb(struct super_block *sb) |
34 | { |
35 | return sb->s_fs_info; |
36 | } |
37 | |
38 | static inline struct qnx4_inode_info *qnx4_i(struct inode *inode) |
39 | { |
40 | return container_of(inode, struct qnx4_inode_info, vfs_inode); |
41 | } |
42 | |
43 | static inline struct qnx4_inode_entry *qnx4_raw_inode(struct inode *inode) |
44 | { |
45 | return &qnx4_i(inode)->raw; |
46 | } |
47 | |
48 | /* |
49 | * A qnx4 directory entry is an inode entry or link info |
50 | * depending on the status field in the last byte. The |
51 | * first byte is where the name start either way, and a |
52 | * zero means it's empty. |
53 | * |
54 | * Also, due to a bug in gcc, we don't want to use the |
55 | * real (differently sized) name arrays in the inode and |
56 | * link entries, but always the 'de_name[]' one in the |
57 | * fake struct entry. |
58 | * |
59 | * See |
60 | * |
61 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6 |
62 | * |
63 | * for details, but basically gcc will take the size of the |
64 | * 'name' array from one of the used union entries randomly. |
65 | * |
66 | * This use of 'de_name[]' (48 bytes) avoids the false positive |
67 | * warnings that would happen if gcc decides to use 'inode.di_name' |
68 | * (16 bytes) even when the pointer and size were to come from |
69 | * 'link.dl_name' (48 bytes). |
70 | * |
71 | * In all cases the actual name pointer itself is the same, it's |
72 | * only the gcc internal 'what is the size of this field' logic |
73 | * that can get confused. |
74 | */ |
75 | union qnx4_directory_entry { |
76 | struct { |
77 | const char de_name[48]; |
78 | u8 de_pad[15]; |
79 | u8 de_status; |
80 | }; |
81 | struct qnx4_inode_entry inode; |
82 | struct qnx4_link_info link; |
83 | }; |
84 | |
85 | static inline const char *get_entry_fname(union qnx4_directory_entry *de, |
86 | int *size) |
87 | { |
88 | /* Make sure the status byte is in the same place for all structs. */ |
89 | BUILD_BUG_ON(offsetof(struct qnx4_inode_entry, di_status) != |
90 | offsetof(struct qnx4_link_info, dl_status)); |
91 | BUILD_BUG_ON(offsetof(struct qnx4_inode_entry, di_status) != |
92 | offsetof(union qnx4_directory_entry, de_status)); |
93 | |
94 | if (!de->de_name[0]) |
95 | return NULL; |
96 | if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK))) |
97 | return NULL; |
98 | if (!(de->de_status & QNX4_FILE_LINK)) |
99 | *size = sizeof(de->inode.di_fname); |
100 | else |
101 | *size = sizeof(de->link.dl_fname); |
102 | |
103 | *size = strnlen(p: de->de_name, maxlen: *size); |
104 | |
105 | return de->de_name; |
106 | } |
107 | |