Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* 
0003  * QNX4 file system, Linux implementation.
0004  * 
0005  * Version : 0.2.1
0006  * 
0007  * Using parts of the xiafs filesystem.
0008  * 
0009  * History :
0010  * 
0011  * 01-06-1998 by Richard Frowijn : first release.
0012  * 21-06-1998 by Frank Denis : dcache support, fixed error codes.
0013  * 04-07-1998 by Frank Denis : first step for rmdir/unlink.
0014  */
0015 
0016 #include <linux/buffer_head.h>
0017 #include "qnx4.h"
0018 
0019 
0020 /*
0021  * check if the filename is correct. For some obscure reason, qnx writes a
0022  * new file twice in the directory entry, first with all possible options at 0
0023  * and for a second time the way it is, they want us not to access the qnx
0024  * filesystem when whe are using linux.
0025  */
0026 static int qnx4_match(int len, const char *name,
0027               struct buffer_head *bh, unsigned long *offset)
0028 {
0029     struct qnx4_inode_entry *de;
0030     int namelen, thislen;
0031 
0032     if (bh == NULL) {
0033         printk(KERN_WARNING "qnx4: matching unassigned buffer !\n");
0034         return 0;
0035     }
0036     de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
0037     *offset += QNX4_DIR_ENTRY_SIZE;
0038     if ((de->di_status & QNX4_FILE_LINK) != 0) {
0039         namelen = QNX4_NAME_MAX;
0040     } else {
0041         namelen = QNX4_SHORT_NAME_MAX;
0042     }
0043     thislen = strlen( de->di_fname );
0044     if ( thislen > namelen )
0045         thislen = namelen;
0046     if (len != thislen) {
0047         return 0;
0048     }
0049     if (strncmp(name, de->di_fname, len) == 0) {
0050         if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) {
0051             return 1;
0052         }
0053     }
0054     return 0;
0055 }
0056 
0057 static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
0058        const char *name, struct qnx4_inode_entry **res_dir, int *ino)
0059 {
0060     unsigned long block, offset, blkofs;
0061     struct buffer_head *bh;
0062 
0063     *res_dir = NULL;
0064     bh = NULL;
0065     block = offset = blkofs = 0;
0066     while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
0067         if (!bh) {
0068             block = qnx4_block_map(dir, blkofs);
0069             if (block)
0070                 bh = sb_bread(dir->i_sb, block);
0071             if (!bh) {
0072                 blkofs++;
0073                 continue;
0074             }
0075         }
0076         *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
0077         if (qnx4_match(len, name, bh, &offset)) {
0078             *ino = block * QNX4_INODES_PER_BLOCK +
0079                 (offset / QNX4_DIR_ENTRY_SIZE) - 1;
0080             return bh;
0081         }
0082         if (offset < bh->b_size) {
0083             continue;
0084         }
0085         brelse(bh);
0086         bh = NULL;
0087         offset = 0;
0088         blkofs++;
0089     }
0090     brelse(bh);
0091     *res_dir = NULL;
0092     return NULL;
0093 }
0094 
0095 struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
0096 {
0097     int ino;
0098     struct qnx4_inode_entry *de;
0099     struct qnx4_link_info *lnk;
0100     struct buffer_head *bh;
0101     const char *name = dentry->d_name.name;
0102     int len = dentry->d_name.len;
0103     struct inode *foundinode = NULL;
0104 
0105     if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino)))
0106         goto out;
0107     /* The entry is linked, let's get the real info */
0108     if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
0109         lnk = (struct qnx4_link_info *) de;
0110         ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) *
0111                     QNX4_INODES_PER_BLOCK +
0112             lnk->dl_inode_ndx;
0113     }
0114     brelse(bh);
0115 
0116     foundinode = qnx4_iget(dir->i_sb, ino);
0117     if (IS_ERR(foundinode))
0118         QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n",
0119                PTR_ERR(foundinode)));
0120 out:
0121     return d_splice_alias(foundinode, dentry);
0122 }