]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
964f5369 AV |
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 { | |
964f5369 AV |
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); | |
00cd8dd3 | 25 | extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); |
964f5369 AV |
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 | ||
964f5369 | 29 | extern const struct inode_operations qnx4_dir_inode_operations; |
964f5369 AV |
30 | extern const struct file_operations qnx4_dir_operations; |
31 | extern int qnx4_is_free(struct super_block *sb, long block); | |
964f5369 AV |
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 | } | |
53853995 KC |
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(de->de_name, *size); | |
104 | ||
105 | return de->de_name; | |
106 | } |