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        if (!dir->i_sb) {
  64                printk(KERN_WARNING "qnx4: no superblock on dir.\n");
  65                return NULL;
  66        }
  67        bh = NULL;
  68        block = offset = blkofs = 0;
  69        while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
  70                if (!bh) {
  71                        block = qnx4_block_map(dir, blkofs);
  72                        if (block)
  73                                bh = sb_bread(dir->i_sb, block);
  74                        if (!bh) {
  75                                blkofs++;
  76                                continue;
  77                        }
  78                }
  79                *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
  80                if (qnx4_match(len, name, bh, &offset)) {
  81                        *ino = block * QNX4_INODES_PER_BLOCK +
  82                            (offset / QNX4_DIR_ENTRY_SIZE) - 1;
  83                        return bh;
  84                }
  85                if (offset < bh->b_size) {
  86                        continue;
  87                }
  88                brelse(bh);
  89                bh = NULL;
  90                offset = 0;
  91                blkofs++;
  92        }
  93        brelse(bh);
  94        *res_dir = NULL;
  95        return NULL;
  96}
  97
  98struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
  99{
 100        int ino;
 101        struct qnx4_inode_entry *de;
 102        struct qnx4_link_info *lnk;
 103        struct buffer_head *bh;
 104        const char *name = dentry->d_name.name;
 105        int len = dentry->d_name.len;
 106        struct inode *foundinode = NULL;
 107
 108        if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino)))
 109                goto out;
 110        /* The entry is linked, let's get the real info */
 111        if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
 112                lnk = (struct qnx4_link_info *) de;
 113                ino = (le32_to_cpu(lnk->dl_inode_blk) - 1) *
 114                    QNX4_INODES_PER_BLOCK +
 115                    lnk->dl_inode_ndx;
 116        }
 117        brelse(bh);
 118
 119        foundinode = qnx4_iget(dir->i_sb, ino);
 120        if (IS_ERR(foundinode)) {
 121                QNX4DEBUG((KERN_ERR "qnx4: lookup->iget -> error %ld\n",
 122                           PTR_ERR(foundinode)));
 123                return ERR_CAST(foundinode);
 124        }
 125out:
 126        d_add(dentry, foundinode);
 127
 128        return NULL;
 129}
 130