18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QNX4 file system, Linux implementation. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Version : 0.2.1 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Using parts of the xiafs filesystem. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * History : 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * 01-06-1998 by Richard Frowijn : first release. 128c2ecf20Sopenharmony_ci * 21-06-1998 by Frank Denis : dcache support, fixed error codes. 138c2ecf20Sopenharmony_ci * 04-07-1998 by Frank Denis : first step for rmdir/unlink. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 178c2ecf20Sopenharmony_ci#include "qnx4.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * check if the filename is correct. For some obscure reason, qnx writes a 228c2ecf20Sopenharmony_ci * new file twice in the directory entry, first with all possible options at 0 238c2ecf20Sopenharmony_ci * and for a second time the way it is, they want us not to access the qnx 248c2ecf20Sopenharmony_ci * filesystem when whe are using linux. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_cistatic int qnx4_match(int len, const char *name, 278c2ecf20Sopenharmony_ci struct buffer_head *bh, unsigned long *offset) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct qnx4_inode_entry *de; 308c2ecf20Sopenharmony_ci int namelen, thislen; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (bh == NULL) { 338c2ecf20Sopenharmony_ci printk(KERN_WARNING "qnx4: matching unassigned buffer !\n"); 348c2ecf20Sopenharmony_ci return 0; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci de = (struct qnx4_inode_entry *) (bh->b_data + *offset); 378c2ecf20Sopenharmony_ci *offset += QNX4_DIR_ENTRY_SIZE; 388c2ecf20Sopenharmony_ci if ((de->di_status & QNX4_FILE_LINK) != 0) { 398c2ecf20Sopenharmony_ci namelen = QNX4_NAME_MAX; 408c2ecf20Sopenharmony_ci } else { 418c2ecf20Sopenharmony_ci namelen = QNX4_SHORT_NAME_MAX; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci thislen = strlen( de->di_fname ); 448c2ecf20Sopenharmony_ci if ( thislen > namelen ) 458c2ecf20Sopenharmony_ci thislen = namelen; 468c2ecf20Sopenharmony_ci if (len != thislen) { 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci if (strncmp(name, de->di_fname, len) == 0) { 508c2ecf20Sopenharmony_ci if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) { 518c2ecf20Sopenharmony_ci return 1; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic struct buffer_head *qnx4_find_entry(int len, struct inode *dir, 588c2ecf20Sopenharmony_ci const char *name, struct qnx4_inode_entry **res_dir, int *ino) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci unsigned long block, offset, blkofs; 618c2ecf20Sopenharmony_ci struct buffer_head *bh; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci *res_dir = NULL; 648c2ecf20Sopenharmony_ci bh = NULL; 658c2ecf20Sopenharmony_ci block = offset = blkofs = 0; 668c2ecf20Sopenharmony_ci while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) { 678c2ecf20Sopenharmony_ci if (!bh) { 688c2ecf20Sopenharmony_ci block = qnx4_block_map(dir, blkofs); 698c2ecf20Sopenharmony_ci if (block) 708c2ecf20Sopenharmony_ci bh = sb_bread(dir->i_sb, block); 718c2ecf20Sopenharmony_ci if (!bh) { 728c2ecf20Sopenharmony_ci blkofs++; 738c2ecf20Sopenharmony_ci continue; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset); 778c2ecf20Sopenharmony_ci if (qnx4_match(len, name, bh, &offset)) { 788c2ecf20Sopenharmony_ci *ino = block * QNX4_INODES_PER_BLOCK + 798c2ecf20Sopenharmony_ci (offset / QNX4_DIR_ENTRY_SIZE) - 1; 808c2ecf20Sopenharmony_ci return bh; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci if (offset < bh->b_size) { 838c2ecf20Sopenharmony_ci continue; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci brelse(bh); 868c2ecf20Sopenharmony_ci bh = NULL; 878c2ecf20Sopenharmony_ci offset = 0; 888c2ecf20Sopenharmony_ci blkofs++; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci brelse(bh); 918c2ecf20Sopenharmony_ci *res_dir = NULL; 928c2ecf20Sopenharmony_ci return NULL; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci int ino; 988c2ecf20Sopenharmony_ci struct qnx4_inode_entry *de; 998c2ecf20Sopenharmony_ci struct qnx4_link_info *lnk; 1008c2ecf20Sopenharmony_ci struct buffer_head *bh; 1018c2ecf20Sopenharmony_ci const char *name = dentry->d_name.name; 1028c2ecf20Sopenharmony_ci int len = dentry->d_name.len; 1038c2ecf20Sopenharmony_ci struct inode *foundinode = NULL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) 1068c2ecf20Sopenharmony_ci goto out; 1078c2ecf20Sopenharmony_ci /* The entry is linked, let's get the real info */ 1088c2ecf20Sopenharmony_ci if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) { 1098c2ecf20Sopenharmony_ci lnk = (struct qnx4_link_info *) de; 1108c2ecf20Sopenharmony_ci ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) * 1118c2ecf20Sopenharmony_ci QNX4_INODES_PER_BLOCK + 1128c2ecf20Sopenharmony_ci lnk->dl_inode_ndx; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci brelse(bh); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci foundinode = qnx4_iget(dir->i_sb, ino); 1178c2ecf20Sopenharmony_ci if (IS_ERR(foundinode)) 1188c2ecf20Sopenharmony_ci QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n", 1198c2ecf20Sopenharmony_ci PTR_ERR(foundinode))); 1208c2ecf20Sopenharmony_ciout: 1218c2ecf20Sopenharmony_ci return d_splice_alias(foundinode, dentry); 1228c2ecf20Sopenharmony_ci} 123