linux/fs/qnx4/namei.c
<<
>>
Prefs
   1/* 
   2 * QNX4 file system, Linux implementation.
   3 * 
   4 * Version : 0.2.1
   5 * 
   6 * Using parts of the xiafs filesystem.
   7 * 
   8 * History :
   9 * 
  10 * 01-06-1998 by Richard Frowijn : first release.
  11 * 21-06-1998 by Frank Denis : dcache support, fixed error codes.
  12 * 04-07-1998 by Frank Denis : first step for rmdir/unlink.
  13 */
  14
  15#include <linux/buffer_head.h>
  16#include "qnx4.h"
  17
  18
  19/*
  20 * check if the filename is correct. For some obscure reason, qnx writes a
  21 * new file twice in the directory entry, first with all possible options at 0
  22 * and for a second time the way it is, they want us not to access the qnx
  23 * filesystem when whe are using linux.
  24 */
  25static int qnx4_match(int len, const char *name,
  26                      struct buffer_head *bh, unsigned long *offset)
  27{
  28        struct qnx4_inode_entry *de;
  29        int namelen, thislen;
  30
  31        if (bh == NULL) {
  32                printk(KERN_WARNING "qnx4: matching unassigned buffer !\n");
  33                return 0;
  34        }
  35        de = (struct qnx4_inode_entry *) (bh->b_data + *offset);
  36        *offset += QNX4_DIR_ENTRY_SIZE;
  37        if ((de->di_status & QNX4_FILE_LINK) != 0) {
  38                namelen = QNX4_NAME_MAX;
  39        } else {
  40                namelen = QNX4_SHORT_NAME_MAX;
  41        }
  42        thislen = strlen( de->di_fname );
  43        if ( thislen > namelen )
  44                thislen = namelen;
  45        if (len != thislen) {
  46                return 0;
  47        }
  48        if (strncmp(name, de->di_fname, len) == 0) {
  49                if ((de->di_status & (QNX4_FILE_USED|QNX4_FILE_LINK)) != 0) {
  50                        return 1;
  51                }
  52        }
  53        return 0;
  54}
  55
  56static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
  57           const char *name, struct qnx4_inode_entry **res_dir, int *ino)
  58{
  59        unsigned long block, offset, blkofs;
  60        struct buffer_head *bh;
  61
  62        *res_dir = NULL;
  63        bh = NULL;
  64        block = offset = blkofs = 0;
  65        while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
  66                if (!bh) {
  67                        block = qnx4_block_map(dir, blkofs);
  68                        if (block)
  69                                bh = sb_bread(dir->i_sb, block);
  70                        if (!bh) {
  71                                blkofs++;
  72                                continue;
  73                        }
  74                }
  75                *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
  76                if (qnx4_match(len, name, bh, &offset)) {
  77                        *ino = block * QNX4_INODES_PER_BLOCK +
  78                            (offset / QNX4_DIR_ENTRY_SIZE) - 1;
  79                        return bh;
  80                }
  81                if (offset < bh->b_size) {
  82                        continue;
  83                }
  84                brelse(bh);
  85                bh = NULL;
  86                offset = 0;
  87                blkofs++;
  88        }
  89        brelse(bh);
  90        *res_dir = NULL;
  91        return NULL;
  92}
  93
  94struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
  95{
  96        int ino;
  97        struct qnx4_inode_entry *de;
  98        struct qnx4_link_info *lnk;
  99        struct buffer_head *bh;
 100        const char *name = dentry->d_name.name;
 101        int len = dentry->d_name.len;
 102        struct inode *foundinode = NULL;
 103
 104        if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino)))
 105                goto out;
 106        /* The entry is linked, let's get the real info */
 107        if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
 108                lnk = (struct qnx4_link_info *) de;
 109                ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) *
 110                    QNX4_INODES_PER_BLOCK +
 111                    lnk->dl_inode_ndx;
 112        }
 113        brelse(bh);
 114
 115        foundinode = qnx4_iget(dir->i_sb, ino);
 116        if (IS_ERR(foundinode)) {
 117                QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n",
 118                           PTR_ERR(foundinode)));
 119                return ERR_CAST(foundinode);
 120        }
 121out:
 122        d_add(dentry, foundinode);
 123
 124        return NULL;
 125}
 126