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